Decompiled source of MagazinePatcher v0.3.1

patchers/OldMagazinePatcherDisabler.dll

Decompiled 5 days ago
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BepInEx;
using BepInEx.Logging;
using Mono.Cecil;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("OldMagazinePatcherDisabler")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("OldMagazinePatcherDisabler")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("4f728f32-4deb-4870-bc9b-67fdd28dbfc4")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace OldMagazinePatcherDisabler;

public static class Disabler
{
	private static readonly ManualLogSource Logger = Logger.CreateLogSource("Deliter");

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

	public static void Patch(AssemblyDefinition asm)
	{
		Logger.LogWarning((object)("No DLLs should be patched, but the patch method was called. Assembly: " + (object)asm));
	}

	public static string CombinePaths(params string[] paths)
	{
		if (paths == null)
		{
			return "";
		}
		return paths.Aggregate(Path.Combine);
	}

	public static void Initialize()
	{
		string text = CombinePaths(Paths.ConfigPath, "h3vr.magazinepatcher.cfg");
		Logger.LogInfo((object)("Config file path: " + text));
		string text2 = CombinePaths(Paths.CachePath, "MagazinePatcher");
		if (!Directory.Exists(text2))
		{
			Directory.CreateDirectory(text2);
		}
		string text3 = CombinePaths(text2, "CachedCompatibleMags.json");
		Logger.LogInfo((object)("Cache path: " + text3));
		string[] directories = Directory.GetDirectories(Paths.PluginPath);
		foreach (string text4 in directories)
		{
			Logger.LogInfo((object)("Found directory " + text4));
			if (!text4.Contains("devyndamonster-MagazinePatcher"))
			{
				continue;
			}
			string text5 = CombinePaths(text4, "MagazinePatcher", "MagazinePatcher.dll");
			string text6 = CombinePaths(text4, "MagazinePatcher", "manifest.json");
			string text7 = CombinePaths(text4, "MagazinePatcher", "CachedCompatibleMags.json");
			if (!File.Exists(text) && !File.Exists(text3))
			{
				if (File.Exists(text5 + ".old"))
				{
					if (File.Exists(text7 + ".old"))
					{
						File.Copy(text7 + ".old", text3, overwrite: true);
					}
					else if (File.Exists(text7))
					{
						File.Copy(text7, text3, overwrite: true);
					}
				}
				else if (File.Exists(text5))
				{
					File.Copy(text7, text3, overwrite: true);
				}
			}
			if (File.Exists(text5))
			{
				if (File.Exists(text5 + ".bak"))
				{
					File.Delete(text5 + ".bak");
				}
				if (File.Exists(text6 + ".bak"))
				{
					File.Delete(text6 + ".bak");
				}
				File.Move(text5, text5 + ".bak");
				File.Move(text6, text6 + ".bak");
				Logger.LogInfo((object)"Disabled original MagazinePatcher install. Re-enable it via reinstalling or renaming the DLL. Will break compatibility with new MagazinePatcher.");
			}
			break;
		}
	}
}

