Decompiled source of OtherLoaderPatched v2.0.3

patchers\Sirdoggy.OldOtherLoaderDisabler.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Valve.Newtonsoft.Json.Linq;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("Sirdoggy")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Sirdoggy.OldOtherLoaderDisabler")]
[assembly: AssemblyTitle("OldOtherLoaderDisabler")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Sirdoggy.OldOtherLoaderDisabler
{
	public static class OldOtherLoaderDisablerPatcher
	{
		private const string OtherLoaderDllFullName = "OtherLoader.dll";

		private const string OtherLoaderDllFullNameDisabled = "OtherLoader.dll.old";

		private const string ManifestFullName = "manifest.json";

		private static readonly ManualLogSource Log = Logger.CreateLogSource("OldOtherLoaderDisabler");

		public static IEnumerable<string> TargetDLLs => Enumerable.Empty<string>();

		internal static void Initialize()
		{
			try
			{
				Log.LogMessage((object)"Attempting to disable original OtherLoader dlls.");
				foreach (string pluginDirectory in GetPluginDirectories())
				{
					if (!IsOldOtherLoaderDirectoryWithEnabledManifest(pluginDirectory))
					{
						continue;
					}
					string text = Path.Combine(pluginDirectory, "OtherLoader.dll");
					string text2 = Path.Combine(pluginDirectory, "OtherLoader.dll.old");
					if (!File.Exists(text))
					{
						Log.LogMessage((object)("Did not resolve 'OtherLoader.dll' in " + pluginDirectory + ", OtherLoader is likely already disabled."));
						continue;
					}
					if (File.Exists(text2))
					{
						File.Delete(text2);
					}
					File.Move(text, text2);
					Log.LogMessage((object)("Successfully disabled original OtherLoader in " + pluginDirectory));
				}
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Exception when disabling original OtherLoader dlls: {arg}");
			}
		}

		public static void RestoreOtherLoaderDll()
		{
			try
			{
				Log.LogMessage((object)"Attempting to restore original OtherLoader dlls");
				foreach (string pluginDirectory in GetPluginDirectories())
				{
					if (!IsOldOtherLoaderDirectoryWithEnabledManifest(pluginDirectory))
					{
						continue;
					}
					string text = Path.Combine(pluginDirectory, "OtherLoader.dll");
					string text2 = Path.Combine(pluginDirectory, "OtherLoader.dll.old");
					if (File.Exists(text2))
					{
						if (File.Exists(text))
						{
							Log.LogWarning((object)("Duplicate dlls exist in " + pluginDirectory + ", this shouldn't happen. Deleting dll.old and exiting..."));
							File.Delete(text2);
						}
						else
						{
							File.Move(text2, text);
							Log.LogMessage((object)("Successfully restored original OtherLoader dll in " + pluginDirectory));
						}
					}
				}
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Exception when restoring original OtherLoader dlls: {arg}");
			}
		}

		private static List<string> GetPluginDirectories()
		{
			List<string> list = Directory.GetDirectories(Paths.PluginPath, "*", SearchOption.TopDirectoryOnly).ToList();
			if (!list.Any())
			{
				throw new Exception("No directories in plugins folder found.");
			}
			return list;
		}

		private static bool IsOldOtherLoaderDirectoryWithEnabledManifest(string directory)
		{
			string path = Path.Combine(directory, "manifest.json");
			if (!File.Exists(path))
			{
				return false;
			}
			try
			{
				JObject obj = JObject.Parse(File.ReadAllText(path));
				string text = ((object)obj["name"])?.ToString();
				string text2 = ((object)obj["website_url"])?.ToString();
				return text == "OtherLoader" && text2 == "https://github.com/devyndamonster/OtherLoader";
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Exception parsing manifest in " + directory + ": " + ex.Message));
				return false;
			}
		}

		public static void Patch(AssemblyDefinition _)
		{
		}
	}
}

OtherLoader.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FistVR;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using OtherLoader.AssetLoading;
using OtherLoader.AssetLoading.AssetLoaders;
using OtherLoader.AssetLoading.AssetLoaders.Implementations;
using OtherLoader.Common;
using OtherLoader.Common.FVR;
using OtherLoader.Common.Unity;
using OtherLoader.ItemSpawner;
using OtherLoader.ItemSpawner.CustomCategories;
using OtherLoader.ItemSpawner.Patches;
using OtherLoader.ItemSpawner.PortableItemSpawner;
using OtherLoader.ItemSpawner.SecondaryObjectsLinker;
using OtherLoader.ItemSpawner.VanillaCategories;
using OtherLoader.ItemUnlocker;
using OtherLoader.Logging;
using OtherLoader.QuickbeltPanel;
using OtherLoader.Unlockathon;
using OtherLoader.Unlockathon.Data;
using OtherLoader.Unlockathon.Patches;
using OtherLoader.Unlockathon.Tags;
using Sirdoggy.OldOtherLoaderDisabler;
using Sodalite;
using Sodalite.Api;
using Sodalite.ModPanel;
using Stratum;
using Stratum.Extensions;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using Valve.Newtonsoft.Json;
using Valve.VR;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("OtherLoader")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("OtherLoader")]
[assembly: AssemblyTitle("OtherLoader")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class ParamCollectionAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace OtherLoader
{
	[CreateAssetMenu(menuName = "MeatKit/Otherloader/SpawnerEntry", fileName = "New Spawner Entry")]
	public class ItemSpawnerEntry : ScriptableObject
	{
		[Header("Item IDs")]
		[Tooltip("ItemID for the main object that will spawn")]
		public string MainObjectID;

		[Tooltip("ItemIDs for items that will spawn alongside the main object")]
		public List<string> SpawnWithIDs = new List<string>();

		[Tooltip("ItemIDs for items that appear in the secondary items section")]
		public List<string> SecondaryObjectIDs = new List<string>();

		[Header("[OPTIONAL] Populate ItemIDs using FVRObjects directly")]
		public FVRObject? MainObjectObj;

		public List<FVRObject> SpawnWithObjs = new List<FVRObject>();

		public List<FVRObject> SecondaryObjs = new List<FVRObject>();

		[Header("Entry Path Properties")]
		[Tooltip("The path for the entry")]
		public string EntryPath;

		public PageMode Page;

		public ESubCategory SubCategory;

		[Header("Display Properties")]
		[Tooltip("The icon that will appear in the spawner for this entry")]
		public Sprite EntryIcon;

		[Tooltip("The name of the entry")]
		public string DisplayName;

		[Tooltip("Decides wether the entry will be visible in the spawner.\n Set to false if you only want the entry visible as a secondary")]
		public bool IsDisplayedInMainEntry;

		[Tooltip("A list modding tags to allow for sorting by mod groups in itemspawner")]
		public List<string> ModTags = new List<string>();

		[Tooltip("A list of tutorial block IDs that will appear when this entry is selected")]
		public List<string> TutorialBlockIDs = new List<string>();

		[Header("Misc Properties")]
		public bool UsesLargeSpawnPad;

		public bool UsesHugeSpawnPad;

		public bool IsReward;

		internal bool IsUncategorized;

		public static ItemSpawnerEntry CreateEmpty(string path)
		{
			ItemSpawnerEntry itemSpawnerEntry = ScriptableObject.CreateInstance<ItemSpawnerEntry>();
			itemSpawnerEntry.EntryPath = path;
			return itemSpawnerEntry;
		}

		public void PopulateIDsFromObj()
		{
			if ((Object)(object)MainObjectObj != (Object)null)
			{
				MainObjectID = MainObjectObj.ItemID;
				OtherLogger.Log("Assigned MainObjectID '" + MainObjectID + "' from MainObjectObj.ItemID", LogTag.Assets);
			}
			foreach (FVRObject spawnWithObj in SpawnWithObjs)
			{
				if (!SpawnWithIDs.Contains(spawnWithObj.ItemID))
				{
					SpawnWithIDs.Add(spawnWithObj.ItemID);
				}
			}
			foreach (FVRObject secondaryObj in SecondaryObjs)
			{
				if (!SecondaryObjectIDs.Contains(secondaryObj.ItemID))
				{
					SecondaryObjectIDs.Add(secondaryObj.ItemID);
				}
			}
		}

		public bool IsCategoryEntry()
		{
			return string.IsNullOrEmpty(MainObjectID);
		}

		internal ESubCategory? GetSpawnerSubcategory()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			string[] array = (from o in EntryPath.Split(new char[1] { '/' })
				where Enum.IsDefined(typeof(ESubCategory), o)
				select o).ToArray();
			if (array.Length == 0)
			{
				return null;
			}
			return ((IEnumerable<string>)array).Select((Func<string, ESubCategory>)((string o) => (ESubCategory)Enum.Parse(typeof(ESubCategory), o))).FirstOrDefault();
		}

		internal EItemCategory? GetSpawnerCategory()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			string[] array = (from o in EntryPath.Split(new char[1] { '/' })
				where Enum.IsDefined(typeof(EItemCategory), o)
				select o).ToArray();
			if (array.Length == 0)
			{
				return null;
			}
			return ((IEnumerable<string>)array).Select((Func<string, EItemCategory>)((string o) => (EItemCategory)Enum.Parse(typeof(EItemCategory), o))).FirstOrDefault();
		}
	}
	public delegate void StatusUpdate(float progress);
	internal enum LoadOrder
	{
		LoadFirst,
		LoadLast,
		LoadUnordered
	}
	public static class LoaderStatus
	{
		private enum BundleStatus
		{
			Waiting,
			CanLoad,
			Loaded,
			Unloaded
		}

		private class BundleLoadStatus
		{
			public readonly string BundleId;

			public BundleStatus Status;

			public LoadOrder LoadOrder;

			public BundleLoadStatus(string bundleId, LoadOrder loadOrder)
			{
				BundleId = bundleId;
				LoadOrder = loadOrder;
				Status = BundleStatus.Waiting;
			}
		}

		private class ModContainer
		{
			private readonly List<BundleLoadStatus> _loadFirst = new List<BundleLoadStatus>();

			private readonly List<BundleLoadStatus> _loadUnordered = new List<BundleLoadStatus>();

			private readonly List<BundleLoadStatus> _loadLast = new List<BundleLoadStatus>();

			private readonly Dictionary<string, BundleLoadStatus> _bundleLoadStatusDic = new Dictionary<string, BundleLoadStatus>();

			public void AddToLoadOrder(string bundleID, LoadOrder loadOrder)
			{
				BundleLoadStatus bundleLoadStatus = new BundleLoadStatus(bundleID, loadOrder);
				if (_bundleLoadStatusDic.ContainsKey(bundleID))
				{
					BundleLoadStatus bundleLoadStatus2 = _bundleLoadStatusDic[bundleID];
					_bundleLoadStatusDic.Remove(bundleID);
					_loadFirst.Remove(bundleLoadStatus2);
					_loadUnordered.Remove(bundleLoadStatus2);
					_loadLast.Remove(bundleLoadStatus2);
					bundleLoadStatus.Status = BundleStatus.Unloaded;
					bundleLoadStatus.LoadOrder = bundleLoadStatus2.LoadOrder;
					if (bundleLoadStatus2.Status != BundleStatus.Loaded && bundleLoadStatus2.Status != BundleStatus.Unloaded)
					{
						OtherLogger.LogError("Tracking a late bundle, but the data bundle isn't already loaded! " + $"Data bundle status: {bundleLoadStatus2.Status}");
					}
				}
				else
				{
					if (loadOrder == LoadOrder.LoadFirst)
					{
						if (_loadFirst.Count == 0 || _loadFirst.All((BundleLoadStatus o) => o.Status == BundleStatus.Loaded || o.Status == BundleStatus.Unloaded))
						{
							bundleLoadStatus.Status = BundleStatus.CanLoad;
						}
						if (_loadUnordered.Count != 0 || _loadLast.Count != 0)
						{
							OtherLogger.LogError("Mod is set to load first, but it looks like unordered or load last mods are already loading! BundleID (" + bundleID + ")");
							_loadUnordered.ForEach(delegate(BundleLoadStatus o)
							{
								OtherLogger.LogError("Load Unordered BundleID (" + o.BundleId + ")");
							});
							_loadLast.ForEach(delegate(BundleLoadStatus o)
							{
								OtherLogger.LogError("Load Last BundleID (" + o.BundleId + ")");
							});
						}
					}
					if (loadOrder == LoadOrder.LoadUnordered)
					{
						if (_loadFirst.Count == 0 || _loadFirst.All((BundleLoadStatus o) => o.Status == BundleStatus.Loaded || o.Status == BundleStatus.Unloaded))
						{
							bundleLoadStatus.Status = BundleStatus.CanLoad;
						}
						if (_loadLast.Count != 0)
						{
							OtherLogger.LogError("Mod is set to load unordered, but it looks like load last mods are already loading! BundleID (" + bundleID + ")");
							_loadLast.ForEach(delegate(BundleLoadStatus o)
							{
								OtherLogger.LogError("Load Last BundleID (" + o.BundleId + ")");
							});
						}
					}
					if (loadOrder == LoadOrder.LoadLast && ((_loadFirst.Count == 0 && _loadUnordered.Count == 0 && _loadLast.Count == 0) || (_loadFirst.All((BundleLoadStatus o) => o.Status == BundleStatus.Loaded || o.Status == BundleStatus.Unloaded) && _loadUnordered.All((BundleLoadStatus o) => o.Status == BundleStatus.Loaded || o.Status == BundleStatus.Unloaded) && _loadLast.All((BundleLoadStatus o) => o.Status == BundleStatus.Loaded || o.Status == BundleStatus.Unloaded))))
					{
						bundleLoadStatus.Status = BundleStatus.CanLoad;
					}
				}
				_bundleLoadStatusDic.Add(bundleID, bundleLoadStatus);
				switch (loadOrder)
				{
				case LoadOrder.LoadFirst:
					_loadFirst.Add(bundleLoadStatus);
					break;
				case LoadOrder.LoadLast:
					_loadLast.Add(bundleLoadStatus);
					break;
				case LoadOrder.LoadUnordered:
					_loadUnordered.Add(bundleLoadStatus);
					break;
				}
			}

			public BundleStatus? TryGetBundleLoadStatus(string bundleID)
			{
				return _bundleLoadStatusDic.GetValueOrNull(bundleID)?.Status;
			}

			public void MarkBundleAsLoaded(string bundleID, bool permanentlyLoaded)
			{
				BundleLoadStatus bundleLoadStatus = _bundleLoadStatusDic[bundleID];
				if (permanentlyLoaded)
				{
					bundleLoadStatus.Status = BundleStatus.Loaded;
				}
				else
				{
					bundleLoadStatus.Status = BundleStatus.Unloaded;
				}
				if (bundleLoadStatus.LoadOrder == LoadOrder.LoadFirst)
				{
					BundleLoadStatus bundleLoadStatus2 = _loadFirst.FirstOrDefault((BundleLoadStatus o) => o.Status == BundleStatus.Waiting);
					if (bundleLoadStatus2 != null)
					{
						bundleLoadStatus2.Status = BundleStatus.CanLoad;
					}
					else if (_loadUnordered.Count > 0)
					{
						_loadUnordered.ForEach(delegate(BundleLoadStatus o)
						{
							o.Status = BundleStatus.CanLoad;
						});
					}
					else if (_loadLast.Count > 0)
					{
						_loadLast[0].Status = BundleStatus.CanLoad;
					}
				}
				else if (bundleLoadStatus.LoadOrder == LoadOrder.LoadUnordered)
				{
					if (_loadUnordered.All((BundleLoadStatus o) => o.Status == BundleStatus.Loaded || o.Status == BundleStatus.Unloaded) && _loadLast.Count != 0)
					{
						_loadLast[0].Status = BundleStatus.CanLoad;
					}
				}
				else if (bundleLoadStatus.LoadOrder == LoadOrder.LoadLast)
				{
					BundleLoadStatus bundleLoadStatus3 = _loadLast.FirstOrDefault((BundleLoadStatus o) => o.Status == BundleStatus.Waiting);
					if (bundleLoadStatus3 != null)
					{
						bundleLoadStatus3.Status = BundleStatus.CanLoad;
					}
				}
			}

			public List<BundleLoadStatus> GetBundleDependencies(string bundleID)
			{
				List<BundleLoadStatus> list = new List<BundleLoadStatus>();
				BundleLoadStatus bundleLoadStatus = _bundleLoadStatusDic[bundleID];
				if (bundleLoadStatus.LoadOrder == LoadOrder.LoadFirst)
				{
					foreach (BundleLoadStatus item in _loadFirst)
					{
						if (item.BundleId == bundleID)
						{
							break;
						}
						if (!AnvilManager.m_bundles.m_lookup.ContainsKey(item.BundleId))
						{
							list.Add(item);
						}
					}
				}
				else if (bundleLoadStatus.LoadOrder == LoadOrder.LoadUnordered)
				{
					foreach (BundleLoadStatus item2 in _loadFirst)
					{
						if (!AnvilManager.m_bundles.m_lookup.ContainsKey(item2.BundleId))
						{
							list.Add(item2);
						}
					}
				}
				else if (bundleLoadStatus.LoadOrder == LoadOrder.LoadLast)
				{
					foreach (BundleLoadStatus item3 in _loadFirst)
					{
						if (!AnvilManager.m_bundles.m_lookup.ContainsKey(item3.BundleId))
						{
							list.Add(item3);
						}
					}
					foreach (BundleLoadStatus item4 in _loadUnordered)
					{
						if (!AnvilManager.m_bundles.m_lookup.ContainsKey(item4.BundleId))
						{
							list.Add(item4);
						}
					}
					foreach (BundleLoadStatus item5 in _loadLast)
					{
						if (item5.BundleId == bundleID)
						{
							break;
						}
						if (!AnvilManager.m_bundles.m_lookup.ContainsKey(item5.BundleId))
						{
							list.Add(item5);
						}
					}
				}
				return list;
			}
		}

		internal static float LastLoadEventTime;

		private static float? _lastStatus;

		private static StatusUpdate? _progressUpdatedReplayingListeners;

		private static readonly List<string> ActiveLoaders = new List<string>();

		private static readonly Dictionary<string, ModContainer> ModContainers = new Dictionary<string, ModContainer>();

		private static readonly Dictionary<string, float> LoaderProgressDic = new Dictionary<string, float>();

		private static float _loadersProgressSum;

		private static float _loadStartTime;

		private const float LoadingCompleteMargin = 2f;

		public static event StatusUpdate? ProgressUpdated;

		public static event StatusUpdate? ProgressUpdatedReplaying
		{
			add
			{
				_progressUpdatedReplayingListeners = (StatusUpdate)Delegate.Combine(_progressUpdatedReplayingListeners, value);
				float? lastStatus = _lastStatus;
				if (lastStatus.HasValue)
				{
					value?.Invoke(_lastStatus.Value);
				}
			}
			remove
			{
				_progressUpdatedReplayingListeners = (StatusUpdate)Delegate.Remove(_progressUpdatedReplayingListeners, value);
			}
		}

		public static float GetLoaderProgress()
		{
			if (LoaderProgressDic.Count == 0)
			{
				return 0f;
			}
			float num = _loadersProgressSum / (float)LoaderProgressDic.Count;
			if (num > 0.99999f)
			{
				num = 1f;
			}
			if (!(Time.realtimeSinceStartup - LastLoadEventTime < 2f))
			{
				return num;
			}
			return Mathf.Min(num, 0.99f);
		}

		internal static IEnumerator LoadTimeCoroutine()
		{
			LastLoadEventTime = Time.realtimeSinceStartup;
			WaitForSeconds delay = new WaitForSeconds(0.1f);
			float loaderProgress;
			do
			{
				yield return delay;
				loaderProgress = GetLoaderProgress();
				DoStatusUpdate(loaderProgress);
			}
			while (loaderProgress < 1f);
			OtherLogger.Log($"All items loaded, took {Time.realtimeSinceStartup - _loadStartTime:0.000} seconds!");
		}

		private static void DoStatusUpdate(float status)
		{
			_lastStatus = status;
			_progressUpdatedReplayingListeners?.Invoke(status);
			LoaderStatus.ProgressUpdated?.Invoke(status);
		}

		internal static void AddActiveLoader(string bundleID)
		{
			if (!ActiveLoaders.Contains(bundleID))
			{
				ActiveLoaders.Add(bundleID);
			}
		}

		internal static void RemoveActiveLoader(BundleInfo bundleInfo, bool permanentlyLoaded)
		{
			string iD = bundleInfo.ID;
			if (ActiveLoaders.Contains(iD))
			{
				ActiveLoaders.Remove(iD);
				string fullDirectoryName = bundleInfo.FullDirectoryName;
				ModContainers[fullDirectoryName].MarkBundleAsLoaded(iD, permanentlyLoaded);
				LastLoadEventTime = Time.realtimeSinceStartup;
			}
		}

		internal static void TrackLoader(BundleInfo bundleInfo, LoadOrder loadOrder)
		{
			LastLoadEventTime = Time.realtimeSinceStartup;
			string iD = bundleInfo.ID;
			string fullDirectoryName = bundleInfo.FullDirectoryName;
			if (LoaderProgressDic.Count == 0)
			{
				_loadStartTime = Time.realtimeSinceStartup;
				OtherLogger.Log("Starting LoadTimeCoroutine", LogTag.BundleLoading);
				OtherLoader.CoroutineStarter.Invoke(LoadTimeCoroutine());
			}
			if (!LoaderProgressDic.ContainsKey(iD))
			{
				LoaderProgressDic.Add(iD, 0f);
			}
			if (!ModContainers.ContainsKey(fullDirectoryName))
			{
				OtherLogger.Log("Adding new load order entry for mod", LogTag.BundleLoading);
				ModContainers.Add(fullDirectoryName, new ModContainer());
			}
			ModContainers[fullDirectoryName].AddToLoadOrder(iD, loadOrder);
			OtherLogger.Log($"Tracking modded bundle: {iD}, LoadOrder: {loadOrder}", LogTag.BundleLoading);
		}

		internal static bool IsBundleAlreadyTracked(BundleInfo bundleInfo)
		{
			string fullDirectoryName = bundleInfo.FullDirectoryName;
			return (ModContainers.GetValueOrNull(fullDirectoryName)?.TryGetBundleLoadStatus(bundleInfo.ID)).HasValue;
		}

		internal static bool CanOrderedModLoad(BundleInfo bundleInfo)
		{
			string fullDirectoryName = bundleInfo.FullDirectoryName;
			BundleStatus? bundleStatus = (ModContainers.GetValueOrNull(fullDirectoryName) ?? throw new Exception("Mod was not found in load order! BundleID: " + bundleInfo.ID)).TryGetBundleLoadStatus(bundleInfo.ID);
			if (!bundleStatus.HasValue)
			{
				throw new Exception("BundleID was not found in mod load order container: " + bundleInfo.ID);
			}
			if (bundleStatus.GetValueOrDefault() == BundleStatus.Loaded || bundleStatus.GetValueOrDefault() == BundleStatus.Unloaded)
			{
				throw new Exception("BundleID is already loaded/unloaded: " + bundleInfo.ID);
			}
			bool flag = bundleStatus.GetValueOrDefault() == BundleStatus.CanLoad;
			return (PluginConfig.MaxActiveLoaders <= 0 || ActiveLoaders.Count < PluginConfig.MaxActiveLoaders) && flag;
		}

		internal static void PrintWaitingBundles(BundleInfo bundleInfo)
		{
			string fullDirectoryName = bundleInfo.FullDirectoryName;
			List<BundleLoadStatus> list = (from o in ModContainers[fullDirectoryName].GetBundleDependencies(bundleInfo.ID)
				where o.Status != BundleStatus.Loaded && o.Status != BundleStatus.Unloaded
				select o).ToList();
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("Bundle '" + bundleInfo.Name + "' has been waiting a long time to load! " + $"Active loaders: {ActiveLoaders.Count}. " + $"Waiting for {list.Count} bundles.");
			foreach (BundleLoadStatus item in list)
			{
				stringBuilder.AppendLine($"- Waiting for BundleID: {item.BundleId}, Status: {item.Status}");
			}
			OtherLogger.Log(stringBuilder.ToString());
		}

		internal static void UpdateProgress(BundleInfo bundleInfo, float progress)
		{
			string iD = bundleInfo.ID;
			float? structOrNull = LoaderProgressDic.GetStructOrNull(iD);
			if (structOrNull.HasValue)
			{
				_loadersProgressSum += progress - structOrNull.Value;
				LoaderProgressDic[iD] = progress;
			}
		}

		internal static List<string> GetDependenciesBundleIDs(string bundleID)
		{
			string directoryFromID = BundleInfo.GetDirectoryFromID(bundleID);
			return (from o in ModContainers[directoryFromID].GetBundleDependencies(bundleID)
				select o.BundleId).ToList();
		}
	}
	[BepInPlugin("h3vr.otherloader", "OtherLoaderPatched", "2.0.3")]
	[BepInDependency("stratum", "1.1.0")]
	[BepInDependency("nrgill28.Sodalite", "1.4.1")]
	public class OtherLoader : StratumPlugin
	{
		private class DirectLoadMod
		{
			public readonly string Path;

			public readonly string LoadFirst;

			public readonly string LoadAny;

			public readonly string LoadLast;

			public DirectLoadMod(string path, string loadFirst, string loadAny, string loadLast)
			{
				Path = path;
				LoadFirst = loadFirst;
				LoadAny = loadAny;
				LoadLast = loadLast;
				base..ctor();
			}
		}

		private const string OtherLoaderVersion = "2.0.3";

		public static readonly Dictionary<string, ItemSpawnerEntry> SpawnerEntriesByID = new Dictionary<string, ItemSpawnerEntry>();

		internal static readonly Dictionary<string, string> ManagedBundles = new Dictionary<string, string>();

		internal static CoroutineStarter CoroutineStarter = null;

		internal static ExceptionCatcher ExceptionCatcher = null;

		private static readonly List<DirectLoadMod> DirectLoadMods = new List<DirectLoadMod>();

		private void Awake()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Expected O, but got Unknown
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Expected O, but got Unknown
			CoroutineStarter = new CoroutineStarter(((MonoBehaviour)this).StartCoroutine);
			ExceptionCatcher = new ExceptionCatcher(((BaseUnityPlugin)this).Logger);
			OtherLogger.Initialize(((BaseUnityPlugin)this).Logger);
			PluginConfig.Initialize(((BaseUnityPlugin)this).Info);
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(LogLevelColorPatcher), (string)null);
			});
			if (PluginConfig.ItemUnlocker != 0)
			{
				ExceptionCatcher.Run(delegate
				{
					Harmony.CreateAndPatchAll(typeof(RewardUnlocksPatchers), (string)null);
				});
			}
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(AnvilRuntimeLoadingPatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(QuickbeltPanelPatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(ItemPickupPatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(VaultSpawnUnlockathonPatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(RandomGunSpawnUnlockathonPatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(ItemSpawnerV2UnlockathonPatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(PortableSpawnerPatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(ItemSpawnerV2InitialPatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(ItemSpawnerV2SimpleModePatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(ItemSpawnerV2SpawningPatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(ItemSpawnerV2DisplayItemsPatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(ItemSpawnerV2TagsFromHeldPatcher), (string)null);
			});
			ExceptionCatcher.Run(UnlockathonManager.Initialize);
			if (PluginConfig.AddUnloadButton)
			{
				WristMenuAPI.Buttons.Add(new WristMenuButton("Unload Bundles", (ButtonClickEvent)delegate
				{
					UnloadAllModdedBundles();
				}));
			}
		}

		private IEnumerator Start()
		{
			GM.SetRunningModded();
			OldOtherLoaderDisablerPatcher.RestoreOtherLoaderDll();
			((MonoBehaviour)this).StartCoroutine(SpawnablePanelManager.Initialize());
			yield break;
		}

		private void OnApplicationQuit()
		{
			UnlockathonManager.SaveAll();
		}

		public override void OnSetup(IStageContext<Empty> ctx)
		{
			ctx.Loaders.Add("icon", (FileSystemInfo _) => default(Empty));
			ctx.Loaders.Add("assembly", MainLoader.LoadAssembly);
		}

		public override IEnumerator OnRuntime(IStageContext<IEnumerator> ctx)
		{
			ctx.Loaders.Add("item_data", MainLoader.BundlePrepareLate);
			ctx.Loaders.Add("item_first_late", (FileSystemInfo handle) => MainLoader.BundleRegisterLate(handle, LoadOrder.LoadFirst));
			ctx.Loaders.Add("item_unordered_late", (FileSystemInfo handle) => MainLoader.BundleRegisterLate(handle, LoadOrder.LoadUnordered));
			ctx.Loaders.Add("item_last_late", (FileSystemInfo handle) => MainLoader.BundleRegisterLate(handle, LoadOrder.LoadLast));
			ctx.Loaders.Add("item", (FileSystemInfo handle) => MainLoader.BundleLoadImmediate(handle, LoadOrder.LoadFirst));
			ctx.Loaders.Add("item_unordered", (FileSystemInfo handle) => MainLoader.BundleLoadImmediate(handle, LoadOrder.LoadUnordered));
			ctx.Loaders.Add("item_last", (FileSystemInfo handle) => MainLoader.BundleLoadImmediate(handle, LoadOrder.LoadLast));
			MainLoader.LoadLegacyBundles();
			foreach (DirectLoadMod directLoadMod in DirectLoadMods)
			{
				MainLoader.BundleLoadDirectFromDirectory(directLoadMod.Path, directLoadMod.LoadFirst.Split(new char[1] { ',' }), directLoadMod.LoadAny.Split(new char[1] { ',' }), directLoadMod.LoadLast.Split(new char[1] { ',' }));
			}
			DirectLoadMods.Clear();
			LoaderStatus.ProgressUpdated += OnLoaderProgress;
			yield break;
		}

		private static void OnLoaderProgress(float progress)
		{
			if (!(progress < 1f))
			{
				LoaderStatus.ProgressUpdated -= OnLoaderProgress;
				ItemSpawnerIDLinker.LinkQueuedEntries();
				ItemManagerDebugger.TryPrintEntries();
				SpawnerTilesDatabase.TryCreateTestCategories();
			}
		}

		public static void RegisterDirectLoad(string path, string guid, string dependancies, string loadFirst, string loadAny, string loadLast)
		{
			DirectLoadMods.Add(new DirectLoadMod(path, loadFirst, loadAny, loadLast));
		}

		private void UnloadAllModdedBundles()
		{
			foreach (string item in ManagedBundles.Keys.Where((string bundleID) => AnvilManager.m_bundles.m_lookup.ContainsKey(bundleID)))
			{
				OtherLogger.Log("Unloading bundle '" + item + "'");
				AnvilCallback<AssetBundle> val = (AnvilCallback<AssetBundle>)(object)AnvilManager.m_bundles.m_lookup[item];
				AnvilManager.m_bundles.m_loading.Remove((AnvilCallbackBase)(object)val);
				AnvilManager.m_bundles.m_lookup.Remove(item);
				val.Result.Unload(false);
			}
		}
	}
	internal static class PluginAssets
	{
		private const string PluginFolderName = "Sirdoggy-OtherLoaderPatched";

		private static readonly string AssetsRelativePath = Path.Combine("Sirdoggy-OtherLoaderPatched", "assets");

		private static readonly string AssetsFullPath = Path.Combine(Paths.PluginPath, AssetsRelativePath);

		public static readonly Sprite? UnknownFolder = SpriteMaker.CreateSpriteFromImage(Path.Combine(AssetsFullPath, "UnknownFolder.png"));

		public static readonly Sprite? Shapes = SpriteMaker.CreateSpriteFromImage(Path.Combine(AssetsFullPath, "Shapes.png"));

		public static readonly Sprite? Lock = SpriteMaker.CreateSpriteFromImage(Path.Combine(AssetsFullPath, "Lock.png"));

		public static readonly Sprite? SettingsIcon = SpriteMaker.CreateSpriteFromImage(Path.Combine(AssetsFullPath, "SettingsIcon.png"));

		public static readonly Texture2D? SpawnablePanelTexture = SpriteMaker.CreateTexture2DFromImage(Path.Combine(AssetsFullPath, "PanelTexture.png"));

		public const string CustomCategoriesHeaderLabel = "Modded Categories";

		public static AssetBundleCreateRequest? OLPAssets => AssetBundle.LoadFromFileAsync(Path.Combine(AssetsFullPath, "otherloaderpatched_assets"));

		public static string CustomCategoriesButtonLabel(int? count)
		{
			return $"MODDED CATEGORIES ({count.GetValueOrDefault()})";
		}

		public static string ModsLoadingProgressLabel(int percentage)
		{
			return $"Loading mods | {percentage}%";
		}

		public static string UnlockathonUnlockedItems(int count)
		{
			return $"Unlocked items: {count}";
		}
	}
	internal static class PluginConfig
	{
		public static bool OptimizeMemory;

		public static int MaxActiveLoaders;

		public static ItemUnlockerMode ItemUnlocker;

		public static ConfigEntry<bool> PreventSelectingModTagsFromHeldObject;

		public static ConfigEntry<bool> ShowSpawnItemButtonInPortableSpawner;

		public static ConfigEntry<ItemSpawnerSortGrouping> ItemSpawnerSortGrouping;

		public static ConfigEntry<ItemSpawnerSortOrder> ItemSpawnerSortOrder;

		public static ConfigEntry<bool> ColoredLogs;

		public static ConfigEntry<LogTag> LogTags;

		public static bool AddUnloadButton;

		public static bool EnableLogTraces;

		public static bool ShowDebugItemSpawnerEntries;

		public const bool DevMode = false;

		private static ConfigFile _configFile;

		private const string ConfigFileName = "OtherLoaderPatched.cfg";

		public static void Initialize(PluginInfo pluginInfo)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			_configFile = new ConfigFile(Path.Combine(Paths.ConfigPath, "OtherLoaderPatched.cfg"), true);
			BindFields();
			UniversalModPanel.RegisterPluginSettings(pluginInfo, _configFile);
			ShowSpawnItemButtonInPortableSpawner.SettingChanged += RefreshItemSpawnerUI;
			ItemSpawnerSortGrouping.SettingChanged += RefreshItemSpawnerUI;
			ItemSpawnerSortOrder.SettingChanged += RefreshItemSpawnerUI;
		}

		private static void RefreshItemSpawnerUI(object sender, EventArgs eventArgs)
		{
			SceneUtils.RunOnAllInstancesOfType<ItemSpawnerV2>((Action<ItemSpawnerV2>)delegate(ItemSpawnerV2 spawner)
			{
				spawner.RedrawStandardCanvasesSafe();
			}, OtherLoader.ExceptionCatcher);
		}

		private static void BindFields()
		{
			OptimizeMemory = _configFile.Bind<bool>("General", "OptimizeMemory", false, "If true, assets that aren't set-up for on-demand loading will be automatically optimized for it. This reduces RAM usage for older mods, but has been reported to cause instability on Linux/Proton. Requires game restart.").Value;
			MaxActiveLoaders = _configFile.Bind<int>("General", "MaxActiveLoaders", 6, "Sets the number of mods that can be loading at once when first launching the game. Values less than 1 will result in all mods being loaded at the same time.").Value;
			ItemUnlocker = _configFile.Bind<ItemUnlockerMode>("General", "ItemUnlocker", ItemUnlockerMode.Disabled, "Cheat. Unlocks all reward/hidden items, including ones that can only spawn in T&H. Using this won't affect your H3VR save file. Requires game restart.").Value;
			PreventSelectingModTagsFromHeldObject = _configFile.Bind<bool>("General", "PreventSelectingModTagsFromHeldObject", true, "ModTags will be skipped when using the 'Select Tags From Held Object' button.");
			ShowSpawnItemButtonInPortableSpawner = _configFile.Bind<bool>("General", "ShowSpawnItemButtonInPortableSpawner", true, "Makes the spawn item button visible in the portable item spawner, letting you spawn objects without having to use the stylus.");
			ItemSpawnerSortGrouping = _configFile.Bind<ItemSpawnerSortGrouping>("General", "ItemSpawnerSortGrouping", global::OtherLoader.ItemSpawner.VanillaCategories.ItemSpawnerSortGrouping.ShowModdedItemsFirst, "Changes how items are grouped and displayed in the item spawner.");
			ItemSpawnerSortOrder = _configFile.Bind<ItemSpawnerSortOrder>("General", "ItemSpawnerSortOrder", global::OtherLoader.ItemSpawner.VanillaCategories.ItemSpawnerSortOrder.AlphabeticalByDisplayName, "'Vanilla' orders items alphabetically by their internal ItemIDs. 'AlphabeticalByDisplayName' orders items by their actual visible names. This does not affect how categories are ordered, only items.");
			ColoredLogs = _configFile.Bind<bool>("Logging", "ColoredLogs", true, "When true, logs will change colors depending on their LogTag.");
			LogTags = _configFile.Bind<LogTag>("Logging", "LogTags", LogTag.General, "Controls which types of logs should be enabled. Errors and warnings will always be logged, regardless of this setting.");
			AddUnloadButton = _configFile.Bind<bool>("Debug", "AddUnloadButton", false, "When true, you'll have a wrist menu button that can unload all modded asset bundles for testing purposes. Requires game restart.").Value;
			EnableLogTraces = _configFile.Bind<bool>("Debug", "EnableLogTraces", false, "Affects performance, only enable when debugging. When true, method call traces will be included in logs. Requires game restart.").Value;
			ShowDebugItemSpawnerEntries = _configFile.Bind<bool>("Debug", "ShowDebugItemSpawnerEntries", false, "When true, debug spawner entries will be added to the item spawner's custom categories tab. Requires game restart.").Value;
		}
	}
	public class SpawnablePanel : MonoBehaviour
	{
		private enum ConfirmState
		{
			None,
			DeleteProfile,
			ImportData
		}

		public GameObject LYT_UnlockathonOn;

		public GameObject LYT_UnlockathonOff;

		public OptionsPanel_ButtonSet BTNSet_EnableUnlockathon;

		public OptionsPanel_ButtonSet BTNSet_ProfileButtons;

		public List<GameObject> ProfileButtonsList;

		public GameObject BTN_CreateNewProfile;

		public GameObject LYT_UnlockathonProfileDetails;

		public Text TXT_UnlockathonUnlockedItems;

		public OptionsPanel_ButtonSet BTNSet_UnlockFromVault;

		public OptionsPanel_ButtonSet BTNSet_UnlockSecondaryItems;

		public OptionsPanel_ButtonSet BTNSet_KeepModded;

		public OptionsPanel_ButtonSet BTNSet_KeepGuns;

		public OptionsPanel_ButtonSet BTNSet_KeepAmmo;

		public OptionsPanel_ButtonSet BTNSet_KeepGrenadesExplosives;

		public OptionsPanel_ButtonSet BTNSet_KeepAttachments;

		public OptionsPanel_ButtonSet BTNSet_KeepMelee;

		public OptionsPanel_ButtonSet BTNSet_KeepToolsToys;

		public GameObject LYT_UnlockathonProfileSidePanel;

		public Text TXT_DeleteProfile;

		public Text TXT_ImportData;

		private const string TextPadding = "  ";

		private ConfirmState _confirmState;

		public void OnSelectUnlockathonPage()
		{
			Boop();
			RedrawUnlockathonCanvas();
		}

		public void OnClose()
		{
			Boop();
			SpawnablePanelManager.HidePanel();
		}

		public void OnSetUnlockathonEnabled(bool isEnabled)
		{
			Boop();
			UnlockathonManager.SetUnlockathonEnabled(isEnabled);
		}

		public void OnClickProfileButton(int index)
		{
			Boop();
			UnlockathonManager.SetSelectedProfile(index);
		}

		public void OnSetUnlockItemsSpawnedFromVault(bool isEnabled)
		{
			Boop();
			UnlockathonManager.SetUnlockItemsSpawnedFromVault(isEnabled);
		}

		public void OnSetUnlockSecondaryItems(bool isEnabled)
		{
			Boop();
			UnlockathonManager.SetUnlockSecondaryItems(isEnabled);
		}

		public void OnSetKeepModded(bool isEnabled)
		{
			Boop();
			UnlockathonManager.SetKeepModded(isEnabled);
		}

		public void OnSetKeepGuns(bool isEnabled)
		{
			Boop();
			UnlockathonManager.SetKeepGuns(isEnabled);
		}

		public void OnSetKeepAmmo(bool isEnabled)
		{
			Boop();
			UnlockathonManager.SetKeepAmmo(isEnabled);
		}

		public void OnSetKeepGrenadesExplosives(bool isEnabled)
		{
			Boop();
			UnlockathonManager.SetKeepGrenadesExplosives(isEnabled);
		}

		public void OnSetKeepAttachments(bool isEnabled)
		{
			Boop();
			UnlockathonManager.SetKeepAttachments(isEnabled);
		}

		public void OnSetKeepMelee(bool isEnabled)
		{
			Boop();
			UnlockathonManager.SetKeepMelee(isEnabled);
		}

		public void OnSetKeepToolsToys(bool isEnabled)
		{
			Boop();
			UnlockathonManager.SetKeepToolsToys(isEnabled);
		}

		public void OnCreateNewProfile()
		{
			Boop();
			UnlockathonManager.CreateNewProfile();
		}

		public void OnCurrentProfileDelete()
		{
			Boop();
			if (_confirmState == ConfirmState.DeleteProfile)
			{
				UnlockathonManager.DeleteCurrentProfile();
				return;
			}
			_confirmState = ConfirmState.DeleteProfile;
			RedrawConfirmableButtons();
		}

		public void OnCurrentProfileRename()
		{
			Boop();
			UnlockathonManager.RenameCurrentProfile();
		}

		public void OnCurrentProfileImportData()
		{
			Boop();
			if (_confirmState == ConfirmState.ImportData)
			{
				UnlockathonManager.ImportDataFromOldOtherLoaderToCurrentProfile();
				return;
			}
			_confirmState = ConfirmState.ImportData;
			RedrawConfirmableButtons();
		}

		private IEnumerator Start()
		{
			List<GameObject> profileButtonsList = ProfileButtonsList;
			if (profileButtonsList == null || profileButtonsList.Count != 9)
			{
				OtherLogger.LogError("ProfileButtonsList is not configured correctly in MeatKit!");
				yield break;
			}
			UnlockathonManager.OnUnlockathonStateChanged += RedrawUnlockathonCanvas;
			RedrawUnlockathonCanvas();
			yield return null;
			RedrawUnlockathonCanvas();
		}

		private void OnDestroy()
		{
			UnlockathonManager.OnUnlockathonStateChanged -= RedrawUnlockathonCanvas;
		}

		private void Boop()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			SM.PlayGlobalUISound((GlobalUISound)0, ((Component)this).transform.position);
		}

		private void RedrawUnlockathonCanvas()
		{
			if (!UnlockathonManager.UnlockathonEnabled)
			{
				BTNSet_EnableUnlockathon.SetSelectedButton(1);
				LYT_UnlockathonOn.SetActive(false);
				LYT_UnlockathonOff.SetActive(true);
			}
			else
			{
				BTNSet_EnableUnlockathon.SetSelectedButton(0);
				LYT_UnlockathonOn.SetActive(true);
				LYT_UnlockathonOff.SetActive(false);
				RedrawUnlockathonProfiles();
			}
		}

		private void RedrawUnlockathonProfiles()
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			RedrawUnlockathonProfileDetails();
			BTNSet_ProfileButtons.SetSelectedButton(UnlockathonManager.SelectedProfileIndex.GetValueOrDefault(9));
			BTN_CreateNewProfile.SetActive(false);
			for (int i = 0; i < 9; i++)
			{
				GameObject val = ProfileButtonsList[i];
				if (i < UnlockathonManager.Profiles.Count)
				{
					Profile profile = UnlockathonManager.Profiles[i];
					val.GetComponent<Text>().text = "  " + profile.DisplayName;
					val.SetActive(true);
				}
				else if (i == UnlockathonManager.Profiles.Count)
				{
					BTN_CreateNewProfile.transform.position = val.transform.position;
					BTN_CreateNewProfile.SetActive(true);
					val.SetActive(false);
				}
				else
				{
					val.SetActive(false);
				}
			}
		}

		private void RedrawUnlockathonProfileDetails()
		{
			if (UnlockathonManager.ActiveProfile == null)
			{
				LYT_UnlockathonProfileDetails.SetActive(false);
				LYT_UnlockathonProfileSidePanel.SetActive(false);
				return;
			}
			_confirmState = ConfirmState.None;
			RedrawConfirmableButtons();
			LYT_UnlockathonProfileDetails.SetActive(true);
			LYT_UnlockathonProfileSidePanel.SetActive(true);
			int count = UnlockathonManager.ActiveProfile.GetArrayOfUnlockedSpawnerIDs().Length;
			TXT_UnlockathonUnlockedItems.text = PluginAssets.UnlockathonUnlockedItems(count);
			BTNSet_UnlockFromVault.SetSelectedButton((!UnlockathonManager.ActiveProfile.UnlockItemsSpawnedFromVault) ? 1 : 0);
			BTNSet_UnlockSecondaryItems.SetSelectedButton((!UnlockathonManager.ActiveProfile.UnlockSecondaryItems) ? 1 : 0);
			BTNSet_KeepModded.SetSelectedButton((!UnlockathonManager.ActiveProfile.KeepModded) ? 1 : 0);
			BTNSet_KeepGuns.SetSelectedButton((!UnlockathonManager.ActiveProfile.KeepGuns) ? 1 : 0);
			BTNSet_KeepAmmo.SetSelectedButton((!UnlockathonManager.ActiveProfile.KeepAmmo) ? 1 : 0);
			BTNSet_KeepGrenadesExplosives.SetSelectedButton((!UnlockathonManager.ActiveProfile.KeepGrenadesExplosives) ? 1 : 0);
			BTNSet_KeepAttachments.SetSelectedButton((!UnlockathonManager.ActiveProfile.KeepAttachments) ? 1 : 0);
			BTNSet_KeepMelee.SetSelectedButton((!UnlockathonManager.ActiveProfile.KeepMelee) ? 1 : 0);
			BTNSet_KeepToolsToys.SetSelectedButton((!UnlockathonManager.ActiveProfile.KeepToolsToys) ? 1 : 0);
		}

		private void RedrawConfirmableButtons()
		{
			switch (_confirmState)
			{
			case ConfirmState.None:
				TXT_DeleteProfile.text = "Delete Profile";
				TXT_ImportData.text = "Import data from\nold OtherLoader";
				break;
			case ConfirmState.DeleteProfile:
				TXT_DeleteProfile.text = "[Click to delete]";
				TXT_ImportData.text = "Import data from\nold OtherLoader";
				break;
			case ConfirmState.ImportData:
				TXT_DeleteProfile.text = "Delete Profile";
				TXT_ImportData.text = "[Click to import]";
				break;
			}
		}
	}
	internal static class SpawnablePanelManager
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ButtonClickEvent <>9__2_0;

			internal void <Initialize>b__2_0(object _, ButtonClickEventArgs args)
			{
				SpawnPanel(args.Hand.OtherHand, null, null);
			}
		}

		private static GameObject? _customCanvasGameO;

		private static LockablePanel? _lockablePanel;

		public static IEnumerator Initialize()
		{
			AssetBundleCreateRequest bundleRequest = PluginAssets.OLPAssets;
			yield return bundleRequest;
			if ((Object)(object)((bundleRequest != null) ? bundleRequest.assetBundle : null) == (Object)null)
			{
				OtherLogger.LogError("OLPAssets AssetBundle is null");
				yield break;
			}
			AssetBundleRequest dataRequest = bundleRequest.assetBundle.LoadAssetAsync<GameObject>("PanelCanvasPrefab");
			yield return dataRequest;
			Object obj = ((dataRequest != null) ? dataRequest.asset : null);
			GameObject val = (GameObject)(object)((obj is GameObject) ? obj : null);
			if (val == null)
			{
				OtherLogger.LogError("Could not find panel GameObject in OLPAssets");
				yield break;
			}
			_customCanvasGameO = val;
			_lockablePanel = new LockablePanel();
			_lockablePanel.Configure += ConfigurePanel;
			_lockablePanel.TextureOverride = PluginAssets.SpawnablePanelTexture;
			ICollection<WristMenuButton> buttons = WristMenuAPI.Buttons;
			object obj2 = <>c.<>9__2_0;
			if (obj2 == null)
			{
				ButtonClickEvent val2 = delegate(object _, ButtonClickEventArgs args)
				{
					SpawnPanel(args.Hand.OtherHand, null, null);
				};
				<>c.<>9__2_0 = val2;
				obj2 = (object)val2;
			}
			buttons.Add(new WristMenuButton("OtherLoader Panel", (ButtonClickEvent)obj2));
		}

		public static void SpawnPanel(FVRViveHand? hand, Vector3? position, Vector3? rotation)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			if (_lockablePanel == null)
			{
				OtherLogger.LogError("LockablePanel is null");
				return;
			}
			GameObject orCreatePanel = _lockablePanel.GetOrCreatePanel();
			orCreatePanel.SetActive(true);
			FVRPhysicalObject component = orCreatePanel.GetComponent<FVRPhysicalObject>();
			if ((Object)(object)component == (Object)null)
			{
				OtherLogger.LogError("FVRPhysicalObject is null");
				return;
			}
			if ((Object)(object)hand != (Object)null)
			{
				hand.RetrieveObject(component);
				return;
			}
			if (position.HasValue)
			{
				((Component)component).transform.position = position.Value;
			}
			if (rotation.HasValue)
			{
				Quaternion val = default(Quaternion);
				((Quaternion)(ref val)).eulerAngles = rotation.Value;
				Quaternion rotation2 = val;
				((Component)component).transform.rotation = rotation2;
			}
		}

		public static void HidePanel()
		{
			LockablePanel? lockablePanel = _lockablePanel;
			if (lockablePanel != null)
			{
				lockablePanel.GetOrCreatePanel().SetActive(false);
			}
		}

		private static void ConfigurePanel(GameObject panel)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			Transform val = panel.transform.Find("OptionsCanvas_0_Main/Canvas");
			Object.Instantiate<GameObject>(_customCanvasGameO, val.position, val.rotation, val.parent);
			Object.Destroy((Object)(object)((Component)val).gameObject);
		}
	}
}
namespace OtherLoader.Unlockathon
{
	internal class Profile
	{
		public bool UnlockItemsSpawnedFromVault;

