Decompiled source of SideloaderMint v1.0.0

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.AssetLoaders;
using Sirdoggy.SideloaderMint.AssetLoaders.Implementations;
using Sirdoggy.SideloaderMint.Common;
using Sirdoggy.SideloaderMint.Common.FVR;
using Sirdoggy.SideloaderMint.Common.Structures;
using Sirdoggy.SideloaderMint.Common.Validation;
using Sirdoggy.SideloaderMint.Patchers;
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.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Sirdoggy.SideloaderMint")]
[assembly: AssemblyTitle("SideloaderMint")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class ParamCollectionAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace 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;
	}
	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.LogDebug((object)("Skipping '" + addon.Guid + "' because it's disabled in the manifest."));
						num++;
					}
					else if (dictionary.ContainsKey(addon.Guid))
					{
						Plugin.Log.LogWarning((object)("Skipping '" + addon.Guid + "' because an addon with the same GUID was already loaded."));
					}
					else
					{
						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.0.0")]
	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.0.0";

		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);
			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.AudioClipPaths.Length);
				string path = value.AudioClipPaths[num];
				AudioClip clip = value.Addon.LoadAudioClip(path, ((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]
	[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 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("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(AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel, new string[3]
					{
						name,
						gunEvent.ToString(),
						itemID
					}).FirstOrDefault();
					AssetTree<AddonAsset>.AssetNode assetNode2 = _gunSoundLoader.AssetTree?.Find(AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel, new string[3]
					{
						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)
								{
									string[] paths = assetMapping.Paths;
									if (paths != null)
									{
										num = ((paths.Length > 0) ? 1 : 0);
										goto IL_0246;
									}
								}
							}
						}
						num = 0;
						goto IL_0246;
						IL_027b:
						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.ReplaceEntriesInAudioSetByEvent(asset2, gunEvent);
						}
						else
						{
							AddonAsset asset3 = assetNode.Asset;
							firearm.AudioClipSet.ReplaceEntriesInAudioSetByEvent(asset3, gunEvent);
						}
						return;
						IL_0246:
						if (assetNode2 != null)
						{
							AddonAsset asset = assetNode2.Asset;
							if (asset != null)
							{
								AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
								if (assetMapping != null)
								{
									string[] paths = assetMapping.Paths;
									if (paths != null)
									{
										num2 = ((paths.Length > 0) ? 1 : 0);
										goto IL_027b;
									}
								}
							}
						}
						num2 = 0;
						goto IL_027b;
					}
					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;
			}
		}

		[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 fvrFirearmAudioSet = (__instance.AudioClipSet = __instance.AudioClipSet.DeepCopy());
			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(AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQuery, new string[2]
				{
					name,
					gunEvent.ToString()
				}).FirstOrDefault();
				AssetTree<AddonAsset>.AssetNode assetNode2 = _gunSoundLoader.AssetTree?.Find(AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQuery, new string[2]
				{
					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)
							{
								string[] paths = assetMapping.Paths;
								if (paths != null)
								{
									num = ((paths.Length > 0) ? 1 : 0);
									goto IL_01f1;
								}
							}
						}
					}
					num = 0;
					goto IL_01f1;
					IL_0226:
					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;
						fvrFirearmAudioSet.ReplaceEntriesInAudioSetByEvent(asset2, gunEvent);
					}
					else
					{
						AddonAsset asset3 = assetNode.Asset;
						fvrFirearmAudioSet.ReplaceEntriesInAudioSetByEvent(asset3, gunEvent);
					}
					goto end_IL_01bc;
					IL_01f1:
					if (assetNode2 != null)
					{
						AddonAsset asset = assetNode2.Asset;
						if (asset != null)
						{
							AddonManifest.AssetMapping assetMapping = asset.AssetMapping;
							if (assetMapping != null)
							{
								string[] paths = assetMapping.Paths;
								if (paths != null)
								{
									num2 = ((paths.Length > 0) ? 1 : 0);
									goto IL_0226;
								}
							}
						}
					}
					num2 = 0;
					goto IL_0226;
					end_IL_01bc:;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("Failed to replace audio for '" + text + "' and '" + text2 + $"\n- Cause: {ex.GetType()}" + "\n- Message: " + ex.Message));
				}
			}
		}

		private static void ReplaceEntriesInAudioSetByEvent(this FVRFirearmAudioSet fvrFirearmAudioSet, AddonAsset addonAsset, GunEvent.Value gunEvent)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			AddonAsset addonAsset2 = addonAsset;
			AudioEvent gunEventBy = fvrFirearmAudioSet.GetGunEventBy(gunEvent);
			List<AudioClip> clips = addonAsset2.AssetMapping.Paths.Select((string path) => addonAsset2.SourceAddon.LoadAudioClip(path, ReplacementAudioClipName)).ToList();
			gunEventBy.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]);
				gunEventBy.VolumeRange = volumeRange;
			}
			if (array2 != null)
			{
				Vector2 pitchRange = default(Vector2);
				((Vector2)(ref pitchRange))..ctor(array2[0], array2[1]);
				gunEventBy.PitchRange = pitchRange;
			}
		}
	}
}
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 enum FindBehaviour
		{
			GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment,
			GetMostSpecificThatMatchesQuery,
			GetMostSpecificThatMatchesQueryAndIsAtLeastTheSameLevel
		}

		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;
			AssetNode[] array = SearchIntermediateNodesInNode(_rootNode);
			if (array.Length != 0)
			{
				return array;
			}
			if (behaviour == 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 (behaviour == 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 (behaviour == 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.FVR
{
	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 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 GetGunEventBy(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("Unknown 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;
		}
	}
	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 readonly Value[] All = Enum.GetValues(typeof(Value)).Cast<Value>().ToArray();
	}
}
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 string[] AudioClipPaths { get; }

			public float[]? VolumeRange { get; }

			public float[]? PitchRange { get; }

			public AddonEntry(Addon addon, string[] audioClipPaths, float[]? volumeRange, float[]? pitchRange)
			{
				Addon = addon;
				AudioClipPaths = audioClipPaths;
				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.Paths, 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);
			}
		}

		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.Paths.Length == 0)
					{
						throw new ArgumentException("Asset mapping in '" + addon2.Guid + "' for target " + $"'{item.Targets}' has no asset paths.");
					}
					string assetPath;
					using IEnumerator<string> enumerator2 = item.Paths.Where((string path) => !addon2.FileExists(addon2.GetAssetPath(path, out assetPath))).GetEnumerator();
					if (enumerator2.MoveNext())
					{
						string 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 => 3;
	}
	internal class GunSoundLoader : BaseAssetTreeLoader
	{
		protected override AddonManifest.AssetType SupportedAssetType => AddonManifest.AssetType.GunSound;

		protected override int TargetSegmentsCount => 3;
	}
	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(AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment, new string[2] { path, text }).FirstOrDefault();
					if (assetNode != null)
					{
						materials[j] = assetNode.Asset.SourceAddon.LoadMaterial(assetNode.Asset.AssetMapping.Paths.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(AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment, new string[3] { path, name, text }).FirstOrDefault();
				if (assetNode != null)
				{
					val.mesh = assetNode.Asset.SourceAddon.LoadMesh(assetNode.Asset.AssetMapping.Paths.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.Paths.First(), out string _)))
				{
					Plugin.Log.LogWarning((object)("[" + addon.Guid + "] Asset '" + item.Paths.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_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: 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(AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment, new string[3]
				{
					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.Paths.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(AssetTree<AddonAsset>.FindBehaviour.GetMostSpecificThatMatchesQueryOrCollectAllWhenReachedLastQuerySegment, new string[3] { 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.Paths.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 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 Path { get; }

		public string Guid => Path.Replace(Paths.BepInExRootPath, "") ?? "";

		public Addon(string path, bool requireUniqueAddonDirectoryName)
		{
			if (!Directory.Exists(path))
			{
				throw new DirectoryNotFoundException("Could not resolve directory.");
			}
			if (requireUniqueAddonDirectoryName)
			{
				string[] array = new DirectoryInfo(path).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 path2 = System.IO.Path.Combine(path, "manifest.json");
			if (!File.Exists(path2))
			{
				throw new FileNotFoundException("The manifest file is missing. The full file name should be 'manifest.json'.");
			}
			ManifestParser.ParsingResult parsingResult = ManifestParser.ParseJson(File.ReadAllText(path2));
			if (!(parsingResult is ManifestParser.ParsingResult.InvalidManifest invalidManifest))
			{
				if (parsingResult is ManifestParser.ParsingResult.Success success)
				{
					AddonManifest manifest = success.Manifest;
					AddonManifest addonManifest = manifest;
					AddonManifest.AssetMapping[] assetMappings = addonManifest.AssetMappings;
					for (int i = 0; i < assetMappings.Length; i++)
					{
						string[] paths = assetMappings[i].Paths;
						foreach (string relativePath in paths)
						{
							PathValidator.Validate(path, relativePath);
						}
					}
					Manifest = addonManifest;
					Path = path;
					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(string path)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_004e: Expected O, but got Unknown
			if (!FileExists(path))
			{
				throw new FileNotFoundException("Tried to load non-existent texture '" + path + "' from mod " + Guid);
			}
			if (_textures.TryGetValue(path, out Texture2D value))
			{
				return value;
			}
			Dictionary<string, Texture2D> textures = _textures;
			Texture2D val = new Texture2D(1, 1, (TextureFormat)5, false);
			Texture2D val2 = val;
			textures[path] = val;
			value = val2;
			value.LoadImage(LoadBytes(path));
			return value;
		}

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

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

		public AudioClip LoadAudioClip(string path, string name)
		{
			if (!FileExists(path))
			{
				throw new FileNotFoundException("Tried to load non-existent audio clip '" + path + "' from mod " + Guid);
			}
			if (_audioClips.TryGetValue(path, out AudioClip value))
			{
				return value;
			}
			long size;
			using Stream from = GetInputStream(path, out size);
			using MemoryStream memoryStream = new MemoryStream();
			StreamExtensions.CopyTo(from, memoryStream);
			using BinaryReader br = new BinaryReader(memoryStream);
			return _audioClips[path] = 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>(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(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 path, out long size)
		{
			if (!FileExists(path))
			{
				throw new FileNotFoundException("'" + path + "' does not exist in " + Guid);
			}
			FileStream fileStream = File.OpenRead(System.IO.Path.Combine(Path, path));
			size = fileStream.Length;
			return fileStream;
		}

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

		public bool FileExists(string relativePath)
		{
			return File.Exists(System.IO.Path.Combine(Path, relativePath));
		}
	}
	internal class InvalidManifestException : Exception
	{
		public InvalidManifestException(string message)
			: base(message)
		{
		}
	}
	internal class InvalidDirectoryNameException : Exception
	{
		public InvalidDirectoryNameException(string message)
			: base(message)
		{
		}
	}
	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, string[] paths, float[]? volumeRange, float[]? pitchRange)
				{
					VolumeRange = volumeRange;
					PitchRange = pitchRange;
					base..ctor(assetType, targets, paths);
				}
			}

			public AssetType AssetType { get; }

			public string[] Targets { get; }

			public string[] Paths { get; }

			public AssetMapping(AssetType assetType, string[] targets, string[] paths)
			{
				AssetType = assetType;
				Targets = targets;
				Paths = paths;
				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 static class ManifestParser
	{
		public abstract class ParsingResult
		{
			public sealed class Success : ParsingResult
			{
				public AddonManifest Manifest { get; }

				public Success(AddonManifest manifest)
				{
					Manifest = manifest;
					base..ctor();
				}
			}

			public sealed class InvalidManifest : ParsingResult
			{
				public List<string> ValidationErrors { get; }

				public InvalidManifest(List<string> validationErrors)
				{
					ValidationErrors = validationErrors;
					base..ctor();
				}
			}
		}

		private const string ManifestRevision1 = "1";

		private const string ManifestRevision2 = "2";

		private const string ManifestRevisionPropertyKey = "ManifestRevision";

		private static readonly string[] SupportedManifestRevisions = new string[2] { "1", "2" };

		public static ParsingResult ParseJson(string manifestJson)
		{
			JObject val = JObject.Parse(manifestJson);
			string text = ((object)(val.GetValue("ManifestRevision", StringComparison.OrdinalIgnoreCase) ?? throw new MissingFieldException("Manifest does not contain 'ManifestRevision' property."))).ToString();
			object obj;
			if (!(text == "1"))
			{
				if (!(text == "2"))
				{
					throw new NotSupportedException("Unsupported manifest revision, supported values are: [" + StringUtils.JoinValues(SupportedManifestRevisions) + "]");
				}
				obj = StrictDeserializer.Deserialize<AddonManifestRevision2Dto>(val);
			}
			else
			{
				obj = ((JToken)val).ToObject<AddonManifestRevision1Dto>();
			}
			object manifestDtoObject = obj;
			List<string> list = ValidateManifest(manifestDtoObject);
			if (list.Count > 0)
			{
				return new ParsingResult.InvalidManifest(list);
			}
			return new ParsingResult.Success(MapManifestToDomain(manifestDtoObject));
		}

		private static List<string> ValidateManifest(object manifestDtoObject)
		{
			List<string> errors = new List<string>();
			if (!(manifestDtoObject is AddonManifestRevision1Dto dto2))
			{
				if (!(manifestDtoObject is AddonManifestRevision2Dto dto3))
				{
					throw new NotSupportedException("Unknown manifest dto object");
				}
				ValidateRevision2(dto3);
			}
			else
			{
				ValidateRevision1(dto2);
			}
			return errors;
			void AddErrorInvalidArraySizeForProperty(string property, int actualSize, int allowedSize)
			{
				errors.Add($"Property '{property}' contains an array of size {actualSize} which is not " + $"allowed - it should be of size {allowedSize}.");
			}
			void AddErrorMissingProperty(string missingProperty)
			{
				errors.Add("Missing required property: '" + missingProperty + "'.");
			}
			void AddErrorNegativeValue(string property, string value)
			{
				errors.Add("Property '" + property + "' contains a negative value '" + value + "' which is not allowed.");
			}
			void AddErrorNeitherOfMultipleSpecified(string[] properties)
			{
				errors.Add("Neither of the following properties is specified: '" + StringUtils.JoinValues(properties) + "'. At least one of them must be specified.");
			}
			void AddErrorUnknownAssetType(string assetType)
			{
				errors.Add("Unknown asset mapping asset type: '" + assetType + "'.");
			}
			void AddErrorUnsupportedPropertyForType(string unsupportedProperty, string assetType)
			{
				errors.Add("Property '" + unsupportedProperty + "' is not supported for asset mapping of type '" + assetType + "'.");
			}
			void ValidateRevision1(AddonManifestRevision1Dto dto)
			{
				if (dto.Guid == null)
				{
					AddErrorMissingProperty("Guid");
				}
				if (dto.Name == null)
				{
					AddErrorMissingProperty("Name");
				}
				if (dto.Version == null)
				{
					AddErrorMissingProperty("Version");
				}
				if (dto.AssetMappings == null)
				{
					AddErrorMissingProperty("AssetMappings");
				}
				else
				{
					AddonManifestRevision1Dto.AssetMappingDto[] assetMappings = dto.AssetMappings;
					foreach (AddonManifestRevision1Dto.AssetMappingDto obj in assetMappings)
					{
						if (obj.Path == null)
						{
							AddErrorMissingProperty("Path");
						}
						if (obj.Target == null)
						{
							AddErrorMissingProperty("Target");
						}
					}
				}
			}
			void ValidateRevision2(AddonManifestRevision2Dto dto)
			{
				if (dto.AssetMappings == null)
				{
					AddErrorMissingProperty("AssetMappings");
				}
				else
				{
					AddonManifestRevision2Dto.AssetMappingDto[] assetMappings2 = dto.AssetMappings;
					foreach (AddonManifestRevision2Dto.AssetMappingDto assetMappingDto in assetMappings2)
					{
						if (!assetMappingDto.Disabled.GetValueOrDefault())
						{
							if (!assetMappingDto.Type.HasValue)
							{
								AddErrorMissingProperty("Type");
							}
							switch (assetMappingDto.Type)
							{
							case AddonManifestRevision2Dto.AssetTypeDto.Texture:
							case AddonManifestRevision2Dto.AssetTypeDto.Prefab:
							case AddonManifestRevision2Dto.AssetTypeDto.Mesh:
							case AddonManifestRevision2Dto.AssetTypeDto.Material:
								if (assetMappingDto.Path == null)
								{
									AddErrorMissingProperty("Path");
								}
								break;
							case AddonManifestRevision2Dto.AssetTypeDto.AudioClip:
							case AddonManifestRevision2Dto.AssetTypeDto.GunSound:
							case AddonManifestRevision2Dto.AssetTypeDto.GunAudioSet:
								if (assetMappingDto.Path == null && assetMappingDto.Paths == null)
								{
									AddErrorNeitherOfMultipleSpecified(new string[2] { "Path", "Paths" });
								}
								break;
							default:
								AddErrorUnknownAssetType(assetMappingDto.Type.ToString());
								break;
							}
							switch (assetMappingDto.Type)
							{
							case AddonManifestRevision2Dto.AssetTypeDto.AudioClip:
							case AddonManifestRevision2Dto.AssetTypeDto.GunSound:
							case AddonManifestRevision2Dto.AssetTypeDto.GunAudioSet:
								if (assetMappingDto.SoundPitch != null)
								{
									if (assetMappingDto.SoundPitch.Length != 2)
									{
										AddErrorInvalidArraySizeForProperty("SoundPitch", assetMappingDto.SoundPitch.Length, 2);
									}
									float[] soundPitch = assetMappingDto.SoundPitch;
									for (int k = 0; k < soundPitch.Length; k++)
									{
										float num = soundPitch[k];
										if (num < 0f)
										{
											AddErrorNegativeValue("SoundPitch", num.ToString(CultureInfo.InvariantCulture));
										}
									}
								}
								if (assetMappingDto.SoundVolume != null)
								{
									if (assetMappingDto.SoundVolume.Length != 2)
									{
										AddErrorInvalidArraySizeForProperty("SoundVolume", assetMappingDto.SoundVolume.Length, 2);
									}
									float[] soundPitch = assetMappingDto.SoundVolume;
									for (int k = 0; k < soundPitch.Length; k++)
									{
										float num2 = soundPitch[k];
										if (num2 < 0f)
										{
											AddErrorNegativeValue("SoundVolume", num2.ToString(CultureInfo.InvariantCulture));
										}
									}
								}
								break;
							case AddonManifestRevision2Dto.AssetTypeDto.Texture:
							case AddonManifestRevision2Dto.AssetTypeDto.Prefab:
							case AddonManifestRevision2Dto.AssetTypeDto.Mesh:
							case AddonManifestRevision2Dto.AssetTypeDto.Material:
								if (assetMappingDto.SoundPitch != null)
								{
									AddErrorUnsupportedPropertyForType("SoundPitch", assetMappingDto.Type.ToString());
								}
								if (assetMappingDto.SoundVolume != null)
								{
									AddErrorUnsupportedPropertyForType("SoundVolume", assetMappingDto.Type.ToString());
								}
								break;
							default:
								AddErrorUnknownAssetType(assetMappingDto.Type.ToString());
								break;
							}
							if (assetMappingDto.Target == null && assetMappingDto.Targets == null)
							{
								AddErrorNeitherOfMultipleSpecified(new string[2] { "Target", "Targets" });
							}
						}
					}
				}
			}
		}

		private static AddonManifest MapManifestToDomain(object manifestDtoObject)
		{
			if (!(manifestDtoObject is AddonManifestRevision1Dto dto))
			{
				if (manifestDtoObject is AddonManifestRevision2Dto dto2)
				{
					return dto2.ToDomain();
				}
				throw new NotSupportedException("Unknown manifest dto object");
			}
			return dto.ToDomain();
		}
	}
}
namespace Sirdoggy.SideloaderMint.Addons.Data
{
	internal class AddonManifestRevision1Dto
	{
		public class AssetMappingDto
		{
			public AssetTypeDto? Type { get; set; }

			public string? Target { get; set; }

			public string? Path { get; set; }
		}

		public enum AssetTypeDto
		{
			Texture,
			Prefab,
			Mesh,
			Material,
			AudioClip,
			FVRObject,
			ItemSpawnerID
		}

		public string? ManifestRevision { get; set; }

		public string? Guid { get; set; }

		public string? Name { get; set; }

		public string? Version { get; set; }

		public string? Description { get; set; }

		public AssetMappingDto[]? AssetMappings { get; set; }
	}
	internal class AddonManifestRevision2Dto
	{
		public class AssetMappingDto
		{
			public bool? Disabled { get; set; }

			public string? Comment { get; set; }

			public AssetTypeDto? Type { get; set; }

			public string? Target { get; set; }

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

			public string? Path { get; set; }

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

			public float[]? SoundVolume { get; set; }

			public float[]? SoundPitch { get; set; }
		}

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

		public string? ManifestRevision { get; set; }

		[Obsolete]
		public string? Guid { get; set; }

		[Obsolete]
		public string? Name { get; set; }

		[Obsolete]
		public string? Version { get; set; }

		[Obsolete]
		public string? Description { get; set; }

		public bool? Disabled { get; set; }

		public string? Comment { get; set; }

		public AssetMappingDto[]? AssetMappings { get; set; }
	}
	internal static class ManifestMappings
	{
		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 string[1] { 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);
			}
			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(), list2.ToArray(), dto.SoundVolume, dto.SoundPitch);
				}
			}
			return new AddonManifest.AssetMapping(dto.Type.ToDomain(), list.ToArray(), list2.ToArray());
		}

		public static AddonManifest.AssetType ToDomain(this AddonManifestRevision2Dto.AssetTypeDto? dto)
		{
			return dto switch
			{
				AddonManifestRevision2Dto.AssetTypeDto.Texture => AddonManifest.AssetType.Texture, 
				AddonManifestRevision2Dto.AssetTypeDto.Prefab => AddonManifest.AssetType.Prefab, 
				AddonManifestRevision2Dto.AssetTypeDto.Mesh => AddonManifest.AssetType.Mesh, 
				AddonManifestRevision2Dto.AssetTypeDto.Material => AddonManifest.AssetType.Material, 
				AddonManifestRevision2Dto.AssetTypeDto.AudioClip => AddonManifest.AssetType.AudioClip, 
				AddonManifestRevision2Dto.AssetTypeDto.GunSound => AddonManifest.AssetType.GunSound, 
				AddonManifestRevision2Dto.AssetTypeDto.GunAudioSet => AddonManifest.AssetType.GunAudioSet, 
				_ => AddonManifest.AssetType.Unknown, 
			};
		}
	}
}
[CompilerGenerated]
internal sealed class <>z__ReadOnlyArray<T> : IEnumerable, ICollection, IList, IEnumerable<T>, ICollection<T>, IList<T>
{
	int ICollection.Count => _items.Length;

	bool ICollection.IsSynchronized => false;

	object ICollection.SyncRoot => this;

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

	bool IList.IsFixedSize => true;

	bool IList.IsReadOnly => true;

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

	bool ICollection<T>.IsReadOnly => true;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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