using System;
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 BoneLib;
using BoneLib.BoneMenu;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Marrow.Audio;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using QuickOneSound;
using UnityEngine;
using UnityEngine.Audio;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(QuickOneSoundMod), "QuickOneSound", "1.0.0", "nontendo", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("QuickOneSound")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("QuickOneSound")]
[assembly: AssemblyTitle("QuickOneSound")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
}
namespace QuickOneSound
{
public static class QuickModsTheme
{
private const string ShareKey = "QuickMods.GlobalTheme";
private const string MenuKey = "QuickMods.GlobalThemeMenuBuilt";
private static MelonPreferences_Category _cat;
private static MelonPreferences_Entry<bool> _useGlobal;
private static MelonPreferences_Entry<float> _hue;
private static MelonPreferences_Entry<float> _sat;
private static MelonPreferences_Entry<bool> _forceQB;
private static MelonPreferences_Entry<bool> _rainbow;
private static MelonPreferences_Entry<float> _rainbowSpeed;
public static bool UseGlobalTheme
{
get
{
return _useGlobal.Value;
}
set
{
_useGlobal.Value = value;
Save();
}
}
public static float Hue
{
get
{
return _hue.Value;
}
set
{
_hue.Value = value;
Save();
}
}
public static float Saturation
{
get
{
return _sat.Value;
}
set
{
_sat.Value = value;
Save();
}
}
public static bool ForceQuickBeatsSync
{
get
{
return _forceQB.Value;
}
set
{
_forceQB.Value = value;
Save();
}
}
public static Color GlobalColor => Color.HSVToRGB(Hue / 360f, Saturation, 1f);
public static bool RainbowMode
{
get
{
return _rainbow.Value;
}
set
{
_rainbow.Value = value;
Save();
}
}
public static float RainbowSpeed
{
get
{
return _rainbowSpeed.Value;
}
set
{
_rainbowSpeed.Value = value;
Save();
}
}
public static Color RainbowColor => Color.HSVToRGB(Time.time * RainbowSpeed % 1f, 0.85f, 1f);
public static Color ResolveAccent(Color modDefault, bool modThemeToSong, Func<Color?> qbGetter)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
if (RainbowMode)
{
return RainbowColor;
}
if (ForceQuickBeatsSync)
{
Color? val = SafeGet(qbGetter);
if (val.HasValue)
{
return val.Value;
}
}
if (UseGlobalTheme)
{
return GlobalColor;
}
if (modThemeToSong)
{
Color? val2 = SafeGet(qbGetter);
if (val2.HasValue)
{
return val2.Value;
}
}
return modDefault;
}
private static Color? SafeGet(Func<Color?> getter)
{
try
{
return getter?.Invoke();
}
catch
{
return null;
}
}
public static void Initialize()
{
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
if (AppDomain.CurrentDomain.GetData("QuickMods.GlobalTheme") is object[] array && array.Length >= 7)
{
try
{
_cat = (MelonPreferences_Category)array[0];
_useGlobal = (MelonPreferences_Entry<bool>)array[1];
_hue = (MelonPreferences_Entry<float>)array[2];
_sat = (MelonPreferences_Entry<float>)array[3];
_forceQB = (MelonPreferences_Entry<bool>)array[4];
_rainbow = (MelonPreferences_Entry<bool>)array[5];
_rainbowSpeed = (MelonPreferences_Entry<float>)array[6];
return;
}
catch
{
}
}
_cat = MelonPreferences.CreateCategory("QuickModsTheme");
_useGlobal = Entry("UseGlobalTheme", fallback: false);
_hue = Entry("Hue", 200f);
_sat = Entry("Saturation", 0.72f);
_forceQB = Entry("ForceQuickBeatsSync", fallback: false);
_rainbow = Entry("RainbowMode", fallback: false);
_rainbowSpeed = Entry("RainbowSpeed", 0.15f);
AppDomain.CurrentDomain.SetData("QuickMods.GlobalTheme", new object[7] { _cat, _useGlobal, _hue, _sat, _forceQB, _rainbow, _rainbowSpeed });
}
private static MelonPreferences_Entry<T> Entry<T>(string id, T fallback)
{
try
{
MelonPreferences_Entry<T> entry = _cat.GetEntry<T>(id);
if (entry != null)
{
return entry;
}
}
catch
{
_cat.DeleteEntry(id);
}
return _cat.CreateEntry<T>(id, fallback, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
}
public static void BuildMenu(Page rootPage)
{
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_0156: Unknown result type (might be due to invalid IL or missing references)
//IL_018a: Unknown result type (might be due to invalid IL or missing references)
object data = AppDomain.CurrentDomain.GetData("QuickMods.GlobalThemeMenuBuilt");
bool flag = default(bool);
int num;
if (data is bool)
{
flag = (bool)data;
num = 1;
}
else
{
num = 0;
}
if (((uint)num & (flag ? 1u : 0u)) == 0)
{
AppDomain.CurrentDomain.SetData("QuickMods.GlobalThemeMenuBuilt", true);
Page obj = rootPage.CreatePage("Global Theme", new Color(1f, 0.55f, 0.85f), 0, true);
obj.CreateBool("Use Global Theme", Color.white, UseGlobalTheme, (Action<bool>)delegate(bool v)
{
UseGlobalTheme = v;
});
obj.CreateFloat("Hue", Color.white, Hue, 5f, 0f, 360f, (Action<float>)delegate(float v)
{
Hue = v;
});
obj.CreateFloat("Saturation", Color.white, Saturation, 0.05f, 0.1f, 1f, (Action<float>)delegate(float v)
{
Saturation = v;
});
obj.CreateBool("Force QuickBeats (All Mods)", Color.magenta, ForceQuickBeatsSync, (Action<bool>)delegate(bool v)
{
ForceQuickBeatsSync = v;
});
obj.CreateBool("Rainbow Mode (All Mods)", Color.red, RainbowMode, (Action<bool>)delegate(bool v)
{
RainbowMode = v;
});
obj.CreateFloat("Rainbow Speed", Color.red, RainbowSpeed, 0.02f, 0.02f, 1f, (Action<float>)delegate(float v)
{
RainbowSpeed = v;
});
}
}
private static void Save()
{
_cat.SaveToFile(false);
}
}
public class QuickOneSoundMod : MelonMod
{
private static FunctionElement? _pick;
private static FunctionElement? _stats;
private static FunctionElement? _hooks;
private static float _wait;
private static bool _patched;
private static readonly string[] HookNames = new string[3] { "Polling Only", "Pooled Player", "Player + Manager" };
public static bool Ready { get; private set; }
public override void OnInitializeMelon()
{
SoundSettings.Initialize();
QuickModsTheme.Initialize();
SoundBank.EnsureFolder();
SoundBank.Rescan();
SoundPatches.CheckGuard();
_wait = Mathf.Max(0f, SoundSettings.Delay);
Hooking.OnLevelLoaded += delegate
{
Ready = false;
_wait = Mathf.Max(0f, SoundSettings.Delay);
SoundPatches.OnLevelLoaded();
SoundSweeper.OnLevelLoaded();
};
SetupMenu();
if (SoundBank.Count == 0)
{
((MelonBase)this).LoggerInstance.Msg("QuickOneSound loaded, but there are no sounds yet. Drop one in " + SoundBank.FolderPath);
}
else
{
((MelonBase)this).LoggerInstance.Msg("QuickOneSound loaded! " + SoundBank.Count + " sound(s), using " + SoundBank.CurrentName);
}
}
public override void OnUpdate()
{
float deltaTime = Time.deltaTime;
SoundPatches.Tick(deltaTime);
if (!Ready)
{
_wait -= deltaTime;
if (_wait > 0f)
{
return;
}
Ready = true;
if (!_patched)
{
_patched = true;
SoundPatches.Apply(((MelonBase)this).HarmonyInstance);
}
}
SoundSweeper.Tick(deltaTime);
}
private static Page GetOrCreateQuickModsPage()
{
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
object? data = AppDomain.CurrentDomain.GetData("QuickMods.RootPage");
Page val = (Page)((data is Page) ? data : null);
if (val != null)
{
return val;
}
Page val2 = Page.Root.CreatePage("Quick Mods", new Color(0.35f, 0.27f, 0.9f), 0, true);
AppDomain.CurrentDomain.SetData("QuickMods.RootPage", val2);
return val2;
}
private static void SetupMenu()
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_012b: Unknown result type (might be due to invalid IL or missing references)
//IL_016f: Unknown result type (might be due to invalid IL or missing references)
//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
//IL_023b: Unknown result type (might be due to invalid IL or missing references)
//IL_028e: Unknown result type (might be due to invalid IL or missing references)
//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
//IL_030a: Unknown result type (might be due to invalid IL or missing references)
//IL_033f: Unknown result type (might be due to invalid IL or missing references)
//IL_0374: Unknown result type (might be due to invalid IL or missing references)
//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
//IL_0420: Unknown result type (might be due to invalid IL or missing references)
//IL_0432: Unknown result type (might be due to invalid IL or missing references)
//IL_0462: Unknown result type (might be due to invalid IL or missing references)
//IL_0496: Unknown result type (might be due to invalid IL or missing references)
//IL_04b2: Unknown result type (might be due to invalid IL or missing references)
Page orCreateQuickModsPage = GetOrCreateQuickModsPage();
QuickModsTheme.BuildMenu(orCreateQuickModsPage);
Page obj = orCreateQuickModsPage.CreatePage("QuickOneSound", new Color(1f, 0.55f, 0.15f), 0, true);
obj.CreateBool("Enabled", Color.white, SoundSettings.Enabled, (Action<bool>)delegate(bool v)
{
SoundSettings.Enabled = v;
if (!v)
{
SoundSweeper.Restore();
}
});
_pick = obj.CreateFunction(PickLabel(), new Color(1f, 0.85f, 0.35f), (Action)delegate
{
SoundBank.Step(1);
Refresh();
});
obj.CreateFunction("Preview It", Color.green, (Action)SoundBank.Preview);
obj.CreateFunction("Rescan Folder", Color.cyan, (Action)delegate
{
SoundBank.Rescan();
Refresh();
});
obj.CreateBool("Random Each Time", Color.white, SoundSettings.Random, (Action<bool>)delegate(bool v)
{
SoundSettings.Random = v;
});
obj.CreateFloat("Volume", Color.white, SoundSettings.Volume, 0.1f, 0f, 4f, (Action<float>)delegate(float v)
{
SoundSettings.Volume = v;
});
obj.CreateFloat("Pitch", Color.white, SoundSettings.Pitch, 0.05f, 0.5f, 2f, (Action<float>)delegate(float v)
{
SoundSettings.Pitch = v;
});
obj.CreateFloat("Trim To Seconds", Color.white, SoundSettings.Trim, 0.05f, 0f, 5f, (Action<float>)delegate(float v)
{
SoundSettings.Trim = v;
});
obj.CreateFloat("Rate Limit", Color.white, SoundSettings.Throttle, 0.01f, 0f, 0.5f, (Action<float>)delegate(float v)
{
SoundSettings.Throttle = v;
});
obj.CreateFloat("Startup Delay", Color.white, SoundSettings.Delay, 1f, 0f, 60f, (Action<float>)delegate(float v)
{
SoundSettings.Delay = v;
});
Page obj2 = obj.CreatePage("What Gets Replaced", new Color(0.4f, 0.8f, 1f), 0, true);
obj2.CreateBool("Guns", Color.white, SoundSettings.Guns, (Action<bool>)delegate(bool v)
{
SoundSettings.Guns = v;
});
obj2.CreateBool("Impacts And Handling", Color.white, SoundSettings.Impacts, (Action<bool>)delegate(bool v)
{
SoundSettings.Impacts = v;
});
obj2.CreateBool("Footsteps", Color.white, SoundSettings.Footsteps, (Action<bool>)delegate(bool v)
{
SoundSettings.Footsteps = v;
});
obj2.CreateBool("Voices", Color.white, SoundSettings.Voices, (Action<bool>)delegate(bool v)
{
SoundSettings.Voices = v;
});
obj2.CreateBool("Menus And UI", Color.white, SoundSettings.Ui, (Action<bool>)delegate(bool v)
{
SoundSettings.Ui = v;
});
obj2.CreateBool("Music And Ambience", Color.white, SoundSettings.Music, (Action<bool>)delegate(bool v)
{
SoundSettings.Music = v;
});
obj2.CreateBool("Looping Sounds", Color.white, SoundSettings.Loops, (Action<bool>)delegate(bool v)
{
SoundSettings.Loops = v;
if (!v)
{
SoundSweeper.Restore();
}
});
Page obj3 = obj.CreatePage("Advanced", new Color(0.7f, 0.7f, 0.7f), 0, true);
_stats = obj3.CreateFunction(StatsLabel(), Color.white, (Action)Refresh);
_hooks = obj3.CreateFunction(HooksLabel(), new Color(1f, 0.6f, 0.6f), (Action)delegate
{
SoundSettings.Hooks = (SoundSettings.Hooks + 1) % 3;
if (_hooks != null)
{
((Element)_hooks).ElementName = HooksLabel();
}
});
obj3.CreateFunction("Put The Game's Sounds Back", Color.yellow, (Action)SoundSweeper.Restore);
obj3.CreateBool("Debug Log", Color.white, SoundSettings.DebugLog, (Action<bool>)delegate(bool v)
{
SoundSettings.DebugLog = v;
});
}
private static void Refresh()
{
if (_pick != null)
{
((Element)_pick).ElementName = PickLabel();
}
if (_stats != null)
{
((Element)_stats).ElementName = StatsLabel();
}
}
private static string PickLabel()
{
if (SoundBank.Count != 0)
{
return "Sound: " + SoundBank.CurrentName;
}
return "No Sounds Found (tap to rescan)";
}
private static string HooksLabel()
{
return "Hooks: " + HookNames[Mathf.Clamp(SoundSettings.Hooks, 0, 2)] + " (restart)";
}
private static string StatsLabel()
{
return "Hooks " + SoundPatches.Hooked + " Swapped " + (SoundPatches.Swapped + SoundSweeper.Swapped) + " Held " + SoundSweeper.Count + (Ready ? "" : " (waiting)");
}
}
internal static class SoundBank
{
public const string Tag = "QOS_";
private static readonly string[] Extensions = new string[3] { ".wav", ".mp3", ".ogg" };
private static readonly Dictionary<string, AudioClip?> _cache = new Dictionary<string, AudioClip>();
private static readonly Dictionary<string, AudioClip?> _trims = new Dictionary<string, AudioClip>();
private static List<string> _files = new List<string>();
private static Il2CppReferenceArray<AudioClip>? _one;
private static AudioClip? _oneOf;
private static AudioSource? _preview;
private static AudioClip? _settled;
private static float _settledTrim = -1f;
private static bool _apiChecked;
private static MethodInfo? _loadAudioClip;
public static string FolderPath => Path.Combine(MelonEnvironment.UserDataDirectory, "QuickOneSound");
public static int Count => _files.Count;
public static string CurrentName
{
get
{
string file = SoundSettings.File;
if (file.Length > 0)
{
return file;
}
if (_files.Count <= 0)
{
return "none";
}
return Path.GetFileName(_files[0]);
}
}
public static void EnsureFolder()
{
try
{
Directory.CreateDirectory(FolderPath);
string path = Path.Combine(FolderPath, "READ ME - drop a sound here.txt");
if (!File.Exists(path))
{
File.WriteAllText(path, "drop a .wav, .mp3 or .ogg in this folder and pick it in BoneMenu.\r\nwhile QuickOneSound is on, every sound in the game becomes that clip.\r\n\r\nmp3 and ogg need the AudioImportLib mod installed. wav always works.\r\nshort clips work best. if yours is long, use the Trim slider.\r\n");
}
}
catch (Exception ex)
{
MelonLogger.Warning("[quickonesound] couldn't make the sounds folder: " + ex.Message);
}
}
public static void Rescan()
{
try
{
_files = (Directory.Exists(FolderPath) ? (from f in Directory.EnumerateFiles(FolderPath)
where Extensions.Contains(Path.GetExtension(f).ToLowerInvariant())
select f).OrderBy<string, string>((string f) => f, StringComparer.OrdinalIgnoreCase).ToList() : new List<string>());
}
catch
{
_files = new List<string>();
}
if (_files.Count > 0 && !_files.Any((string f) => string.Equals(Path.GetFileName(f), SoundSettings.File, StringComparison.OrdinalIgnoreCase)))
{
SoundSettings.File = Path.GetFileName(_files[0]);
}
_one = null;
_oneOf = null;
_settled = null;
}
public static void Step(int dir)
{
if (_files.Count == 0)
{
Rescan();
if (_files.Count == 0)
{
return;
}
}
int num = _files.FindIndex((string f) => string.Equals(Path.GetFileName(f), SoundSettings.File, StringComparison.OrdinalIgnoreCase));
if (num < 0)
{
num = 0;
}
num = (num + dir + _files.Count) % _files.Count;
SoundSettings.File = Path.GetFileName(_files[num]);
_one = null;
_oneOf = null;
_settled = null;
}
public static AudioClip? Clip()
{
if (_files.Count == 0)
{
return null;
}
if (!SoundSettings.Random && (Object)(object)_settled != (Object)null && _settledTrim == SoundSettings.Trim)
{
return _settled;
}
string path;
if (SoundSettings.Random && _files.Count > 1)
{
path = _files[Random.Range(0, _files.Count)];
}
else
{
int num = _files.FindIndex((string f) => string.Equals(Path.GetFileName(f), SoundSettings.File, StringComparison.OrdinalIgnoreCase));
path = _files[(num >= 0) ? num : 0];
}
AudioClip val = Load(path);
if ((Object)(object)val == (Object)null)
{
return null;
}
float trim = SoundSettings.Trim;
if (trim > 0.01f)
{
val = Trimmed(path, val, trim) ?? val;
}
_settled = val;
_settledTrim = trim;
return val;
}
public static Il2CppReferenceArray<AudioClip> AsSet(AudioClip c)
{
if (_one == null || (Object)(object)_oneOf != (Object)(object)c)
{
_one = new Il2CppReferenceArray<AudioClip>(1L);
((Il2CppArrayBase<AudioClip>)(object)_one)[0] = c;
_oneOf = c;
}
return _one;
}
public static bool IsOurs(AudioClip? clip)
{
if ((Object)(object)clip == (Object)null)
{
return false;
}
try
{
return ((Object)clip).name.StartsWith("QOS_", StringComparison.Ordinal);
}
catch
{
return false;
}
}
public static void Preview()
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Expected O, but got Unknown
AudioClip val = Clip();
if ((Object)(object)val == (Object)null)
{
MelonLogger.Warning("[quickonesound] nothing to preview, the folder is empty");
return;
}
if ((Object)(object)_preview == (Object)null)
{
GameObject val2 = new GameObject("[quickonesound] preview");
Object.DontDestroyOnLoad((Object)val2);
_preview = val2.AddComponent<AudioSource>();
_preview.playOnAwake = false;
_preview.spatialBlend = 0f;
}
_preview.volume = Mathf.Clamp01(SoundSettings.Volume);
_preview.pitch = Mathf.Clamp(SoundSettings.Pitch, 0.1f, 3f);
_preview.PlayOneShot(val);
}
private static AudioClip? Load(string path)
{
if (_cache.TryGetValue(path, out AudioClip value) && (Object)(object)value != (Object)null)
{
return value;
}
AudioClip val = ViaAudioImportLib(path);
if ((Object)(object)val == (Object)null && Path.GetExtension(path).ToLowerInvariant() == ".wav")
{
try
{
val = ParseWav(File.ReadAllBytes(path), "QOS_" + Path.GetFileName(path));
}
catch (Exception ex)
{
MelonLogger.Warning("[quickonesound] wav parse failed for " + Path.GetFileName(path) + ": " + ex.Message);
}
}
if ((Object)(object)val == (Object)null)
{
if (!_cache.ContainsKey(path))
{
MelonLogger.Warning("[quickonesound] couldn't load " + Path.GetFileName(path) + " (mp3/ogg need AudioImportLib)");
}
}
else
{
try
{
((Object)val).name = "QOS_" + Path.GetFileName(path);
}
catch
{
}
}
_cache[path] = val;
return val;
}
private static AudioClip? ViaAudioImportLib(string path)
{
try
{
if (!_apiChecked)
{
_apiChecked = true;
_loadAudioClip = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "AudioImportLib")?.GetType("AudioImportLib.API")?.GetMethod("LoadAudioClip", BindingFlags.Static | BindingFlags.Public);
}
if (_loadAudioClip == null)
{
return null;
}
object? obj = _loadAudioClip.Invoke(null, new object[2] { path, true });
return (AudioClip?)((obj is AudioClip) ? obj : null);
}
catch (Exception ex)
{
MelonLogger.Warning("[quickonesound] AudioImportLib load failed for " + Path.GetFileName(path) + ": " + ex.Message);
return null;
}
}
private static AudioClip? Trimmed(string path, AudioClip src, float seconds)
{
string key = path + "|" + seconds.ToString("0.00");
if (_trims.TryGetValue(key, out AudioClip value) && (Object)(object)value != (Object)null)
{
return value;
}
AudioClip val = null;
try
{
int num = Mathf.Max(1, src.channels);
int num2 = Mathf.Max(8000, src.frequency);
int num3 = Mathf.Min(src.samples, Mathf.RoundToInt(seconds * (float)num2));
if (num3 > 64 && num3 < src.samples)
{
Il2CppStructArray<float> val2 = new Il2CppStructArray<float>((long)(num3 * num));
src.GetData(val2, 0);
int num4 = Mathf.Min(num3 / 4, num2 / 200);
for (int i = num3 - num4; i < num3; i++)
{
float num5 = (float)(num3 - i) / (float)num4;
for (int j = 0; j < num; j++)
{
Il2CppStructArray<float> val3 = val2;
int num6 = i * num + j;
((Il2CppArrayBase<float>)(object)val3)[num6] = ((Il2CppArrayBase<float>)(object)val3)[num6] * num5;
}
}
val = AudioClip.Create("QOS_trim_" + Path.GetFileName(path), num3, num, num2, false);
val.SetData(val2, 0);
}
}
catch (Exception ex)
{
if (SoundSettings.DebugLog)
{
MelonLogger.Warning("[quickonesound] trim failed: " + ex.Message);
}
}
_trims[key] = val;
return val;
}
private static AudioClip? ParseWav(byte[] data, string clipName)
{
if (data.Length < 12 || data[0] != 82 || data[1] != 73 || data[2] != 70 || data[3] != 70)
{
return null;
}
int num = 1;
int num2 = 44100;
int num3 = 16;
byte[] array = null;
int num4 = 12;
while (num4 + 8 <= data.Length)
{
char c = (char)data[num4];
char c2 = (char)data[num4 + 1];
char c3 = (char)data[num4 + 2];
char c4 = (char)data[num4 + 3];
int num5 = BitConverter.ToInt32(data, num4 + 4);
int num6 = num4 + 8;
if (num5 < 0 || num6 + num5 > data.Length)
{
num5 = data.Length - num6;
}
if (c == 'f' && c2 == 'm' && c3 == 't' && c4 == ' ')
{
num = BitConverter.ToInt16(data, num6 + 2);
num2 = BitConverter.ToInt32(data, num6 + 4);
num3 = BitConverter.ToInt16(data, num6 + 14);
}
else if (c == 'd' && c2 == 'a' && c3 == 't' && c4 == 'a')
{
array = new byte[num5];
Array.Copy(data, num6, array, 0, num5);
}
num4 = num6 + num5 + num5 % 2;
}
if (array == null || array.Length == 0)
{
return null;
}
int num7 = Mathf.Max(1, num3 / 8);
int num8 = array.Length / num7;
float[] array2 = new float[num8];
switch (num3)
{
case 8:
{
for (int j = 0; j < num8; j++)
{
array2[j] = (float)(array[j] - 128) / 128f;
}
break;
}
case 16:
{
for (int k = 0; k < num8; k++)
{
array2[k] = (float)BitConverter.ToInt16(array, k * 2) / 32768f;
}
break;
}
case 32:
{
for (int i = 0; i < num8; i++)
{
array2[i] = (float)BitConverter.ToInt32(array, i * 4) / 2.1474836E+09f;
}
break;
}
default:
return null;
}
num = Mathf.Max(1, num);
AudioClip obj = AudioClip.Create(clipName, num8 / num, num, Mathf.Max(8000, num2), false);
obj.SetData(Il2CppStructArray<float>.op_Implicit(array2), 0);
return obj;
}
}
internal static class SoundPatches
{
private static float _last;
public static int Swapped;
public static int Hooked;
private static bool _forcedOff;
private static float _disarm = -1f;
private static float _groupCheck = -99f;
private static int _gun;
private static int _shells;
private static int _impact;
private static int _bullet;
private static int _soft;
private static int _hard;
private static int _foot;
private static int _npc;
private static int _head;
private static int _ui;
private static int _dMusic;
private static int _nMusic;
private static int _amb;
private static bool _groups;
private static string MarkerPath => Path.Combine(MelonEnvironment.UserDataDirectory, "QuickOneSound", ".hooked");
public static void CheckGuard()
{
try
{
if (File.Exists(MarkerPath))
{
_forcedOff = true;
File.Delete(MarkerPath);
MelonLogger.Warning("[quickonesound] the game went down last run with hooks on, watching instead of patching this time");
}
}
catch
{
}
}
public static void Tick(float dt)
{
if (_disarm < 0f)
{
return;
}
_disarm -= dt;
if (_disarm > 0f)
{
return;
}
_disarm = -1f;
try
{
if (File.Exists(MarkerPath))
{
File.Delete(MarkerPath);
}
}
catch
{
}
}
public static void Apply(Harmony h)
{
Hooked = 0;
int num = ((!_forcedOff) ? SoundSettings.Hooks : 0);
if (num <= 0)
{
MelonLogger.Msg("[quickonesound] watching the scene's audio sources, no hooks");
return;
}
try
{
File.WriteAllText(MarkerPath, "hooks were on when this run started");
}
catch
{
}
_disarm = 30f;
Scan(h, typeof(AudioPlayer), (string n) => n == "Play", level: true);
if (num >= 2)
{
Scan(h, typeof(Audio3dManager), (string n) => n.StartsWith("Play", StringComparison.Ordinal), level: false);
}
MelonLogger.Msg("[quickonesound] hooked " + Hooked + " audio entry points (mode " + num + ")");
}
private static void Scan(Harmony h, Type type, Func<string, bool> wanted, bool level)
{
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
//IL_0112: Unknown result type (might be due to invalid IL or missing references)
//IL_011f: Expected O, but got Unknown
foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type))
{
try
{
if (!wanted(declaredMethod.Name) || declaredMethod.ReturnType != typeof(void))
{
continue;
}
ParameterInfo[] parameters = declaredMethod.GetParameters();
if (parameters.Length != 0)
{
Type parameterType = parameters[0].ParameterType;
Type type2 = ((parameters.Length > 1) ? parameters[1].ParameterType : null);
string text = null;
if (parameterType == typeof(AudioClip))
{
text = ((type2 == typeof(AudioClip)) ? "TwoClips" : "OneClip");
}
else if (parameterType == typeof(Il2CppReferenceArray<AudioClip>))
{
text = ((type2 == typeof(Il2CppReferenceArray<AudioClip>)) ? "TwoSets" : "OneSet");
}
if (text != null)
{
h.Patch((MethodBase)declaredMethod, new HarmonyMethod(typeof(SoundPatches), text, (Type[])null), (!level) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(SoundPatches), "Level", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Hooked++;
}
}
}
catch (Exception ex)
{
MelonLogger.Warning("[quickonesound] couldn't hook " + type.Name + "." + declaredMethod.Name + ": " + ex.Message);
}
}
}
private static bool OneClip(ref AudioClip __0, AudioMixerGroup mixerGroup)
{
try
{
if (SoundBank.IsOurs(__0) || !Wanted(mixerGroup))
{
return true;
}
bool drop;
AudioClip val = Take(out drop);
if (drop)
{
return false;
}
if ((Object)(object)val == (Object)null)
{
return true;
}
__0 = val;
}
catch (Exception e)
{
Complain(e);
}
return true;
}
private static bool TwoClips(ref AudioClip __0, ref AudioClip __1, AudioMixerGroup mixerGroup)
{
try
{
if (SoundBank.IsOurs(__0) || !Wanted(mixerGroup))
{
return true;
}
bool drop;
AudioClip val = Take(out drop);
if (drop)
{
return false;
}
if ((Object)(object)val == (Object)null)
{
return true;
}
__0 = val;
__1 = val;
}
catch (Exception e)
{
Complain(e);
}
return true;
}
private static bool OneSet(ref Il2CppReferenceArray<AudioClip> __0, AudioMixerGroup mixerGroup)
{
try
{
if (Ours(__0) || !Wanted(mixerGroup))
{
return true;
}
bool drop;
AudioClip val = Take(out drop);
if (drop)
{
return false;
}
if ((Object)(object)val == (Object)null)
{
return true;
}
__0 = SoundBank.AsSet(val);
}
catch (Exception e)
{
Complain(e);
}
return true;
}
private static bool TwoSets(ref Il2CppReferenceArray<AudioClip> __0, ref Il2CppReferenceArray<AudioClip> __1, AudioMixerGroup mixerGroup)
{
try
{
if (Ours(__0) || !Wanted(mixerGroup))
{
return true;
}
bool drop;
AudioClip val = Take(out drop);
if (drop)
{
return false;
}
if ((Object)(object)val == (Object)null)
{
return true;
}
__1 = (__0 = SoundBank.AsSet(val));
}
catch (Exception e)
{
Complain(e);
}
return true;
}
private static void Level(AudioPlayer __instance)
{
try
{
if (SoundSettings.Enabled)
{
AudioSource source = __instance.source;
if (!((Object)(object)source == (Object)null) && SoundBank.IsOurs(source.clip))
{
source.volume *= Mathf.Clamp(SoundSettings.Volume, 0f, 4f);
source.pitch *= Mathf.Clamp(SoundSettings.Pitch, 0.1f, 3f);
}
}
}
catch (Exception e)
{
Complain(e);
}
}
private static AudioClip? Take(out bool drop)
{
drop = false;
if (!SoundSettings.Enabled)
{
return null;
}
AudioClip val = SoundBank.Clip();
if ((Object)(object)val == (Object)null)
{
return null;
}
float throttle = SoundSettings.Throttle;
float unscaledTime = Time.unscaledTime;
if (throttle > 0.001f && unscaledTime - _last < throttle)
{
drop = true;
return null;
}
_last = unscaledTime;
Swapped++;
return val;
}
private static bool Ours(Il2CppReferenceArray<AudioClip>? set)
{
try
{
return set != null && ((Il2CppArrayBase<AudioClip>)(object)set).Length > 0 && SoundBank.IsOurs(((Il2CppArrayBase<AudioClip>)(object)set)[0]);
}
catch
{
return false;
}
}
public static bool Wanted(AudioMixerGroup? g)
{
if ((Object)(object)g == (Object)null)
{
return true;
}
Groups();
if (!_groups)
{
return true;
}
int instanceID;
try
{
instanceID = ((Object)g).GetInstanceID();
}
catch
{
return true;
}
if (instanceID == _gun || instanceID == _shells)
{
return SoundSettings.Guns;
}
if (instanceID == _impact || instanceID == _bullet || instanceID == _soft || instanceID == _hard)
{
return SoundSettings.Impacts;
}
if (instanceID == _foot)
{
return SoundSettings.Footsteps;
}
if (instanceID == _npc || instanceID == _head)
{
return SoundSettings.Voices;
}
if (instanceID == _ui)
{
return SoundSettings.Ui;
}
if (instanceID == _dMusic || instanceID == _nMusic || instanceID == _amb)
{
return SoundSettings.Music;
}
return true;
}
private static void Groups()
{
if (_groups)
{
return;
}
float unscaledTime = Time.unscaledTime;
if (unscaledTime - _groupCheck < 3f)
{
return;
}
_groupCheck = unscaledTime;
try
{
AudioMixerGroup gunShot = Audio3dManager.gunShot;
if (!((Object)(object)gunShot == (Object)null))
{
_gun = ((Object)gunShot).GetInstanceID();
_shells = Id(Audio3dManager.shells);
_impact = Id(Audio3dManager.impact);
_bullet = Id(Audio3dManager.bulletImpact);
_soft = Id(Audio3dManager.softInteraction);
_hard = Id(Audio3dManager.hardInteraction);
_foot = Id(Audio3dManager.footsteps);
_npc = Id(Audio3dManager.npcVocals);
_head = Id(Audio3dManager.inHead);
_ui = Id(Audio3dManager.ui);
_dMusic = Id(Audio3dManager.diegeticMusic);
_nMusic = Id(Audio3dManager.nonDiegeticMusic);
_amb = Id(Audio3dManager.ambience);
_groups = true;
}
}
catch
{
}
}
private static int Id(AudioMixerGroup? g)
{
try
{
return ((Object)(object)g != (Object)null) ? ((Object)g).GetInstanceID() : 0;
}
catch
{
return 0;
}
}
public static void OnLevelLoaded()
{
_groups = false;
_groupCheck = -99f;
}
private static void Complain(Exception e)
{
if (SoundSettings.DebugLog && Time.frameCount % 300 == 0)
{
MelonLogger.Warning("[quickonesound] swap: " + e.Message);
}
}
}
public static class SoundSettings
{
private static MelonPreferences_Category _cat;
private static MelonPreferences_Entry<bool> _enabled;
private static MelonPreferences_Entry<string> _file;
private static MelonPreferences_Entry<bool> _random;
private static MelonPreferences_Entry<float> _volume;
private static MelonPreferences_Entry<float> _pitch;
private static MelonPreferences_Entry<float> _throttle;
private static MelonPreferences_Entry<float> _trim;
private static MelonPreferences_Entry<bool> _loops;
private static MelonPreferences_Entry<bool> _guns;
private static MelonPreferences_Entry<bool> _impacts;
private static MelonPreferences_Entry<bool> _footsteps;
private static MelonPreferences_Entry<bool> _voices;
private static MelonPreferences_Entry<bool> _ui;
private static MelonPreferences_Entry<bool> _music;
private static MelonPreferences_Entry<bool> _debug;
private static MelonPreferences_Entry<int> _hooks;
private static MelonPreferences_Entry<float> _delay;
public static bool Enabled
{
get
{
return _enabled.Value;
}
set
{
_enabled.Value = value;
Save();
}
}
public static string File
{
get
{
return _file.Value;
}
set
{
_file.Value = value;
Save();
}
}
public static bool Random
{
get
{
return _random.Value;
}
set
{
_random.Value = value;
Save();
}
}
public static float Volume
{
get
{
return _volume.Value;
}
set
{
_volume.Value = value;
Save();
}
}
public static float Pitch
{
get
{
return _pitch.Value;
}
set
{
_pitch.Value = value;
Save();
}
}
public static float Throttle
{
get
{
return _throttle.Value;
}
set
{
_throttle.Value = value;
Save();
}
}
public static float Trim
{
get
{
return _trim.Value;
}
set
{
_trim.Value = value;
Save();
}
}
public static bool Loops
{
get
{
return _loops.Value;
}
set
{
_loops.Value = value;
Save();
}
}
public static bool Guns
{
get
{
return _guns.Value;
}
set
{
_guns.Value = value;
Save();
}
}
public static bool Impacts
{
get
{
return _impacts.Value;
}
set
{
_impacts.Value = value;
Save();
}
}
public static bool Footsteps
{
get
{
return _footsteps.Value;
}
set
{
_footsteps.Value = value;
Save();
}
}
public static bool Voices
{
get
{
return _voices.Value;
}
set
{
_voices.Value = value;
Save();
}
}
public static bool Ui
{
get
{
return _ui.Value;
}
set
{
_ui.Value = value;
Save();
}
}
public static bool Music
{
get
{
return _music.Value;
}
set
{
_music.Value = value;
Save();
}
}
public static bool DebugLog
{
get
{
return _debug.Value;
}
set
{
_debug.Value = value;
Save();
}
}
public static int Hooks
{
get
{
return _hooks.Value;
}
set
{
_hooks.Value = value;
Save();
}
}
public static float Delay
{
get
{
return _delay.Value;
}
set
{
_delay.Value = value;
Save();
}
}
public static void Initialize()
{
_cat = MelonPreferences.CreateCategory("QuickOneSound");
_enabled = _cat.CreateEntry<bool>("Enabled", false, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_file = _cat.CreateEntry<string>("File", "", (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_random = _cat.CreateEntry<bool>("RandomEachTime", false, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_volume = _cat.CreateEntry<float>("Volume", 1f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_pitch = _cat.CreateEntry<float>("Pitch", 1f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_throttle = _cat.CreateEntry<float>("Throttle", 0.06f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_trim = _cat.CreateEntry<float>("Trim", 0f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_loops = _cat.CreateEntry<bool>("Loops", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_guns = _cat.CreateEntry<bool>("Guns", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_impacts = _cat.CreateEntry<bool>("Impacts", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_footsteps = _cat.CreateEntry<bool>("Footsteps", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_voices = _cat.CreateEntry<bool>("Voices", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_ui = _cat.CreateEntry<bool>("UI", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_music = _cat.CreateEntry<bool>("Music", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_debug = _cat.CreateEntry<bool>("DebugLog", false, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_hooks = _cat.CreateEntry<int>("Hooks", 0, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_delay = _cat.CreateEntry<float>("Delay", 10f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
}
private static void Save()
{
_cat.SaveToFile(false);
}
}
internal static class SoundSweeper
{
private sealed class Held
{
public AudioSource Src;
public AudioClip? Clip;
}
private static readonly List<AudioSource> _watch = new List<AudioSource>();
private static readonly Dictionary<int, Held> _held = new Dictionary<int, Held>();
private static readonly HashSet<int> _skip = new HashSet<int>();
private static readonly Dictionary<int, bool> _pooled = new Dictionary<int, bool>();
private static float _rescan;
private static float _last;
public static int Swapped;
public static int Count => _held.Count;
public static void OnLevelLoaded()
{
_watch.Clear();
_held.Clear();
_skip.Clear();
_pooled.Clear();
_rescan = 0f;
}
public static void Tick(float dt)
{
if (!SoundSettings.Enabled)
{
if (_held.Count > 0)
{
Restore();
}
return;
}
_rescan -= dt;
if (_rescan <= 0f)
{
_rescan = 2f;
Collect();
}
AudioClip val = SoundBank.Clip();
if ((Object)(object)val == (Object)null)
{
return;
}
float unscaledTime = Time.unscaledTime;
float throttle = SoundSettings.Throttle;
for (int i = 0; i < _watch.Count; i++)
{
AudioSource val2 = _watch[i];
try
{
if ((Object)(object)val2 == (Object)null || !val2.isPlaying)
{
continue;
}
AudioClip clip = val2.clip;
if ((Object)(object)clip == (Object)null || SoundBank.IsOurs(clip))
{
continue;
}
bool loop = val2.loop;
if ((loop && !SoundSettings.Loops) || !SoundPatches.Wanted(val2.outputAudioMixerGroup))
{
continue;
}
if (!loop && throttle > 0.001f && unscaledTime - _last < throttle)
{
val2.Stop();
continue;
}
if (!loop)
{
_last = unscaledTime;
}
if (!Pooled(val2, ((Object)val2).GetInstanceID()))
{
int instanceID = ((Object)val2).GetInstanceID();
if (!_held.TryGetValue(instanceID, out Held value))
{
_held[instanceID] = new Held
{
Src = val2,
Clip = clip
};
}
else
{
value.Clip = clip;
}
}
val2.volume = Mathf.Clamp(val2.volume * SoundSettings.Volume, 0f, 1f);
val2.pitch = Mathf.Clamp(val2.pitch * SoundSettings.Pitch, 0.1f, 3f);
val2.clip = val;
val2.Play();
Swapped++;
}
catch
{
}
}
}
private static void Collect()
{
try
{
_watch.Clear();
foreach (AudioSource item in Object.FindObjectsOfType<AudioSource>())
{
if ((Object)(object)item == (Object)null)
{
continue;
}
int instanceID = ((Object)item).GetInstanceID();
if (!_skip.Contains(instanceID))
{
if (!Safe(item))
{
_skip.Add(instanceID);
}
else
{
_watch.Add(item);
}
}
}
}
catch (Exception ex)
{
if (SoundSettings.DebugLog)
{
MelonLogger.Warning("[quickonesound] collect: " + ex.Message);
}
}
}
private static bool Safe(AudioSource src)
{
try
{
string text = ((Object)((Component)src).gameObject).name.ToLowerInvariant();
if (text.Contains("voice") || text.Contains("mic") || text.Contains("[quickonesound]"))
{
return false;
}
}
catch
{
return false;
}
return true;
}
private static bool Pooled(AudioSource src, int id)
{
if (_pooled.TryGetValue(id, out var value))
{
return value;
}
bool flag;
try
{
flag = (Object)(object)((Component)src).GetComponent<AudioPlayer>() != (Object)null;
}
catch
{
flag = true;
}
_pooled[id] = flag;
return flag;
}
public static void Restore()
{
foreach (Held value in _held.Values)
{
try
{
if (!((Object)(object)value.Src == (Object)null) && !((Object)(object)value.Clip == (Object)null))
{
bool isPlaying = value.Src.isPlaying;
value.Src.clip = value.Clip;
if (isPlaying)
{
value.Src.Play();
}
}
}
catch
{
}
}
_held.Clear();
}
}
}