		public bool UnlockSecondaryItems = true;

		public bool KeepModded;

		public bool KeepGuns;

		public bool KeepAmmo;

		public bool KeepGrenadesExplosives;

		public bool KeepAttachments;

		public bool KeepMelee;

		public bool KeepToolsToys = true;

		public string? FileName { get; set; }

		public string DisplayName { get; set; }

		public HashSet<string> UnlockedItemSpawnerIDs { get; set; } = new HashSet<string>();


		public HashSet<string> UnlockedItemSpawnerIDsSecondaries { get; set; } = new HashSet<string>();


		public HashSet<string> UnlockedObjectIDs { get; set; } = new HashSet<string>();


		public HashSet<string> UnlockedObjectIDsSecondaries { get; set; } = new HashSet<string>();


		public Profile(string displayName)
		{
			DisplayName = displayName;
		}

		public string[] GetArrayOfUnlockedSpawnerIDs()
		{
			if (!UnlockSecondaryItems)
			{
				return UnlockedItemSpawnerIDs.ToArray();
			}
			return UnlockedItemSpawnerIDs.Concat(UnlockedItemSpawnerIDsSecondaries).ToArray();
		}

		public bool IsSpawnerIDUnlocked(string id)
		{
			FVRObject val = IM.GetSpawnerID(id)?.MainObject;
			if ((Object)(object)val != (Object)null)
			{
				if (val.IsModContent && KeepModded)
				{
					return true;
				}
				if (val.IsFirearm() && KeepGuns)
				{
					return true;
				}
				if (val.IsAmmo() && KeepAmmo)
				{
					return true;
				}
				if (val.IsAttachment() && KeepAttachments)
				{
					return true;
				}
				if (val.IsExplosive() && KeepGrenadesExplosives)
				{
					return true;
				}
				if (val.IsMelee() && KeepMelee)
				{
					return true;
				}
				if (val.IsMisc() && KeepToolsToys)
				{
					return true;
				}
			}
			if (!UnlockSecondaryItems)
			{
				return UnlockedItemSpawnerIDs.Contains(id);
			}
			if (!UnlockedItemSpawnerIDs.Contains(id))
			{
				return UnlockedItemSpawnerIDsSecondaries.Contains(id);
			}
			return true;
		}

