Decompiled source of SideloaderMint v1.5.0

Sirdoggy.SideloaderMint.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using FistVR;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using ModularWorkshop;
using Sirdoggy.SideloaderMint.Addons;
using Sirdoggy.SideloaderMint.Addons.Data;
using Sirdoggy.SideloaderMint.Addons.Data.Model;
using Sirdoggy.SideloaderMint.AssetLoaders;
using Sirdoggy.SideloaderMint.AssetLoaders.Implementations;
using Sirdoggy.SideloaderMint.Common;
using Sirdoggy.SideloaderMint.Common.Coroutines;
using Sirdoggy.SideloaderMint.Common.Structures;
using Sirdoggy.SideloaderMint.Common.Validation;
using Sirdoggy.SideloaderMint.Model;
using Sirdoggy.SideloaderMint.Patchers;
using Sirdoggy.SideloaderMint.Patchers.Extensions;
using Sirdoggy.SideloaderMint.Patchers.Tags;
using UnityEngine;
using UnityEngine.SceneManagement;
using Valve.Newtonsoft.Json;
using Valve.Newtonsoft.Json.Linq;
using XUnity.ResourceRedirector;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("Sirdoggy")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Text-based asset replacer for H3VR")]
[assembly: AssemblyFileVersion("1.5.0.0")]
[assembly: AssemblyInformationalVersion("1.5.0")]
[assembly: AssemblyProduct("Sirdoggy.SideloaderMint")]
[assembly: AssemblyTitle("SideloaderMint")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.5.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[CompilerGenerated]
internal sealed class <>z__ReadOnlyArray<T> : IEnumerable, ICollection, IList, IEnumerable<T>, ICollection<T>, IList<T>
{
	int ICollection.Count => _items.Length;

	bool ICollection.IsSynchronized => false;

	object ICollection.SyncRoot => this;

	object IList.this[int index]
	{
		get
		{
			return _items[index];
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	bool IList.IsFixedSize => true;

	bool IList.IsReadOnly => true;

	int ICollection<T>.Count => _items.Length;

	bool ICollection<T>.IsReadOnly => true;

	T IList<T>.this[int index]
	{
		get
		{
			return _items[index];
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	public <>z__ReadOnlyArray(T[] items)
	{
		_items = items;
	}

	IEnumerator IEnumerable.GetEnumerator()
	{
		return ((IEnumerable)_items).GetEnumerator();
	}

	void ICollection.CopyTo(Array array, int index)
	{
		((ICollection)_items).CopyTo(array, index);
	}

	int IList.Add(object value)
	{
		throw new NotSupportedException();
	}

	void IList.Clear()
	{
		throw new NotSupportedException();
	}

	bool IList.Contains(object value)
	{
		return ((IList)_items).Contains(value);
	}

	int IList.IndexOf(object value)
	{
		return ((IList)_items).IndexOf(value);
	}

	void IList.Insert(int index, object value)
	{
		throw new NotSupportedException();
	}

	void IList.Remove(object value)
	{
		throw new NotSupportedException();
	}

	void IList.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}

	IEnumerator<T> IEnumerable<T>.GetEnumerator()
	{
		return ((IEnumerable<T>)_items).GetEnumerator();
	}

	void ICollection<T>.Add(T item)
	{
		throw new NotSupportedException();
	}

	void ICollection<T>.Clear()
	{
		throw new NotSupportedException();
	}

	bool ICollection<T>.Contains(T item)
	{
		return ((ICollection<T>)_items).Contains(item);
	}

	void ICollection<T>.CopyTo(T[] array, int arrayIndex)
	{
		((ICollection<T>)_items).CopyTo(array, arrayIndex);
	}

	bool ICollection<T>.Remove(T item)
	{
		throw new NotSupportedException();
	}

	int IList<T>.IndexOf(T item)
	{
		return ((IList<T>)_items).IndexOf(item);
	}

	void IList<T>.Insert(int index, T item)
	{
		throw new NotSupportedException();
	}

	void IList<T>.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}
}
[CompilerGenerated]
internal sealed class <>z__ReadOnlySingleElementList<T> : IEnumerable, ICollection, IList, IEnumerable<T>, ICollection<T>, IList<T>
{
	private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator<T>
	{
		object IEnumerator.Current => _item;

		T IEnumerator<T>.Current => _item;

		public Enumerator(T item)
		{
			_item = item;
		}

		bool IEnumerator.MoveNext()
		{
			if (!_moveNextCalled)
			{
				return _moveNextCalled = true;
			}
			return false;
		}

		void IEnumerator.Reset()
		{
			_moveNextCalled = false;
		}

		void IDisposable.Dispose()
		{
		}
	}

	int ICollection.Count => 1;

	bool ICollection.IsSynchronized => false;

	object ICollection.SyncRoot => this;

	object IList.this[int index]
	{
		get
		{
			if (index != 0)
			{
				throw new IndexOutOfRangeException();
			}
			return _item;
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	bool IList.IsFixedSize => true;

	bool IList.IsReadOnly => true;

	int ICollection<T>.Count => 1;

	bool ICollection<T>.IsReadOnly => true;

	T IList<T>.this[int index]
	{
		get
		{
			if (index != 0)
			{
				throw new IndexOutOfRangeException();
			}
			return _item;
		}
		set
		{
			throw new NotSupportedException();
		}
	}

	public <>z__ReadOnlySingleElementList(T item)
	{
		_item = item;
	}

	IEnumerator IEnumerable.GetEnumerator()
	{
		return new Enumerator(_item);
	}

	void ICollection.CopyTo(Array array, int index)
	{
		array.SetValue(_item, index);
	}

	int IList.Add(object value)
	{
		throw new NotSupportedException();
	}

	void IList.Clear()
	{
		throw new NotSupportedException();
	}

	bool IList.Contains(object value)
	{
		return EqualityComparer<T>.Default.Equals(_item, (T)value);
	}

	int IList.IndexOf(object value)
	{
		if (!EqualityComparer<T>.Default.Equals(_item, (T)value))
		{
			return -1;
		}
		return 0;
	}

	void IList.Insert(int index, object value)
	{
		throw new NotSupportedException();
	}

	void IList.Remove(object value)
	{
		throw new NotSupportedException();
	}

	void IList.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}

	IEnumerator<T> IEnumerable<T>.GetEnumerator()
	{
		return new Enumerator(_item);
	}

	void ICollection<T>.Add(T item)
	{
		throw new NotSupportedException();
	}

	void ICollection<T>.Clear()
	{
		throw new NotSupportedException();
	}

	bool ICollection<T>.Contains(T item)
	{
		return EqualityComparer<T>.Default.Equals(_item, item);
	}

	void ICollection<T>.CopyTo(T[] array, int arrayIndex)
	{
		array[arrayIndex] = _item;
	}

	bool ICollection<T>.Remove(T item)
	{
		throw new NotSupportedException();
	}

	int IList<T>.IndexOf(T item)
	{
		if (!EqualityComparer<T>.Default.Equals(_item, item))
		{
			return -1;
		}
		return 0;
	}

	void IList<T>.Insert(int index, T item)
	{
		throw new NotSupportedException();
	}

	void IList<T>.RemoveAt(int index)
	{
		throw new NotSupportedException();
	}
}
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[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;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class ExtensionMarkerAttribute : Attribute
	{
		private readonly string <Name>k__BackingField;

		public string Name => <Name>k__BackingField;

		public ExtensionMarkerAttribute(string name)
		{
			<Name>k__BackingField = name;
		}
	}
}
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string id = null, string name = null, string version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string id = null, string name = null, string version = null)
		{
		}
	}
}
namespace Sirdoggy.SideloaderMint
{
	internal static class Constants
	{
		public const char AssetSegmentDelimiter = ':';

		public const char AddonDirectoryNameSegmentDelimiter = '-';

		public const string ManifestFileName = "manifest.json";

		public const string AddonFolderName = "SideloaderMint";

		public const int HarmonyPriority = 300;

		public static string PluginDirectory => Path.Combine(Paths.PluginPath, "Sirdoggy.SideloaderMint".Replace('.', '-'));
	}
	internal static class MainLoader
	{
		private class ResolvedAddonDirectory
		{
			public enum Type
			{
				LegacyDirectoryAddon,
				PluginsAddon,
				PluginsSubAddon
			}

			public string FileAccessBoundaryPath { get; }

			public string AddonFullPath { get; }

			public Type AddonType { get; }

			public string? InvalidDirectoryNameError { get; }

			public ResolvedAddonDirectory(string fileAccessBoundaryPath, string addonFullPath, Type addonType, string? invalidDirectoryNameError)
			{
				FileAccessBoundaryPath = fileAccessBoundaryPath;
				AddonFullPath = addonFullPath;
				AddonType = addonType;
				InvalidDirectoryNameError = invalidDirectoryNameError;
				base..ctor();
			}

			public override string ToString()
			{
				return StringUtils.FormatTypeProperties("ResolvedAddonDirectory", new <>z__ReadOnlyArray<string>(new string[3]
				{
					"AddonFullPath: " + AddonFullPath,
					string.Format("{0}: {1}", "AddonType", AddonType),
					"InvalidDirectoryNameError: " + InvalidDirectoryNameError
				}));
			}
		}

		[SpecialName]
		public sealed class <G>$75E6429709F2538C8DBED7BDB4D59AC5
		{
			[SpecialName]
			public static class <M>$2D6E795AA6D0AF6F09DB47CF4AC4FB04
			{
			}

			[ExtensionMarker("<M>$2D6E795AA6D0AF6F09DB47CF4AC4FB04")]
			private void AddAddonsFromLegacyDirectory()
			{
				throw new NotSupportedException();
			}

			[ExtensionMarker("<M>$2D6E795AA6D0AF6F09DB47CF4AC4FB04")]
			private void AddAddonsFromPluginDirectories()
			{
				throw new NotSupportedException();
			}
		}

		public static int TargetConflictsDuringLoadCount;

		public static readonly MaterialLoader MaterialLoader = new MaterialLoader();

		public static readonly MeshLoader MeshLoader = new MeshLoader();

		public static readonly TextureLoader TextureLoader = new TextureLoader();

		private static readonly GunSoundLoader GunSoundLoader = new GunSoundLoader();

		private static readonly GunAudioSetLoader GunAudioSetLoader = new GunAudioSetLoader();

		private static readonly AudioClipLoader AudioClipLoader = new AudioClipLoader();

		private static readonly string LegacyAddonsPath = Path.Combine(Paths.BepInExRootPath, "SideloaderMint");

		private static readonly IAssetLoader[] AllAssetLoaders = new IAssetLoader[7]
		{
			AudioClipLoader,
			GunSoundLoader,
			GunAudioSetLoader,
			MaterialLoader,
			MeshLoader,
			new PrefabLoader(),
			TextureLoader
		};

		public static void ReloadAddons()
		{
			TargetConflictsDuringLoadCount = 0;
			IAssetLoader[] allAssetLoaders = AllAssetLoaders;
			for (int i = 0; i < allAssetLoaders.Length; i++)
			{
				allAssetLoaders[i].Clear();
			}
			InitializeAssetLoadersAndLoadAddons();
		}

		public static void InitializeAssetLoadersAndLoadAddons()
		{
			FVRFireArmPatcher.Initialize(GunSoundLoader, GunAudioSetLoader);
			AudioSourcePatcher.Initialize(AudioClipLoader);
			Plugin.Log.LogMessage((object)"Loading addons...");
			List<ResolvedAddonDirectory> list = new List<ResolvedAddonDirectory>();
			list.AddAddonsFromLegacyDirectory();
			list.AddAddonsFromPluginDirectories();
			Dictionary<string, Addon> dictionary = new Dictionary<string, Addon>();
			int num = 0;
			int num2 = 0;
			foreach (ResolvedAddonDirectory item in list)
			{
				try
				{
					Addon addon2 = new Addon(item.AddonFullPath, item.FileAccessBoundaryPath);
					if (item.InvalidDirectoryNameError != null)
					{
						Plugin.Log.LogError((object)("Failed to load addon '" + addon2.GUID + "'. " + item.InvalidDirectoryNameError));
						num2++;
						continue;
					}
					Plugin.PluginConfig.BindConfigForAddon(addon2);
					if (!addon2.Enabled)
					{
						Plugin.Log.LogInfo((object)("Skipped addon '" + addon2.GUID + "' because it's disabled."));
						num++;
					}
					else if (dictionary.ContainsKey(addon2.GUID))
					{
						Plugin.Log.LogError((object)("Failed to load addon '" + addon2.GUID + "' because an addon with the same GUID was already loaded!"));
					}
					else
					{
						Plugin.Log.LogInfo((object)("Loaded addon '" + addon2.GUID + "'"));
						dictionary.Add(addon2.GUID, addon2);
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("Failed to load addon from path: " + item.AddonFullPath + "\n- Message: " + ex.Message));
				}
			}
			StringBuilder stringBuilder = new StringBuilder().Append($"Loaded {dictionary.Count}/{list.Count} addons.");
			if (num > 0)
			{
				stringBuilder.Append($" {num} addons were skipped because they're set as disabled in their manifest.");
			}
			if (num2 > 0)
			{
				stringBuilder.Append($" {num2} addons were skipped because they have incorrect directory names.");
			}
			Plugin.Log.LogInfo((object)stringBuilder.ToString());
			if (Plugin.PluginConfig.ClearUninstalledAddons)
			{
				Plugin.Log.LogMessage((object)"Clearing uninstalled addons from config file.");
				Plugin.PluginConfig.ClearUninstalledAddonsConfigEntries();
			}
			try
			{
				List<Addon> addons = dictionary.Values.OrderByDescending((Addon addon) => addon.Priority).ToList();
				IAssetLoader[] allAssetLoaders = AllAssetLoaders;
				foreach (IAssetLoader assetLoader in allAssetLoaders)
				{
					Plugin.Log.LogMessage((object)$"Initializing '{assetLoader}'...)'");
					assetLoader.Initialize(addons);
				}
				StringBuilder stringBuilder2 = new StringBuilder().Append("Asset loaders initialized successfully!");
				if (TargetConflictsDuringLoadCount > 0)
				{
					stringBuilder2.Append($" Resolved {TargetConflictsDuringLoadCount} conflicts based on addon" + " priorities in config file.");
				}
				Plugin.Log.LogInfo((object)stringBuilder2.ToString());
			}
			catch (Exception arg)
			{
				Plugin.Log.LogFatal((object)("An exception has occured while initializing asset loaders, some of your installed addons will likely not work!" + $"\n- Exception: {arg}"));
			}
		}

		private static void AddAddonsFromLegacyDirectory(this List<ResolvedAddonDirectory> output)
		{
			if (!Directory.Exists(LegacyAddonsPath))
			{
				return;
			}
			string[] directories = Directory.GetDirectories(LegacyAddonsPath, "*", SearchOption.TopDirectoryOnly);
			foreach (string text in directories)
			{
				if (File.Exists(Path.Combine(text, "manifest.json")))
				{
					string invalidDirectoryNameError = IsAddonDirectoryNameValid(text);
					ResolvedAddonDirectory item = new ResolvedAddonDirectory(LegacyAddonsPath, text, ResolvedAddonDirectory.Type.LegacyDirectoryAddon, invalidDirectoryNameError);
					output.Add(item);
				}
			}
		}

		private static void AddAddonsFromPluginDirectories(this List<ResolvedAddonDirectory> output)
		{
			string[] directories = Directory.GetDirectories(Paths.PluginPath, "*", SearchOption.TopDirectoryOnly);
			foreach (string text in directories)
			{
				string text2 = Path.Combine(text, "SideloaderMint");
				if (!Directory.Exists(text2))
				{
					continue;
				}
				if (File.Exists(Path.Combine(text2, "manifest.json")))
				{
					string addonFullPath = text2;
					ResolvedAddonDirectory item = new ResolvedAddonDirectory(text, addonFullPath, ResolvedAddonDirectory.Type.PluginsAddon, null);
					output.Add(item);
					continue;
				}
				string[] directories2 = Directory.GetDirectories(text2, "*", SearchOption.TopDirectoryOnly);
				foreach (string text3 in directories2)
				{
					if (File.Exists(Path.Combine(text3, "manifest.json")))
					{
						string invalidDirectoryNameError = IsAddonDirectoryNameValid(text3);
						ResolvedAddonDirectory item2 = new ResolvedAddonDirectory(text, text3, ResolvedAddonDirectory.Type.PluginsSubAddon, invalidDirectoryNameError);
						output.Add(item2);
					}
				}
			}
		}

		private static string? IsAddonDirectoryNameValid(string directoryPath)
		{
			string name = new DirectoryInfo(directoryPath).Name;
			if (!SubAddonNameValidator.IsValid(name))
			{
				return "Directory name '" + name + "' contains invalid characters. Allowed characters are: a-z A-Z 0-9 _ . , ( )";
			}
			return null;
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInProcess("h3vr.exe")]
	[BepInPlugin("Sirdoggy.SideloaderMint", "SideloaderMint", "1.5.0")]
	public class Plugin : BaseUnityPlugin
	{
		private const string ModularWorkshopPluginID = "h3vr.cityrobo.ModularWorkshopManager";

		private const string OldSideloaderPluginID = "horse.coder.h3vr.sideloader";

		internal static ManualLogSource Log = null;

		internal static PluginConfig PluginConfig = new PluginConfig();

		internal static ExceptionCatcher ExceptionCatcher = null;

		private static bool _isFinishedLoading;

		private static SharedAssetInfo _sharedAssetInfo = SharedAssetInfo.SharedAllowNew;

		public const string Id = "Sirdoggy.SideloaderMint";

		public static string Name => "SideloaderMint";

		public static string Version => "1.5.0";

		internal static void LogVerbose(string message)
		{
			if (PluginConfig.VerboseDebugLogsEnabled)
			{
				Log.LogDebug((object)message);
			}
		}

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			ExceptionCatcher = new ExceptionCatcher(Log);
			ResourceRedirection.EnableSyncOverAsyncAssetLoads();
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(AudioSourcePatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(FVRFireArmPatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(FVRFireArmMagazinePatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(ClosedBoltHandlePatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(ClosedBoltPatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(HandgunSlidePatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(TubeFedShotgunBoltPatcher), (string)null);
			});
			ExceptionCatcher.Run(delegate
			{
				Harmony.CreateAndPatchAll(typeof(TubeFedShotgunHandlePatcher), (string)null);
			});
			if (Chainloader.PluginInfos != null)
			{
				if (Chainloader.PluginInfos.ContainsKey("h3vr.cityrobo.ModularWorkshopManager"))
				{
					Log.LogDebug((object)"ModularWorkshop is installed, patching...");
					ExceptionCatcher.Run(delegate
					{
						Harmony.CreateAndPatchAll(typeof(ModularBarrelExtensionPatcher), (string)null);
					});
				}
				else
				{
					Log.LogDebug((object)"ModularWorkshop is not installed.");
				}
				if (Chainloader.PluginInfos.ContainsKey("horse.coder.h3vr.sideloader"))
				{
					Log.LogDebug((object)"Old Sideloader is installed, patching...");
					ExceptionCatcher.Run(OldSideloaderPatcher.ApplyPatch);
				}
				else
				{
					Log.LogDebug((object)"Old Sideloader is not installed.");
				}
			}
			MainLoader.InitializeAssetLoadersAndLoadAddons();
			SceneManager.sceneLoaded += OnSceneLoaded;
			_isFinishedLoading = true;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			ReplaceAllSharedAssets();
		}

		private void ReplaceAllSharedAssets()
		{
			GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>();
			foreach (GameObject gameO in array)
			{
				MainLoader.MaterialLoader.ReplaceMaterials(gameO, "SharedAssets", _sharedAssetInfo);
				MainLoader.MeshLoader.ReplaceMeshes(gameO, "SharedAssets", _sharedAssetInfo);
				MainLoader.TextureLoader.ReplaceTextures(gameO, "SharedAssets", _sharedAssetInfo);
			}
			_sharedAssetInfo = SharedAssetInfo.SharedDoNotAllowNew;
		}

		private void Update()
		{
			if (Input.GetKey((KeyCode)306) && Input.GetKeyDown((KeyCode)114) && _isFinishedLoading && PluginConfig.EnableAddonReloading)
			{
				_isFinishedLoading = false;
				PluginConfig = new PluginConfig();
				MainLoader.ReloadAddons();
				ReplaceAllSharedAssets();
				_isFinishedLoading = true;
			}
			MainLoader.MaterialLoader.TryReplaceQueuedMaterials();
			MainLoader.MeshLoader.TryReplaceQueuedMeshes();
			MainLoader.TextureLoader.TryReplaceQueuedTextures();
		}
	}
	internal class PluginConfig
	{
		private const string ConfigFileName = "Sirdoggy.SideloaderMint.cfg";

		private readonly ConfigFileWrapper _configFile;

		public bool ClearUninstalledAddons { get; }

		public bool EnableAddonReloading { get; }

		public bool VerboseDebugLogsEnabled { get; }

		public PluginConfig()
		{
			_configFile = new ConfigFileWrapper("Sirdoggy.SideloaderMint.cfg");
			ClearUninstalledAddons = _configFile.BindBool(new ConfigFileWrapper.SimpleConfigEntry<bool>("General Settings", "Clear Uninstalled Addons", defaultValue: true, "If set to true, uninstalled addons will be removed from the config file upon launching the game."));
			EnableAddonReloading = _configFile.BindBool(new ConfigFileWrapper.SimpleConfigEntry<bool>("General Settings", "Enable Addon Reloading", defaultValue: true, "Allows you to reload all addons by pressing Ctrl + R. New assets might not load in until the scene is also reloaded."));
			VerboseDebugLogsEnabled = _configFile.BindBool(new ConfigFileWrapper.SimpleConfigEntry<bool>("Developer Settings", "VerboseDebugLogs", defaultValue: false, "Enables verbose debug logs. These will noticeably spam the console."));
		}

		public void BindConfigForAddon(Addon addon)
		{
			addon.Enabled = _configFile.BindBool(new ConfigFileWrapper.SimpleConfigEntry<bool>("Addons - Enabled addons", "Addon Enabled: " + addon.GUID, addon.Enabled));
			addon.Priority = _configFile.BindInt(new ConfigFileWrapper.SimpleConfigEntry<int>("Addons - Priorities of addons", "Addon Priority: " + addon.GUID, addon.Priority));
		}

		public void ClearUninstalledAddonsConfigEntries()
		{
			_configFile.ClearUntrackedEntries();
		}
	}
	public enum SharedAssetInfo
	{
		NotShared,
		SharedAllowNew,
		SharedDoNotAllowNew
	}
}
namespace Sirdoggy.SideloaderMint.Patchers
{
	[HarmonyWrapSafe]
	[HarmonyPatch(typeof(AudioSource))]
	internal static class AudioSourcePatcher
	{
		private static AudioClipLoader? _audioClipLoader;

		internal static void Initialize(AudioClipLoader audioClipLoader)
		{
			_audioClipLoader = audioClipLoader;
		}

		[HarmonyPrefix]
		[HarmonyPatch("Play", new Type[] { typeof(ulong) })]
		private static void PlayPrefix(AudioSource __instance)
		{
			AudioClip clip = __instance.clip;
			if (((clip != null) ? ((Object)clip).name : null) == null)
			{
				return;
			}
			Plugin.Log.LogDebug((object)$"Attempting to replace AudioClip '{__instance.clip}'");
			if (_audioClipLoader == null)
			{
				Plugin.Log.LogError((object)(string.Format("Did not replace AudioClip '{0}' because '{1}' ", __instance.clip, "AudioSourcePatcher") + "has not been initialized yet."));
				return;
			}
			if (!_audioClipLoader.AddonEntriesByTarget.TryGetValue(((Object)__instance.clip).name, out AudioClipLoader.AddonEntry value))
			{
				Plugin.LogVerbose($"Did not replace AudioClip '{__instance.clip}' because it has no " + "replacement sounds.");
				return;
			}
			try
			{
				int num = new Random().Next(value.ResourceReferences.Length);
				AddonManifest.AssetReference replacement = value.ResourceReferences[num];
				AudioClip val = value.Addon.LoadAudioClip(replacement);
				((Object)val).name = ((Object)__instance.clip).name;
				__instance.clip = val;
				float[] volumeRange = value.VolumeRange;
				float[] volumeMultiplierRange = value.VolumeMultiplierRange;
				float[] pitchRange = value.PitchRange;
				float[] pitchMultiplierRange = value.PitchMultiplierRange;
				if (volumeRange != null)
				{
					float volume = Random.Range(volumeRange[0], volumeRange[1]);
					__instance.volume = volume;
				}
				if (volumeMultiplierRange != null)
				{
					float num2 = Random.Range(volumeMultiplierRange[0], volumeMultiplierRange[1]);
					__instance.volume *= num2;
				}
				if (pitchRange != null)
				{
					float pitch = Random.Range(pitchRange[0], pitchRange[1]);
					__instance.pitch = pitch;
				}
				if (pitchMultiplierRange != null)
				{
					float num3 = Random.Range(pitchMultiplierRange[0], pitchMultiplierRange[1]);
					__instance.pitch *= num3;
				}
				Plugin.Log.LogDebug((object)$"Successfully replaced AudioClip '{__instance.clip}'");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)($"Failed to load AudioClip '{__instance.clip}' from mod '{value.Addon.GUID}'" + $"\n- Cause: {ex.GetType()}" + "\n- Message: " + ex.Message));
			}
		}
	}
	[HarmonyWrapSafe]
	[HarmonyPriority(300)]
	[HarmonyPatch(typeof(ClosedBoltHandle))]
	internal static class ClosedBoltHandlePatcher
	{
		private class UpdateHandleSharedState
		{
			public readonly bool BoltCanBeSlappedInPrefix;

			public UpdateHandleSharedState(bool boltCanBeSlappedInPrefix)
			{
				BoltCanBeSlappedInPrefix = boltCanBeSlappedInPrefix;
				base..ctor();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("UpdateInteraction")]
		private static void UpdateInteractionPostfix(ClosedBoltHandle __instance)
		{
			FirearmTag component = ((Component)__instance.Weapon).gameObject.GetComponent<FirearmTag>();
			if (Object.op_Implicit((Object)(object)component))
			{
				string itemID = ((FVRPhysicalObject)__instance.Weapon).ObjectWrapper.ItemID;
				Plugin.LogVerbose($"[UpdateInteractionPostfix] Updating tag for firearm '{itemID}' ({component})");
				if (__instance.Weapon.IsBoltHeldOpen())
				{
					Plugin.LogVerbose("[UpdateInteractionPostfix] Bolt of firearm '" + itemID + "' is held open");
					return;
				}
				component.OnManualCharge();
				Plugin.LogVerbose($"[UpdateInteractionPostfix] Successfully updated tag for firearm '{itemID}' ({component})");
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("UpdateHandle")]
		private static void UpdateHandlePrefix(ClosedBoltHandle __instance, ref UpdateHandleSharedState? __state)
		{
			if (__instance != null && __instance.m_hasRotCatch && __instance.IsSlappable && __instance.m_isAtLockAngle)
			{
				__state = new UpdateHandleSharedState(boltCanBeSlappedInPrefix: true);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("UpdateHandle")]
		private static void UpdateHandlePostfix(ClosedBoltHandle __instance, ref UpdateHandleSharedState? __state)
		{
			if (__state != null)
			{
				FirearmTag component = ((Component)__instance.Weapon).gameObject.GetComponent<FirearmTag>();
				if (Object.op_Implicit((Object)(object)component) && __state.BoltCanBeSlappedInPrefix && !__instance.m_isAtLockAngle)
				{
					component.OnHandleSlap();
				}
			}
		}
	}
	[HarmonyWrapSafe]
	[HarmonyPriority(300)]
	[HarmonyPatch(typeof(ClosedBolt))]
	internal static class ClosedBoltPatcher
	{
		[HarmonyPostfix]
		[HarmonyPatch("UpdateInteraction")]
		private static void UpdateInteractionPostfix(ClosedBolt __instance)
		{
			FirearmTag component = ((Component)__instance.Weapon).gameObject.GetComponent<FirearmTag>();
			if (Object.op_Implicit((Object)(object)component))
			{
				string itemID = ((FVRPhysicalObject)__instance.Weapon).ObjectWrapper.ItemID;
				Plugin.LogVerbose($"[UpdateInteractionPostfix] Updating tag for firearm '{itemID}' ({component})");
				if (__instance.Weapon.IsBoltHeldOpen())
				{
					Plugin.LogVerbose("[UpdateInteractionPostfix] Bolt of firearm '" + itemID + "' is held open");
					return;
				}
				component.OnManualCharge();
				Plugin.LogVerbose($"[UpdateInteractionPostfix] Successfully updated tag for firearm '{itemID}' ({component})");
			}
		}
	}
	[HarmonyWrapSafe]
	[HarmonyPriority(300)]
	[HarmonyPatch(typeof(HandgunSlide))]
	internal static class HandgunSlidePatcher
	{
		[HarmonyPostfix]
		[HarmonyPatch("EndInteraction")]
		private static void EndInteractionPostfix(HandgunSlide __instance)
		{
			FirearmTag component = ((Component)__instance.Handgun).gameObject.GetComponent<FirearmTag>();
			if (Object.op_Implicit((Object)(object)component))
			{
				string itemID = ((FVRPhysicalObject)__instance.Handgun).ObjectWrapper.ItemID;
				Plugin.LogVerbose($"[EndInteractionPostfix] Updating tag for handgun '{itemID}' ({component})");
				if (__instance.Handgun.IsSlideHeldOpen())
				{
					Plugin.LogVerbose("[EndInteractionPostfix] Slide of handgun '" + itemID + "' is being held open");
					return;
				}
				component.OnManualCharge();
				Plugin.LogVerbose($"[EndInteractionPostfix] Successfully updated tag for handgun '{itemID}' ({component})");
			}
		}
	}
	[HarmonyWrapSafe]
	[HarmonyPriority(300)]
	[HarmonyPatch(typeof(TubeFedShotgunBolt))]
	internal static class TubeFedShotgunBoltPatcher
	{
		[HarmonyPostfix]
		[HarmonyPatch("UpdateBolt")]
		private static void UpdateInteractionPostfix(TubeFedShotgunBolt __instance)
		{
			FirearmTag component = ((Component)__instance.Shotgun).gameObject.GetComponent<FirearmTag>();
			if (Object.op_Implicit((Object)(object)component) && ((FVRInteractiveObject)__instance).IsHeld && !__instance.Shotgun.IsTubeFedShotgunBoltHeldOpen())
			{
				component.OnManualCharge();
			}
		}
	}
	[HarmonyWrapSafe]
	[HarmonyPriority(300)]
	[HarmonyPatch(typeof(TubeFedShotgunHandle))]
	internal static class TubeFedShotgunHandlePatcher
	{
		[HarmonyPostfix]
		[HarmonyPatch("UpdateInteraction")]
		private static void UpdateInteractionPostfix(TubeFedShotgunHandle __instance)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Invalid comparison between Unknown and I4
			FirearmTag component = ((Component)__instance.Shotgun).gameObject.GetComponent<FirearmTag>();
			if (Object.op_Implicit((Object)(object)component))
			{
				string itemID = ((FVRPhysicalObject)__instance.Shotgun).ObjectWrapper.ItemID;
				Plugin.LogVerbose($"[UpdateInteractionPostfix] Updating tag for shotgun '{itemID}' ({component})");
				if ((int)__instance.Shotgun.Mode == 1)
				{
					Plugin.LogVerbose("[UpdateInteractionPostfix] Shotgun '" + itemID + "' is in automatic mode");
					return;
				}
				component.OnManualCharge();
				Plugin.LogVerbose("[UpdateInteractionPostfix] Successfully updated tag for " + $"shotgun '{itemID}' ({component})");
			}
		}
	}
	[HarmonyWrapSafe]
	[HarmonyPriority(300)]
	[HarmonyPatch(typeof(FVRFireArmMagazine))]
	internal static class FVRFireArmMagazinePatcher
	{
		[HarmonyPostfix]
		[HarmonyPatch("Awake")]
		private static void AwakePostfix(FVRFireArmMagazine __instance)
		{
			if (Object.op_Implicit((Object)(object)((FVRPhysicalObject)__instance).ObjectWrapper))
			{
				string itemID = ((FVRPhysicalObject)__instance).ObjectWrapper.ItemID;
				if (itemID != null)
				{
					Plugin.Log.LogMessage((object)("A firearm magazine with ItemID '" + itemID + "' has spawned."));
				}
			}
		}
	}
	[HarmonyWrapSafe]
	[HarmonyPriority(300)]
	[HarmonyPatch(typeof(FVRFireArm))]
	internal static class FVRFireArmPatcher
	{
		private class HandleMagOverrideSharedState
		{
			public FVRFireArmMagazine FirearmMagReference { get; }

			public bool MagUsesOverride { get; }

			public AudioEvent? FirearmMagInClip { get; }

			public AudioEvent? FirearmMagOutClip { get; }

			public HandleMagOverrideSharedState(FVRFireArmMagazine firearmMagReference, bool magUsesOverride, AudioEvent? firearmMagInClip, AudioEvent? firearmMagOutClip)
			{
				FirearmMagReference = firearmMagReference;
				MagUsesOverride = magUsesOverride;
				FirearmMagInClip = firearmMagInClip;
				FirearmMagOutClip = firearmMagOutClip;
				base..ctor();
			}
		}

		private class PlayAudioEventSharedState
		{
			public AudioEvent? OriginalAudioEvent { get; }

			public GunEvent.Value Type { get; }

			public PlayAudioEventSharedState(GunEvent.Value type, AudioEvent? originalAudioEvent)
			{
				OriginalAudioEvent = originalAudioEvent;
				Type = type;
				base..ctor();
			}
		}

		[CompilerGenerated]
		private sealed class <ReplaceFirearmAudioSetRoutine>d__19 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public FVRFirearmAudioSet firearmClipSetCopied;

			public string itemID;

			public string gunAudioSetName;

			public FirearmTag firearmTag;

			private GunEvent.Value[] <>7__wrap1;

			private int <>7__wrap2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ReplaceFirearmAudioSetRoutine>d__19(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>7__wrap1 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					ProcessGunEvent(firearmClipSetCopied, itemID, gunAudioSetName, GunEvent.Value.MagazineIn);
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<>7__wrap1 = GunEvent.All;
					<>7__wrap2 = 0;
					goto IL_00b6;
				case 2:
					{
						<>1__state = -1;
						goto IL_00a8;
					}
					IL_00b6:
					if (<>7__wrap2 < <>7__wrap1.Length)
					{
						GunEvent.Value value = <>7__wrap1[<>7__wrap2];
						if (value != GunEvent.Value.MagazineIn)
						{
							ProcessGunEvent(firearmClipSetCopied, itemID, gunAudioSetName, value);
							<>2__current = null;
							<>1__state = 2;
							return true;
						}
						goto IL_00a8;
					}
					<>7__wrap1 = null;
					SaveSlideForwardOverrideAudioEventsInFirearmTag(itemID, gunAudioSetName, firearmTag, firearmClipSetCopied);
					SaveHandleForwardOverrideAudioEventsInFirearmTag(itemID, gunAudioSetName, firearmTag, firearmClipSetCopied);
					Plugin.LogVerbose($"FirearmTag initialization finished ({firearmTag})");
					return false;
					IL_00a8:
					<>7__wrap2++;
					goto IL_00b6;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static GunSoundLoader? _gunSoundLoader;

		private static GunAudioSetLoader? _gunAudioSetLoader;

		private static readonly string ReplacementAudioClipName = Guid.NewGuid().ToString();

		internal static void Initialize(GunSoundLoader gunSoundLoader, GunAudioSetLoader gunAudioSetLoader)
		{
			_gunSoundLoader = gunSoundLoader;
			_gunAudioSetLoader = gunAudioSetLoader;
		}

		[HarmonyPrefix]
		[HarmonyPatch("Fire")]
		private static void FirePrefix(FVRFireArm __instance)
		{
			FirearmTag component = ((Component)__instance).gameObject.GetComponent<FirearmTag>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return;
			}
			string itemID = ((FVRPhysicalObject)__instance).ObjectWrapper.ItemID;
			Plugin.LogVerbose($"[FirePrefix] Updating tag for firearm '{itemID}' ({component})");
			ClosedBoltWeapon val = (ClosedBoltWeapon)(object)((__instance is ClosedBoltWeapon) ? __instance : null);
			if (val != null && val.WillBoltBeHeldOpenAfterNextShot())
			{
				Plugin.LogVerbose("[FirePrefix] Bolt of firearm '" + itemID + "' will be held open");
				return;
			}
			Handgun val2 = (Handgun)(object)((__instance is Handgun) ? __instance : null);
			if (val2 != null && val2.WillSlideBeHeldOpenAfterNextShot())
			{
				Plugin.LogVerbose("[FirePrefix] Slide of handgun '" + itemID + "' will be held open");
				return;
			}
			TubeFedShotgun val3 = (TubeFedShotgun)(object)((__instance is TubeFedShotgun) ? __instance : null);
			if (val3 != null && val3.WillTubeFedShotgunBoltBeHeldOpenAfterNextShot())
			{
				Plugin.LogVerbose("[FirePrefix] Bolt of shotgun '" + itemID + "' will be held open, or shotgunis in pump mode");
				return;
			}
			component.OnShot();
			Plugin.LogVerbose($"[FirePrefix] Successfully updated tag for firearm '{itemID}' ({component})");
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FVRFireArm), "PlayAudioEvent")]
		private static void PlayAudioEventPrefix(FVRFireArm __instance, FirearmAudioEventType eType, ref PlayAudioEventSharedState? __state)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			PlayAudioEventSharedPrefix(__instance, eType, ref __state);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FVRFireArm), "PlayAudioEvent")]
		private static void PlayAudioEventPostfix(FVRFireArm __instance, ref PlayAudioEventSharedState? __state)
		{
			PlayAudioEventSharedPostfix(__instance, ref __state);
		}

		[HarmonyPrefix]
		[HarmonyPatch("LoadMag")]
		private static void LoadMagPrefix(FVRFireArmMagazine mag, FVRFireArm __instance, ref HandleMagOverrideSharedState? __state)
		{
			HandleMagOverrideSharedPrefix(mag, __instance, ref __state, GunEvent.Value.MagazineIn);
		}

		[HarmonyPrefix]
		[HarmonyPatch("EjectMag")]
		private static void EjectMagPrefix(FVRFireArm __instance, ref HandleMagOverrideSharedState? __state)
		{
			HandleMagOverrideSharedPrefix(__instance.Magazine, __instance, ref __state, GunEvent.Value.MagazineOut);
		}

		[HarmonyPostfix]
		[HarmonyPatch("LoadMag")]
		private static void LoadMagPostfix(FVRFireArmMagazine mag, FVRFireArm __instance, HandleMagOverrideSharedState? __state)
		{
			HandleMagOverrideSharedPostfix(__instance, __state);
		}

		[HarmonyPostfix]
		[HarmonyPatch("EjectMag")]
		private static void EjectMagPostfix(FVRFireArm __instance, HandleMagOverrideSharedState? __state)
		{
			HandleMagOverrideSharedPostfix(__instance, __state);
		}

		private static void HandleMagOverrideSharedPrefix(FVRFireArmMagazine magazine, FVRFireArm firearm, ref HandleMagOverrideSharedState? state, GunEvent.Value gunEvent)
		{
			if (!Object.op_Implicit((Object)(object)magazine) || !Object.op_Implicit((Object)(object)((FVRPhysicalObject)magazine).ObjectWrapper))
			{
				return;
			}
			string itemID = ((FVRPhysicalObject)magazine).ObjectWrapper.ItemID;
			if (itemID == null)
			{
				Plugin.Log.LogWarning((object)"[HandleMagOverrideSharedPrefix] Did not replace audio for magazine because its itemID is null.");
			}
			else
			{
				if (!Object.op_Implicit((Object)(object)((FVRPhysicalObject)firearm).ObjectWrapper))
				{
					return;
				}
				string itemID2 = ((FVRPhysicalObject)firearm).ObjectWrapper.ItemID;
				if (itemID2 == null)
				{
					Plugin.Log.LogWarning((object)("[HandleMagOverrideSharedPrefix] Did not replace audio for magazine with ItemID '" + itemID + "' because its parent firearm has a null ItemID."));
					return;
				}
				if (_gunSoundLoader == null || _gunAudioSetLoader == null)
				{
					Plugin.Log.LogError((object)"[HandleMagOverrideSharedPrefix] Failed to replace audio for magazine because 'FVRFireArmPatcher' has not been initialized yet.");
					return;
				}
				if (Object.op_Implicit((Object)(object)firearm.AudioClipSet))
				{
					string name = ((Object)firearm.AudioClipSet).name;
					state = new HandleMagOverrideSharedState(magazine, magazine.UsesOverrideInOut, firearm.AudioClipSet.MagazineIn.DeepCopy(), firearm.AudioClipSet.MagazineOut.DeepCopy());
					string text = string.Join(':'.ToString(), itemID2, gunEvent.ToString(), itemID);
					string text2 = string.Join(':'.ToString(), name, gunEvent.ToString(), itemID);
					Plugin.LogVerbose("[HandleMagOverrideSharedPrefix] Attempting to replace firearm magazine audio for '" + text + "' and '" + text2 + "'");
					AssetTree<AddonAsset>.AssetNode assetNode = _gunAudioSetLoader.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel(), name, gunEvent.ToString(), itemID).FirstOrDefault();
					AssetTree<AddonAsset>.AssetNode assetNode2 = _gunSoundLoader.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel(), itemID2, gunEvent.ToString(), itemID).FirstOrDefault();
					try
					{
						int num;
						if (assetNode != null)
						{
							AddonAsset asset = assetNode.Asset;
							if (asset != null)
							{
								AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
								if (assetMapping != null)
								{
									AddonManifest.AssetReference[] resourceReferences = assetMapping.ResourceReferences;
									if (resourceReferences != null)
									{
										num = ((resourceReferences.Length > 0) ? 1 : 0);
										goto IL_024e;
									}
								}
							}
						}
						num = 0;
						goto IL_024e;
						IL_0283:
						int num2;
						bool flag = (byte)num2 != 0;
						if (num == 0 && !flag)
						{
							Plugin.LogVerbose("[HandleMagOverrideSharedPrefix] Did not replace audio for '" + text + "' and '" + text2 + "' because they have no replacement sounds.");
							return;
						}
						Plugin.LogVerbose("[HandleMagOverrideSharedPrefix] Replacing audio for '" + text + "' and '" + text2 + "'");
						magazine.UsesOverrideInOut = false;
						if (flag)
						{
							AddonAsset asset2 = assetNode2.Asset;
							firearm.AudioClipSet.ReplaceAudioEventByGunEventFromAddonAsset(asset2, gunEvent);
						}
						else
						{
							AddonAsset asset3 = assetNode.Asset;
							firearm.AudioClipSet.ReplaceAudioEventByGunEventFromAddonAsset(asset3, gunEvent);
						}
						return;
						IL_024e:
						if (assetNode2 != null)
						{
							AddonAsset asset = assetNode2.Asset;
							if (asset != null)
							{
								AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
								if (assetMapping != null)
								{
									AddonManifest.AssetReference[] resourceReferences = assetMapping.ResourceReferences;
									if (resourceReferences != null)
									{
										num2 = ((resourceReferences.Length > 0) ? 1 : 0);
										goto IL_0283;
									}
								}
							}
						}
						num2 = 0;
						goto IL_0283;
					}
					catch (Exception ex)
					{
						Plugin.Log.LogError((object)("[HandleMagOverrideSharedPrefix] Failed to replace audio for '" + text + "' and '" + text2 + $"\n- Cause: {ex.GetType()}" + "\n- Message: " + ex.Message));
						return;
					}
				}
				Plugin.Log.LogWarning((object)("[HandleMagOverrideSharedPrefix] Did not replace audio for magazine with ItemID '" + itemID + "' because the AudioClipSet of the parent '" + itemID2 + "' is null."));
			}
		}

		private static void HandleMagOverrideSharedPostfix(FVRFireArm firearm, HandleMagOverrideSharedState? state)
		{
			if (state != null && Object.op_Implicit((Object)(object)state.FirearmMagReference))
			{
				Plugin.LogVerbose("[HandleMagOverrideSharedPostfix] Setting UsesOverrideInOut back " + $"to: {state.MagUsesOverride}");
				state.FirearmMagReference.UsesOverrideInOut = state.MagUsesOverride;
				firearm.AudioClipSet.MagazineIn = state.FirearmMagInClip;
				firearm.AudioClipSet.MagazineOut = state.FirearmMagOutClip;
			}
		}

		private static void PlayAudioEventSharedPrefix(FVRFireArm firearm, FirearmAudioEventType fvrAudioEventType, ref PlayAudioEventSharedState? state)
		{
			//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_0006: Invalid comparison between Unknown and I4
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Invalid comparison between Unknown and I4
			GunEvent.Value? value = (((int)fvrAudioEventType == 0) ? new GunEvent.Value?(GunEvent.Value.BoltSlideForward) : (((int)fvrAudioEventType != 11) ? null : new GunEvent.Value?(GunEvent.Value.HandleForward)));
			GunEvent.Value? value2 = value;
			if (!value2.HasValue || !Object.op_Implicit((Object)(object)((FVRPhysicalObject)firearm).ObjectWrapper))
			{
				return;
			}
			string itemID = ((FVRPhysicalObject)firearm).ObjectWrapper.ItemID;
			if (itemID == null)
			{
				Plugin.Log.LogWarning((object)"[PlayAudioEventSharedPrefix] Did not replace audio for firearm because its ItemID is null.");
				return;
			}
			if (_gunSoundLoader == null || _gunAudioSetLoader == null)
			{
				Plugin.Log.LogError((object)"[PlayAudioEventSharedPrefix] Failed to replace audio for magazine because 'FVRFireArmPatcher' has not been initialized yet.");
				return;
			}
			if (!Object.op_Implicit((Object)(object)firearm.AudioClipSet))
			{
				Plugin.Log.LogWarning((object)("[PlayAudioEventSharedPrefix] Did not replace slide audio for firearm with ItemID '" + itemID + "' because the AudioClipSet of the instance is null."));
				return;
			}
			FirearmTag component = ((Component)firearm).GetComponent<FirearmTag>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				Plugin.Log.LogError((object)("[PlayAudioEventSharedPrefix] Did not replace slide audio for firearm with ItemID '" + itemID + "' because FirearmTag is null."));
				return;
			}
			AudioEvent val = (((int)fvrAudioEventType == 0) ? component.GetLatestSlideForwardCircumstanceAudioEvent() : (((int)fvrAudioEventType != 11) ? null : component.GetLatestHandleForwardCircumstanceAudioEvent()));
			AudioEvent val2 = val;
			if (val2 == null)
			{
				Plugin.LogVerbose("[PlayAudioEventSharedPrefix] Did not replace audio for firearm with ItemID '" + itemID + "' because there is no available circumstance override.");
				return;
			}
			AudioEvent audioEventBy = firearm.AudioClipSet.GetAudioEventBy(value2.Value);
			state = new PlayAudioEventSharedState(value2.Value, audioEventBy.DeepCopy());
			firearm.AudioClipSet.ReplaceAudioEventBy(value2.Value, val2);
		}

		private static void PlayAudioEventSharedPostfix(FVRFireArm firearm, ref PlayAudioEventSharedState? state)
		{
			if (state?.OriginalAudioEvent != null)
			{
				Plugin.LogVerbose($"[PlayAudioEventSharedPostfix] Setting {state.Type} back to default clip.");
				firearm.AudioClipSet.ReplaceAudioEventBy(state.Type, state.OriginalAudioEvent);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Awake")]
		private static void AwakePostfix(FVRFireArm __instance)
		{
			ReplaceFirearmAudioSet(__instance, isModular: false);
		}

		public static void ReplaceFirearmAudioSet(FVRFireArm fvrFirearm, bool isModular)
		{
			if ((Object)(object)((FVRPhysicalObject)fvrFirearm).ObjectWrapper == (Object)null)
			{
				return;
			}
			string itemID = ((FVRPhysicalObject)fvrFirearm).ObjectWrapper.ItemID;
			if (itemID == null)
			{
				Plugin.Log.LogWarning((object)"Did not replace audio for firearm because its ItemID is null.");
				return;
			}
			if (_gunSoundLoader == null || _gunAudioSetLoader == null)
			{
				Plugin.Log.LogError((object)("Failed to replace audio for firearm with ItemID '" + itemID + "' because 'FVRFireArmPatcher' has not been initialized yet."));
				return;
			}
			if ((Object)(object)fvrFirearm.AudioClipSet == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Did not replace audio for firearm with ItemID '" + itemID + "' because the AudioClipSet of the instance is null."));
				return;
			}
			string name = ((Object)fvrFirearm.AudioClipSet).name;
			if (isModular)
			{
				Plugin.Log.LogMessage((object)("Replacing/updating audio for modular firearm with ItemID '" + itemID + "' and audio set '" + name + "'"));
			}
			else
			{
				Plugin.Log.LogMessage((object)("Attempting to replace audio for firearm with ItemID '" + itemID + "' and audio set '" + name + "'"));
			}
			FVRFirearmAudioSet firearmClipSetCopied = (fvrFirearm.AudioClipSet = fvrFirearm.AudioClipSet.DeepCopy());
			FirearmTag firearmTag = ((Component)fvrFirearm).GetComponent<FirearmTag>();
			if (!Object.op_Implicit((Object)(object)firearmTag))
			{
				firearmTag = ((Component)fvrFirearm).gameObject.AddComponent<FirearmTag>();
				((Object)firearmTag).hideFlags = (HideFlags)61;
			}
			CoroutineRunner.Run(ReplaceFirearmAudioSetRoutine(firearmClipSetCopied, itemID, name, firearmTag));
		}

		private static IEnumerator ReplaceFirearmAudioSetRoutine(FVRFirearmAudioSet firearmClipSetCopied, string itemID, string gunAudioSetName, FirearmTag firearmTag)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ReplaceFirearmAudioSetRoutine>d__19(0)
			{
				firearmClipSetCopied = firearmClipSetCopied,
				itemID = itemID,
				gunAudioSetName = gunAudioSetName,
				firearmTag = firearmTag
			};
		}

		private static void ProcessGunEvent(FVRFirearmAudioSet firearmClipSetCopied, string itemID, string gunAudioSetName, GunEvent.Value gunEvent)
		{
			string text = itemID + ":" + gunEvent;
			string text2 = gunAudioSetName + ":" + gunEvent;
			Plugin.LogVerbose("Attempting to replace firearm audio for '" + text + "' and '" + text2 + "'");
			AssetTree<AddonAsset>.AssetNode assetNode = _gunAudioSetLoader?.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQuery(), gunAudioSetName, gunEvent.ToString()).FirstOrDefault();
			AssetTree<AddonAsset>.AssetNode assetNode2 = _gunSoundLoader?.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQuery(), itemID, gunEvent.ToString()).FirstOrDefault();
			try
			{
				int num;
				if (assetNode != null)
				{
					AddonAsset asset = assetNode.Asset;
					if (asset != null)
					{
						AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
						if (assetMapping != null)
						{
							AddonManifest.AssetReference[] resourceReferences = assetMapping.ResourceReferences;
							if (resourceReferences != null)
							{
								num = ((resourceReferences.Length > 0) ? 1 : 0);
								goto IL_0119;
							}
						}
					}
				}
				num = 0;
				goto IL_0119;
				IL_014c:
				int num2;
				bool flag = (byte)num2 != 0;
				if (num == 0 && !flag)
				{
					Plugin.LogVerbose("Did not replace audio for '" + text + "' and '" + text2 + "' because they have no replacement sounds.");
				}
				else if (flag)
				{
					AddonAsset asset2 = assetNode2.Asset;
					firearmClipSetCopied.ReplaceAudioEventByGunEventFromAddonAsset(asset2, gunEvent);
				}
				else
				{
					AddonAsset asset3 = assetNode.Asset;
					firearmClipSetCopied.ReplaceAudioEventByGunEventFromAddonAsset(asset3, gunEvent);
				}
				return;
				IL_0119:
				if (assetNode2 != null)
				{
					AddonAsset asset = assetNode2.Asset;
					if (asset != null)
					{
						AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
						if (assetMapping != null)
						{
							AddonManifest.AssetReference[] resourceReferences = assetMapping.ResourceReferences;
							if (resourceReferences != null)
							{
								num2 = ((resourceReferences.Length > 0) ? 1 : 0);
								goto IL_014c;
							}
						}
					}
				}
				num2 = 0;
				goto IL_014c;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Failed to replace audio for '" + text + "' and '" + text2 + "'" + $"\n- Cause: {ex.GetType()}" + "\n- Message: " + ex.Message));
			}
		}

		private static void SaveSlideForwardOverrideAudioEventsInFirearmTag(string itemID, string gunAudioSetName, FirearmTag firearmTag, FVRFirearmAudioSet firearmAudioSet)
		{
			if (_gunAudioSetLoader == null || _gunSoundLoader == null)
			{
				return;
			}
			BoltSlideForwardCircumstance.Value[] all = BoltSlideForwardCircumstance.All;
			foreach (BoltSlideForwardCircumstance.Value value in all)
			{
				Plugin.LogVerbose("[SaveSlideForwardOverrideAudioEventsInFirearmTag] " + $"Attempting to find sound replacements for '{value}' for " + "'" + itemID + "' and '" + gunAudioSetName + "'");
				string[] targetPath = value.GetTargetPath();
				List<string> list = new List<string>(2) { gunAudioSetName, "BoltSlideForward" };
				List<string> list2 = new List<string>(2) { itemID, "BoltSlideForward" };
				list.AddRange(targetPath);
				list2.AddRange(targetPath);
				string text = StringUtils.JoinValues(list, ':'.ToString());
				string text2 = StringUtils.JoinValues(list2, ':'.ToString());
				Plugin.LogVerbose("[SaveSlideForwardOverrideAudioEventsInFirearmTag] Attempting to load '" + text + "' and '" + text2 + "'");
				AssetTree<AddonAsset>.AssetNode assetNode = _gunAudioSetLoader.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryAndSpecifications(3, 4), list.ToArray()).FirstOrDefault();
				AssetTree<AddonAsset>.AssetNode assetNode2 = _gunSoundLoader.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryAndSpecifications(3, 4), list2.ToArray()).FirstOrDefault();
				try
				{
					int num;
					if (assetNode != null)
					{
						AddonAsset asset = assetNode.Asset;
						if (asset != null)
						{
							AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
							if (assetMapping != null)
							{
								AddonManifest.AssetReference[] resourceReferences = assetMapping.ResourceReferences;
								if (resourceReferences != null)
								{
									num = ((resourceReferences.Length > 0) ? 1 : 0);
									goto IL_019b;
								}
							}
						}
					}
					num = 0;
					goto IL_019b;
					IL_01d0:
					int num2;
					bool flag = (byte)num2 != 0;
					if (num == 0 && !flag)
					{
						Plugin.LogVerbose("[SaveSlideForwardOverrideAudioEventsInFirearmTag] Could not find '" + text + "' and '" + text2 + "'");
						continue;
					}
					Plugin.LogVerbose("[SaveSlideForwardOverrideAudioEventsInFirearmTag] Saving '" + text + "' and '" + text2 + "' in firearm tag");
					AudioEvent val = firearmAudioSet.BoltSlideForward.DeepCopy();
					if (val != null)
					{
						AddonAsset asset = ((!flag) ? assetNode.Asset : assetNode2.Asset);
						AddonAsset addonAsset = asset;
						val.ReplaceClipsInAudioEvent(addonAsset);
						firearmTag.SaveBoltSlideForwardCircumstanceAudioEvent(val, value);
					}
					goto end_IL_0166;
					IL_019b:
					if (assetNode2 != null)
					{
						AddonAsset asset = assetNode2.Asset;
						if (asset != null)
						{
							AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
							if (assetMapping != null)
							{
								AddonManifest.AssetReference[] resourceReferences = assetMapping.ResourceReferences;
								if (resourceReferences != null)
								{
									num2 = ((resourceReferences.Length > 0) ? 1 : 0);
									goto IL_01d0;
								}
							}
						}
					}
					num2 = 0;
					goto IL_01d0;
					end_IL_0166:;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("[SaveSlideForwardOverrideAudioEventsInFirearmTag] Failed to replace audio for '" + text + "' and '" + text2 + $"\n- Cause: {ex.GetType()}" + "\n- Message: " + ex.Message));
				}
			}
		}

		private static void SaveHandleForwardOverrideAudioEventsInFirearmTag(string itemID, string gunAudioSetName, FirearmTag firearmTag, FVRFirearmAudioSet firearmAudioSet)
		{
			if (_gunAudioSetLoader == null || _gunSoundLoader == null)
			{
				return;
			}
			HandleForwardCircumstance.Value[] all = HandleForwardCircumstance.All;
			foreach (HandleForwardCircumstance.Value value in all)
			{
				Plugin.LogVerbose("[SaveHandleForwardOverrideAudioEventsInFirearmTag] " + $"Attempting to find sound replacements for '{value}' for " + "'" + itemID + "' and '" + gunAudioSetName + "'");
				string[] targetPath = value.GetTargetPath();
				List<string> list = new List<string>(2) { gunAudioSetName, "HandleForward" };
				List<string> list2 = new List<string>(2) { itemID, "HandleForward" };
				list.AddRange(targetPath);
				list2.AddRange(targetPath);
				string text = StringUtils.JoinValues(list, ':'.ToString());
				string text2 = StringUtils.JoinValues(list2, ':'.ToString());
				Plugin.LogVerbose("[SaveHandleForwardOverrideAudioEventsInFirearmTag] Attempting to load '" + text + "' and '" + text2 + "'");
				AssetTree<AddonAsset>.AssetNode assetNode = _gunAudioSetLoader.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryAndSpecifications(3, 4), list.ToArray()).FirstOrDefault();
				AssetTree<AddonAsset>.AssetNode assetNode2 = _gunSoundLoader.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryAndSpecifications(3, 4), list2.ToArray()).FirstOrDefault();
				try
				{
					int num;
					if (assetNode != null)
					{
						AddonAsset asset = assetNode.Asset;
						if (asset != null)
						{
							AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
							if (assetMapping != null)
							{
								AddonManifest.AssetReference[] resourceReferences = assetMapping.ResourceReferences;
								if (resourceReferences != null)
								{
									num = ((resourceReferences.Length > 0) ? 1 : 0);
									goto IL_019b;
								}
							}
						}
					}
					num = 0;
					goto IL_019b;
					IL_01d0:
					int num2;
					bool flag = (byte)num2 != 0;
					if (num == 0 && !flag)
					{
						Plugin.LogVerbose("[SaveHandleForwardOverrideAudioEventsInFirearmTag] Could not find '" + text + "' and '" + text2 + "'");
						continue;
					}
					Plugin.LogVerbose("[SaveHandleForwardOverrideAudioEventsInFirearmTag] Saving '" + text + "' and '" + text2 + "' in firearm tag");
					AudioEvent val = firearmAudioSet.HandleForward.DeepCopy();
					if (val != null)
					{
						AddonAsset asset = ((!flag) ? assetNode.Asset : assetNode2.Asset);
						AddonAsset addonAsset = asset;
						val.ReplaceClipsInAudioEvent(addonAsset);
						firearmTag.SaveHandleForwardCircumstanceAudioEvent(val, value);
					}
					goto end_IL_0166;
					IL_019b:
					if (assetNode2 != null)
					{
						AddonAsset asset = assetNode2.Asset;
						if (asset != null)
						{
							AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
							if (assetMapping != null)
							{
								AddonManifest.AssetReference[] resourceReferences = assetMapping.ResourceReferences;
								if (resourceReferences != null)
								{
									num2 = ((resourceReferences.Length > 0) ? 1 : 0);
									goto IL_01d0;
								}
							}
						}
					}
					num2 = 0;
					goto IL_01d0;
					end_IL_0166:;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("[SaveHandleForwardOverrideAudioEventsInFirearmTag] Failed to replace audio for '" + text + "' and '" + text2 + $"\n- Cause: {ex.GetType()}" + "\n- Message: " + ex.Message));
				}
			}
		}

		private static void ReplaceAudioEventByGunEventFromAddonAsset(this FVRFirearmAudioSet fvrFirearmAudioSet, AddonAsset addonAsset, GunEvent.Value gunEvent)
		{
			fvrFirearmAudioSet.GetAudioEventBy(gunEvent).ReplaceClipsInAudioEvent(addonAsset);
		}

		private static void ReplaceClipsInAudioEvent(this AudioEvent audioEvent, AddonAsset addonAsset)
		{
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			List<AudioClip> list = new List<AudioClip>();
			AddonManifest.AssetReference[] resourceReferences = addonAsset.AssetMapping.ResourceReferences;
			foreach (AddonManifest.AssetReference replacement in resourceReferences)
			{
				AudioClip val = addonAsset.SourceAddon.LoadAudioClip(replacement, gunSound: true);
				((Object)val).name = ReplacementAudioClipName;
				list.Add(val);
			}
			audioEvent.Clips = list;
			float[] array = (addonAsset.AssetMapping as AddonManifest.AssetMapping.Audio)?.VolumeRange;
			float[] array2 = (addonAsset.AssetMapping as AddonManifest.AssetMapping.Audio)?.VolumeMultiplierRange;
			float[] array3 = (addonAsset.AssetMapping as AddonManifest.AssetMapping.Audio)?.PitchRange;
			float[] array4 = (addonAsset.AssetMapping as AddonManifest.AssetMapping.Audio)?.PitchMultiplierRange;
			if (array != null)
			{
				audioEvent.VolumeRange = new Vector2(array[0], array[1]);
			}
			if (array2 != null)
			{
				float num = Random.Range(array2[0], array2[1]);
				float num2 = Random.Range(array2[0], array2[1]);
				audioEvent.VolumeRange = new Vector2(audioEvent.VolumeRange.x * num, audioEvent.VolumeRange.y * num2);
			}
			if (array3 != null)
			{
				audioEvent.PitchRange = new Vector2(array3[0], array3[1]);
			}
			if (array4 != null)
			{
				float num3 = Random.Range(array4[0], array4[1]);
				float num4 = Random.Range(array4[0], array4[1]);
				audioEvent.PitchRange = new Vector2(audioEvent.PitchRange.x * num3, audioEvent.PitchRange.y * num4);
			}
		}
	}
	[HarmonyPatch(typeof(ModularBarrelExtension))]
	internal static class ModularBarrelExtensionPatcher
	{
		private static readonly FieldInfo _firearm = AccessTools.Field(typeof(ModularBarrelExtension), "_firearm");

		[HarmonyPostfix]
		[HarmonyPatch("DisablePart")]
		private static void DisablePart_Postfix(ModularBarrelExtension __instance)
		{
			ModularBarrelExtension __instance2 = __instance;
			Plugin.ExceptionCatcher.Run(delegate
			{
				Plugin.Log.LogDebug((object)"ModularBarrel DisablePart patcher");
				FVRFireArm val = __instance2.Access<FVRFireArm>(_firearm);
				if ((Object)(object)val != (Object)null)
				{
					FVRFireArmPatcher.ReplaceFirearmAudioSet(val, isModular: true);
				}
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch("EnablePart")]
		private static void EnablePart_Postfix(ModularBarrelExtension __instance)
		{
			ModularBarrelExtension __instance2 = __instance;
			Plugin.ExceptionCatcher.Run(delegate
			{
				Plugin.Log.LogDebug((object)"ModularBarrel EnablePart patcher");
				FVRFireArm val = __instance2.Access<FVRFireArm>(_firearm);
				if ((Object)(object)val != (Object)null)
				{
					FVRFireArmPatcher.ReplaceFirearmAudioSet(val, isModular: true);
				}
			});
		}
	}
	internal static class OldSideloaderPatcher
	{
		public static void ApplyPatch()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			Type type = AccessTools.TypeByName("H3VR.Sideloader.AssetLoaders.AudioClipLoader");
			if ((object)type == null)
			{
				Plugin.Log.LogError((object)"Old Sideloader type is null.");
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(type, "OnAudioSourcePlay", (Type[])null, (Type[])null);
			if ((object)methodInfo == null)
			{
				Plugin.Log.LogError((object)"Old Sideloader method is null.");
			}
			else
			{
				new Harmony("Sirdoggy.SideloaderMint/OldSideloaderPatcher").Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(OldSideloaderPatcher), "Transpiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			try
			{
				for (int i = 0; i < list.Count; i++)
				{
					if (CodeInstructionExtensions.Calls(list[i], AccessTools.PropertySetter(typeof(AudioSource), "clip")))
					{
						list[i] = new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(OldSideloaderPatcher), "SetClipWithPreservedName", (Type[])null, (Type[])null));
						break;
					}
				}
				return list;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Exception in transpiler: {arg}");
				return list;
			}
		}

		private static void SetClipWithPreservedName(AudioSource instance, AudioClip newClip)
		{
			string name = ((Object)newClip).name;
			AudioClip clip = instance.clip;
			string text = ((clip != null) ? ((Object)clip).name : null);
			instance.clip = newClip;
			if (text != null)
			{
				((Object)instance.clip).name = text;
				Plugin.LogVerbose("Patched old Sideloader method, restoring clip name: " + name + " => " + text);
			}
		}
	}
}
namespace Sirdoggy.SideloaderMint.Patchers.Tags
{
	internal class FirearmTag : MonoBehaviour
	{
		private const double CircumstanceValidityTimeSpanMillis = 250.0;

