Decompiled source of loaforcsSoundAPI CW v1.0.6

plugins/me.loaforc.soundapi.dll

Decompiled 8 months ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using loaforcsSoundAPI.API;
using loaforcsSoundAPI.Behaviours;
using loaforcsSoundAPI.Data;
using loaforcsSoundAPI.LethalCompany;
using loaforcsSoundAPI.LethalCompany.Conditions;
using loaforcsSoundAPI.Providers.Conditions;
using loaforcsSoundAPI.Providers.Formats;
using loaforcsSoundAPI.Providers.Random;
using loaforcsSoundAPI.Utils;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("ClientNetworkTransform")]
[assembly: IgnoresAccessChecksTo("DissonanceVoip")]
[assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")]
[assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")]
[assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")]
[assembly: IgnoresAccessChecksTo("Unity.Burst")]
[assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")]
[assembly: IgnoresAccessChecksTo("Unity.Collections")]
[assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")]
[assembly: IgnoresAccessChecksTo("Unity.Jobs")]
[assembly: IgnoresAccessChecksTo("Unity.Mathematics")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")]
[assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")]
[assembly: IgnoresAccessChecksTo("Unity.Services.QoS")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Relay")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("Unity.Timeline")]
[assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: AssemblyCompany("me.loaforc.soundapi")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.6.0")]
[assembly: AssemblyInformationalVersion("1.0.6+11ed51c98a849d7f9152657957012f5d15f5d53a")]
[assembly: AssemblyProduct("loaforcsSoundAPI")]
[assembly: AssemblyTitle("me.loaforc.soundapi")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.6.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace loaforcsSoundAPI
{
	public static class SoundLoader
	{
		internal static Dictionary<string, AudioType> TYPE_MAPPINGS = new Dictionary<string, AudioType> { 
		{
			".ogg",
			(AudioType)14
		} };

		public static bool GetAudioClip(string packName, string folder, string soundName, out AudioClip clip)
		{
			clip = null;
			if (!GetAudioPath(packName, folder, soundName, out var path))
			{
				SoundPlugin.logger.LogError((object)"Failed getting path, check above for more detailed error!");
				return false;
			}
			clip = SoundReplacementAPI.FileFormats[Path.GetExtension(path).ToLower()].LoadAudioClip(path);
			if ((Object)(object)clip == (Object)null)
			{
				SoundPlugin.logger.LogError((object)"Failed getting clip from disk, check above for more detailed error!");
				return false;
			}
			if (string.IsNullOrEmpty(clip.GetName()))
			{
				((Object)clip).name = soundName;
			}
			return true;
		}

		private static bool GetAudioPath(string packName, string folder, string soundName, out string path)
		{
			string text = Path.Combine(Paths.PluginPath, packName, "sounds", folder);
			path = Path.Combine(text, soundName);
			if (!Directory.Exists(text))
			{
				SoundPlugin.logger.LogError((object)(text + " doesn't exist! (failed loading: " + soundName + ")"));
				path = null;
				return false;
			}
			if (!File.Exists(path))
			{
				SoundPlugin.logger.LogError((object)(path + " is a valid folder but the sound contained doesn't exist!"));
				path = null;
				return false;
			}
			return true;
		}
	}
	[BepInPlugin("me.loaforc.soundapi", "loaforcsSoundAPI", "1.0.6")]
	public class SoundPlugin : BaseUnityPlugin
	{
		internal static List<string> UniqueSounds;

		internal static List<SoundPack> SoundPacks = new List<SoundPack>();

		internal JoinableThreadPool nonstartupThreadPool;

		public static SoundPlugin Instance { get; private set; }

		internal static ManualLogSource logger { get; private set; }

		private void Awake()
		{
			logger = Logger.CreateLogSource("me.loaforc.soundapi");
			Instance = this;
			logger.LogInfo((object)"Patching...");
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "me.loaforc.soundapi");
			logger.LogInfo((object)"Setting up config...");
			new SoundPluginConfig(((BaseUnityPlugin)this).Config);
			logger.LogInfo((object)"Searching for soundpacks...");
			string[] directories = Directory.GetDirectories(Paths.PluginPath);
			logger.LogInfo((object)"Beginning Bindings");
			logger.LogInfo((object)"Bindings => General => Audio Formats");
			SoundReplacementAPI.RegisterAudioFormatProvider(".mp3", new Mp3AudioFormat());
			SoundReplacementAPI.RegisterAudioFormatProvider(".ogg", new OggAudioFormat());
			SoundReplacementAPI.RegisterAudioFormatProvider(".wav", new WavAudioFormat());
			logger.LogInfo((object)"Bindings => General => Random Generators");
			SoundReplacementAPI.RegisterRandomProvider("pure", new PureRandomProvider());
			SoundReplacementAPI.RegisterRandomProvider("deterministic", new DeterminsticRandomProvider());
			logger.LogInfo((object)"Bindings => General => Conditions");
			SoundReplacementAPI.RegisterConditionProvider("config", new ConfigCondition());
			SoundReplacementAPI.RegisterConditionProvider("mod_installed", new ModInstalledConditionProvider());
			SoundReplacementAPI.RegisterConditionProvider("and", new AndCondition());
			SoundReplacementAPI.RegisterConditionProvider("not", new NotCondition());
			SoundReplacementAPI.RegisterConditionProvider("or", new OrCondition());
			LethalCompanyBindings.Bind();
			string[] array = directories;
			foreach (string text in array)
			{
				string[] directories2 = Directory.GetDirectories(text);
				foreach (string text2 in directories2)
				{
					string path = Path.Combine(text2, "sound_pack.json");
					((BaseUnityPlugin)this).Logger.LogDebug((object)text2);
					if (File.Exists(path))
					{
						SoundPacks.Add(new SoundPack(text2));
						break;
					}
				}
				string path2 = Path.Combine(text, "sound_pack.json");
				if (File.Exists(path2))
				{
					SoundPacks.Add(new SoundPack(text));
				}
			}
			logger.LogInfo((object)"Starting up JoinableThreadPool.");
			nonstartupThreadPool = new JoinableThreadPool(SoundPluginConfig.THREADPOOL_MAX_THREADS.Value);
			foreach (SoundPack soundPack in SoundPacks)
			{
				soundPack.QueueNonStartupOnThreadPool(nonstartupThreadPool);
			}
			nonstartupThreadPool.Start();
			if (!SoundPluginConfig.ENABLE_MULTITHREADING.Value)
			{
				logger.LogInfo((object)"Multithreading is disabled :(, joining the thread pool and blocking the main thread.");
				nonstartupThreadPool.Join();
			}
			logger.LogInfo((object)"Registering onSceneLoaded");
			SceneManager.sceneLoaded += delegate(Scene scene, LoadSceneMode __)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				AudioSource[] array2 = Object.FindObjectsOfType<AudioSource>(true);
				foreach (AudioSource val in array2)
				{
					if (!(((Component)val).gameObject.scene != scene))
					{
						AudioSourceReplaceHelper audioSourceReplaceHelper = ((Component)val).gameObject.AddComponent<AudioSourceReplaceHelper>();
						audioSourceReplaceHelper.source = val;
						if (val.playOnAwake)
						{
							val.Stop();
							val.Play();
						}
					}
				}
			};
			logger.LogInfo((object)"me.loaforc.soundapi:1.0.6 has loaded!");
		}

		private void OnDisable()
		{
			nonstartupThreadPool.Join();
		}
	}
	internal class SoundPluginConfig
	{
		internal static ConfigEntry<bool> ENABLE_MULTITHREADING;

		internal static ConfigEntry<int> THREADPOOL_MAX_THREADS;

		internal SoundPluginConfig(ConfigFile config)
		{
			ENABLE_MULTITHREADING = config.Bind<bool>("SoundLoading", "Multithreading", true, "Whether or not to use multithreading when loading a sound pack. If you haven't been told that you should disable multithreading, you probably don't need to!\nThis setting may not be needed with the new 1.0.0 rewrite of multithreading.");
			THREADPOOL_MAX_THREADS = config.Bind<int>("SoundLoading", "MaxThreadsInThreadPool", 32, "Max amount of threads the loading thread pool can create at once.\nIncreasing this number will decrease loading of non-startup packs but may be unsupported by your CPU.");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "me.loaforc.soundapi";

		public const string PLUGIN_NAME = "loaforcsSoundAPI";

		public const string PLUGIN_VERSION = "1.0.6";
	}
}
namespace loaforcsSoundAPI.Utils
{
	public static class ExtensionMethods
	{
		public static T GetValueOrDefault<T>(this JObject jsonObject, string key, T defaultValue = default(T))
		{
			JToken val = ((jsonObject != null) ? jsonObject.GetValue(key, StringComparison.OrdinalIgnoreCase) : null);
			if (val == null)
			{
				return defaultValue;
			}
			return val.ToObject<T>();
		}

		public static TValue GetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
		{
			if (!dictionary.TryGetValue(key, out var value))
			{
				return defaultValue;
			}
			return value;
		}

		public static TValue GetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, Func<TValue> defaultValueProvider)
		{
			if (!dictionary.TryGetValue(key, out var value))
			{
				return defaultValueProvider();
			}
			return value;
		}

		public static bool IsNumber(this object @object)
		{
			if (!(@object is int) && !(@object is double))
			{
				return @object is float;
			}
			return true;
		}
	}
	internal class JoinableThreadPool
	{
		private readonly ConcurrentQueue<Action> ActionQueue = new ConcurrentQueue<Action>();

		private const int DEFAULT_MAX = 4;

		private int max;

		private Stopwatch timer;

		public void Queue(Action action)
		{
			ActionQueue.Enqueue(action);
		}

		public void Start()
		{
			timer = Stopwatch.StartNew();
			for (int i = 0; i < Mathf.Min(max, ActionQueue.Count); i++)
			{
				new Thread(RunThroughQueue).Start();
				Thread.Sleep(10);
				SoundPlugin.logger.LogDebug((object)("[Multithreading] Started thread " + i + "/" + max));
			}
		}

		public void Join()
		{
			SoundPlugin.logger.LogDebug((object)"[Multithreading] Joined JoinableThreadPool.");
			RunThroughQueue();
		}

		private void RunThroughQueue()
		{
			Action result;
			while (ActionQueue.TryDequeue(out result))
			{
				try
				{
					result();
				}
				catch (Exception ex)
				{
					SoundPlugin.logger.LogError((object)ex);
				}
				Thread.Yield();
				SoundPlugin.logger.LogDebug((object)"[Multithreading] Finished processing an action.");
			}
		}

		public JoinableThreadPool()
		{
			max = 4;
		}

		public JoinableThreadPool(int max)
		{
			this.max = max;
		}
	}
}
namespace loaforcsSoundAPI.Providers.Random
{
	internal class DeterminsticRandomProvider : RandomProvider
	{
		internal static Dictionary<SoundReplaceGroup, System.Random> Generators = new Dictionary<SoundReplaceGroup, System.Random>();

		public override int Range(SoundReplaceGroup group, int min, int max)
		{
			if (!Generators.TryGetValue(group, out var value))
			{
				value = new System.Random(group.pack.Name.GetHashCode());
				Generators[group] = value;
			}
			return value.Next(min, max);
		}
	}
	internal class PureRandomProvider : RandomProvider
	{
		public override int Range(SoundReplaceGroup group, int min, int max)
		{
			return Random.Range(min, max);
		}
	}
}
namespace loaforcsSoundAPI.Providers.Formats
{
	internal class Mp3AudioFormat : AudioFormatProvider
	{
		public override AudioClip LoadAudioClip(string path)
		{
			return LoadFromUWR(path, (AudioType)24);
		}
	}
	internal class OggAudioFormat : AudioFormatProvider
	{
		public override AudioClip LoadAudioClip(string path)
		{
			return LoadFromUWR(path, (AudioType)14);
		}
	}
	internal class WavAudioFormat : AudioFormatProvider
	{
		public override AudioClip LoadAudioClip(string path)
		{
			return LoadFromUWR(path, (AudioType)20);
		}
	}
}
namespace loaforcsSoundAPI.Providers.Conditions
{
	internal class AndCondition : ConditionProvider
	{
		public override bool Evaluate(SoundReplaceGroup pack, JObject conditionDef)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			foreach (JObject item in (IEnumerable<JToken>)conditionDef["conditions"])
			{
				JObject val = item;
				if (!SoundReplacementAPI.ConditionProviders[(string)val["type"]].Evaluate(pack, val))
				{
					return false;
				}
			}
			return true;
		}
	}
	internal class ConfigCondition : ConditionProvider
	{
		public override bool Evaluate(SoundReplaceGroup group, JObject conditionDef)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Invalid comparison between Unknown and I4
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Invalid comparison between Unknown and I4
			if (!conditionDef.ContainsKey("value"))
			{
				return group.pack.GetConfigOption<bool>((string)conditionDef["config"]);
			}
			if ((int)conditionDef["value"].Type == 9)
			{
				return group.pack.GetConfigOption<bool>((string)conditionDef["config"]) == (bool)conditionDef["value"];
			}
			object rawConfigOption = group.pack.GetRawConfigOption((string)conditionDef["config"]);
			if ((int)conditionDef["value"].Type == 8)
			{
				if (rawConfigOption is ConfigEntry<float>)
				{
					return EvaluateRangeOperator((rawConfigOption as ConfigEntry<float>).Value, (string)conditionDef["value"]);
				}
				return (string)rawConfigOption == (string)conditionDef["value"];
			}
			return false;
		}
	}
	internal class ModInstalledConditionProvider : ConditionProvider
	{
		public override bool Evaluate(SoundReplaceGroup group, JObject conditionDef)
		{
			return Chainloader.PluginInfos.ContainsKey((string)conditionDef["value"]);
		}
	}
	internal class NotCondition : ConditionProvider
	{
		public override bool Evaluate(SoundReplaceGroup pack, JObject conditionDef)
		{
			ConditionProvider conditionProvider = SoundReplacementAPI.ConditionProviders[(string)conditionDef["condition"][(object)"type"]];
			JToken obj = conditionDef["condition"];
			return !conditionProvider.Evaluate(pack, (JObject)(object)((obj is JObject) ? obj : null));
		}
	}
	internal class OrCondition : ConditionProvider
	{
		public override bool Evaluate(SoundReplaceGroup pack, JObject conditionDef)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			foreach (JObject item in (IEnumerable<JToken>)conditionDef["conditions"])
			{
				JObject val = item;
				if (SoundReplacementAPI.ConditionProviders[(string)val["type"]].Evaluate(pack, val))
				{
					return true;
				}
			}
			return false;
		}
	}
}
namespace loaforcsSoundAPI.Patches
{
	[HarmonyPatch(typeof(AudioSource))]
	internal static class AudioSourcePatch
	{
		[HarmonyPrefix]
		[HarmonyPatch("Play", new Type[] { })]
		[HarmonyPatch("Play", new Type[] { typeof(ulong) })]
		internal static void Play(AudioSource __instance)
		{
			if ((Object)(object)((Component)__instance).gameObject == (Object)null)
			{
				SoundPlugin.logger.LogWarning((object)"AudioSource has no GameObject!!");
			}
			else
			{
				if (AudioSourceReplaceHelper.helpers.TryGetValue(__instance, out var value) && value.DisableReplacing)
				{
					return;
				}
				SoundReplacementCollection collection;
				AudioClip replacementClip = GetReplacementClip(ProcessName(__instance, __instance.clip), out collection);
				if (!((Object)(object)replacementClip != (Object)null))
				{
					return;
				}
				((Object)replacementClip).name = ((Object)__instance.clip).name;
				__instance.clip = replacementClip;
				if ((Object)(object)value == (Object)null)
				{
					if (__instance.playOnAwake)
					{
						__instance.Stop();
					}
					value = ((Component)__instance).gameObject.AddComponent<AudioSourceReplaceHelper>();
					value.source = __instance;
				}
				value.replacedWith = collection;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("PlayOneShot", new Type[]
		{
			typeof(AudioClip),
			typeof(float)
		})]
		internal static void PlayOneShot(AudioSource __instance, ref AudioClip clip)
		{
			if ((Object)(object)((Component)__instance).gameObject == (Object)null)
			{
				SoundPlugin.logger.LogWarning((object)"AudioSource has no GameObject!!");
			}
			else
			{
				if (AudioSourceReplaceHelper.helpers.TryGetValue(__instance, out var value) && value.DisableReplacing)
				{
					return;
				}
				SoundReplacementCollection collection;
				AudioClip replacementClip = GetReplacementClip(ProcessName(__instance, clip), out collection);
				if (!((Object)(object)replacementClip != (Object)null))
				{
					return;
				}
				if ((Object)(object)value == (Object)null)
				{
					if (__instance.playOnAwake)
					{
						__instance.Stop();
					}
					value = ((Component)__instance).gameObject.AddComponent<AudioSourceReplaceHelper>();
					value.source = __instance;
				}
				((Object)replacementClip).name = ((Object)clip).name;
				clip = replacementClip;
				value.replacedWith = collection;
			}
		}

		internal static string TrimGameObjectName(GameObject gameObject)
		{
			string text = ((Object)gameObject).name.Replace("(Clone)", "");
			for (int i = 0; i < 10; i++)
			{
				text = text.Replace("(" + i + ")", "");
			}
			return text.Trim();
		}

		internal static string ProcessName(AudioSource source, AudioClip clip)
		{
			if ((Object)(object)clip == (Object)null)
			{
				return null;
			}
			string text = ":" + TrimGameObjectName(((Component)source).gameObject);
			if ((Object)(object)((Component)source).transform.parent != (Object)null)
			{
				text = TrimGameObjectName(((Component)((Component)source).transform.parent).gameObject) + text;
			}
			return text + ":" + ((Object)clip).name;
		}

		internal static AudioClip GetReplacementClip(string name, out SoundReplacementCollection collection)
		{
			collection = null;
			if (name == null)
			{
				return null;
			}
			SoundPlugin.logger.LogDebug((object)("Getting replacement for: " + name + " (doing top level search for " + name.Split(":")[2] + ")"));
			if (!SoundReplacementAPI.SoundReplacements.ContainsKey(name.Split(":")[2]))
			{
				return null;
			}
			List<SoundReplacementCollection> list = (from x in SoundReplacementAPI.SoundReplacements[name.Split(":")[2]]
				where x.MatchesWith(name)
				where x.TestCondition()
				select x).ToList();
			if (list.Count == 0)
			{
				return null;
			}
			_ = list.Count;
			_ = 1;
			collection = list[Random.Range(0, list.Count)];
			List<SoundReplacement> list2 = collection.replacements.Where((SoundReplacement x) => x.TestCondition()).ToList();
			if (list2.Count == 0)
			{
				return null;
			}
			int totalWeight = 0;
			list2.ForEach(delegate(SoundReplacement replacement)
			{
				totalWeight += replacement.Weight;
			});
			int num = collection.group.Random.Range(collection.group, 0, totalWeight);
			int index = 0;
			while (num > 0)
			{
				index = collection.group.Random.Range(collection.group, 0, list2.Count);
				num -= collection.group.Random.Range(collection.group, 1, list2[index].Weight);
			}
			return list2[index].Clip;
		}
	}
	[HarmonyPatch(typeof(GameObject))]
	internal class GameObjectPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch("AddComponent", new Type[] { typeof(Type) })]
		internal static void NewAudioSource(GameObject __instance, ref Component __result)
		{
			if (__result is AudioSource)
			{
				Component obj = __result;
				AudioSource val = (AudioSource)(object)((obj is AudioSource) ? obj : null);
				if (val.playOnAwake)
				{
					val.Stop();
				}
				AudioSourceReplaceHelper audioSourceReplaceHelper = __instance.AddComponent<AudioSourceReplaceHelper>();
				audioSourceReplaceHelper.source = val;
			}
		}
	}
	[HarmonyPatch(typeof(Object))]
	internal static class UnityObjectPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch("Instantiate", new Type[] { typeof(Object) })]
		[HarmonyPatch("Instantiate", new Type[]
		{
			typeof(Object),
			typeof(Transform),
			typeof(bool)
		})]
		[HarmonyPatch("Instantiate", new Type[]
		{
			typeof(Object),
			typeof(Vector3),
			typeof(Quaternion)
		})]
		[HarmonyPatch("Instantiate", new Type[]
		{
			typeof(Object),
			typeof(Vector3),
			typeof(Quaternion),
			typeof(Transform)
		})]
		internal static void FixPlayOnAwake(ref Object __result)
		{
			if (__result is GameObject)
			{
				Object obj = __result;
				CheckGameObject((GameObject)(object)((obj is GameObject) ? obj : null));
			}
		}

		private static void CheckGameObject(GameObject @object)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			AudioSourceReplaceHelper audioSourceReplaceHelper = default(AudioSourceReplaceHelper);
			if (@object.TryGetComponent<AudioSourceReplaceHelper>(ref audioSourceReplaceHelper))
			{
				return;
			}
			AudioSource[] components = @object.GetComponents<AudioSource>();
			AudioSource[] array = components;
			foreach (AudioSource val in array)
			{
				if (val.playOnAwake)
				{
					val.Stop();
				}
				AudioSourceReplaceHelper audioSourceReplaceHelper2 = @object.AddComponent<AudioSourceReplaceHelper>();
				audioSourceReplaceHelper2.source = val;
			}
			foreach (Transform item in @object.transform)
			{
				Transform val2 = item;
				CheckGameObject(((Component)val2).gameObject);
			}
		}
	}
}
namespace loaforcsSoundAPI.LethalCompany
{
	internal static class LethalCompanyBindings
	{
		internal static void Bind()
		{
			SoundReplacementAPI.RegisterConditionProvider("LethalCompany:dungeon_name", new DungeonConditionProvider());
			SoundReplacementAPI.RegisterConditionProvider("LethalCompany:moon_name", new MoonConditionProvider());
			SoundReplacementAPI.RegisterConditionProvider("LethalCompany:player_health", new PlayerHealthConditionProvider());
			SoundReplacementAPI.RegisterConditionProvider("LethalCompany:time_of_day", new TimeOfDayConditionProvider());
			SoundReplacementAPI.RegisterConditionProvider("LethalCompany:player_location", new PlayerLocationTypeConditionProvider());
		}
	}
}
namespace loaforcsSoundAPI.LethalCompany.Conditions
{
	internal class DungeonConditionProvider : ConditionProvider
	{
		public override bool Evaluate(SoundReplaceGroup group, JObject conditionDef)
		{
			SoundPlugin.logger.LogDebug((object)("LethalCompany:dungeon_name value: " + ((Object)RoundManager.Instance.dungeonGenerator.Generator.DungeonFlow).name));
			return Extensions.Value<string>((IEnumerable<JToken>)conditionDef["value"]) == ((Object)RoundManager.Instance.dungeonGenerator.Generator.DungeonFlow).name;
		}
	}
	internal class MoonConditionProvider : ConditionProvider
	{
		public override bool Evaluate(SoundReplaceGroup group, JObject conditionDef)
		{
			SoundPlugin.logger.LogDebug((object)("LethalCompany:moon_name value: " + ((Object)StartOfRound.Instance.currentLevel).name));
			return Extensions.Value<string>((IEnumerable<JToken>)conditionDef["value"]) == ((Object)StartOfRound.Instance.currentLevel).name;
		}
	}
	internal class PlayerHealthConditionProvider : ConditionProvider
	{
		public override bool Evaluate(SoundReplaceGroup group, JObject conditionDef)
		{
			return EvaluateRangeOperator(GameNetworkManager.Instance.localPlayerController.health, Extensions.Value<string>((IEnumerable<JToken>)conditionDef["value"]));
		}
	}
	internal class PlayerLocationTypeConditionProvider : ConditionProvider
	{
		public override bool Evaluate(SoundReplaceGroup group, JObject varDef)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			if (GameNetworkManager.Instance.localPlayerController.isPlayerDead)
			{
				return false;
			}
			if (GameNetworkManager.Instance.localPlayerController.isInsideFactory)
			{
				return Extensions.Value<string>((IEnumerable<JToken>)varDef["value"]) == "inside";
			}
			Bounds bounds = StartOfRound.Instance.shipBounds.bounds;
			if (((Bounds)(ref bounds)).Contains(((Component)GameNetworkManager.Instance.localPlayerController).transform.position))
			{
				return Extensions.Value<string>((IEnumerable<JToken>)varDef["value"]) == "on_ship";
			}
			return Extensions.Value<string>((IEnumerable<JToken>)varDef["value"]) == "outside";
		}
	}
	internal class TimeOfDayConditionProvider : ConditionProvider
	{
		public override bool Evaluate(SoundReplaceGroup group, JObject varDef)
		{
			return Extensions.Value<string>((IEnumerable<JToken>)varDef["value"]) == ((object)(DayMode)(ref TimeOfDay.Instance.dayMode)).ToString().ToLower();
		}
	}
}
namespace loaforcsSoundAPI.Data
{
	public class SoundPack
	{
		private static List<SoundPack> LoadedSoundPacks = new List<SoundPack>();