		public bool ShouldSkipUnlockingID(string id)
		{
			if (!UnlockedItemSpawnerIDs.Contains(id))
			{
				return UnlockedObjectIDs.Contains(id);
			}
			return true;
		}
	}
	internal static class UnlockathonInventoryManager
	{
		private struct UnlockRequest
		{
			public readonly string ID;

			public readonly bool IsSecondary;

			public UnlockRequest(string id, bool isSecondary)
			{
				ID = id;
				IsSecondary = isSecondary;
			}
		}

		public static ItemSpawnerID? GetUnlockableItemSpawnerID(string? id)
		{
			return GetUnlockableItemSpawnerIDPrivate(id, firstPass: true);
		}

		private static ItemSpawnerID? GetUnlockableItemSpawnerIDPrivate(string? id, bool firstPass)
		{
			if (id == null || !IM.HasSpawnedID(id))
			{
				return null;
			}
			ItemSpawnerID spawnerID = IM.GetSpawnerID(id);
			if ((Object)(object)spawnerID == (Object)null)
			{
				return null;
			}
			if (!UnlockathonManager.UnlockathonEnabled)
			{
				return spawnerID;
			}
			ItemSpawnerID val = Object.Instantiate<ItemSpawnerID>(spawnerID);
			if (!IsItemSpawnerIDUnlocked(id))
			{
				val.Sprite = PluginAssets.Lock;
			}
			if (firstPass)
			{
				ItemSpawnerID[] secondaries = spawnerID.Secondaries;
				if (secondaries != null && secondaries.Length > 0)
				{
					List<ItemSpawnerID> list = new List<ItemSpawnerID>();
					secondaries = spawnerID.Secondaries;
					for (int i = 0; i < secondaries.Length; i++)
					{
						ItemSpawnerID unlockableItemSpawnerIDPrivate = GetUnlockableItemSpawnerIDPrivate(secondaries[i]?.ItemID, firstPass: false);
						if ((Object)(object)unlockableItemSpawnerIDPrivate != (Object)null)
						{
							list.Add(unlockableItemSpawnerIDPrivate);
						}
					}
					val.Secondaries = list.ToArray();
				}
			}
			return val;
		}

