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;
}
}
}