Decompiled source of Player Limit Mod v1.1.0

BepInEx\plugins\PlayerLimitMod\PlayerLimitMod.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PlayerLimitMod.Patches;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
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: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("PlayerLimitMod")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Increases multiplayer player limit for Stolen Realm")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+a7afe6dac038cc6962b81ae753bee12f00fd7bfa")]
[assembly: AssemblyProduct("PlayerLimitMod")]
[assembly: AssemblyTitle("PlayerLimitMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 PlayerLimitMod
{
	[BepInPlugin("com.stolenrealm.playerlimit", "Player Limit Mod", "1.1.0")]
	public class PlayerLimitPlugin : BaseUnityPlugin
	{
		internal static ManualLogSource Logger;

		internal static ConfigEntry<int> MaxPlayers;

		internal static bool IsShuttingDown = false;

		private Harmony _harmony;

		private static Harmony _harmonyInstance;

		private static readonly string _traceLog = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "plm_trace.log");

		private bool _f9DumpDone = false;

		private bool _f10DumpDone = false;

		private int _frameSkip = 0;

		private static bool _updateTraced = false;

		internal static void Trace(string msg)
		{
			try
			{
				File.AppendAllText(_traceLog, $"[{DateTime.Now:HH:mm:ss.fff}] {msg}\r\n");
			}
			catch
			{
			}
		}

		private void Awake()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			Trace("Awake() START");
			MaxPlayers = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxPlayers", 16, new ConfigDescription("Maximum number of players allowed in multiplayer lobbies.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 16), Array.Empty<object>()));
			Logger.LogInfo((object)"=== Player Limit Mod v1.1.0 ===");
			Logger.LogInfo((object)$"Max players set to: {MaxPlayers.Value}");
			_harmony = new Harmony("com.stolenrealm.playerlimit");
			_harmonyInstance = _harmony;
			try
			{
				_harmony.PatchAll();
				Trace("PatchAll() succeeded");
			}
			catch (Exception arg)
			{
				Trace($"PatchAll() FAILED: {arg}");
				Logger.LogError((object)$"PatchAll FAILED: {arg}");
			}
			Application.quitting += OnQuitting;
			Logger.LogInfo((object)"Harmony patches applied!");
			Trace("Awake() DONE");
		}

		public static void UnpatchAll()
		{
			IsShuttingDown = true;
			ManualLogSource logger = Logger;
			if (logger != null)
			{
				logger.LogInfo((object)"Player Limit Mod: Shutting down");
			}
		}

		private void OnQuitting()
		{
			IsShuttingDown = true;
			Logger.LogInfo((object)"Player Limit Mod: Application quitting");
		}

		private void OnDestroy()
		{
			IsShuttingDown = true;
			Logger.LogInfo((object)"Player Limit Mod unloaded");
		}

		public static int GetMaxPlayers()
		{
			return MaxPlayers.Value;
		}

		private void Update()
		{
			if (!_updateTraced)
			{
				_updateTraced = true;
				Trace($"Update() FIRST CALL shutting={IsShuttingDown} playing={Application.isPlaying}");
			}
			if (IsShuttingDown || !Application.isPlaying)
			{
				return;
			}
			try
			{
				if (Input.GetKeyDown((KeyCode)290) && !_f9DumpDone)
				{
					_f9DumpDone = true;
					DumpFullSceneHierarchy();
				}
				if (Input.GetKeyDown((KeyCode)291) && !_f10DumpDone)
				{
					_f10DumpDone = true;
					DumpAllMonoBehaviourTypes();
				}
				if (Input.GetKeyDown((KeyCode)292))
				{
					_f9DumpDone = false;
					_f10DumpDone = false;
					PortraitExpander.Reset();
					Logger.LogInfo((object)"=== DUMP FLAGS RESET — Press F9/F10 again ===");
				}
				_frameSkip++;
				if (_frameSkip < 60)
				{
					return;
				}
				_frameSkip = 0;
				try
				{
					PortraitExpander.UpdateFromPlugin();
				}
				catch (Exception ex)
				{
					Logger.LogError((object)$"UpdateFromPlugin EXCEPTION: {ex}");
					try
					{
						File.AppendAllText(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "portrait_debug.log"), $"[{DateTime.Now:HH:mm:ss.fff}] OUTER EXCEPTION: {ex}\r\n");
					}
					catch
					{
					}
				}
			}
			catch (Exception ex2)
			{
				Logger.LogWarning((object)("Update error: " + ex2.Message));
			}
		}

		private void DumpFullSceneHierarchy()
		{
			//IL_0031: 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)
			Logger.LogInfo((object)"==========================================================");
			Logger.LogInfo((object)"=== F9: FULL SCENE HIERARCHY DUMP ===");
			Logger.LogInfo((object)"==========================================================");
			Scene activeScene = SceneManager.GetActiveScene();
			GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects();
			Logger.LogInfo((object)$"Root GameObjects in active scene: {rootGameObjects.Length}");
			GameObject[] array = rootGameObjects;
			foreach (GameObject val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					int maxDepth = ((((Object)val).name.ToLower().Contains("gui") || ((Object)val).name.ToLower().Contains("ui") || ((Object)val).name.ToLower().Contains("canvas")) ? 6 : 4);
					Logger.LogInfo((object)$"\n--- ROOT: '{((Object)val).name}' active={val.activeInHierarchy} children={val.transform.childCount} ---");
					DumpTransformRecursive(val.transform, 1, maxDepth);
				}
			}
			Logger.LogInfo((object)"=== END F9 SCENE HIERARCHY DUMP ===");
		}

		private void DumpTransformRecursive(Transform t, int depth, int maxDepth)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: 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)
			if (depth > maxDepth || (Object)(object)t == (Object)null)
			{
				return;
			}
			string text = new string(' ', depth * 2);
			for (int i = 0; i < t.childCount; i++)
			{
				Transform child = t.GetChild(i);
				if ((Object)(object)child == (Object)null)
				{
					continue;
				}
				RectTransform val = (RectTransform)(object)((child is RectTransform) ? child : null);
				string text2 = "";
				if ((Object)(object)val != (Object)null)
				{
					text2 = $" rect=({val.sizeDelta.x:F0},{val.sizeDelta.y:F0}) anchor=({val.anchorMin.x:F2},{val.anchorMin.y:F2})-({val.anchorMax.x:F2},{val.anchorMax.y:F2})";
				}
				Component[] components = ((Component)child).GetComponents<Component>();
				List<string> list = new List<string>();
				Component[] array = components;
				foreach (Component val2 in array)
				{
					if (!((Object)(object)val2 == (Object)null))
					{
						string name = ((object)val2).GetType().Name;
						if (name != "Transform" && name != "RectTransform")
						{
							list.Add(name);
						}
					}
				}
				string text3 = ((list.Count > 0) ? (" [" + string.Join(",", list) + "]") : "");
				Logger.LogInfo((object)$"{text}[{i}] '{((Object)child).name}' active={((Component)child).gameObject.activeInHierarchy} children={child.childCount}{text2}{text3}");
				DumpTransformRecursive(child, depth + 1, maxDepth);
			}
		}

		private void DumpAllMonoBehaviourTypes()
		{
			Logger.LogInfo((object)"==========================================================");
			Logger.LogInfo((object)"=== F10: ALL MONOBEHAVIOUR TYPES IN SCENE ===");
			Logger.LogInfo((object)"==========================================================");
			MonoBehaviour[] array = Object.FindObjectsOfType<MonoBehaviour>();
			Logger.LogInfo((object)$"Total MonoBehaviour instances: {array.Length}");
			SortedDictionary<string, List<string>> sortedDictionary = new SortedDictionary<string, List<string>>();
			MonoBehaviour[] array2 = array;
			foreach (MonoBehaviour val in array2)
			{
				if (!((Object)(object)val == (Object)null))
				{
					string fullName = ((object)val).GetType().FullName;
					if (!sortedDictionary.ContainsKey(fullName))
					{
						sortedDictionary[fullName] = new List<string>();
					}
					sortedDictionary[fullName].Add(((Object)((Component)val).gameObject).name);
				}
			}
			Logger.LogInfo((object)$"Unique MonoBehaviour types: {sortedDictionary.Count}");
			foreach (KeyValuePair<string, List<string>> item in sortedDictionary)
			{
				if (item.Value.Count <= 3)
				{
					Logger.LogInfo((object)string.Format("  {0} ({1}): {2}", item.Key, item.Value.Count, string.Join(", ", item.Value)));
				}
				else
				{
					Logger.LogInfo((object)string.Format("  {0} ({1}): {2}...", item.Key, item.Value.Count, string.Join(", ", item.Value.GetRange(0, 3))));
				}
			}
			Logger.LogInfo((object)"\n--- Types with potentially relevant names ---");
			string[] array3 = new string[14]
			{
				"portrait", "status", "hud", "panel", "bar", "frame", "character", "player", "unit", "health",
				"turn", "initiative", "party", "gui"
			};
			foreach (KeyValuePair<string, List<string>> item2 in sortedDictionary)
			{
				string text = item2.Key.ToLower();
				string[] array4 = array3;
				foreach (string value in array4)
				{
					if (!text.Contains(value))
					{
						continue;
					}
					Logger.LogInfo((object)$"  ** {item2.Key} ({item2.Value.Count})");
					foreach (string item3 in item2.Value)
					{
						MonoBehaviour[] array5 = array;
						foreach (MonoBehaviour val2 in array5)
						{
							if ((Object)(object)val2 != (Object)null && ((object)val2).GetType().FullName == item2.Key && ((Object)((Component)val2).gameObject).name == item3)
							{
								Logger.LogInfo((object)$"     on '{item3}' path={GetPath(((Component)val2).transform)} active={((Component)val2).gameObject.activeInHierarchy}");
								break;
							}
						}
					}
					break;
				}
			}
			Logger.LogInfo((object)"=== END F10 MONOBEHAVIOUR DUMP ===");
		}

		private static string GetPath(Transform t)
		{
			string text = ((Object)t).name;
			Transform parent = t.parent;
			int num = 0;
			while ((Object)(object)parent != (Object)null && num < 6)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
				num++;
			}
			return text;
		}
	}
	public static class ModInfo
	{
		public const string PLUGIN_GUID = "com.stolenrealm.playerlimit";

		public const string PLUGIN_NAME = "Player Limit Mod";

		public const string PLUGIN_VERSION = "1.1.0";
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "PlayerLimitMod";

		public const string PLUGIN_NAME = "PlayerLimitMod";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace PlayerLimitMod.Patches
{
	[HarmonyPatch]
	public static class PlayFabNetworkConfig_MaxPlayerCount_Patch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("PlayFabNetworkConfiguration");
			if (type == null)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)"PlayFabNetworkConfiguration type not found");
				return null;
			}
			return AccessTools.PropertyGetter(type, "MaxPlayerCount");
		}

		private static void Postfix(ref uint __result)
		{
			__result = (uint)PlayerLimitPlugin.MaxPlayers.Value;
		}
	}
	[HarmonyPatch]
	public static class PlayFabNetworkConfig_SetMaxPlayerCount_Patch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("PlayFabNetworkConfiguration");
			if (type == null)
			{
				return null;
			}
			return AccessTools.PropertySetter(type, "MaxPlayerCount");
		}

		private static bool Prefix(object __instance, uint value)
		{
			if (PlayerLimitPlugin.IsShuttingDown)
			{
				return true;
			}
			FieldInfo fieldInfo = AccessTools.Field(__instance.GetType(), "_maxPlayerCount");
			if (fieldInfo != null)
			{
				uint num = Math.Max(value, (uint)PlayerLimitPlugin.MaxPlayers.Value);
				fieldInfo.SetValue(__instance, num);
				PlayerLimitPlugin.Logger.LogDebug((object)$"Set _maxPlayerCount to {num}");
			}
			return false;
		}
	}
	[HarmonyPatch]
	public static class GlobalSettings_CharacterLimit_Patch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("GlobalSettings");
			if (type == null)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)"GlobalSettings type not found");
				return null;
			}
			return AccessTools.PropertyGetter(type, "CharacterLimit");
		}

		private static void Postfix(ref int __result)
		{
			int num = Math.Max(30, PlayerLimitPlugin.MaxPlayers.Value);
			if (__result < num)
			{
				PlayerLimitPlugin.Logger.LogDebug((object)$"GlobalSettings.CharacterLimit: {__result} -> {num}");
				__result = num;
			}
		}
	}
	[HarmonyPatch]
	public static class CharacterChoiceManager_Open_Patch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("CharacterChoiceManager");
			if (type == null)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)"CharacterChoiceManager type not found");
				return null;
			}
			return AccessTools.Method(type, "OpenCharacterChoiceManager", (Type[])null, (Type[])null);
		}

		private static void Postfix(object __instance)
		{
			CharacterChoiceHelper.SetPartyMax(__instance, "OpenCharacterChoiceManager");
		}
	}
	[HarmonyPatch]
	public static class CharacterChoiceManager_Start_Patch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("CharacterChoiceManager");
			if (type == null)
			{
				return null;
			}
			return AccessTools.Method(type, "Start", (Type[])null, (Type[])null);
		}

		private static void Postfix(object __instance)
		{
			CharacterChoiceHelper.SetPartyMax(__instance, "Start");
		}
	}
	[HarmonyPatch]
	public static class CharacterChoiceManager_Refresh_Patch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("CharacterChoiceManager");
			if (type == null)
			{
				return null;
			}
			return AccessTools.Method(type, "RefreshCharacters", (Type[])null, (Type[])null);
		}

		private static void Prefix(object __instance)
		{
			CharacterChoiceHelper.SetPartyMax(__instance, "RefreshCharacters");
			CharacterChoiceHelper.ExpandPartySlots(__instance);
		}
	}
	[HarmonyPatch]
	public static class CharacterChoiceManager_RefreshPostfix_Patch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("CharacterChoiceManager");
			if (type == null)
			{
				return null;
			}
			return AccessTools.Method(type, "RefreshCharacters", (Type[])null, (Type[])null);
		}

		private static void Postfix(object __instance)
		{
			try
			{
				FieldInfo fieldInfo = AccessTools.Field(__instance.GetType(), "partySlots");
				if (fieldInfo == null || !(fieldInfo.GetValue(__instance) is IList partySlots))
				{
					return;
				}
				object obj = AccessTools.Field(__instance.GetType(), "partyChars")?.GetValue(__instance);
				int activeCharCount = 0;
				if (obj != null)
				{
					PropertyInfo property = obj.GetType().GetProperty("Count");
					if (property != null)
					{
						activeCharCount = (int)property.GetValue(obj);
					}
				}
				object? obj2 = AccessTools.Field(__instance.GetType(), "partyHolder")?.GetValue(__instance);
				Transform partyHolder = (Transform)((obj2 is Transform) ? obj2 : null);
				PartyPanelPager.ApplyPagination(partySlots, activeCharCount, partyHolder);
			}
			catch (Exception ex)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)("RefreshCharacters Postfix error: " + ex.Message));
			}
		}
	}
	[HarmonyPatch]
	public static class CharacterChoiceManager_Update_Patch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("CharacterChoiceManager");
			if (type == null)
			{
				return null;
			}
			return AccessTools.Method(type, "Update", (Type[])null, (Type[])null);
		}

		private static void Postfix(object __instance)
		{
			if (PlayerLimitPlugin.IsShuttingDown)
			{
				return;
			}
			try
			{
				FieldInfo fieldInfo = AccessTools.Field(__instance.GetType(), "partyChars");
				if (fieldInfo == null)
				{
					return;
				}
				object value = fieldInfo.GetValue(__instance);
				if (value == null)
				{
					return;
				}
				PropertyInfo property = value.GetType().GetProperty("Count");
				int num = (int)property.GetValue(value);
				if (num <= 0)
				{
					return;
				}
				FieldInfo fieldInfo2 = AccessTools.Field(__instance.GetType(), "acceptBtn");
				if (!(fieldInfo2 == null))
				{
					object? value2 = fieldInfo2.GetValue(__instance);
					Button val = (Button)((value2 is Button) ? value2 : null);
					if ((Object)(object)val != (Object)null && !((Selectable)val).interactable)
					{
						((Selectable)val).interactable = true;
					}
				}
			}
			catch (Exception ex)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)("CharacterChoiceManager_Update_Patch error: " + ex.Message));
			}
		}
	}
	public static class PartyPanelPager
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__24_0;

			public static UnityAction <>9__24_1;

			internal void <CreateUI>b__24_0()
			{
				PrevPage();
			}

			internal void <CreateUI>b__24_1()
			{
				NextPage();
			}
		}

		private const int SLOTS_PER_PAGE = 6;

		private static int _currentPage;

		private static int _totalActiveSlots;

		private static IList _cachedSlots;

		private static Transform _cachedHolder;

		private static GameObject _partyCounterGO;

		private static GameObject _pageIndicatorGO;

		private static GameObject _prevBtnGO;

		private static GameObject _nextBtnGO;

		private static TextMeshProUGUI _partyCounterText;

		private static TextMeshProUGUI _pageText;

		private static Button _prevBtn;

		private static Button _nextBtn;

		private static TMP_FontAsset _gameFont;

		private static bool _uiCreated;

		private static Sprite _arrowLeftSprite;

		private static Sprite _arrowRightSprite;

		public static void ApplyPagination(IList partySlots, int activeCharCount, Transform partyHolder)
		{
			_cachedSlots = partySlots;
			_totalActiveSlots = activeCharCount;
			if ((Object)(object)partyHolder != (Object)null)
			{
				_cachedHolder = partyHolder;
			}
			if ((Object)(object)_cachedHolder != (Object)null && !_uiCreated)
			{
				CreateUI(_cachedHolder);
			}
			UpdatePartyCounter();
			if (activeCharCount <= 6)
			{
				_currentPage = 0;
				HideNav();
				return;
			}
			int totalPages = GetTotalPages();
			if (_currentPage >= totalPages)
			{
				_currentPage = totalPages - 1;
			}
			if (_currentPage < 0)
			{
				_currentPage = 0;
			}
			int num = _currentPage * 6;
			int num2 = num + 6;
			for (int i = 0; i < partySlots.Count; i++)
			{
				object? obj = partySlots[i];
				Component val = (Component)((obj is Component) ? obj : null);
				if (!((Object)(object)val == (Object)null))
				{
					if (i < activeCharCount)
					{
						bool active = i >= num && i < num2;
						val.gameObject.SetActive(active);
					}
					else
					{
						val.gameObject.SetActive(false);
					}
				}
			}
			UpdateNavDisplay();
			UpdatePartyCounter();
			PlayerLimitPlugin.Logger.LogDebug((object)$"PartyPanelPager: page {_currentPage + 1}/{totalPages}, slots {num}-{Math.Min(num2, activeCharCount) - 1} of {activeCharCount}");
		}

		public static void NextPage()
		{
			if (_currentPage < GetTotalPages() - 1)
			{
				_currentPage++;
				if (_cachedSlots != null)
				{
					ApplyPagination(_cachedSlots, _totalActiveSlots, null);
				}
			}
		}

		public static void PrevPage()
		{
			if (_currentPage > 0)
			{
				_currentPage--;
				if (_cachedSlots != null)
				{
					ApplyPagination(_cachedSlots, _totalActiveSlots, null);
				}
			}
		}

		private static int GetTotalPages()
		{
			return Math.Max(1, (int)Math.Ceiling((double)_totalActiveSlots / 6.0));
		}

		private static TMP_FontAsset FindGameFont(Transform searchRoot)
		{
			if ((Object)(object)_gameFont != (Object)null)
			{
				return _gameFont;
			}
			TextMeshProUGUI[] componentsInChildren = ((Component)searchRoot).GetComponentsInChildren<TextMeshProUGUI>(true);
			TextMeshProUGUI[] array = componentsInChildren;
			foreach (TextMeshProUGUI val in array)
			{
				if ((Object)(object)((TMP_Text)val).font != (Object)null)
				{
					_gameFont = ((TMP_Text)val).font;
					PlayerLimitPlugin.Logger.LogInfo((object)("PartyPanelPager: Using font '" + ((Object)_gameFont).name + "' from '" + ((Object)((Component)val).gameObject).name + "'"));
					return _gameFont;
				}
			}
			PlayerLimitPlugin.Logger.LogWarning((object)"PartyPanelPager: No TMP font found in hierarchy");
			return null;
		}

		private static void LoadArrowSprites()
		{
			if ((Object)(object)_arrowLeftSprite != (Object)null)
			{
				return;
			}
			try
			{
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				_arrowLeftSprite = LoadSpriteFromResource(executingAssembly, "arrow_left.png");
				_arrowRightSprite = LoadSpriteFromResource(executingAssembly, "arrow_right.png");
				PlayerLimitPlugin.Logger.LogInfo((object)$"PartyPanelPager: Arrow sprites loaded (left={(Object)(object)_arrowLeftSprite != (Object)null}, right={(Object)(object)_arrowRightSprite != (Object)null})");
			}
			catch (Exception ex)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)("PartyPanelPager: Failed to load arrow sprites: " + ex.Message));
			}
		}

		private static Sprite LoadSpriteFromResource(Assembly asm, string resourceName)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			using Stream stream = asm.GetManifestResourceStream(resourceName);
			if (stream == null)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)("Embedded resource '" + resourceName + "' not found"));
				return null;
			}
			byte[] array = new byte[stream.Length];
			stream.Read(array, 0, array.Length);
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			ImageConversion.LoadImage(val, array);
			((Texture)val).filterMode = (FilterMode)1;
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
		}

		private static void CreateUI(Transform partyHolder)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Expected O, but got Unknown
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Expected O, but got Unknown
			Transform parent = partyHolder.parent;
			if ((Object)(object)parent == (Object)null)
			{
				return;
			}
			_uiCreated = true;
			FindGameFont(parent);
			LoadArrowSprites();
			_partyCounterGO = CreateDarkBox(parent, "PartyCounter", "Party: 0/16", (TextAlignmentOptions)4097, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(100f, 22f), new Vector2(5f, -2f));
			_partyCounterText = _partyCounterGO.GetComponentInChildren<TextMeshProUGUI>();
			_pageIndicatorGO = CreateDarkBox(parent, "PageIndicator", "Page 1/1", (TextAlignmentOptions)4100, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(90f, 22f), new Vector2(-5f, -2f));
			_pageText = _pageIndicatorGO.GetComponentInChildren<TextMeshProUGUI>();
			Sprite arrowLeftSprite = _arrowLeftSprite;
			object obj = <>c.<>9__24_0;
			if (obj == null)
			{
				UnityAction val = delegate
				{
					PrevPage();
				};
				<>c.<>9__24_0 = val;
				obj = (object)val;
			}
			_prevBtnGO = CreateSpriteButton(parent, "PrevPage", arrowLeftSprite, (UnityAction)obj, new Vector2(0.35f, 1f), new Vector2(0.35f, 1f), new Vector2(1f, 1f), new Vector2(-5f, -2f));
			_prevBtn = _prevBtnGO.GetComponent<Button>();
			Sprite arrowRightSprite = _arrowRightSprite;
			object obj2 = <>c.<>9__24_1;
			if (obj2 == null)
			{
				UnityAction val2 = delegate
				{
					NextPage();
				};
				<>c.<>9__24_1 = val2;
				obj2 = (object)val2;
			}
			_nextBtnGO = CreateSpriteButton(parent, "NextPage", arrowRightSprite, (UnityAction)obj2, new Vector2(0.65f, 1f), new Vector2(0.65f, 1f), new Vector2(0f, 1f), new Vector2(5f, -2f));
			_nextBtn = _nextBtnGO.GetComponent<Button>();
			PlayerLimitPlugin.Logger.LogInfo((object)"PartyPanelPager: UI created with sprite arrow buttons");
		}

		private static GameObject CreateDarkBox(Transform parent, string name, string text, TextAlignmentOptions alignment, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 size, Vector2 position)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: 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)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			RectTransform val2 = val.AddComponent<RectTransform>();
			val2.anchorMin = anchorMin;
			val2.anchorMax = anchorMax;
			val2.pivot = pivot;
			val2.sizeDelta = size;
			val2.anchoredPosition = position;
			Image val3 = val.AddComponent<Image>();
			((Graphic)val3).color = new Color(0.08f, 0.07f, 0.06f, 0.85f);
			GameObject val4 = new GameObject("Text");
			val4.transform.SetParent(val.transform, false);
			RectTransform val5 = val4.AddComponent<RectTransform>();
			val5.anchorMin = Vector2.zero;
			val5.anchorMax = Vector2.one;
			val5.offsetMin = new Vector2(6f, 2f);
			val5.offsetMax = new Vector2(-6f, -2f);
			TextMeshProUGUI val6 = val4.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val6).text = text;
			if ((Object)(object)_gameFont != (Object)null)
			{
				((TMP_Text)val6).font = _gameFont;
			}
			((TMP_Text)val6).fontSize = 13f;
			((Graphic)val6).color = new Color(0.9f, 0.85f, 0.7f);
			((TMP_Text)val6).alignment = alignment;
			((TMP_Text)val6).enableAutoSizing = false;
			((TMP_Text)val6).overflowMode = (TextOverflowModes)0;
			return val;
		}

		private static GameObject CreateSpriteButton(Transform parent, string name, Sprite sprite, UnityAction onClick, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 position)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: 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_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			RectTransform val2 = val.AddComponent<RectTransform>();
			val2.anchorMin = anchorMin;
			val2.anchorMax = anchorMax;
			val2.pivot = pivot;
			val2.sizeDelta = new Vector2(56f, 22f);
			val2.anchoredPosition = position;
			Image val3 = val.AddComponent<Image>();
			if ((Object)(object)sprite != (Object)null)
			{
				val3.sprite = sprite;
				val3.type = (Type)0;
				val3.preserveAspect = true;
			}
			else
			{
				((Graphic)val3).color = new Color(0.12f, 0.1f, 0.08f, 0.9f);
			}
			Button val4 = val.AddComponent<Button>();
			((Selectable)val4).targetGraphic = (Graphic)(object)val3;
			ColorBlock colors = ((Selectable)val4).colors;
			((ColorBlock)(ref colors)).normalColor = Color.white;
			((ColorBlock)(ref colors)).highlightedColor = new Color(1f, 0.9f, 0.7f, 1f);
			((ColorBlock)(ref colors)).pressedColor = new Color(0.7f, 0.6f, 0.4f, 1f);
			((ColorBlock)(ref colors)).disabledColor = new Color(0.4f, 0.4f, 0.4f, 0.5f);
			((Selectable)val4).colors = colors;
			((UnityEvent)val4.onClick).AddListener(onClick);
			return val;
		}

		private static void UpdatePartyCounter()
		{
			if ((Object)(object)_partyCounterText != (Object)null)
			{
				((TMP_Text)_partyCounterText).text = $"Party: {_totalActiveSlots}/{PlayerLimitPlugin.MaxPlayers.Value}";
			}
			if ((Object)(object)_partyCounterGO != (Object)null)
			{
				_partyCounterGO.SetActive(true);
			}
		}

		private static void UpdateNavDisplay()
		{
			int totalPages = GetTotalPages();
			bool active = totalPages > 1;
			if ((Object)(object)_pageText != (Object)null)
			{
				((TMP_Text)_pageText).text = $"Page {_currentPage + 1}/{totalPages}";
			}
			if ((Object)(object)_prevBtn != (Object)null)
			{
				((Selectable)_prevBtn).interactable = _currentPage > 0;
			}
			if ((Object)(object)_nextBtn != (Object)null)
			{
				((Selectable)_nextBtn).interactable = _currentPage < totalPages - 1;
			}
			if ((Object)(object)_prevBtnGO != (Object)null)
			{
				_prevBtnGO.SetActive(active);
			}
			if ((Object)(object)_nextBtnGO != (Object)null)
			{
				_nextBtnGO.SetActive(active);
			}
			if ((Object)(object)_pageIndicatorGO != (Object)null)
			{
				_pageIndicatorGO.SetActive(active);
			}
		}

		private static void HideNav()
		{
			if ((Object)(object)_prevBtnGO != (Object)null)
			{
				_prevBtnGO.SetActive(false);
			}
			if ((Object)(object)_nextBtnGO != (Object)null)
			{
				_nextBtnGO.SetActive(false);
			}
			if ((Object)(object)_pageIndicatorGO != (Object)null)
			{
				_pageIndicatorGO.SetActive(false);
			}
		}

		public static void ResetState()
		{
			if ((Object)(object)_partyCounterGO != (Object)null)
			{
				Object.Destroy((Object)(object)_partyCounterGO);
			}
			if ((Object)(object)_pageIndicatorGO != (Object)null)
			{
				Object.Destroy((Object)(object)_pageIndicatorGO);
			}
			if ((Object)(object)_prevBtnGO != (Object)null)
			{
				Object.Destroy((Object)(object)_prevBtnGO);
			}
			if ((Object)(object)_nextBtnGO != (Object)null)
			{
				Object.Destroy((Object)(object)_nextBtnGO);
			}
			_partyCounterGO = null;
			_pageIndicatorGO = null;
			_prevBtnGO = null;
			_nextBtnGO = null;
			_partyCounterText = null;
			_pageText = null;
			_prevBtn = null;
			_nextBtn = null;
			_uiCreated = false;
			_currentPage = 0;
			_totalActiveSlots = 0;
			_cachedSlots = null;
			_cachedHolder = null;
		}
	}
	[HarmonyPatch]
	public static class CharacterChoiceManager_LimitReached_Patch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("CharacterChoiceManager");
			if (type == null)
			{
				return null;
			}
			return AccessTools.PropertyGetter(type, "characterLimitReached");
		}

		private static void Postfix(ref bool __result)
		{
			if (__result)
			{
				__result = false;
				PlayerLimitPlugin.Logger.LogDebug((object)"characterLimitReached: forced false (creation always allowed)");
			}
		}
	}
	[HarmonyPatch]
	public static class CharacterChoiceManager_CanAdd_Patch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("CharacterChoiceManager");
			if (type == null)
			{
				return null;
			}
			return AccessTools.PropertyGetter(type, "CanAddCharacter");
		}

		private static void Postfix(object __instance, ref bool __result)
		{
			if (__result)
			{
				return;
			}
			try
			{
				FieldInfo fieldInfo = AccessTools.Field(__instance.GetType(), "partyChars");
				if (!(fieldInfo != null))
				{
					return;
				}
				object value = fieldInfo.GetValue(__instance);
				if (value != null)
				{
					PropertyInfo property = value.GetType().GetProperty("Count");
					int num = (int)property.GetValue(value);
					if (num < PlayerLimitPlugin.MaxPlayers.Value)
					{
						__result = true;
						PlayerLimitPlugin.Logger.LogDebug((object)$"CanAddCharacter override: false -> true (count={num}, max={PlayerLimitPlugin.MaxPlayers.Value})");
					}
				}
			}
			catch (Exception ex)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)("CanAddCharacter patch error: " + ex.Message));
			}
		}
	}
	[HarmonyPatch]
	public static class CharacterChoiceManager_ToggleSelectedCharacter_Patch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("CharacterChoiceManager");
			if (type == null)
			{
				return null;
			}
			return AccessTools.Method(type, "ToggleSelectedCharacter", new Type[1] { typeof(int) }, (Type[])null);
		}

		private static void Prefix(object __instance)
		{
			CharacterChoiceHelper.SetPartyMax(__instance, "ToggleSelectedCharacter");
		}
	}
	public static class CharacterChoiceHelper
	{
		public static void SetPartyMax(object instance, string source)
		{
			try
			{
				FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), "partyMax");
				if (fieldInfo != null)
				{
					int num = (int)fieldInfo.GetValue(instance);
					int value = PlayerLimitPlugin.MaxPlayers.Value;
					if (num < value)
					{
						fieldInfo.SetValue(instance, value);
						PlayerLimitPlugin.Logger.LogInfo((object)$"[{source}] partyMax: {num} -> {value}");
					}
				}
				FieldInfo fieldInfo2 = AccessTools.Field(instance.GetType(), "maxCharacterLimitText");
				if (!(fieldInfo2 != null))
				{
					return;
				}
				object value2 = fieldInfo2.GetValue(instance);
				if (value2 == null)
				{
					return;
				}
				PropertyInfo property = value2.GetType().GetProperty("text");
				if (property != null)
				{
					string text = (string)property.GetValue(value2);
					if (text != null && text.Contains("6"))
					{
						property.SetValue(value2, text.Replace("6", PlayerLimitPlugin.MaxPlayers.Value.ToString()));
					}
				}
			}
			catch (Exception ex)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)("SetPartyMax [" + source + "]: " + ex.Message));
			}
		}

		public static void ExpandPartySlots(object instance)
		{
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), "partySlots");
				if (fieldInfo == null || !(fieldInfo.GetValue(instance) is IList list) || list.Count == 0)
				{
					return;
				}
				int value = PlayerLimitPlugin.MaxPlayers.Value;
				if (list.Count >= value)
				{
					return;
				}
				FieldInfo fieldInfo2 = AccessTools.Field(instance.GetType(), "characterChoicePrefab");
				FieldInfo fieldInfo3 = AccessTools.Field(instance.GetType(), "partyHolder");
				if (fieldInfo2 == null || fieldInfo3 == null)
				{
					return;
				}
				object? value2 = fieldInfo2.GetValue(instance);
				Component val = (Component)((value2 is Component) ? value2 : null);
				object? value3 = fieldInfo3.GetValue(instance);
				Transform val2 = (Transform)((value3 is Transform) ? value3 : null);
				if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
				{
					return;
				}
				int count = list.Count;
				for (int i = count; i < value; i++)
				{
					GameObject val3 = Object.Instantiate<GameObject>(val.gameObject, val2);
					val3.transform.localScale = Vector3.one;
					val3.SetActive(false);
					Component component = val3.GetComponent(((object)val).GetType());
					if ((Object)(object)component != (Object)null)
					{
						list.Add(component);
					}
				}
				FieldInfo fieldInfo4 = AccessTools.Field(instance.GetType(), "allSlots");
				if (fieldInfo4 != null)
				{
					fieldInfo4.SetValue(instance, null);
				}
				PlayerLimitPlugin.Logger.LogInfo((object)$"ExpandPartySlots: {count} -> {list.Count} slots");
			}
			catch (Exception ex)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)("ExpandPartySlots error: " + ex.Message));
			}
		}
	}
	[HarmonyPatch]
	public static class PartyNetworkConfig_Patch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("PlayFab.Party.PlayFabMultiplayerManager");
			if (type == null)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)"PlayFabMultiplayerManager type not found");
				return null;
			}
			return AccessTools.Method(type, "Awake", (Type[])null, (Type[])null);
		}

		private static void Postfix(object __instance)
		{
			PlayerLimitPlugin.Logger.LogInfo((object)"PlayFabMultiplayerManager initialized - player limit mod active");
			try
			{
				uint num = (uint)Math.Max(1, PlayerLimitPlugin.MaxPlayers.Value);
				bool flag = false;
				Type type = AccessTools.TypeByName("PlayFab.Party.PARTY_NETWORK_CONFIGURATION");
				if (type != null)
				{
					FieldInfo fieldInfo = AccessTools.Field(type, "maxUserCount");
					if (fieldInfo != null)
					{
						fieldInfo.SetValue(null, num);
						flag = true;
					}
				}
				if (!flag && __instance != null)
				{
					FieldInfo[] fields = __instance.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					FieldInfo[] array = fields;
					foreach (FieldInfo fieldInfo2 in array)
					{
						object value = fieldInfo2.GetValue(__instance);
						if (value == null)
						{
							continue;
						}
						FieldInfo fieldInfo3 = AccessTools.Field(value.GetType(), "maxUserCount");
						if (fieldInfo3 == null)
						{
							continue;
						}
						if (fieldInfo3.FieldType == typeof(uint))
						{
							fieldInfo3.SetValue(value, num);
						}
						else
						{
							if (!(fieldInfo3.FieldType == typeof(int)))
							{
								continue;
							}
							fieldInfo3.SetValue(value, (int)num);
						}
						if (fieldInfo2.FieldType.IsValueType)
						{
							fieldInfo2.SetValue(__instance, value);
						}
						flag = true;
						break;
					}
				}
				PlayerLimitPlugin.Logger.LogInfo((object)(flag ? $"Party network maxUserCount patched to {num}" : "Party network maxUserCount field not found; relying on MaxPlayerCount patches"));
			}
			catch (Exception ex)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)("Party network config patch failed (non-fatal): " + ex.Message));
			}
		}
	}
	[HarmonyPatch]
	public static class SteamLobby_Size_Transpiler
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("MainMenu");
			if (type == null)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)"SteamLobby_Size_Transpiler: MainMenu type not found");
				return null;
			}
			Type[] nestedTypes = type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic);
			foreach (Type type2 in nestedTypes)
			{
				if (type2.Name.Contains("<CreateSteamLobby>"))
				{
					MethodInfo methodInfo = AccessTools.Method(type2, "MoveNext", (Type[])null, (Type[])null);
					if (methodInfo != null)
					{
						PlayerLimitPlugin.Logger.LogInfo((object)("SteamLobby_Size_Transpiler: Found state machine " + type2.FullName));
						return methodInfo;
					}
				}
			}
			PlayerLimitPlugin.Logger.LogWarning((object)"SteamLobby_Size_Transpiler: CreateSteamLobby state machine not found");
			return null;
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			MethodInfo methodInfo = AccessTools.Method(typeof(PlayerLimitPlugin), "GetMaxPlayers", (Type[])null, (Type[])null);
			int num = 0;
			for (int i = 0; i < list.Count; i++)
			{
				if (list[i].opcode == OpCodes.Ldc_I4_6)
				{
					list[i] = new CodeInstruction(OpCodes.Call, (object)methodInfo);
					num++;
				}
			}
			PlayerLimitPlugin.Logger.LogInfo((object)$"SteamLobby_Size_Transpiler: Replaced {num} instances of ldc.i4.6 with GetMaxPlayers()");
			return list;
		}
	}
	[HarmonyPatch]
	public static class PlayFabLobby_CreateAndJoin_Patch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("PlayFab.Multiplayer.PlayFabMultiplayer");
			if (type == null)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)"PlayFabLobby_CreateAndJoin_Patch: PlayFabMultiplayer type not found");
				return null;
			}
			MethodInfo[] array = (from m in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
				where m.Name == "CreateAndJoinLobby" && m.GetParameters().Length == 3
				select m).ToArray();
			if (array.Length == 1)
			{
				PlayerLimitPlugin.Logger.LogInfo((object)"PlayFabLobby_CreateAndJoin_Patch: Found CreateAndJoinLobby (3 params)");
				return array[0];
			}
			if (array.Length > 1)
			{
				PlayerLimitPlugin.Logger.LogInfo((object)$"PlayFabLobby_CreateAndJoin_Patch: Found {array.Length} overloads with 3 params, using first");
				return array[0];
			}
			MethodInfo[] array2 = (from m in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
				where m.Name == "CreateAndJoinLobby"
				select m).ToArray();
			if (array2.Length != 0)
			{
				PlayerLimitPlugin.Logger.LogInfo((object)$"PlayFabLobby_CreateAndJoin_Patch: Using first of {array2.Length} overloads ({array2[0].GetParameters().Length} params)");
				return array2[0];
			}
			PlayerLimitPlugin.Logger.LogWarning((object)"PlayFabLobby_CreateAndJoin_Patch: CreateAndJoinLobby method not found");
			return null;
		}

		private static void Prefix(object __1)
		{
			if (__1 == null)
			{
				return;
			}
			try
			{
				uint value = (uint)PlayerLimitPlugin.MaxPlayers.Value;
				PropertyInfo propertyInfo = AccessTools.Property(__1.GetType(), "MaxMemberCount");
				if (propertyInfo != null)
				{
					propertyInfo.SetValue(__1, value);
					PlayerLimitPlugin.Logger.LogInfo((object)$"PlayFab lobby MaxMemberCount set to {value}");
					return;
				}
				FieldInfo fieldInfo = AccessTools.Field(__1.GetType(), "MaxMemberCount");
				if (fieldInfo != null)
				{
					fieldInfo.SetValue(__1, value);
					PlayerLimitPlugin.Logger.LogInfo((object)$"PlayFab lobby MaxMemberCount set to {value}");
				}
			}
			catch (Exception ex)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)("PlayFab lobby MaxMemberCount patch error: " + ex.Message));
			}
		}
	}
	[HarmonyPatch]
	public static class Root_PlayerColor_Patch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("Root");
			if (type == null)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)"Root_PlayerColor_Patch: Root type not found");
				return null;
			}
			return AccessTools.Method(type, "GetPlayerControllerColor", new Type[2]
			{
				typeof(int),
				typeof(int)
			}, (Type[])null);
		}

		private static bool Prefix(object __instance, int owner, int controllerPlayerId, ref Color __result)
		{
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PropertyInfo propertyInfo = AccessTools.Property(__instance.GetType(), "ActiveConnections");
				if (propertyInfo == null)
				{
					return true;
				}
				if (!(propertyInfo.GetValue(__instance) is IDictionary dictionary))
				{
					return true;
				}
				int num = 0;
				foreach (object key in dictionary.Keys)
				{
					if (key is int num2 && num2 < owner)
					{
						num++;
					}
				}
				Type type = AccessTools.TypeByName("GUIManager");
				if (type == null)
				{
					return true;
				}
				object obj = AccessTools.PropertyGetter(type, "instance")?.Invoke(null, null);
				if (obj == null)
				{
					return true;
				}
				FieldInfo fieldInfo = AccessTools.Field(type, "ConnectionColors");
				if (fieldInfo == null)
				{
					return true;
				}
				if (!(fieldInfo.GetValue(obj) is Color[] array))
				{
					return true;
				}
				int num3 = num * 6 + controllerPlayerId;
				if (num3 >= 0 && num3 < array.Length)
				{
					__result = array[num3];
				}
				else
				{
					float num4 = (float)num3 * 0.618034f % 1f;
					__result = Color.HSVToRGB(num4, 0.65f, 0.95f);
				}
				return false;
			}
			catch
			{
				return true;
			}
		}
	}
	[HarmonyPatch]
	public static class MainMenu_LobbyFull_Patch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("MainMenu");
			if (type == null)
			{
				return null;
			}
			return AccessTools.PropertyGetter(type, "EitherLobbyIsFull");
		}

		private static void Postfix(ref bool __result)
		{
			if (__result && PlayerLimitPlugin.MaxPlayers.Value > 6)
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch]
	public static class MainMenu_ExitGame_Patch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("MainMenu");
			if (type == null)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)"MainMenu type not found for ExitGame patch");
				return null;
			}
			return AccessTools.Method(type, "ExitGame", (Type[])null, (Type[])null);
		}

		private static bool Prefix()
		{
			PlayerLimitPlugin.Logger.LogInfo((object)"ExitGame intercepted — setting shutdown flag");
			PlayerLimitPlugin.IsShuttingDown = true;
			return true;
		}
	}
	[HarmonyPatch]
	public static class BattleManager_Placement_Patch
	{
		private static bool _radiusSet;

		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("BattleManager");
			if (type == null)
			{
				return null;
			}
			return AccessTools.PropertyGetter(type, "instance");
		}

		private static void Postfix(object __result)
		{
			if (PlayerLimitPlugin.IsShuttingDown || __result == null || _radiusSet || !Application.isPlaying)
			{
				return;
			}
			try
			{
				int value = PlayerLimitPlugin.MaxPlayers.Value;
				if (value <= 6)
				{
					return;
				}
				FieldInfo fieldInfo = AccessTools.Field(__result.GetType(), "PlayerPlacementRadius");
				if (fieldInfo != null)
				{
					int num = (int)fieldInfo.GetValue(__result);
					int num2 = Math.Max(num, (int)Math.Ceiling((double)value / 3.0));
					if (num < num2)
					{
						fieldInfo.SetValue(__result, num2);
						PlayerLimitPlugin.Logger.LogDebug((object)$"PlayerPlacementRadius: {num} -> {num2}");
						_radiusSet = true;
					}
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch]
	public static class PortraitManager_UpdatePortraits_Patch
	{
		private static Type _pmType;

		private static Type _nmType;

		private static FieldInfo _portraitsField;

		private static MethodInfo _nmInstanceGetter;

		private static MethodInfo _partyCharsGetter;

		private static PropertyInfo _charPropCache;

		private static bool _cached;

		private static bool _failed;

		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("PortraitManager");
			if (type == null)
			{
				return null;
			}
			return AccessTools.Method(type, "UpdatePortraits", (Type[])null, (Type[])null);
		}

		private static void CacheOnce()
		{
			if (_cached || _failed)
			{
				return;
			}
			_cached = true;
			_pmType = AccessTools.TypeByName("PortraitManager");
			_nmType = AccessTools.TypeByName("NetworkingManager");
			if (_pmType == null || _nmType == null)
			{
				_failed = true;
				return;
			}
			_portraitsField = AccessTools.Field(_pmType, "portraits");
			_nmInstanceGetter = AccessTools.PropertyGetter(_nmType, "Instance");
			_partyCharsGetter = AccessTools.PropertyGetter(_nmType, "PartyCharacters");
			Type type = AccessTools.TypeByName("Portrait");
			if (type != null)
			{
				_charPropCache = type.GetProperty("Character");
			}
			if (_portraitsField == null || _nmInstanceGetter == null || _partyCharsGetter == null)
			{
				_failed = true;
				PlayerLimitPlugin.Logger.LogWarning((object)("UpdatePortraits_Patch: cache failed - " + $"portraits={_portraitsField != null}, nmInstance={_nmInstanceGetter != null}, partyChars={_partyCharsGetter != null}"));
			}
		}

		private static bool Prefix(object __instance)
		{
			try
			{
				CacheOnce();
				if (_failed)
				{
					return true;
				}
				object obj = _nmInstanceGetter.Invoke(null, null);
				if (obj == null)
				{
					return false;
				}
				object obj2 = _partyCharsGetter.Invoke(obj, null);
				if (obj2 == null)
				{
					return false;
				}
				if (!(obj2 is IList list))
				{
					return false;
				}
				if (!(_portraitsField.GetValue(__instance) is Array array) || array.Length == 0)
				{
					return false;
				}
				int count = list.Count;
				for (int i = 0; i < array.Length; i++)
				{
					object? value = array.GetValue(i);
					Component val = (Component)((value is Component) ? value : null);
					if ((Object)(object)val == (Object)null || i >= count)
					{
						continue;
					}
					object obj3 = list[i];
					if (_charPropCache != null)
					{
						object value2 = _charPropCache.GetValue(val);
						if (value2 != obj3)
						{
							_charPropCache.SetValue(val, obj3);
						}
					}
				}
				PortraitExpander.ApplyPagination(array, count);
				return false;
			}
			catch (Exception ex)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)("UpdatePortraits patch error: " + ex.Message));
				return true;
			}
		}
	}
	[HarmonyPatch]
	public static class BattleManager_CheckBattleDrops_Patch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("BattleManager");
			if (type == null)
			{
				return null;
			}
			return AccessTools.Method(type, "CheckBattleDrops", (Type[])null, (Type[])null);
		}

		private static bool Prefix(object __instance, int newTurnNumber)
		{
			try
			{
				Type type = __instance.GetType();
				FieldInfo fieldInfo = AccessTools.Field(type, "BattleDropTurnStart");
				FieldInfo fieldInfo2 = AccessTools.Field(type, "BattleDropTurnDelay");
				FieldInfo fieldInfo3 = AccessTools.Field(type, "BattleDropSpawnCountPerPlayer");
				if (fieldInfo == null || fieldInfo2 == null || fieldInfo3 == null)
				{
					return true;
				}
				int num = (int)fieldInfo.GetValue(__instance);
				int num2 = (int)fieldInfo2.GetValue(__instance);
				if (newTurnNumber < num * 2 || newTurnNumber % (num2 * 2) != 0)
				{
					return false;
				}
				if (!(fieldInfo3.GetValue(__instance) is int[] array) || array.Length == 0)
				{
					return false;
				}
				Type type2 = AccessTools.TypeByName("NetworkingManager");
				object obj = AccessTools.PropertyGetter(type2, "Instance")?.Invoke(null, null);
				if (obj == null)
				{
					return false;
				}
				if (!(AccessTools.PropertyGetter(type2, "PartyCharacters")?.Invoke(obj, null) is IList list) || list.Count == 0)
				{
					return false;
				}
				int num3 = Math.Min(list.Count - 1, array.Length - 1);
				int num4 = array[num3];
				MethodInfo methodInfo = AccessTools.Method(type, "SpawnPickups", (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					methodInfo.Invoke(__instance, new object[3] { list, newTurnNumber, num4 });
				}
				return false;
			}
			catch (Exception ex)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)("CheckBattleDrops patch error: " + ex.Message));
				return true;
			}
		}
	}
	public static class PortraitExpander
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__35_0;

			public static UnityAction <>9__35_1;

			internal void <CreateArrowUI>b__35_0()
			{
				PrevPage();
			}

			internal void <CreateArrowUI>b__35_1()
			{
				NextPage();
			}
		}

		private const int PORTRAITS_PER_PAGE = 6;

		private static bool _expanded = false;

		private static int _lastCharCount = -1;

		private static bool _loggedOnce = false;

		private static string _lastScene = "";

		private static List<GameObject> _clonedPortraits = new List<GameObject>();

		private static int _originalPortraitCount = -1;

		private static int _currentPage = 0;

		private static int _totalChars = 0;

		private static GameObject _upArrowGO;

		private static GameObject _downArrowGO;

		private static Button _upArrowBtn;

		private static Button _downArrowBtn;

		private static bool _arrowsCreated = false;

		private static Sprite _arrowUpSprite;

		private static Sprite _arrowDownSprite;

		private static Type _portraitMgrType;

		private static Type _portraitType;

		private static FieldInfo _portraitsField;

		private static FieldInfo _vlgField;

		private static FieldInfo _portraitCharField;

		private static MethodInfo _pmInstanceGetter;

		private static bool _reflectionCached = false;

		private static void DebugLog(string msg)
		{
			PlayerLimitPlugin.Trace("[Portrait] " + msg);
		}

		private static void CacheReflection()
		{
			if (!_reflectionCached)
			{
				_portraitMgrType = AccessTools.TypeByName("PortraitManager");
				_portraitType = AccessTools.TypeByName("Portrait");
				if (_portraitMgrType != null)
				{
					_portraitsField = AccessTools.Field(_portraitMgrType, "portraits");
					_vlgField = AccessTools.Field(_portraitMgrType, "vlg");
					_pmInstanceGetter = AccessTools.PropertyGetter(_portraitMgrType, "Instance");
				}
				if (_portraitType != null)
				{
					_portraitCharField = AccessTools.Field(_portraitType, "character");
				}
				_reflectionCached = true;
				PlayerLimitPlugin.Logger.LogInfo((object)("PortraitExpander reflection cached: " + $"PM={_portraitMgrType != null}, Portrait={_portraitType != null}, " + $"portraits={_portraitsField != null}, pmGetter={_pmInstanceGetter != null}"));
			}
		}

		public static void ApplyPagination(Array portraits, int totalChars)
		{
			_totalChars = totalChars;
			int totalPages = GetTotalPages();
			if (_currentPage >= totalPages)
			{
				_currentPage = totalPages - 1;
			}
			if (_currentPage < 0)
			{
				_currentPage = 0;
			}
			int num = _currentPage * 6;
			int num2 = Math.Min(num + 6, totalChars);
			for (int i = 0; i < portraits.Length; i++)
			{
				object? value = portraits.GetValue(i);
				Component val = (Component)((value is Component) ? value : null);
				if (!((Object)(object)val == (Object)null))
				{
					bool flag = i >= num && i < num2;
					if (val.gameObject.activeSelf != flag)
					{
						val.gameObject.SetActive(flag);
					}
				}
			}
			UpdateArrowStates();
		}

		public static void UpdateFromPlugin()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (PlayerLimitPlugin.IsShuttingDown)
			{
				return;
			}
			try
			{
				Scene activeScene = SceneManager.GetActiveScene();
				string name = ((Scene)(ref activeScene)).name;
				if (!_loggedOnce)
				{
					DebugLog($"HEARTBEAT scene='{name}' lastScene='{_lastScene}' expanded={_expanded}");
					PlayerLimitPlugin.Logger.LogInfo((object)$"PortraitExpander: HEARTBEAT scene='{name}' lastScene='{_lastScene}' expanded={_expanded}");
				}
				if (name != _lastScene)
				{
					DebugLog("Scene changed from '" + _lastScene + "' to '" + name + "'");
					PlayerLimitPlugin.Logger.LogInfo((object)("PortraitExpander: Scene changed from '" + _lastScene + "' to '" + name + "'"));
					if (_expanded)
					{
						CleanupAll();
					}
					PartyPanelPager.ResetState();
					_lastScene = name;
					_loggedOnce = false;
				}
				if (IsMainMenuScene(name))
				{
					if (!_loggedOnce)
					{
						_loggedOnce = true;
						DebugLog("IsMainMenuScene=true for '" + name + "', returning");
					}
					return;
				}
				CacheReflection();
				if (_pmInstanceGetter == null)
				{
					if (!_loggedOnce)
					{
						_loggedOnce = true;
						DebugLog("_pmInstanceGetter is null");
					}
					return;
				}
				object obj = _pmInstanceGetter.Invoke(null, null);
				if (obj == null)
				{
					if (!_loggedOnce)
					{
						_loggedOnce = true;
						DebugLog("pmInstance is null");
					}
					return;
				}
				int partyCharacterCount = GetPartyCharacterCount();
				if (partyCharacterCount <= 0)
				{
					if (!_loggedOnce)
					{
						_loggedOnce = true;
						DebugLog($"charCount={partyCharacterCount} (<=0), skipping");
					}
					return;
				}
				if (!_loggedOnce)
				{
					_loggedOnce = true;
					DebugLog($"charCount={partyCharacterCount}, expanded={_expanded}, arrowsCreated={_arrowsCreated}");
					PlayerLimitPlugin.Logger.LogInfo((object)$"PortraitExpander: charCount={partyCharacterCount}, expanded={_expanded}, arrowsCreated={_arrowsCreated}");
				}
				EnsurePortraitsForAllCharacters(obj, partyCharacterCount);
				if (!_arrowsCreated && _expanded)
				{
					CreateArrowUI(obj);
				}
			}
			catch (Exception ex)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)("PortraitExpander.UpdateFromPlugin error: " + ex.Message));
			}
		}

		private static int GetPartyCharacterCount()
		{
			try
			{
				Type type = AccessTools.TypeByName("NetworkingManager");
				if (type == null)
				{
					return -1;
				}
				MethodInfo methodInfo = AccessTools.PropertyGetter(type, "Instance");
				if (methodInfo == null)
				{
					return -1;
				}
				object obj = methodInfo.Invoke(null, null);
				if (obj == null)
				{
					return -1;
				}
				MethodInfo methodInfo2 = AccessTools.PropertyGetter(type, "PartyCharacters");
				if (methodInfo2 == null)
				{
					return -1;
				}
				if (!(methodInfo2.Invoke(obj, null) is IList list))
				{
					return -1;
				}
				return list.Count;
			}
			catch
			{
				return -1;
			}
		}

		private static bool IsMainMenuScene(string sceneName)
		{
			if (string.IsNullOrEmpty(sceneName))
			{
				return true;
			}
			string text = sceneName.ToLower();
			return text.Contains("menu") || text.Contains("title") || text.Contains("splash") || text.Contains("loading");
		}

		private static void NextPage()
		{
			int totalPages = GetTotalPages();
			if (_currentPage < totalPages - 1)
			{
				_currentPage++;
				PlayerLimitPlugin.Logger.LogInfo((object)$"PortraitExpander: Page {_currentPage + 1}/{totalPages}");
			}
		}

		private static void PrevPage()
		{
			if (_currentPage > 0)
			{
				_currentPage--;
				PlayerLimitPlugin.Logger.LogInfo((object)$"PortraitExpander: Page {_currentPage + 1}/{GetTotalPages()}");
			}
		}

		private static int GetTotalPages()
		{
			if (_totalChars <= 6)
			{
				return 1;
			}
			return (int)Math.Ceiling((double)_totalChars / 6.0);
		}

		private static void UpdateArrowStates()
		{
			int totalPages = GetTotalPages();
			bool active = totalPages > 1;
			if ((Object)(object)_upArrowGO != (Object)null)
			{
				_upArrowGO.SetActive(active);
				if ((Object)(object)_upArrowBtn != (Object)null)
				{
					((Selectable)_upArrowBtn).interactable = _currentPage > 0;
				}
			}
			if ((Object)(object)_downArrowGO != (Object)null)
			{
				_downArrowGO.SetActive(active);
				if ((Object)(object)_downArrowBtn != (Object)null)
				{
					((Selectable)_downArrowBtn).interactable = _currentPage < totalPages - 1;
				}
			}
		}

		private static void LoadArrowSprites()
		{
			if ((Object)(object)_arrowUpSprite != (Object)null)
			{
				return;
			}
			try
			{
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				Sprite arrowUpSprite = LoadSpriteFromResource(executingAssembly, "arrow_left.png");
				Sprite arrowDownSprite = LoadSpriteFromResource(executingAssembly, "arrow_right.png");
				_arrowUpSprite = arrowUpSprite;
				_arrowDownSprite = arrowDownSprite;
				PlayerLimitPlugin.Logger.LogInfo((object)$"PortraitExpander: Arrow sprites loaded (up={(Object)(object)_arrowUpSprite != (Object)null}, down={(Object)(object)_arrowDownSprite != (Object)null})");
			}
			catch (Exception ex)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)("PortraitExpander: Failed to load arrow sprites: " + ex.Message));
			}
		}

		private static Sprite LoadSpriteFromResource(Assembly asm, string resourceName)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			using Stream stream = asm.GetManifestResourceStream(resourceName);
			if (stream == null)
			{
				return null;
			}
			byte[] array = new byte[stream.Length];
			stream.Read(array, 0, array.Length);
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			ImageConversion.LoadImage(val, array);
			((Texture)val).filterMode = (FilterMode)1;
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
		}

		private static void CreateArrowUI(object pmInstance)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			Component val = (Component)((pmInstance is Component) ? pmInstance : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			LoadArrowSprites();
			Transform transform = val.transform;
			Sprite arrowUpSprite = _arrowUpSprite;
			object obj = <>c.<>9__35_0;
			if (obj == null)
			{
				UnityAction val2 = delegate
				{
					PrevPage();
				};
				<>c.<>9__35_0 = val2;
				obj = (object)val2;
			}
			_upArrowGO = CreateArrowButton(transform, "PortraitPageUp", arrowUpSprite, (UnityAction)obj, isUp: true);
			Sprite arrowDownSprite = _arrowDownSprite;
			object obj2 = <>c.<>9__35_1;
			if (obj2 == null)
			{
				UnityAction val3 = delegate
				{
					NextPage();
				};
				<>c.<>9__35_1 = val3;
				obj2 = (object)val3;
			}
			_downArrowGO = CreateArrowButton(transform, "PortraitPageDown", arrowDownSprite, (UnityAction)obj2, isUp: false);
			if ((Object)(object)_upArrowGO != (Object)null)
			{
				_upArrowBtn = _upArrowGO.GetComponent<Button>();
			}
			if ((Object)(object)_downArrowGO != (Object)null)
			{
				_downArrowBtn = _downArrowGO.GetComponent<Button>();
			}
			_arrowsCreated = true;
			UpdateArrowStates();
			PlayerLimitPlugin.Logger.LogInfo((object)"PortraitExpander: Arrow navigation UI created");
		}

		private static GameObject CreateArrowButton(Transform parent, string name, Sprite sprite, UnityAction onClick, bool isUp)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			RectTransform val2 = val.AddComponent<RectTransform>();
			val2.sizeDelta = new Vector2(30f, 12f);
			Image val3 = val.AddComponent<Image>();
			if ((Object)(object)sprite != (Object)null)
			{
				val3.sprite = sprite;
				val3.type = (Type)0;
				val3.preserveAspect = true;
			}
			else
			{
				((Graphic)val3).color = new Color(0.12f, 0.1f, 0.08f, 0.9f);
			}
			((Transform)val2).localRotation = Quaternion.Euler(0f, 0f, -90f);
			Button val4 = val.AddComponent<Button>();
			((Selectable)val4).targetGraphic = (Graphic)(object)val3;
			ColorBlock colors = ((Selectable)val4).colors;
			((ColorBlock)(ref colors)).normalColor = Color.white;
			((ColorBlock)(ref colors)).highlightedColor = new Color(1f, 0.9f, 0.7f, 1f);
			((ColorBlock)(ref colors)).pressedColor = new Color(0.7f, 0.6f, 0.4f, 1f);
			((ColorBlock)(ref colors)).disabledColor = new Color(0.4f, 0.4f, 0.4f, 0.5f);
			((Selectable)val4).colors = colors;
			((UnityEvent)val4.onClick).AddListener(onClick);
			if (isUp)
			{
				val.transform.SetAsFirstSibling();
			}
			else
			{
				val.transform.SetAsLastSibling();
			}
			LayoutElement val5 = val.AddComponent<LayoutElement>();
			val5.preferredHeight = 30f;
			val5.preferredWidth = 12f;
			val5.flexibleWidth = 0f;
			val5.flexibleHeight = 0f;
			return val;
		}

		public static void EnsurePortraitsForAllCharacters(object portraitMgrInstance, int charCount)
		{
			CacheReflection();
			if (_portraitsField == null || _portraitType == null)
			{
				if (!_loggedOnce)
				{
					_loggedOnce = true;
					PlayerLimitPlugin.Logger.LogWarning((object)$"PortraitExpander: early exit - portraitsField={_portraitsField != null}, portraitType={_portraitType != null}");
				}
				return;
			}
			Array array = _portraitsField.GetValue(portraitMgrInstance) as Array;
			if (array == null || array.Length == 0)
			{
				if (!_loggedOnce)
				{
					_loggedOnce = true;
					PlayerLimitPlugin.Logger.LogWarning((object)("PortraitExpander: early exit - portraitsArray is " + ((array == null) ? "null" : "empty")));
				}
				return;
			}
			if (!_loggedOnce || (charCount > 0 && charCount != _lastCharCount))
			{
				_loggedOnce = true;
				PlayerLimitPlugin.Logger.LogInfo((object)$"PortraitExpander: charCount={charCount}, portraitSlots={array.Length}, lastCharCount={_lastCharCount}, expanded={_expanded}");
			}
			if (charCount > 0 && (charCount != _lastCharCount || !_expanded))
			{
				PlayerLimitPlugin.Logger.LogInfo((object)$"PortraitExpander: Processing {charCount} characters, {array.Length} portrait slots");
				_lastCharCount = charCount;
				if (charCount > array.Length)
				{
					ExpandPortraitSlots(portraitMgrInstance, array, charCount);
				}
				_expanded = true;
			}
		}

		private static void ExpandPortraitSlots(object portraitMgrInstance, Array existingPortraits, int needed)
		{
			int length = existingPortraits.Length;
			if (needed <= length)
			{
				return;
			}
			if (_originalPortraitCount < 0)
			{
				_originalPortraitCount = length;
			}
			PlayerLimitPlugin.Logger.LogInfo((object)$"PortraitExpander: Expanding from {length} to {needed} portrait slots");
			object? value = existingPortraits.GetValue(0);
			Component val = (Component)((value is Component) ? value : null);
			if ((Object)(object)val == (Object)null)
			{
				PlayerLimitPlugin.Logger.LogWarning((object)"PortraitExpander: No template portrait to clone");
				return;
			}
			GameObject gameObject = val.gameObject;
			Transform parent = gameObject.transform.parent;
			Array array = Array.CreateInstance(_portraitType, needed);
			Array.Copy(existingPortraits, array, length);
			for (int i = length; i < needed; i++)
			{
				GameObject val2 = Object.Instantiate<GameObject>(gameObject, parent);
				((Object)val2).name = $"Portrait Item ({i + 3})";
				val2.SetActive(false);
				Component component = val2.GetComponent(_portraitType);
				if ((Object)(object)component != (Object)null)
				{
					array.SetValue(component, i);
					_clonedPortraits.Add(val2);
					PlayerLimitPlugin.Logger.LogInfo((object)$"PortraitExpander: Created portrait slot [{i}] '{((Object)val2).name}'");
				}
			}
			_portraitsField.SetValue(portraitMgrInstance, array);
			PlayerLimitPlugin.Logger.LogInfo((object)$"PortraitExpander: portraits array expanded to {needed}");
		}

		private static void CleanupAll()
		{
			PlayerLimitPlugin.Logger.LogInfo((object)$"PortraitExpander: Cleaning up {_clonedPortraits.Count} cloned portraits");
			foreach (GameObject clonedPortrait in _clonedPortraits)
			{
				if ((Object)(object)clonedPortrait != (Object)null)
				{
					Object.Destroy((Object)(object)clonedPortrait);
				}
			}
			_clonedPortraits.Clear();
			if ((Object)(object)_upArrowGO != (Object)null)
			{
				Object.Destroy((Object)(object)_upArrowGO);
				_upArrowGO = null;
			}
			if ((Object)(object)_downArrowGO != (Object)null)
			{
				Object.Destroy((Object)(object)_downArrowGO);
				_downArrowGO = null;
			}
			_upArrowBtn = null;
			_downArrowBtn = null;
			_arrowsCreated = false;
			if (_originalPortraitCount > 0 && _pmInstanceGetter != null && _portraitsField != null)
			{
				try
				{
					object obj = _pmInstanceGetter.Invoke(null, null);
					if (obj != null && _portraitsField.GetValue(obj) is Array array && array.Length > _originalPortraitCount)
					{
						Array array2 = Array.CreateInstance(_portraitType, _originalPortraitCount);
						Array.Copy(array, array2, _originalPortraitCount);
						_portraitsField.SetValue(obj, array2);
					}
				}
				catch (Exception ex)
				{
					PlayerLimitPlugin.Logger.LogWarning((object)("PortraitExpander: Cleanup restore error: " + ex.Message));
				}
			}
			_expanded = false;
			_lastCharCount = -1;
			_currentPage = 0;
			_totalChars = 0;
		}

		public static void Reset()
		{
			CleanupAll();
			_loggedOnce = false;
		}
	}
}