		public static bool IsItemSpawnerIDUnlocked(string id)
		{
			return UnlockathonManager.ActiveProfile?.IsSpawnerIDUnlocked(id) ?? true;
		}

		public static void UnlockItem(FVRPhysicalObject? physicalObject)
		{
			if ((Object)(object)physicalObject == (Object)null)
			{
				return;
			}
			Profile activeProfile = UnlockathonManager.ActiveProfile;
			if (activeProfile != null)
			{
				if ((Object)(object)physicalObject.IDSpawnedFrom != (Object)null)
				{
					OtherLogger.Log("Skipping unlock for object '" + ((Object)physicalObject).name + "' spawned from item spawner.", LogTag.Unlockathon);
					return;
				}
				if ((Object)(object)((Component)physicalObject).GetComponent<SpawnLockDuplicateTag>() != (Object)null)
				{
					OtherLogger.Log("Skipping unlock for object '" + ((Object)physicalObject).name + "' because it's been duplicated by spawn lock.", LogTag.Unlockathon);
					return;
				}
				if ((Object)(object)((Component)physicalObject).GetComponent<SpawnedByRandomGunButtonTag>() != (Object)null)
				{
					OtherLogger.Log("Skipping unlock for object '" + ((Object)physicalObject).name + "' spawned by random gun spawner.", LogTag.Unlockathon);
					return;
				}
				if (!activeProfile.UnlockItemsSpawnedFromVault && (Object)(object)((Component)physicalObject).GetComponent<SpawnedFromVaultTag>() != (Object)null)
				{
					OtherLogger.Log("Skipping unlock for object '" + ((Object)physicalObject).name + "' spawned from vault.", LogTag.Unlockathon);
					return;
				}
				List<string> ids = new List<string>
				{
					physicalObject.ObjectWrapper?.ItemID,
					physicalObject.IDSpawnedFrom?.ItemID
				};
				OtherLoader.CoroutineStarter.Invoke(UnlockItemsByID(ids));
			}
		}

