Decompiled source of PlayerCountFixed v1.1.0

PlayerCountFixed.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
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("PlayerCountFixed")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PlayerCountFixed")]
[assembly: AssemblyTitle("PlayerCountFixed")]
[assembly: AssemblyVersion("1.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 PlayerCountFixed
{
	[BepInPlugin("local.playercountfixed", "PlayerCountFixed", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(MenuPageLobby), "Awake")]
		private static class MenuPageLobbyAwakePatch
		{
			private static void Postfix(MenuPageLobby __instance)
			{
				TryAttachLobbyCounter(__instance);
			}
		}

		[HarmonyPatch(typeof(MenuPageLobby), "Start")]
		private static class MenuPageLobbyStartPatch
		{
			private static void Postfix(MenuPageLobby __instance)
			{
				TryAttachLobbyCounter(__instance);
			}
		}

		private sealed class PlayerCountFixedUpdater : MonoBehaviour
		{
			[CompilerGenerated]
			private sealed class <RefreshLoop>d__7 : IEnumerator<object>, IEnumerator, IDisposable
			{
				private int <>1__state;

				private object <>2__current;

				public PlayerCountFixedUpdater <>4__this;

				object IEnumerator<object>.Current
				{
					[DebuggerHidden]
					get
					{
						return <>2__current;
					}
				}

				object IEnumerator.Current
				{
					[DebuggerHidden]
					get
					{
						return <>2__current;
					}
				}

				[DebuggerHidden]
				public <RefreshLoop>d__7(int <>1__state)
				{
					this.<>1__state = <>1__state;
				}

				[DebuggerHidden]
				void IDisposable.Dispose()
				{
					<>1__state = -2;
				}

				private bool MoveNext()
				{
					int num = <>1__state;
					PlayerCountFixedUpdater playerCountFixedUpdater = <>4__this;
					if (num != 0)
					{
						if (num != 1)
						{
							return false;
						}
						<>1__state = -1;
					}
					else
					{
						<>1__state = -1;
					}
					playerCountFixedUpdater.RefreshOnce();
					<>2__current = playerCountFixedUpdater._refreshDelay;
					<>1__state = 1;
					return true;
				}

				bool IEnumerator.MoveNext()
				{
					//ILSpy generated this explicit interface implementation from .override directive in MoveNext
					return this.MoveNext();
				}

				[DebuggerHidden]
				void IEnumerator.Reset()
				{
					throw new NotSupportedException();
				}
			}

			private TextMeshProUGUI? _text;

			private Coroutine? _refreshCoroutine;

			private string? _lastText;

			private readonly WaitForSeconds _refreshDelay = new WaitForSeconds(0.25f);

			internal void SetText(TextMeshProUGUI text)
			{
				_text = text;
				if (_refreshCoroutine == null && ((Behaviour)this).isActiveAndEnabled)
				{
					_refreshCoroutine = ((MonoBehaviour)this).StartCoroutine(RefreshLoop());
				}
			}

			private void OnEnable()
			{
				if ((Object)(object)_text != (Object)null && _refreshCoroutine == null)
				{
					_refreshCoroutine = ((MonoBehaviour)this).StartCoroutine(RefreshLoop());
				}
			}

			private void OnDisable()
			{
				if (_refreshCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(_refreshCoroutine);
					_refreshCoroutine = null;
				}
			}

			[IteratorStateMachine(typeof(<RefreshLoop>d__7))]
			private IEnumerator RefreshLoop()
			{
				//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
				return new <RefreshLoop>d__7(0)
				{
					<>4__this = this
				};
			}

			internal void RefreshNow()
			{
				_lastText = null;
				RefreshOnce();
			}

			private void RefreshOnce()
			{
				try
				{
					if ((Object)(object)_text == (Object)null)
					{
						return;
					}
					string text = string.Empty;
					Room currentRoom = PhotonNetwork.CurrentRoom;
					if (PhotonNetwork.InRoom && currentRoom != null)
					{
						if ((Object)(object)Instance == (Object)null || Instance.UseNewColorMode())
						{
							string arg = ((currentRoom.PlayerCount == currentRoom.MaxPlayers) ? "#FF0000" : "#00FF00");
							text = $"Players: <color={arg}>{currentRoom.PlayerCount}</color><color=#FFFFFF>/</color><color=#FF0000>{currentRoom.MaxPlayers}</color>";
						}
						else
						{
							text = $"Players: {currentRoom.PlayerCount}/{currentRoom.MaxPlayers}";
						}
					}
					if (!string.Equals(_lastText, text, StringComparison.Ordinal))
					{
						((TMP_Text)_text).text = text;
						_lastText = text;
					}
				}
				catch (Exception ex)
				{
					Instance?.LogUpdateFailureOnce(ex);
				}
			}
		}

		public const string PluginGuid = "local.playercountfixed";

		public const string PluginName = "PlayerCountFixed";

		public const string PluginVersion = "1.0.0";

		private const string LobbyTextObjectName = "PlayerCountFixedTextLobby";

		private const float DefaultPositionX1080 = 240f;

		private const float DefaultPositionY1080 = 30f;

		private const float DefaultFontSize = 22f;

		private const float MinFontSize = 1f;

		private const float MaxFontSize = 200f;

		private const float MinPosition = 0f;

		private const float MaxPosition = 10000f;

		private Harmony? _harmony;

		private ConfigEntry<float>? _positionX1080;

		private ConfigEntry<float>? _positionY1080;

		private ConfigEntry<float>? _fontSize;

		private ConfigEntry<string>? _colorMode;

		private bool _loggedUiAttached;

		private bool _loggedUiAttachFailure;

		private bool _loggedUiConfigFailure;

		private bool _loggedUpdateFailure;

		internal static Plugin? Instance { get; private set; }

		private void Awake()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			Instance = this;
			BindConfig();
			_harmony = new Harmony("local.playercountfixed");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"PlayerCountFixed loaded.");
		}

		private void OnDestroy()
		{
			UnsubscribeUiConfigChanged();
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		internal static void TryAttachLobbyCounter(MenuPageLobby lobby)
		{
			Instance?.AttachLobbyCounter(lobby);
		}

		private void AttachLobbyCounter(MenuPageLobby lobby)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)lobby == (Object)null)
				{
					return;
				}
				Transform transform = ((Component)lobby).transform;
				Transform val = transform.Find("Panel");
				Transform val2 = val ?? transform;
				Transform val3 = FindExistingCounter(transform);
				if ((Object)(object)val3 != (Object)null)
				{
					if ((Object)(object)val != (Object)null && (Object)(object)val3.parent != (Object)(object)val)
					{
						val3.SetParent(val, false);
					}
					ApplyUiConfig(val3, ((Component)val3).GetComponent<TextMeshProUGUI>());
					EnsureUpdater(((Component)val3).gameObject, ((Component)val3).GetComponent<TextMeshProUGUI>());
					return;
				}
				TextMeshProUGUI val4 = FindReferenceText(transform);
				GameObject val5 = new GameObject("PlayerCountFixedTextLobby");
				val5.transform.SetParent(val2, false);
				RectTransform obj = val5.AddComponent<RectTransform>();
				obj.anchorMin = new Vector2(0f, 1f);
				obj.anchorMax = new Vector2(0f, 1f);
				obj.pivot = new Vector2(0f, 1f);
				obj.sizeDelta = new Vector2(240f, 30f);
				TextMeshProUGUI val6 = val5.AddComponent<TextMeshProUGUI>();
				if ((Object)(object)val4 != (Object)null)
				{
					((TMP_Text)val6).font = ((TMP_Text)val4).font;
					((TMP_Text)val6).fontSharedMaterial = ((TMP_Text)val4).fontSharedMaterial;
					((TMP_Text)val6).fontStyle = ((TMP_Text)val4).fontStyle;
				}
				((TMP_Text)val6).alignment = (TextAlignmentOptions)513;
				((Graphic)val6).color = Color.yellow;
				((Graphic)val6).raycastTarget = false;
				((TMP_Text)val6).text = string.Empty;
				ApplyUiConfig(val5.transform, val6);
				EnsureUpdater(val5, val6);
				if (!_loggedUiAttached)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Lobby player count UI attached.");
					_loggedUiAttached = true;
				}
			}
			catch (Exception ex)
			{
				LogUiAttachFailureOnce(ex);
			}
		}

		private void BindConfig()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			_positionX1080 = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "Position X (1080p)", 240f, new ConfigDescription("Horizontal RectTransform anchored-position UI offset from the top-left anchor, in UI units. Values are clamped to a safe non-negative range.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10000f), Array.Empty<object>()));
			_positionY1080 = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "Position Y (1080p)", 30f, new ConfigDescription("Vertical RectTransform anchored-position UI offset from the top-left anchor, in UI units. Values are clamped to a safe non-negative range.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10000f), Array.Empty<object>()));
			_fontSize = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "Font Size", 22f, new ConfigDescription("Lobby counter TextMeshPro font size. Values are clamped to a safe positive range.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 200f), Array.Empty<object>()));
			_colorMode = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "Color Mode", "new", new ConfigDescription("Lobby counter color style. Use 'new' for colored player counts or 'old' for the plain all-yellow display.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "new", "old" }), Array.Empty<object>()));
			SubscribeUiConfigChanged();
		}

		private void SubscribeUiConfigChanged()
		{
			((BaseUnityPlugin)this).Config.ConfigReloaded += OnUiConfigChanged;
			if (_positionX1080 != null)
			{
				_positionX1080.SettingChanged += OnUiConfigChanged;
			}
			if (_positionY1080 != null)
			{
				_positionY1080.SettingChanged += OnUiConfigChanged;
			}
			if (_fontSize != null)
			{
				_fontSize.SettingChanged += OnUiConfigChanged;
			}
			if (_colorMode != null)
			{
				_colorMode.SettingChanged += OnUiConfigChanged;
			}
		}

		private void UnsubscribeUiConfigChanged()
		{
			((BaseUnityPlugin)this).Config.ConfigReloaded -= OnUiConfigChanged;
			if (_positionX1080 != null)
			{
				_positionX1080.SettingChanged -= OnUiConfigChanged;
			}
			if (_positionY1080 != null)
			{
				_positionY1080.SettingChanged -= OnUiConfigChanged;
			}
			if (_fontSize != null)
			{
				_fontSize.SettingChanged -= OnUiConfigChanged;
			}
			if (_colorMode != null)
			{
				_colorMode.SettingChanged -= OnUiConfigChanged;
			}
		}

		private void OnUiConfigChanged(object sender, EventArgs args)
		{
			try
			{
				MenuPageLobby instance = MenuPageLobby.instance;
				if (!((Object)(object)instance == (Object)null))
				{
					Transform val = FindExistingCounter(((Component)instance).transform);
					if (!((Object)(object)val == (Object)null))
					{
						ApplyUiConfig(val, ((Component)val).GetComponent<TextMeshProUGUI>());
						((Component)val).GetComponent<PlayerCountFixedUpdater>()?.RefreshNow();
					}
				}
			}
			catch (Exception ex)
			{
				LogUiConfigFailureOnce(ex);
			}
		}

		private void ApplyUiConfig(Transform transform, TextMeshProUGUI? text)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			if (val != null)
			{
				float num = ClampConfigValue(_positionX1080?.Value, 240f, 0f, 10000f);
				float num2 = ClampConfigValue(_positionY1080?.Value, 30f, 0f, 10000f);
				val.anchoredPosition = new Vector2(num, num2);
			}
			if ((Object)(object)text != (Object)null)
			{
				((TMP_Text)text).fontSize = ClampConfigValue(_fontSize?.Value, 22f, 1f, 200f);
				((TMP_Text)text).richText = true;
			}
		}

		private static float ClampConfigValue(float? value, float fallback, float min, float max)
		{
			float num = value.GetValueOrDefault(fallback);
			if (float.IsNaN(num) || float.IsInfinity(num))
			{
				num = fallback;
			}
			return Mathf.Clamp(num, min, max);
		}

		private bool UseNewColorMode()
		{
			return !string.Equals(_colorMode?.Value, "old", StringComparison.OrdinalIgnoreCase);
		}

		private static TextMeshProUGUI? FindReferenceText(Transform root)
		{
			Transform val = root.Find("Menu Button - Leave/ButtonText") ?? root.Find("Menu Button - Settings/ButtonText");
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return ((Component)val).GetComponent<TextMeshProUGUI>();
		}

		private static Transform? FindExistingCounter(Transform root)
		{
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && string.Equals(((Object)val).name, "PlayerCountFixedTextLobby", StringComparison.Ordinal))
				{
					return val;
				}
			}
			return null;
		}

		private static void EnsureUpdater(GameObject go, TextMeshProUGUI? text)
		{
			if (!((Object)(object)go == (Object)null) && !((Object)(object)text == (Object)null))
			{
				(go.GetComponent<PlayerCountFixedUpdater>() ?? go.AddComponent<PlayerCountFixedUpdater>()).SetText(text);
			}
		}

		internal void LogUpdateFailureOnce(Exception ex)
		{
			if (!_loggedUpdateFailure)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Player count update failed; suppressing further update errors. " + ex.GetType().Name + ": " + ex.Message));
				_loggedUpdateFailure = true;
			}
		}

		private void LogUiAttachFailureOnce(Exception ex)
		{
			if (!_loggedUiAttachFailure)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Lobby player count UI attach failed; suppressing further attach errors. " + ex.GetType().Name + ": " + ex.Message));
				_loggedUiAttachFailure = true;
			}
		}

		private void LogUiConfigFailureOnce(Exception ex)
		{
			if (!_loggedUiConfigFailure)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Lobby player count UI config reload failed; suppressing further config reload errors. " + ex.GetType().Name + ": " + ex.Message));
				_loggedUiConfigFailure = true;
			}
		}
	}
}