		private AudioEvent? _boltSlideForwardAfterManualChargeAudioEvent;

		private AudioEvent? _boltSlideForwardAfterHandleSlapAudioEvent;

		private AudioEvent? _boltSlideForwardAfterShotAudioEvent;

		private AudioEvent? _handleForwardAfterHandleSlapAudioEvent;

		private float? _lastManualChargeTime;

		private float? _lastHandleSlapTimeSlideForward;

		private float? _lastHandleSlapTimeHandleForward;

		private float? _lastShotTime;

		public void SaveBoltSlideForwardCircumstanceAudioEvent(AudioEvent audioEvent, BoltSlideForwardCircumstance.Value circumstance)
		{
			switch (circumstance)
			{
			case BoltSlideForwardCircumstance.Value.Shot:
				_boltSlideForwardAfterShotAudioEvent = audioEvent;
				break;
			case BoltSlideForwardCircumstance.Value.HandleSlap:
				_boltSlideForwardAfterHandleSlapAudioEvent = audioEvent;
				break;
			case BoltSlideForwardCircumstance.Value.ManualCharge:
				_boltSlideForwardAfterManualChargeAudioEvent = audioEvent;
				break;
			}
		}

		public void SaveHandleForwardCircumstanceAudioEvent(AudioEvent audioEvent, HandleForwardCircumstance.Value circumstance)
		{
			if (circumstance == HandleForwardCircumstance.Value.HandleSlap)
			{
				_handleForwardAfterHandleSlapAudioEvent = audioEvent;
			}
		}