		public static IEnumerator UnlockItemsByID(IEnumerable<string?> ids)
		{
			Profile profile = UnlockathonManager.ActiveProfile;
			if (profile == null)
			{
				yield break;
			}
			HashSet<string> processedIDs = new HashSet<string>();
			Queue<UnlockRequest> pendingRequests = new Queue<UnlockRequest>();
			foreach (string id in ids)
			{
				if (!id.IsNullOrEmpty() && !profile.ShouldSkipUnlockingID(id))
				{
					pendingRequests.Enqueue(new UnlockRequest(id, isSecondary: false));
				}
			}
			if (pendingRequests.Count == 0)
			{
				yield break;
			}
			int processedCount = 0;
			while (pendingRequests.Count > 0)
			{
				UnlockRequest unlockRequest = pendingRequests.Dequeue();
				string iD = unlockRequest.ID;
				bool isSecondary = unlockRequest.IsSecondary;
				if (iD.IsNullOrEmpty() || !processedIDs.Add(iD))
				{
					continue;
				}
				OtherLogger.Log($"Attempting to unlock item by ID: {iD}, isSecondary: {isSecondary}", LogTag.Unlockathon);
				FVRObject valueOrNull = IM.OD.GetValueOrNull(iD);
				if ((Object)(object)valueOrNull != (Object)null)
				{
					if (isSecondary)
					{
						if (!profile.UnlockedObjectIDs.Contains(iD))
						{
							profile.UnlockedObjectIDsSecondaries.Add(iD);
						}
					}
					else
					{
						profile.UnlockedObjectIDs.Add(iD);
						profile.UnlockedObjectIDsSecondaries.Remove(iD);
					}
					if (!valueOrNull.SpawnedFromId.IsNullOrEmpty())
					{
						pendingRequests.Enqueue(new UnlockRequest(valueOrNull.SpawnedFromId, isSecondary));
					}
				}
				if (IM.HasSpawnedID(iD))
				{
					if (isSecondary)
					{
						if (!profile.UnlockedItemSpawnerIDs.Contains(iD))
						{
							profile.UnlockedItemSpawnerIDsSecondaries.Add(iD);
						}
					}
					else
					{
						profile.UnlockedItemSpawnerIDs.Add(iD);
						profile.UnlockedItemSpawnerIDsSecondaries.Remove(iD);
					}
					ItemSpawnerID spawnerID = IM.GetSpawnerID(iD);
					if ((Object)(object)spawnerID != (Object)null)
					{
						if ((Object)(object)spawnerID.MainObject != (Object)null && !spawnerID.MainObject.ItemID.IsNullOrEmpty())
						{
							pendingRequests.Enqueue(new UnlockRequest(spawnerID.MainObject.ItemID, isSecondary));
						}
						if ((Object)(object)spawnerID.SecondObject != (Object)null && !spawnerID.SecondObject.ItemID.IsNullOrEmpty())
						{
							pendingRequests.Enqueue(new UnlockRequest(spawnerID.SecondObject.ItemID, isSecondary));
						}
						if (spawnerID.Secondaries != null)
						{
							ItemSpawnerID[] secondaries = spawnerID.Secondaries;
							foreach (ItemSpawnerID val in secondaries)
							{
								if ((Object)(object)val != (Object)null && !val.ItemID.IsNullOrEmpty())
								{
									pendingRequests.Enqueue(new UnlockRequest(val.ItemID, isSecondary: true));
								}
							}
						}
						if (spawnerID.Secondaries_ByStringID != null)
						{
							foreach (string item in spawnerID.Secondaries_ByStringID)
							{
								if (!item.IsNullOrEmpty())
								{
									pendingRequests.Enqueue(new UnlockRequest(item, isSecondary: true));
								}
							}
						}
					}
				}
				ItemSpawnerEntry valueOrNull2 = OtherLoader.SpawnerEntriesByID.GetValueOrNull(iD);
				if ((Object)(object)valueOrNull2 != (Object)null && valueOrNull2.SpawnWithIDs != null)
				{
					foreach (string spawnWithID in valueOrNull2.SpawnWithIDs)
					{
						if (!spawnWithID.IsNullOrEmpty())
						{
							pendingRequests.Enqueue(new UnlockRequest(spawnWithID, isSecondary));
						}
					}
				}
				processedCount++;
				if (processedCount % 50 == 0)
				{
					yield return null;
				}
			}
			UnlockathonManager.SaveActiveProfile();
		}
	}
	internal static class UnlockathonManager
	{
		public const int MaxSupportedProfilesCount = 9;

		private static readonly string SavedProfilesDirectoryPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "My Games/H3VR/OtherLoaderPatched");

		private static readonly string SavedPreferencesFilePath = Path.Combine(Paths.ConfigPath, "Sirdoggy.OLPSavedPreferences");

		private const string ProfilePrefix = "profile_";

		private const string JsonPostfix = ".json";

		private const int MaxCharactersInProfileName = 20;

		public static List<Profile> Profiles { get; } = new List<Profile>();


		public static bool UnlockathonEnabled { get; private set; }

		public static int? SelectedProfileIndex { get; private set; }

		private static bool IsKeyboardDisplayed { get; set; }

		public static Profile? ActiveProfile
		{
			get
			{
				if (!UnlockathonEnabled)
				{
					return null;
				}
				if (SelectedProfileIndex.HasValue)
				{
					return Profiles[SelectedProfileIndex.Value];
				}
				return null;
			}
		}

		public static event Action? OnUnlockathonStateChanged;

		public static void Initialize()
		{
			OtherLogger.Log("Loading Unlockathon data...");
			LoadProfiles();
			LoadPreferences();
			StartListeningToKeyboardEvents();
			NotifyStateChanged();
			OtherLogger.Log("Loading Unlockathon data complete!");
		}

		public static void SetUnlockathonEnabled(bool enabled)
		{
			UnlockathonEnabled = enabled;
			SavePreferences();
			NotifyStateChanged();
		}

		public static void SetSelectedProfile(int index)
		{
			SelectedProfileIndex = Mathf.Clamp(index, 0, Profiles.Count - 1);
			SavePreferences();
			NotifyStateChanged();
		}

		public static void SetUnlockItemsSpawnedFromVault(bool enabled)
		{
			if (ActiveProfile != null)
			{
				ActiveProfile.UnlockItemsSpawnedFromVault = enabled;
				SaveProfile(ActiveProfile);
				NotifyStateChanged();
			}
		}

		public static void SetUnlockSecondaryItems(bool enabled)
		{
			if (ActiveProfile != null)
			{
				ActiveProfile.UnlockSecondaryItems = enabled;
				SaveProfile(ActiveProfile);
				NotifyStateChanged();
			}
		}

		public static void SetKeepModded(bool enabled)
		{
			if (ActiveProfile != null)
			{
				ActiveProfile.KeepModded = enabled;
				SaveProfile(ActiveProfile);
				NotifyStateChanged();
			}
		}

		public static void SetKeepGuns(bool enabled)
		{
			if (ActiveProfile != null)
			{
				ActiveProfile.KeepGuns = enabled;
				SaveProfile(ActiveProfile);
				NotifyStateChanged();
			}
		}

		public static void SetKeepAmmo(bool enabled)
		{
			if (ActiveProfile != null)
			{
				ActiveProfile.KeepAmmo = enabled;
				SaveProfile(ActiveProfile);
				NotifyStateChanged();
			}
		}

		public static void SetKeepGrenadesExplosives(bool enabled)
		{
			if (ActiveProfile != null)
			{
				ActiveProfile.KeepGrenadesExplosives = enabled;
				SaveProfile(ActiveProfile);
				NotifyStateChanged();
			}
		}

		public static void SetKeepAttachments(bool enabled)
		{
			if (ActiveProfile != null)
			{
				ActiveProfile.KeepAttachments = enabled;
				SaveProfile(ActiveProfile);
				NotifyStateChanged();
			}
		}

		public static void SetKeepMelee(bool enabled)
		{
			if (ActiveProfile != null)
			{
				ActiveProfile.KeepMelee = enabled;
				SaveProfile(ActiveProfile);
				NotifyStateChanged();
			}
		}

		public static void SetKeepToolsToys(bool enabled)
		{
			if (ActiveProfile != null)
			{
				ActiveProfile.KeepToolsToys = enabled;
				SaveProfile(ActiveProfile);
				NotifyStateChanged();
			}
		}

		public static void CreateNewProfile()
		{
			if (Profiles.Count >= 9)
			{
				OtherLogger.LogWarning("Can't create a new profile, max limit reached.");
				return;
			}
			Profile profile = new Profile($"Profile {Profiles.Count + 1}");
			Profiles.Add(profile);
			SelectedProfileIndex = Profiles.Count - 1;
			SaveProfile(profile);
			SortProfiles();
			SavePreferences();
			NotifyStateChanged();
		}

		public static void RenameCurrentProfile()
		{
			SteamVR instance = SteamVR.instance;
			CVROverlay val = ((instance != null) ? instance.overlay : null);
			if (val == null)
			{
				OtherLogger.LogError("SteamVR overlay is null");
			}
			else
			{
				OtherLoader.CoroutineStarter.Invoke(ShowRenameProfileOverlayCoroutine(val));
			}
		}

		public static void DeleteCurrentProfile()
		{
			if (!SelectedProfileIndex.HasValue || ActiveProfile == null)
			{
				return;
			}
			if (ActiveProfile.FileName != null)
			{
				string filePath = Path.Combine(SavedProfilesDirectoryPath, ActiveProfile.FileName);
				if (File.Exists(filePath))
				{
					OtherLoader.ExceptionCatcher.Run(delegate
					{
						File.Delete(filePath);
					});
				}
			}
			Profiles.RemoveAt(SelectedProfileIndex.Value);
			SelectedProfileIndex = null;
			SavePreferences();
			NotifyStateChanged();
		}

		public static void ImportDataFromOldOtherLoaderToCurrentProfile()
		{
			string text = Path.Combine(Application.dataPath.Replace("h3vr_Data", "OtherLoader"), "UnlockedItems.json");
			if (!File.Exists(text))
			{
				OtherLogger.LogWarning("Could not find old OtherLoader save data: " + text);
				return;
			}
			try
			{
				OldOtherLoaderDataDto oldOtherLoaderDataDto = JsonConvert.DeserializeObject<OldOtherLoaderDataDto>(File.ReadAllText(text));
				if (oldOtherLoaderDataDto?.UnlockedItemIDs == null || oldOtherLoaderDataDto.UnlockedItemIDs.Length == 0)
				{
					OtherLogger.LogWarning("Old OtherLoader save data is empty.");
				}
				else
				{
					OtherLoader.CoroutineStarter.Invoke(ImportDataRoutine(oldOtherLoaderDataDto.UnlockedItemIDs));
				}
			}
			catch (Exception ex)
			{
				OtherLogger.LogError("Failed to import old OtherLoader data: " + ex.Message);
			}
		}

		private static IEnumerator ImportDataRoutine(string[] ids)
		{
			yield return UnlockathonInventoryManager.UnlockItemsByID(ids);
			OtherLogger.Log($"Successfully imported {ids.Length} items from old OtherLoader.");
		}

		public static void SaveAll()
		{
			foreach (Profile profile in Profiles)
			{
				SaveProfile(profile);
			}
			SavePreferences();
		}

		public static void SaveActiveProfile()
		{
			if (ActiveProfile != null)
			{
				SaveProfile(ActiveProfile);
				NotifyStateChanged();
			}
		}

		private static void NotifyStateChanged()
		{
			SceneUtils.RunOnAllInstancesOfType<ItemSpawnerV2>((Action<ItemSpawnerV2>)delegate(ItemSpawnerV2 spawner)
			{
				spawner.RedrawStandardCanvasesSafe();
			}, OtherLoader.ExceptionCatcher);
			UnlockathonManager.OnUnlockathonStateChanged?.Invoke();
		}

		private static IEnumerator ShowRenameProfileOverlayCoroutine(CVROverlay overlay)
		{
			if (ActiveProfile != null)
			{
				IsKeyboardDisplayed = true;
				yield return (object)new WaitForSecondsRealtime(0.3f);
				overlay.ShowKeyboard(0, 0, "Rename Profile", 20u, ActiveProfile.DisplayName, false, 0uL);
			}
		}

		private static void StartListeningToKeyboardEvents()
		{
			Event<VREvent_t> val = SteamVR_Events.System((EVREventType)1202);
			Event<VREvent_t> val2 = SteamVR_Events.System((EVREventType)1200);
			if (val == null || val2 == null)
			{
				OtherLogger.LogError("VREvent_KeyboardDone/Closed is null");
				return;
			}
			val2.Listen((UnityAction<VREvent_t>)HandleKeyboardClosed);
			val.Listen((UnityAction<VREvent_t>)HandleKeyboardDone);
		}

		private static void HandleKeyboardClosed(VREvent_t _)
		{
			IsKeyboardDisplayed = false;
		}

		private static void HandleKeyboardDone(VREvent_t _)
		{
			if (!IsKeyboardDisplayed)
			{
				return;
			}
			IsKeyboardDisplayed = false;
			if (ActiveProfile == null)
			{
				return;
			}
			StringBuilder stringBuilder = new StringBuilder(160);
			SteamVR instance = SteamVR.instance;
			if (instance != null)
			{
				CVROverlay overlay = instance.overlay;
				if (overlay != null)
				{
					overlay.GetKeyboardText(stringBuilder, 160u);
				}
			}
			string text = stringBuilder.ToString();
			if (string.IsNullOrEmpty(text))
			{
				OtherLogger.Log("Can not rename Unlockathon profile to empty string, aborting...");
				return;
			}
			string displayName = ActiveProfile.DisplayName;
			ActiveProfile.DisplayName = text.Take(20).JoinToString("");
			OtherLogger.Log("Renamed Unlockathon profile from '" + displayName + "' to '" + text + "'");
			if (ActiveProfile.FileName != null)
			{
				string filePath = Path.Combine(SavedProfilesDirectoryPath, ActiveProfile.FileName);
				if (File.Exists(filePath))
				{
					OtherLoader.ExceptionCatcher.Run(delegate
					{
						File.Delete(filePath);
						ActiveProfile.FileName = null;
					});
				}
				else
				{
					ActiveProfile.FileName = null;
				}
			}
			SaveProfile(ActiveProfile);
			SortProfiles();
			SavePreferences();
			NotifyStateChanged();
		}