plugins/MagazinePatcher/MagazinePatcher.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.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FistVR;
using Microsoft.CodeAnalysis;
using OtherLoader;
using Stratum;
using UnityEngine;
using Valve.Newtonsoft.Json;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("MagazinePatcher")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MagazinePatcher")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("98995a27-db6e-4095-afcc-a831bf390698")]
[assembly: AssemblyFileVersion("0.3.1.0")]
[assembly: AssemblyVersion("0.3.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MagazinePatcher
{
	public class CompatibleMagazineCache
	{
		public List<string> Firearms;

		public List<string> Magazines;

		public List<string> Clips;

		public List<string> SpeedLoaders;

		public List<string> Bullets;

		public Dictionary<string, MagazineCacheEntry> Entries;

		public Dictionary<string, AmmoObjectDataTemplate> AmmoObjects;

		public Dictionary<FireArmMagazineType, List<AmmoObjectDataTemplate>> MagazineData;

		public Dictionary<FireArmClipType, List<AmmoObjectDataTemplate>> ClipData;

		public Dictionary<FireArmRoundType, List<AmmoObjectDataTemplate>> SpeedLoaderData;

		public Dictionary<FireArmRoundType, List<AmmoObjectDataTemplate>> BulletData;

		public static CompatibleMagazineCache Instance;

		public static Dictionary<string, MagazineBlacklistEntry> BlacklistEntries;

		public CompatibleMagazineCache()
		{
			Firearms = new List<string>();
			Magazines = new List<string>();
			Clips = new List<string>();
			SpeedLoaders = new List<string>();
			Bullets = new List<string>();
			Entries = new Dictionary<string, MagazineCacheEntry>();
			AmmoObjects = new Dictionary<string, AmmoObjectDataTemplate>();
			MagazineData = new Dictionary<FireArmMagazineType, List<AmmoObjectDataTemplate>>();
			ClipData = new Dictionary<FireArmClipType, List<AmmoObjectDataTemplate>>();
			SpeedLoaderData = new Dictionary<FireArmRoundType, List<AmmoObjectDataTemplate>>();
			BulletData = new Dictionary<FireArmRoundType, List<AmmoObjectDataTemplate>>();
			BlacklistEntries = new Dictionary<string, MagazineBlacklistEntry>();
		}

		public void AddMagazineData(FVRFireArmMagazine mag)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (!MagazineData.ContainsKey(mag.MagazineType))
			{
				MagazineData.Add(mag.MagazineType, new List<AmmoObjectDataTemplate>());
			}
			MagazineData[mag.MagazineType].Add(new AmmoObjectDataTemplate(mag));
			if (!AmmoObjects.ContainsKey(((FVRPhysicalObject)mag).ObjectWrapper.ItemID))
			{
				AmmoObjects.Add(((FVRPhysicalObject)mag).ObjectWrapper.ItemID, new AmmoObjectDataTemplate(mag));
			}
		}

		public void AddClipData(FVRFireArmClip clip)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (!ClipData.ContainsKey(clip.ClipType))
			{
				ClipData.Add(clip.ClipType, new List<AmmoObjectDataTemplate>());
			}
			ClipData[clip.ClipType].Add(new AmmoObjectDataTemplate(clip));
			if (!AmmoObjects.ContainsKey(((FVRPhysicalObject)clip).ObjectWrapper.ItemID))
			{
				AmmoObjects.Add(((FVRPhysicalObject)clip).ObjectWrapper.ItemID, new AmmoObjectDataTemplate(clip));
			}
		}

		public void AddSpeedLoaderData(Speedloader speedloader)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if (!SpeedLoaderData.ContainsKey(speedloader.Chambers[0].Type))
			{
				SpeedLoaderData.Add(speedloader.Chambers[0].Type, new List<AmmoObjectDataTemplate>());
			}
			SpeedLoaderData[speedloader.Chambers[0].Type].Add(new AmmoObjectDataTemplate(speedloader));
			if (!AmmoObjects.ContainsKey(((FVRPhysicalObject)speedloader).ObjectWrapper.ItemID))
			{
				AmmoObjects.Add(((FVRPhysicalObject)speedloader).ObjectWrapper.ItemID, new AmmoObjectDataTemplate(speedloader));
			}
		}

		public void AddBulletData(FVRFireArmRound bullet)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (!BulletData.ContainsKey(bullet.RoundType))
			{
				BulletData.Add(bullet.RoundType, new List<AmmoObjectDataTemplate>());
			}
			BulletData[bullet.RoundType].Add(new AmmoObjectDataTemplate(bullet));
			if (!AmmoObjects.ContainsKey(((FVRPhysicalObject)bullet).ObjectWrapper.ItemID))
			{
				AmmoObjects.Add(((FVRPhysicalObject)bullet).ObjectWrapper.ItemID, new AmmoObjectDataTemplate(bullet));
			}
		}
	}
	public class MagazineCacheEntry
	{
		public string FirearmID;

		public FireArmMagazineType MagType;

		public FireArmClipType ClipType;

		public FireArmRoundType BulletType;

		public bool DoesUseSpeedloader;

		public HashSet<string> CompatibleMagazines;

		public HashSet<string> CompatibleClips;

		public HashSet<string> CompatibleSpeedLoaders;

		public HashSet<string> CompatibleBullets;

		public MagazineCacheEntry()
		{
			CompatibleMagazines = new HashSet<string>();
			CompatibleClips = new HashSet<string>();
			CompatibleSpeedLoaders = new HashSet<string>();
			CompatibleBullets = new HashSet<string>();
		}
	}
	public class AmmoObjectDataTemplate
	{
		public string ObjectID;

		public int Capacity;

		public FireArmMagazineType MagType;

		public FireArmRoundType RoundType;

		public AmmoObjectDataTemplate()
		{
		}

		public AmmoObjectDataTemplate(FVRFireArmMagazine mag)
		{
			//IL_0025: 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)
			//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)
			ObjectID = ((FVRPhysicalObject)mag).ObjectWrapper.ItemID;
			Capacity = mag.m_capacity;
			MagType = mag.MagazineType;
			RoundType = mag.RoundType;
		}

		public AmmoObjectDataTemplate(FVRFireArmClip clip)
		{
			//IL_0025: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			ObjectID = ((FVRPhysicalObject)clip).ObjectWrapper.ItemID;
			Capacity = clip.m_capacity;
			MagType = (FireArmMagazineType)0;
			RoundType = clip.RoundType;
		}

		public AmmoObjectDataTemplate(Speedloader speedloader)
		{
			//IL_002a: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			ObjectID = ((FVRPhysicalObject)speedloader).ObjectWrapper.ItemID;
			Capacity = speedloader.Chambers.Count;
			MagType = (FireArmMagazineType)0;
			RoundType = speedloader.Chambers[0].Type;
		}

		public AmmoObjectDataTemplate(FVRFireArmRound bullet)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			ObjectID = ((FVRPhysicalObject)bullet).ObjectWrapper.ItemID;
			Capacity = -1;
			MagType = (FireArmMagazineType)0;
			RoundType = bullet.RoundType;
		}
	}
	public class MagazineBlacklistEntry
	{
		public string FirearmID;

		public List<string> MagazineBlacklist = new List<string>();

		public List<string> MagazineWhitelist = new List<string>();

		public List<string> ClipBlacklist = new List<string>();

		public List<string> ClipWhitelist = new List<string>();

		public List<string> SpeedLoaderBlacklist = new List<string>();

		public List<string> SpeedLoaderWhitelist = new List<string>();

		public List<string> RoundBlacklist = new List<string>();

		public List<string> RoundWhitelist = new List<string>();

		public bool IsItemBlacklisted(string itemID)
		{
			if (!MagazineBlacklist.Contains(itemID) && !ClipBlacklist.Contains(itemID) && !RoundBlacklist.Contains(itemID))
			{
				return SpeedLoaderBlacklist.Contains(itemID);
			}
			return true;
		}

		public bool IsMagazineAllowed(string itemID)
		{
			if (MagazineWhitelist.Count > 0 && !MagazineWhitelist.Contains(itemID))
			{
				return false;
			}
			if (MagazineBlacklist.Contains(itemID))
			{
				return false;
			}
			return true;
		}

		public bool IsClipAllowed(string itemID)
		{
			if (ClipWhitelist.Count > 0 && !ClipWhitelist.Contains(itemID))
			{
				return false;
			}
			if (ClipBlacklist.Contains(itemID))
			{
				return false;
			}
			return true;
		}

		public bool IsSpeedloaderAllowed(string itemID)
		{
			if (SpeedLoaderWhitelist.Count > 0 && !SpeedLoaderWhitelist.Contains(itemID))
			{
				return false;
			}
			if (SpeedLoaderBlacklist.Contains(itemID))
			{
				return false;
			}
			return true;
		}

		public bool IsRoundAllowed(string itemID)
		{
			if (RoundWhitelist.Count > 0 && !RoundWhitelist.Contains(itemID))
			{
				return false;
			}
			if (RoundBlacklist.Contains(itemID))
			{
				return false;
			}
			return true;
		}
	}
	internal static class PatchLogger
	{
		public enum LogType
		{
			General,
			Debug
		}

		public static ManualLogSource BepLog;

		public static bool AllowLogging;

		public static bool LogDebug;

		public static void Init()
		{
			BepLog = Logger.CreateLogSource("MagazinePatcher");
		}

		public static void Log(string log, LogType type)
		{
			if (!AllowLogging)
			{
				return;
			}
			switch (type)
			{
			case LogType.General:
				BepLog.LogInfo((object)log);
				break;
			case LogType.Debug:
				if (LogDebug)
				{
					BepLog.LogInfo((object)log);
				}
				break;
			}
		}

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

		public static void LogError(string log)
		{
			BepLog.LogError((object)log);
		}
	}
	[BepInPlugin("h3vr.magazinepatcher", "MagazinePatcher", "0.3.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency("stratum", "1.1.0")]
	public class MagazinePatcher : StratumPlugin
	{
		private static ConfigEntry<bool> ResetBasicCacheOnNextStart;

		private static ConfigEntry<bool> ResetXLCacheOnNextStart;

		private static ConfigEntry<bool> DeleteCacheOnNextStart;

		private static ConfigEntry<bool> EnableLogging;

		private static ConfigEntry<bool> LogDebugInfo;

		private static string FullCachePath;

		private static string BlacklistPath;

		private static string BasicCachePath;

		private static string XLCachePath;

		private static string LastTouchedItem;

		private void Awake()
		{
			PatchLogger.Init();
			GetPaths();
			LoadConfigFile();
		}

		private void GetPaths()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			FullCachePath = Path.Combine(Path.Combine(Paths.CachePath, "MagazinePatcher"), "CachedCompatibleMags.json");
			PatchLogger.Log("Full cache path: " + FullCachePath, PatchLogger.LogType.Debug);
			BlacklistPath = Path.Combine(new PluginDirectories(new DirectoryInfo(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))).Data.FullName, "MagazineCacheBlacklist.json");
			PatchLogger.Log("Blacklist path: " + BlacklistPath, PatchLogger.LogType.Debug);
			string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "backup");
			BasicCachePath = Path.Combine(path, "CachedCompatibleMags-Basic.json");
			PatchLogger.Log("Backup cache path: " + BasicCachePath, PatchLogger.LogType.Debug);
			XLCachePath = Path.Combine(path, "CachedCompatibleMags-XL.json");
			PatchLogger.Log("Backup cache path: " + BasicCachePath, PatchLogger.LogType.Debug);
		}

		private void LoadConfigFile()
		{
			PatchLogger.Log("Getting config file", PatchLogger.LogType.General);
			ResetBasicCacheOnNextStart = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Reset to Basic Cache on Next Start", false, "If true, resets the cache from a basic starting cache on the next start of H3VR. MagazinePatcher will then cache any items that are missing from it. This setting will always be set back to false after startup.");
			ResetXLCacheOnNextStart = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Reset to XL Cache on Next Start", false, "Experimental. If true, resets the cache from the XL starting cache on the next start of H3VR. This is a large cache made from many available mods. This setting will always be set back to false after startup.");
			DeleteCacheOnNextStart = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Delete Cache on Next Start", false, "Nuclear option. If true, deletes the cache on the next start of H3VR. The cache will be built from scratch. This takes the most time and the most RAM to finish. This setting will always be set back to false after startup.");
			EnableLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableLogging", true, "Set to true to enable logging");
			LogDebugInfo = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogDebugInfo", false, "If true, logs extra debugging info");
			((BaseUnityPlugin)this).Config.SettingChanged += ConfigSettingChanged;
			PatchLogger.AllowLogging = EnableLogging.Value;
			PatchLogger.LogDebug = LogDebugInfo.Value;
		}

		private void ConfigSettingChanged(object sender, SettingChangedEventArgs e)
		{
			if (e.ChangedSetting == ResetBasicCacheOnNextStart)
			{
				if (ResetBasicCacheOnNextStart.Value)
				{
					ResetXLCacheOnNextStart.Value = false;
					DeleteCacheOnNextStart.Value = false;
				}
			}
			else if (e.ChangedSetting == ResetXLCacheOnNextStart)
			{
				if (ResetXLCacheOnNextStart.Value)
				{
					ResetBasicCacheOnNextStart.Value = false;
					DeleteCacheOnNextStart.Value = false;
				}
			}
			else if (e.ChangedSetting == DeleteCacheOnNextStart && DeleteCacheOnNextStart.Value)
			{
				ResetBasicCacheOnNextStart.Value = false;
				ResetXLCacheOnNextStart.Value = false;
			}
		}

		public override void OnSetup(IStageContext<Empty> ctx)
		{
		}

		public override IEnumerator OnRuntime(IStageContext<IEnumerator> ctx)
		{
			PatchLogger.Log("MagazinePatcher runtime has started!", PatchLogger.LogType.General);
			((MonoBehaviour)this).StartCoroutine(RunAndCatch(LoadMagazineCacheAsync(), delegate(Exception e)
			{
				PatcherStatus.AppendCacheLog("Something bad happened while caching item: " + LastTouchedItem);
				PatcherStatus.CachingFailed = true;
				PatchLogger.LogError("Something bad happened while caching item: " + LastTouchedItem);
				PatchLogger.LogError(e.ToString());
			}));
			yield break;
		}

		private static Dictionary<string, MagazineBlacklistEntry> GetMagazineCacheBlacklist()
		{
			try
			{
				if (string.IsNullOrEmpty(BlacklistPath) || !File.Exists(BlacklistPath))
				{
					PatchLogger.LogError("Failed to load magazine blacklist! Creating new one!");
					return CreateNewBlacklist();
				}
				string text = File.ReadAllText(BlacklistPath);
				if (string.IsNullOrEmpty(text))
				{
					return CreateNewBlacklist();
				}
				List<MagazineBlacklistEntry> list = JsonConvert.DeserializeObject<List<MagazineBlacklistEntry>>(text);
				Dictionary<string, MagazineBlacklistEntry> dictionary = new Dictionary<string, MagazineBlacklistEntry>();
				foreach (MagazineBlacklistEntry item in list)
				{
					dictionary.Add(item.FirearmID, item);
				}
				return dictionary;
			}
			catch (Exception ex)
			{
				PatchLogger.LogError("Failed to load magazine blacklist! Creating new one! Stack trace below:");
				PatchLogger.LogError(ex.ToString());
				return CreateNewBlacklist();
			}
		}

		private static Dictionary<string, MagazineBlacklistEntry> CreateNewBlacklist()
		{
			PatchLogger.Log("Blacklist does not exist! Building new one", PatchLogger.LogType.General);
			Dictionary<string, MagazineBlacklistEntry> dictionary = new Dictionary<string, MagazineBlacklistEntry>();
			StreamWriter streamWriter = File.CreateText(BlacklistPath);
			List<MagazineBlacklistEntry> list = new List<MagazineBlacklistEntry>();
			MagazineBlacklistEntry magazineBlacklistEntry = new MagazineBlacklistEntry
			{
				FirearmID = "SKSClassic"
			};
			magazineBlacklistEntry.MagazineWhitelist.Add("None");
			list.Add(magazineBlacklistEntry);
			string value = JsonConvert.SerializeObject((object)list, (Formatting)1);
			streamWriter.WriteLine(value);
			streamWriter.Close();
			foreach (MagazineBlacklistEntry item in list)
			{
				dictionary.Add(item.FirearmID, item);
			}
			return dictionary;
		}

		private static void PokeOtherLoader()
		{
			LoaderStatus.GetLoaderProgress();
		}

		private static float GetOtherLoaderProgress()
		{
			return LoaderStatus.GetLoaderProgress();
		}

		private static IEnumerator LoadMagazineCacheAsync()
		{
			PatchLogger.Log("Patching has started", PatchLogger.LogType.General);
			bool canCache = false;
			bool isOtherloaderLoaded = false;
			try
			{
				PokeOtherLoader();
				isOtherloaderLoaded = true;
				PatchLogger.Log("Otherloader detected!", PatchLogger.LogType.General);
			}
			catch
			{
				PatchLogger.Log("Otherloader not detected!", PatchLogger.LogType.General);
			}
			do
			{
				yield return null;
				if (isOtherloaderLoaded)
				{
					canCache = GetOtherLoaderProgress() >= 1f;
				}
			}
			while (!canCache && isOtherloaderLoaded);
			PatcherStatus.AppendCacheLog("Checking Cache");
			bool num = LoadFullCache();
			CompatibleMagazineCache.BlacklistEntries = GetMagazineCacheBlacklist();
			if (!num)
			{
				PatchLogger.Log($"[{DateTime.Now:HH:mm:ss}] Caching started!", PatchLogger.LogType.General);
				PatchLogger.Log("Building new magazine cache -- This may take a while!", PatchLogger.LogType.General);
				PatcherStatus.AppendCacheLog("Caching Started -- This may take a while!");
				List<FVRObject> list = ManagerSingleton<IM>.Instance.odicTagCategory[(ObjectCategory)2];
				List<FVRObject> clips = ManagerSingleton<IM>.Instance.odicTagCategory[(ObjectCategory)3];
				List<FVRObject> speedloaders = ManagerSingleton<IM>.Instance.odicTagCategory[(ObjectCategory)6];
				List<FVRObject> bullets = ManagerSingleton<IM>.Instance.odicTagCategory[(ObjectCategory)4];
				List<FVRObject> firearms = ManagerSingleton<IM>.Instance.odicTagCategory[(ObjectCategory)1];
				int totalObjects = list.Count + clips.Count + bullets.Count + speedloaders.Count + firearms.Count;
				int progress = 0;
				PatchLogger.Log("Loading all magazines", PatchLogger.LogType.General);
				PatcherStatus.AppendCacheLog("Caching Magazines");
				DateTime start = DateTime.Now;
				foreach (FVRObject magazine5 in list)
				{
					if ((DateTime.Now - start).TotalSeconds > 2.0)
					{
						start = DateTime.Now;
						PatchLogger.Log($"-- {(int)((float)progress / (float)totalObjects * 100f)}% --", PatchLogger.LogType.General);
					}
					PatcherStatus.UpdateProgress(Mathf.Min((float)progress / (float)totalObjects, 0.999f));
					progress++;
					LastTouchedItem = magazine5.ItemID;
					if (CompatibleMagazineCache.Instance.Magazines.Contains(magazine5.ItemID))
					{
						continue;
					}
					yield return ((AnvilAsset)magazine5).GetGameObjectAsync();
					if ((Object)(object)((AnvilAsset)magazine5).GetGameObject() == (Object)null)
					{
						PatchLogger.LogWarning("No object was found to use FVRObject! ItemID: " + magazine5.ItemID);
						continue;
					}
					FVRFireArmMagazine component = ((AnvilAsset)magazine5).GetGameObject().GetComponent<FVRFireArmMagazine>();
					if ((Object)(object)component != (Object)null)
					{
						if ((Object)(object)((FVRPhysicalObject)component).ObjectWrapper == (Object)null)
						{
							PatchLogger.LogWarning("Object was found to have no ObjectWrapper assigned! ItemID: " + magazine5.ItemID);
							continue;
						}
						CompatibleMagazineCache.Instance.AddMagazineData(component);
					}
					CompatibleMagazineCache.Instance.Magazines.Add(magazine5.ItemID);
				}
				PatchLogger.Log("Loading all clips", PatchLogger.LogType.General);
				PatcherStatus.AppendCacheLog("Caching Clips");
				foreach (FVRObject magazine5 in clips)
				{
					if ((DateTime.Now - start).TotalSeconds > 2.0)
					{
						start = DateTime.Now;
						PatchLogger.Log($"-- {(int)((float)progress / (float)totalObjects * 100f)}% --", PatchLogger.LogType.General);
					}
					PatcherStatus.UpdateProgress(Mathf.Min((float)progress / (float)totalObjects, 0.999f));
					progress++;
					LastTouchedItem = magazine5.ItemID;
					if (CompatibleMagazineCache.Instance.Clips.Contains(magazine5.ItemID))
					{
						continue;
					}
					yield return ((AnvilAsset)magazine5).GetGameObjectAsync();
					if ((Object)(object)((AnvilAsset)magazine5).GetGameObject() == (Object)null)
					{
						PatchLogger.LogWarning("No object was found to use FVRObject! ItemID: " + magazine5.ItemID);
						continue;
					}
					FVRFireArmClip component2 = ((AnvilAsset)magazine5).GetGameObject().GetComponent<FVRFireArmClip>();
					if ((Object)(object)component2 != (Object)null)
					{
						if ((Object)(object)((FVRPhysicalObject)component2).ObjectWrapper == (Object)null)
						{
							PatchLogger.LogWarning("Object was found to have no ObjectWrapper assigned! ItemID: " + magazine5.ItemID);
							continue;
						}
						CompatibleMagazineCache.Instance.AddClipData(component2);
					}
					CompatibleMagazineCache.Instance.Clips.Add(magazine5.ItemID);
				}
				PatchLogger.Log("Loading all speedloaders", PatchLogger.LogType.General);
				PatcherStatus.AppendCacheLog("Caching Speedloaders");
				foreach (FVRObject magazine5 in speedloaders)
				{
					if ((DateTime.Now - start).TotalSeconds > 2.0)
					{
						start = DateTime.Now;
						PatchLogger.Log($"-- {(int)((float)progress / (float)totalObjects * 100f)}% --", PatchLogger.LogType.General);
					}
					PatcherStatus.UpdateProgress(Mathf.Min((float)progress / (float)totalObjects, 0.999f));
					progress++;
					LastTouchedItem = magazine5.ItemID;
					if (CompatibleMagazineCache.Instance.SpeedLoaders.Contains(magazine5.ItemID))
					{
						continue;
					}
					yield return ((AnvilAsset)magazine5).GetGameObjectAsync();
					if ((Object)(object)((AnvilAsset)magazine5).GetGameObject() == (Object)null)
					{
						PatchLogger.LogWarning("No object was found to use FVRObject! ItemID: " + magazine5.ItemID);
						continue;
					}
					Speedloader component3 = ((AnvilAsset)magazine5).GetGameObject().GetComponent<Speedloader>();
					if ((Object)(object)component3 != (Object)null)
					{
						if ((Object)(object)((FVRPhysicalObject)component3).ObjectWrapper == (Object)null)
						{
							PatchLogger.LogWarning("Object was found to have no ObjectWrapper assigned! ItemID: " + magazine5.ItemID);
							continue;
						}
						CompatibleMagazineCache.Instance.AddSpeedLoaderData(component3);
					}
					CompatibleMagazineCache.Instance.SpeedLoaders.Add(magazine5.ItemID);
				}
				PatchLogger.Log("Loading all bullets", PatchLogger.LogType.General);
				PatcherStatus.AppendCacheLog("Caching Bullets");
				foreach (FVRObject magazine5 in bullets)
				{
					if ((DateTime.Now - start).TotalSeconds > 2.0)
					{
						start = DateTime.Now;
						PatchLogger.Log($"-- {(int)((float)progress / (float)totalObjects * 100f)}% --", PatchLogger.LogType.General);
					}
					PatcherStatus.UpdateProgress(Mathf.Min((float)progress / (float)totalObjects, 0.999f));
					progress++;
					LastTouchedItem = magazine5.ItemID;
					if (CompatibleMagazineCache.Instance.Bullets.Contains(magazine5.ItemID))
					{
						continue;
					}
					yield return ((AnvilAsset)magazine5).GetGameObjectAsync();
					if ((Object)(object)((AnvilAsset)magazine5).GetGameObject() == (Object)null)
					{
						PatchLogger.LogWarning("No object was found to use FVRObject! ItemID: " + magazine5.ItemID);
						continue;
					}
					FVRFireArmRound component4 = ((AnvilAsset)magazine5).GetGameObject().GetComponent<FVRFireArmRound>();
					if ((Object)(object)component4 != (Object)null)
					{
						if ((Object)(object)((FVRPhysicalObject)component4).ObjectWrapper == (Object)null)
						{
							PatchLogger.LogWarning("Object was found to have no ObjectWrapper assigned! ItemID: " + magazine5.ItemID);
							continue;
						}
						CompatibleMagazineCache.Instance.AddBulletData(component4);
					}
					CompatibleMagazineCache.Instance.Bullets.Add(magazine5.ItemID);
				}
				PatchLogger.Log("Loading all firearms", PatchLogger.LogType.General);
				PatcherStatus.AppendCacheLog("Caching Firearms");
				List<string> skipList = new List<string>();
				foreach (FVRObject magazine5 in firearms)
				{
					if ((DateTime.Now - start).TotalSeconds > 2.0)
					{
						start = DateTime.Now;
						PatchLogger.Log($"-- {(int)((float)progress / (float)totalObjects * 100f)}% --", PatchLogger.LogType.General);
					}
					PatcherStatus.UpdateProgress(Mathf.Min((float)progress / (float)totalObjects, 0.999f));
					progress++;
					LastTouchedItem = magazine5.ItemID;
					if (!magazine5.IsModContent && (int)magazine5.TagFirearmAction == 8 && magazine5.TagFirearmFeedOption.Contains((OTagFirearmFeedOption)1))
					{
						skipList.Add(magazine5.ItemID);
					}
					if (CompatibleMagazineCache.Instance.Firearms.Contains(magazine5.ItemID))
					{
						continue;
					}
					if (!IM.OD.ContainsKey(magazine5.ItemID))
					{
						PatchLogger.LogWarning("Item not found in Object Dictionary! ItemID: " + magazine5.ItemID);
						continue;
					}
					yield return ((AnvilAsset)magazine5).GetGameObjectAsync();
					if ((Object)(object)((AnvilAsset)magazine5).GetGameObject() == (Object)null)
					{
						PatchLogger.LogWarning("No object was found to use FVRObject! ItemID: " + magazine5.ItemID);
						continue;
					}
					FVRFireArm component5 = ((AnvilAsset)magazine5).GetGameObject().GetComponent<FVRFireArm>();
					if ((Object)(object)component5 != (Object)null)
					{
						if ((Object)(object)((FVRPhysicalObject)component5).ObjectWrapper == (Object)null)
						{
							PatchLogger.LogWarning("Object was found to have no ObjectWrapper assigned! ItemID: " + magazine5.ItemID);
							continue;
						}
						if (!ValidFireArm(component5.RoundType, component5.ClipType, component5.MagazineType, magazine5.MagazineCapacity))
						{
							PatchLogger.Log("Firearm " + magazine5.DisplayName + " skipped!", PatchLogger.LogType.Debug);
							continue;
						}
						MagazineCacheEntry magazineCacheEntry = new MagazineCacheEntry
						{
							FirearmID = magazine5.ItemID,
							MagType = component5.MagazineType,
							ClipType = component5.ClipType,
							BulletType = component5.RoundType
						};
						Revolver component6 = ((Component)component5).gameObject.GetComponent<Revolver>();
						if ((Object)(object)component6 != (Object)null)
						{
							magazineCacheEntry.DoesUseSpeedloader = true;
							IM.OD[magazineCacheEntry.FirearmID].MagazineCapacity = component6.Chambers.Length;
						}
						CompatibleMagazineCache.Instance.Entries.Add(magazine5.ItemID, magazineCacheEntry);
					}
					CompatibleMagazineCache.Instance.Firearms.Add(magazine5.ItemID);
				}
				PatchLogger.Log("Building Cache Entries", PatchLogger.LogType.General);
				PatcherStatus.AppendCacheLog("Building Cache");
				foreach (MagazineCacheEntry value2 in CompatibleMagazineCache.Instance.Entries.Values)
				{
					if (!IM.OD.ContainsKey(value2.FirearmID) || skipList.Contains(value2.FirearmID))
					{
						continue;
					}
					LastTouchedItem = value2.FirearmID;
					if (CompatibleMagazineCache.Instance.MagazineData.ContainsKey(value2.MagType))
					{
						foreach (AmmoObjectDataTemplate item in CompatibleMagazineCache.Instance.MagazineData[value2.MagType])
						{
							value2.CompatibleMagazines.Add(item.ObjectID);
						}
					}
					if (CompatibleMagazineCache.Instance.ClipData.ContainsKey(value2.ClipType))
					{
						foreach (AmmoObjectDataTemplate item2 in CompatibleMagazineCache.Instance.ClipData[value2.ClipType])
						{
							value2.CompatibleClips.Add(item2.ObjectID);
						}
					}
					if (value2.DoesUseSpeedloader && CompatibleMagazineCache.Instance.SpeedLoaderData.ContainsKey(value2.BulletType))
					{
						foreach (AmmoObjectDataTemplate item3 in CompatibleMagazineCache.Instance.SpeedLoaderData[value2.BulletType])
						{
							if (IM.OD[value2.FirearmID].MagazineCapacity == item3.Capacity)
							{
								value2.CompatibleSpeedLoaders.Add(item3.ObjectID);
							}
						}
					}
					if (!CompatibleMagazineCache.Instance.BulletData.ContainsKey(value2.BulletType))
					{
						continue;
					}
					foreach (AmmoObjectDataTemplate item4 in CompatibleMagazineCache.Instance.BulletData[value2.BulletType])
					{
						value2.CompatibleBullets.Add(item4.ObjectID);
					}
				}
				PatchLogger.Log("Saving Data", PatchLogger.LogType.General);
				PatcherStatus.AppendCacheLog("Saving");
				using StreamWriter streamWriter = File.CreateText(FullCachePath);
				string value = JsonConvert.SerializeObject((object)CompatibleMagazineCache.Instance, (Formatting)1);
				streamWriter.WriteLine(value);
				streamWriter.Close();
				PatchLogger.Log($"[{DateTime.Now:HH:mm:ss}] Caching finished!", PatchLogger.LogType.General);
			}
			PatchLogger.Log("Applying magazine cache to firearms", PatchLogger.LogType.General);
			ApplyMagazineCache(CompatibleMagazineCache.Instance);
			RemoveBlacklistedMagazines(CompatibleMagazineCache.BlacklistEntries);
			PatcherStatus.UpdateProgress(1f);
		}

		private static bool CheckBackupCache()
		{
			bool value = ResetBasicCacheOnNextStart.Value;
			bool flag = !value && ResetXLCacheOnNextStart.Value;
			bool num = !value && !flag && DeleteCacheOnNextStart.Value;
			ResetBasicCacheOnNextStart.Value = false;
			ResetXLCacheOnNextStart.Value = false;
			DeleteCacheOnNextStart.Value = false;
			if (num)
			{
				PatchLogger.Log("Deleted cache and starting from scratch!", PatchLogger.LogType.General);
				if (File.Exists(FullCachePath))
				{
					File.Delete(FullCachePath);
				}
				return true;
			}
			string text = (flag ? XLCachePath : BasicCachePath);
			if (!File.Exists(text))
			{
				PatchLogger.Log("Starting cache is missing: " + text + "!", PatchLogger.LogType.General);
				return false;
			}
			if (!File.Exists(FullCachePath) || value || flag)
			{
				File.Copy(text, FullCachePath, overwrite: true);
				PatchLogger.Log("Starting cache restored from " + text + "!", PatchLogger.LogType.General);
				return true;
			}
			return false;
		}

		private static bool LoadFullCache()
		{
			bool result = false;
			CheckBackupCache();
			if (!string.IsNullOrEmpty(FullCachePath) && File.Exists(FullCachePath))
			{
				try
				{
					CompatibleMagazineCache.Instance = JsonConvert.DeserializeObject<CompatibleMagazineCache>(File.ReadAllText(FullCachePath));
					result = IsMagazineCacheValid(CompatibleMagazineCache.Instance);
					PatchLogger.Log("Cache file found! Is Valid? " + result, PatchLogger.LogType.General);
				}
				catch (Exception ex)
				{
					CompatibleMagazineCache.Instance = new CompatibleMagazineCache();
					PatchLogger.LogError("Failed to read cache file!");
					PatchLogger.LogError(ex.ToString());
					File.Delete(FullCachePath);
				}
			}
			else
			{
				PatchLogger.Log("Cache file not found! Creating new cache file", PatchLogger.LogType.General);
				CompatibleMagazineCache.Instance = new CompatibleMagazineCache();
			}
			return result;
		}

		public static bool ValidFireArm(FireArmRoundType roundType, FireArmClipType clipType, FireArmMagazineType magazineType, int magazineCapacity)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			if ((int)roundType == 0 && (int)magazineType == 0 && magazineCapacity == 0)
			{
				return (int)clipType > 0;
			}
			return true;
		}

		private static void ApplyMagazineCache(CompatibleMagazineCache magazineCache)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<FireArmMagazineType, List<AmmoObjectDataTemplate>> magazineDatum in CompatibleMagazineCache.Instance.MagazineData)
			{
				if (!IM.CompatMags.ContainsKey(magazineDatum.Key))
				{
					IM.CompatMags.Add(magazineDatum.Key, new List<FVRObject>());
				}
				List<FVRObject> list = new List<FVRObject>();
				foreach (AmmoObjectDataTemplate item in magazineDatum.Value)
				{
					if (IM.OD.ContainsKey(item.ObjectID))
					{
						FVRObject val = IM.OD[item.ObjectID];
						val.MagazineType = magazineDatum.Key;
						val.RoundType = item.RoundType;
						val.MagazineCapacity = item.Capacity;
						list.Add(val);
					}
				}
				IM.CompatMags[magazineDatum.Key] = list;
			}
			foreach (MagazineCacheEntry value in magazineCache.Entries.Values)
			{
				if (!IM.OD.ContainsKey(value.FirearmID))
				{
					continue;
				}
				FVRObject val2 = IM.OD[value.FirearmID];
				if (IM.CompatMags.ContainsKey(value.MagType))
				{
					val2.MagazineType = value.MagType;
				}
				val2.RoundType = value.BulletType;
				val2.ClipType = value.ClipType;
				LastTouchedItem = value.FirearmID;
				int num = -1;
				int num2 = -1;
				foreach (string mag in value.CompatibleMagazines)
				{
					if (IM.OD.ContainsKey(mag) && !val2.CompatibleMagazines.Any((FVRObject o) => (Object)(object)o != (Object)null && o.ItemID == mag))
					{
						FVRObject val3 = IM.OD[mag];
						val2.CompatibleMagazines.Add(val3);
						if (magazineCache.AmmoObjects.ContainsKey(mag))
						{
							val3.MagazineCapacity = magazineCache.AmmoObjects[mag].Capacity;
						}
						if (num < val3.MagazineCapacity)
						{
							num = val3.MagazineCapacity;
						}
						if (num2 == -1)
						{
							num2 = val3.MagazineCapacity;
						}
						else if (num2 > val3.MagazineCapacity)
						{
							num2 = val3.MagazineCapacity;
						}
					}
				}
				foreach (string clip in value.CompatibleClips)
				{
					if (IM.OD.ContainsKey(clip) && !val2.CompatibleClips.Any((FVRObject o) => (Object)(object)o != (Object)null && o.ItemID == clip))
					{
						FVRObject val4 = IM.OD[clip];
						val2.CompatibleClips.Add(val4);
						if (magazineCache.AmmoObjects.ContainsKey(clip))
						{
							val4.MagazineCapacity = magazineCache.AmmoObjects[clip].Capacity;
						}
						if (num < val4.MagazineCapacity)
						{
							num = val4.MagazineCapacity;
						}
						if (num2 == -1)
						{
							num2 = val4.MagazineCapacity;
						}
						else if (num2 > val4.MagazineCapacity)
						{
							num2 = val4.MagazineCapacity;
						}
					}
				}
				foreach (string speedloader in value.CompatibleSpeedLoaders)
				{
					if (IM.OD.ContainsKey(speedloader) && !val2.CompatibleSpeedLoaders.Any((FVRObject o) => (Object)(object)o != (Object)null && o.ItemID == speedloader))
					{
						FVRObject val5 = IM.OD[speedloader];
						val2.CompatibleSpeedLoaders.Add(val5);
						if (magazineCache.AmmoObjects.ContainsKey(speedloader))
						{
							val5.MagazineCapacity = magazineCache.AmmoObjects[speedloader].Capacity;
						}
						if (num < val5.MagazineCapacity)
						{
							num = val5.MagazineCapacity;
						}
						if (num2 == -1)
						{
							num2 = val5.MagazineCapacity;
						}
						else if (num2 > val5.MagazineCapacity)
						{
							num2 = val5.MagazineCapacity;
						}
					}
				}
				foreach (string bullet in value.CompatibleBullets)
				{
					if (IM.OD.ContainsKey(bullet) && !val2.CompatibleSingleRounds.Any((FVRObject o) => (Object)(object)o != (Object)null && o.ItemID == bullet))
					{
						val2.CompatibleSingleRounds.Add(IM.OD[bullet]);
					}
				}
				if (num != -1)
				{
					val2.MaxCapacityRelated = num;
				}
				if (num2 != -1)
				{
					val2.MinCapacityRelated = num2;
				}
			}
		}

		private static void RemoveBlacklistedMagazines(Dictionary<string, MagazineBlacklistEntry> blacklist)
		{
			foreach (FVRObject item in ManagerSingleton<IM>.Instance.odicTagCategory[(ObjectCategory)1])
			{
				if (!blacklist.ContainsKey(item.ItemID))
				{
					continue;
				}
				for (int num = item.CompatibleMagazines.Count - 1; num >= 0; num--)
				{
					if (!blacklist[item.ItemID].IsMagazineAllowed(item.CompatibleMagazines[num].ItemID))
					{
						item.CompatibleMagazines.RemoveAt(num);
					}
				}
				for (int num2 = item.CompatibleClips.Count - 1; num2 >= 0; num2--)
				{
					if (!blacklist[item.ItemID].IsClipAllowed(item.CompatibleClips[num2].ItemID))
					{
						item.CompatibleClips.RemoveAt(num2);
					}
				}
				for (int num3 = item.CompatibleSingleRounds.Count - 1; num3 >= 0; num3--)
				{
					if (!blacklist[item.ItemID].IsRoundAllowed(item.CompatibleSingleRounds[num3].ItemID))
					{
						item.CompatibleSingleRounds.RemoveAt(num3);
					}
				}
				for (int num4 = item.CompatibleSpeedLoaders.Count - 1; num4 >= 0; num4--)
				{
					if (!blacklist[item.ItemID].IsSpeedloaderAllowed(item.CompatibleSpeedLoaders[num4].ItemID))
					{
						item.CompatibleSpeedLoaders.RemoveAt(num4);
					}
				}
			}
		}

		private static bool IsMagazineCacheValid(CompatibleMagazineCache magazineCache)
		{
			bool result = true;
			foreach (string item in ManagerSingleton<IM>.Instance.odicTagCategory[(ObjectCategory)2].Select((FVRObject f) => f.ItemID))
			{
				if (!magazineCache.Magazines.Contains(item))
				{
					PatchLogger.LogWarning("Magazine not found in cache: " + item);
					result = false;
				}
			}
			foreach (string item2 in ManagerSingleton<IM>.Instance.odicTagCategory[(ObjectCategory)1].Select((FVRObject f) => f.ItemID))
			{
				if (!magazineCache.Firearms.Contains(item2))
				{
					PatchLogger.LogWarning("Firearm not found in cache: " + item2);
					result = false;
				}
			}
			foreach (string item3 in ManagerSingleton<IM>.Instance.odicTagCategory[(ObjectCategory)3].Select((FVRObject f) => f.ItemID))
			{
				if (!magazineCache.Clips.Contains(item3))
				{
					PatchLogger.LogWarning("Clip not found in cache: " + item3);
					result = false;
				}
			}
			foreach (string item4 in ManagerSingleton<IM>.Instance.odicTagCategory[(ObjectCategory)4].Select((FVRObject f) => f.ItemID))
			{
				if (!magazineCache.Bullets.Contains(item4))
				{
					PatchLogger.LogWarning("Bullet not found in cache: " + item4);
					result = false;
				}
			}
			return result;
		}

		public static IEnumerator RunAndCatch(IEnumerator routine, Action<Exception> onError = null)
		{
			bool more = true;
			while (more)
			{
				try
				{
					more = routine.MoveNext();
				}
				catch (Exception obj)
				{
					onError?.Invoke(obj);
					break;
				}
				if (more)
				{
					yield return routine.Current;
				}
			}
		}
	}
	public static class PatcherStatus
	{
		public static string CacheLog = "";

		private static float patcherProgress = 0f;

		public static bool CachingFailed = false;

		private static List<string> CacheLogList = new List<string>();

		public static float PatcherProgress => patcherProgress;

		public static void UpdateProgress(float progress)
		{
			patcherProgress = progress;
		}

		public static void AppendCacheLog(string log)
		{
			CacheLogList.Add(log);
			if (CacheLogList.Count > 6)
			{
				CacheLogList.RemoveAt(0);
			}
			CacheLog = string.Join("\n", CacheLogList.ToArray());
		}
	}
}