		public void OnManualCharge()
		{
			_lastManualChargeTime = Time.time;
			_lastHandleSlapTimeHandleForward = null;
		}

		public void OnHandleSlap()
		{
			_lastHandleSlapTimeSlideForward = Time.time;
			_lastHandleSlapTimeHandleForward = Time.time;
		}

		public void OnShot()
		{
			_lastShotTime = Time.time;
		}

		public AudioEvent? GetLatestSlideForwardCircumstanceAudioEvent()
		{
			List<KeyValuePair<AudioEvent, float?>> list = (from pair in new List<KeyValuePair<AudioEvent, float?>>
				{
					new KeyValuePair<AudioEvent, float?>(_boltSlideForwardAfterManualChargeAudioEvent, _lastManualChargeTime),
					new KeyValuePair<AudioEvent, float?>(_boltSlideForwardAfterHandleSlapAudioEvent, _lastHandleSlapTimeSlideForward),
					new KeyValuePair<AudioEvent, float?>(_boltSlideForwardAfterShotAudioEvent, _lastShotTime)
				}
				where IsValidLastTime(pair.Value)
				orderby pair.Value descending
				select pair).ToList();
			_lastManualChargeTime = null;
			_lastHandleSlapTimeSlideForward = null;
			_lastShotTime = null;
			if (list.Count == 0)
			{
				return null;
			}
			return list.First().Key;
		}