		private static void SortProfiles()
		{
			Profile activeProfile = ActiveProfile;
			Profiles.Sort((Profile a, Profile b) => string.Compare(a.FileName, b.FileName, StringComparison.Ordinal));
			if (activeProfile != null)
			{
				SelectedProfileIndex = Profiles.IndexOf(activeProfile);
			}
		}

		private static void SaveProfile(Profile profile)
		{
			string text;
			string path;
			if (profile.FileName != null)
			{
				text = profile.FileName;
				path = Path.Combine(SavedProfilesDirectoryPath, text);
			}
			else
			{
				text = "profile_" + ReplaceDisallowedFileNameChars(profile.DisplayName) + ".json";
				path = Path.Combine(SavedProfilesDirectoryPath, text);
				int num = 1;
				while (File.Exists(path))
				{
					text = "profile_" + ReplaceDisallowedFileNameChars(profile.DisplayName) + $"({num})" + ".json";
					path = Path.Combine(SavedProfilesDirectoryPath, text);
					num++;
				}
				profile.FileName = text;
			}
			try
			{
				string contents = JsonConvert.SerializeObject((object)new ProfileDto
				{
					DisplayName = profile.DisplayName,
					UnlockedItemSpawnerIDs = profile.UnlockedItemSpawnerIDs.ToArray(),
					UnlockedItemSpawnerIDsSecondaries = profile.UnlockedItemSpawnerIDsSecondaries.ToArray(),
					UnlockedObjectIDs = profile.UnlockedObjectIDs.ToArray(),
					UnlockedObjectIDsSecondaries = profile.UnlockedObjectIDsSecondaries.ToArray(),
					UnlockItemsSpawnedFromVault = profile.UnlockItemsSpawnedFromVault,
					UnlockSecondaryItems = profile.UnlockSecondaryItems,
					KeepModded = profile.KeepModded,
					KeepGuns = profile.KeepGuns,
					KeepAmmo = profile.KeepAmmo,
					KeepGrenadesExplosives = profile.KeepGrenadesExplosives,
					KeepAttachments = profile.KeepAttachments,
					KeepMelee = profile.KeepMelee,
					KeepToolsToys = profile.KeepToolsToys
				}, (Formatting)1);
				File.WriteAllText(path, contents);
			}
			catch (Exception ex)
			{
				OtherLogger.LogError("Failed to save profile in file '" + text + "': " + ex.Message);
			}
		}

		private static string ReplaceDisallowedFileNameChars(string fileName)
		{
			char[] disallowedChars = Path.GetInvalidFileNameChars();
			return new string(fileName.Select((char character) => (!disallowedChars.Contains(character)) ? character : '_').ToArray());
		}

		private static void SavePreferences()
		{
			try
			{
				string contents = JsonConvert.SerializeObject((object)new PreferencesDto
				{
					UnlockathonEnabled = UnlockathonEnabled,
					UnlockathonSelectedProfileFileName = ((!SelectedProfileIndex.HasValue) ? null : Profiles[SelectedProfileIndex.Value]?.FileName)
				}, (Formatting)1);
				File.WriteAllText(SavedPreferencesFilePath, contents);
			}
			catch (Exception ex)
			{
				OtherLogger.LogError("Failed to save preferences: " + ex.Message);
			}
		}

		private static void LoadProfiles()
		{
			if (Profiles.Count > 0)
			{
				OtherLogger.Log("Profiles have already been loaded.");
				return;
			}
			if (!Directory.Exists(SavedProfilesDirectoryPath))
			{
				OtherLogger.Log("Creating new directory for Unlockathon profiles.");
				Directory.CreateDirectory(SavedProfilesDirectoryPath);
				return;
			}
			List<string> list = (from name in Directory.GetFiles(SavedProfilesDirectoryPath, "profile_*.json", SearchOption.TopDirectoryOnly)
				orderby name
				select name).Take(9).ToList();
			if (list.Count == 0)
			{
				OtherLogger.Log("No saved profiles, creating a default profile.");
				Profile profile = new Profile("Profile 1");
				Profiles.Add(profile);
				SelectedProfileIndex = 0;
				SaveProfile(profile);
				SavePreferences();
				return;
			}
			foreach (string item2 in list)
			{
				try
				{
					ProfileDto profileDto = JsonConvert.DeserializeObject<ProfileDto>(File.ReadAllText(item2));
					if (profileDto == null)
					{
						OtherLogger.LogWarning("Profile data in file `" + item2 + "` is null, deleting it...");
						File.Delete(item2);
						continue;
					}
					Profile profile2 = new Profile(profileDto.DisplayName ?? "Restored Profile")
					{
						FileName = Path.GetFileName(item2)
					};
					if (profileDto.UnlockedItemSpawnerIDs != null)
					{
						Profile profile3 = profile2;
						HashSet<string> hashSet = new HashSet<string>();
						string[] unlockedItemSpawnerIDs = profileDto.UnlockedItemSpawnerIDs;
						foreach (string item in unlockedItemSpawnerIDs)
						{
							hashSet.Add(item);
						}
						profile3.UnlockedItemSpawnerIDs = hashSet;
					}
					if (profileDto.UnlockedItemSpawnerIDsSecondaries != null)
					{
						Profile profile3 = profile2;
						HashSet<string> hashSet = new HashSet<string>();
						string[] unlockedItemSpawnerIDs = profileDto.UnlockedItemSpawnerIDsSecondaries;
						foreach (string item in unlockedItemSpawnerIDs)
						{
							hashSet.Add(item);
						}
						profile3.UnlockedItemSpawnerIDsSecondaries = hashSet;
					}
					if (profileDto.UnlockedObjectIDs != null)
					{
						Profile profile3 = profile2;
						HashSet<string> hashSet = new HashSet<string>();
						string[] unlockedItemSpawnerIDs = profileDto.UnlockedObjectIDs;
						foreach (string item in unlockedItemSpawnerIDs)
						{
							hashSet.Add(item);
						}
						profile3.UnlockedObjectIDs = hashSet;
					}
					if (profileDto.UnlockedObjectIDsSecondaries != null)
					{
						Profile profile3 = profile2;
						HashSet<string> hashSet = new HashSet<string>();
						string[] unlockedItemSpawnerIDs = profileDto.UnlockedObjectIDsSecondaries;
						foreach (string item in unlockedItemSpawnerIDs)
						{
							hashSet.Add(item);
						}
						profile3.UnlockedObjectIDsSecondaries = hashSet;
					}
					if (profileDto.UnlockItemsSpawnedFromVault.HasValue)
					{
						profile2.UnlockItemsSpawnedFromVault = profileDto.UnlockItemsSpawnedFromVault.Value;
					}
					if (profileDto.UnlockSecondaryItems.HasValue)
					{
						profile2.UnlockSecondaryItems = profileDto.UnlockSecondaryItems.Value;
					}
					if (profileDto.KeepModded.HasValue)
					{
						profile2.KeepModded = profileDto.KeepModded.Value;
					}
					if (profileDto.KeepGuns.HasValue)
					{
						profile2.KeepGuns = profileDto.KeepGuns.Value;
					}
					if (profileDto.KeepAmmo.HasValue)
					{
						profile2.KeepAmmo = profileDto.KeepAmmo.Value;
					}
					if (profileDto.KeepGrenadesExplosives.HasValue)
					{
						profile2.KeepGrenadesExplosives = profileDto.KeepGrenadesExplosives.Value;
					}
					if (profileDto.KeepAttachments.HasValue)
					{
						profile2.KeepAttachments = profileDto.KeepAttachments.Value;
					}
					if (profileDto.KeepMelee.HasValue)
					{
						profile2.KeepMelee = profileDto.KeepMelee.Value;
					}
					if (profileDto.KeepToolsToys.HasValue)
					{
						profile2.KeepToolsToys = profileDto.KeepToolsToys.Value;
					}
					Profiles.Add(profile2);
				}
				catch (Exception ex)
				{
					OtherLogger.LogError("Failed to load profile data from file '" + item2 + "': " + ex.Message);
				}
			}
			if (Profiles.Count != list.Count)
			{
				OtherLogger.LogWarning($"Loaded {Profiles.Count}/{list.Count} saved profiles.");
			}
			else
			{
				OtherLogger.Log($"Successfully loaded {Profiles.Count} saved profiles.");
			}
		}

		private static void LoadPreferences()
		{
			if (!File.Exists(SavedPreferencesFilePath))
			{
				OtherLogger.Log("No saved preferences file.");
				return;
			}
			try
			{
				string text = File.ReadAllText(SavedPreferencesFilePath);
				PreferencesDto preferencesDto = JsonConvert.DeserializeObject<PreferencesDto>(text);
				if (preferencesDto == null)
				{
					OtherLogger.LogWarning("Preferences data is null.");
					return;
				}
				if (preferencesDto.UnlockathonEnabled.HasValue)
				{
					UnlockathonEnabled = preferencesDto.UnlockathonEnabled.Value;
				}
				if (preferencesDto.UnlockathonSelectedProfileFileName != null)
				{
					int num = Profiles.FindIndex((Profile profile) => profile.FileName == preferencesDto.UnlockathonSelectedProfileFileName);
					if (num != -1)
					{
						SelectedProfileIndex = num;
					}
				}
				else
				{
					int? unlockathonSelectedProfileIndex = preferencesDto.UnlockathonSelectedProfileIndex;
					if (unlockathonSelectedProfileIndex.HasValue)
					{
						SelectedProfileIndex = Mathf.Clamp(unlockathonSelectedProfileIndex.Value, 0, Profiles.Count - 1);
					}
				}
			}
			catch (Exception ex)
			{
				OtherLogger.LogError("Failed to load preferences: " + ex.Message);
				return;
			}
			OtherLogger.Log("Successfully loaded saved preferences.");
		}
	}
}
namespace OtherLoader.Unlockathon.Tags
{
	internal class SpawnedByRandomGunButtonTag : MonoBehaviour
	{
	}
	internal class SpawnedFromVaultTag : MonoBehaviour
	{
	}
	internal class SpawnLockDuplicateTag : MonoBehaviour
	{
	}
}
namespace OtherLoader.Unlockathon.Patches
{
	[HarmonyWrapSafe]
	[HarmonyPatch(typeof(FVRPhysicalObject))]
	internal class ItemPickupPatcher
	{
		private static string? _nextItemDuplicateID;