		private List<SoundReplaceGroup> replaceGroups = new List<SoundReplaceGroup>();

		private string[] loadOnStartup;

		private Dictionary<string, object> Config = new Dictionary<string, object>();

		public string Name { get; private set; }

		public string PackPath { get; private set; }

		public IReadOnlyCollection<SoundReplaceGroup> ReplaceGroups => replaceGroups.AsReadOnly();

		public T GetConfigOption<T>(string configID)
		{
			return ((ConfigEntry<T>)Config[configID]).Value;
		}

		internal object GetRawConfigOption(string configID)
		{
			return Config[configID];
		}

		public SoundPack(string folder)
		{
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Expected O, but got Unknown
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Expected O, but got Unknown
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Expected I4, but got Unknown
			//IL_040d: Unknown result type (might be due to invalid IL or missing references)
			SoundPlugin.logger.LogDebug((object)("Soundpack `" + folder + "` is being loaded."));
			Stopwatch stopwatch = Stopwatch.StartNew();
			PackPath = Path.Combine(Paths.PluginPath, folder);
			string text = File.ReadAllText(Path.Combine(PackPath, "sound_pack.json"));
			object obj = JsonConvert.DeserializeObject(text);
			JObject val = (JObject)((obj is JObject) ? obj : null);
			Name = (string)val["name"];
			if (string.IsNullOrEmpty(Name))
			{
				SoundPlugin.logger.LogError((object)("`name` is missing or empty in `" + folder + "/sound_pack.json`"));
				return;
			}
			if (!Directory.Exists(Path.Combine(PackPath, "replacers")))
			{
				SoundPlugin.logger.LogInfo((object)"You've succesfully made a Sound-Pack! Continue with the tutorial to learn how to begin replacing sounds.");
			}
			else
			{
				loadOnStartup = (from name in val.GetValueOrDefault("load_on_startup", new string[0])
					select name + ".json").ToArray();
				if (!val.ContainsKey("load_on_startup"))
				{
					SoundPlugin.logger.LogWarning((object)"No replacers were defined in `replacers` so every single replacer is being loaded on start-up. Consider adding some so that loaforcsSoundAPI can use multithreading.");
					loadOnStartup = Directory.GetFiles(Path.Combine(PackPath, "replacers")).Select(Path.GetFileName).ToArray();
				}
				SoundPlugin.logger.LogInfo((object)("Loading: " + string.Join(",", loadOnStartup) + " on startup."));
				ParseReplacers(loadOnStartup);
			}
			if (val.ContainsKey("config"))
			{
				Stopwatch stopwatch2 = Stopwatch.StartNew();
				ConfigFile val2 = new ConfigFile(Utility.CombinePaths(new string[2]
				{
					Paths.ConfigPath,
					"soundpack." + Name + ".cfg"
				}), false, MetadataHelper.GetMetadata((object)SoundPlugin.Instance));
				foreach (JProperty item in (IEnumerable<JToken>)val["config"])
				{
					JProperty val3 = item;
					JToken value = val3.Value;
					JObject val4 = (JObject)(object)((value is JObject) ? value : null);
					if (!val4.ContainsKey("default"))
					{
						SoundPlugin.logger.LogError((object)("`" + val3.Name + " doesn't have a default value!"));
						continue;
					}
					if (!val4.ContainsKey("description"))
					{
						SoundPlugin.logger.LogWarning((object)("`" + val3.Name + " doesn't have a description, consider adding one!"));
					}
					JTokenType type = val4["default"].Type;
					switch (type - 6)
					{
					case 3:
						Config.Add(val3.Name, val2.Bind<bool>(val3.Name.Split(":")[0], val3.Name.Split(":")[1], (bool)val4["default"], val4.GetValueOrDefault("description", "[no description was provided]")));
						break;
					case 2:
						Config.Add(val3.Name, val2.Bind<string>(val3.Name.Split(":")[0], val3.Name.Split(":")[1], (string)val4["default"], val4.GetValueOrDefault("description", "[no description was provided]")));
						break;
					case 0:
					case 1:
						Config.Add(val3.Name, val2.Bind<float>(val3.Name.Split(":")[0], val3.Name.Split(":")[1], (float)val4["default"], val4.GetValueOrDefault("description", "[no description was provided]")));
						break;
					default:
						SoundPlugin.logger.LogError((object)string.Format("`{0} configtype is currently unsupported! Supported values: bool, float, int, string", val4["default"].Type));
						break;
					}
				}
				stopwatch2.Stop();
				SoundPlugin.logger.LogInfo((object)$"Loaded {Name}(start-up:config) in {stopwatch2.ElapsedMilliseconds}ms.");
			}
			LoadedSoundPacks.Add(this);
			stopwatch.Stop();
			SoundPlugin.logger.LogInfo((object)$"Loaded {Name}(start-up) in {stopwatch.ElapsedMilliseconds}ms.");
		}