		public AudioEvent? GetLatestHandleForwardCircumstanceAudioEvent()
		{
			List<KeyValuePair<AudioEvent, float?>> list = (from pair in new List<KeyValuePair<AudioEvent, float?>>
				{
					new KeyValuePair<AudioEvent, float?>(_handleForwardAfterHandleSlapAudioEvent, _lastHandleSlapTimeHandleForward)
				}
				where IsValidLastTime(pair.Value)
				orderby pair.Value descending
				select pair).ToList();
			_lastHandleSlapTimeHandleForward = null;
			if (list.Count == 0)
			{
				return null;
			}
			return list.First().Key;
		}

		private static bool IsValidLastTime(float? time)
		{
			if (!time.HasValue)
			{
				return false;
			}
			return (double?)((Time.time - time) * 1000f) < 250.0;
		}

		public override string ToString()
		{
			return StringUtils.FormatTypeProperties("FirearmTag", new <>z__ReadOnlyArray<string>(new string[4]
			{
				string.Format("{0}: {1}", "_lastManualChargeTime", _lastManualChargeTime),
				string.Format("{0}: {1}", "_lastHandleSlapTimeSlideForward", _lastHandleSlapTimeSlideForward),
				string.Format("{0}: {1}", "_lastShotTime", _lastShotTime),
				string.Format("{0}: {1}", "_lastHandleSlapTimeHandleForward", _lastHandleSlapTimeHandleForward)
			}));
		}
	}
}
namespace Sirdoggy.SideloaderMint.Patchers.Extensions
{
	internal static class AudioEventExtensions
	{
		public static AudioEvent? DeepCopy(this AudioEvent? original)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_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)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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)
			//IL_005a: Expected O, but got Unknown
			if (original == null)
			{
				return null;
			}
			AudioEvent val = (AudioEvent)FormatterServices.GetUninitializedObject(typeof(AudioEvent));
			val.Clips = ((original.Clips != null) ? original.Clips.ToList() : null);
			val.VolumeRange = original.VolumeRange;
			val.PitchRange = original.PitchRange;
			val.ClipLengthRange = original.ClipLengthRange;
			return val;
		}
	}
	internal static class BoltStateExtensions
	{
		public static bool IsBoltHeldOpen(this ClosedBoltWeapon firearm)
		{
			if (!firearm.Bolt.IsBoltLocked() && !firearm.IsBoltCatchButtonHeld)
			{
				if (firearm.Bolt.HasLastRoundBoltHoldOpen && Object.op_Implicit((Object)(object)((FVRFireArm)firearm).Magazine) && !((FVRFireArm)firearm).Magazine.HasARound())
				{
					return !firearm.Chamber.IsFull;
				}
				return false;
			}
			return true;
		}

		public static bool WillBoltBeHeldOpenAfterNextShot(this ClosedBoltWeapon firearm)
		{
			if (!firearm.IsBoltCatchButtonHeld)
			{
				if (firearm.Bolt.HasLastRoundBoltHoldOpen && Object.op_Implicit((Object)(object)((FVRFireArm)firearm).Magazine))
				{
					return !((FVRFireArm)firearm).Magazine.HasARound();
				}
				return false;
			}
			return true;
		}

		public static bool IsSlideHeldOpen(this Handgun handgun)
		{
			if ((handgun == null || !handgun.DoesSafetyLockSlide || !handgun.IsSafetyEngaged) && !handgun.IsSLideLockMechanismEngaged)
			{
				return handgun.IsSlideCatchEngaged();
			}
			return true;
		}

		public static bool WillSlideBeHeldOpenAfterNextShot(this Handgun handgun)
		{
			if (handgun.HasSlideRelease && Object.op_Implicit((Object)(object)((FVRFireArm)handgun).Magazine))
			{
				return !((FVRFireArm)handgun).Magazine.HasARound();
			}
			return false;
		}

		public static bool IsTubeFedShotgunBoltHeldOpen(this TubeFedShotgun shotgun)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)shotgun.Mode == 1)
			{
				if (!shotgun.Bolt.m_isBoltLocked)
				{
					if (shotgun.Bolt.HasLastRoundBoltHoldOpen && Object.op_Implicit((Object)(object)((FVRFireArm)shotgun).Magazine) && !((FVRFireArm)shotgun).Magazine.HasARound())
					{
						return !shotgun.Chamber.IsFull;
					}
					return false;
				}
				return true;
			}
			return false;
		}

		public static bool WillTubeFedShotgunBoltBeHeldOpenAfterNextShot(this TubeFedShotgun shotgun)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)shotgun.Mode == 1 && shotgun.Bolt.HasLastRoundBoltHoldOpen && Object.op_Implicit((Object)(object)((FVRFireArm)shotgun).Magazine))
			{
				return !((FVRFireArm)shotgun).Magazine.HasARound();
			}
			return false;
		}
	}
	internal static class FVRFirearmAudioSetExtensions
	{
		public static FVRFirearmAudioSet DeepCopy(this FVRFirearmAudioSet original)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			FVRFirearmAudioSet obj = ScriptableObject.CreateInstance<FVRFirearmAudioSet>();
			((Object)obj).name = ((Object)original).name;
			((Object)obj).hideFlags = ((Object)original).hideFlags;
			obj.Loudness_Primary = original.Loudness_Primary;
			obj.Loudness_Suppressed = original.Loudness_Suppressed;
			obj.Loudness_OperationMult = original.Loudness_OperationMult;
			obj.FTP = original.FTP;
			obj.Shots_Main = original.Shots_Main.DeepCopy();
			obj.Shots_Suppressed = original.Shots_Suppressed.DeepCopy();
			obj.Shots_LowPressure = original.Shots_LowPressure.DeepCopy();
			obj.TailPitchMod_Main = original.TailPitchMod_Main;
			obj.TailPitchMod_Suppressed = original.TailPitchMod_Suppressed;
			obj.TailPitchMod_LowPressure = original.TailPitchMod_LowPressure;
			obj.TailConcurrentLimit = original.TailConcurrentLimit;
			obj.UsesTail_Main = original.UsesTail_Main;
			obj.UsesTail_Suppressed = original.UsesTail_Suppressed;
			obj.UsesLowPressureSet = original.UsesLowPressureSet;
			obj.BoltRelease = original.BoltRelease.DeepCopy();
			obj.BoltSlideBack = original.BoltSlideBack.DeepCopy();
			obj.BoltSlideBackHeld = original.BoltSlideBackHeld.DeepCopy();
			obj.BoltSlideBackLocked = original.BoltSlideBackLocked.DeepCopy();
			obj.BoltSlideForward = original.BoltSlideForward.DeepCopy();
			obj.BoltSlideForwardHeld = original.BoltSlideForwardHeld.DeepCopy();
			obj.BreachOpen = original.BreachOpen.DeepCopy();
			obj.BreachClose = original.BreachClose.DeepCopy();
			obj.BeltBulletSet = original.BeltBulletSet.DeepCopy();
			obj.CatchOnSear = original.CatchOnSear.DeepCopy();
			obj.ChamberManual = original.ChamberManual.DeepCopy();
			obj.FireSelector = original.FireSelector.DeepCopy();
			obj.HammerHit = original.HammerHit.DeepCopy();
			obj.HandleBack = original.HandleBack.DeepCopy();
			obj.HandleBackEmpty = original.HandleBackEmpty.DeepCopy();
			obj.HandleForward = original.HandleForward.DeepCopy();
			obj.HandleForwardEmpty = original.HandleForwardEmpty.DeepCopy();
			obj.HandleUp = original.HandleUp.DeepCopy();
			obj.HandleDown = original.HandleDown.DeepCopy();
			obj.HandleGrab = original.HandleGrab.DeepCopy();
			obj.MagazineIn = original.MagazineIn.DeepCopy();
			obj.MagazineOut = original.MagazineOut.DeepCopy();
			obj.MagazineInsertRound = original.MagazineInsertRound.DeepCopy();
			obj.MagazineEjectRound = original.MagazineEjectRound.DeepCopy();
			obj.Prefire = original.Prefire.DeepCopy();
			obj.Safety = original.Safety.DeepCopy();
			obj.TriggerReset = original.TriggerReset.DeepCopy();
			obj.TopCoverRelease = original.TopCoverRelease.DeepCopy();
			obj.TopCoverUp = original.TopCoverUp.DeepCopy();
			obj.TopCoverDown = original.TopCoverDown.DeepCopy();
			obj.StockOpen = original.StockOpen.DeepCopy();
			obj.StockClosed = original.StockClosed.DeepCopy();
			obj.BipodOpen = original.BipodOpen.DeepCopy();
			obj.BipodClosed = original.BipodClosed.DeepCopy();
			obj.BeltGrab = original.BeltGrab.DeepCopy();
			obj.BeltRelease = original.BeltRelease.DeepCopy();
			obj.BeltSeat = original.BeltSeat.DeepCopy();
			obj.BeltSettle = original.BeltSettle.DeepCopy();
			obj.BeltSettlingLimit = original.BeltSettlingLimit;
			return obj;
		}

		public static AudioEvent GetAudioEventBy(this FVRFirearmAudioSet clipSet, GunEvent.Value gunEvent)
		{
			return (AudioEvent)(gunEvent switch
			{
				GunEvent.Value.Shot => clipSet.Shots_Main, 
				GunEvent.Value.ShotSuppressed => clipSet.Shots_Suppressed, 
				GunEvent.Value.ShotLowPressure => clipSet.Shots_LowPressure, 
				GunEvent.Value.BoltRelease => clipSet.BoltRelease, 
				GunEvent.Value.BoltSlideBack => clipSet.BoltSlideBack, 
				GunEvent.Value.BoltSlideBackHeld => clipSet.BoltSlideBackHeld, 
				GunEvent.Value.BoltSlideBackLocked => clipSet.BoltSlideBackLocked, 
				GunEvent.Value.BoltSlideForward => clipSet.BoltSlideForward, 
				GunEvent.Value.BoltSlideForwardHeld => clipSet.BoltSlideForwardHeld, 
				GunEvent.Value.BreachOpen => clipSet.BreachOpen, 
				GunEvent.Value.BreachClose => clipSet.BreachClose, 
				GunEvent.Value.BeltBulletSet => clipSet.BeltBulletSet, 
				GunEvent.Value.CatchOnSear => clipSet.CatchOnSear, 
				GunEvent.Value.ChamberManual => clipSet.ChamberManual, 
				GunEvent.Value.FireSelector => clipSet.FireSelector, 
				GunEvent.Value.HammerHit => clipSet.HammerHit, 
				GunEvent.Value.HandleBack => clipSet.HandleBack, 
				GunEvent.Value.HandleBackEmpty => clipSet.HandleBackEmpty, 
				GunEvent.Value.HandleForward => clipSet.HandleForward, 
				GunEvent.Value.HandleForwardEmpty => clipSet.HandleForwardEmpty, 
				GunEvent.Value.HandleUp => clipSet.HandleUp, 
				GunEvent.Value.HandleDown => clipSet.HandleDown, 
				GunEvent.Value.HandleGrab => clipSet.HandleGrab, 
				GunEvent.Value.MagazineOut => clipSet.MagazineOut, 
				GunEvent.Value.MagazineIn => clipSet.MagazineIn, 
				GunEvent.Value.MagazineInsertRound => clipSet.MagazineInsertRound, 
				GunEvent.Value.MagazineEjectRound => clipSet.MagazineEjectRound, 
				GunEvent.Value.Prefire => clipSet.Prefire, 
				GunEvent.Value.Safety => clipSet.Safety, 
				GunEvent.Value.TriggerReset => clipSet.TriggerReset, 
				GunEvent.Value.TopCoverRelease => clipSet.TopCoverRelease, 
				GunEvent.Value.TopCoverUp => clipSet.TopCoverUp, 
				GunEvent.Value.TopCoverDown => clipSet.TopCoverDown, 
				GunEvent.Value.StockOpen => clipSet.StockOpen, 
				GunEvent.Value.StockClosed => clipSet.StockClosed, 
				GunEvent.Value.BipodOpen => clipSet.BipodOpen, 
				GunEvent.Value.BipodClosed => clipSet.BipodClosed, 
				GunEvent.Value.BeltGrab => clipSet.BeltGrab, 
				GunEvent.Value.BeltRelease => clipSet.BeltRelease, 
				GunEvent.Value.BeltSeat => clipSet.BeltSeat, 
				GunEvent.Value.BeltSettle => clipSet.BeltSettle, 
				_ => throw new NotSupportedException("Unsupported GunEvent"), 
			});
		}

		public static void ReplaceAudioEventBy(this FVRFirearmAudioSet clipSet, GunEvent.Value gunEvent, AudioEvent audioEvent)
		{
			switch (gunEvent)
			{
			case GunEvent.Value.BoltSlideForward:
				clipSet.BoltSlideForward = audioEvent;
				break;
			case GunEvent.Value.HandleForward:
				clipSet.HandleForward = audioEvent;
				break;
			default:
				throw new NotSupportedException("Unsupported GunEvent");
			}
		}
	}
	internal static class FVRFirearmMagazineAudioSetExtensions
	{
		public static FVRFirearmMagazineAudioSet DeepCopy(this FVRFirearmMagazineAudioSet original)
		{
			FVRFirearmMagazineAudioSet obj = ScriptableObject.CreateInstance<FVRFirearmMagazineAudioSet>();
			obj.MagazineIn = original.MagazineIn.DeepCopy();
			obj.MagazineOut = original.MagazineOut.DeepCopy();
			obj.MagazineInsertRound = original.MagazineInsertRound.DeepCopy();
			obj.MagazineEjectRound = original.MagazineEjectRound.DeepCopy();
			return obj;
		}
	}
}
namespace Sirdoggy.SideloaderMint.Model
{
	internal static class BoltSlideForwardCircumstance
	{
		public enum Value
		{
			ManualCharge,
			HandleSlap,
			Shot
		}

