Decompiled source of SideloaderMint v1.1.1

Sirdoggy.SideloaderMint.dll

Decompiled a week 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.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FistVR;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Sirdoggy.SideloaderMint.Addons;
using Sirdoggy.SideloaderMint.Addons.Data;
using Sirdoggy.SideloaderMint.Addons.Model;
using Sirdoggy.SideloaderMint.AssetLoaders;
using Sirdoggy.SideloaderMint.AssetLoaders.Implementations;
using Sirdoggy.SideloaderMint.Common;
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 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("Updated version of Sideloader with new features")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: AssemblyInformationalVersion("1.1.1")]
[assembly: AssemblyProduct("Sirdoggy.SideloaderMint")]
[assembly: AssemblyTitle("SideloaderMint")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class ParamCollectionAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace 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 int HarmonyPriority = 300;

		public static string PluginDirectory => Path.Combine(Paths.PluginPath, "Sirdoggy.SideloaderMint".Replace('.', '-'));
	}
	internal static class MainAddonLoader
	{
		private const string AddonFolderName = "SideloaderMint";

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

		private static readonly GunSoundLoader GunSoundLoader = new GunSoundLoader();

		private static readonly GunAudioSetLoader GunAudioSetLoader = new GunAudioSetLoader();

		private static readonly AudioClipLoader AudioClipLoader = new AudioClipLoader();

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

		internal static void InitializeAssetLoadersAndLoadAddons()
		{
			FVRFireArmPatcher.Initialize(GunSoundLoader, GunAudioSetLoader);
			AudioSourcePatcher.Initialize(AudioClipLoader);
			Plugin.Log.LogMessage((object)"Loading addons...");
			List<string> list = new List<string>();
			string[] directories;
			if (Directory.Exists(LegacyAddonsPath))
			{
				directories = Directory.GetDirectories(LegacyAddonsPath, "*", SearchOption.TopDirectoryOnly);
				foreach (string text in directories)
				{
					if (File.Exists(Path.Combine(text, "manifest.json")))
					{
						list.Add(text);
					}
				}
			}
			directories = Directory.GetDirectories(Paths.PluginPath, "*", SearchOption.TopDirectoryOnly);
			for (int i = 0; i < directories.Length; i++)
			{
				string text2 = Path.Combine(directories[i], "SideloaderMint");
				if (!Directory.Exists(text2))
				{
					continue;
				}
				if (File.Exists(Path.Combine(text2, "manifest.json")))
				{
					list.Add(text2);
					continue;
				}
				string[] directories2 = Directory.GetDirectories(text2, "*", SearchOption.TopDirectoryOnly);
				foreach (string text3 in directories2)
				{
					if (File.Exists(Path.Combine(text3, "manifest.json")))
					{
						list.Add(text3);
					}
				}
			}
			Dictionary<string, Addon> dictionary = new Dictionary<string, Addon>();
			int num = 0;
			foreach (string item in list)
			{
				try
				{
					Addon addon = new Addon(item, requireUniqueAddonDirectoryName: false);
					if (addon.Manifest.Disabled)
					{
						Plugin.Log.LogInfo((object)("Skipped addon '" + addon.GUID + "' because it's disabled in the manifest."));
						num++;
					}
					else if (dictionary.ContainsKey(addon.GUID))
					{
						Plugin.Log.LogError((object)("Failed to load addon '" + addon.GUID + "' because an addon with the same GUID was already loaded."));
					}
					else
					{
						Plugin.Log.LogInfo((object)("Loaded addon '" + addon.GUID + "'"));
						dictionary.Add(addon.GUID, addon);
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("Failed to load addon from path: " + item + $"\n- Cause: {ex.GetType()}" + "\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.");
			}
			Plugin.Log.LogInfo((object)stringBuilder.ToString());
			try
			{
				IAssetLoader[] allAssetLoaders = AllAssetLoaders;
				foreach (IAssetLoader assetLoader in allAssetLoaders)
				{
					Plugin.Log.LogMessage((object)$"Initializing '{assetLoader}'...)'");
					assetLoader.Initialize(dictionary.Values);
				}
				Plugin.Log.LogInfo((object)"Successfully initialized all asset loaders!");
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogFatal((object)("An exception has occured while initializing asset loaders, some of your installed addons will likely not work!" + $"\n- Cause: {ex2.GetType()}" + "\n- Message: " + ex2.Message));
			}
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInProcess("h3vr.exe")]
	[BepInPlugin("Sirdoggy.SideloaderMint", "SideloaderMint", "1.1.1")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log = null;

		internal static readonly PluginConfig PluginConfig = new PluginConfig();

		public const string Id = "Sirdoggy.SideloaderMint";

		public static string Name => "SideloaderMint";

		public static string Version => "1.1.1";

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

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			ResourceRedirection.EnableSyncOverAsyncAssetLoads();
			Harmony.CreateAndPatchAll(typeof(AudioSourcePatcher), (string)null);
			Harmony.CreateAndPatchAll(typeof(FVRFireArmPatcher), (string)null);
			Harmony.CreateAndPatchAll(typeof(FVRFireArmMagazinePatcher), (string)null);
			Harmony.CreateAndPatchAll(typeof(ClosedBoltHandlePatcher), (string)null);
			Harmony.CreateAndPatchAll(typeof(ClosedBoltPatcher), (string)null);
			Harmony.CreateAndPatchAll(typeof(HandgunSlidePatcher), (string)null);
			Harmony.CreateAndPatchAll(typeof(TubeFedShotgunBoltPatcher), (string)null);
			Harmony.CreateAndPatchAll(typeof(TubeFedShotgunHandlePatcher), (string)null);
			MainAddonLoader.InitializeAssetLoadersAndLoadAddons();
		}
	}
	internal class PluginConfig
	{
		private const string ConfigFileName = "Sirdoggy.SideloaderMint.cfg";

		public ConfigEntry<bool> VerboseDebugLogs { get; }

		public PluginConfig()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			ConfigFile val = new ConfigFile(Path.Combine(Paths.ConfigPath, "Sirdoggy.SideloaderMint.cfg"), true);
			VerboseDebugLogs = val.Bind<bool>("Developer Settings", "VerboseDebugLogs", false, "Enables verbose debug logs. These will noticeably spam the console.");
		}
	}
}
namespace Sirdoggy.SideloaderMint.Patchers
{
	[HarmonyWrapSafe]
	[HarmonyPriority(300)]
	[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)
		{
			if (!Object.op_Implicit((Object)(object)__instance.clip))
			{
				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.LoadedAudioClips.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.Replacements.Length);
				ReplacementAsset replacement = value.Replacements[num];
				AudioClip clip = value.Addon.LoadAudioClip(replacement, ((Object)__instance.clip).name);
				__instance.clip = clip;
				float[] volumeRange = value.VolumeRange;
				float[] pitchRange = value.PitchRange;
				if (volumeRange != null)
				{
					float volume = Random.Range(volumeRange[0], volumeRange[1]);
					__instance.volume = volume;
				}
				if (pitchRange != null)
				{
					float pitch = Random.Range(pitchRange[0], pitchRange[1]);
					__instance.pitch = pitch;
				}
				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();
			}
		}

		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)
								{
									ReplacementAsset[] replacements = assetMapping.Replacements;
									if (replacements != null)
									{
										num = ((replacements.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)
								{
									ReplacementAsset[] replacements = assetMapping.Replacements;
									if (replacements != null)
									{
										num2 = ((replacements.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)
		{
			if (!Object.op_Implicit((Object)(object)((FVRPhysicalObject)__instance).ObjectWrapper))
			{
				return;
			}
			string itemID = ((FVRPhysicalObject)__instance).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.op_Implicit((Object)(object)__instance.AudioClipSet))
			{
				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)__instance.AudioClipSet).name;
			Plugin.Log.LogMessage((object)("Attempting to replace audio for firearm with ItemID '" + itemID + "' and audio set '" + name + "'"));
			FVRFirearmAudioSet val = (__instance.AudioClipSet = __instance.AudioClipSet.DeepCopy());
			FirearmTag firearmTag = ((Component)__instance).GetComponent<FirearmTag>();
			if (!Object.op_Implicit((Object)(object)firearmTag))
			{
				firearmTag = ((Component)__instance).gameObject.AddComponent<FirearmTag>();
				((Object)firearmTag).hideFlags = (HideFlags)61;
			}
			GunEvent.Value[] all = GunEvent.All;
			for (int i = 0; i < all.Length; i++)
			{
				GunEvent.Value gunEvent = all[i];
				string text = itemID + ":" + gunEvent;
				string text2 = name + ":" + gunEvent;
				Plugin.LogVerbose("Attempting to replace firearm audio for '" + text + "' and '" + text2 + "'");
				AssetTree<AddonAsset>.AssetNode assetNode = _gunAudioSetLoader.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQuery(), name, 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)
							{
								ReplacementAsset[] replacements = assetMapping.Replacements;
								if (replacements != null)
								{
									num = ((replacements.Length > 0) ? 1 : 0);
									goto IL_021e;
								}
							}
						}
					}
					num = 0;
					goto IL_021e;
					IL_0253:
					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;
						val.ReplaceAudioEventByGunEventFromAddonAsset(asset2, gunEvent);
					}
					else
					{
						AddonAsset asset3 = assetNode.Asset;
						val.ReplaceAudioEventByGunEventFromAddonAsset(asset3, gunEvent);
					}
					goto end_IL_01e9;
					IL_021e:
					if (assetNode2 != null)
					{
						AddonAsset asset = assetNode2.Asset;
						if (asset != null)
						{
							AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
							if (assetMapping != null)
							{
								ReplacementAsset[] replacements = assetMapping.Replacements;
								if (replacements != null)
								{
									num2 = ((replacements.Length > 0) ? 1 : 0);
									goto IL_0253;
								}
							}
						}
					}
					num2 = 0;
					goto IL_0253;
					end_IL_01e9:;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("Failed to replace audio for '" + text + "' and '" + text2 + "'" + $"\n- Cause: {ex.GetType()}" + "\n- Message: " + ex.Message));
				}
			}
			SaveSlideForwardOverrideAudioEventsInFirearmTag(itemID, name, firearmTag, val);
			SaveHandleForwardOverrideAudioEventsInFirearmTag(itemID, name, firearmTag, val);
			Plugin.LogVerbose($"FirearmTag initialization finished ({firearmTag})");
		}

		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)
							{
								ReplacementAsset[] replacements = assetMapping.Replacements;
								if (replacements != null)
								{
									num = ((replacements.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)
							{
								ReplacementAsset[] replacements = assetMapping.Replacements;
								if (replacements != null)
								{
									num2 = ((replacements.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)
							{
								ReplacementAsset[] replacements = assetMapping.Replacements;
								if (replacements != null)
								{
									num = ((replacements.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)
							{
								ReplacementAsset[] replacements = assetMapping.Replacements;
								if (replacements != null)
								{
									num2 = ((replacements.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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			AddonAsset addonAsset2 = addonAsset;
			List<AudioClip> clips = addonAsset2.AssetMapping.Replacements.Select((ReplacementAsset replacement) => addonAsset2.SourceAddon.LoadAudioClip(replacement, ReplacementAudioClipName)).ToList();
			audioEvent.Clips = clips;
			float[] array = (addonAsset2.AssetMapping as AddonManifest.AssetMapping.Audio)?.VolumeRange;
			float[] array2 = (addonAsset2.AssetMapping as AddonManifest.AssetMapping.Audio)?.PitchRange;
			if (array != null)
			{
				Vector2 volumeRange = default(Vector2);
				((Vector2)(ref volumeRange))..ctor(array[0], array[1]);
				audioEvent.VolumeRange = volumeRange;
			}
			if (array2 != null)
			{
				Vector2 pitchRange = default(Vector2);
				((Vector2)(ref pitchRange))..ctor(array2[0], array2[1]);
				audioEvent.PitchRange = pitchRange;
			}
		}
	}
}
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 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 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 Validate(string basePath, string relativePath)
		{
			string fullPath = Path.GetFullPath(basePath);
			if (!Path.GetFullPath(Path.Combine(fullPath, relativePath)).StartsWith(fullPath, StringComparison.OrdinalIgnoreCase))
			{
				throw new UnauthorizedAccessException("Path '" + relativePath + "' is not allowed to access resource outside of its 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_0020: Unknown result type (might be due to invalid IL or missing references)
			JsonReader val = ((JToken)jObject).CreateReader();
			T val2 = Serializer.Deserialize<T>(val);
			if (val2 == null)
			{
				throw new JsonSerializationException("Deserialization failed");
			}
			return val2;
		}
	}
}
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
		{
			int Level { get; }
		}

		public abstract class TraversableNode : INode
		{
			public abstract int Level { get; }

			public List<INode> Children { get; } = new List<INode>();


			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;

		private readonly RootNode _rootNode;

		public AssetTree(int maxIntermediateLevels)
		{
			<maxIntermediateLevels>P = maxIntermediateLevels;
			_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 segment in array2)
			{
				IntermediateNode intermediateNode = traversableNode.Children.Where((INode node) => node is IntermediateNode).Cast<IntermediateNode>().FirstOrDefault((IntermediateNode node) => node.TargetSegment == segment);
				if (intermediateNode == null)
				{
					intermediateNode = new IntermediateNode(traversableNode.Level + 1, segment);
					traversableNode.Children.Add(intermediateNode);
				}
				traversableNode = intermediateNode;
			}
			AssetNode item = new AssetNode(traversableNode.Level + 1, asset, (array.Length == <maxIntermediateLevels>P && <maxIntermediateLevels>P > 0) ? array[<maxIntermediateLevels>P - 1] : null);
			traversableNode.Children.Add(item);
		}

		public AssetNode[] Find(FindBehaviour behaviour, params string[] segmentedQuery)
		{
			string[] segmentedQuery2 = segmentedQuery;
			FindBehaviour behaviour2 = behaviour;
			AssetNode[] array = SearchIntermediateNodesInNode(_rootNode);
			if (array.Length != 0)
			{
				return array;
			}
			if (behaviour2 is FindBehaviour.GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel && segmentedQuery2.Length != 0)
			{
				return new AssetNode[0];
			}
			return _rootNode.Children.Where((INode node) => node is AssetNode).Cast<AssetNode>().ToArray();
			static void CollectAllChildNodesFromCurrent(TraversableNode currentNode, List<AssetNode> collectedAssetNodes)
			{
				foreach (INode child in currentNode.Children)
				{
					if (!(child is AssetNode item))
					{
						if (child is TraversableNode currentNode2)
						{
							CollectAllChildNodesFromCurrent(currentNode2, collectedAssetNodes);
						}
					}
					else
					{
						collectedAssetNodes.Add(item);
					}
				}
			}
			AssetNode[] FindInIntermediateLevel(IntermediateNode nodeToSearch)
			{
				string text = ((nodeToSearch.Level <= segmentedQuery2.Length) ? segmentedQuery2[nodeToSearch.Level - 1] : null);
				if (nodeToSearch.TargetSegment != null && nodeToSearch.TargetSegment != text)
				{
					return new AssetNode[0];
				}
				if (behaviour2 is FindBehaviour.GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment && nodeToSearch.Level >= segmentedQuery2.Length)
				{
					List<AssetNode> list = new List<AssetNode>();
					CollectAllChildNodesFromCurrent(nodeToSearch, list);
					return list.ToArray();
				}
				AssetNode[] array2 = SearchIntermediateNodesInNode(nodeToSearch);
				if (array2.Length != 0)
				{
					return array2;
				}
				if (behaviour2 is FindBehaviour.GetMostSpecificThatMatchesQueryAndSpecifications getMostSpecificThatMatchesQueryAndSpecifications && (nodeToSearch.Level < getMostSpecificThatMatchesQueryAndSpecifications.MinLevel || nodeToSearch.Level > getMostSpecificThatMatchesQueryAndSpecifications.MaxLevel))
				{
					return new AssetNode[0];
				}
				if (behaviour2 is FindBehaviour.GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel && nodeToSearch.Level <= segmentedQuery2.Length - 1)
				{
					return new AssetNode[0];
				}
				return nodeToSearch.Children.Where((INode node) => node is AssetNode).Cast<AssetNode>().ToArray();
			}
			AssetNode[] SearchIntermediateNodesInNode(TraversableNode nodeToSearch)
			{
				foreach (IntermediateNode item2 in from IntermediateNode node in nodeToSearch.Children.Where((INode node) => node is IntermediateNode)
					where node.TargetSegment != null
					select node)
				{
					AssetNode[] array3 = FindInIntermediateLevel(item2);
					if (array3.Length != 0)
					{
						return array3;
					}
				}
				foreach (IntermediateNode item3 in from IntermediateNode node in nodeToSearch.Children.Where((INode node) => node is IntermediateNode)
					where node.TargetSegment == null
					select node)
				{
					AssetNode[] array4 = FindInIntermediateLevel(item3);
					if (array4.Length != 0)
					{
						return array4;
					}
				}
				return new AssetNode[0];
			}
		}

		public override string ToString()
		{
			return string.Format("AssetTree({0}: {1})", "maxIntermediateLevels", <maxIntermediateLevels>P) + $"\n{_rootNode}";
		}
	}
}
namespace Sirdoggy.SideloaderMint.Common.Coroutines
{
	internal class CoroutineRunner : MonoBehaviour
	{
		private static CoroutineRunner _instance;

		public static Coroutine Run(IEnumerator coroutine)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)_instance))
			{
				GameObject val = new GameObject("CoroutineRunner")
				{
					hideFlags = (HideFlags)61
				};
				Object.DontDestroyOnLoad((Object)val);
				_instance = val.AddComponent<CoroutineRunner>();
			}
			return ((MonoBehaviour)_instance).StartCoroutine(coroutine);
		}
	}
}
namespace Sirdoggy.SideloaderMint.AssetLoaders
{
	internal class AddonAsset
	{
		public AddonManifest.AssetMapping AssetMapping { get; }

		public Addon SourceAddon { get; }

		public AddonAsset(AddonManifest.AssetMapping assetMapping, Addon addon)
		{
			AssetMapping = assetMapping;
			SourceAddon = addon;
			base..ctor();
		}
	}
	internal interface IAssetLoader
	{
		void Initialize(IEnumerable<Addon> addons);
	}
}
namespace Sirdoggy.SideloaderMint.AssetLoaders.Implementations
{
	internal class AudioClipLoader : IAssetLoader
	{
		internal class AddonEntry
		{
			public Addon Addon { get; }

			public ReplacementAsset[] Replacements { get; }

			public float[]? VolumeRange { get; }

			public float[]? PitchRange { get; }

			public AddonEntry(Addon addon, ReplacementAsset[] replacements, float[]? volumeRange, float[]? pitchRange)
			{
				Addon = addon;
				Replacements = replacements;
				VolumeRange = volumeRange;
				PitchRange = pitchRange;
				base..ctor();
			}
		}

		internal readonly Dictionary<string, AddonEntry> LoadedAudioClips = new Dictionary<string, AddonEntry>(StringComparer.OrdinalIgnoreCase);

		public void Initialize(IEnumerable<Addon> addons)
		{
			foreach (Addon addon in addons)
			{
				foreach (AddonManifest.AssetMapping item in addon.Manifest.AssetMappings.Where((AddonManifest.AssetMapping assetMapping) => assetMapping.AssetType == AddonManifest.AssetType.AudioClip))
				{
					float[] volumeRange = (item as AddonManifest.AssetMapping.Audio)?.VolumeRange;
					float[] pitchRange = (item as AddonManifest.AssetMapping.Audio)?.PitchRange;
					AddonEntry value = new AddonEntry(addon, item.Replacements, volumeRange, pitchRange);
					string[] targets = item.Targets;
					foreach (string text in targets)
					{
						if (LoadedAudioClips.TryGetValue(text, out AddonEntry value2))
						{
							Plugin.Log.LogWarning((object)("[" + addon.GUID + "] AudioClip " + text + " is already replaced by '" + value2.Addon.GUID + "', skipping."));
						}
						else
						{
							LoadedAudioClips[text] = value;
						}
					}
				}
			}
		}
	}
	internal abstract class BaseAssetTreeLoader : IAssetLoader
	{
		protected abstract AddonManifest.AssetType SupportedAssetType { get; }

		protected abstract int TargetSegmentsCount { get; }

		internal AssetTree<AddonAsset>? AssetTree { get; private set; }

		public virtual void Initialize(IEnumerable<Addon> addons)
		{
			AssetTree = new AssetTree<AddonAsset>(TargetSegmentsCount);
			foreach (Addon addon in addons)
			{
				AddAssetsFromAddon(addon);
			}
			if (Plugin.PluginConfig.VerboseDebugLogs.Value)
			{
				Plugin.Log.LogInfo((object)AssetTree);
			}
		}

		private void AddAssetsFromAddon(Addon addon)
		{
			Addon addon2 = addon;
			foreach (AddonManifest.AssetMapping item in addon2.Manifest.AssetMappings.Where((AddonManifest.AssetMapping mapping) => mapping.AssetType == SupportedAssetType))
			{
				try
				{
					if (item.Replacements.Length == 0)
					{
						throw new ArgumentException("Asset mapping in '" + addon2.GUID + "' for target " + $"'{item.Targets}' has no asset paths.");
					}
					string assetPath;
					using IEnumerator<ReplacementAsset> enumerator2 = (from replacement in item.Replacements
						where replacement is ReplacementAsset.LoadFromAddon
						where !addon2.FileExists(addon2.GetAssetPath(replacement, out assetPath))
						select replacement).GetEnumerator();
					if (enumerator2.MoveNext())
					{
						ReplacementAsset current2 = enumerator2.Current;
						throw new FileNotFoundException($"[{addon2.GUID}] Asset '{current2}' of type '{SupportedAssetType}' could " + "not be resolved.");
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("Failed to add assets from addon: " + addon2.GUID + $"\n- Cause: {ex.GetType()}" + "\n- Message: " + ex.Message));
					continue;
				}
				AddonAsset asset = new AddonAsset(item, addon2);
				string[] targets = item.Targets;
				foreach (string target in targets)
				{
					AssetTree?.AddAssetToTree(target, asset, addon2.Manifest.UsesAsterisksAsWildcardsInTargetField());
				}
			}
		}
	}
	internal class GunAudioSetLoader : BaseAssetTreeLoader
	{
		protected override AddonManifest.AssetType SupportedAssetType => AddonManifest.AssetType.GunAudioSet;

		protected override int TargetSegmentsCount => 4;
	}
	internal class GunSoundLoader : BaseAssetTreeLoader
	{
		protected override AddonManifest.AssetType SupportedAssetType => AddonManifest.AssetType.GunSound;

		protected override int TargetSegmentsCount => 4;
	}
	internal class MaterialLoader : BaseAssetTreeLoader
	{
		private static readonly string[] MaterialPathSchema = new string[2] { "prefabPath", "materialName" };

		protected override AddonManifest.AssetType SupportedAssetType => AddonManifest.AssetType.Material;

		protected override int TargetSegmentsCount { get; } = MaterialPathSchema.Length;


		public override void Initialize(IEnumerable<Addon> addons)
		{
			base.Initialize(addons);
			ResourceRedirection.RegisterAssetLoadedHook((HookBehaviour)2, 100, (Action<AssetLoadedContext>)PatchLoadedAsset);
		}

		private void PatchLoadedAsset(AssetLoadedContext ctx)
		{
			Object[] assets = ctx.Assets;
			foreach (Object val in assets)
			{
				string uniqueFileSystemAssetPath = ctx.GetUniqueFileSystemAssetPath(val);
				GameObject val2 = (GameObject)(object)((val is GameObject) ? val : null);
				if (val2 != null)
				{
					ReplaceMaterials(val2, uniqueFileSystemAssetPath);
				}
			}
		}

		private void ReplaceMaterials(GameObject go, string path)
		{
			MeshRenderer[] componentsInChildren = go.GetComponentsInChildren<MeshRenderer>();
			foreach (MeshRenderer val in componentsInChildren)
			{
				Material[] materials = ((Renderer)val).materials;
				if (materials == null)
				{
					continue;
				}
				for (int j = 0; j < materials.Length; j++)
				{
					string text = ((Object)materials[j]).name.Replace(" (Instance)", "");
					Plugin.LogVerbose("Material: " + string.Join(":", path, text));
					AssetTree<AddonAsset>.AssetNode assetNode = base.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment(), path, text).FirstOrDefault();
					if (assetNode != null)
					{
						materials[j] = assetNode.Asset.SourceAddon.LoadMaterial(assetNode.Asset.AssetMapping.Replacements.First());
					}
				}
				((Renderer)val).materials = materials;
			}
		}
	}
	internal class MeshLoader : BaseAssetTreeLoader
	{
		private static readonly string[] MeshPathSchema = new string[3] { "prefabPath", "meshContainerName", "meshName" };

		protected override AddonManifest.AssetType SupportedAssetType => AddonManifest.AssetType.Mesh;

		protected override int TargetSegmentsCount { get; } = MeshPathSchema.Length;


		public override void Initialize(IEnumerable<Addon> addons)
		{
			base.Initialize(addons);
			ResourceRedirection.RegisterAssetLoadedHook((HookBehaviour)2, (Action<AssetLoadedContext>)PatchLoadedAsset);
		}

		private void PatchLoadedAsset(AssetLoadedContext ctx)
		{
			Object[] assets = ctx.Assets;
			foreach (Object val in assets)
			{
				string uniqueFileSystemAssetPath = ctx.GetUniqueFileSystemAssetPath(val);
				GameObject val2 = (GameObject)(object)((val is GameObject) ? val : null);
				if (val2 != null)
				{
					ReplaceMeshes(val2, uniqueFileSystemAssetPath);
				}
			}
		}

		private void ReplaceMeshes(GameObject go, string path)
		{
			MeshFilter[] componentsInChildren = go.GetComponentsInChildren<MeshFilter>();
			foreach (MeshFilter val in componentsInChildren)
			{
				string name = ((Object)val).name;
				string text = ((Object)val.mesh).name.Replace(" Instance", "");
				Plugin.LogVerbose("Mesh: " + string.Join(":", path, name, text));
				AssetTree<AddonAsset>.AssetNode assetNode = base.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment(), path, name, text).FirstOrDefault();
				if (assetNode != null)
				{
					val.mesh = assetNode.Asset.SourceAddon.LoadMesh(assetNode.Asset.AssetMapping.Replacements.First());
				}
			}
		}
	}
	internal class PrefabLoader : IAssetLoader
	{
		private readonly Dictionary<string, Addon> _prefabReplacements = new Dictionary<string, Addon>();

		public void Initialize(IEnumerable<Addon> addons)
		{
			foreach (Addon addon in addons)
			{
				RegisterPrefabReplacements(addon);
			}
			ResourceRedirection.RegisterAsyncAndSyncAssetLoadingHook(500, (Action<IAssetLoadingContext>)ReplacePrefab);
		}

		private void ReplacePrefab(IAssetLoadingContext ctx)
		{
			string text = (ctx.GetNormalizedAssetBundlePath() + "\\" + ctx.Parameters.Name).ToLowerInvariant();
			if (_prefabReplacements.TryGetValue(text, out Addon value))
			{
				ctx.Asset = (Object)(object)value.LoadPrefab(text);
				bool? flag = false;
				ctx.Complete(true, (bool?)true, flag);
			}
		}

		private void RegisterPrefabReplacements(Addon addon)
		{
			foreach (AddonManifest.AssetMapping item in addon.Manifest.AssetMappings.Where((AddonManifest.AssetMapping assetMapping) => assetMapping.AssetType == AddonManifest.AssetType.Prefab))
			{
				if (!addon.FileExists(addon.GetAssetPath(item.Replacements.First(), out string _)))
				{
					Plugin.Log.LogWarning((object)($"[{addon.GUID}] Asset '{item.Replacements.First()}' of type " + $"'{AddonManifest.AssetType.Prefab}' does not exist in the mod, skipping."));
				}
				string[] targets = item.Targets;
				foreach (string text in targets)
				{
					if (_prefabReplacements.TryGetValue(text, out Addon value))
					{
						Plugin.Log.LogWarning((object)("[" + addon.GUID + "] prefab " + text + " is already being replaced by '" + value.GUID + "', skipping."));
					}
					else
					{
						_prefabReplacements[text] = addon;
					}
				}
			}
		}
	}
	internal class TextureLoader : BaseAssetTreeLoader
	{
		private static readonly string[] TexturePathSchema = new string[4] { "prefabPath", "materialName", "textureName", "materialParameter" };

		protected override AddonManifest.AssetType SupportedAssetType => AddonManifest.AssetType.Texture;

		protected override int TargetSegmentsCount { get; } = TexturePathSchema.Length;


		public override void Initialize(IEnumerable<Addon> addons)
		{
			base.Initialize(addons);
			ResourceRedirection.RegisterAssetLoadedHook((HookBehaviour)2, (Action<AssetLoadedContext>)PatchLoadedAsset);
			ResourceRedirection.RegisterResourceLoadedHook((HookBehaviour)2, (Action<ResourceLoadedContext>)PatchLoadedResource);
		}

		private void PatchLoadedResource(ResourceLoadedContext ctx)
		{
			Plugin.LogVerbose($"Loaded resource to load resource {ctx.Parameters.Path}, {ctx.Parameters.Type}");
			Object[] assets = ctx.Assets;
			foreach (Object val in assets)
			{
				string uniqueFileSystemAssetPath = ctx.GetUniqueFileSystemAssetPath(val);
				ItemSpawnerID val2 = (ItemSpawnerID)(object)((val is ItemSpawnerID) ? val : null);
				if (val2 != null)
				{
					ReplaceItemSpawnerIcon(val2, uniqueFileSystemAssetPath);
				}
			}
		}

		private void ReplaceItemSpawnerIcon(ItemSpawnerID itemSpawnerId, string path)
		{
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)itemSpawnerId.Sprite))
			{
				Plugin.LogVerbose("ItemSpawnerID Icon: " + string.Join(":", path, ((Object)itemSpawnerId.Sprite).name, ((Object)itemSpawnerId.Sprite.texture).name));
				AssetTree<AddonAsset>.AssetNode assetNode = base.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment(), path, ((Object)itemSpawnerId.Sprite).name, ((Object)itemSpawnerId.Sprite.texture).name).FirstOrDefault();
				if (assetNode != null)
				{
					Sprite sprite = Sprite.Create(assetNode.Asset.SourceAddon.LoadTexture(assetNode.Asset.AssetMapping.Replacements.First()), itemSpawnerId.Sprite.rect, itemSpawnerId.Sprite.pivot, itemSpawnerId.Sprite.pixelsPerUnit, 0u, (SpriteMeshType)1, itemSpawnerId.Sprite.border);
					itemSpawnerId.Sprite = sprite;
				}
			}
		}

		private void PatchLoadedAsset(AssetLoadedContext ctx)
		{
			Object[] assets = ctx.Assets;
			foreach (Object val in assets)
			{
				string uniqueFileSystemAssetPath = ctx.GetUniqueFileSystemAssetPath(val);
				GameObject val2 = (GameObject)(object)((val is GameObject) ? val : null);
				if (val2 != null)
				{
					ReplaceTextures(val2, uniqueFileSystemAssetPath);
				}
			}
		}

		private void ReplaceTextures(GameObject go, string path)
		{
			MeshRenderer[] componentsInChildren = go.GetComponentsInChildren<MeshRenderer>();
			foreach (MeshRenderer val in componentsInChildren)
			{
				Material[] materials = ((Renderer)val).materials;
				if (materials == null)
				{
					continue;
				}
				Material[] array = materials;
				foreach (Material val2 in array)
				{
					string text = ((Object)val2).name.Replace("(Instance)", "").Trim();
					string text2 = (Object.op_Implicit((Object)(object)val2.mainTexture) ? ((Object)val2.mainTexture).name : "NULL");
					Plugin.LogVerbose("Texture: " + string.Join(":", path, text, text2));
					AssetTree<AddonAsset>.AssetNode[] array2 = base.AssetTree?.Find(new AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment(), path, text, text2);
					if (array2 == null || array2.Length == 0)
					{
						continue;
					}
					AssetTree<AddonAsset>.AssetNode[] array3 = array2;
					foreach (AssetTree<AddonAsset>.AssetNode assetNode in array3)
					{
						Texture2D val3 = assetNode.Asset.SourceAddon.LoadTexture(assetNode.Asset.AssetMapping.Replacements.First());
						if (assetNode.FinalTargetSegment == null)
						{
							val2.mainTexture = (Texture)(object)val3;
						}
						else
						{
							val2.SetTexture(assetNode.FinalTargetSegment, (Texture)(object)val3);
						}
					}
				}
				((Renderer)val).materials = materials;
			}
		}
	}
}
namespace Sirdoggy.SideloaderMint.Addons
{
	internal class Addon
	{
		private const string MuteAudioClipPathValue = "_mute";

