using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using HarmonyLib; using MelonLoader; using Microsoft.CodeAnalysis; using Newtonsoft.Json.Linq; using SoundImporter; using SoundImporter.Managers; using Steamworks; using UnityEngine; using UnityEngine.Networking; using UnityEngine.UIElements; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(Core), "BetonJukebox", "1.0.0", "Xannix", null)] [assembly: MelonGame("Jan Malitschek", "BetonBrutal")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("BetonJukebox")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("BetonJukebox")] [assembly: AssemblyTitle("BetonJukebox")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 SoundImporter { public class Core : MelonMod { public override void OnInitializeMelon() { ((MelonBase)this).LoggerInstance.Msg("Initialized."); } } [Serializable] public class CustomSound { public string ID; public string Path; public string Name; public string Category; public string Subcategory; } } namespace SoundImporter.Patches { [HarmonyPatch(typeof(MapEditor), "LoadMap")] public static class OnLocalMapLoading { private static void Prefix(string mapName) { RegisterManager.ClearCustomSounds(); string text = Path.Combine(Application.persistentDataPath, "CustomMaps", mapName); if (Directory.Exists(text)) { SoundImporter.Managers.SoundImporter.LoadSoundsFromDirectory(text); } else { MelonLogger.Warning("Directory does not exist: " + text); } } } [HarmonyPatch(typeof(MapEditor), "LoadDownloadedMap")] public static class OnWorkshopMapLoading { private static void Prefix(string mapItemID) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) RegisterManager.ClearCustomSounds(); string text = $"{SteamApps.AppInstallDir(default(AppId))}\\..\\..\\workshop\\content\\{SteamClient.AppId.Value}\\{mapItemID}"; if (Directory.Exists(text)) { SoundImporter.Managers.SoundImporter.LoadSoundsFromDirectory(text); } else { MelonLogger.Warning("Directory does not exist: " + text); } } } [HarmonyPatch(typeof(SoundPicker), "Init")] public static class SoundPickerInitPatch { public static void RefreshCategories(SoundPicker picker) { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown if (picker == null || (Object)(object)TriggerSoundManager.Instance == (Object)null) { return; } ScrollView value = Traverse.Create((object)picker).Field("categories").Value; List value2 = Traverse.Create((object)picker).Field>("categoryItems").Value; if (value == null || value2 == null) { return; } ((VisualElement)value).Clear(); value2.Clear(); HashSet hashSet = TriggerSoundManager.Instance.TriggerSounds.Select((TriggerSound x) => x.category).ToHashSet(); foreach (string item in hashSet) { Category val = new Category(); val.Populate(item); val.onClick += delegate(string catName) { Traverse.Create((object)picker).Method("PopulateCategory", new object[1] { catName }).GetValue(); }; val.Select(false); ((VisualElement)value).Add((VisualElement)(object)val); value2.Add(val); } if (hashSet.Count > 0) { Traverse.Create((object)picker).Method("PopulateCategory", new object[1] { hashSet.First() }).GetValue(); } } } [HarmonyPatch(typeof(MoveTriggerScreen), "PickSound")] public static class OnSoundMenuOpened { private static void Prefix() { UIUpdate(); } private static void UIUpdate() { //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) UIDocument[] array = Object.FindObjectsOfType(); UIDocument[] array2 = array; foreach (UIDocument val in array2) { if (val.rootVisualElement == null) { continue; } List list = UQueryExtensions.Query(val.rootVisualElement, (string)null, (string)null).ToList(); foreach (SoundPicker item in list) { SoundPickerInitPatch.RefreshCategories(item); } } } } } namespace SoundImporter.Managers { public static class RegisterManager { private static readonly Dictionary LoadedCustomSounds = new Dictionary(); public static void RegisterCustomTriggerSound(CustomSound soundData, List clips) { if (!((Object)(object)TriggerSoundManager.Instance == (Object)null) && clips != null && clips.Count != 0) { if (LoadedCustomSounds.ContainsKey(soundData.ID)) { MelonLogger.Warning("Sounds already has " + soundData.ID + "! Skipping"); return; } TriggerSound val = ScriptableObject.CreateInstance(); ((Object)val).name = soundData.ID; val.soundName = soundData.Name; val.category = soundData.Category; val.subcategory = soundData.Subcategory; val.sounds = clips.ToArray(); val.mixerChannel = TriggerSoundManager.Instance.defaultMixerChannel; List list = new List(TriggerSoundManager.Instance.TriggerSounds) { val }; typeof(TriggerSoundManager).GetProperty("TriggerSounds")?.SetValue(TriggerSoundManager.Instance, list.ToArray()); LoadedCustomSounds.Add(soundData.ID, val); Debug.Log((object)$"Sound registered: '{soundData.ID}' ({clips.Count} files)"); } } public static void ClearCustomSounds() { if (LoadedCustomSounds.Count == 0) { return; } TriggerSoundManager instance = TriggerSoundManager.Instance; if ((Object)(object)instance != (Object)null && instance.TriggerSounds != null) { List list = new List(instance.TriggerSounds); foreach (TriggerSound value in LoadedCustomSounds.Values) { list.Remove(value); if (value.sounds != null) { AudioClip[] sounds = value.sounds; foreach (AudioClip val in sounds) { Object.Destroy((Object)(object)val); } } Object.Destroy((Object)(object)value); } typeof(TriggerSoundManager).GetProperty("TriggerSounds")?.SetValue(instance, list.ToArray()); } LoadedCustomSounds.Clear(); Debug.Log((object)"Custom sounds cleared."); } } public static class SoundImporter { public static void LoadSoundsFromDirectory(string mapFolderPath) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Invalid comparison between Unknown and I4 //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Invalid comparison between Unknown and I4 MelonLogger.Msg("Sync loading sounds for: " + mapFolderPath); if (!Directory.Exists(mapFolderPath)) { MelonLogger.Warning("Directory does not exist: " + mapFolderPath); return; } string[] files; try { files = Directory.GetFiles(mapFolderPath, "*.json", SearchOption.AllDirectories); MelonLogger.Msg($"Found {files.Length} .json files."); } catch (Exception ex) { MelonLogger.Error("Failed to read directory: " + ex.Message); return; } string[] array = files; foreach (string text in array) { List list = new List(); try { string text2 = File.ReadAllText(text); JToken val = JToken.Parse(text2); if ((int)val.Type == 2) { list = val.ToObject>(); } else if ((int)val.Type == 1) { CustomSound customSound = val.ToObject(); if (customSound != null) { list.Add(customSound); } } } catch { continue; } if (list == null || list.Count == 0) { continue; } foreach (CustomSound item in list) { if (string.IsNullOrEmpty(item.Name) || string.IsNullOrEmpty(item.Path)) { MelonLogger.Warning("Skipping entry in " + text + ": Missing Name or Path."); continue; } string category = (string.IsNullOrEmpty(item.Category) ? "Custom" : item.Category); string subcategory = (string.IsNullOrEmpty(item.Subcategory) ? "Sounds" : item.Subcategory); string text3 = Path.Combine(mapFolderPath, "Sounds", item.Path); List list2 = new List(); if (File.Exists(text3) && text3.EndsWith(".ogg", StringComparison.OrdinalIgnoreCase)) { list2.Add(text3); } else if (Directory.Exists(text3)) { list2.AddRange(Directory.GetFiles(text3, "*.ogg", SearchOption.AllDirectories)); } if (list2.Count == 0) { MelonLogger.Warning("No .ogg files found for sound '" + item.Name + "' at path: " + text3); continue; } List list3 = new List(); foreach (string item2 in list2) { AudioClip val2 = LoadAudioClipSync(item2); if ((Object)(object)val2 != (Object)null) { list3.Add(val2); } } if (list3.Count > 0) { item.Category = category; item.Subcategory = subcategory; item.ID = string.Join('_', item.Name.Split(" ")).ToLower(); RegisterManager.RegisterCustomTriggerSound(item, list3); } } } } private static AudioClip LoadAudioClipSync(string filePath) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Invalid comparison between Unknown and I4 string text = "file://" + filePath; UnityWebRequest audioClip = UnityWebRequestMultimedia.GetAudioClip(text, (AudioType)14); try { UnityWebRequestAsyncOperation val = audioClip.SendWebRequest(); while (!((AsyncOperation)val).isDone) { } if ((int)audioClip.result != 1) { MelonLogger.Error("Failed to load " + filePath + ": " + audioClip.error); return null; } AudioClip content = DownloadHandlerAudioClip.GetContent(audioClip); if ((Object)(object)content != (Object)null) { ((Object)content).name = Path.GetFileNameWithoutExtension(filePath); } return content; } finally { ((IDisposable)audioClip)?.Dispose(); } } } }