		public static Value[] All => Enum.GetValues(typeof(Value)).Cast<Value>().ToArray();

		public static string[] GetTargetPath(this Value value)
		{
			return value switch
			{
				Value.Shot => new string[1] { "AfterShot" }, 
				Value.HandleSlap => new string[2] { "AfterManualCharge", "AfterHKSlap" }, 
				Value.ManualCharge => new string[1] { "AfterManualCharge" }, 
				_ => throw new NotSupportedException("Unknown BoltSlideForwardCircumstance value"), 
			};
		}
	}
	internal static class GunEvent
	{
		public enum Value
		{
			Shot,
			ShotSuppressed,
			ShotLowPressure,
			BoltRelease,
			BoltSlideBack,
			BoltSlideBackHeld,
			BoltSlideBackLocked,
			BoltSlideForward,
			BoltSlideForwardHeld,
			BreachOpen,
			BreachClose,
			BeltBulletSet,
			CatchOnSear,
			ChamberManual,
			FireSelector,
			HammerHit,
			HandleBack,
			HandleBackEmpty,
			HandleForward,
			HandleForwardEmpty,
			HandleUp,
			HandleDown,
			HandleGrab,
			MagazineIn,
			MagazineOut,
			MagazineInsertRound,
			MagazineEjectRound,
			Prefire,
			Safety,
			TriggerReset,
			TopCoverRelease,
			TopCoverUp,
			TopCoverDown,
			StockOpen,
			StockClosed,
			BipodOpen,
			BipodClosed,
			BeltGrab,
			BeltRelease,
			BeltSeat,
			BeltSettle
		}