		private const string SilenceSoundFileRelativePath = "assets/silence.wav";

		private readonly Dictionary<string, AssetBundle> _assetBundles = new Dictionary<string, AssetBundle>();

		private readonly Dictionary<string, AudioClip> _audioClips = new Dictionary<string, AudioClip>();

		private readonly Dictionary<string, Material> _materials = new Dictionary<string, Material>();

		private readonly Dictionary<string, Mesh> _meshes = new Dictionary<string, Mesh>();

		private readonly Dictionary<string, Texture2D> _textures = new Dictionary<string, Texture2D>();

		public AddonManifest Manifest { get; }

		public string BasePath { get; }

		public string GUID => BasePath.Replace(Paths.BepInExRootPath, "") ?? "";

		public Addon(string basePath, bool requireUniqueAddonDirectoryName)
		{
			if (!Directory.Exists(basePath))
			{
				throw new DirectoryNotFoundException("Could not resolve directory.");
			}
			if (requireUniqueAddonDirectoryName)
			{
				string[] array = new DirectoryInfo(basePath).Name.Split(new char[1] { '-' });
				if (array.Length != 2)
				{
					throw new InvalidDirectoryNameException("Addon directory name does not match naming convention. Directory name should match: {AddonAuthor}" + $"{'-'}{{AddonName}}. " + "The directory name must contain only one " + $"'{'-'}' character.");
				}
				string text = array[0].Trim();
				string text2 = array[1].Trim();
				if (text.Length == 0)
				{
					throw new InvalidDirectoryNameException("Addon directory name does not match naming convention. Author name cannot be blank.");
				}
				if (text2.Length == 0)
				{
					throw new InvalidDirectoryNameException("Addon directory name does not match naming convention. Addon name cannot be blank.");
				}
			}
			string path = Path.Combine(basePath, "manifest.json");
			if (!File.Exists(path))
			{
				throw new FileNotFoundException("The manifest file is missing. The full file name should be 'manifest.json'.");
			}
			AddonManifestParser.ParsingResult parsingResult = AddonManifestParser.ParseJson(File.ReadAllText(path));
			if (!(parsingResult is AddonManifestParser.ParsingResult.InvalidManifest invalidManifest))
			{
				if (parsingResult is AddonManifestParser.ParsingResult.Success success)
				{
					AddonManifest manifest = success.Manifest;
					AddonManifest addonManifest = manifest;
					AddonManifest.AssetMapping[] assetMappings = addonManifest.AssetMappings;
					for (int i = 0; i < assetMappings.Length; i++)
					{
						foreach (ReplacementAsset item in assetMappings[i].Replacements.Where((ReplacementAsset asset) => asset is ReplacementAsset.LoadFromAddon))
						{
							PathValidator.Validate(basePath, (item as ReplacementAsset.LoadFromAddon).RelativePath);
						}
					}
					Manifest = addonManifest;
					BasePath = basePath;
					return;
				}
				throw new NotSupportedException("Unknown validation result");
			}
			throw new InvalidManifestException("The manifest is not valid. Errors:\n" + StringUtils.JoinValues(invalidManifest.ValidationErrors, "\n"));
		}