		[HarmonyPrefix]
		[HarmonyPatch("BeginInteraction")]
		private static void BeginInteraction_Prefix(FVRPhysicalObject __instance)
		{
			if (_nextItemDuplicateID != null && _nextItemDuplicateID == __instance?.ObjectWrapper?.ItemID)
			{
				OtherLogger.Log("Adding SpawnLockDuplicateTag to object: " + ((Object)__instance).name, LogTag.Unlockathon);
				if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<SpawnLockDuplicateTag>()))
				{
					((Object)((Component)__instance).gameObject.AddComponent<SpawnLockDuplicateTag>()).hideFlags = (HideFlags)61;
				}
			}
			else
			{
				_nextItemDuplicateID = null;
				UnlockathonInventoryManager.UnlockItem(__instance);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("DuplicateFromSpawnLock")]
		private static void DuplicateFromSpawnLock_Prefix(FVRPhysicalObject __instance)
		{
			_nextItemDuplicateID = __instance?.ObjectWrapper?.ItemID;
		}
	}
	[HarmonyWrapSafe]
	[HarmonyPatch(typeof(ItemSpawnerV2))]
	internal static class ItemSpawnerV2UnlockathonPatcher
	{
		[HarmonyTranspiler]
		[HarmonyPatch("RedrawSimpleCanvas")]
		private static IEnumerable<CodeInstruction> RedrawSimpleCanvas_Transpiler_LockItems(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			List<CodeInstruction> list = instructions.ToList();
			try
			{
				return new CodeMatcher((IEnumerable<CodeInstruction>)list, (ILGenerator)null).SearchForward((Func<CodeInstruction, bool>)((CodeInstruction code) => code.opcode == OpCodes.Call && code.operand == AccessTools.Method(typeof(IM), "GetSpawnerID", (Type[])null, (Type[])null))).SetAndAdvance(OpCodes.Call, (object)AccessTools.Method(typeof(UnlockathonInventoryManager), "GetUnlockableItemSpawnerID", (Type[])null, (Type[])null)).InstructionEnumeration();
			}
			catch (Exception arg)
			{
				OtherLogger.LogError(string.Format("Exception in {0} transpiler: {1}", "RedrawSimpleCanvas_Transpiler_LockItems", arg));
				return list;
			}
		}

		[HarmonyTranspiler]
		[HarmonyPatch("RedrawListCanvas")]
		private static IEnumerable<CodeInstruction> RedrawListCanvas_Transpiler_LockItems(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			List<CodeInstruction> list = instructions.ToList();
			try
			{
				return new CodeMatcher((IEnumerable<CodeInstruction>)list, (ILGenerator)null).SearchForward((Func<CodeInstruction, bool>)((CodeInstruction code) => code.opcode == OpCodes.Call && code.operand == AccessTools.Method(typeof(IM), "GetSpawnerID", (Type[])null, (Type[])null))).SetAndAdvance(OpCodes.Call, (object)AccessTools.Method(typeof(UnlockathonInventoryManager), "GetUnlockableItemSpawnerID", (Type[])null, (Type[])null)).SearchForward((Func<CodeInstruction, bool>)((CodeInstruction code) => code.opcode == OpCodes.Call && code.operand == AccessTools.Method(typeof(IM), "GetSpawnerID", (Type[])null, (Type[])null)))
					.SetAndAdvance(OpCodes.Call, (object)AccessTools.Method(typeof(UnlockathonInventoryManager), "GetUnlockableItemSpawnerID", (Type[])null, (Type[])null))
					.InstructionEnumeration();
			}
			catch (Exception arg)
			{
				OtherLogger.LogError(string.Format("Exception in {0} transpiler: {1}", "RedrawListCanvas_Transpiler_LockItems", arg));
				return list;
			}
		}

		[HarmonyTranspiler]
		[HarmonyPatch("RedrawDetailsCanvas")]
		private static IEnumerable<CodeInstruction> RedrawDetailsCanvas_Transpiler_LockItems(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			List<CodeInstruction> list = instructions.ToList();
			try
			{
				return new CodeMatcher((IEnumerable<CodeInstruction>)list, (ILGenerator)null).SearchForward((Func<CodeInstruction, bool>)((CodeInstruction code) => code.opcode == OpCodes.Call && code.operand == AccessTools.Method(typeof(IM), "GetSpawnerID", (Type[])null, (Type[])null))).SetAndAdvance(OpCodes.Call, (object)AccessTools.Method(typeof(UnlockathonInventoryManager), "GetUnlockableItemSpawnerID", (Type[])null, (Type[])null)).SearchForward((Func<CodeInstruction, bool>)((CodeInstruction code) => code.opcode == OpCodes.Call && code.operand == AccessTools.Method(typeof(IM), "GetSpawnerID", (Type[])null, (Type[])null)))
					.SetAndAdvance(OpCodes.Call, (object)AccessTools.Method(typeof(UnlockathonInventoryManager), "GetUnlockableItemSpawnerID", (Type[])null, (Type[])null))
					.InstructionEnumeration();
			}
			catch (Exception arg)
			{
				OtherLogger.LogError(string.Format("Exception in {0} transpiler: {1}", "RedrawDetailsCanvas_Transpiler_LockItems", arg));
				return list;
			}
		}

		[HarmonyPriority(100)]
		[HarmonyPostfix]
		[HarmonyPatch("RedrawDetailsCanvas")]
		private static void RedrawDetailsCanvas_Postfix_ShowLockedDetails(ItemSpawnerV2 __instance)
		{
			if (string.IsNullOrEmpty(__instance.m_selectedID))
			{
				return;
			}
			bool flag = UnlockathonInventoryManager.IsItemSpawnerIDUnlocked(__instance.m_selectedID);
			OtherLogger.Log($"ItemSpawnerID: {__instance.m_selectedID}, Unlocked: {flag}", LogTag.Unlockathon);
			if (flag)
			{
				return;
			}
			GameObject bTN_SpawnSelectedObject = __instance.BTN_SpawnSelectedObject;
			if (bTN_SpawnSelectedObject != null)
			{
				GameObject gameObject = bTN_SpawnSelectedObject.gameObject;
				if (gameObject != null)
				{
					gameObject.SetActive(false);
				}
			}
		}
	}
	[HarmonyWrapSafe]
	internal static class RandomGunSpawnUnlockathonPatcher
	{
		private static float _lastClickTimestamp = -100f;

		private const float MarginSeconds = 5f;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(ItemSpawnerV2), "BTN_TryToSpawnRandomGun")]
		private static void BTN_TryToSpawnRandomGun_Prefix()
		{
			_lastClickTimestamp = Time.time;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FVRInteractiveObject), "Start")]
		private static void FVRPhysicalObject_Start_Prefix(FVRInteractiveObject __instance)
		{
			if (__instance is FVRPhysicalObject && !(_lastClickTimestamp + 5f < Time.time))
			{
				OtherLogger.Log("Adding SpawnedByRandomGunButtonTag to object: " + ((Object)__instance).name, LogTag.Unlockathon);
				if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<SpawnedByRandomGunButtonTag>()))
				{
					((Object)((Component)__instance).gameObject.AddComponent<SpawnedByRandomGunButtonTag>()).hideFlags = (HideFlags)61;
				}
			}
		}
	}
	[HarmonyWrapSafe]
	[HarmonyPatch(typeof(VaultSystem))]
	internal static class VaultSpawnUnlockathonPatcher
	{
		[HarmonyPrefix]
		[HarmonyPatch("SpawnVaultFile")]
		private static void SpawnVaultFile_Prefix_AddTagToObjects(ref ReturnObjectListDelegate del)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			ReturnObjectListDelegate originalDel = del;
			del = (ReturnObjectListDelegate)delegate(List<FVRPhysicalObject> rootObjs)
			{
				OtherLoader.ExceptionCatcher.Run(delegate
				{
					if (rootObjs != null)
					{
						foreach (FVRPhysicalObject rootObj in rootObjs)
						{
							if (!((Object)(object)rootObj == (Object)null))
							{
								List<FVRPhysicalObject> list = new List<FVRPhysicalObject>();
								list.Add(rootObj);
								list.AddRange(rootObj.GetAllChildPhysicalObjectsRecursively());
								foreach (FVRPhysicalObject item in list)
								{
									OtherLogger.Log("Adding SpawnedFromVaultTag to object: " + ((Object)item).name, LogTag.Unlockathon);
									if (!Object.op_Implicit((Object)(object)((Component)item).GetComponent<SpawnedFromVaultTag>()))
									{
										((Object)((Component)item).gameObject.AddComponent<SpawnedFromVaultTag>()).hideFlags = (HideFlags)61;
									}
								}
							}
						}
					}
				});
				ReturnObjectListDelegate obj = originalDel;
				if (obj != null)
				{
					obj.Invoke(rootObjs);
				}
			};
		}
	}
}
namespace OtherLoader.Unlockathon.Data
{
	public class OldOtherLoaderDataDto
	{
		public string[]? UnlockedItemIDs { get; set; }
	}
	internal class PreferencesDto
	{
		public bool? UnlockathonEnabled { get; set; }

		public string? UnlockathonSelectedProfileFileName { get; set; }

		public int? UnlockathonSelectedProfileIndex
		{
			get; [Obsolete]
			set;
		}
	}
	internal class ProfileDto
	{
		public string? DisplayName { get; set; }

		public bool? UnlockItemsSpawnedFromVault { get; set; }

		public bool? UnlockSecondaryItems { get; set; }

		public bool? KeepModded { get; set; }

		public bool? KeepGuns { get; set; }

		public bool? KeepAmmo { get; set; }

		public bool? KeepGrenadesExplosives { get; set; }

		public bool? KeepAttachments { get; set; }

		public bool? KeepMelee { get; set; }

		public bool? KeepToolsToys { get; set; }

		public string[]? UnlockedItemSpawnerIDs { get; set; }

		public string[]? UnlockedItemSpawnerIDsSecondaries { get; set; }

		public string[]? UnlockedObjectIDs { get; set; }

		public string[]? UnlockedObjectIDsSecondaries { get; set; }
	}
}
namespace OtherLoader.QuickbeltPanel
{
	internal class QBslotPageController : MonoBehaviour
	{
		public const int QbsPerPage = 14;

		public OptionsPanel_ButtonSet QBslotButtonSet;

		public GameObject ButtonNextPage;

		public GameObject ButtonPreviousPage;

		public int currentPage;

		public void Start()
		{
			SetVisibility();
		}

		public void SetButtons()
		{
			ButtonNextPage.SetActive(true);
			ButtonPreviousPage.SetActive(true);
			if (currentPage <= 0)
			{
				ButtonPreviousPage.SetActive(false);
			}
			int num = Mathf.CeilToInt((float)(QBslotButtonSet.ButtonsInSet.Length / 14));
			if (currentPage >= num)
			{
				ButtonNextPage.SetActive(false);
			}
		}

		public void SetVisibility()
		{
			SetButtons();
			FVRPointableButton[] buttonsInSet = QBslotButtonSet.ButtonsInSet;
			for (int i = 0; i < buttonsInSet.Length; i++)
			{
				((Component)buttonsInSet[i]).gameObject.SetActive(false);
			}
			int num = currentPage * 14;
			int num2 = num + 14;
			for (int j = num; j < num2 && j < QBslotButtonSet.ButtonsInSet.Length; j++)
			{
				((Component)QBslotButtonSet.ButtonsInSet[j]).gameObject.SetActive(true);
			}
		}

		public void GotoPreviousPage()
		{
			currentPage--;
			SetVisibility();
		}

		public void GotoNextPage()
		{
			currentPage++;
			SetVisibility();
		}
	}
	[HarmonyWrapSafe]
	internal static class QuickbeltPanelPatcher
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(OptionsScreen_Quickbelt), "Awake")]
		private static bool Awake_Prefix_AddScreens(OptionsScreen_Quickbelt __instance)
		{
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Expected O, but got Unknown
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Expected O, but got Unknown
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Expected O, but got Unknown
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Expected O, but got Unknown
			OptionsScreen_Quickbelt __instance2 = __instance;
			QBslotPageController pageController = ((Component)__instance2).gameObject.AddComponent<QBslotPageController>();
			pageController.QBslotButtonSet = __instance2.OBS_SlotStyle;
			GameObject gameObject = ((Component)__instance2.OBS_Handedness.ButtonsInSet[0]).gameObject;
			FVRPointableButton[] buttonsInSet = __instance2.OBS_SlotStyle.ButtonsInSet;
			for (int i = 0; i < buttonsInSet.Length; i++)
			{
				Object.Destroy((Object)(object)((Component)buttonsInSet[i]).gameObject);
			}
			__instance2.OBS_SlotStyle.ButtonsInSet = (FVRPointableButton[])(object)new FVRPointableButton[ManagerSingleton<GM>.Instance.QuickbeltConfigurations.Length];
			for (int j = 0; j < __instance2.OBS_SlotStyle.ButtonsInSet.Length; j++)
			{
				int num = j % 14;
				int column = num % 4;
				int row = (int)Mathf.Floor((float)num / 4f);
				OtherLogger.Log("Adding QB " + ((Object)ManagerSingleton<GM>.Instance.QuickbeltConfigurations[j]).name, LogTag.BundleLoading);
				GameObject val = Object.Instantiate<GameObject>(gameObject, ((Component)__instance2.OBS_SlotStyle).transform, true);
				FVRPointableButton component = val.GetComponent<FVRPointableButton>();
				__instance2.OBS_SlotStyle.ButtonsInSet[j] = component;
				string text = ((Object)ManagerSingleton<GM>.Instance.QuickbeltConfigurations[j]).name.Split(new char[1] { '_' }).Last();
				Button uiButton = SetQBSlotOptionsPanelButton(val, row, column, text);
				((UnityEvent)uiButton.onClick).AddListener((UnityAction)delegate
				{
					__instance2.SetSlotStyle(((Component)uiButton).transform.GetSiblingIndex());
				});
				((UnityEvent)uiButton.onClick).AddListener((UnityAction)delegate
				{
					__instance2.OBS_SlotStyle.SetSelectedButton(((Component)uiButton).transform.GetSiblingIndex());
				});
			}
			Button val2 = SetQBSlotOptionsPanelButton(Object.Instantiate<GameObject>(gameObject, ((Component)__instance2.OBS_SlotStyle).transform, true), 3, 2, "Previous Page");
			((UnityEvent)val2.onClick).AddListener((UnityAction)delegate
			{
				pageController.GotoPreviousPage();
			});
			pageController.ButtonPreviousPage = ((Component)val2).gameObject;
			val2 = SetQBSlotOptionsPanelButton(Object.Instantiate<GameObject>(gameObject, ((Component)__instance2.OBS_SlotStyle).transform, true), 3, 3, "Next Page");
			((UnityEvent)val2.onClick).AddListener((UnityAction)delegate
			{
				pageController.GotoNextPage();
			});
			pageController.ButtonNextPage = ((Component)val2).gameObject;
			return true;
		}

		public static Button SetQBSlotOptionsPanelButton(GameObject button, int row, int column, string text)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			float num = -100 + 125 * column;
			float num2 = -40 + -45 * row;
			button.transform.localPosition = new Vector3(num, num2, button.transform.localPosition.z);
			((Component)button.gameObject.transform.GetChild(0)).GetComponent<Text>().text = text;
			Button component = button.GetComponent<Button>();
			((UnityEventBase)component.onClick).RemoveAllListeners();
			return component;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FVRPlayerBody), "ConfigureQuickbelt")]
		private static bool ConfigureQuickbelt_Prefix_PreventIndexOutOfRange(ref int index)
		{
			index = Mathf.Clamp(index, 0, ManagerSingleton<GM>.Instance.QuickbeltConfigurations.Length - 1);
			return true;
		}
	}
}
namespace OtherLoader.Logging
{
	[Flags]
	internal enum LogTag
	{
		None = 0,
		General = 1,
		Assets = 2,
		BundleLoading = 4,
		ItemSpawnerPatches = 8,
		ItemSpawnerTagging = 0x10,
		ItemUnlocker = 0x20,
		Unlockathon = 0x40,
		All = 0x1F
	}
	internal static class OtherLogger
	{
		private static ManualLogSource _logSource;

		public static void Initialize(ManualLogSource log)
		{
			_logSource = log;
		}

		public static void LogInfo(string log)
		{
			_logSource.LogInfo((object)log);
		}

		public static void LogWarning(string log)
		{
			_logSource.LogWarning((object)log);
		}

		public static void LogError(string log)
		{
			_logSource.LogError((object)log);
		}

		public static void LogFatal(string log)
		{
			_logSource.LogFatal((object)log);
		}

		public static void Log(string log, LogTag tag = LogTag.General)
		{
			if ((tag == LogTag.None || tag == LogTag.All) ? true : false)
			{
				LogError("Invalid log tag");
			}
			else if (CanBeLogged(tag))
			{
				ConsoleColor? color = null;
				if (PluginConfig.ColoredLogs.Value)
				{
					color = tag switch
					{
						LogTag.Assets => ConsoleColor.Blue, 
						LogTag.BundleLoading => ConsoleColor.DarkCyan, 
						LogTag.ItemSpawnerPatches => ConsoleColor.DarkMagenta, 
						LogTag.ItemSpawnerTagging => ConsoleColor.DarkGreen, 
						LogTag.ItemUnlocker => ConsoleColor.DarkBlue, 
						LogTag.Unlockathon => ConsoleColor.DarkYellow, 
						_ => null, 
					};
				}
				if (color.HasValue)
				{
					LogLevelColorPatcher.QueueColor(color);
				}
				_logSource.LogMessage((object)log);
				if ((object)null != null)
				{
					((Harmony)null).UnpatchSelf();
				}
			}
		}

		private static bool CanBeLogged(LogTag logTag)
		{
			return (PluginConfig.LogTags.Value & logTag) != 0;
		}
	}
	internal class TL
	{
		private readonly List<string> _traceElements;

		private LogTag _logTag;

		public TL(string first, LogTag logTag)
		{
			_logTag = logTag;
			if (PluginConfig.EnableLogTraces)
			{
				_traceElements = new List<string>(1) { first };
			}
		}

		private TL(TL tl)
		{
			_traceElements = new List<string>(tl._traceElements);
			_logTag = tl._logTag;
		}

		public TL New(string next, LogTag? newTag = null)
		{
			if (!PluginConfig.EnableLogTraces)
			{
				return this;
			}
			TL tL = new TL(this);
			if (!tL._traceElements.Contains(next))
			{
				tL._traceElements.Add(next);
			}
			if (newTag.HasValue)
			{
				tL._logTag = newTag.Value;
			}
			return tL;
		}