		public static Value[] All => Enum.GetValues(typeof(Value)).Cast<Value>().ToArray();
	}
	internal static class HandleForwardCircumstance
	{
		public enum Value
		{
			HandleSlap
		}

		public static Value[] All => Enum.GetValues(typeof(Value)).Cast<Value>().ToArray();

		public static string[] GetTargetPath(this Value value)
		{
			if (value == Value.HandleSlap)
			{
				return new string[1] { "AfterHKSlap" };
			}
			throw new NotSupportedException("Unknown BoltSlideForwardCircumstance value");
		}
	}
}
namespace Sirdoggy.SideloaderMint.Common
{
	internal class ConfigFileWrapper
	{
		public class SimpleConfigEntry<T>
		{
			public string Section { get; }

			public string Key { get; }

			public T DefaultValue { get; }

			public string? Description { get; }

			public NullableGeneric<T> SavedConfigValue { get; set; }

			public SimpleConfigEntry(string section, string key, T defaultValue, string? description = null)
			{
				Section = section;
				Key = key;
				DefaultValue = defaultValue;
				Description = description;
				SavedConfigValue = NullableGeneric<T>.Null;
				base..ctor();
			}

			public override string ToString()
			{
				return StringUtils.FormatTypeProperties("SimpleConfigEntry", new <>z__ReadOnlyArray<string>(new string[5]
				{
					"Section: " + Section,
					"Key: " + Key,
					string.Format("{0}: {1}", "DefaultValue", DefaultValue),
					"Description: " + Description,
					string.Format("{0}: {1}", "SavedConfigValue", SavedConfigValue)
				}));
			}
		}

