Decompiled source of LoadoutManager v0.1.5

BepInEx/plugins/REPO.LoadoutManager.dll

Decompiled an hour ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("REPO.LoadoutManager")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("REPO mod: pick which purchased items to bring from the truck monitor screen")]
[assembly: AssemblyFileVersion("0.1.5.0")]
[assembly: AssemblyInformationalVersion("0.1.5")]
[assembly: AssemblyProduct("REPO.LoadoutManager")]
[assembly: AssemblyTitle("REPO.LoadoutManager")]
[assembly: AssemblyVersion("0.1.5.0")]
[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 REPO.ItemSpawner
{
	[HarmonyPatch(typeof(TruckScreenText), "Awake")]
	internal static class TruckScreenText_Awake_Patch
	{
		private static void Postfix(TruckScreenText __instance)
		{
			try
			{
				MonitorUI.Build(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[MonitorUI] Failed to build embedded UI: {arg}");
			}
		}
	}
	internal static class MonitorUI
	{
		private static GameObject _rootGO;

		private static RectTransform _content;

		private static ScrollRect _scroll;

		private static int _selectedCategoryIndex;

		private static int _selectedRowIndex;

		private static readonly List<Image> _tabImages = new List<Image>();

		private static readonly List<Image> _rowImages = new List<Image>();

		private static readonly Dictionary<string, Sprite> _iconCache = new Dictionary<string, Sprite>();

		private static readonly Color TabColor = new Color(1f, 1f, 1f, 0.14f);

		private static readonly Color TabSelectedColor = new Color(1f, 0.85f, 0.2f, 0.5f);

		private static readonly Color RowColor = new Color(1f, 1f, 1f, 0.08f);

		private static readonly Color RowSelectedColor = new Color(1f, 0.85f, 0.2f, 0.35f);

		private static readonly Color FavoriteTabColor = new Color(0.85f, 0.75f, 0.1f, 0.35f);

		private static readonly Color FavoriteTabSelectedColor = new Color(1f, 0.9f, 0.15f, 0.65f);

		private static readonly Color HideTabColor = new Color(0.7f, 0.15f, 0.15f, 0.35f);

		private static readonly Color HideTabSelectedColor = new Color(1f, 0.2f, 0.2f, 0.65f);

		private static void GetTabColors(string category, out Color normal, out Color selected)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_004e: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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)
			if (category == "Favorite")
			{
				normal = FavoriteTabColor;
				selected = FavoriteTabSelectedColor;
			}
			else if (category == "Hide")
			{
				normal = HideTabColor;
				selected = HideTabSelectedColor;
			}
			else
			{
				normal = TabColor;
				selected = TabSelectedColor;
			}
		}

		public static void Build(TruckScreenText truckScreenText)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: 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_00e0: 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)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Expected O, but got Unknown
			//IL_019b: 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_01bb: 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_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Expected O, but got Unknown
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_034b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Expected O, but got Unknown
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_0456: Unknown result type (might be due to invalid IL or missing references)
			//IL_045d: Expected O, but got Unknown
			//IL_0464: Unknown result type (might be due to invalid IL or missing references)
			//IL_046b: Expected O, but got Unknown
			//IL_048f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fc: Expected O, but got Unknown
			//IL_0518: Unknown result type (might be due to invalid IL or missing references)
			//IL_0531: 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_0559: Unknown result type (might be due to invalid IL or missing references)
			//IL_0563: Unknown result type (might be due to invalid IL or missing references)
			Transform val = ((Component)truckScreenText).transform.Find("Canvas");
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[MonitorUI] Could not find 'Canvas' child under TruckScreenText.");
				return;
			}
			if ((Object)(object)((Component)val).GetComponent<Canvas>() == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[MonitorUI] 'Canvas' child has no Canvas component.");
				return;
			}
			Transform obj = val.Find("Bg");
			RectTransform val2 = (RectTransform)(object)((obj is RectTransform) ? obj : null);
			GameObject val3 = new GameObject("REPO.ItemSpawner.Panel", new Type[2]
			{
				typeof(RectTransform),
				typeof(Canvas)
			});
			_rootGO = val3;
			RectTransform val4 = (RectTransform)val3.transform;
			((Transform)val4).SetParent(val, false);
			if ((Object)(object)val2 != (Object)null)
			{
				val4.anchorMin = val2.anchorMin;
				val4.anchorMax = val2.anchorMax;
				val4.anchoredPosition = val2.anchoredPosition + new Vector2(0f, 0.3f);
				val4.sizeDelta = val2.sizeDelta;
			}
			else
			{
				val4.anchorMin = Vector2.zero;
				val4.anchorMax = Vector2.one;
				val4.anchoredPosition = Vector2.zero;
				val4.sizeDelta = Vector2.zero;
			}
			((Transform)val4).localScale = new Vector3(0.95f, 0.75f, 1f);
			Canvas component = val3.GetComponent<Canvas>();
			component.overrideSorting = true;
			component.sortingOrder = 100;
			((Graphic)val3.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0.9f);
			GameObject val5 = new GameObject("Padding", new Type[1] { typeof(RectTransform) });
			RectTransform val6 = (RectTransform)val5.transform;
			((Transform)val6).SetParent((Transform)(object)val4, false);
			val6.anchorMin = Vector2.zero;
			val6.anchorMax = Vector2.one;
			val6.offsetMin = new Vector2(0.08f, 0.08f);
			val6.offsetMax = new Vector2(-0.08f, -0.08f);
			VerticalLayoutGroup obj2 = val5.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj2).spacing = 0.04f;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true;
			AddLabel((Transform)(object)val6, "Your Items", 0.2f, 0.26f);
			AddLabel((Transform)(object)val6, "Arrows: Move   Enter: Spawn   F: Favorite   H: Hide", 0.115f, 0.18f);
			GameObject val7 = new GameObject("Tabs", new Type[3]
			{
				typeof(RectTransform),
				typeof(VerticalLayoutGroup),
				typeof(LayoutElement)
			});
			RectTransform val8 = (RectTransform)val7.transform;
			((Transform)val8).SetParent((Transform)(object)val6, false);
			VerticalLayoutGroup component2 = val7.GetComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)component2).spacing = 0.02f;
			((HorizontalOrVerticalLayoutGroup)component2).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)component2).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)component2).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)component2).childControlHeight = true;
			LayoutElement component3 = val7.GetComponent<LayoutElement>();
			string[] order = ItemCategories.Order;
			int num = (order.Length + 3) / 4;
			component3.preferredHeight = 0.26f * (float)num + ((HorizontalOrVerticalLayoutGroup)component2).spacing * (float)(num - 1);
			component3.minHeight = component3.preferredHeight;
			component3.flexibleHeight = 0f;
			_tabImages.Clear();
			for (int i = 0; i < order.Length; i += 4)
			{
				GameObject val9 = new GameObject($"TabRow{i / 4}", new Type[3]
				{
					typeof(RectTransform),
					typeof(HorizontalLayoutGroup),
					typeof(LayoutElement)
				});
				RectTransform val10 = (RectTransform)val9.transform;
				((Transform)val10).SetParent((Transform)(object)val8, false);
				HorizontalLayoutGroup component4 = val9.GetComponent<HorizontalLayoutGroup>();
				((HorizontalOrVerticalLayoutGroup)component4).spacing = 0.02f;
				((HorizontalOrVerticalLayoutGroup)component4).childForceExpandWidth = true;
				((HorizontalOrVerticalLayoutGroup)component4).childForceExpandHeight = true;
				((HorizontalOrVerticalLayoutGroup)component4).childControlWidth = true;
				((HorizontalOrVerticalLayoutGroup)component4).childControlHeight = true;
				LayoutElement component5 = val9.GetComponent<LayoutElement>();
				component5.preferredHeight = 0.26f;
				component5.minHeight = 0.26f;
				component5.flexibleHeight = 0f;
				for (int j = i; j < Math.Min(i + 4, order.Length); j++)
				{
					Image item = CreateTab((Transform)(object)val10, order[j], 0.15f, 0.26f);
					_tabImages.Add(item);
				}
			}
			GameObject val11 = new GameObject("Scroll", new Type[5]
			{
				typeof(RectTransform),
				typeof(ScrollRect),
				typeof(Image),
				typeof(RectMask2D),
				typeof(LayoutElement)
			});
			RectTransform val12 = (RectTransform)val11.transform;
			((Transform)val12).SetParent((Transform)(object)val6, false);
			((Graphic)val11.GetComponent<Image>()).color = new Color(1f, 1f, 1f, 0.03f);
			LayoutElement component6 = val11.GetComponent<LayoutElement>();
			component6.flexibleHeight = 1f;
			component6.minHeight = 0.5f;
			GameObject val13 = new GameObject("Content", new Type[3]
			{
				typeof(RectTransform),
				typeof(VerticalLayoutGroup),
				typeof(ContentSizeFitter)
			});
			_content = (RectTransform)val13.transform;
			((Transform)_content).SetParent((Transform)(object)val12, false);
			_content.anchorMin = new Vector2(0f, 1f);
			_content.anchorMax = new Vector2(1f, 1f);
			_content.pivot = new Vector2(0.5f, 1f);
			_content.sizeDelta = Vector2.zero;
			VerticalLayoutGroup component7 = val13.GetComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)component7).spacing = 0.03f;
			((HorizontalOrVerticalLayoutGroup)component7).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)component7).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)component7).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)component7).childForceExpandWidth = true;
			ContentSizeFitter component8 = val13.GetComponent<ContentSizeFitter>();
			component8.horizontalFit = (FitMode)0;
			component8.verticalFit = (FitMode)2;
			_scroll = val11.GetComponent<ScrollRect>();
			_scroll.content = _content;
			_scroll.horizontal = false;
			_scroll.vertical = true;
			RefreshList();
			Canvas.ForceUpdateCanvases();
			LayoutRebuilder.ForceRebuildLayoutImmediate(val4);
			Plugin.Log.LogInfo((object)"[MonitorUI] Embedded panel built (keyboard nav).");
		}

		public static void SetVisible(bool visible)
		{
			if ((Object)(object)_rootGO != (Object)null)
			{
				_rootGO.SetActive(visible);
			}
		}

		public static void MoveSelection(int delta)
		{
			int count = CurrentGrouped().Count;
			if (count != 0)
			{
				_selectedRowIndex = ((_selectedRowIndex + delta) % count + count) % count;
				UpdateHighlight();
				ScrollToSelected();
			}
		}

		public static void ChangeCategory(int delta)
		{
			string[] order = ItemCategories.Order;
			_selectedCategoryIndex = ((_selectedCategoryIndex + delta) % order.Length + order.Length) % order.Length;
			_selectedRowIndex = 0;
			RefreshList();
		}

		public static void ConfirmSelection()
		{
			List<(Item, int)> list = CurrentGrouped();
			if (_selectedRowIndex >= 0 && _selectedRowIndex < list.Count)
			{
				ItemSpawner.RequestSpawn(list[_selectedRowIndex].Item1);
				RefreshList();
			}
		}

		public static void CycleFavoriteSelected()
		{
			List<(Item, int)> list = CurrentGrouped();
			if (_selectedRowIndex >= 0 && _selectedRowIndex < list.Count)
			{
				Item item = list[_selectedRowIndex].Item1;
				int ownedTotal = GetOwnedTotal(item);
				ItemSpawner.RequestCycleFavorite(item, ownedTotal);
			}
		}

		public static void ToggleHiddenSelected()
		{
			List<(Item, int)> list = CurrentGrouped();
			if (_selectedRowIndex >= 0 && _selectedRowIndex < list.Count)
			{
				Hidden.Toggle(list[_selectedRowIndex].Item1.itemName);
				RefreshList();
			}
		}

		private static int GetOwnedTotal(Item item)
		{
			if (!((Object)(object)StatsManager.instance != (Object)null))
			{
				return 0;
			}
			return StatsManager.instance.GetItemPurchased(item);
		}

		private static List<(Item item, int count)> CurrentGrouped()
		{
			if ((Object)(object)StatsManager.instance == (Object)null || (Object)(object)ItemManager.instance == (Object)null)
			{
				return new List<(Item, int)>();
			}
			string selectedCategory = ItemCategories.Order[_selectedCategoryIndex];
			Dictionary<string, int> remainingByName = (from i in ItemManager.instance.purchasedItems
				group i by i.itemName).ToDictionary((IGrouping<string, Item> g) => g.Key, (IGrouping<string, Item> g) => g.Count());
			IEnumerable<Item> source = StatsManager.instance.itemDictionary.Values.Where((Item it) => !it.disabled && GetOwnedTotal(it) > 0);
			if (selectedCategory == "Hide")
			{
				return (from it in source
					where Hidden.Set.Contains(it.itemName)
					select (it: it, Remaining(it))).ToList();
			}
			source = source.Where((Item it) => !Hidden.Set.Contains(it.itemName));
			if (selectedCategory == "Favorite")
			{
				return (from it in source
					where Favorites.Get(it.itemName) > 0
					select (it: it, GetOwnedTotal(it))).ToList();
			}
			return (from it in source
				where selectedCategory == "All" || ItemCategories.Of(it) == selectedCategory
				select (item: it, count: Remaining(it)) into g
				where g.count > 0
				select g).ToList();
			int Remaining(Item it)
			{
				if (!remainingByName.TryGetValue(it.itemName, out var value))
				{
					return 0;
				}
				return value;
			}
		}

		private static void AddLabel(Transform parent, string text, float fontSize, float height)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Label", new Type[3]
			{
				typeof(RectTransform),
				typeof(TextMeshProUGUI),
				typeof(LayoutElement)
			});
			val.transform.SetParent(parent, false);
			TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component).text = text;
			((TMP_Text)component).fontSize = fontSize;
			((TMP_Text)component).alignment = (TextAlignmentOptions)513;
			((Graphic)component).color = Color.white;
			((TMP_Text)component).enableWordWrapping = false;
			((TMP_Text)component).overflowMode = (TextOverflowModes)0;
			LayoutElement component2 = val.GetComponent<LayoutElement>();
			component2.preferredHeight = height;
			component2.minHeight = height;
			component2.flexibleHeight = 0f;
		}

		private static Image CreateTab(Transform parent, string label, float fontSize, float height)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: 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_010c: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Tab_" + label, new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(LayoutElement)
			});
			val.transform.SetParent(parent, false);
			Image component = val.GetComponent<Image>();
			((Graphic)component).color = TabColor;
			LayoutElement component2 = val.GetComponent<LayoutElement>();
			component2.preferredHeight = height;
			component2.minHeight = height;
			component2.flexibleHeight = 0f;
			GameObject val2 = new GameObject("Label", new Type[2]
			{
				typeof(RectTransform),
				typeof(TextMeshProUGUI)
			});
			val2.transform.SetParent(val.transform, false);
			RectTransform val3 = (RectTransform)val2.transform;
			val3.anchorMin = Vector2.zero;
			val3.anchorMax = Vector2.one;
			val3.offsetMin = Vector2.zero;
			val3.offsetMax = Vector2.zero;
			TextMeshProUGUI component3 = val2.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component3).text = label;
			((TMP_Text)component3).fontSize = fontSize;
			((TMP_Text)component3).alignment = (TextAlignmentOptions)514;
			((Graphic)component3).color = Color.white;
			((TMP_Text)component3).enableAutoSizing = true;
			((TMP_Text)component3).fontSizeMin = 0.06f;
			((TMP_Text)component3).fontSizeMax = fontSize;
			((TMP_Text)component3).enableWordWrapping = true;
			((TMP_Text)component3).overflowMode = (TextOverflowModes)3;
			return component;
		}

		public static void RefreshList()
		{
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Expected O, but got Unknown
			//IL_0116: 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)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Expected O, but got Unknown
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_030e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_content == (Object)null || (Object)(object)ItemManager.instance == (Object)null)
			{
				return;
			}
			for (int num = ((Transform)_content).childCount - 1; num >= 0; num--)
			{
				Object.Destroy((Object)(object)((Component)((Transform)_content).GetChild(num)).gameObject);
			}
			_rowImages.Clear();
			List<(Item, int)> list = CurrentGrouped();
			if (_selectedRowIndex >= list.Count)
			{
				_selectedRowIndex = Math.Max(0, list.Count - 1);
			}
			if (list.Count == 0)
			{
				AddLabel((Transform)(object)_content, "No items in this category", 0.14f, 0.3f);
			}
			else
			{
				foreach (var item3 in list)
				{
					Item item = item3.Item1;
					int item2 = item3.Item2;
					GameObject val = new GameObject("Row_" + item.itemName, new Type[4]
					{
						typeof(RectTransform),
						typeof(Image),
						typeof(HorizontalLayoutGroup),
						typeof(LayoutElement)
					});
					((Transform)(RectTransform)val.transform).SetParent((Transform)(object)_content, false);
					Image component = val.GetComponent<Image>();
					((Graphic)component).color = RowColor;
					_rowImages.Add(component);
					LayoutElement component2 = val.GetComponent<LayoutElement>();
					component2.preferredHeight = 0.32f;
					component2.minHeight = 0.32f;
					component2.flexibleHeight = 0f;
					HorizontalLayoutGroup component3 = val.GetComponent<HorizontalLayoutGroup>();
					((LayoutGroup)component3).padding = new RectOffset(0, 0, 0, 0);
					((HorizontalOrVerticalLayoutGroup)component3).spacing = 0.04f;
					((LayoutGroup)component3).childAlignment = (TextAnchor)3;
					((HorizontalOrVerticalLayoutGroup)component3).childForceExpandHeight = true;
					((HorizontalOrVerticalLayoutGroup)component3).childForceExpandWidth = false;
					((HorizontalOrVerticalLayoutGroup)component3).childControlHeight = true;
					((HorizontalOrVerticalLayoutGroup)component3).childControlWidth = true;
					GameObject val2 = new GameObject("Icon", new Type[3]
					{
						typeof(RectTransform),
						typeof(Image),
						typeof(LayoutElement)
					});
					val2.transform.SetParent(val.transform, false);
					LayoutElement component4 = val2.GetComponent<LayoutElement>();
					component4.preferredWidth = 0.26f;
					component4.preferredHeight = 0.26f;
					component4.minWidth = 0.26f;
					component4.minHeight = 0.26f;
					component4.flexibleWidth = 0f;
					component4.flexibleHeight = 0f;
					Image component5 = val2.GetComponent<Image>();
					Sprite icon = GetIcon(item);
					if ((Object)(object)icon != (Object)null)
					{
						component5.sprite = icon;
						component5.preserveAspect = true;
					}
					else
					{
						((Graphic)component5).color = new Color(1f, 1f, 1f, 0.15f);
					}
					GameObject val3 = new GameObject("Label", new Type[3]
					{
						typeof(RectTransform),
						typeof(TextMeshProUGUI),
						typeof(LayoutElement)
					});
					val3.transform.SetParent(val.transform, false);
					RectTransform val4 = (RectTransform)val3.transform;
					val4.anchorMin = new Vector2(0f, 0f);
					val4.anchorMax = new Vector2(1f, 1f);
					val4.offsetMin = Vector2.zero;
					val4.offsetMax = Vector2.zero;
					LayoutElement component6 = val3.GetComponent<LayoutElement>();
					component6.flexibleWidth = 1f;
					component6.minWidth = 0.5f;
					component6.minHeight = 0.3f;
					component6.preferredHeight = 0.3f;
					TextMeshProUGUI component7 = val3.GetComponent<TextMeshProUGUI>();
					int num2 = Favorites.Get(item.itemName);
					string arg = ((num2 > 0) ? ((num2 == GetOwnedTotal(item)) ? "* " : $"*{num2} ") : "");
					((TMP_Text)component7).text = $"{arg}{item.itemName}  x{item2}";
					((TMP_Text)component7).fontSize = 0.16f;
					((Graphic)component7).color = Color.white;
					((TMP_Text)component7).alignment = (TextAlignmentOptions)513;
					((TMP_Text)component7).enableWordWrapping = false;
					((TMP_Text)component7).overflowMode = (TextOverflowModes)0;
				}
			}
			UpdateHighlight();
		}

		private static void UpdateHighlight()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			string[] order = ItemCategories.Order;
			for (int i = 0; i < _tabImages.Count; i++)
			{
				GetTabColors(order[i], out var normal, out var selected);
				((Graphic)_tabImages[i]).color = ((i == _selectedCategoryIndex) ? selected : normal);
			}
			for (int j = 0; j < _rowImages.Count; j++)
			{
				((Graphic)_rowImages[j]).color = ((j == _selectedRowIndex) ? RowSelectedColor : RowColor);
			}
		}

		private static void ScrollToSelected()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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)
			if ((Object)(object)_scroll == (Object)null || _rowImages.Count == 0)
			{
				return;
			}
			Rect rect = ((RectTransform)((Component)_scroll).transform).rect;
			float height = ((Rect)(ref rect)).height;
			rect = _content.rect;
			float height2 = ((Rect)(ref rect)).height;
			if (height2 <= height)
			{
				_scroll.verticalNormalizedPosition = 1f;
				return;
			}
			float num = height2 / (float)_rowImages.Count;
			float num2 = (float)_selectedRowIndex * num;
			float num3 = num2 + num;
			float num4 = height2 - height;
			float num5 = (1f - _scroll.verticalNormalizedPosition) * num4;
			float num6 = num5 + height;
			float num7 = num5;
			if (num2 < num5)
			{
				num7 = num2;
			}
			else if (num3 > num6)
			{
				num7 = num3 - height;
			}
			num7 = Mathf.Clamp(num7, 0f, num4);
			_scroll.verticalNormalizedPosition = 1f - num7 / num4;
		}

		private static Sprite GetIcon(Item item)
		{
			if (_iconCache.TryGetValue(((Object)item).name, out var value))
			{
				return value;
			}
			Sprite val = SemiFunc.LoadSpriteFromFile(Path.Combine(Application.persistentDataPath, "Cache", "Icons", "Items", ((Object)item).name.ToLowerInvariant() + ".png"));
			_iconCache[((Object)item).name] = val;
			return val;
		}
	}
	[BepInPlugin("kohei.repo.loadoutmanager", "REPO Loadout Manager", "0.1.5")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "kohei.repo.loadoutmanager";

		public const string PluginName = "REPO Loadout Manager";

		public const string PluginVersion = "0.1.5";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> DebugDumpsEnabled;

		internal static ConfigEntry<bool> DebugHotkeysEnabled;

		internal static ConfigEntry<bool> DisableFavoritesPatch;

		private void Awake()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			DebugDumpsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableDebugDumps", false, "Log the full item DB and the truck monitor's 3D hierarchy once, for development. Leave off unless debugging.");
			DebugHotkeysEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableDebugHotkeys", false, "Ctrl+F9 = jump straight to Prepare (via Shop), Ctrl+F10 = advance one step (Shop->Prepare->Run->Shop...), Ctrl+F11 = jump straight to a Run level. Off by default - these are level-skip shortcuts for testing, not meant for normal play. Enable only when debugging.");
			DisableFavoritesPatch = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DisableFavoritesPatch", false, "Temporary isolation switch: when true, PunManager.TruckPopulateItemVolumes runs 100% vanilla (no purchasedItems truncation for favorites). Used to test whether that patch is the cause of the belt-slot item loss bug.");
			Favorites.Load();
			new Harmony("kohei.repo.loadoutmanager").PatchAll();
			Log.LogInfo((object)"REPO Loadout Manager v0.1.5 loaded.");
		}
	}
	[HarmonyPatch(typeof(ItemManager), "Awake")]
	internal static class ItemManager_Awake_Patch
	{
		private static void Postfix()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			if (!((Object)(object)ItemSpawnerRuntime.Instance != (Object)null))
			{
				GameObject val = new GameObject("REPO.ItemSpawner.Runtime");
				Object.DontDestroyOnLoad((Object)val);
				ItemSpawnerRuntime.Instance = val.AddComponent<ItemSpawnerRuntime>();
				Plugin.Log.LogInfo((object)"[ItemSpawner] Runtime UI object created.");
			}
		}
	}
	internal class ItemSpawnerRuntime : MonoBehaviour
	{
		public static ItemSpawnerRuntime Instance;

		private static readonly FieldRef<RunManager, bool> RunManagerRestartingRef = AccessTools.FieldRefAccess<RunManager, bool>("restarting");

		private void OnDisable()
		{
			Plugin.Log.LogWarning((object)"[ItemSpawner] Runtime OnDisable - Update() will stop firing.");
		}

		private void OnDestroy()
		{
			Plugin.Log.LogWarning((object)"[ItemSpawner] Runtime OnDestroy.");
		}

		private void Update()
		{
			if (ItemSpawnerState.MonitorActive)
			{
				if (Input.GetKeyDown((KeyCode)274))
				{
					MonitorUI.MoveSelection(1);
				}
				else if (Input.GetKeyDown((KeyCode)273))
				{
					MonitorUI.MoveSelection(-1);
				}
				else if (Input.GetKeyDown((KeyCode)275))
				{
					MonitorUI.ChangeCategory(1);
				}
				else if (Input.GetKeyDown((KeyCode)276))
				{
					MonitorUI.ChangeCategory(-1);
				}
				else if (Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)271))
				{
					MonitorUI.ConfirmSelection();
				}
				else if (Input.GetKeyDown((KeyCode)102))
				{
					MonitorUI.CycleFavoriteSelected();
				}
				else if (Input.GetKeyDown((KeyCode)104))
				{
					MonitorUI.ToggleHiddenSelected();
				}
			}
			if (Plugin.DebugHotkeysEnabled.Value && !((Object)(object)RunManager.instance == (Object)null) && (Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305)))
			{
				if (Input.GetKeyDown((KeyCode)290))
				{
					Plugin.Log.LogInfo((object)$"[Debug] Ctrl+F9 pressed. MenuLevel={SemiFunc.MenuLevel()} MasterOrSP={SemiFunc.IsMasterClientOrSingleplayer()} restarting={RunManagerRestartingRef.Invoke(RunManager.instance)}");
					RunManager.instance.ChangeLevel(false, false, (ChangeLevelType)5);
					((MonoBehaviour)this).StartCoroutine(AdvanceToPrepareAfterShop());
				}
				else if (Input.GetKeyDown((KeyCode)291))
				{
					Plugin.Log.LogInfo((object)$"[Debug] Ctrl+F10 pressed. MenuLevel={SemiFunc.MenuLevel()} MasterOrSP={SemiFunc.IsMasterClientOrSingleplayer()} restarting={RunManagerRestartingRef.Invoke(RunManager.instance)}");
					RunManager.instance.ChangeLevel(false, false, (ChangeLevelType)0);
					Plugin.Log.LogInfo((object)"[Debug] Advanced one step (Shop->Prepare / Prepare->Run / Run->Shop).");
				}
				else if (Input.GetKeyDown((KeyCode)292))
				{
					Plugin.Log.LogInfo((object)$"[Debug] Ctrl+F11 pressed. MenuLevel={SemiFunc.MenuLevel()} MasterOrSP={SemiFunc.IsMasterClientOrSingleplayer()} restarting={RunManagerRestartingRef.Invoke(RunManager.instance)}");
					RunManager.instance.ChangeLevel(false, false, (ChangeLevelType)1);
					Plugin.Log.LogInfo((object)"[Debug] Jumped straight to a Run level.");
				}
			}
		}

		private IEnumerator AdvanceToPrepareAfterShop()
		{
			float elapsed = 0f;
			while (!SemiFunc.RunIsShop() && elapsed < 10f)
			{
				yield return (object)new WaitForSeconds(0.2f);
				elapsed += 0.2f;
			}
			if (elapsed >= 10f)
			{
				Plugin.Log.LogWarning((object)"[Debug] Ctrl+F9: timed out waiting for Shop to load, not advancing to Prepare.");
				yield break;
			}
			yield return (object)new WaitForSeconds(0.5f);
			RunManager.instance.ChangeLevel(false, false, (ChangeLevelType)0);
			Plugin.Log.LogInfo((object)"[Debug] Ctrl+F9: Shop -> Prepare.");
		}
	}
	[HarmonyPatch(typeof(TruckScreenText), "Update")]
	internal static class TruckScreenText_HierarchyDump_Patch
	{
		private static bool _dumped;

		private static void Postfix(TruckScreenText __instance)
		{
			if (!_dumped && ItemSpawnerState.MonitorActive && Plugin.DebugDumpsEnabled.Value)
			{
				_dumped = true;
				Plugin.Log.LogInfo((object)"=== TruckScreenText hierarchy dump ===");
				DumpRecursive(((Component)__instance).transform, 0);
				Plugin.Log.LogInfo((object)"=== end hierarchy dump ===");
			}
		}

		private static void DumpRecursive(Transform t, int depth)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_0060: 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)
			string text = new string(' ', depth * 2);
			Renderer component = ((Component)t).GetComponent<Renderer>();
			object obj;
			if (!((Object)(object)component != (Object)null))
			{
				obj = "";
			}
			else
			{
				Bounds bounds = component.bounds;
				obj = $" [Renderer bounds={((Bounds)(ref bounds)).size}]";
			}
			string text2 = (string)obj;
			Plugin.Log.LogInfo((object)$"{text}{((Object)t).name}  localPos={t.localPosition} localScale={t.localScale}{text2}");
			for (int i = 0; i < t.childCount; i++)
			{
				DumpRecursive(t.GetChild(i), depth + 1);
			}
		}
	}
	internal static class ItemSpawnerState
	{
		public static bool MonitorActive;
	}
	[HarmonyPatch(typeof(RunManager), "ChangeLevel")]
	internal static class RunManager_ChangeLevel_Diag_Patch
	{
		private static void Prefix()
		{
			DumpSpawnedItems("BEFORE ChangeLevel");
		}

		private static void Postfix()
		{
			ItemSpawnerRuntime instance = ItemSpawnerRuntime.Instance;
			if (instance != null)
			{
				((MonoBehaviour)instance).StartCoroutine(DumpAfterDelay());
			}
		}

		private static IEnumerator DumpAfterDelay()
		{
			yield return (object)new WaitForSeconds(1.5f);
			DumpSpawnedItems("1.5s AFTER ChangeLevel");
		}

		private static void DumpSpawnedItems(string label)
		{
			if ((Object)(object)ItemManager.instance == (Object)null)
			{
				Plugin.Log.LogInfo((object)("[Diag] " + label + ": ItemManager.instance is null."));
				return;
			}
			List<ItemAttributes> spawnedItems = ItemManager.instance.spawnedItems;
			Plugin.Log.LogInfo((object)$"[Diag] {label}: spawnedItems.Count={spawnedItems.Count}");
			foreach (ItemAttributes item in spawnedItems)
			{
				bool flag = (Object)(object)item != (Object)null;
				Plugin.Log.LogInfo((object)("[Diag]   " + (flag ? "ALIVE" : "DESTROYED") + " - " + (flag ? ((Object)((Component)item).gameObject).name : "?")));
			}
		}
	}
	[HarmonyPatch(typeof(RunManager), "GameDirectorStart")]
	internal static class RunManager_GameDirectorStart_Diag_Patch
	{
		private static void Postfix()
		{
			Plugin.Log.LogInfo((object)"[Diag] GameDirectorStart fired - run is now officially active (Prepare -> Run, no scene reload).");
			DumpSlots("AT GameDirectorStart");
			ItemSpawnerRuntime instance = ItemSpawnerRuntime.Instance;
			if (instance != null)
			{
				((MonoBehaviour)instance).StartCoroutine(DumpSlotsAfterDelay());
			}
		}

		private static IEnumerator DumpSlotsAfterDelay()
		{
			yield return (object)new WaitForSeconds(1.5f);
			DumpSlots("1.5s AFTER GameDirectorStart");
		}

		private static void DumpSlots(string label)
		{
			if ((Object)(object)Inventory.instance == (Object)null)
			{
				Plugin.Log.LogInfo((object)("[Diag] " + label + ": Inventory.instance is null."));
				return;
			}
			List<InventorySpot> allSpots = Inventory.instance.GetAllSpots();
			for (int i = 0; i < allSpots.Count; i++)
			{
				InventorySpot obj = allSpots[i];
				ItemEquippable val = ((obj != null) ? obj.CurrentItem : null);
				Plugin.Log.LogInfo((object)string.Format("[Diag] {0}: slot {1} = {2}", label, i, ((Object)(object)val != (Object)null) ? ((Object)val).name : "EMPTY"));
			}
		}
	}
	[HarmonyPatch(typeof(StatsManager), "PlayerInventoryUpdate")]
	internal static class StatsManager_PlayerInventoryUpdate_Diag_Patch
	{
		private static void Prefix(string _steamID, string itemName, int spot, bool sync)
		{
			Plugin.Log.LogInfo((object)$"[Diag] PlayerInventoryUpdate: steamID={_steamID} itemName='{itemName}' spot={spot} sync={sync}");
		}
	}
	[HarmonyPatch(typeof(StatsManager), "LoadItemsFromFolder")]
	internal static class StatsManager_LoadItemsFromFolder_Patch
	{
		private static bool _dumped;

		private static void Postfix(StatsManager __instance)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			if (_dumped || !Plugin.DebugDumpsEnabled.Value)
			{
				return;
			}
			_dumped = true;
			Plugin.Log.LogInfo((object)$"=== Item DB dump ({__instance.itemDictionary.Count} items) ===");
			foreach (KeyValuePair<string, Item> item in __instance.itemDictionary.OrderBy((KeyValuePair<string, Item> kv) => ((object)Unsafe.As<itemType, itemType>(ref kv.Value.itemType)/*cast due to .constrained prefix*/).ToString()))
			{
				Item value = item.Value;
				Plugin.Log.LogInfo((object)$"[{value.itemType}] key={item.Key} itemName=\"{value.itemName}\" category={ItemCategories.Of(value)} disabled={value.disabled}");
			}
			Plugin.Log.LogInfo((object)"=== end item DB dump ===");
		}
	}
	internal static class ItemCategories
	{
		public const string All = "All";

		public const string Favorite = "Favorite";

		public const string Hide = "Hide";

		private static readonly Dictionary<itemType, string> Map = new Dictionary<itemType, string>
		{
			{
				(itemType)9,
				"Weapons"
			},
			{
				(itemType)7,
				"Weapons"
			},
			{
				(itemType)6,
				"Weapons"
			},
			{
				(itemType)15,
				"Weapons"
			},
			{
				(itemType)11,
				"Weapons"
			},
			{
				(itemType)0,
				"Drones"
			},
			{
				(itemType)1,
				"Drones"
			},
			{
				(itemType)10,
				"Drones"
			},
			{
				(itemType)8,
				"Healing"
			},
			{
				(itemType)3,
				"Upgrades"
			},
			{
				(itemType)4,
				"Upgrades"
			},
			{
				(itemType)2,
				"Vehicles"
			},
			{
				(itemType)12,
				"Vehicles"
			},
			{
				(itemType)14,
				"Vehicles"
			},
			{
				(itemType)13,
				"Tools"
			},
			{
				(itemType)5,
				"Other"
			}
		};

		public static readonly string[] Order = new string[10] { "All", "Favorite", "Hide", "Weapons", "Drones", "Healing", "Upgrades", "Vehicles", "Tools", "Other" };

		public static string Of(Item item)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (!Map.TryGetValue(item.itemType, out var value))
			{
				return "Other";
			}
			return value;
		}
	}
	[HarmonyPatch(typeof(TruckScreenText), "Update")]
	internal static class TruckScreenText_Update_Patch
	{
		private static readonly FieldRef<TruckScreenText, bool> ScreenActiveRef = AccessTools.FieldRefAccess<TruckScreenText, bool>("screenActive");

		private const float MaxInteractDistance = 8f;

		private static void Postfix(TruckScreenText __instance)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			bool flag = ScreenActiveRef.Invoke(__instance) && !SemiFunc.RunIsShop();
			if (flag)
			{
				PlayerAvatar val = SemiFunc.PlayerGetLocal();
				if ((Object)(object)val == (Object)null)
				{
					flag = false;
				}
				else if (Vector3.Distance(val.playerTransform.position, ((Component)__instance).transform.position) > 8f)
				{
					flag = false;
				}
			}
			ItemSpawnerState.MonitorActive = flag;
			MonitorUI.SetVisible(flag);
		}
	}
	[HarmonyPatch(typeof(PunManager), "TruckPopulateItemVolumes")]
	internal static class PunManager_TruckPopulateItemVolumes_Patch
	{
		private static void Prefix()
		{
			if (!Plugin.DisableFavoritesPatch.Value && !SemiFunc.IsNotMasterClient() && SemiFunc.IsMultiplayer())
			{
				((MonoBehaviourPun)((Component)PunManager.instance).GetComponent<ItemSpawnerNetwork>()).photonView.RPC("SyncFavoritesRPC", (RpcTarget)1, new object[2]
				{
					Favorites.Counts.Keys.ToArray(),
					Favorites.Counts.Values.ToArray()
				});
			}
		}

		private static void Postfix()
		{
			if (!Plugin.DisableFavoritesPatch.Value && !SemiFunc.IsNotMasterClient())
			{
				ItemSpawnerRuntime instance = ItemSpawnerRuntime.Instance;
				if (instance != null)
				{
					((MonoBehaviour)instance).StartCoroutine(CullNonFavoritedAfterSpawn());
				}
			}
		}

		private static IEnumerator CullNonFavoritedAfterSpawn()
		{
			yield return (object)new WaitForSeconds(0.3f);
			ItemManager instance = ItemManager.instance;
			List<ItemAttributes> spawnedItems = instance.spawnedItems;
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			int num = 0;
			int num2 = 0;
			for (int num3 = spawnedItems.Count - 1; num3 >= 0; num3--)
			{
				ItemAttributes val = spawnedItems[num3];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.item == (Object)null))
				{
					string itemName = val.item.itemName;
					int num4 = Favorites.Get(itemName);
					int value;
					int num5 = (dictionary.TryGetValue(itemName, out value) ? value : 0);
					if (num5 < num4)
					{
						dictionary[itemName] = num5 + 1;
					}
					else
					{
						ItemEquippable component = ((Component)val).GetComponent<ItemEquippable>();
						if ((Object)(object)component != (Object)null && (Object)(object)Inventory.instance != (Object)null && Inventory.instance.IsItemEquipped(component))
						{
							dictionary[itemName] = num5 + 1;
							num2++;
						}
						else
						{
							PhotonView val2 = (SemiFunc.IsMultiplayer() ? ((Component)val).GetComponent<PhotonView>() : null);
							if ((Object)(object)val2 != (Object)null)
							{
								PhotonNetwork.Destroy(val2);
							}
							else
							{
								Object.Destroy((Object)(object)((Component)val).gameObject);
							}
							spawnedItems.RemoveAt(num3);
							num++;
						}
					}
				}
			}
			foreach (KeyValuePair<string, int> kv in dictionary)
			{
				for (int i = 0; i < kv.Value; i++)
				{
					int num6 = instance.purchasedItems.FindIndex((Item it) => it.itemName == kv.Key);
					if (num6 >= 0)
					{
						instance.purchasedItems.RemoveAt(num6);
					}
				}
			}
			if (SemiFunc.IsMultiplayer() && dictionary.Count > 0)
			{
				((MonoBehaviourPun)((Component)PunManager.instance).GetComponent<ItemSpawnerNetwork>()).photonView.RPC("ConsumeStockBatchRPC", (RpcTarget)1, new object[2]
				{
					dictionary.Keys.ToArray(),
					dictionary.Values.ToArray()
				});
			}
			Plugin.Log.LogInfo((object)$"[ItemSpawner] Truck auto-spawn: kept {dictionary.Values.Sum()} instance(s) across {dictionary.Count} type(s) ({num2} kept only because already equipped), removed {num} non-favorited vanilla-scattered instance(s).");
			MonitorUI.RefreshList();
		}
	}
	internal static class Favorites
	{
		public static readonly Dictionary<string, int> Counts = new Dictionary<string, int>();

		private static readonly string SaveFilePath = Path.Combine(Paths.ConfigPath, "REPO.LoadoutManager.Favorites.txt");

		public static int Get(string itemName)
		{
			if (!Counts.TryGetValue(itemName, out var value))
			{
				return 0;
			}
			return value;
		}

		public static void Set(string itemName, int count)
		{
			if (count <= 0)
			{
				Counts.Remove(itemName);
			}
			else
			{
				Counts[itemName] = count;
			}
			Save();
		}

		public static int Cycle(string itemName, int ownedCount)
		{
			int num = Get(itemName) + 1;
			if (num > ownedCount)
			{
				num = 0;
			}
			Set(itemName, num);
			return num;
		}

		public static void ReplaceAll(IEnumerable<string> names, IEnumerable<int> counts)
		{
			Counts.Clear();
			using IEnumerator<string> enumerator = names.GetEnumerator();
			using IEnumerator<int> enumerator2 = counts.GetEnumerator();
			while (enumerator.MoveNext() && enumerator2.MoveNext())
			{
				if (enumerator2.Current > 0)
				{
					Counts[enumerator.Current] = enumerator2.Current;
				}
			}
			Save();
		}

		public static void Load()
		{
			try
			{
				if (!File.Exists(SaveFilePath))
				{
					return;
				}
				Counts.Clear();
				string[] array = File.ReadAllLines(SaveFilePath);
				for (int i = 0; i < array.Length; i++)
				{
					string[] array2 = array[i].Split(new char[1] { '=' });
					if (array2.Length == 2 && int.TryParse(array2[1], out var result) && result > 0)
					{
						Counts[array2[0]] = result;
					}
				}
				Plugin.Log.LogInfo((object)$"[Favorites] Loaded {Counts.Count} saved favorite(s) from disk.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Favorites] Failed to load saved favorites: " + ex.Message));
			}
		}

		private static void Save()
		{
			try
			{
				File.WriteAllLines(SaveFilePath, Counts.Select((KeyValuePair<string, int> kv) => $"{kv.Key}={kv.Value}"));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Favorites] Failed to save favorites: " + ex.Message));
			}
		}
	}
	internal static class Hidden
	{
		public static readonly HashSet<string> Set = new HashSet<string>();

		public static bool Toggle(string itemName)
		{
			if (Set.Contains(itemName))
			{
				Set.Remove(itemName);
				return false;
			}
			Set.Add(itemName);
			return true;
		}
	}
	[HarmonyPatch(typeof(PunManager), "Awake")]
	internal static class PunManager_Awake_Patch
	{
		private static void Postfix(PunManager __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponent<ItemSpawnerNetwork>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<ItemSpawnerNetwork>();
			}
		}
	}
	internal class ItemSpawnerNetwork : MonoBehaviourPun
	{
		[PunRPC]
		public void RequestSpawnRPC(string itemName, Vector3 position, Quaternion rotation, PhotonMessageInfo info = default(PhotonMessageInfo))
		{
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: 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)
			if (SemiFunc.IsMasterClient())
			{
				Item val = ((IEnumerable<Item>)StatsManager.instance.itemDictionary.Values).FirstOrDefault((Func<Item, bool>)((Item it) => it.itemName == itemName));
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogWarning((object)("Spawn request for unknown item: " + itemName));
				}
				else if (!ItemManager.instance.purchasedItems.Any((Item i) => i.itemName == itemName))
				{
					ManualLogSource log = Plugin.Log;
					string[] obj = new string[5] { "Rejected spawn request - no remaining stock of ", itemName, " (requested by ", null, null };
					Player sender = info.Sender;
					obj[3] = ((sender != null) ? sender.NickName : null);
					obj[4] = ")";
					log.LogWarning((object)string.Concat(obj));
				}
				else
				{
					PhotonNetwork.InstantiateRoomObject(((PrefabRef<GameObject>)(object)val.prefab).ResourcePath, position, rotation, (byte)0, (object[])null);
					((MonoBehaviourPun)this).photonView.RPC("ConsumeStockRPC", (RpcTarget)0, new object[1] { itemName });
				}
			}
		}

		[PunRPC]
		public void ConsumeStockRPC(string itemName)
		{
			List<Item> purchasedItems = ItemManager.instance.purchasedItems;
			int num = purchasedItems.FindIndex((Item i) => i.itemName == itemName);
			if (num >= 0)
			{
				purchasedItems.RemoveAt(num);
			}
			else
			{
				Plugin.Log.LogWarning((object)("ConsumeStockRPC: no local stock entry found for " + itemName + "."));
			}
		}

		[PunRPC]
		public void ConsumeStockBatchRPC(string[] itemNames, int[] counts)
		{
			List<Item> purchasedItems = ItemManager.instance.purchasedItems;
			int i;
			for (i = 0; i < itemNames.Length; i++)
			{
				for (int j = 0; j < counts[i]; j++)
				{
					int num = purchasedItems.FindIndex((Item it) => it.itemName == itemNames[i]);
					if (num >= 0)
					{
						purchasedItems.RemoveAt(num);
					}
					else
					{
						Plugin.Log.LogWarning((object)("ConsumeStockBatchRPC: no local stock entry found for " + itemNames[i] + "."));
					}
				}
			}
			MonitorUI.RefreshList();
		}

		[PunRPC]
		public void RequestCycleFavoriteRPC(string itemName, int ownedCount, PhotonMessageInfo info = default(PhotonMessageInfo))
		{
			if (SemiFunc.IsMasterClient())
			{
				int num = Favorites.Cycle(itemName, ownedCount);
				((MonoBehaviourPun)this).photonView.RPC("SetFavoriteRPC", (RpcTarget)0, new object[2] { itemName, num });
			}
		}

		[PunRPC]
		public void SetFavoriteRPC(string itemName, int count)
		{
			Favorites.Set(itemName, count);
			MonitorUI.RefreshList();
		}

		[PunRPC]
		public void SyncFavoritesRPC(string[] itemNames, int[] counts)
		{
			Favorites.ReplaceAll(itemNames, counts);
			MonitorUI.RefreshList();
		}
	}
	internal static class ItemSpawner
	{
		public static void RequestSpawn(Item item)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: 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_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)item == (Object)null)
			{
				return;
			}
			PlayerAvatar val = SemiFunc.PlayerGetLocal();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Vector3 val2 = val.playerTransform.position + val.playerTransform.forward * 1.5f;
			Quaternion identity = Quaternion.identity;
			if (!SemiFunc.IsMultiplayer())
			{
				List<Item> purchasedItems = ItemManager.instance.purchasedItems;
				int num = purchasedItems.FindIndex((Item i) => i.itemName == item.itemName);
				if (num < 0)
				{
					Plugin.Log.LogWarning((object)("Blocked spawn - no remaining stock of " + item.itemName));
					return;
				}
				purchasedItems.RemoveAt(num);
				Object.Instantiate<GameObject>(((PrefabRef<GameObject>)(object)item.prefab).Prefab, val2, identity);
			}
			else
			{
				((MonoBehaviourPun)((Component)PunManager.instance).GetComponent<ItemSpawnerNetwork>()).photonView.RPC("RequestSpawnRPC", (RpcTarget)2, new object[3] { item.itemName, val2, identity });
			}
		}

		public static void RequestCycleFavorite(Item item, int ownedCount)
		{
			if ((Object)(object)item == (Object)null)
			{
				return;
			}
			if (!SemiFunc.IsMultiplayer())
			{
				int num = Favorites.Cycle(item.itemName, ownedCount);
				Plugin.Log.LogInfo((object)$"[MonitorUI] {item.itemName} favorite count -> {num}/{ownedCount}");
				MonitorUI.RefreshList();
				return;
			}
			ItemSpawnerNetwork component = ((Component)PunManager.instance).GetComponent<ItemSpawnerNetwork>();
			if (SemiFunc.IsMasterClient())
			{
				int num2 = Favorites.Cycle(item.itemName, ownedCount);
				((MonoBehaviourPun)component).photonView.RPC("SetFavoriteRPC", (RpcTarget)1, new object[2] { item.itemName, num2 });
				Plugin.Log.LogInfo((object)$"[MonitorUI] {item.itemName} favorite count -> {num2}/{ownedCount}");
				MonitorUI.RefreshList();
			}
			else
			{
				((MonoBehaviourPun)component).photonView.RPC("RequestCycleFavoriteRPC", (RpcTarget)2, new object[2] { item.itemName, ownedCount });
			}
		}
	}
}