		internal void QueueNonStartupOnThreadPool(JoinableThreadPool threadPool)
		{
			if (!Directory.Exists(Path.Combine(PackPath, "replacers")))
			{
				return;
			}
			string[] array = (from replacer in Directory.GetFiles(Path.Combine(PackPath, "replacers")).Select(Path.GetFileName)
				where !loadOnStartup.Contains(replacer)
				select replacer).ToArray();
			string[] array2 = array;
			foreach (string replacer2 in array2)
			{
				threadPool.Queue(delegate
				{
					ParseReplacer(replacer2);
				});
			}
		}

		private void ParseReplacers(string[] replacers)
		{
			foreach (string replacer in replacers)
			{
				ParseReplacer(replacer);
			}
		}

		private void ParseReplacer(string replacer)
		{
			string path = Path.Combine(PackPath, "replacers", replacer);
			SoundPlugin.logger.LogDebug((object)("Parsing `" + Path.GetFileName(path) + "` as a sound replacer"));
			object obj = JsonConvert.DeserializeObject(File.ReadAllText(path));
			JObject data = (JObject)((obj is JObject) ? obj : null);
			new SoundReplaceGroup(this, data);
		}
	}
	public class SoundReplaceGroup : Conditonal
	{
		public SoundPack pack { get; private set; }

