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)
{
}
}
}