		public GameObject? LoadPrefab(string target)
		{
			if (FileExists(GetAssetPath(target, out string _)))
			{
				return this.LoadAssetBundleAsset<GameObject>(target, (IDictionary<string, GameObject>)null);
			}
			Plugin.Log.LogWarning((object)("[" + GUID + "] no prefab defined at '" + target + "'"));
			return null;
		}

		public Texture2D LoadTexture(ReplacementAsset replacement)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_0068: Expected O, but got Unknown
			string relativePath = ((replacement as ReplacementAsset.LoadFromAddon) ?? throw new NotSupportedException("Only ReplacementAsset.LoadFromAddon is supported.")).RelativePath;
			if (!FileExists(relativePath))
			{
				throw new FileNotFoundException("Tried to load non-existent texture '" + relativePath + "' from mod " + GUID);
			}
			if (_textures.TryGetValue(relativePath, out Texture2D value))
			{
				return value;
			}
			Dictionary<string, Texture2D> textures = _textures;
			Texture2D val = new Texture2D(1, 1, (TextureFormat)5, false);
			Texture2D val2 = val;
			textures[relativePath] = val;
			value = val2;
			value.LoadImage(LoadBytes(relativePath));
			return value;
		}

		public Material LoadMaterial(ReplacementAsset replacement)
		{
			return this.LoadAssetBundleAsset<Material>(replacement, (IDictionary<string, Material>)_materials);
		}