		private readonly string _configFilePath;

		private ConfigFile _configFile;

		private readonly List<SimpleConfigEntry<bool>> _trackedBoolEntries = new List<SimpleConfigEntry<bool>>();

		private readonly List<SimpleConfigEntry<int>> _trackedIntEntries = new List<SimpleConfigEntry<int>>();

		public ConfigFileWrapper()
		{
		}

		public ConfigFileWrapper(string configFileName)
			: this()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			_configFilePath = Path.Combine(Paths.ConfigPath, configFileName);
			_configFile = new ConfigFile(_configFilePath, true);
		}

		public bool BindBool(SimpleConfigEntry<bool> simpleConfigEntry)
		{
			ConfigEntry<bool> val = BindFromSimpleConfigEntry(simpleConfigEntry);
			simpleConfigEntry.SavedConfigValue = val.Value;
			_trackedBoolEntries.Add(simpleConfigEntry);
			return val.Value;
		}

		public int BindInt(SimpleConfigEntry<int> simpleConfigEntry)
		{
			ConfigEntry<int> val = BindFromSimpleConfigEntry(simpleConfigEntry);
			simpleConfigEntry.SavedConfigValue = val.Value;
			_trackedIntEntries.Add(simpleConfigEntry);
			return val.Value;
		}

		public void ClearUntrackedEntries()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			Plugin.Log.LogDebug((object)"Recreating config file...");
			File.Delete(_configFilePath);
			_configFile = new ConfigFile(_configFilePath, true);
			foreach (SimpleConfigEntry<bool> trackedBoolEntry in _trackedBoolEntries)
			{
				Plugin.Log.LogDebug((object)$"Recreating {trackedBoolEntry}...");
				BindFromSimpleConfigEntry(trackedBoolEntry);
			}
			foreach (SimpleConfigEntry<int> trackedIntEntry in _trackedIntEntries)
			{
				Plugin.Log.LogDebug((object)$"Recreating {trackedIntEntry}...");
				BindFromSimpleConfigEntry(trackedIntEntry);
			}
			Plugin.Log.LogInfo((object)"Finished removing untracked config keys!");
		}

		private ConfigEntry<T> BindFromSimpleConfigEntry<T>(SimpleConfigEntry<T> simpleConfigEntry)
		{
			ConfigEntry<T> val = ((simpleConfigEntry.Description == null) ? _configFile.Bind<T>(simpleConfigEntry.Section, simpleConfigEntry.Key, simpleConfigEntry.DefaultValue, (ConfigDescription)null) : _configFile.Bind<T>(simpleConfigEntry.Section, simpleConfigEntry.Key, simpleConfigEntry.DefaultValue, simpleConfigEntry.Description));
			if (val == null)
			{
				throw new NullReferenceException("configEntry is null, this shouldn't happen");
			}
			if (simpleConfigEntry.SavedConfigValue.HasValue)
			{
				val.Value = simpleConfigEntry.SavedConfigValue.Value;
				_configFile.Save();
			}
			return val;
		}
	}
	internal static class DictionaryExtensions
	{
		public static TValue GetOrCreateDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key) where TValue : new()
		{
			if (!dictionary.ContainsKey(key))
			{
				dictionary.Add(key, new TValue());
			}
			return dictionary[key];
		}

		public static bool AddIfUnique<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue value)
		{
			if (!dictionary.ContainsKey(key))
			{
				dictionary.Add(key, value);
				return true;
			}
			return false;
		}

		public static TValue? GetValueOrNull<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key) where TKey : notnull where TValue : class
		{
			if (!dictionary.TryGetValue(key, out TValue value))
			{
				return null;
			}
			return value;
		}
	}
	internal static class ListExtensions
	{
		public static bool AddIfUnique<T>(this List<T> list, T value)
		{
			if (!list.Contains(value))
			{
				list.Add(value);
				return true;
			}
			return false;
		}
	}
	internal class ExceptionCatcher
	{
		private readonly ManualLogSource _log;

		public ExceptionCatcher(ManualLogSource log)
		{
			_log = log;
		}

		public void Run(Action action)
		{
			try
			{
				action();
			}
			catch (Exception ex)
			{
				_log.LogError((object)ex);
			}
		}
	}
	internal readonly struct NullableGeneric<T>
	{
		private readonly T _value;

		public bool HasValue { get; }

		public T Value
		{
			get
			{
				if (!HasValue)
				{
					throw new InvalidOperationException("NullableGeneric has no value.");
				}
				return _value;
			}
		}

		public static NullableGeneric<T> Null => default(NullableGeneric<T>);

		public NullableGeneric(T value)
		{
			HasValue = false;
			_value = value;
			HasValue = true;
		}

		public override string ToString()
		{
			if (!HasValue)
			{
				return "null";
			}
			T value = _value;
			return ((value != null) ? value.ToString() : null) ?? "null";
		}

		public static implicit operator NullableGeneric<T>(T value)
		{
			return new NullableGeneric<T>(value);
		}
	}
	internal static class ReflectionExtensions
	{
		public static T Access<T>(this object obj, FieldInfo field)
		{
			return (T)field.GetValue(obj);
		}

		public static Action<T> Delegate<T>(string methodName)
		{
			return (Action<T>)System.Delegate.CreateDelegate(typeof(Action<T>), AccessTools.Method(typeof(T), methodName, (Type[])null, (Type[])null));
		}

		public static Action<T, TParam1> Delegate<T, TParam1>(string methodName)
		{
			return (Action<T, TParam1>)System.Delegate.CreateDelegate(typeof(Action<T, TParam1>), AccessTools.Method(typeof(T), methodName, (Type[])null, (Type[])null));
		}
	}
	internal static class StreamExtensions
	{
		public static void CopyTo(this Stream from, Stream to)
		{
			byte[] array = new byte[4096];
			int count;
			while ((count = from.Read(array, 0, array.Length)) > 0)
			{
				to.Write(array, 0, count);
			}
		}
	}
	internal static class StringUtils
	{
		public static string FormatTypeProperties<T>(string nameOfType, [ParamCollection] IEnumerable<T> properties)
		{
			if (properties is string)
			{
				return $"{nameOfType}({properties})";
			}
			return nameOfType + "(" + JoinValues(properties) + ")";
		}

		public static string JoinValues<T>(IEnumerable<T> values, string seperator = ", ")
		{
			string[] value = values.Select((T element) => element?.ToString()).ToArray();
			return string.Join(seperator, value);
		}

		public static string RemoveFirstOccurenceOf(string input, string toRemove)
		{
			int num = input.IndexOf(toRemove, StringComparison.Ordinal);
			if (num < 0)
			{
				return input;
			}
			return input.Remove(num, toRemove.Length);
		}
	}
	public class WavUtility
	{
		private class BitReader
		{
			public int SizeOf { get; set; }

			public Func<BinaryReader, float> Reader { get; set; }

			public int MaxValue { get; set; }
		}

		private static readonly Dictionary<int, BitReader> readers = new Dictionary<int, BitReader>
		{
			[8] = new BitReader
			{
				MaxValue = 127,
				SizeOf = 1,
				Reader = (BinaryReader br) => br.ReadSByte()
			},
			[16] = new BitReader
			{
				MaxValue = 32767,
				SizeOf = 2,
				Reader = (BinaryReader br) => br.ReadInt16()
			},
			[24] = new BitReader
			{
				MaxValue = int.MaxValue,
				SizeOf = 3,
				Reader = delegate(BinaryReader br)
				{
					byte[] array = new byte[4];
					br.Read(array, 1, 3);
					return BitConverter.ToInt32(array, 0);
				}
			},
			[32] = new BitReader
			{
				MaxValue = int.MaxValue,
				SizeOf = 4,
				Reader = (BinaryReader br) => br.ReadInt32()
			}
		};

		public static AudioClip ToAudioClip(BinaryReader br, string name = "wav")
		{
			br.BaseStream.Position = 16L;
			int num = br.ReadInt32();
			ushort num2 = br.ReadUInt16();
			string arg = FormatCode(num2);
			if (num2 != 1 && num2 != 65534)
			{
				throw new Exception($"Detected format code '{arg}' ({num2}), but only PCM and WaveFormatExtensable uncompressed formats are currently supported.");
			}
			ushort num3 = br.ReadUInt16();
			int num4 = br.ReadInt32();
			br.ReadInt32();
			br.ReadUInt16();
			ushort key = br.ReadUInt16();
			br.BaseStream.Position = 20 + num + 4;
			int dataSize = br.ReadInt32();
			if (readers.TryGetValue(key, out BitReader value))
			{
				float[] array = ReadAudioClipSamples(br, value, dataSize);
				AudioClip obj = AudioClip.Create(name, array.Length, (int)num3, num4, false);
				obj.SetData(array, 0);
				return obj;
			}
			throw new Exception(key + " bit depth is not supported.");
		}

		private static float[] ReadAudioClipSamples(BinaryReader br, BitReader reader, int dataSize)
		{
			float[] array = new float[dataSize / reader.SizeOf];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = reader.Reader(br) / (float)reader.MaxValue;
			}
			return array;
		}

		private static string FormatCode(ushort code)
		{
			switch (code)
			{
			case 1:
				return "PCM";
			case 2:
				return "ADPCM";
			case 3:
				return "IEEE";
			case 7:
				return "μ-law";
			case 65534:
				return "WaveFormatExtensable";
			default:
				Debug.LogWarning((object)("Unknown wav code format:" + code));
				return "";
			}
		}
	}
}
namespace Sirdoggy.SideloaderMint.Common.Validation
{
	internal static class PathValidator
	{
		public static void ValidatePathIsPartOfBasePath(string basePath, string actualFullPath)
		{
			string text = Path.GetFullPath(basePath).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			string value = text + directorySeparatorChar;
			if (!Path.GetFullPath(actualFullPath).StartsWith(value, StringComparison.OrdinalIgnoreCase))
			{
				throw new UnauthorizedAccessException("Path '" + actualFullPath + "' is not allowed to access resource outside of base path '" + basePath + "'");
			}
		}
	}
	internal static class StrictDeserializer
	{
		private static readonly JsonSerializer Serializer = JsonSerializer.Create(new JsonSerializerSettings
		{
			MissingMemberHandling = (MissingMemberHandling)1
		});