		internal RandomProvider Random { get; private set; }

		internal JObject RandomSettings { get; private set; }

		internal bool UpdateEveryFrame { get; private set; }

		public SoundReplaceGroup(SoundPack pack, JObject data)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			this.pack = pack;
			foreach (JObject item in (IEnumerable<JToken>)data["replacements"])
			{
				JObject data2 = item;
				new SoundReplacementCollection(this, data2);
			}
			Random = SoundReplacementAPI.RandomProviders["pure"];
			if (data.ContainsKey("randomness"))
			{
				JToken obj = data["randomness"];
				RandomSettings = (JObject)(object)((obj is JObject) ? obj : null);
				if (SoundReplacementAPI.RandomProviders.ContainsKey((string)RandomSettings["type"]))
				{
					Random = SoundReplacementAPI.RandomProviders[(string)RandomSettings["type"]];
				}
			}
			if (data.ContainsKey("condition"))
			{
				JToken obj2 = data["condition"];
				Setup(this, (JObject)(object)((obj2 is JObject) ? obj2 : null));
			}
			if (data.ContainsKey("update_every_frame"))
			{
				UpdateEveryFrame = (bool)data["update_every_frame"];
			}
		}
	}
	internal class SoundReplacementCollection : Conditonal
	{
		internal readonly List<SoundReplacement> replacements = new List<SoundReplacement>();

		private readonly List<string> matchers = new List<string>();

		internal readonly SoundReplaceGroup group;

		internal SoundReplacementCollection(SoundReplaceGroup group, JObject data)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			this.group = group;
			if (data.ContainsKey("condition"))
			{
				JToken obj = data["condition"];
				Setup(group, (JObject)(object)((obj is JObject) ? obj : null));
			}
			foreach (JObject item in (IEnumerable<JToken>)data["sounds"])
			{
				JObject val = item;
				SoundReplacement soundReplacement = new SoundReplacement(group, val)
				{
					SoundPath = (string)val["sound"],
					Weight = val.GetValueOrDefault("weight", 1)
				};
				SoundLoader.GetAudioClip(group.pack.PackPath, Path.GetDirectoryName(soundReplacement.SoundPath), Path.GetFileName(soundReplacement.SoundPath), out var clip);
				if ((Object)(object)clip == (Object)null)
				{
					SoundPlugin.logger.LogError((object)"Failed to get audio clip, check above more detailed error");
					continue;
				}
				soundReplacement.Clip = clip;
				replacements.Add(soundReplacement);
			}
			if (((object)data["matches"]).GetType() == typeof(JValue))
			{
				RegisterWithMatch((string)data["matches"]);
				return;
			}
			foreach (JToken item2 in (IEnumerable<JToken>)data["matches"])
			{
				string matchString = (string)item2;
				RegisterWithMatch(matchString);
			}
		}

		internal bool MatchesWith(string a)
		{
			foreach (string matcher in matchers)
			{
				if (SoundReplacementAPI.MatchStrings(a, matcher))
				{
					return true;
				}
			}
			return false;
		}

		private void RegisterWithMatch(string matchString)
		{
			string key = SoundReplacementAPI.FormatMatchString(matchString).Split(":")[2];
			List<SoundReplacementCollection> valueOrDefault = SoundReplacementAPI.SoundReplacements.GetValueOrDefault(key, new List<SoundReplacementCollection>());
			valueOrDefault.Add(this);
			matchers.Add(SoundReplacementAPI.FormatMatchString(matchString));
			SoundReplacementAPI.SoundReplacements[key] = valueOrDefault;
		}

		public override bool TestCondition()
		{
			if (base.TestCondition())
			{
				return group.TestCondition();
			}
			return false;
		}
	}
	internal class SoundReplacement : Conditonal
	{
		public int Weight = 1;

		public string SoundPath { get; set; }

		public AudioClip Clip { get; set; }

		public SoundReplacement(SoundReplaceGroup group, JObject data)
		{
			if (data.ContainsKey("condition"))
			{
				JToken obj = data["condition"];
				Setup(group, (JObject)(object)((obj is JObject) ? obj : null));
			}
		}
	}
}
namespace loaforcsSoundAPI.Behaviours
{
	public class AudioSourceReplaceHelper : MonoBehaviour
	{
		internal AudioSource source;