		public Mesh LoadMesh(ReplacementAsset replacement)
		{
			return this.LoadAssetBundleAsset<Mesh>(replacement, (IDictionary<string, Mesh>)_meshes);
		}

		public AudioClip LoadAudioClip(ReplacementAsset replacement, string name)
		{
			string text = null;
			string text2 = null;
			if (!(replacement is ReplacementAsset.LoadFromAddon loadFromAddon))
			{
				if (replacement is ReplacementAsset.Silence)
				{
					text = Constants.PluginDirectory;
					text2 = "assets/silence.wav";
				}
			}
			else
			{
				text = BasePath;
				text2 = loadFromAddon.RelativePath;
			}
			if (!File.Exists(Path.Combine(text, text2)))
			{
				throw new FileNotFoundException("Tried to load non-existent audio clip '" + text2 + "' from mod '" + GUID + "'");
			}
			if (_audioClips.TryGetValue(text2, out AudioClip value))
			{
				return value;
			}
			long size;
			using Stream from = GetInputStream(text, text2, out size);
			using MemoryStream memoryStream = new MemoryStream();
			StreamExtensions.CopyTo(from, memoryStream);
			using BinaryReader br = new BinaryReader(memoryStream);
			return _audioClips[text2] = WavUtility.ToAudioClip(br, name);
		}