		public static T Deserialize<T>(JObject jObject)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			JToken val = default(JToken);
			if (jObject.TryGetValue("$schema", ref val))
			{
				Plugin.Log.LogDebug((object)"Removing $schema from jObject");
				jObject.Remove("$schema");
			}
			JsonReader val2 = ((JToken)jObject).CreateReader() ?? throw new Exception("Failed to create json reader.");
			T val3 = Serializer.Deserialize<T>(val2);
			if (val3 == null)
			{
				throw new JsonSerializationException("Json deserialization failed.");
			}
			return val3;
		}
	}
	public static class ThunderstoreNameValidator
	{
		public static bool IsValid(string text)
		{
			return Regex.IsMatch(text, "^[a-zA-Z0-9_]+$");
		}
	}
	public static class SubAddonNameValidator
	{
		public static bool IsValid(string text)
		{
			return Regex.IsMatch(text, "^[a-zA-Z0-9_ .,()]+$");
		}
	}
}
namespace Sirdoggy.SideloaderMint.Common.Structures
{
	public class AssetTree<TAsset>
	{
		public abstract class FindBehaviour
		{
			public sealed class GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment : FindBehaviour
			{
			}

			public sealed class GetMostSpecificThatMatchesQuery : FindBehaviour
			{
			}

			public sealed class GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel : FindBehaviour
			{
			}

			public sealed class GetMostSpecificThatMatchesQueryAndSpecifications : FindBehaviour
			{
				public int MinLevel { get; }

				public int MaxLevel { get; }

				public GetMostSpecificThatMatchesQueryAndSpecifications(int minLevel, int maxLevel)
				{
					MinLevel = minLevel;
					MaxLevel = maxLevel;
					base..ctor();
				}
			}
		}

		public interface INode
		{
		}

		public abstract class TraversableNode : INode
		{
			public IntermediateNode? IntermediateWildcardChild;

			public AssetNode? AssetNodeChild;

			public abstract int Level { get; }

			public Dictionary<string, IntermediateNode> IntermediateChildren { get; } = new Dictionary<string, IntermediateNode>();


			public List<INode> Children
			{
				get
				{
					List<INode> list = new List<INode>();
					list.AddRange(IntermediateChildren.Values.Cast<INode>());
					if (IntermediateWildcardChild != null)
					{
						list.Add(IntermediateWildcardChild);
					}
					if (AssetNodeChild != null)
					{
						list.Add(AssetNodeChild);
					}
					return list;
				}
			}

			protected abstract string ReadableName { get; }

			protected abstract string[] ReadableProperties { get; }

			public override string ToString()
			{
				string value = StringUtils.FormatTypeProperties(ReadableName, ReadableProperties);
				StringBuilder stringBuilder = new StringBuilder().Append(' ', Level * 2 + 2).Append((Level == 0) ? "  " : "└─").Append(value);
				foreach (INode child in Children)
				{
					stringBuilder.Append($"\n{child}");
				}
				return stringBuilder.ToString();
			}
		}

		public sealed class RootNode : TraversableNode
		{
			public override int Level => 0;

			protected override string ReadableName => "RootNode";

			protected override string[] ReadableProperties => new string[1] { string.Format("{0}: {1}", "Level", Level) };
		}

		public sealed class IntermediateNode : TraversableNode
		{
			public override int Level { get; }

			public string? TargetSegment { get; }

			protected override string ReadableName => "IntermediateNode";

			protected override string[] ReadableProperties => new string[2]
			{
				string.Format("{0}: {1}", "Level", Level),
				"TargetSegment: " + (TargetSegment ?? "*")
			};

			public IntermediateNode(int level, string? targetSegment)
			{
				Level = level;
				TargetSegment = targetSegment;
				base..ctor();
			}
		}

		public sealed class AssetNode : INode
		{
			public int Level { get; }

			public TAsset Asset { get; }

			public string? FinalTargetSegment { get; }

			public AssetNode(int level, TAsset asset, string? finalTargetSegment)
			{
				Level = level;
				Asset = asset;
				FinalTargetSegment = finalTargetSegment;
				base..ctor();
			}

			public override string ToString()
			{
				string value = StringUtils.FormatTypeProperties("AssetNode", new <>z__ReadOnlyArray<string>(new string[3]
				{
					string.Format("{0}: {1}", "Level", Level),
					string.Format("{0}: {1}", "Asset", Asset),
					"FinalTargetSegment: " + (FinalTargetSegment ?? "null")
				}));
				return new StringBuilder().Append(' ', Level * 2 + 2).Append("└─").Append(value)
					.ToString();
			}
		}

		[CompilerGenerated]
		private int <maxIntermediateLevels>P;

		[CompilerGenerated]
		private Action<string>? <onTargetConflict>P;

		private readonly RootNode _rootNode;

		public AssetTree(int maxIntermediateLevels, Action<string>? onTargetConflict = null)
		{
			<maxIntermediateLevels>P = maxIntermediateLevels;
			<onTargetConflict>P = onTargetConflict;
			_rootNode = new RootNode();
			base..ctor();
		}

		public void AddAssetToTree(string target, TAsset asset, bool parseAsterisksAsWildcards = true)
		{
			string[] array = (from part in target.Split(new char[1] { ':' })
				select part.Trim() into part
				select (part.Length != 0) ? part : null).Reverse().SkipWhile((string part) => part == null).Reverse()
				.ToArray();
			if (parseAsterisksAsWildcards)
			{
				array = array.Select((string part) => (!(part == "*")) ? part : null).ToArray();
			}
			if (array.Length > <maxIntermediateLevels>P)
			{
				throw new ArgumentException("Can't add asset to AssetTree because target '" + target + "' consists " + $"of more than {<maxIntermediateLevels>P} segments.");
			}
			TraversableNode traversableNode = _rootNode;
			string[] array2 = array;
			foreach (string text in array2)
			{
				IntermediateNode intermediateNode;
				if (text == null)
				{
					intermediateNode = ((traversableNode.IntermediateWildcardChild != null) ? traversableNode.IntermediateWildcardChild : (traversableNode.IntermediateWildcardChild = new IntermediateNode(traversableNode.Level + 1, null)));
				}
				else
				{
					IntermediateNode valueOrNull = traversableNode.IntermediateChildren.GetValueOrNull(text);
					if (valueOrNull == null)
					{
						intermediateNode = new IntermediateNode(traversableNode.Level + 1, text);
						traversableNode.IntermediateChildren.Add(text, intermediateNode);
					}
					else
					{
						intermediateNode = valueOrNull;
					}
				}
				traversableNode = intermediateNode;
			}
			if (traversableNode.AssetNodeChild != null)
			{
				<onTargetConflict>P?.Invoke(target);
				return;
			}
			AssetNode assetNodeChild = new AssetNode(traversableNode.Level + 1, asset, (array.Length == <maxIntermediateLevels>P && <maxIntermediateLevels>P > 0) ? array[<maxIntermediateLevels>P - 1] : null);
			traversableNode.AssetNodeChild = assetNodeChild;
		}

		public AssetNode[] Find(FindBehaviour behaviour, params string[] segmentedQuery)
		{
			string[] segmentedQuery2 = segmentedQuery;
			FindBehaviour behaviour2 = behaviour;
			if (segmentedQuery2.Length > <maxIntermediateLevels>P)
			{
				throw new ArgumentException("Segmented query is longer than max intermediate levels");
			}
			AssetNode[] array = SearchIntermediateNodesInNode(_rootNode);
			if (array.Length != 0)
			{
				return array;
			}
			if (behaviour2 is FindBehaviour.GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel && segmentedQuery2.Length != 0)
			{
				return new AssetNode[0];
			}
			if (_rootNode.AssetNodeChild != null)
			{
				return new AssetNode[1] { _rootNode.AssetNodeChild };
			}
			return new AssetNode[0];
			static void CollectAllChildNodesFromCurrent(TraversableNode currentNode, List<AssetNode> collectedAssetNodes)
			{
				foreach (IntermediateNode value in currentNode.IntermediateChildren.Values)
				{
					CollectAllChildNodesFromCurrent(value, collectedAssetNodes);
				}
				if (currentNode.IntermediateWildcardChild != null)
				{
					CollectAllChildNodesFromCurrent(currentNode.IntermediateWildcardChild, collectedAssetNodes);
				}
				if (currentNode.AssetNodeChild != n