using System;
using System.Collections;
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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyCompany("SoundpackLoader")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Loads custom soundpacks")]
[assembly: AssemblyFileVersion("0.2.6.0")]
[assembly: AssemblyInformationalVersion("0.2.6")]
[assembly: AssemblyProduct("SoundpackLoader")]
[assembly: AssemblyTitle("SoundpackLoader")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.6.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
}
namespace SoundpackLoader
{
internal static class AccessExtensions
{
public static T CallStaticMethod<T>(this Type type, string methodName, params object[] args)
{
MethodInfo method = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (method == null)
{
throw new MissingMemberException(type.Name, methodName);
}
return (T)method.Invoke(null, args);
}
}
internal static class CollectionExtensions
{
public static T GetRandom<T>(this IEnumerable<T> vals)
{
return vals.OrderBy((T x) => Guid.NewGuid()).First();
}
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> source) where T : class
{
return source.Where((T item) => item != null);
}
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> source) where T : struct
{
return source.Where(delegate(T? item)
{
T? val2 = item;
return val2.HasValue;
}).Select(delegate(T? item)
{
T? val = item;
return val.Value;
});
}
}
public static class VanillaExtensions
{
public static void ChangePack(this GameController self, Soundpack soundpack)
{
SoundpackManager.ChangePack(self, soundpack);
}
}
[BepInPlugin("org.crispykevin.soundpackloader", "SoundpackLoader", "0.2.6")]
internal class Plugin : BaseUnityPlugin
{
public static ManualLogSource Logger = null;
public static SoundpackLoader Loader = null;
public static ConfigEntry<KeyCode> CycleForwards = null;
public static ConfigEntry<KeyCode> CycleBackwards = null;
public static ConfigEntry<int> SelectedIdx = null;
public static string CustomSoundpacksPath = Path.Combine(Paths.BepInExRootPath, "CustomSoundpacks");
public Plugin()
{
Logger = ((BaseUnityPlugin)this).Logger;
}
private void Awake()
{
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
CycleForwards = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "CycleForwards", (KeyCode)281, (ConfigDescription)null);
CycleBackwards = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "CycleBackwards", (KeyCode)280, (ConfigDescription)null);
SelectedIdx = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Soundpack Index", 0, (ConfigDescription)null);
new Harmony("org.crispykevin.soundpackloader").PatchAll();
Logger.LogInfo((object)"Plugin org.crispykevin.soundpackloader v0.2.6 is loaded!");
}
private void Start()
{
Loader = ((Component)this).gameObject.AddComponent<SoundpackLoader>();
LoadVanillaSoundpacks();
LoadCustomSoundpacks();
SoundpackManager.CurrentPack = SoundpackManager.soundpacks[0];
SoundpackManager.SoundpackChanged += delegate(object _, SoundpackChangedEventArgs e)
{
int num = SoundpackManager.soundpacks.IndexOf(e.NewPack);
if (num != -1)
{
SelectedIdx.Value = num;
}
Logger.LogInfo((object)$"{SelectedIdx.Value}. {e.NewPack}");
};
}
private void LoadVanillaSoundpacks()
{
Logger.LogInfo((object)"Loading vanilla soundpacks...");
foreach (KeyValuePair<string, SoundpackInfo> item in SoundpackManager.VANILLA_SOUNDPACK_INFO)
{
SoundpackManager.AddPack(new Soundpack
{
Name = item.Key,
Namespace = "vanilla",
VolumeModifier = item.Value.volume
});
}
}
private void LoadCustomSoundpacks()
{
Logger.LogInfo((object)"Loading custom soundpacks...");
DirectoryInfo directoryInfo = new DirectoryInfo(CustomSoundpacksPath);
if (!directoryInfo.Exists)
{
Directory.CreateDirectory(CustomSoundpacksPath);
}
if (!directoryInfo.Exists)
{
return;
}
IEnumerable<DirectoryInfo> enumerable = directoryInfo.EnumerateDirectories();
foreach (DirectoryInfo item in enumerable)
{
((MonoBehaviour)this).StartCoroutine(Loader.LoadSoundpack(item));
}
}
}
[HarmonyPatch(typeof(GameController))]
internal class GameControllerPatch
{
private static EventHandler<SoundpackChangedEventArgs>? OnSoundpackChanged;
private static GameObject? TrombClipsHolder;
private static IEnumerator EmptyIEnumerator()
{
yield break;
}
[HarmonyPrefix]
[HarmonyPatch("loadSoundBundleResources")]
private static bool PatchOutSoundBundleResources(GameController __instance, ref IEnumerator __result)
{
if (!SoundpackManager.CurrentPack.IsVanilla)
{
__result = EmptyIEnumerator();
__instance.fixAudioMixerStuff();
return false;
}
return true;
}
[HarmonyPostfix]
[HarmonyPatch("Start")]
private static void AfterStart(GameController __instance)
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Expected O, but got Unknown
GameController __instance2 = __instance;
OnSoundpackChanged = delegate(object _, SoundpackChangedEventArgs e)
{
SoundpackManager.ChangePack(__instance2, e.NewPack);
};
SoundpackManager.SoundpackChanged += OnSoundpackChanged;
TrombClipsHolder = new GameObject();
__instance2.trombclips = TrombClipsHolder.AddComponent<AudioClipsTromb>();
SoundpackManager.ChangePack(__instance2, SoundpackManager.CurrentPack);
}
[HarmonyPostfix]
[HarmonyPatch("unloadBundles")]
private static void AfterUnloadBundles(GameController __instance)
{
Plugin.Logger.LogInfo((object)"AfterUnloadBundles");
SoundpackManager.SoundpackChanged -= OnSoundpackChanged;
OnSoundpackChanged = null;
Object.Destroy((Object)(object)TrombClipsHolder);
TrombClipsHolder = null;
}
}
[HarmonyPatch(typeof(CharSelectController_new))]
internal class CharSelectControllerPatch
{
private static GameObject soundpackTextHolder;
private static Text soundpackText;
private static int soundpackIndex;
[HarmonyPrefix]
[HarmonyPatch("Start")]
private static void BeforeStart()
{
soundpackIndex = Plugin.SelectedIdx.Value;
}
[HarmonyPostfix]
[HarmonyPatch("Start")]
private static void AfterStart(CharSelectController_new __instance)
{
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
//IL_0137: Unknown result type (might be due to invalid IL or missing references)
Plugin.Logger.LogInfo((object)"AfterStart");
__instance.chooseSoundPack(soundpackIndex);
GameObject gameObject = __instance.all_sfx_buttons[0].img_text.gameObject;
soundpackTextHolder = Object.Instantiate<GameObject>(gameObject, Vector3.zero, Quaternion.identity, GameObject.Find("Canvas").transform);
soundpackTextHolder.SetActive(true);
soundpackText = soundpackTextHolder.GetComponent<Text>();
string name = SoundpackManager.CurrentPack.Name;
soundpackText.text = name;
((Component)((Component)soundpackText).transform.GetChild(0)).GetComponent<Text>().text = name;
((Graphic)soundpackText).rectTransform.anchorMin = new Vector2(0.7f, 1f);
((Graphic)soundpackText).rectTransform.anchorMax = new Vector2(1f, 1f);
((Graphic)soundpackText).rectTransform.offsetMin = new Vector2(0f, -75f);
((Graphic)soundpackText).rectTransform.offsetMax = new Vector2(0f, -75f);
((Transform)((Graphic)soundpackText).rectTransform).localScale = new Vector3(0.6f, 0.6f, 1f);
soundpackText.alignment = (TextAnchor)7;
SoundpackManager.SoundpackChanged += OnSoundpackChanged;
}
private static void OnSoundpackChanged(object? sender, SoundpackChangedEventArgs e)
{
soundpackText.text = e.NewPack.Name;
((Component)((Component)soundpackText).transform.GetChild(0)).GetComponent<Text>().text = e.NewPack.Name;
}
[HarmonyPostfix]
[HarmonyPatch("Update")]
private static void Update(CharSelectController_new __instance)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
if (Input.GetKeyDown(Plugin.CycleForwards.Value))
{
ConfigEntry<int> selectedIdx = Plugin.SelectedIdx;
int num2 = (selectedIdx.Value += 1);
if (num2 >= SoundpackManager.soundpacks.Count)
{
Plugin.SelectedIdx.Value = 0;
}
__instance.chooseSoundPack(Plugin.SelectedIdx.Value);
}
if (Input.GetKeyDown(Plugin.CycleBackwards.Value))
{
ConfigEntry<int> selectedIdx2 = Plugin.SelectedIdx;
int num2 = (selectedIdx2.Value -= 1);
if (num2 < 0)
{
Plugin.SelectedIdx.Value = SoundpackManager.soundpacks.Count - 1;
}
__instance.chooseSoundPack(Plugin.SelectedIdx.Value);
}
}
[HarmonyPostfix]
[HarmonyPatch("loadNextScene")]
private static void OnLeaveSelectScreen(CharSelectController_new __instance)
{
Plugin.Logger.LogInfo((object)"Cleaning up char select screen");
soundpackTextHolder.SetActive(false);
Object.Destroy((Object)(object)soundpackTextHolder);
SoundpackManager.SoundpackChanged -= OnSoundpackChanged;
}
[HarmonyPrefix]
[HarmonyPatch("chooseSoundPack")]
private static bool BeforeChooseSoundPack(CharSelectController_new __instance, int sfx_choice)
{
SoundpackManager.CurrentPack = SoundpackManager.soundpacks[sfx_choice];
for (int i = 0; i < __instance.all_sfx_buttons.Length; i++)
{
if (i != sfx_choice)
{
__instance.all_sfx_buttons[i].deselectBtn();
}
}
return sfx_choice < __instance.all_sfx_buttons.Length;
}
}
public class Soundpack
{
public string Name { get; init; } = "Custom Soundpack";
public string Namespace { get; init; } = "unknown";
public float VolumeModifier { get; init; } = 1f;
public DirectoryInfo Directory { get; init; } = null;
public AudioClip[] Notes { get; init; } = (AudioClip[])(object)new AudioClip[15];
public bool IsVanilla => Namespace == "vanilla";
public string QualifiedName => Namespace + ":" + Name;
internal Soundpack()
{
}
public override string ToString()
{
return QualifiedName;
}
}
internal record SoundpackInfo(int order, float volume);
internal class SoundpackJsonMetadata
{
public int SoundpackFormatRevision = -1;
public string Name { get; set; } = "Custom Soundpack";
public string Namespace { get; set; } = "unknown";
public float VolumeModifier { get; set; } = 1f;
}
public class SoundpackChangedEventArgs : EventArgs
{
public Soundpack NewPack { get; }
public Soundpack OldPack { get; }
internal SoundpackChangedEventArgs(Soundpack newPack, Soundpack oldPack)
{
NewPack = newPack;
OldPack = oldPack;
}
}
public class SoundpackLoader : MonoBehaviour
{
public IEnumerator LoadSoundpack(DirectoryInfo dir)
{
FileInfo jsonFile = dir.GetFiles("*.json").FirstOrDefault();
if (jsonFile == null)
{
Plugin.Logger.LogWarning((object)("No JSON file in soundpack directory: " + dir.FullName));
yield break;
}
SoundpackJsonMetadata metadata = JsonUtil.ReadFile<SoundpackJsonMetadata>(jsonFile);
if (metadata == null)
{
Plugin.Logger.LogWarning((object)("Failed to read JSON file: " + jsonFile.FullName));
yield break;
}
if (metadata.SoundpackFormatRevision == -1)
{
Plugin.Logger.LogWarning((object)("Missing SoundpackFormatRevision number in soundpack " + metadata.Namespace + ":" + metadata.Name + "! (Located in " + dir.Name + ")"));
}
Soundpack soundpack = new Soundpack
{
Name = metadata.Name,
Namespace = metadata.Namespace,
VolumeModifier = metadata.VolumeModifier,
Directory = dir
};
((MonoBehaviour)this).StartCoroutine(LoadNoteAudioFilesCoroutine(soundpack));
SoundpackManager.AddPack(soundpack);
yield return null;
}
private IEnumerator GetAudioClipCoroutine(FileInfo fileInfo, Action<AudioClip> onSuccess, Action<string> onError)
{
Dictionary<string, AudioType> EXTENSION_TO_AUD_TYPE = new Dictionary<string, AudioType>
{
["wav"] = (AudioType)20,
["mp3"] = (AudioType)13,
["ogg"] = (AudioType)14
};
AudioType audType = CollectionExtensions.GetValueOrDefault<string, AudioType>((IReadOnlyDictionary<string, AudioType>)EXTENSION_TO_AUD_TYPE, fileInfo.Extension.ToLower(), (AudioType)0);
string uri = "file://" + fileInfo.FullName;
UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(uri, audType);
try
{
((DownloadHandlerAudioClip)www.downloadHandler).streamAudio = false;
yield return www.SendWebRequest();
if (www.error != null)
{
onError(www.error);
yield break;
}
AudioClip myClip = DownloadHandlerAudioClip.GetContent(www);
onSuccess(myClip);
}
finally
{
((IDisposable)www)?.Dispose();
}
}
private IEnumerator LoadNoteAudioFilesCoroutine(Soundpack soundpack)
{
Soundpack soundpack2 = soundpack;
string[] NOTE_NAMES = new string[15]
{
"C1", "D1", "E1", "F1", "G1", "A1", "B1", "C2", "D2", "E2",
"F2", "G2", "A2", "B2", "C3"
};
int numLoadedClips = 0;
bool isWaiting = false;
Plugin.Logger.LogInfo((object)soundpack2.QualifiedName);
int i = 0;
while (i < NOTE_NAMES.Length)
{
if (isWaiting)
{
yield return null;
}
string noteName = NOTE_NAMES[i];
FileInfo noteFile = soundpack2.Directory.GetFiles("*" + noteName + ".*").FirstOrDefault();
if (noteFile == null)
{
string err2 = "Audio file not found for note " + noteName + " in soundpack " + soundpack2.QualifiedName;
Plugin.Logger.LogWarning((object)err2);
break;
}
int idx = i;
((MonoBehaviour)this).StartCoroutine(GetAudioClipCoroutine(noteFile, delegate(AudioClip clip)
{
soundpack2.Notes[idx] = clip;
int num2 = NOTE_NAMES.Length;
int num3 = numLoadedClips + 1;
numLoadedClips = num3;
if (num2 == num3)
{
Plugin.Logger.LogInfo((object)("Successfully loaded soundpack: " + soundpack2.QualifiedName));
}
isWaiting = false;
}, delegate(string err)
{
string text = "Error loading note " + noteName + " in soundpack " + soundpack2.QualifiedName + ": " + err;
Plugin.Logger.LogWarning((object)text);
}));
isWaiting = true;
yield return null;
int num = i + 1;
i = num;
}
}
}
public class SoundpackManager
{
internal static List<Soundpack> soundpacks = new List<Soundpack>();
internal static readonly Dictionary<string, SoundpackInfo> VANILLA_SOUNDPACK_INFO = new Dictionary<string, SoundpackInfo>
{
["default"] = new SoundpackInfo(0, 1f),
["bass"] = new SoundpackInfo(1, 0.72f),
["muted"] = new SoundpackInfo(2, 0.34f),
["eightbit"] = new SoundpackInfo(3, 0.25f),
["club"] = new SoundpackInfo(4, 0.25f),
["fart"] = new SoundpackInfo(5, 0.75f)
};
internal static Soundpack _currentPack = new Soundpack();
public static Soundpack CurrentPack
{
get
{
return _currentPack;
}
set
{
Soundpack currentPack = _currentPack;
_currentPack = value;
if (currentPack != _currentPack)
{
OnSoundpackChanged(_currentPack, currentPack);
}
}
}
public static event EventHandler<SoundpackChangedEventArgs>? SoundpackChanged;
public static IEnumerable<Soundpack> GetAllPacks()
{
return soundpacks;
}
public static IEnumerable<Soundpack> GetVanillaPacks()
{
return from p in GetAllPacks()
where p.IsVanilla
select p;
}
public static IEnumerable<Soundpack> GetCustomPacks()
{
return from p in GetAllPacks()
where !p.IsVanilla
select p;
}
public static Soundpack? FindPack(string nmspace, string name)
{
string nmspace2 = nmspace;
string name2 = name;
return soundpacks.FirstOrDefault((Soundpack s) => s.Namespace == nmspace2 && s.Name == name2);
}
public static void AddPack(Soundpack pack)
{
soundpacks.Add(pack);
}
public static bool RemovePack(Soundpack pack)
{
return soundpacks.Remove(pack);
}
public static Soundpack? RemovePack(string nmspace, string name)
{
string nmspace2 = nmspace;
string name2 = name;
int num = soundpacks.FindIndex((Soundpack p) => p.Namespace == nmspace2 && p.Name == name2);
if (num != -1)
{
Soundpack result = soundpacks[num];
soundpacks.RemoveAt(num);
return result;
}
return null;
}
public static Soundpack ClonePack(Soundpack pack)
{
Soundpack soundpack = new Soundpack
{
Name = pack.Name,
Namespace = pack.Namespace,
Directory = pack.Directory,
VolumeModifier = pack.VolumeModifier
};
float[] buf = new float[pack.Notes.Max((AudioClip n) => n.channels * n.samples)];
for (int i = 0; i < pack.Notes.Length; i++)
{
soundpack.Notes[i] = AudioUtil.CloneAudioClip(pack.Notes[i], buf);
}
return soundpack;
}
public static void ChangePack(GameController gc, Soundpack soundpack)
{
CurrentPack = soundpack;
if (!soundpack.IsVanilla)
{
gc.trombclips.tclips = soundpack.Notes;
float trombvol_current = (gc.currentnotesound.volume = soundpack.VolumeModifier);
gc.trombvol_default = (gc.trombvol_current = trombvol_current);
}
}
internal static void OnSoundpackChanged(Soundpack newPack, Soundpack oldPack)
{
SoundpackManager.SoundpackChanged?.Invoke(null, new SoundpackChangedEventArgs(CurrentPack, oldPack));
}
}
internal class AudioUtil
{
public static AudioClip CloneAudioClip(AudioClip clip, float[]? buf = null)
{
AudioClip val = AudioClip.Create(((Object)clip).name, clip.samples, clip.channels, clip.frequency, false);
if (buf == null || buf.Length < clip.samples * clip.channels)
{
buf = new float[clip.samples * clip.channels];
}
object[] array = new object[4] { clip, buf, clip.samples, 0 };
typeof(AudioClip).CallStaticMethod<bool>("GetData", array);
array[0] = val;
typeof(AudioClip).CallStaticMethod<bool>("SetData", array);
return val;
}
}
internal class DebugUtil
{
public static void Dump(object? obj, LogLevel level = 16, string objExpression = "<unknown>")
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Expected O, but got Unknown
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
JsonSerializerSettings val = new JsonSerializerSettings();
val.Formatting = (Formatting)1;
val.MaxDepth = 6;
val.ReferenceLoopHandling = (ReferenceLoopHandling)1;
string text = JsonConvert.SerializeObject(obj, val);
Plugin.Logger.Log(level, (object)(objExpression + " = " + text));
}
}
internal class JsonUtil
{
public static T? ReadFile<T>(FileInfo file) where T : class
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Expected O, but got Unknown
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Expected O, but got Unknown
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
JsonSerializerSettings val = new JsonSerializerSettings();
JsonSerializer val2 = new JsonSerializer();
using StreamReader streamReader = new StreamReader(file.FullName);
JsonTextReader val3 = new JsonTextReader((TextReader)streamReader);
try
{
return val2.Deserialize<T>((JsonReader)(object)val3);
}
catch (Exception obj)
{
DebugUtil.Dump(obj, (LogLevel)4);
return null;
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
public static T? ReadFile<T>(string path) where T : class
{
return ReadFile<T>(new FileInfo(path));
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "org.crispykevin.soundpackloader";
public const string PLUGIN_NAME = "SoundpackLoader";
public const string PLUGIN_VERSION = "0.2.6";
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
internal sealed class CallerArgumentExpressionAttribute : Attribute
{
public string ParameterName { get; }
public CallerArgumentExpressionAttribute(string parameterName)
{
ParameterName = parameterName;
}
}
internal static class IsExternalInit
{
}
}