using System;
using System.Buffers;
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.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using loaforcsSoundAPI.Core;
using loaforcsSoundAPI.Core.Data;
using loaforcsSoundAPI.Core.JSON;
using loaforcsSoundAPI.Core.Networking;
using loaforcsSoundAPI.Core.Patches;
using loaforcsSoundAPI.Core.Util;
using loaforcsSoundAPI.Reporting;
using loaforcsSoundAPI.Reporting.Data;
using loaforcsSoundAPI.SoundPacks;
using loaforcsSoundAPI.SoundPacks.Data;
using loaforcsSoundAPI.SoundPacks.Data.Conditions;
using loaforcsSoundAPI.Util.Extensions;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("loaforc")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: AssemblyInformationalVersion("2.0.0+1c5da9aa0ecea20002b9c72ce776120988276ecd")]
[assembly: AssemblyProduct("loaforcsSoundAPI")]
[assembly: AssemblyTitle("me.loaforc.soundapi")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/LoafOrc/loaforcsSoundAPI")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.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]
[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
{
[BepInPlugin("me.loaforc.soundapi", "loaforcsSoundAPI", "2.0.0")]
internal class loaforcsSoundAPI : BaseUnityPlugin
{
private static loaforcsSoundAPI _instance;
internal static ManualLogSource Logger { get; private set; }
private void Awake()
{
_instance = this;
Logger = Logger.CreateLogSource("me.loaforc.soundapi");
((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
Logger.LogInfo((object)"Setting up config");
Debuggers.Bind(((BaseUnityPlugin)this).Config);
SoundReportHandler.Bind(((BaseUnityPlugin)this).Config);
Logger.LogInfo((object)"Running patches");
Harmony harmony = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "me.loaforc.soundapi");
UnityObjectPatch.Init(harmony);
Logger.LogInfo((object)"Registering data");
SoundAPI.RegisterAll(Assembly.GetExecutingAssembly());
SoundReplacementHandler.Register();
((BaseUnityPlugin)this).Config.Save();
Logger.LogInfo((object)"me.loaforc.soundapi by loaforc has loaded :3");
}
internal static ConfigFile GenerateConfigFile(string name)
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Expected O, but got Unknown
return new ConfigFile(Utility.CombinePaths(new string[2]
{
Paths.ConfigPath,
name + ".cfg"
}), false, MetadataHelper.GetMetadata((object)_instance));
}
}
public static class SoundAPI
{
public const string PLUGIN_GUID = "me.loaforc.soundapi";
internal static NetworkAdapter CurrentNetworkAdapter { get; private set; }
public static void RegisterAll(Assembly assembly)
{
foreach (Type loadableType in assembly.GetLoadableTypes())
{
if (loadableType.IsNested)
{
continue;
}
SoundAPIConditionAttribute soundAPIConditionAttribute = (SoundAPIConditionAttribute)loadableType.GetCustomAttribute(typeof(SoundAPIConditionAttribute));
if (soundAPIConditionAttribute == null)
{
continue;
}
if (loadableType.BaseType == null || (loadableType.BaseType != typeof(Condition) && loadableType.BaseType.GetGenericTypeDefinition() != typeof(Condition<>)))
{
loaforcsSoundAPI.Logger.LogError((object)("Condition: '" + loadableType.FullName + "' has been marked with [SoundAPICondition] but does not extend Condition!"));
continue;
}
ConstructorInfo info = loadableType.GetConstructor(Array.Empty<Type>());
if (info == null)
{
loaforcsSoundAPI.Logger.LogError((object)("Condition: '" + loadableType.FullName + "' has no valid constructor! It must have a constructor with no parameters! If you need extra parameters do not mark it with [SoundAPICondition] and Register it manually."));
continue;
}
RegisterCondition(soundAPIConditionAttribute.ID, () => (Condition)info.Invoke(Array.Empty<object>()));
}
}
public static void RegisterCondition(string id, Func<Condition> factory)
{
SoundPackDataHandler.Register(id, factory);
}
public static void RegisterNetworkAdapter(NetworkAdapter adapter)
{
CurrentNetworkAdapter = adapter;
loaforcsSoundAPI.Logger.LogInfo((object)("Registered network adapter: '" + CurrentNetworkAdapter.Name + "'"));
CurrentNetworkAdapter.OnRegister();
}
public static void RegisterSoundPack(SoundPack pack)
{
if (SoundPackDataHandler.LoadedPacks.Contains(pack))
{
throw new InvalidOperationException("Already registered sound-pack: '" + pack.Name + "'!");
}
SoundPackDataHandler.AddLoadedPack(pack);
foreach (SoundReplacementCollection replacementCollection in pack.ReplacementCollections)
{
foreach (SoundReplacementGroup replacement in replacementCollection.Replacements)
{
SoundPackDataHandler.AddReplacement(replacement);
}
}
}
}
internal static class MyPluginInfo
{
public const string PLUGIN_GUID = "me.loaforc.soundapi";
public const string PLUGIN_NAME = "loaforcsSoundAPI";
public const string PLUGIN_VERSION = "2.0.0";
}
}
namespace loaforcsSoundAPI.Util.Extensions
{
internal static class AssemblyExtensions
{
internal static IEnumerable<Type> GetLoadableTypes(this Assembly assembly)
{
if (assembly == null)
{
throw new ArgumentNullException("assembly");
}
try
{
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
return ex.Types.Where((Type t) => t != null);
}
}
}
}
namespace loaforcsSoundAPI.SoundPacks
{
internal class LoadSoundOperation
{
public readonly UnityWebRequest WebRequest = webRequest.webRequest;
public readonly SoundInstance Sound;
public bool IsReady => WebRequest.isDone;
public bool IsDone { get; set; }
public LoadSoundOperation(SoundInstance soundInstance, UnityWebRequestAsyncOperation webRequest)
{
Sound = soundInstance;
base..ctor();
}
}
internal static class SoundPackDataHandler
{
private static List<SoundPack> _loadedPacks = new List<SoundPack>();
internal static Dictionary<string, List<SoundReplacementGroup>> SoundReplacements = new Dictionary<string, List<SoundReplacementGroup>>();
internal static Dictionary<string, Func<Condition>> conditionFactories = new Dictionary<string, Func<Condition>>();
internal static List<AudioClip> allLoadedClips = new List<AudioClip>();
internal static IReadOnlyList<SoundPack> LoadedPacks => _loadedPacks.AsReadOnly();
internal static void Register(string id, Func<Condition> factory)
{
conditionFactories[id] = factory;
}
public static Condition CreateCondition(string id)
{
if (conditionFactories.TryGetValue(id, out var value))
{
return value();
}
return new InvalidCondition(id);
}
internal static void AddLoadedPack(SoundPack pack)
{
_loadedPacks.Add(pack);
}
internal static void AddReplacement(SoundReplacementGroup group)
{
foreach (string match in group.Matches)
{
string key = match.Split(":").Last();
if (!SoundReplacements.TryGetValue(key, out var value))
{
value = new List<SoundReplacementGroup>();
}
if (!value.Contains(group))
{
value.Add(group);
SoundReplacements[key] = value;
}
}
}
}
internal static class SoundPackLoadPipeline
{
private static volatile int _activeThreads;
private static Dictionary<string, List<string>> mappings;
internal static event Action OnFinishedPipeline;
internal static async void StartPipeline()
{
Stopwatch completeLoadingTimer = Stopwatch.StartNew();
Stopwatch timer = Stopwatch.StartNew();
List<SoundPack> list = FindAndLoadPacks();
loaforcsSoundAPI.Logger.LogInfo((object)$"(Step 1) Loading Sound-pack definitions took {timer.ElapsedMilliseconds}ms");
timer.Restart();
List<LoadSoundOperation> webRequestOperations = new List<LoadSoundOperation>();
foreach (SoundPack item2 in list)
{
string path = Path.Combine(item2.PackFolder, "soundapi_mappings.json");
if (!File.Exists(path))
{
continue;
}
Dictionary<string, List<string>> dictionary = JSONDataLoader.LoadFromFile<Dictionary<string, List<string>>>(path);
foreach (KeyValuePair<string, List<string>> item3 in dictionary)
{
if (mappings.ContainsKey(item3.Key))
{
mappings[item3.Key].AddRange(item3.Value);
}
else
{
mappings[item3.Key] = item3.Value;
}
}
}
loaforcsSoundAPI.Logger.LogInfo((object)$"(Step 2) Loading Sound-pack mappings ('{mappings.Count}') took {timer.ElapsedMilliseconds}ms");
timer.Restart();
foreach (SoundPack item4 in list)
{
foreach (SoundReplacementCollection item5 in LoadSoundReplacementCollections(item4))
{
item5.Pack = item4;
foreach (SoundReplacementGroup replacement in item5.Replacements)
{
replacement.Parent = item5;
List<IValidatable.ValidationResult> results = replacement.Validate();
if (!IValidatable.LogAndCheckValidationResult("loading a replacement group in '" + LogFormats.FormatFilePath(item5.FilePath) + "'", results))
{
continue;
}
List<IValidatable.ValidationResult> list2 = new List<IValidatable.ValidationResult>();
foreach (SoundInstance sound in replacement.Sounds)
{
sound.Parent = replacement;
list2.AddRange(sound.Validate());
}
if (!IValidatable.LogAndCheckValidationResult("loading a replacement group in '" + LogFormats.FormatFilePath(item5.FilePath) + "'", list2))
{
continue;
}
SoundPackDataHandler.AddReplacement(replacement);
foreach (SoundInstance sound2 in replacement.Sounds)
{
webRequestOperations.Add(StartWebRequestOperation(item4, sound2));
}
}
}
}
int amountOfOperations = webRequestOperations.Count;
loaforcsSoundAPI.Logger.LogInfo((object)$"(Step 3) Loading sound replacement collections took {timer.ElapsedMilliseconds}ms");
if (SoundReportHandler.CurrentReport != null)
{
SoundReportHandler.CurrentReport.AudioClipsLoaded = amountOfOperations;
}
loaforcsSoundAPI.Logger.LogInfo((object)$"(Step 4) Started loading {amountOfOperations} audio file(s)");
loaforcsSoundAPI.Logger.LogInfo((object)"Waiting for splash screens to complete to continue...");
completeLoadingTimer.Stop();
await Task.Delay(1);
loaforcsSoundAPI.Logger.LogInfo((object)"Splash screens done! Continuing pipeline");
loaforcsSoundAPI.Logger.LogWarning((object)"The game will freeze for a moment!");
timer.Restart();
completeLoadingTimer.Start();
bool flag = false;
ConcurrentQueue<LoadSoundOperation> queuedOperations = new ConcurrentQueue<LoadSoundOperation>();
ConcurrentBag<Exception> threadPoolExceptions = new ConcurrentBag<Exception>();
for (int i = 0; i < 8; i++)
{
Task.Run(delegate
{
while (queuedOperations.Count == 0)
{
Thread.Sleep(10);
}
Interlocked.Increment(ref _activeThreads);
Debuggers.SoundReplacementLoader?.Log($"active threads at {_activeThreads}");
LoadSoundOperation result;
while (queuedOperations.TryDequeue(out result))
{
try
{
AudioClip content2 = DownloadHandlerAudioClip.GetContent(result.WebRequest);
result.Sound.Clip = content2;
result.WebRequest.Dispose();
Debuggers.SoundReplacementLoader?.Log("clip generated");
result.IsDone = true;
}
catch (Exception item)
{
threadPoolExceptions.Add(item);
}
}
Interlocked.Decrement(ref _activeThreads);
});
}
bool flag2 = true;
try
{
while (webRequestOperations.Count > 0)
{
foreach (LoadSoundOperation item6 in from operation in webRequestOperations.ToList()
where operation.IsReady
select operation)
{
if (flag2)
{
queuedOperations.Enqueue(item6);
}
else
{
AudioClip content = DownloadHandlerAudioClip.GetContent(item6.WebRequest);
item6.Sound.Clip = content;
item6.WebRequest.Dispose();
Debuggers.SoundReplacementLoader?.Log("clip generated");
}
webRequestOperations.Remove(item6);
}
if (!flag && webRequestOperations.Count < amountOfOperations / 2)
{
flag = true;
loaforcsSoundAPI.Logger.LogInfo((object)"(Step 5) Queued half of the needed operations!");
}
Thread.Sleep(100);
}
loaforcsSoundAPI.Logger.LogInfo((object)"(Step 5) All file reads are done, waiting for the audio clips conversions.");
while (_activeThreads > 0 || webRequestOperations.Any((LoadSoundOperation operation) => !operation.IsDone))
{
Thread.Sleep(100);
}
loaforcsSoundAPI.Logger.LogInfo((object)$"(Step 6) Took {timer.ElapsedMilliseconds}ms to finish loading audio clips from files");
if (threadPoolExceptions.Count != 0)
{
loaforcsSoundAPI.Logger.LogError((object)$"(Step 6) {threadPoolExceptions.Count} internal error(s) happened while loading:");
foreach (Exception item7 in threadPoolExceptions)
{
loaforcsSoundAPI.Logger.LogError((object)item7.ToString());
}
}
SoundPackLoadPipeline.OnFinishedPipeline();
mappings = null;
loaforcsSoundAPI.Logger.LogDebug((object)$"Active Threads that are left over: {_activeThreads}");
loaforcsSoundAPI.Logger.LogInfo((object)$"Entire load process took an effective {completeLoadingTimer.ElapsedMilliseconds}ms");
}
catch (Exception ex)
{
loaforcsSoundAPI.Logger.LogError((object)ex);
}
}
private static List<SoundPack> FindAndLoadPacks(string entryPoint = "sound_pack.json")
{
List<SoundPack> list = new List<SoundPack>();
string[] files = Directory.GetFiles(Paths.PluginPath, entryPoint, SearchOption.AllDirectories);
foreach (string text in files)
{
Debuggers.SoundReplacementLoader?.Log("found entry point: '" + text + "'!");
SoundPack soundPack = JSONDataLoader.LoadFromFile<SoundPack>(text);
if (soundPack != null)
{
soundPack.PackFolder = Path.GetDirectoryName(text);
Debuggers.SoundReplacementLoader?.Log("json loaded, validating");
List<IValidatable.ValidationResult> results = soundPack.Validate();
if (IValidatable.LogAndCheckValidationResult("loading '" + text + "'", results))
{
ConfigFile val = loaforcsSoundAPI.GenerateConfigFile("soundpack." + soundPack.Name);
val.SaveOnConfigSet = false;
soundPack.Bind(val);
val.Save();
list.Add(soundPack);
SoundPackDataHandler.AddLoadedPack(soundPack);
Debuggers.SoundReplacementLoader?.Log("pack folder: " + soundPack.PackFolder);
}
}
}
Debuggers.SoundReplacementLoader?.Log($"loaded '{list.Count}' packs.");
return list;
}
private static List<SoundReplacementCollection> LoadSoundReplacementCollections(SoundPack pack)
{
List<SoundReplacementCollection> list = new List<SoundReplacementCollection>();
if (!Directory.Exists(Path.Combine(pack.PackFolder, "replacers")))
{
return list;
}
Debuggers.SoundReplacementLoader?.Log("start loading '" + pack.Name + "'!");
string[] files = Directory.GetFiles(Path.Combine(pack.PackFolder, "replacers"), "*.json", SearchOption.AllDirectories);
foreach (string text in files)
{
Debuggers.SoundReplacementLoader?.Log("found replacer: '" + text + "'!");
SoundReplacementCollection soundReplacementCollection = JSONDataLoader.LoadFromFile<SoundReplacementCollection>(text);
if (soundReplacementCollection == null)
{
continue;
}
foreach (SoundReplacementGroup replacement in soundReplacementCollection.Replacements)
{
foreach (string item in replacement.Matches.ToList())
{
if (item.StartsWith("#"))
{
replacement.Matches.Remove(item);
List<string> matches = replacement.Matches;
Dictionary<string, List<string>> dictionary = mappings;
string text2 = item;
matches.AddRange(dictionary[text2.Substring(1, text2.Length - 1)]);
}
}
List<string> collection = replacement.Matches.Select((string match) => (match.Split(":").Length != 2) ? match : ("*:" + match)).ToList();
replacement.Matches.Clear();
replacement.Matches.AddRange(collection);
}
list.Add(soundReplacementCollection);
}
return list;
}
private static LoadSoundOperation StartWebRequestOperation(SoundPack pack, SoundInstance sound)
{
string text = Path.Combine(pack.PackFolder, "sounds", sound.Sound);
UnityWebRequest audioClip = UnityWebRequestMultimedia.GetAudioClip(text, (AudioType)14);
return new LoadSoundOperation(sound, audioClip.SendWebRequest());
}
static SoundPackLoadPipeline()
{
SoundPackLoadPipeline.OnFinishedPipeline = delegate
{
};
mappings = new Dictionary<string, List<string>>();
}
}
internal static class SoundReplacementHandler
{
private const int TOKEN_PARENT_NAME = 0;
private const int TOKEN_OBJECT_NAME = 1;
private const int TOKEN_CLIP_NAME = 2;
private static readonly string[] _suffixesToRemove = new string[1] { "(Clone)" };
private static readonly Dictionary<int, string> _cachedObjectNames = new Dictionary<int, string>();
private static readonly StringBuilder _builder = new StringBuilder();
internal static readonly DefaultConditionContext DEFAULT_CONTEXT = new DefaultConditionContext();
internal static void Register()
{
SceneManager.sceneLoaded += delegate(Scene scene, LoadSceneMode _)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
_cachedObjectNames.Clear();
AudioSource[] array = Object.FindObjectsOfType<AudioSource>(true);
foreach (AudioSource val in array)
{
if (!(((Component)val).gameObject.scene != scene) && val.playOnAwake && TryReplaceAudio(val, val.clip, out var replacement))
{
val.Stop();
if (!((Object)(object)replacement == (Object)null))
{
val.clip = replacement;
}
}
}
};
}
internal static bool TryReplaceAudio(AudioSource source, AudioClip clip, out AudioClip replacement)
{
replacement = null;
if ((Object)(object)((Component)source).gameObject == (Object)null)
{
return false;
}
AudioSourceAdditionalData orCreate = AudioSourceAdditionalData.GetOrCreate(source);
if (orCreate.ReplacedWith != null && orCreate.ReplacedWith.Parent.UpdateEveryFrame)
{
return false;
}
string[] name = ArrayPool<string>.Shared.Rent(3);
if (!TryProcessName(ref name, source, clip) || !TryGetReplacementClip(name, out var group, out var clip2, orCreate.CurrentContext ?? DEFAULT_CONTEXT))
{
ArrayPool<string>.Shared.Return(name);
return false;
}
ArrayPool<string>.Shared.Return(name);
((Object)clip2).name = ((Object)clip).name;
replacement = clip2;
orCreate.ReplacedWith = group;
return true;
}
private static string TrimObjectName(GameObject gameObject)
{
if (_cachedObjectNames.ContainsKey(((object)gameObject).GetHashCode()))
{
return _cachedObjectNames[((object)gameObject).GetHashCode()];
}
_builder.Clear();
_builder.Append(((Object)gameObject).name);
string[] suffixesToRemove = _suffixesToRemove;
foreach (string oldValue in suffixesToRemove)
{
_builder.Replace(oldValue, string.Empty);
}
for (int j = 0; j < _builder.Length; j++)
{
if (_builder[j] == '(')
{
int num = j;
for (j++; j < _builder.Length && char.IsDigit(_builder[j]); j++)
{
}
if (j < _builder.Length && _builder[j] == ')')
{
_builder.Remove(num, j - num + 1);
j = num - 1;
}
}
}
int num2 = _builder.Length;
while (num2 > 0 && _builder[num2 - 1] == ' ')
{
num2--;
}
_builder.Remove(num2, _builder.Length - num2);
string text = _builder.ToString();
_cachedObjectNames[((object)gameObject).GetHashCode()] = text;
return text;
}
private static bool TryProcessName(ref string[] name, AudioSource source, AudioClip clip)
{
if ((Object)(object)clip == (Object)null)
{
return false;
}
if ((Object)(object)((Component)source).transform.parent == (Object)null)
{
name[0] = "*";
}
else
{
name[0] = TrimObjectName(((Component)((Component)source).transform.parent).gameObject);
}
name[1] = TrimObjectName(((Component)source).gameObject);
name[2] = ((Object)clip).name;
if (SoundReportHandler.CurrentReport != null)
{
string text;
try
{
text = new StackTrace(fNeedFileInfo: true).GetFrame(5).GetMethod().DeclaringType.Name;
}
catch
{
text = "<unknown>";
}
string text2 = name[0] + ":" + name[1] + ":" + name[2];
if (!SoundReportHandler.CurrentReport.AllMatchStrings.Contains(text2))
{
SoundReportHandler.CurrentReport.AllMatchStrings.Add(text + " > " + text2);
SoundReportHandler.CurrentReport.RawMatchStrings.Add(text2);
Debuggers.MatchStrings?.Log(text2);
}
}
return true;
}
private static bool TryGetReplacementClip(string[] name, out SoundReplacementGroup group, out AudioClip clip, IContext context)
{
group = null;
clip = null;
if (name == null)
{
return false;
}
Debuggers.SoundReplacementHandler?.Log("beginning replacement attempt for " + name[2]);
if (!SoundPackDataHandler.SoundReplacements.TryGetValue(name[2], out var value))
{
return false;
}
Debuggers.SoundReplacementHandler?.Log("sound dictionary hit");
value = value.Where((SoundReplacementGroup it) => it.Parent.Evaluate(context) && it.Evaluate(context) && CheckGroupMatches(it, name)).ToList();
if (value.Count == 0)
{
return false;
}
Debuggers.SoundReplacementHandler?.Log("sound group that matches");
group = value[Random.Range(0, value.Count)];
List<SoundInstance> list = group.Sounds.Where((SoundInstance it) => it.Evaluate(context)).ToList();
if (list.Count == 0)
{
return false;
}
Debuggers.SoundReplacementHandler?.Log("has valid sounds");
int totalWeight = 0;
list.ForEach(delegate(SoundInstance replacement)
{
totalWeight += replacement.Weight;
});
int num = Random.Range(0, totalWeight);
SoundInstance soundInstance = null;
foreach (SoundInstance item in list)
{
soundInstance = item;
num -= soundInstance.Weight;
if (num <= 0)
{
break;
}
}
clip = soundInstance.Clip;
Debuggers.SoundReplacementHandler?.Log("done, dumping stack trace!");
Debuggers.SoundReplacementHandler?.Log(string.Join(", ", group.Matches));
Debuggers.SoundReplacementHandler?.Log(((Object)clip).name);
Debuggers.SoundReplacementHandler?.Log(new StackTrace(fNeedFileInfo: true).ToString().Trim());
return true;
}
private static bool CheckGroupMatches(SoundReplacementGroup group, string[] a)
{
foreach (string match in group.Matches)
{
if (MatchStrings(a, match))
{
return true;
}
}
return false;
}
private static bool MatchStrings(string[] a, string b)
{
string[] array = b.Split(":");
if (array[0] != "*" && array[0] != a[0])
{
return false;
}
if (array[1] != "*" && array[1] != a[1])
{
return false;
}
return a[2] == array[2];
}
}
}
namespace loaforcsSoundAPI.SoundPacks.Data
{
public interface IPackData
{
SoundPack Pack { get; internal set; }
}
public class SoundInstance : Conditional
{
[field: NonSerialized]
public SoundReplacementGroup Parent { get; internal set; }
public string Sound { get; private set; }
public int Weight { get; private set; }
[field: NonSerialized]
public AudioClip Clip { get; internal set; }
public override SoundPack Pack
{
get
{
return Parent.Pack;
}
set
{
if (Parent.Pack != null)
{
throw new InvalidOperationException("Pack has already been set.");
}
Parent.Pack = value;
}
}
[JsonConstructor]
internal SoundInstance()
{
}
public SoundInstance(SoundReplacementGroup parent, int weight, AudioClip clip)
{
Parent = parent;
Weight = weight;
Clip = clip;
parent.AddSoundReplacement(this);
}
public override List<IValidatable.ValidationResult> Validate()
{
List<IValidatable.ValidationResult> list = base.Validate();
if (!File.Exists(Path.Combine(Parent.Parent.Pack.PackFolder, "sounds", Sound)))
{
list.Add(new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, "Sound '" + Sound + "' couldn't be found or doesn't exist!"));
}
return list;
}
}
public class SoundPack : IValidatable
{
[NonSerialized]
private readonly Dictionary<string, object> _configData = new Dictionary<string, object>();
[JsonProperty]
private Dictionary<string, JObject> config { get; set; }
public string Name { get; private set; }
public string PackFolder { get; internal set; }
[field: NonSerialized]
public List<SoundReplacementCollection> ReplacementCollections { get; private set; } = new List<SoundReplacementCollection>();
[JsonConstructor]
internal SoundPack()
{
}
internal void Bind(ConfigFile file)
{
//IL_0095: 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_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Invalid comparison between Unknown and I4
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Invalid comparison between Unknown and I4
if (config == null || config.Count == 0)
{
return;
}
loaforcsSoundAPI.Logger.LogDebug((object)"handling config");
JToken val2 = default(JToken);
foreach (KeyValuePair<string, JObject> item in config)
{
string[] array = item.Key.Split(":");
string text = array[0];
string text2 = array[1];
JToken val = item.Value["default"];
string text3 = (item.Value.TryGetValue("description", ref val2) ? ((object)val2).ToString() : "no description defined!");
JTokenType type = val.Type;
if ((int)type != 8)
{
if ((int)type != 9)
{
throw new NotImplementedException("WHAT");
}
_configData[item.Key] = file.Bind<bool>(text, text2, (bool)val, text3).Value;
}
else
{
_configData[item.Key] = file.Bind<string>(text, text2, (string)val, text3).Value;
}
}
}
public SoundPack(string name, string packFolder)
{
Name = name;
PackFolder = packFolder;
}
internal bool TryGetConfigValue(string id, out object returnValue)
{
returnValue = null;
if (!_configData.TryGetValue(id, out var value))
{
return false;
}
returnValue = value;
return true;
}
public List<IValidatable.ValidationResult> Validate()
{
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Invalid comparison between Unknown and I4
//IL_0117: Unknown result type (might be due to invalid IL or missing references)
//IL_011d: Invalid comparison between Unknown and I4
//IL_012f: Unknown result type (might be due to invalid IL or missing references)
List<IValidatable.ValidationResult> list = new List<IValidatable.ValidationResult>();
if (string.IsNullOrEmpty(Name))
{
list.Add(new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, "'name' can not be missing or empty!"));
return list;
}
string name = Name;
foreach (char c in name)
{
if (!char.IsLetter(c) && c != '_')
{
list.Add(new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, $"'name' can not contain special character '{c}'!"));
}
}
if (config == null)
{
return list;
}
JToken val = default(JToken);
foreach (KeyValuePair<string, JObject> item in config)
{
string[] array = item.Key.Split(":");
if (array.Length != 2)
{
list.Add(new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, "'" + item.Key + "' is not a valid key for config! It must be 'section:name' with exactly one colon!"));
}
if (!item.Value.TryGetValue("default", ref val))
{
list.Add(new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, "'" + item.Key + "' does not have a 'default' value! This is needed to get what type the config is!"));
}
else if ((int)val.Type != 9 && (int)val.Type != 8)
{
list.Add(new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, $"'{item.Key}' is of unsupported type: '{val.Type}'! Only supported types are strings/text or booleans!"));
}
if (!item.Value.ContainsKey("description"))
{
list.Add(new IValidatable.ValidationResult(IValidatable.ResultType.WARN, "'" + item.Key + "' does not have a description."));
}
}
return list;
}
}
public class SoundReplacementCollection : Conditional, IFilePathAware, IPackData
{
[field: NonSerialized]
public override SoundPack Pack { get; set; }
[JsonProperty("update_every_frame")]
public bool UpdateEveryFrame { get; private set; }
public bool Synced { get; private set; }
public List<SoundReplacementGroup> Replacements { get; private set; } = new List<SoundReplacementGroup>();
public string FilePath { get; set; }
[JsonConstructor]
internal SoundReplacementCollection()
{
}
public SoundReplacementCollection(SoundPack pack)
{
Pack = pack;
pack.ReplacementCollections.Add(this);
}
internal void AddSoundReplacementGroup(SoundReplacementGroup group)
{
Replacements.Add(group);
}
}
public class SoundReplacementGroup : Conditional
{
[field: NonSerialized]
public SoundReplacementCollection Parent { get; internal set; }
public List<string> Matches { get; private set; }
public List<SoundInstance> Sounds { get; private set; } = new List<SoundInstance>();
public override SoundPack Pack
{
get
{
return Parent.Pack;
}
set
{
if (Parent.Pack != null)
{
throw new InvalidOperationException("Pack has already been set.");
}
Parent.Pack = value;
}
}
[JsonConstructor]
internal SoundReplacementGroup()
{
}
public SoundReplacementGroup(SoundReplacementCollection parent, List<string> matches)
{
Parent = parent;
Matches = matches;
if (SoundPackDataHandler.LoadedPacks.Contains(parent.Pack))
{
throw new InvalidOperationException("SoundPack has already been registered, trying to add a new SoundReplacementGroup does not work!");
}
parent.AddSoundReplacementGroup(this);
}
internal void AddSoundReplacement(SoundInstance sound)
{
Sounds.Add(sound);
}
public override List<IValidatable.ValidationResult> Validate()
{
List<IValidatable.ValidationResult> list = base.Validate();
foreach (string match in Matches)
{
if (string.IsNullOrEmpty(match))
{
list.Add(new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, "Match string can not be empty!"));
continue;
}
string[] array = match.Split(":");
if (array.Length == 1)
{
list.Add(new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, "'" + match + "' is not valid! If you mean to match to all Audio clips with this name you must explicitly do '*:" + match + "'."));
}
}
return list;
}
}
}
namespace loaforcsSoundAPI.SoundPacks.Data.Conditions
{
public abstract class Condition : IValidatable
{
[field: NonSerialized]
public Conditional Parent { get; internal set; }
protected SoundPack Pack => Parent.Pack;
public abstract bool Evaluate(IContext context);
public virtual List<IValidatable.ValidationResult> Validate()
{
return new List<IValidatable.ValidationResult>();
}
protected bool EvaluateRangeOperator(int number, string condition)
{
return EvaluateRangeOperator((double)number, condition);
}
protected bool EvaluateRangeOperator(float number, string condition)
{
return EvaluateRangeOperator((double)number, condition);
}
protected bool EvaluateRangeOperator(double value, string condition)
{
string[] array = condition.Split("..");
if (array.Length == 1)
{
if (double.TryParse(array[0], out var result))
{
return value == 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 (value >= result2)
{
return value <= result3;
}
return false;
}
return false;
}
protected bool ValidateRangeOperator(string condition, out IValidatable.ValidationResult result)
{
result = null;
if (string.IsNullOrEmpty(condition))
{
result = new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, "Range operator can not be missing or empty!");
return false;
}
string[] array = condition.Split("..");
int num = array.Length;
if (num <= 2)
{
switch (num)
{
case 1:
{
if (!double.TryParse(array[0], out var _))
{
result = new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, "Failed to parse: '" + array[0] + "' as a number!");
}
break;
}
case 2:
{
double num2;
if (array[0] == "")
{
num2 = double.MinValue;
}
else if (!double.TryParse(array[0], out num2))
{
result = new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, "Failed to parse: '" + array[0] + "' as a number!");
}
double num3;
if (array[1] == "")
{
num3 = double.MaxValue;
}
else if (!double.TryParse(array[1], out num3))
{
result = new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, "Failed to parse: '" + array[1] + "' as a number!");
}
break;
}
}
}
else
{
result = new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, "Range operator: '" + condition + "' uses .. more than once!");
}
return result == null;
}
}
internal sealed class InvalidCondition : Condition
{
[CompilerGenerated]
private string <type>P;
public InvalidCondition(string type)
{
<type>P = type;
base..ctor();
}
public override bool Evaluate(IContext context)
{
return false;
}
public override List<IValidatable.ValidationResult> Validate()
{
if (string.IsNullOrEmpty(<type>P))
{
return new List<IValidatable.ValidationResult>(1)
{
new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, "Condition must have a type!")
};
}
return new List<IValidatable.ValidationResult>(1)
{
new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, "'" + <type>P + "' is not a valid condition type!")
};
}
}
public abstract class Condition<TContext> : Condition where TContext : IContext
{
public override bool Evaluate(IContext context)
{
if (!(context is TContext context2))
{
return EvaluateFallback(context);
}
return EvaluateWithContext(context2);
}
protected abstract bool EvaluateWithContext(TContext context);
protected virtual bool EvaluateFallback(IContext context)
{
return false;
}
}
public abstract class Conditional : IValidatable, IPackData
{
public Condition Condition { get; set; }
public abstract SoundPack Pack { get; set; }
public bool Evaluate(IContext context)
{
if (Condition == null)
{
return true;
}
return Condition.Evaluate(context);
}
public virtual List<IValidatable.ValidationResult> Validate()
{
if (Condition == null)
{
return new List<IValidatable.ValidationResult>();
}
Condition.Parent = this;
return Condition.Validate();
}
}
public interface IContext
{
}
internal class DefaultConditionContext : IContext
{
}
[AttributeUsage(AttributeTargets.Class)]
[MeansImplicitUse]
public class SoundAPIConditionAttribute : Attribute
{
public string ID { get; private set; }
public SoundAPIConditionAttribute(string id)
{
ID = id;
base..ctor();
}
}
}
namespace loaforcsSoundAPI.SoundPacks.Conditions
{
[SoundAPICondition("and")]
internal class AndCondition : Condition<DefaultConditionContext>
{
public Condition[] Conditions { get; private set; }
protected override bool EvaluateWithContext(DefaultConditionContext context)
{
Condition[] conditions = Conditions;
foreach (Condition condition in conditions)
{
if (condition is InvalidCondition)
{
return false;
}
if (!condition.Evaluate(context))
{
return false;
}
}
return true;
}
public override List<IValidatable.ValidationResult> Validate()
{
if (Conditions.Length == 0)
{
return new List<IValidatable.ValidationResult>(1)
{
new IValidatable.ValidationResult(IValidatable.ResultType.WARN, "'and' condition has no conditions and will always return true!")
};
}
return new List<IValidatable.ValidationResult>();
}
}
[SoundAPICondition("config")]
internal class ConfigCondition : Condition<DefaultConditionContext>
{
public string Config { get; private set; }
public object Value { get; private set; }
protected override bool EvaluateWithContext(DefaultConditionContext context)
{
if (!base.Pack.TryGetConfigValue(Config, out var returnValue))
{
return false;
}
if (Value == null)
{
if (returnValue is bool)
{
return (bool)returnValue;
}
if (returnValue is string value)
{
return string.IsNullOrEmpty(value);
}
return false;
}
if (returnValue is bool flag)
{
return flag == (bool)Value;
}
if (returnValue is string text)
{
return text == (string)Value;
}
return false;
}
public override List<IValidatable.ValidationResult> Validate()
{
if (!base.Pack.TryGetConfigValue(Config, out var returnValue))
{
List<IValidatable.ValidationResult> list = new List<IValidatable.ValidationResult>(1);
list.Add(new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, "Config '" + Config + "' does not exist on SoundPack '" + base.Pack.Name + "'"));
return list;
}
if (Value != null && returnValue.GetType() != Value.GetType())
{
return new List<IValidatable.ValidationResult>(1)
{
new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, $"Config '{Config}' has a type of: '{returnValue.GetType()}' but the Value type is '{Value.GetType()}'!")
};
}
return new List<IValidatable.ValidationResult>();
}
}
[SoundAPICondition("mod_installed")]
internal class ModInstalledCondition : Condition<DefaultConditionContext>
{
public string Value { get; private set; }
protected override bool EvaluateWithContext(DefaultConditionContext context)
{
return Chainloader.PluginInfos.ContainsKey(Value);
}
public override List<IValidatable.ValidationResult> Validate()
{
if (string.IsNullOrEmpty(Value))
{
return new List<IValidatable.ValidationResult>(1)
{
new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, "Value on 'mod_installed' must be there and must not be empty.")
};
}
return new List<IValidatable.ValidationResult>();
}
}
[SoundAPICondition("not")]
internal class NotCondition : Condition<DefaultConditionContext>
{
[JsonProperty("condition")]
public Condition Condition { get; private set; }
protected override bool EvaluateWithContext(DefaultConditionContext context)
{
if (Condition is InvalidCondition)
{
return false;
}
return !Condition.Evaluate(context);
}
public override List<IValidatable.ValidationResult> Validate()
{
if (Condition == null)
{
return new List<IValidatable.ValidationResult>(1)
{
new IValidatable.ValidationResult(IValidatable.ResultType.FAIL, "'not' condition has no valid condition to invert!")
};
}
return new List<IValidatable.ValidationResult>();
}
}
[SoundAPICondition("or")]
internal class OrCondition : Condition<DefaultConditionContext>
{
public Condition[] Conditions { get; private set; }
protected override bool EvaluateWithContext(DefaultConditionContext context)
{
Condition[] conditions = Conditions;
foreach (Condition condition in conditions)
{
if (condition is InvalidCondition)
{
return false;
}
if (condition.Evaluate(context))
{
return true;
}
}
return false;
}
public override List<IValidatable.ValidationResult> Validate()
{
if (Conditions.Length == 0)
{
return new List<IValidatable.ValidationResult>(1)
{
new IValidatable.ValidationResult(IValidatable.ResultType.WARN, "'or' condition has no conditions and will always return false!")
};
}
return new List<IValidatable.ValidationResult>();
}
}
}
namespace loaforcsSoundAPI.Reporting
{
public static class SoundReportHandler
{
private const string _datetimeFormat = "dd_MM_yyyy-HH_mm";
private static Action<StreamWriter, SoundReport> _reportSections = delegate
{
};
public static SoundReport CurrentReport { get; private set; }
public static Action OnStartReport { get; set; } = delegate
{
};
public static void AddReportSection(string header, Action<StreamWriter, SoundReport> callback)
{
_reportSections = (Action<StreamWriter, SoundReport>)Delegate.Combine(_reportSections, (Action<StreamWriter, SoundReport>)delegate(StreamWriter stream, SoundReport report)
{
stream.WriteLine("## " + header);
callback(stream, report);
stream.WriteLine("");
stream.WriteLine("");
});
}
internal static void Register()
{
Directory.CreateDirectory(GetFolder());
CurrentReport = new SoundReport();
loaforcsSoundAPI.Logger.LogWarning((object)"SoundAPI is generating a report!");
loaforcsSoundAPI.Logger.LogInfo((object)("The report will be located at '" + LogFormats.FormatFilePath(Path.Combine(GetFolder(), GetFileName(CurrentReport, ".md")))));
Application.quitting += delegate
{
WriteReportToFile(CurrentReport);
};
SoundPackLoadPipeline.OnFinishedPipeline += delegate
{
foreach (SoundPack loadedPack in SoundPackDataHandler.LoadedPacks)
{
CurrentReport.SoundPackNames.Add(loadedPack.Name);
}
};
AddReportSection("General Information", delegate(StreamWriter stream, SoundReport report)
{
stream.WriteLine("SoundAPI version: `2.0.0` <br/><br/>");
stream.WriteLine($"Audio-clips loaded: `{report.AudioClipsLoaded}` <br/>");
stream.WriteLine($"Match strings registered: `{SoundPackDataHandler.SoundReplacements.Values.Sum((List<SoundReplacementGroup> it) => it.Count)}` <br/>");
WriteList("Loaded sound-packs", stream, report.SoundPackNames);
});
AddReportSection("Dynamic Data", delegate(StreamWriter stream, SoundReport _)
{
if (SoundAPI.CurrentNetworkAdapter != null)
{
stream.WriteLine("Network Adapter: `" + SoundAPI.CurrentNetworkAdapter.Name + "` <br/><br/>");
}
WriteList("Registered Conditions", stream, SoundPackDataHandler.conditionFactories.Keys.ToList());
});
AddReportSection("All Match Strings", delegate(StreamWriter stream, SoundReport report)
{
WriteList(null, stream, report.AllMatchStrings);
});
OnStartReport();
}
internal static void Bind(ConfigFile file)
{
if (file.Bind<bool>("Developer", "GenerateReports", false, "While true SoundAPI will generate a json and markdown file per session that records information SoundAPI and related mods find.").Value)
{
Register();
}
}
private static string GetFileName(SoundReport report, string extension)
{
return "generated_report-" + report.StartedAt.ToString("dd_MM_yyyy-HH_mm") + extension;
}
private static string GetFolder()
{
return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "reports");
}
private static void WriteReportToFile(SoundReport report)
{
using StreamWriter streamWriter = new StreamWriter(Path.Combine(GetFolder(), GetFileName(report, ".md")));
streamWriter.WriteLine("# Generated Report");
streamWriter.WriteLine($"At {report.StartedAt} :3");
streamWriter.WriteLine("");
_reportSections(streamWriter, report);
streamWriter.Flush();
streamWriter.Close();
using StreamWriter streamWriter2 = new StreamWriter(Path.Combine(GetFolder(), GetFileName(report, ".json")));
streamWriter2.WriteLine(JsonConvert.SerializeObject((object)report, (Formatting)1));
}
public static void WriteList(string header, StreamWriter stream, ICollection<string> list)
{
if (!string.IsNullOrEmpty(header))
{
stream.WriteLine($"### {header} (`{list.Count}`)");
}
stream.WriteLine(string.Join("<br/>\n", list.Select((string it) => "- " + it)));
}
public static void WriteEnum<T>(string header, StreamWriter stream) where T : Enum
{
WriteList(header, stream, (from it in Enum.GetValues(typeof(T)).OfType<T>()
select it.ToString().ToLowerInvariant()).ToList());
}
}
}
namespace loaforcsSoundAPI.Reporting.Data
{
public class SoundReport
{
public DateTime StartedAt { get; private set; } = DateTime.Now;
public List<string> AllMatchStrings { get; private set; } = new List<string>();
public List<string> RawMatchStrings { get; private set; } = new List<string>();
public List<string> SoundPackNames { get; private set; } = new List<string>();
public int AudioClipsLoaded { get; set; }
}
}
namespace loaforcsSoundAPI.Core
{
public class AudioSourceAdditionalData
{
public AudioSource Source { get; }
internal SoundReplacementGroup ReplacedWith { get; set; }
public IContext CurrentContext { get; set; }
public AudioSourceAdditionalData(AudioSource source)
{
Source = source;
base..ctor();
}
internal void Update()
{
if (!Object.op_Implicit((Object)(object)Source) || !((Behaviour)Source).enabled || ReplacedWith == null)
{
return;
}
if (!Source.isPlaying)
{
ReplacedWith = null;
}
else if (ReplacedWith.Parent.UpdateEveryFrame)
{
IContext context = CurrentContext ?? SoundReplacementHandler.DEFAULT_CONTEXT;
SoundInstance soundInstance = ReplacedWith.Sounds.FirstOrDefault((SoundInstance x) => x.Evaluate(context));
if (soundInstance != null && !((Object)(object)soundInstance.Clip == (Object)(object)Source.clip))
{
float time = Source.time;
Source.clip = soundInstance.Clip;
Source.Play();
Source.time = time;
}
}
}
public static AudioSourceAdditionalData GetOrCreate(AudioSource source)
{
if (SoundAPIAudioManager.audioSourceData.TryGetValue(source, out var value))
{
return value;
}
value = new AudioSourceAdditionalData(source);
SoundAPIAudioManager.audioSourceData[source] = value;
return value;
}
}
internal static class Debuggers
{
internal static DebugLogSource AudioSourceAdditionalData;
internal static DebugLogSource SoundReplacementLoader;
internal static DebugLogSource SoundReplacementHandler;
internal static DebugLogSource MatchStrings;
internal static void Bind(ConfigFile file)
{
FieldInfo[] fields = typeof(Debuggers).GetFields(BindingFlags.Static | BindingFlags.NonPublic);
foreach (FieldInfo fieldInfo in fields)
{
if (file.Bind<bool>("InternalDebugging", fieldInfo.Name, false, "Enable/Disable this DebugLogSource. Should only be true if you know what you are doing or have been asked to.").Value)
{
fieldInfo.SetValue(null, new DebugLogSource(fieldInfo.Name));
}
else
{
fieldInfo.SetValue(null, null);
}
}
}
}
internal class DebugLogSource
{
[CompilerGenerated]
private string <title>P;
public DebugLogSource(string title)
{
<title>P = title;
base..ctor();
}
internal void Log(object message)
{
loaforcsSoundAPI.Logger.LogDebug((object)$"[Debug-{<title>P}] {message}");
}
}
internal class SoundAPIAudioManager : MonoBehaviour
{
internal static readonly Dictionary<AudioSource, AudioSourceAdditionalData> audioSourceData = new Dictionary<AudioSource, AudioSourceAdditionalData>();
private static SoundAPIAudioManager Instance;
private void Awake()
{
SceneManager.sceneLoaded += delegate
{
if (!Object.op_Implicit((Object)(object)Instance))
{
SpawnManager();
}
RunCleanup();
};
}
private static void SpawnManager()
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Expected O, but got Unknown
loaforcsSoundAPI.Logger.LogInfo((object)"Starting AudioManager.");
GameObject val = new GameObject("SoundAPI_AudioManager");
Object.DontDestroyOnLoad((Object)(object)val);
Instance = val.AddComponent<SoundAPIAudioManager>();
}
private void Update()
{
foreach (AudioSourceAdditionalData value in audioSourceData.Values)
{
value.Update();
}
}
private void OnDisable()
{
loaforcsSoundAPI.Logger.LogDebug((object)"manager disabled");
}
private void OnDestroy()
{
loaforcsSoundAPI.Logger.LogDebug((object)"manager destroyed");
}
private static void RunCleanup()
{
loaforcsSoundAPI.Logger.LogDebug((object)"cleaning up old audio source entries");
AudioSource[] array = audioSourceData.Keys.ToArray();
foreach (AudioSource val in array)
{
if (!Object.op_Implicit((Object)(object)val))
{
audioSourceData.Remove(val);
}
}
}
}
}
namespace loaforcsSoundAPI.Core.Util
{
internal static class LogFormats
{
internal static string FormatFilePath(string path)
{
return $"plugins{Path.DirectorySeparatorChar}{Path.Combine(Path.GetRelativePath(Paths.PluginPath, path))}";
}
}
}
namespace loaforcsSoundAPI.Core.Patches
{
[HarmonyPatch(typeof(AudioSource))]
internal static class AudioSourcePatch
{
[HarmonyPrefix]
[HarmonyPatch("Play", new Type[] { })]
[HarmonyPatch("Play", new Type[] { typeof(ulong) })]
[HarmonyPatch("Play", new Type[] { typeof(double) })]
private static bool Play(AudioSource __instance)
{
if (SoundReplacementHandler.TryReplaceAudio(__instance, __instance.clip, out var replacement))
{
if ((Object)(object)replacement == (Object)null)
{
return false;
}
__instance.clip = replacement;
}
return true;
}
[HarmonyPrefix]
[HarmonyPatch("PlayOneShot", new Type[]
{
typeof(AudioClip),
typeof(float)
})]
private static bool PlayOneShot(AudioSource __instance, ref AudioClip clip)
{
if (SoundReplacementHandler.TryReplaceAudio(__instance, clip, out var replacement))
{
if ((Object)(object)replacement == (Object)null)
{
return false;
}
clip = replacement;
}
return true;
}
}
[HarmonyPatch(typeof(GameObject))]
internal static class GameObjectPatch
{
[HarmonyPostfix]
[HarmonyPatch("AddComponent", new Type[] { typeof(Type) })]
internal static void NewAudioSource(GameObject __instance, ref Component __result)
{
Component obj = __result;
AudioSource val = (AudioSource)(object)((obj is AudioSource) ? obj : null);
if (val != null)
{
AudioSourceAdditionalData.GetOrCreate(val);
}
}
}
[HarmonyPatch(typeof(Logger))]
internal static class LoggerPatch
{
[HarmonyPrefix]
[HarmonyPatch("LogMessage")]
private static void ReenableAndSaveConfigs(object data)
{
if (data is string text && text == "Chainloader startup complete")
{
loaforcsSoundAPI.Logger.LogInfo((object)"Starting Sound-pack loading pipeline");
SoundPackLoadPipeline.StartPipeline();
}
}
}
internal static class UnityObjectPatch
{
private static void InstantiatePatch(Object __result)
{
Debuggers.AudioSourceAdditionalData?.Log("aghuobr: " + __result.name);
GameObject val = (GameObject)(object)((__result is GameObject) ? __result : null);
if (val != null)
{
CheckInstantiationRecursively(val);
}
}
internal static void Init(Harmony harmony)
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
HarmonyMethod val = new HarmonyMethod(typeof(UnityObjectPatch).GetMethod("InstantiatePatch", BindingFlags.Static | BindingFlags.NonPublic));
MethodInfo[] methods = typeof(Object).GetMethods();
foreach (MethodInfo methodInfo in methods)
{
if (!(methodInfo.Name != "Instantiate"))
{
Debuggers.AudioSourceAdditionalData?.Log($"patching {methodInfo}");
if (methodInfo.IsGenericMethod)
{
harmony.Patch((MethodBase)methodInfo.MakeGenericMethod(typeof(Object)), (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
else
{
harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
}
}
}
private static void CheckInstantiationRecursively(GameObject gameObject)
{
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Expected O, but got Unknown
AudioSourceAdditionalData audioSourceAdditionalData = default(AudioSourceAdditionalData);
if (gameObject.TryGetComponent<AudioSourceAdditionalData>(ref audioSourceAdditionalData))
{
return;
}
AudioSource[] components = gameObject.GetComponents<AudioSource>();
foreach (AudioSource val in components)
{
AudioSourceAdditionalData.GetOrCreate(val);
if (!val.playOnAwake)
{
continue;
}
AudioClip clip = val.clip;
if (SoundReplacementHandler.TryReplaceAudio(val, clip, out var replacement))
{
val.Stop();
if (!((Object)(object)replacement == (Object)null))
{
val.clip = replacement;
val.Play();
}
}
else
{
val.clip = clip;
val.Play();
}
}
foreach (Transform item in gameObject.transform)
{
Transform val2 = item;
CheckInstantiationRecursively(((Component)val2).gameObject);
}
}
}
}
namespace loaforcsSoundAPI.Core.Networking
{
public abstract class NetworkAdapter
{
public abstract string Name { get; }
public abstract void OnRegister();
}
}
namespace loaforcsSoundAPI.Core.JSON
{
public static class JSONDataLoader
{
private class MatchesJSONConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(List<string>);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Invalid comparison between Unknown and I4
JToken val = JToken.Load(reader);
if ((int)val.Type == 2)
{
return val.ToObject<List<string>>();
}
return new List<string> { ((object)val).ToString() };
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
}
private class IncludePrivatePropertiesContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
JsonProperty val = ((DefaultContractResolver)this).CreateProperty(member, memberSerialization);
if (!val.Writable && member is PropertyInfo propertyInfo)
{
val.Writable = propertyInfo.GetSetMethod(nonPublic: true) != null;
}
return val;
}
}
private class ConditionConverter : JsonConverter<Condition>
{
public override Condition ReadJson(JsonReader reader, Type objectType, Condition existingValue, bool hasExistingValue, JsonSerializer serializer)
{
JObject val = JObject.Load(reader);
string text = ((object)val["type"])?.ToString();
if (string.IsNullOrEmpty(text))
{
return new InvalidCondition(null);
}
Condition condition = SoundPackDataHandler.CreateCondition(text);
if (condition == null)
{
return null;
}
serializer.Populate(((JToken)val).CreateReader(), (object)condition);
return condition;
}
public override void WriteJson(JsonWriter writer, Condition value, JsonSerializer serializer)
{
throw new NotImplementedException("no.");
}
}
private static readonly JsonSerializerSettings _settings = new JsonSerializerSettings
{
ContractResolver = (IContractResolver)(object)new IncludePrivatePropertiesContractResolver(),
Converters = new List<JsonConverter>(2)
{
(JsonConverter)(object)new MatchesJSONConverter(),
(JsonConverter)(object)new ConditionConverter()
}
};
public static T LoadFromFile<T>(string path)
{
//IL_0056: Expected O, but got Unknown
string text = File.ReadAllText(path);
try
{
T val = JsonConvert.DeserializeObject<T>(text, _settings);
if ((object)val is IFilePathAware filePathAware)
{
filePathAware.FilePath = path;
}
if ((object)val is Conditional conditional && conditional.Condition != null)
{
conditional.Condition.Parent = conditional;
}
return val;
}
catch (JsonReaderException val2)
{
JsonReaderException val3 = val2;
loaforcsSoundAPI.Logger.LogError((object)$"Failed to read json file: 'plugins{Path.DirectorySeparatorChar}{Path.GetRelativePath(Paths.PluginPath, path)}'");
loaforcsSoundAPI.Logger.LogError((object)((Exception)(object)val3).Message);
string[] array = text.Split("\n");
int num = int.MaxValue;
for (int i = Mathf.Max(0, val3.LineNumber - 3); i < Mathf.Min(array.Length, val3.LineNumber + 3); i++)
{
int num2 = array[i].TakeWhile(char.IsWhiteSpace).Count();
num = Mathf.Min(num, num2);
}
for (int j = Mathf.Max(0, val3.LineNumber - 3); j < Mathf.Min(array.Length, val3.LineNumber + 3); j++)
{
string text2 = $"{(j + 1).ToString(),-5}| ";
string text3 = array[j];
int num3 = Mathf.Min(array[j].Length, num);
string text4 = text2 + text3.Substring(num3, text3.Length - num3).TrimEnd();
if (j + 1 == val3.LineNumber)
{
text4 += " // <- HERE";
}
loaforcsSoundAPI.Logger.LogError((object)text4);
}
}
return default(T);
}
}
}
namespace loaforcsSoundAPI.Core.Data
{
public interface IFilePathAware
{
string FilePath { get; internal set; }
}
public interface IValidatable
{
public enum ResultType
{
WARN,
FAIL
}
public class ValidationResult
{
public ResultType Status { get; private set; }
public string Reason { get; private set; }
public ValidationResult(ResultType resultType, string reason = null)
{
Status = resultType;
Reason = reason ?? string.Empty;
base..ctor();
}
}
private static readonly StringBuilder _stringBuilder = new StringBuilder();
List<ValidationResult> Validate();
internal static bool LogAndCheckValidationResult(string context, List<ValidationResult> results)
{
if (results.Count == 0)
{
return true;
}
int num = 0;
int num2 = 0;
foreach (ValidationResult result in results)
{
switch (result.Status)
{
case ResultType.WARN:
num++;
break;
case ResultType.FAIL:
num2++;
break;
default:
throw new ArgumentOutOfRangeException();
}
}
_stringBuilder.Clear();
if (num2 != 0)
{
_stringBuilder.Append(num2);
_stringBuilder.Append(" fail(s)");
}
if (num != 0)
{
if (num2 != 0)
{
_stringBuilder.Append(" and ");
}
_stringBuilder.Append(num);
_stringBuilder.Append(" warning(s)");
}
_stringBuilder.Append(" while ");
_stringBuilder.Append(context);
_stringBuilder.Append(": ");
if (num2 != 0)
{
loaforcsSoundAPI.Logger.LogError((object)_stringBuilder);
}
else
{
loaforcsSoundAPI.Logger.LogWarning((object)_stringBuilder);
}
foreach (ValidationResult result2 in results)
{
switch (result2.Status)
{
case ResultType.WARN:
loaforcsSoundAPI.Logger.LogWarning((object)("WARN: " + result2.Reason));
break;
case ResultType.FAIL:
loaforcsSoundAPI.Logger.LogError((object)("FAIL: " + result2.Reason));
break;
default:
throw new ArgumentOutOfRangeException();
}
}
return num2 != 0;
}
}
}