		internal SoundReplacementCollection replacedWith;

		internal static Dictionary<AudioSource, AudioSourceReplaceHelper> helpers = new Dictionary<AudioSource, AudioSourceReplaceHelper>();

		public bool DisableReplacing { get; private set; }

		private void Awake()
		{
			if ((Object)(object)source == (Object)null)
			{
				SoundPlugin.logger.LogWarning((object)("AudioSource (on gameobject: " + ((Object)((Component)this).gameObject).name + ") became null between the OnSceneLoaded callback and Awake."));
			}
			else
			{
				helpers[source] = this;
			}
		}

		private void OnEnable()
		{
			if (!((Object)(object)source == (Object)null))
			{
				helpers[source] = this;
			}
		}

		private void OnDestroy()
		{
			if (!((Object)(object)source == (Object)null) && helpers.ContainsKey(source))
			{
				helpers.Remove(source);
			}
		}

		private void LateUpdate()
		{
			if (replacedWith != null && replacedWith.group.UpdateEveryFrame)
			{
				DisableReplacing = true;
				float time = source.time;
				SoundReplacement soundReplacement = replacedWith.replacements.Where((SoundReplacement x) => x.TestCondition()).ToList()[0];
				if (!((Object)(object)soundReplacement.Clip == (Object)(object)source.clip))
				{
					source.clip = soundReplacement.Clip;
					source.Play();
					source.time = time;
				}
			}
		}
	}
}
namespace loaforcsSoundAPI.API
{
	public abstract class AudioFormatProvider
	{
		public abstract AudioClip LoadAudioClip(string path);