		public AssetBundle LoadAssetBundle(string path, out string assetPath)
		{
			string assetPath2 = GetAssetPath(path, out assetPath);
			if (!_assetBundles.TryGetValue(assetPath2, out AssetBundle value))
			{
				return _assetBundles[assetPath2] = AssetBundle.LoadFromMemory(LoadBytes(assetPath2));
			}
			return value;
		}

		public T LoadAssetBundleAsset<T>(ReplacementAsset replacement, IDictionary<string, T> assetCache = null) where T : Object
		{
			string relativePath = ((replacement as ReplacementAsset.LoadFromAddon) ?? throw new NotSupportedException("Only ReplacementAsset.LoadFromAddon is supported.")).RelativePath;
			return LoadAssetBundleAsset(relativePath, assetCache);
		}

		public T LoadAssetBundleAsset<T>(string path, IDictionary<string, T> assetCache = null) where T : Object
		{
			Plugin.LogVerbose("Loading asset from " + path);
			if (assetCache != null && assetCache.TryGetValue(path, out T value))
			{
				return value;
			}
			value = LoadAssetBundle(path, out string assetPath).LoadAsset<T>(assetPath);
			if (assetCache != null)
			{
				assetCache[path] = value;
			}
			return value;
		}

		public string GetAssetPath(ReplacementAsset replacement, out string assetPath)
		{
			string relativePath = ((replacement as ReplacementAsset.LoadFromAddon) ?? throw new NotSupportedException("Only ReplacementAsset.LoadFromAddon is supported.")).RelativePath;
			return GetAssetPath(relativePath, out assetPath);
		}