		public void Log(string message, LogTag? tag = null)
		{
			if (!PluginConfig.EnableLogTraces)
			{
				OtherLogger.Log(message, tag ?? _logTag);
			}
			else
			{
				OtherLogger.Log(ConstructFullMessage(message), tag ?? _logTag);
			}
		}

		public void LogInfo(string message)
		{
			if (!PluginConfig.EnableLogTraces)
			{
				OtherLogger.LogInfo(message);
			}
			else
			{
				OtherLogger.LogInfo(ConstructFullMessage(message));
			}
		}

		public void LogError(string message)
		{
			if (!PluginConfig.EnableLogTraces)
			{
				OtherLogger.LogError(message);
			}
			else
			{
				OtherLogger.LogError(ConstructFullMessage(message));
			}
		}

		public void LogWarning(string message)
		{
			if (!PluginConfig.EnableLogTraces)
			{
				OtherLogger.LogWarning(message);
			}
			else
			{
				OtherLogger.LogWarning(ConstructFullMessage(message));
			}
		}

		private string ConstructFullMessage(string message)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (string traceElement in _traceElements)
			{
				stringBuilder.Append("[" + traceElement + "]");
			}
			stringBuilder.Append(' ').Append(message);
			return stringBuilder.ToString();
		}
	}
}
namespace OtherLoader.ItemUnlocker
{
	public enum ItemUnlockerMode
	{
		Disabled,
		UnlockOnlyFirearmsAndAmmo,
		UnlockOnlyModdedItems,
		UnlockAllItems
	}
	[HarmonyWrapSafe]
	internal static class RewardUnlocksPatchers
	{
		private static int _activeMethods;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(RewardUnlocks), "IsRewardUnlocked", new Type[] { typeof(ItemSpawnerID) })]
		private static void IsRewardUnlocked_Postfix(ItemSpawnerID ID, ref bool __result)
		{
			if (_activeMethods == 0)
			{
				return;
			}
			if (!__result)
			{
				if (PluginConfig.ItemUnlocker == ItemUnlockerMode.UnlockOnlyModdedItems)
				{
					if (string.IsNullOrEmpty(ID.FromMod))
					{
						OtherLogger.Log("Reward item '" + ID.DisplayName + "' is not modded, skipping...", LogTag.ItemUnlocker);
						return;
					}
				}
				else if (PluginConfig.ItemUnlocker == ItemUnlockerMode.UnlockOnlyFirearmsAndAmmo && !ID.IsFirearm() && !ID.IsAmmo())
				{
					OtherLogger.Log("Reward item '" + ID.DisplayName + "' is not firearm or ammo, skipping...", LogTag.ItemUnlocker);
					return;
				}
				OtherLogger.Log("Game checked if '" + ID.DisplayName + "' is unlocked, returning true!", LogTag.ItemUnlocker);
				if (!ID.ModTags.Contains("GrantedByItemUnlocker"))
				{
					ID.ModTags = ID.ModTags.Concat(new <>z__ReadOnlySingleElementList<string>("GrantedByItemUnlocker")).ToList();
				}
			}
			__result = true;
		}

		private static void AddActiveMethod()
		{
			Interlocked.Increment(ref _activeMethods);
		}

		private static void RemoveActiveMethod()
		{
			if (Interlocked.Decrement(ref _activeMethods) < 0)
			{
				Interlocked.Exchange(ref _activeMethods, 0);
			}
		}

		[HarmonyPriority(700)]
		[HarmonyPrefix]
		[HarmonyPatch(typeof(ItemSpawnerIDRegisterer), "Register")]
		private static void Register_Prefix()
		{
			AddActiveMethod();
		}

		[HarmonyFinalizer]
		[HarmonyPatch(typeof(ItemSpawnerIDRegisterer), "Register")]
		private static Exception Register_Finalizer(Exception __exception)
		{
			RemoveActiveMethod();
			return __exception;
		}

		[HarmonyPriority(700)]
		[HarmonyPrefix]
		[HarmonyPatch(typeof(IM), "GenerateItemDBs")]
		private static void GenerateItemDBs_Prefix()
		{
			AddActiveMethod();
		}

		[HarmonyFinalizer]
		[HarmonyPatch(typeof(IM), "GenerateItemDBs")]
		private static Exception GenerateItemDBs_Finalizer(Exception __exception)
		{
			RemoveActiveMethod();
			return __exception;
		}

		[HarmonyPriority(700)]
		[HarmonyPrefix]
		[HarmonyPatch(typeof(ItemSpawnerV2), "RedrawDetailsCanvas")]
		private static void RedrawDetailsCanvas_Prefix()
		{
			AddActiveMethod();
		}

		[HarmonyFinalizer]
		[HarmonyPatch(typeof(ItemSpawnerV2), "RedrawDetailsCanvas")]
		private static Exception RedrawDetailsCanvas_Finalizer(Exception __exception)
		{
			RemoveActiveMethod();
			return __exception;
		}
	}
}
namespace OtherLoader.ItemSpawner
{
	internal static class ItemSpawnerIDRegisterer
	{
		public static void Register(TL oldTL, ItemSpawnerID itemSpawnerID, bool registerInTilesDatabase, bool unifyItemIDs, bool blockDuplicateIDs, string pluginName)
		{
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0378: Unknown result type (might be due to invalid IL or missing references)
			//IL_038d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0311: Unknown result type (might be due to invalid IL or missing references)
			//IL_0329: Unknown result type (might be due to invalid IL or missing references)
			TL tL = oldTL.New("Register", LogTag.Assets);
			EnsureMainObjectIsNotNull(tL, itemSpawnerID);
			itemSpawnerID.FromMod = pluginName;
			if (unifyItemIDs && itemSpawnerID.MainObject?.ItemID != null)
			{
				itemSpawnerID.ItemID = itemSpawnerID.MainObject.ItemID;
				itemSpawnerID.MainObject.SpawnedFromId = itemSpawnerID.MainObject.ItemID;
				tL.Log("Unified spawner IDs");
			}
			if (itemSpawnerID.ItemID == null)
			{
				tL.LogError("ItemSpawnerID.ItemID is null, can't register ItemSpawnerID!");
				return;
			}
			tL.Log("Registering new ItemSpawnerID\n- DisplayName '" + itemSpawnerID.DisplayName + "'\n- ItemID '" + itemSpawnerID.ItemID + "'\n- MainObject.ItemID '" + (itemSpawnerID.MainObject?.ItemID ?? "null") + "'" + $"\n- Category '{itemSpawnerID.Category}'" + $"\n- SubCategory '{itemSpawnerID.SubCategory}'" + $"\n- IsDisplayedInMainEntry '{itemSpawnerID.IsDisplayedInMainEntry}'" + $"\n- IsReward '{itemSpawnerID.IsReward}'" + $"\n- SecondObject '{itemSpawnerID.SecondObject}'" + "\n- Secondaries: " + (itemSpawnerID.Secondaries?.JoinToString() ?? "null") + "\n- SecondariesByStringID: " + (itemSpawnerID.Secondaries_ByStringID?.JoinToString() ?? "null"));
			if (IM.HasSpawnedID(itemSpawnerID.ItemID))
			{
				if (blockDuplicateIDs)
				{
					tL.LogWarning("Warning! Duplicates are specifically disabled for this mod! Skipping ItemSpawnerID with ID '" + itemSpawnerID.ItemID + "' because a spawner entry with the same ID is already registered!");
					return;
				}
				tL.LogWarning("Warning! Registering ItemSpawnerID with ID '" + itemSpawnerID.ItemID + "' even though a spawner entry with the same ID is already registered!");
				if (itemSpawnerID.IsDisplayedInMainEntry)
				{
					ManagerSingleton<IM>.Instance.SpawnerIDDic[itemSpawnerID.ItemID] = itemSpawnerID;
				}
			}
			else
			{
				ManagerSingleton<IM>.Instance.SpawnerIDDic[itemSpawnerID.ItemID] = itemSpawnerID;
			}
			if (!GM.Rewards.RewardUnlocks.IsRewardUnlocked(itemSpawnerID))
			{
				tL.LogInfo("Item spawner entry '" + itemSpawnerID.DisplayName + "' (ID: " + itemSpawnerID.ItemID + ") is a reward unlock that's not unlocked, it will not appear in the spawner.");
				return;
			}
			ItemSpawnerIDTagger.RegisterSpawnerIDIntoTagSystem(itemSpawnerID);
			IM.CD.GetValueOrNull(itemSpawnerID.Category)?.Add(itemSpawnerID);
			IM.SCD.GetValueOrNull(itemSpawnerID.SubCategory)?.Add(itemSpawnerID);
			RegisteredItemSpawnerIDsDatabase.RegisteredModdedIDs.Add(itemSpawnerID.ItemID);
			if (!itemSpawnerID.IsDisplayedInMainEntry || !registerInTilesDatabase)
			{
				return;
			}
			if (Enum.IsDefined(typeof(EItemCategory), itemSpawnerID.Category))
			{
				if (!Enum.IsDefined(typeof(ESubCategory), itemSpawnerID.SubCategory))
				{
					ItemSpawnerEntry itemSpawnerEntry = ItemSpawnerEntry.CreateEmpty($"{itemSpawnerID.SubCategory}/" + itemSpawnerID.ItemID);
					itemSpawnerEntry.DisplayName = itemSpawnerID.DisplayName;
					itemSpawnerEntry.MainObjectID = itemSpawnerID.ItemID;
					itemSpawnerEntry.EntryIcon = itemSpawnerID.Sprite;
					SpawnerTilesDatabase.TryRegister(itemSpawnerEntry);
				}
			}
			else
			{
				ItemSpawnerEntry itemSpawnerEntry2 = ItemSpawnerEntry.CreateEmpty($"{itemSpawnerID.Category}/" + $"{itemSpawnerID.SubCategory}/" + itemSpawnerID.ItemID);
				itemSpawnerEntry2.DisplayName = itemSpawnerID.DisplayName;
				itemSpawnerEntry2.MainObjectID = itemSpawnerID.ItemID;
				itemSpawnerEntry2.EntryIcon = itemSpawnerID.Sprite;
				SpawnerTilesDatabase.TryRegister(itemSpawnerEntry2);
			}
		}

		private static void EnsureMainObjectIsNotNull(TL oldTL, ItemSpawnerID spawnerId)
		{
			TL tL = oldTL.New("EnsureMainObjectIsNotNull");
			if (!((Object)(object)spawnerId.MainObject != (Object)null))
			{
				spawnerId.MainObject = spawnerId.Secondaries.Select((ItemSpawnerID obj) => obj.MainObject).FirstOrDefault((Func<FVRObject, bool>)((FVRObject obj) => (Object)(object)obj != (Object)null));
				if ((Object)(object)spawnerId.MainObject == (Object)null)
				{
					throw new NullReferenceException("ItemSpawnerID.MainObject is null, and there are no secondary objects to use as the main object");
				}
				spawnerId.ItemID = spawnerId.MainObject.ItemID;
				tL.Log("Assigned ItemID '" + spawnerId.ItemID + "' from secondary object");
			}
		}
	}
	internal static class ItemSpawnerIDTagger
	{
		public static void RegisterSpawnerIDIntoTagSystem(ItemSpawnerID spawnerID)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Invalid comparison between Unknown and I4
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Invalid comparison between Unknown and I4
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Invalid comparison between Unknown and I4
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			TL tL = new TL("RegisterSpawnerIDIntoTagSystem", LogTag.ItemSpawnerTagging);
			tL.Log("Attempting to tag '" + spawnerID.ItemID + "'");
			PageMode spawnerPageForSpawnerId = GetSpawnerPageForSpawnerId(spawnerID);
			tL.Log($"Assigning item to spawner page '{spawnerPageForSpawnerId}'");
			RegisterModTags(spawnerID, spawnerPageForSpawnerId);
			RegisterCategoryTags(spawnerID, spawnerPageForSpawnerId);
			if ((int)spawnerPageForSpawnerId == 1)
			{
				RegisterFirearmIntoMetaTagSystem(spawnerID, spawnerPageForSpawnerId);
			}
			else if ((int)spawnerPageForSpawnerId == 3)
			{
				RegisterAttachmentIntoMetaTagSystem(spawnerID, spawnerPageForSpawnerId);
			}
			else if ((int)spawnerPageForSpawnerId == 2)
			{
				RegisterAmmoIntoMetaTagSystem(spawnerID, spawnerPageForSpawnerId);
			}
		}

		private static PageMode GetSpawnerPageForSpawnerId(ItemSpawnerID spawnerId)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Invalid comparison between Unknown and I4
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Invalid comparison between Unknown and I4
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			if (ShouldItemBeTaggedAsToolsToys(spawnerId))
			{
				return (PageMode)5;
			}
			if (ShouldItemBeTaggedAsMelee(spawnerId))
			{
				return (PageMode)4;
			}
			if (ShouldItemBeTaggedAsAmmo(spawnerId))
			{
				return (PageMode)2;
			}
			if ((int)ItemSubCategoryMapper.InferCategoryFrom(spawnerId.SubCategory).GetValueOrDefault() == 4)
			{
				return (PageMode)3;
			}
			if (spawnerId.IsFirearm())
			{
				return (PageMode)1;
			}
			if ((int)spawnerId.MainObject.Category == 5)
			{
				return (PageMode)3;
			}
			return (PageMode)1;
		}

		private static void RegisterCategoryTags(ItemSpawnerID spawnerId, PageMode page)
		{
			//IL_0018: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			IM.AddMetaTag(((object)(EItemCategory)(ref spawnerId.Category)).ToString(), (TagType)2, spawnerId.ItemID, page);
			if ((int)spawnerId.SubCategory != 0)
			{
				IM.AddMetaTag(((object)(ESubCategory)(ref spawnerId.SubCategory)).ToString(), (TagType)3, spawnerId.ItemID, page);
			}
		}

		private static void RegisterModTags(ItemSpawnerID spawnerId, PageMode page)
		{
			//IL_001d: 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)
			foreach (string modTag in spawnerId.ModTags)
			{
				IM.AddMetaTag(modTag, (TagType)50, spawnerId.ItemID, page);
			}
			IM.AddMetaTag("Ot