		protected AudioClip LoadFromUWR(string path, AudioType type)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			AudioClip result = null;
			UnityWebRequest audioClip = UnityWebRequestMultimedia.GetAudioClip(path, type);
			try
			{
				audioClip.SendWebRequest();
				try
				{
					while (!audioClip.isDone)
					{
					}
					if ((int)audioClip.result != 1)
					{
						SoundPlugin.logger.LogError((object)"============");
						SoundPlugin.logger.LogError((object)("UnityWebRequest failed while trying to get " + path + ". Full error below"));
						SoundPlugin.logger.LogError((object)audioClip.error);
						SoundPlugin.logger.LogError((object)"============");
					}
					else
					{
						result = DownloadHandlerAudioClip.GetContent(audioClip);
					}
				}
				catch (Exception ex)
				{
					SoundPlugin.logger.LogError((object)(ex.Message + ", " + ex.StackTrace));
				}
			}
			finally
			{
				((IDisposable)audioClip)?.Dispose();
			}
			return result;
		}
	}
	public abstract class ConditionProvider
	{
		public abstract bool Evaluate(SoundReplaceGroup group, JObject conditionDef);

		public bool EvaluateRangeOperator(JToken number, string condition)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)number.Type == 7)
			{
				return EvaluateRangeOperator(Extensions.Value<float>((IEnumerable<JToken>)number), condition);
			}
			return EvaluateRangeOperator(Extensions.Value<int>((IEnumerable<JToken>)number), condition);
		}

		public bool EvaluateRangeOperator(int number, string condition)
		{
			return EvaluateRangeOperator((double)number, condition);
		}

		public bool EvaluateRangeOperator(float number, string condition)
		{
			return EvaluateRangeOperator((double)number, condition);
		}

		public bool EvaluateRangeOperator(double number, string condition)
		{
			string[] array = condition.Split("..");
			if (array.Length == 1)
			{
				if (double.TryParse(array[0], out var result))
				{
					return number == result;
				}
				return false;
			}
			if (array.Length == 2)
			{
				double result2;
				if (array[0] == "")
				{
					result2 = double.MinValue;
				}
				else if (!double.TryParse(array[0], out result2))
				{
					return false;
				}
				double result3;
				if (array[1] == "")
				{
					result3 = double.MaxValue;
				}
				else if (!double.TryParse(array[1], out result3))
				{
					return false;
				}
				if (number >= result2)
				{
					return number <= result3;
				}
				return false;
			}
			return false;
		}
	}
	public abstract class Conditonal
	{
		private ConditionProvider GroupCondition;

		private SoundReplaceGroup group;

		internal JObject ConditionSettings { get; private set; }

		protected void Setup(SoundReplaceGroup group, JObject settings)
		{
			this.group = group;
			if (settings != null)
			{
				ConditionSettings = settings;
				GroupCondition = SoundReplacementAPI.ConditionProviders[(string)ConditionSettings["type"]];
			}
		}

		public virtual bool TestCondition()
		{
			if (GroupCondition == null)
			{
				return true;
			}
			return GroupCondition.Evaluate(group, ConditionSettings);
		}
	}
	public abstract class RandomProvider
	{
		public abstract int Range(SoundReplaceGroup group, int min, int max);
	}
	public static class SoundReplacementAPI
	{
		internal static Dictionary<string, AudioFormatProvider> FileFormats = new Dictionary<string, AudioFormatProvider>();

		internal static Dictionary<string, RandomProvider> RandomProviders = new Dictionary<string, RandomProvider>();

		internal static Dictionary<string, ConditionProvider> ConditionProviders = new Dictionary<string, ConditionProvider>();

		internal static ConcurrentDictionary<string, List<SoundReplacementCollection>> SoundReplacements = new ConcurrentDictionary<string, List<SoundReplacementCollection>>();

		public static void RegisterAudioFormatProvider(string extension, AudioFormatProvider provider)
		{
			FileFormats.Add(extension, provider);
		}

		public static void RegisterRandomProvider(string extension, RandomProvider provider)
		{
			RandomProviders.Add(extension, provider);
		}

		public static void RegisterConditionProvider(string extension, ConditionProvider provider)
		{
			ConditionProviders.Add(extension, provider);
		}

		public static string FormatMatchString(string input)
		{
			if (input.Split(":").Length == 2)
			{
				input = "*:" + input;
			}
			return input;
		}

		public static bool MatchStrings(string a, string b)
		{
			SoundPlugin.logger.LogDebug((object)(a + " == " + b + "?"));
			string[] array = a.Split(":");
			string[] array2 = b.Split(":");
			if (array2[0] != "*" && array2[0] != array[0])
			{
				return false;
			}
			if (array2[1] != "*" && array2[1] != array[1])
			{
				return false;
			}
			return array[2] == array2[2];
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}