		public string GetAssetPath(string path, out string assetPath)
		{
			assetPath = null;
			string[] array = path.Split(new char[1] { ':' }, StringSplitOptions.RemoveEmptyEntries);
			if (array.Length == 0)
			{
				return null;
			}
			assetPath = ((array.Length >= 2) ? array[^1] : null);
			return array[0];
		}

		private Stream GetInputStream(string basePath, string relativePath, out long size)
		{
			if (!File.Exists(Path.Combine(basePath, relativePath)))
			{
				throw new FileNotFoundException("'" + relativePath + "' does not exist in " + GUID);
			}
			FileStream fileStream = File.OpenRead(Path.Combine(basePath, relativePath));
			size = fileStream.Length;
			return fileStream;
		}

		private byte[] LoadBytes(string relativePath)
		{
			long size;
			using Stream stream = GetInputStream(BasePath, relativePath, out size);
			byte[] array = new byte[size];
			stream.Read(array, 0, array.Length);
			return array;
		}

		public bool FileExists(string relativePath)
		{
			if (!File.Exists(Path.Combine(BasePath, relativePath)))
			{
				return relativePath == "_mute";
			}
			return true;
		}
	}
	internal class InvalidManifestException : Exception
	{
		public InvalidManifestException(string message)
			: base(message)
		{
		}
	}
	internal class InvalidDirectoryNameException : Exception
	{
		public InvalidDirectoryNameException(string message)
			: base(message)
		{
		}
	}
	internal static class AddonsConstants
	{
		public const string SilenceAssetPath = "_mute";
	}
}
namespace Sirdoggy.SideloaderMint.Addons.Model
{
	internal class AddonManifest
	{
		public class AssetMapping
		{
			public sealed class Audio : AssetMapping
			{
				public float[]? VolumeRange { get; }

