using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using HarmonyLib; using InventoryExpansion; using InventoryExpansion.Config; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using Mimic.Actors; using ReluProtocol; using ReluProtocol.Enum; using TMPro; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Core), "InventoryExpansion", "1.4.1", "DooDesch", null)] [assembly: MelonGame("ReLUGames", "MIMESIS")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("InventoryExpansion")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.4.1.0")] [assembly: AssemblyInformationalVersion("1.4.1+6acff1ebbc8a8bee4fd279ac402b35ce8cd29532")] [assembly: AssemblyProduct("InventoryExpansion")] [assembly: AssemblyTitle("InventoryExpansion")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.4.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 InventoryExpansion { public sealed class Core : MelonMod { public override void OnInitializeMelon() { InventoryExpansionPreferences.Initialize(); ((MelonBase)this).HarmonyInstance.PatchAll(); MelonLogger.Msg("InventoryExpansion initialized. Enabled={0}", new object[1] { InventoryExpansionPreferences.Enabled }); } } } namespace InventoryExpansion.Patches { [HarmonyPatch(typeof(Hub))] internal static class GameConfigPatches { private static bool _slotsAlreadyExpanded; [HarmonyPostfix] [HarmonyPatch("Awake")] private static void Hub_Awake_Postfix(Hub __instance) { try { if (!InventoryExpansionPreferences.Enabled || _slotsAlreadyExpanded) { return; } object obj = typeof(Hub).GetField("gameConfig", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(__instance); if (obj == null) { MelonLogger.Warning("InventoryExpansion: gameConfig is null, cannot adjust inventory slot count."); return; } object obj2 = obj.GetType().GetField("playerActor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj); if (obj2 == null) { MelonLogger.Warning("InventoryExpansion: gameConfig.playerActor is null, cannot adjust inventory slot count."); return; } FieldInfo field = obj2.GetType().GetField("maxGenericInventorySlot", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { MelonLogger.Warning("InventoryExpansion: PlayerActor.maxGenericInventorySlot field not found."); return; } int num = (int)(field.GetValue(obj2) ?? ((object)4)); int additionalSlots = InventoryExpansionPreferences.AdditionalSlots; if (additionalSlots <= 0) { MelonLogger.Msg($"InventoryExpansion: keeping base inventory slots = {num}."); return; } int num2 = num + additionalSlots; field.SetValue(obj2, num2); _slotsAlreadyExpanded = true; MelonLogger.Msg($"InventoryExpansion: expanded inventory slots from {num} to {num2}."); } catch (Exception arg) { MelonLogger.Error($"InventoryExpansion: failed to adjust inventory slot size: {arg}"); } } } [HarmonyPatch(typeof(InventoryController))] internal static class InventoryControllerPatches { [HarmonyPostfix] [HarmonyPatch("Initialize")] private static void Initialize_Postfix(InventoryController __instance) { try { if (!InventoryExpansionPreferences.Enabled) { return; } Hub s = Hub.s; object obj = typeof(Hub).GetField("gameConfig", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(s); if (obj == null) { return; } object obj2 = obj.GetType().GetField("playerActor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj); if (obj2 == null) { return; } FieldInfo field = obj2.GetType().GetField("maxGenericInventorySlot", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { return; } int num = (int)(field.GetValue(obj2) ?? ((object)4)); if (num <= 4) { return; } FieldInfo field2 = typeof(InventoryController).GetField("_inventorySlots", BindingFlags.Instance | BindingFlags.NonPublic); if (field2 == null) { MelonLogger.Warning("InventoryExpansion: failed to find InventoryController._inventorySlots field."); return; } if (!(field2.GetValue(__instance) is IDictionary dictionary)) { MelonLogger.Warning("InventoryExpansion: InventoryController._inventorySlots is not an IDictionary."); return; } for (int i = 5; i <= num; i++) { if (!dictionary.Contains(i)) { dictionary[i] = null; } } MelonLogger.Msg($"InventoryExpansion: InventoryController extended to {num} slots."); } catch (Exception arg) { MelonLogger.Error($"InventoryExpansion: failed to extend InventoryController slots: {arg}"); } } [HarmonyPrefix] [HarmonyPatch("InvenFull")] private static bool InvenFull_Prefix(InventoryController __instance, ref bool __result) { try { if (!InventoryExpansionPreferences.Enabled) { return true; } Hub s = Hub.s; if ((Object)(object)s == (Object)null) { return true; } object obj = typeof(Hub).GetField("gameConfig", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(s); object obj2 = (obj?.GetType().GetField("playerActor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(obj); int num = (int)((obj2?.GetType().GetField("maxGenericInventorySlot", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(obj2) ?? ((object)4)); if (!(typeof(InventoryController).GetField("_inventorySlots", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(__instance) is IDictionary dictionary)) { return true; } int num2 = 0; foreach (DictionaryEntry item in dictionary) { if (item.Value != null) { num2++; } } __result = num2 >= num; return false; } catch (Exception arg) { MelonLogger.Error($"InventoryExpansion: InvenFull prefix failed, falling back to original. {arg}"); return true; } } } [HarmonyPatch(typeof(UIPrefab_Inventory))] internal static class InventoryUiPatches { [HarmonyPostfix] [HarmonyPatch("Awake")] private static void Awake_Postfix(UIPrefab_Inventory __instance) { //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_0379: Expected O, but got Unknown //IL_03a3: Unknown result type (might be due to invalid IL or missing references) //IL_03bf: Unknown result type (might be due to invalid IL or missing references) //IL_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_03e0: Unknown result type (might be due to invalid IL or missing references) //IL_03ed: Unknown result type (might be due to invalid IL or missing references) //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_042c: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Unknown result type (might be due to invalid IL or missing references) //IL_045f: Unknown result type (might be due to invalid IL or missing references) //IL_0486: Unknown result type (might be due to invalid IL or missing references) //IL_048b: Unknown result type (might be due to invalid IL or missing references) //IL_04b7: Unknown result type (might be due to invalid IL or missing references) //IL_04c5: Unknown result type (might be due to invalid IL or missing references) //IL_04f0: Unknown result type (might be due to invalid IL or missing references) //IL_04fd: Unknown result type (might be due to invalid IL or missing references) //IL_050a: Unknown result type (might be due to invalid IL or missing references) //IL_0517: Unknown result type (might be due to invalid IL or missing references) //IL_0523: Unknown result type (might be due to invalid IL or missing references) //IL_054a: Unknown result type (might be due to invalid IL or missing references) //IL_054f: Unknown result type (might be due to invalid IL or missing references) //IL_05d2: Unknown result type (might be due to invalid IL or missing references) //IL_05e0: Unknown result type (might be due to invalid IL or missing references) //IL_0612: Unknown result type (might be due to invalid IL or missing references) //IL_0617: Unknown result type (might be due to invalid IL or missing references) //IL_0648: Unknown result type (might be due to invalid IL or missing references) //IL_0656: Unknown result type (might be due to invalid IL or missing references) //IL_0664: Unknown result type (might be due to invalid IL or missing references) //IL_0672: Unknown result type (might be due to invalid IL or missing references) //IL_0680: Unknown result type (might be due to invalid IL or missing references) try { if (!InventoryExpansionPreferences.Enabled) { return; } int val = 4; try { Hub s = Hub.s; if ((Object)(object)s != (Object)null) { object obj = typeof(Hub).GetField("gameConfig", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(s); object obj2 = (obj?.GetType().GetField("playerActor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(obj); FieldInfo fieldInfo = obj2?.GetType().GetField("maxGenericInventorySlot", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo != null) { val = (int)(fieldInfo.GetValue(obj2) ?? ((object)4)); } } } catch { val = 4; } int num = Math.Min(val, 4 + InventoryExpansionPreferences.AdditionalSlots); FieldInfo field = typeof(UIPrefab_Inventory).GetField("inventorySlots", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null || !(field.GetValue(__instance) is IList { Count: var count } list) || count == 0 || count >= num) { return; } Type type = list[0].GetType(); FieldInfo field2 = type.GetField("frame", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field3 = type.GetField("image", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field4 = type.GetField("stackCount", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field5 = type.GetField("waitEvent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field2 == null || field3 == null || field4 == null || field5 == null) { return; } object? value = field2.GetValue(list[0]); Image val2 = (Image)((value is Image) ? value : null); object? value2 = field3.GetValue(list[0]); Image val3 = (Image)((value2 is Image) ? value2 : null); object? value3 = field4.GetValue(list[0]); TMP_Text val4 = (TMP_Text)((value3 is TMP_Text) ? value3 : null); object? value4 = field5.GetValue(list[0]); Transform val5 = (Transform)((value4 is Transform) ? value4 : null); if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null) { return; } RectTransform rectTransform = ((Graphic)val2).rectTransform; _ = ((Graphic)val3).rectTransform; _ = val4.rectTransform; float num2 = 0f; if (count > 1) { object? value5 = field2.GetValue(list[1]); Image val6 = (Image)((value5 is Image) ? value5 : null); if ((Object)(object)val6 != (Object)null) { num2 = ((Graphic)val6).rectTransform.anchoredPosition.x - rectTransform.anchoredPosition.x; } } if (Mathf.Approximately(num2, 0f)) { num2 = rectTransform.sizeDelta.x + 10f; } float num3 = rectTransform.sizeDelta.y + 10f; Transform parent = ((Transform)rectTransform).parent; RectTransform val7 = (RectTransform)(object)((parent is RectTransform) ? parent : null); for (int i = count; i < num; i++) { int index = count - 1; object obj4 = list[index]; object? value6 = field2.GetValue(obj4); Image val8 = (Image)((value6 is Image) ? value6 : null); object? value7 = field3.GetValue(obj4); Image val9 = (Image)((value7 is Image) ? value7 : null); object? value8 = field4.GetValue(obj4); TMP_Text val10 = (TMP_Text)((value8 is TMP_Text) ? value8 : null); object? value9 = field5.GetValue(obj4); Transform val11 = (Transform)((value9 is Transform) ? value9 : null); if ((Object)(object)val8 == (Object)null || (Object)(object)val9 == (Object)null || (Object)(object)val10 == (Object)null || (Object)(object)val11 == (Object)null) { continue; } int num4 = i - count; int num5 = num4 / 8; int num6 = num4 % 8; GameObject val12 = new GameObject(((Object)((Component)val8).gameObject).name + "_Extra" + i); val12.transform.SetParent((Transform)(object)val7, false); Image val13 = val12.AddComponent(); val13.sprite = val8.sprite; val13.type = val8.type; ((Graphic)val13).material = ((Graphic)val8).material; ((Graphic)val13).color = ((Graphic)val8).color; RectTransform rectTransform2 = ((Graphic)val13).rectTransform; rectTransform2.anchorMin = rectTransform.anchorMin; rectTransform2.anchorMax = rectTransform.anchorMax; rectTransform2.pivot = rectTransform.pivot; rectTransform2.sizeDelta = rectTransform.sizeDelta; object? value10 = field2.GetValue(list[count - 1]); object? obj5 = ((value10 is Image) ? value10 : null); float num7 = (((obj5 != null) ? ((Graphic)obj5).rectTransform : null) ?? rectTransform).anchoredPosition.x + num2; float y = rectTransform.anchoredPosition.y; float num8 = num7 - (float)num6 * num2; float num9 = y + (float)num5 * num3; rectTransform2.anchoredPosition = new Vector2(num8, num9); GameObject val14 = new GameObject(((Object)((Component)val9).gameObject).name + "_Extra" + i); val14.transform.SetParent(val12.transform, false); Image val15 = val14.AddComponent(); val15.sprite = val9.sprite; val15.type = val9.type; ((Graphic)val15).color = ((Graphic)val9).color; ((Graphic)val15).material = ((Graphic)val9).material; RectTransform rectTransform3 = ((Graphic)val15).rectTransform; RectTransform rectTransform4 = ((Graphic)val9).rectTransform; rectTransform3.anchorMin = rectTransform4.anchorMin; rectTransform3.anchorMax = rectTransform4.anchorMax; rectTransform3.pivot = rectTransform4.pivot; rectTransform3.sizeDelta = rectTransform4.sizeDelta; rectTransform3.anchoredPosition = rectTransform4.anchoredPosition; GameObject val16 = new GameObject(((Object)((Component)val10).gameObject).name + "_Extra" + i); val16.transform.SetParent(val12.transform, false); Component obj6 = val16.AddComponent(((object)val10).GetType()); TMP_Text val17 = (TMP_Text)(object)((obj6 is TMP_Text) ? obj6 : null); if ((Object)(object)val17 == (Object)null) { MelonLogger.Error("[InventoryExpansion][UI] Failed to create TMP_Text for extra slot " + i + "; skipping this slot."); Object.Destroy((Object)(object)val12); continue; } val17.text = string.Empty; val17.font = val10.font; val17.fontSize = val10.fontSize; val17.alignment = val10.alignment; ((Graphic)val17).color = ((Graphic)val10).color; BackpackPanelPatch.ApplyStackPlacement(val17, rectTransform, val4); GameObject val18 = new GameObject(((Object)((Component)val11).gameObject).name + "_Extra" + i); val18.transform.SetParent(val12.transform, false); RectTransform val19 = val18.AddComponent(); RectTransform val20 = (RectTransform)(object)((val11 is RectTransform) ? val11 : null); if ((Object)(object)val20 != (Object)null) { val19.anchorMin = val20.anchorMin; val19.anchorMax = val20.anchorMax; val19.pivot = val20.pivot; val19.sizeDelta = val20.sizeDelta; val19.anchoredPosition = val20.anchoredPosition; } object obj7 = Activator.CreateInstance(type); field2.SetValue(obj7, val13); field3.SetValue(obj7, val15); field4.SetValue(obj7, val17); field5.SetValue(obj7, ((Component)val19).transform); list.Add(obj7); } MelonLogger.Msg("[InventoryExpansion][UI] Extended inventorySlots from " + count + " to " + list.Count + " visual slots."); } catch (Exception ex) { MelonLogger.Error("[InventoryExpansion][UI] Awake postfix failed while extending slots: " + ex); } } } [HarmonyPatch] internal static class InventoryDebugControllerPatches { [HarmonyPostfix] [HarmonyPatch(typeof(InventoryController), "Initialize")] private static void InventoryController_Initialize_Postfix(InventoryController __instance) { try { if (typeof(InventoryController).GetField("_inventorySlots", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(__instance) is IDictionary dictionary) { string text = string.Join(",", dictionary.Keys.Cast()); MelonLogger.Msg("[InventoryExpansion][Debug] InventoryController.Initialize: slot dict count = " + dictionary.Count + ", keys = [" + text + "]"); } } catch (Exception arg) { MelonLogger.Error($"[InventoryExpansion][Debug] InventoryController.Initialize debug failed: {arg}"); } } [HarmonyPostfix] [HarmonyPatch(typeof(InventoryController), "GetInventoryInfos")] private static void InventoryController_GetInventoryInfos_Postfix(Dictionary __result) { try { if (__result == null) { MelonLogger.Msg("[InventoryExpansion][Debug] GetInventoryInfos: result is null."); return; } int count = __result.Count; int num = ((__result.Count > 0) ? __result.Keys.Max() : 0); MelonLogger.Msg($"[InventoryExpansion][Debug] GetInventoryInfos: {count} entries, max key = {num}."); } catch (Exception arg) { MelonLogger.Error($"[InventoryExpansion][Debug] GetInventoryInfos debug failed: {arg}"); } } [HarmonyPostfix] [HarmonyPatch(typeof(InventoryController), "HandleAddItem")] private unsafe static void InventoryController_HandleAddItem_Postfix(InventoryController __instance, MsgErrorCode __result, int addedSlotIndex) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) try { IDictionary dictionary = typeof(InventoryController).GetField("_inventorySlots", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(__instance) as IDictionary; int num = dictionary?.Count ?? (-1); string text = ((dictionary != null) ? string.Join(",", dictionary.Keys.Cast()) : "null"); if ((int)__result == 20000012) { MelonLogger.Msg("[InventoryExpansion][Debug] HandleAddItem: INVENTORY FULL. slotCount=" + num + ", keys=[" + text + "]"); } else if ((int)__result == 0) { MelonLogger.Msg("[InventoryExpansion][Debug] HandleAddItem: Success, addedSlotIndex=" + addedSlotIndex + ", slotCount=" + num + "."); } else { MelonLogger.Msg("[InventoryExpansion][Debug] HandleAddItem: Result=" + ((object)(*(MsgErrorCode*)(&__result))/*cast due to .constrained prefix*/).ToString() + ", addedSlotIndex=" + addedSlotIndex + ", slotCount=" + num + "."); } } catch (Exception arg) { MelonLogger.Error($"[InventoryExpansion][Debug] HandleAddItem debug failed: {arg}"); } } } [HarmonyPatch] internal static class InventoryDebugClientPatches { private static MethodBase TargetMethod() { try { Type nestedType = typeof(ProtoActor).GetNestedType("Inventory", BindingFlags.Public | BindingFlags.NonPublic); if (nestedType == null) { MelonLogger.Error("[InventoryExpansion][Debug] Failed to find nested type ProtoActor.Inventory for ResolveInventoryInfos debug patch."); return null; } MethodInfo? method = nestedType.GetMethod("ResolveInventoryInfos", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { MelonLogger.Error("[InventoryExpansion][Debug] Failed to find ResolveInventoryInfos method on ProtoActor.Inventory."); } return method; } catch (Exception ex) { MelonLogger.Error("[InventoryExpansion][Debug] TargetMethod for ResolveInventoryInfos failed: " + ex); return null; } } [HarmonyPostfix] private static void Inventory_ResolveInventoryInfos_Postfix(object __instance, Dictionary serverItemInfos, int? currentServerSlotIndex) { try { if (__instance == null) { return; } Type type = __instance.GetType(); int num = (int)(type.GetField("slotSize", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(__instance) ?? ((object)0)); IList list = type.GetField("slotItems", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(__instance) as IList; int num2 = 0; if (list != null) { foreach (object item in list) { if (item != null) { num2++; } } } int num3 = serverItemInfos?.Count ?? 0; int num4 = ((num3 > 0) ? serverItemInfos.Keys.Max() : 0); string text = (currentServerSlotIndex.HasValue ? currentServerSlotIndex.Value.ToString() : "null"); MelonLogger.Msg("[InventoryExpansion][Debug] ResolveInventoryInfos: slotSize=" + num + ", serverItems=" + num3 + ", serverMaxKey=" + num4 + ", localNonNullItems=" + num2 + ", currentServerSlotIndex=" + text + "."); } catch (Exception ex) { MelonLogger.Error("[InventoryExpansion][Debug] ResolveInventoryInfos debug failed: " + ex); } } } [HarmonyPatch] internal static class BackpackPanelPatch { private static GameObject _rootObj; private static GameObject _canvasObj; private static RectTransform _backpackPanel; private static bool _slotsMoved; private static bool _backpackFullyVisible; private static Sprite _backpackSprite; private static object _animationCoroutine; private static float _panelHeight; private static float _initialPanelY; private static TMP_Text _keyHintText; private static int _savedStandardSlot; private static FieldInfo _uimanField; internal static bool IsBackpackFullyVisible => _backpackFullyVisible; [HarmonyPostfix] [HarmonyPatch(typeof(UIPrefab_Inventory), "Awake")] private static void UIPrefab_Inventory_Awake_Postfix(UIPrefab_Inventory __instance) { try { if (InventoryExpansionPreferences.Enabled) { BackpackSceneChangeHandler.Initialize(); if ((Object)(object)_backpackPanel != (Object)null) { CleanupMovedSlots(); _slotsMoved = false; MelonCoroutines.Start(MoveSlotsToPanelCoroutine(__instance)); } else { CreateRoot(); CreateUI(); MelonCoroutines.Start(MoveSlotsToPanelCoroutine(__instance)); } } } catch (Exception ex) { MelonLogger.Error("[InventoryExpansion][BackpackPanel] Failed to create backpack panel: " + ex); } } private static void CreateRoot() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown if (!((Object)(object)_rootObj != (Object)null)) { _rootObj = new GameObject("InventoryExpansion_Root"); Object.DontDestroyOnLoad((Object)(object)_rootObj); } } private static void CreateUI() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_008e: 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_00fb: Expected O, but got Unknown //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_canvasObj != (Object)null) { return; } if ((Object)(object)_rootObj == (Object)null) { CreateRoot(); } _canvasObj = new GameObject("InventoryExpansion_Canvas"); _canvasObj.transform.SetParent(_rootObj.transform, false); Canvas val = _canvasObj.AddComponent(); val.renderMode = (RenderMode)0; CanvasScaler obj = _canvasObj.AddComponent(); obj.uiScaleMode = (ScaleMode)0; obj.scaleFactor = 1f; Canvas val2 = null; Canvas[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (Canvas val3 in array) { if ((int)val3.renderMode == 0 && ((Object)val3).name.Contains("Canvas") && !((Object)val3).name.Contains("InventoryExpansion")) { val2 = val3; break; } } if ((Object)(object)val2 != (Object)null) { val.sortingOrder = val2.sortingOrder + 1; } _canvasObj.AddComponent(); GameObject val4 = new GameObject("InventoryExpansion_BackpackPanel"); val4.transform.SetParent(_canvasObj.transform, false); Image val5 = val4.AddComponent(); LoadBackpackSprite(); if ((Object)(object)_backpackSprite != (Object)null) { val5.sprite = _backpackSprite; val5.type = (Type)0; val5.preserveAspect = false; } else { ((Graphic)val5).color = new Color(0f, 0f, 0f, 0.8f); } ((Graphic)val5).raycastTarget = false; _backpackPanel = val4.GetComponent(); _backpackPanel.anchorMin = new Vector2(1f, 0f); _backpackPanel.anchorMax = new Vector2(1f, 0f); _backpackPanel.pivot = new Vector2(1f, 0f); _backpackPanel.sizeDelta = new Vector2(450f, 200f); _backpackPanel.anchoredPosition = new Vector2(-40f, 40f); _initialPanelY = 40f; try { CreateKeyHintText(val4); } catch (Exception arg) { MelonLogger.Warning($"[InventoryExpansion][BackpackPanel] Failed to create key hint text during UI creation: {arg}"); } _backpackFullyVisible = false; ((Component)_backpackPanel).gameObject.SetActive(false); } private static void LoadBackpackSprite() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) try { string text = Path.Combine(Path.GetDirectoryName(typeof(BackpackPanelPatch).Assembly.Location), "Assets", "Backpack.png"); if (!File.Exists(text)) { MelonLogger.Warning("[InventoryExpansion][BackpackPanel] Backpack asset not found at: " + text); return; } byte[] array = File.ReadAllBytes(text); Texture2D val = new Texture2D(2, 2); bool flag = false; try { flag = ImageConversion.LoadImage(val, array); } catch { try { flag = ImageConversion.LoadImage(val, array); } catch { } } if (!flag) { MelonLogger.Error("[InventoryExpansion][BackpackPanel] Failed to load Backpack.png as texture"); Object.Destroy((Object)(object)val); } else { _backpackSprite = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); MelonLogger.Msg($"[InventoryExpansion][BackpackPanel] Loaded Backpack sprite: {((Texture)val).width}x{((Texture)val).height}"); } } catch (Exception arg) { MelonLogger.Error($"[InventoryExpansion][BackpackPanel] Failed to load Backpack sprite: {arg}"); } } internal static void ToggleBackpack() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_backpackPanel == (Object)null) && !IsInLoadingScreen() && !IsGamePaused()) { bool targetVisible = !_backpackFullyVisible; if (_animationCoroutine != null) { MelonCoroutines.Stop(_animationCoroutine); _animationCoroutine = null; } ((Component)_backpackPanel).gameObject.SetActive(true); if (_panelHeight == 0f) { _panelHeight = _backpackPanel.sizeDelta.y; } if (_initialPanelY == 0f) { _initialPanelY = 40f; } _animationCoroutine = MelonCoroutines.Start(AnimateBackpackVisibility(targetVisible)); } } internal static void HandleCursorHandoff(ProtoActor avatar, bool opening) { try { if ((Object)(object)avatar == (Object)null || (opening && !InventoryExpansionPreferences.SelectBackpackSlotOnOpen) || (!opening && !InventoryExpansionPreferences.RestoreStandardSlotOnClose)) { return; } object obj = InventorySelectionHelper.GetActorInventoryField()?.GetValue(avatar); if (obj == null) { return; } Type type = obj.GetType(); FieldInfo slotSizeField = InventorySelectionHelper.GetSlotSizeField(type); FieldInfo selectedSlotIndexField = InventorySelectionHelper.GetSelectedSlotIndexField(type); MethodInfo selectSlotMethod = InventorySelectionHelper.GetSelectSlotMethod(type); if (slotSizeField == null || selectedSlotIndexField == null || selectSlotMethod == null || (int)(slotSizeField.GetValue(obj) ?? ((object)4)) <= 4) { return; } int num = (int)(selectedSlotIndexField.GetValue(obj) ?? ((object)0)); if (opening) { if (num >= 0 && num <= 3) { _savedStandardSlot = num; } selectSlotMethod.Invoke(obj, new object[1] { 4 }); } else { int num2 = Mathf.Clamp(_savedStandardSlot, 0, 3); selectSlotMethod.Invoke(obj, new object[1] { num2 }); } } catch (Exception arg) { MelonLogger.Error($"[InventoryExpansion][BackpackPanel] Cursor handoff failed: {arg}"); } } internal static bool IsGamePaused() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) try { if (Time.timeScale <= 0.01f) { return true; } if ((int)Cursor.lockState == 0 && Cursor.visible && IsInGame()) { return true; } return false; } catch { return false; } } internal static bool IsInGame() { try { GameMainBase main = Hub.Main; ProtoActor val = ((main != null) ? main.GetMyAvatar() : null); if ((Object)(object)val == (Object)null) { return false; } return val.AmIAvatar(); } catch (Exception arg) { MelonLogger.Warning($"[InventoryExpansion][BackpackPanel] IsInGame check failed: {arg}"); return false; } } private static bool IsInLoadingScreen() { try { if ((Object)(object)Hub.s == (Object)null) { return true; } GameMainBase main = Hub.Main; ProtoActor val = ((main != null) ? main.GetMyAvatar() : null); if ((Object)(object)val == (Object)null) { return true; } return !val.AmIAvatar(); } catch { return false; } } internal static void HideBackpackCompletely() { if ((Object)(object)_backpackPanel != (Object)null && (Object)(object)((Component)_backpackPanel).gameObject != (Object)null) { ((Component)_backpackPanel).gameObject.SetActive(false); } } private static void CleanupMovedSlots() { if ((Object)(object)_backpackPanel == (Object)null) { return; } for (int num = ((Transform)_backpackPanel).childCount - 1; num >= 0; num--) { Transform child = ((Transform)_backpackPanel).GetChild(num); if ((Object)(object)child != (Object)null && ((Object)child).name.StartsWith("InventoryExpansion_SlotContainer_")) { Object.Destroy((Object)(object)((Component)child).gameObject); } } } internal static bool IsLoadingScreenActive() { try { Hub s = Hub.s; if ((Object)(object)s == (Object)null) { return false; } if (_uimanField == null) { _uimanField = typeof(Hub).GetField("k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); } object? obj = _uimanField?.GetValue(s); UIPrefab_Scene_Loading val = ((UIManager)(((obj is UIManager) ? obj : null)?)).ui_sceneloading; return (Object)(object)val != (Object)null && ((Behaviour)val).isActiveAndEnabled; } catch { return false; } } internal static void EnsurePeekIfHidden() { //IL_0040: 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_008c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_backpackPanel == (Object)null) && _slotsMoved && _animationCoroutine == null && !((Component)_backpackPanel).gameObject.activeSelf) { if (_panelHeight == 0f) { _panelHeight = _backpackPanel.sizeDelta.y; } if (_initialPanelY == 0f) { _initialPanelY = 40f; } float num = _initialPanelY - _panelHeight * 0.75f; _backpackPanel.anchoredPosition = new Vector2(_backpackPanel.anchoredPosition.x, num); _backpackFullyVisible = false; ((Component)_backpackPanel).gameObject.SetActive(true); UpdateKeyHintVisibility(); } } private static IEnumerator AnimateBackpackVisibility(bool targetVisible) { if ((Object)(object)_backpackPanel == (Object)null) { yield break; } if (_panelHeight == 0f) { _panelHeight = _backpackPanel.sizeDelta.y; } if (_initialPanelY == 0f) { _initialPanelY = 40f; } float num = _initialPanelY - _panelHeight * 0.75f; float initialPanelY = _initialPanelY; Vector2 startPos = _backpackPanel.anchoredPosition; Vector2 targetPos = (targetVisible ? new Vector2(startPos.x, initialPanelY) : new Vector2(startPos.x, num)); if (Mathf.Abs(startPos.y - targetPos.y) < 1f) { _backpackFullyVisible = targetVisible; UpdateKeyHintVisibility(); _animationCoroutine = null; yield break; } float elapsed = 0f; ((Component)_backpackPanel).gameObject.SetActive(true); while (elapsed < 0.3f) { if ((Object)(object)_backpackPanel == (Object)null || (Object)(object)((Component)_backpackPanel).gameObject == (Object)null) { yield break; } elapsed += Time.deltaTime; float num2 = Mathf.Clamp01(elapsed / 0.3f); num2 = 1f - Mathf.Pow(1f - num2, 3f); _backpackPanel.anchoredPosition = Vector2.Lerp(startPos, targetPos, num2); UpdateKeyHintVisibility(); yield return null; } if ((Object)(object)_backpackPanel != (Object)null && (Object)(object)((Component)_backpackPanel).gameObject != (Object)null) { _backpackPanel.anchoredPosition = targetPos; _backpackFullyVisible = targetVisible; UpdateKeyHintVisibility(); } _animationCoroutine = null; } private static void CreateKeyHintText(GameObject parent) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)parent == (Object)null) { MelonLogger.Warning("[InventoryExpansion][BackpackPanel] Cannot create key hint text: parent is null"); return; } Type type = null; TMP_FontAsset val = null; try { TMP_Text[] array = Object.FindObjectsByType((FindObjectsSortMode)0); if (array != null && array.Length != 0) { TMP_Text[] array2 = array; foreach (TMP_Text val2 in array2) { if ((Object)(object)val2 != (Object)null && !((object)val2).Equals((object?)null) && (Object)(object)val2.font != (Object)null) { type = ((object)val2).GetType(); val = val2.font; break; } } } } catch (Exception arg) { MelonLogger.Warning($"[InventoryExpansion][BackpackPanel] Error finding TMP_Text type: {arg}"); } if (type == null) { type = typeof(TMP_Text); } GameObject val3 = new GameObject("InventoryExpansion_KeyHint"); if ((Object)(object)val3 == (Object)null) { MelonLogger.Warning("[InventoryExpansion][BackpackPanel] Failed to create key hint GameObject"); return; } val3.transform.SetParent(parent.transform, false); val3.transform.SetAsLastSibling(); Component obj = val3.AddComponent(type); _keyHintText = (TMP_Text)(object)((obj is TMP_Text) ? obj : null); if ((Object)(object)_keyHintText == (Object)null) { MelonLogger.Warning("[InventoryExpansion][BackpackPanel] Failed to add TMP_Text component"); Object.Destroy((Object)(object)val3); return; } if ((Object)(object)val != (Object)null) { _keyHintText.font = val; } else { TMP_FontAsset defaultFontAsset = TMP_Settings.defaultFontAsset; if ((Object)(object)defaultFontAsset != (Object)null) { _keyHintText.font = defaultFontAsset; } } _keyHintText.text = ((object)InventoryExpansionPreferences.BackpackKey/*cast due to .constrained prefix*/).ToString(); _keyHintText.fontSize = 24f; _keyHintText.alignment = (TextAlignmentOptions)514; ((Graphic)_keyHintText).color = new Color(1f, 1f, 1f, 1f); _keyHintText.fontStyle = (FontStyles)1; Outline val4 = val3.AddComponent(); if ((Object)(object)val4 != (Object)null) { ((Shadow)val4).effectColor = new Color(0f, 0f, 0f, 1f); ((Shadow)val4).effectDistance = new Vector2(2f, 2f); } if ((Object)(object)_keyHintText.rectTransform == (Object)null) { MelonLogger.Warning("[InventoryExpansion][BackpackPanel] Key hint text has no RectTransform"); return; } RectTransform rectTransform = _keyHintText.rectTransform; rectTransform.anchorMin = new Vector2(0.5f, 1f); rectTransform.anchorMax = new Vector2(0.5f, 1f); rectTransform.pivot = new Vector2(0.5f, 0.5f); rectTransform.sizeDelta = new Vector2(60f, 35f); rectTransform.anchoredPosition = new Vector2(0f, -95f); ((Graphic)_keyHintText).raycastTarget = false; ((Component)_keyHintText).gameObject.SetActive(true); MelonLogger.Msg("[InventoryExpansion][BackpackPanel] Key hint text created successfully"); } catch (Exception arg2) { MelonLogger.Error($"[InventoryExpansion][BackpackPanel] Failed to create key hint text: {arg2}"); _keyHintText = null; } } private static void UpdateKeyHintVisibility() { if ((Object)(object)_keyHintText == (Object)null || (Object)(object)((Component)_keyHintText).gameObject == (Object)null) { return; } try { ((Component)_keyHintText).gameObject.SetActive(true); } catch { } } private static (float padding, float paddingTop, float paddingBottom) GetPaddingForSlotCount(int additionalSlots) { return additionalSlots switch { 4 => (padding: 90f, paddingTop: 130f, paddingBottom: 90f), 9 => (padding: 160f, paddingTop: 200f, paddingBottom: 140f), _ => (padding: 200f, paddingTop: 240f, paddingBottom: 180f), }; } private static (float horizontal, float top) GetSlotPaddingForSlotCount(int additionalSlots) { return additionalSlots switch { 4 => (horizontal: 90f, top: 170f), 9 => (horizontal: 160f, top: 260f), _ => (horizontal: 200f, top: 320f), }; } internal static void ApplyStackPlacement(TMP_Text stackText, RectTransform templateFrameRT, TMP_Text templateStack) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)stackText == (Object)null) && !((Object)(object)templateFrameRT == (Object)null)) { RectTransform rectTransform = stackText.rectTransform; Vector2 sizeDelta = templateFrameRT.sizeDelta; rectTransform.anchorMin = new Vector2(0.5f, 0.5f); rectTransform.anchorMax = new Vector2(0.5f, 0.5f); rectTransform.pivot = new Vector2(0.5f, 0.5f); rectTransform.sizeDelta = new Vector2(sizeDelta.x * 0.85f, sizeDelta.y * 0.85f); rectTransform.anchoredPosition = Vector2.zero; stackText.alignment = (TextAlignmentOptions)1028; if ((Object)(object)templateStack != (Object)null) { stackText.fontSize = templateStack.fontSize; } } } private static IEnumerator MoveSlotsToPanelCoroutine(UIPrefab_Inventory inventoryUI) { yield return null; try { if ((Object)(object)_backpackPanel == (Object)null || _slotsMoved) { yield break; } FieldInfo field = typeof(UIPrefab_Inventory).GetField("inventorySlots", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { MelonLogger.Error("[InventoryExpansion][BackpackPanel] Could not find inventorySlots field!"); } else { if (!(field.GetValue(inventoryUI) is IList { Count: >4 } list)) { yield break; } Type type = list[0].GetType(); FieldInfo field2 = type.GetField("frame", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field2 == null) { MelonLogger.Error("[InventoryExpansion][BackpackPanel] Could not find frame field in slot!"); yield break; } object obj = list[0]; object? value = field2.GetValue(obj); Image val = (Image)((value is Image) ? value : null); if ((Object)(object)val == (Object)null) { MelonLogger.Error("[InventoryExpansion][BackpackPanel] Could not get first frame!"); yield break; } RectTransform rectTransform = ((Graphic)val).rectTransform; float x = rectTransform.sizeDelta.x; float y = rectTransform.sizeDelta.y; x *= 0.5f; y *= 0.5f; Image val2 = null; Transform parent = ((Transform)rectTransform).parent; if ((Object)(object)parent != (Object)null) { for (int i = 0; i < parent.childCount; i++) { Transform child = parent.GetChild(i); if (((Object)child).name.Contains("InvenBG") || ((Object)child).name.Contains("BG")) { val2 = ((Component)child).GetComponent(); if ((Object)(object)val2 != (Object)null) { break; } } } } float num = 10f; int num2 = list.Count - 4; int num3 = num2 switch { 4 => 2, 9 => 3, 16 => 4, _ => Mathf.CeilToInt(Mathf.Sqrt((float)num2)), }; int num4 = Mathf.CeilToInt((float)num2 / (float)num3); float num5 = (float)num3 * x + (float)(num3 + 1) * num; float num6 = (float)num4 * y + (float)(num4 + 1) * num; (float padding, float paddingTop, float paddingBottom) paddingForSlotCount = GetPaddingForSlotCount(num2); float item = paddingForSlotCount.padding; float item2 = paddingForSlotCount.paddingTop; float item3 = paddingForSlotCount.paddingBottom; float num7 = num5 + item * 2f; float num8 = num6 + item2 + item3; _backpackPanel.sizeDelta = new Vector2(num7, num8); FieldInfo field3 = type.GetField("image", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field4 = type.GetField("stackCount", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); object? obj2 = field3?.GetValue(obj); Image val3 = (Image)((obj2 is Image) ? obj2 : null); object? obj3 = field4?.GetValue(obj); TMP_Text templateStack = (TMP_Text)((obj3 is TMP_Text) ? obj3 : null); RectTransform val4 = ((val3 != null) ? ((Graphic)val3).rectTransform : null); for (int j = 4; j < list.Count; j++) { object obj4 = list[j]; object? value2 = field2.GetValue(obj4); Image val5 = (Image)((value2 is Image) ? value2 : null); if ((Object)(object)val5 == (Object)null) { continue; } RectTransform rectTransform2 = ((Graphic)val5).rectTransform; if (!((Object)((Component)val5).gameObject).name.Contains("_Extra")) { continue; } GameObject val6 = new GameObject("InventoryExpansion_SlotContainer_" + j); val6.transform.SetParent((Transform)(object)_backpackPanel, false); RectTransform obj5 = val6.AddComponent(); int num9 = j - 4; int num10 = num9 / num3; int num11 = num9 % num3; obj5.anchorMin = new Vector2(0f, 1f); obj5.anchorMax = new Vector2(0f, 1f); obj5.pivot = new Vector2(0f, 1f); (float horizontal, float top) slotPaddingForSlotCount = GetSlotPaddingForSlotCount(num2); float item4 = slotPaddingForSlotCount.horizontal; float item5 = slotPaddingForSlotCount.top; float num12 = item4 + num + (float)num11 * (x + num); float num13 = 0f - (item5 + num + (float)num10 * (y + num)); obj5.anchoredPosition = new Vector2(num12, num13); obj5.sizeDelta = new Vector2(x, y); if ((Object)(object)val2 != (Object)null) { GameObject val7 = new GameObject("InvenBG_Extra" + j); val7.transform.SetParent(val6.transform, false); Image obj6 = val7.AddComponent(); obj6.sprite = val2.sprite; ((Graphic)obj6).material = ((Graphic)val2).material; ((Graphic)obj6).color = ((Graphic)val2).color; obj6.type = val2.type; obj6.preserveAspect = val2.preserveAspect; obj6.fillMethod = val2.fillMethod; obj6.fillAmount = val2.fillAmount; obj6.fillCenter = val2.fillCenter; obj6.fillClockwise = val2.fillClockwise; obj6.fillOrigin = val2.fillOrigin; ((Graphic)obj6).raycastTarget = ((Graphic)val2).raycastTarget; ((MaskableGraphic)obj6).maskable = ((MaskableGraphic)val2).maskable; RectTransform rectTransform3 = ((Graphic)obj6).rectTransform; RectTransform rectTransform4 = ((Graphic)val2).rectTransform; rectTransform3.anchorMin = rectTransform4.anchorMin; rectTransform3.anchorMax = rectTransform4.anchorMax; rectTransform3.pivot = rectTransform4.pivot; rectTransform3.sizeDelta = rectTransform4.sizeDelta * 0.5f; rectTransform3.anchoredPosition = rectTransform4.anchoredPosition * 0.5f; } ((Transform)rectTransform2).SetParent(val6.transform, false); RectTransform rectTransform5 = ((Graphic)val).rectTransform; rectTransform2.anchorMin = new Vector2(0.5f, 0.5f); rectTransform2.anchorMax = new Vector2(0.5f, 0.5f); rectTransform2.pivot = rectTransform5.pivot; rectTransform2.sizeDelta = rectTransform5.sizeDelta; rectTransform2.anchoredPosition = Vector2.zero; ((Transform)rectTransform2).localScale = new Vector3(0.5f, 0.5f, 1f); val5.sprite = val.sprite; ((Graphic)val5).material = ((Graphic)val).material; ((Graphic)val5).color = ((Graphic)val).color; val5.type = val.type; val5.preserveAspect = val.preserveAspect; val5.fillMethod = val.fillMethod; val5.fillAmount = val.fillAmount; val5.fillCenter = val.fillCenter; val5.fillClockwise = val.fillClockwise; val5.fillOrigin = val.fillOrigin; if (field3 != null && (Object)(object)val3 != (Object)null && (Object)(object)val4 != (Object)null) { object? value3 = field3.GetValue(obj4); Image val8 = (Image)((value3 is Image) ? value3 : null); if ((Object)(object)val8 != (Object)null) { RectTransform rectTransform6 = ((Graphic)val8).rectTransform; val8.sprite = val3.sprite; ((Graphic)val8).material = ((Graphic)val3).material; ((Graphic)val8).color = ((Graphic)val3).color; val8.type = val3.type; val8.preserveAspect = val3.preserveAspect; val8.fillMethod = val3.fillMethod; val8.fillAmount = val3.fillAmount; val8.fillCenter = val3.fillCenter; val8.fillClockwise = val3.fillClockwise; val8.fillOrigin = val3.fillOrigin; rectTransform6.anchorMin = val4.anchorMin; rectTransform6.anchorMax = val4.anchorMax; rectTransform6.pivot = val4.pivot; rectTransform6.sizeDelta = val4.sizeDelta; rectTransform6.anchoredPosition = val4.anchoredPosition; } } if (field4 != null) { object? value4 = field4.GetValue(obj4); TMP_Text val9 = (TMP_Text)((value4 is TMP_Text) ? value4 : null); if ((Object)(object)val9 != (Object)null) { ApplyStackPlacement(val9, rectTransform5, templateStack); } } } _slotsMoved = true; _panelHeight = _backpackPanel.sizeDelta.y; if (_initialPanelY == 0f) { _initialPanelY = 40f; } float num14 = _initialPanelY - _panelHeight * 0.75f; _backpackPanel.anchoredPosition = new Vector2(_backpackPanel.anchoredPosition.x, num14); _backpackFullyVisible = false; UpdateKeyHintVisibility(); MelonLogger.Msg("[InventoryExpansion][BackpackPanel] Moved {0} additional slots to panel. Panel size: {1}", new object[2] { num2, _backpackPanel.sizeDelta }); } } catch (Exception ex) { MelonLogger.Error("[InventoryExpansion][BackpackPanel] Failed to move slots to panel: " + ex); } } } [HarmonyPatch(typeof(ProtoActor), "Update")] internal static class BackpackInputUpdatePatch { private static bool wasKeyPressedLastFrame; [HarmonyPostfix] private unsafe static void Update_Postfix(ProtoActor __instance) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) try { if (!InventoryExpansionPreferences.Enabled || !__instance.AmIAvatar()) { return; } if (BackpackPanelPatch.IsLoadingScreenActive()) { BackpackPanelPatch.HideBackpackCompletely(); wasKeyPressedLastFrame = false; return; } if (BackpackPanelPatch.IsGamePaused()) { if (BackpackPanelPatch.IsBackpackFullyVisible) { BackpackPanelPatch.ToggleBackpack(); } else { BackpackPanelPatch.HideBackpackCompletely(); } wasKeyPressedLastFrame = false; return; } BackpackPanelPatch.EnsurePeekIfHidden(); Keyboard current = Keyboard.current; if (current == null) { wasKeyPressedLastFrame = false; return; } KeyCode backpackKey = InventoryExpansionPreferences.BackpackKey; Key val = (Key)0; try { val = (Key)Enum.Parse(typeof(Key), ((object)(*(KeyCode*)(&backpackKey))/*cast due to .constrained prefix*/).ToString()); } catch { MelonLogger.Warning($"[InventoryExpansion][BackpackPanel] Could not convert KeyCode {backpackKey} to Input System Key"); return; } bool isPressed = ((ButtonControl)current[val]).isPressed; bool num = isPressed && !wasKeyPressedLastFrame; wasKeyPressedLastFrame = isPressed; if (num) { bool opening = !BackpackPanelPatch.IsBackpackFullyVisible; BackpackPanelPatch.ToggleBackpack(); BackpackPanelPatch.HandleCursorHandoff(__instance, opening); } } catch (Exception arg) { MelonLogger.Error($"[InventoryExpansion][BackpackPanel] Update postfix failed: {arg}"); } } } [HarmonyPatch(typeof(ProtoActor))] internal static class BackpackMovementSpeedPatch { private static FieldInfo _netSyncActorDataField; private static bool _fieldInitialized; private static long _originalMoveSpeedWalk; private static long _originalMoveSpeedRun; private static bool _speedReduced; [HarmonyPostfix] [HarmonyPatch("Update")] private static void Update_Postfix(ProtoActor __instance) { try { if (!InventoryExpansionPreferences.Enabled) { RestoreMoveSpeed(__instance); } else { if (!__instance.AmIAvatar()) { return; } if (!_fieldInitialized) { _netSyncActorDataField = typeof(ProtoActor).GetField("netSyncActorData", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _fieldInitialized = true; } if (_netSyncActorDataField == null) { return; } object value = _netSyncActorDataField.GetValue(__instance); if (value == null) { return; } FieldInfo field = value.GetType().GetField("MoveSpeedWalk", BindingFlags.Instance | BindingFlags.Public); FieldInfo field2 = value.GetType().GetField("MoveSpeedRun", BindingFlags.Instance | BindingFlags.Public); if (field == null || field2 == null) { return; } if (BackpackPanelPatch.IsBackpackFullyVisible && InventoryExpansionPreferences.ReduceMovementSpeed) { if (!_speedReduced) { _originalMoveSpeedWalk = (long)(field.GetValue(value) ?? ((object)350L)); _originalMoveSpeedRun = (long)(field2.GetValue(value) ?? ((object)700L)); _speedReduced = true; } field.SetValue(value, (long)((float)_originalMoveSpeedWalk * 0.5f)); field2.SetValue(value, (long)((float)_originalMoveSpeedRun * 0.5f)); } else { RestoreMoveSpeed(value, field, field2); } } } catch (Exception arg) { MelonLogger.Error($"[InventoryExpansion][Movement] Movement speed patch failed: {arg}"); } } private static void RestoreMoveSpeed(ProtoActor instance) { if (!_speedReduced || _netSyncActorDataField == null) { return; } object value = _netSyncActorDataField.GetValue(instance); if (value != null) { FieldInfo field = value.GetType().GetField("MoveSpeedWalk", BindingFlags.Instance | BindingFlags.Public); FieldInfo field2 = value.GetType().GetField("MoveSpeedRun", BindingFlags.Instance | BindingFlags.Public); if (field != null && field2 != null) { RestoreMoveSpeed(value, field, field2); } } } private static void RestoreMoveSpeed(object netSyncActorData, FieldInfo moveSpeedWalkField, FieldInfo moveSpeedRunField) { if (_speedReduced && _originalMoveSpeedWalk > 0 && _originalMoveSpeedRun > 0) { moveSpeedWalkField.SetValue(netSyncActorData, _originalMoveSpeedWalk); moveSpeedRunField.SetValue(netSyncActorData, _originalMoveSpeedRun); _speedReduced = false; } } } [HarmonyPatch(typeof(ProtoActor), "OnDestroy")] internal static class BackpackProtoActorDestroyPatch { [HarmonyPostfix] private static void OnDestroy_Postfix(ProtoActor __instance) { try { if (InventoryExpansionPreferences.Enabled && __instance.AmIAvatar()) { BackpackSceneChangeHandler.HideBackpack(); } } catch (Exception arg) { MelonLogger.Error($"[InventoryExpansion][BackpackPanel] ProtoActor OnDestroy patch failed: {arg}"); } } } internal static class BackpackSceneChangeHandler { private static bool _initialized; internal static void Initialize() { if (!_initialized) { SceneManager.activeSceneChanged += OnActiveSceneChanged; _initialized = true; } } private static void OnActiveSceneChanged(Scene previousScene, Scene newScene) { try { if (InventoryExpansionPreferences.Enabled && !IsInGame()) { HideBackpack(); } } catch (Exception arg) { MelonLogger.Error($"[InventoryExpansion][BackpackPanel] Scene change handler failed: {arg}"); } } private static bool IsInGame() { try { GameMainBase main = Hub.Main; ProtoActor val = ((main != null) ? main.GetMyAvatar() : null); if ((Object)(object)val == (Object)null) { return false; } return val.AmIAvatar(); } catch { return false; } } internal static void HideBackpack() { if (BackpackPanelPatch.IsBackpackFullyVisible) { BackpackPanelPatch.ToggleBackpack(); } else { BackpackPanelPatch.HideBackpackCompletely(); } } } internal static class InventorySelectionHelper { internal static Type GetInventoryType() { return typeof(ProtoActor).GetNestedType("Inventory", BindingFlags.Public | BindingFlags.NonPublic); } internal static FieldInfo GetSelectedSlotIndexField(Type inventoryType) { return inventoryType?.GetField("selectedSlotIndex", BindingFlags.Instance | BindingFlags.NonPublic); } internal static FieldInfo GetSlotSizeField(Type inventoryType) { return inventoryType?.GetField("slotSize", BindingFlags.Instance | BindingFlags.NonPublic); } internal static FieldInfo GetActorInventoryField() { return typeof(ProtoActor).GetField("inventory", BindingFlags.Instance | BindingFlags.NonPublic); } internal static MethodInfo GetSelectSlotMethod(Type inventoryType) { return inventoryType?.GetMethod("SelectSlot", BindingFlags.Instance | BindingFlags.NonPublic); } } [HarmonyPatch] internal static class InventorySelectionNextPatches { private static MethodBase TargetMethod() { return InventorySelectionHelper.GetInventoryType()?.GetMethod("SelectNextSlot", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } [HarmonyPrefix] private static bool SelectNextSlot_Prefix(object __instance) { return InventorySelectionCommon.HandleSlotSelection(__instance, forward: true); } } [HarmonyPatch] internal static class InventorySelectionPreviousPatches { private static MethodBase TargetMethod() { return InventorySelectionHelper.GetInventoryType()?.GetMethod("SelectPreviousSlot", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } [HarmonyPrefix] private static bool SelectPreviousSlot_Prefix(object __instance) { return InventorySelectionCommon.HandleSlotSelection(__instance, forward: false); } } internal static class InventorySelectionCommon { internal static bool HandleSlotSelection(object __instance, bool forward) { try { if (!InventoryExpansionPreferences.Enabled) { return true; } if (__instance == null) { return true; } Type type = __instance.GetType(); FieldInfo selectedSlotIndexField = InventorySelectionHelper.GetSelectedSlotIndexField(type); FieldInfo slotSizeField = InventorySelectionHelper.GetSlotSizeField(type); if (selectedSlotIndexField == null || slotSizeField == null) { return true; } int num = (int)(selectedSlotIndexField.GetValue(__instance) ?? ((object)0)); int num2 = (int)(slotSizeField.GetValue(__instance) ?? ((object)4)); int num3; int num4; if (BackpackPanelPatch.IsBackpackFullyVisible) { num3 = 4; num4 = num2 - 1; } else { num3 = 0; num4 = 3; } if (num3 > num4 || num < num3 || num > num4) { MethodInfo method = type.GetMethod("SelectSlot", BindingFlags.Instance | BindingFlags.NonPublic); if (method != null) { method.Invoke(__instance, new object[1] { num3 }); return false; } return true; } int num5; if (forward) { num5 = num + 1; if (num5 > num4) { num5 = num3; } } else { num5 = num - 1; if (num5 < num3) { num5 = num4; } } MethodInfo method2 = type.GetMethod("SelectSlot", BindingFlags.Instance | BindingFlags.NonPublic); if (method2 != null) { method2.Invoke(__instance, new object[1] { num5 }); return false; } return true; } catch (Exception arg) { MelonLogger.Error($"[InventoryExpansion][Selection] Slot selection prefix failed: {arg}"); return true; } } } [HarmonyPatch(typeof(InventoryController))] internal static class InventoryPickupPatches { private static FieldInfo _slotsField; private static MethodInfo _onAddItemByLooting; private static bool _reflectionInitialized; private static void EnsureReflection() { if (!_reflectionInitialized) { _reflectionInitialized = true; _slotsField = typeof(InventoryController).GetField("_inventorySlots", BindingFlags.Instance | BindingFlags.NonPublic); _onAddItemByLooting = typeof(InventoryController).GetMethod("OnAddItemByLooting", BindingFlags.Instance | BindingFlags.NonPublic); } } [HarmonyPrefix] [HarmonyPatch("HandleAddItem")] private static bool HandleAddItem_Prefix(InventoryController __instance, ItemElement itemElement, ref int addedSlotIndex, bool sync, bool byLooting, ref MsgErrorCode __result) { try { if (!InventoryExpansionPreferences.Enabled || !InventoryExpansionPreferences.FillBackpackFirst) { return true; } if (!BackpackPanelPatch.IsBackpackFullyVisible) { return true; } EnsureReflection(); if (_slotsField == null) { return true; } if (!(_slotsField.GetValue(__instance) is IDictionary dictionary)) { return true; } int currentInventorySlot = __instance.CurrentInventorySlot; if (dictionary.Contains(currentInventorySlot) && dictionary[currentInventorySlot] == null) { return true; } int num = -1; foreach (object key in dictionary.Keys) { if (key is int num2 && num2 >= 5 && dictionary[key] == null && (num < 0 || num2 < num)) { num = num2; } } if (num < 0) { return true; } if (byLooting && _onAddItemByLooting != null) { _onAddItemByLooting.Invoke(__instance, new object[1] { itemElement }); } __instance.AddInvenItem(num, itemElement, sync); addedSlotIndex = num; __result = (MsgErrorCode)0; return false; } catch (Exception arg) { MelonLogger.Error($"[InventoryExpansion][Pickup] HandleAddItem prefix failed, falling back to original: {arg}"); return true; } } } } namespace InventoryExpansion.Config { internal static class InventoryExpansionPreferences { private const string CategoryId = "InventoryExpansion"; private static MelonPreferences_Category _category; private static MelonPreferences_Entry _enabled; private static MelonPreferences_Entry _additionalSlots; private static MelonPreferences_Entry _backpackKey; private static MelonPreferences_Entry _reduceMovementSpeed; private static MelonPreferences_Entry _selectBackpackSlotOnOpen; private static MelonPreferences_Entry _restoreStandardSlotOnClose; private static MelonPreferences_Entry _fillBackpackFirst; internal static bool Enabled => _enabled.Value; internal static int AdditionalSlots { get { if (_additionalSlots == null) { return 4; } int value = _additionalSlots.Value; int num = ClampToValidBackpackSize(value); if (num != value) { _additionalSlots.Value = num; } return num; } } internal static KeyCode BackpackKey { get { //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (_backpackKey == null) { return (KeyCode)99; } string value = _backpackKey.Value; if (string.IsNullOrEmpty(value)) { return (KeyCode)99; } if (Enum.TryParse(value, ignoreCase: true, out KeyCode result)) { return result; } return (KeyCode)99; } } internal static bool ReduceMovementSpeed => _reduceMovementSpeed?.Value ?? true; internal static bool SelectBackpackSlotOnOpen => _selectBackpackSlotOnOpen?.Value ?? true; internal static bool RestoreStandardSlotOnClose => _restoreStandardSlotOnClose?.Value ?? true; internal static bool FillBackpackFirst => _fillBackpackFirst?.Value ?? true; internal static void Initialize() { if (_category == null) { _category = MelonPreferences.CreateCategory("InventoryExpansion", "InventoryExpansion"); _enabled = CreateEntry("Enabled", defaultValue: true, "Enabled", "Enable InventoryExpansion functionality. When disabled, the mod will not modify game behavior."); _additionalSlots = CreateEntry("AdditionalSlots", 4, "Additional Inventory Slots", "Number of extra inventory slots to add on top of the game's default inventory size. Valid values: 4, 9, or 16 (for square grids: 2x2, 3x3, or 4x4). Other values will be rounded to the nearest valid option."); _backpackKey = CreateEntry("BackpackKey", "C", "Backpack Toggle Key", "Key to toggle backpack visibility. Press to switch between standard inventory and backpack."); _reduceMovementSpeed = CreateEntry("ReduceMovementSpeed", defaultValue: true, "Reduce Movement Speed", "When enabled, player movement speed is reduced to 50% while the backpack is fully open."); _selectBackpackSlotOnOpen = CreateEntry("SelectBackpackSlotOnOpen", defaultValue: true, "Select Backpack Slot On Open", "When opening the backpack, move the selected slot to the first backpack slot."); _restoreStandardSlotOnClose = CreateEntry("RestoreStandardSlotOnClose", defaultValue: true, "Restore Standard Slot On Close", "When closing the backpack, return the selected slot to the standard inventory (the slot that was selected before opening)."); _fillBackpackFirst = CreateEntry("FillBackpackFirst", defaultValue: true, "Fill Backpack First", "While the backpack is open, picked-up items fill the backpack slots before the standard inventory. Takes effect only when you are the host or in single-player."); } } private static MelonPreferences_Entry CreateEntry(string identifier, T defaultValue, string displayName, string description = null) { if (_category == null) { throw new InvalidOperationException("Preference category not initialized."); } return _category.CreateEntry(identifier, defaultValue, displayName, description, false, false, (ValueValidator)null, (string)null); } private static int ClampToValidBackpackSize(int value) { if (value <= 0) { return 4; } if (value <= 6) { return 4; } if (value <= 12) { return 9; } return 16; } } }