				public float[]? PitchRange { get; }

				public Audio(AssetType assetType, string[] targets, ReplacementAsset[] replacements, float[]? volumeRange, float[]? pitchRange)
				{
					VolumeRange = volumeRange;
					PitchRange = pitchRange;
					base..ctor(assetType, targets, replacements);
				}
			}

			public AssetType AssetType { get; }

			public string[] Targets { get; }

			public ReplacementAsset[] Replacements { get; }

			public AssetMapping(AssetType assetType, string[] targets, ReplacementAsset[] replacements)
			{
				AssetType = assetType;
				Targets = targets;
				Replacements = replacements;
				base..ctor();
			}
		}

		public enum AssetType
		{
			Texture,
			Prefab,
			Mesh,
			Material,
			AudioClip,
			GunSound,
			GunAudioSet,
			Unknown
		}

		public string ManifestRevision { get; }

		public AssetMapping[] AssetMappings { get; }

		public bool Disabled { get; }

		public AddonManifest(string manifestRevision, AssetMapping[] assetMappings, bool disabled)
		{
			ManifestRevision = manifestRevision;
			AssetMappings = assetMappings;
			Disabled = disabled;
			base..ctor();
		}

		public bool UsesAsterisksAsWildcardsInTargetField()
		{
			return ManifestRevision != "1";
		}
	}
	internal abstract class ReplacementAsset
	{
		public sealed class LoadFromAddon : ReplacementAsset
		{
			public string RelativePath { get; }

			public LoadFromAddon(string relativePath)
			{
				RelativePath = relativePath;
				base..ctor();
			}

			public override string ToString()
			{
				return RelativePath;
			}
		}

		public sealed class Silence : ReplacementAsset
		{
		}

		public static ReplacementAsset Create(string relativePath)
		{
			if (string.Equals(relativePath, "_mute", StringComparison.OrdinalIgnoreCase))
			{
				return new Silence();
			}
			return new LoadFromAddon(relativePath);
		}
	}
}
namespace Sirdoggy.SideloaderMint.Addons.Data
{
	internal static class AddonManifestMapper
	{
		public static AddonManifest ToDomain(this AddonManifestRevision1Dto dto)
		{
			return new AddonManifest(dto.ManifestRevision ?? throw new NullReferenceException(), (dto.AssetMappings ?? new AddonManifestRevision1Dto.AssetMappingDto[0]).Select((AddonManifestRevision1Dto.AssetMappingDto assetMappingDto) => assetMappingDto.ToDomain()).ToArray(), disabled: false);
		}

		public static AddonManifest.AssetMapping ToDomain(this AddonManifestRevision1Dto.AssetMappingDto dto)
		{
			return new AddonManifest.AssetMapping(dto.Type.ToDomain(), new string[1] { dto.Target ?? throw new NullReferenceException() }, new ReplacementAsset[1]
			{
				new ReplacementAsset.LoadFromAddon(dto.Path ?? throw new NullReferenceException())
			});
		}

		public static AddonManifest.AssetType ToDomain(this AddonManifestRevision1Dto.AssetTypeDto? dto)
		{
			return dto switch
			{
				AddonManifestRevision1Dto.AssetTypeDto.Texture => AddonManifest.AssetType.Texture, 
				AddonManifestRevision1Dto.AssetTypeDto.Prefab => AddonManifest.AssetType.Prefab, 
				AddonManifestRevision1Dto.AssetTypeDto.Mesh => AddonManifest.AssetType.Mesh, 
				AddonManifestRevision1Dto.AssetTypeDto.Material => AddonManifest.AssetType.Material, 
				AddonManifestRevision1Dto.AssetTypeDto.AudioClip => AddonManifest.AssetType.AudioClip, 
				_ => AddonManifest.AssetType.Unknown, 
			};
		}

		public static AddonManifest ToDomain(this AddonManifestRevision2Dto dto)
		{
			return new AddonManifest(dto.ManifestRevision ?? throw new NullReferenceException(), disabled: dto.Disabled.GetValueOrDefault(), assetMappings: (from assetMappingDto in dto.AssetMappings ?? new AddonManifestRevision2Dto.AssetMappingDto[0]
				where ((!assetMappingDto.Disabled) ?? true) ? true : false
				select assetMappingDto.ToDomain()).ToArray());
		}

		public static AddonManifest.AssetMapping ToDomain(this AddonManifestRevision2Dto.AssetMappingDto dto)
		{
			List<string> list = dto.Targets?.ToList() ?? new List<string>();
			if (dto.Target != null)
			{
				list.Add(dto.Target);
			}
			List<string> list2 = dto.Paths?.ToList() ?? new List<string>();
			if (dto.Path != null)
			{
				list2.Add(dto.Path);
			}
			ReplacementAsset[] replacements = list2.Select(ReplacementAsset.Create).ToArray();
			AddonManifestRevision2Dto.AssetTypeDto? type = dto.Type;
			if (type.HasValue)
			{
				AddonManifestRevision2Dto.AssetTypeDto valueOrDefault = type.GetValueOrDefault();
				if ((uint)(valueOrDefault - 4) <= 2u)
				{
					return new AddonManifest.AssetMapping.Audio(dto.Type.ToDomain(), list.ToArray(), replacements, dto.SoundVolume, dto.SoundPitch);
				}
			}
			return new AddonManifest.AssetMapping(dto.Type.ToDomain(), list.ToArray(), replacements);
		}

		public static AddonManifest.AssetType ToDomain(this AddonManifestRevision2Dto.AssetTypeDto? dto)
		{
			return dto switch
			{
				AddonManifestRevision2Dto.AssetTypeDto.Texture => AddonManifest.AssetType.Texture, 
				AddonMani