Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ElsaMusicMod v0.0.3
plugins\ElsaMusicMod.dll
Decompiled a month agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ElsaMusicMod.Audio; using ElsaMusicMod.Components; using ElsaMusicMod.Config; using ElsaMusicMod.Utils; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6", FrameworkDisplayName = ".NET Framework 4.6")] [assembly: AssemblyVersion("0.0.0.0")] [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 ElsaMusicMod { public static class Constants { public const string PluginGUID = "ua.jaffyfox.elsamusicmod"; public const string PluginName = "ElsaMusicMod"; public const string PluginVersion = "0.0.2"; public const string LogPrefix = "[ElsaMusicMod]"; public const string ConfigSectionGeneral = "General"; public const string ConfigSectionAudio = "Audio"; public const string ConfigSectionDebug = "Debug"; public const string ConfigKeyEnableMod = "EnableMod"; public const string ConfigKeyEnableSoundElsa = "EnableSoundElsa"; public const string ConfigKeyEnableSoundHuntsman = "EnableSoundHuntsman"; public const string ConfigKeySoundPathElsa = "SoundPathElsa"; public const string ConfigKeySoundPathHuntsman = "SoundPathHuntsman"; public const string ConfigKeyVolume = "Volume"; public const string ConfigKeyAudioMode = "AudioMode"; public const string ConfigKeySpatialMaxDistance = "SpatialMaxDistance"; public const string ConfigKeyDebugMode = "DebugMode"; public const string ConfigKeyLanguage = "Language"; public const string ConfigKeyFadeDuration = "FadeDuration"; public const string ConfigKeySpatialMuffle = "SpatialMuffle"; public const bool DefaultEnableMod = true; public const bool DefaultEnableSoundElsa = true; public const bool DefaultEnableSoundHuntsman = true; public const string DefaultSoundPathElsa = ""; public const string DefaultSoundPathHuntsman = ""; public const float DefaultVolume = 0.8f; public const string DefaultAudioMode = "Spatial"; public const float DefaultSpatialMaxDistance = 20f; public const bool DefaultDebugMode = false; public const string DefaultLanguage = "en"; public const float DefaultFadeDuration = 0.5f; public const bool DefaultSpatialMuffle = true; public const string AudioModeGlobal = "Global"; public const string AudioModeSpatial = "Spatial"; public const string LangEnglish = "en"; public const string LangRussian = "ru"; public const string DefaultElsaSoundFile = "Sounds/elsa_theme.ogg"; public const string DefaultHuntsmanSoundFile = "Sounds/huntsman_shoot.ogg"; public const float SpatialBlend3D = 1f; public const float SpatialBlend2D = 0f; public const float SpatialMinDistance = 1f; public const float DopplerLevel = 0f; public const float LowPassCutoffClose = 22000f; public const float LowPassCutoffFar = 400f; public const float LowPassResonance = 1f; public static readonly string[] AggressiveStateNames = new string[7] { "TransformSmallToBig", "GoToPlayerBig", "GoToPlayerOverBig", "BackToNavMeshBig", "LookUnderStartBig", "LookUnderBig", "LookUnderStopBig" }; public static readonly string[] AggressiveHunterStateNames = new string[1] { "Shoot" }; } [BepInPlugin("ua.jaffyfox.elsamusicmod", "ElsaMusicMod", "0.0.2")] public class Plugin : BaseUnityPlugin { private Harmony _harmony; public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } private void Awake() { //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Expected O, but got Unknown if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[ElsaMusicMod] Duplicate initialization — ignoring."); return; } Instance = this; Log = ((BaseUnityPlugin)this).Logger; ModConfig.Init(((BaseUnityPlugin)this).Config); Loc.LogInfo("ElsaMusicMod v0.0.2 — initializing...", "ElsaMusicMod v0.0.2 — инициализация..."); Loc.LogInfo("Config loaded.", "Конфиг загружен."); Loc.LogInfo($" EnableMod: {ModConfig.EnableMod.Value}", $" EnableMod: {ModConfig.EnableMod.Value}"); Loc.LogInfo($" EnableSoundElsa: {ModConfig.EnableSoundElsa.Value}", $" EnableSoundElsa: {ModConfig.EnableSoundElsa.Value}"); Loc.LogInfo($" EnableSoundHuntsman: {ModConfig.EnableSoundHuntsman.Value}", $" EnableSoundHuntsman: {ModConfig.EnableSoundHuntsman.Value}"); Loc.LogInfo(" Language: " + ModConfig.Language.Value, " Language: " + ModConfig.Language.Value); if (!ModConfig.EnableMod.Value) { Loc.LogInfo("Mod disabled in config. No patches applied.", "Мод отключен в конфиге. Патчи не применяются."); return; } string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); AudioManager.Initialize(directoryName); Loc.LogDebug("Plugin folder: " + directoryName, "Папка плагина: " + directoryName); ((MonoBehaviour)this).StartCoroutine(AudioManager.LoadAudioCoroutine(ModConfig.SoundPathElsa.Value, isElsa: true)); ((MonoBehaviour)this).StartCoroutine(AudioManager.LoadAudioCoroutine(ModConfig.SoundPathHuntsman.Value, isElsa: false)); try { _harmony = new Harmony("ua.jaffyfox.elsamusicmod"); _harmony.PatchAll(); Loc.LogInfo("Harmony patches applied successfully.", "Harmony патчи успешно применены."); } catch (Exception arg) { Loc.LogError($"Harmony patching error: {arg}", $"Ошибка при применении патчей Harmony: {arg}"); Loc.LogError("Mod will not work. Game classes may have changed in an update.", "Мод не будет работать. Возможно, классы игры изменились в обновлении."); } Loc.LogInfo("ElsaMusicMod v0.0.2 — initialized!", "ElsaMusicMod v0.0.2 — успешно инициализирован!"); } } } namespace ElsaMusicMod.Utils { public static class Loc { public static bool IsRussian { get { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)Application.systemLanguage != 30) { if ((Object)(object)Plugin.Instance != (Object)null && ModConfig.Language != null) { return ModConfig.Language.Value == "ru"; } return false; } return true; } } public static string Get(string en, string ru) { if (!IsRussian) { return en; } return ru; } public static void LogInfo(string en, string ru) { Plugin.Log.LogInfo((object)("[ElsaMusicMod] " + Get(en, ru))); } public static void LogWarning(string en, string ru) { Plugin.Log.LogWarning((object)("[ElsaMusicMod] " + Get(en, ru))); } public static void LogError(string en, string ru) { Plugin.Log.LogError((object)("[ElsaMusicMod] " + Get(en, ru))); } public static void LogDebug(string en, string ru) { if ((Object)(object)Plugin.Instance != (Object)null && ModConfig.IsDebug) { Plugin.Log.LogInfo((object)("[ElsaMusicMod] [DEBUG] " + Get(en, ru))); } } } } namespace ElsaMusicMod.Patches { [HarmonyPatch(typeof(EnemyElsa), "Update")] internal static class EnemyElsaUpdatePatch { private static readonly Dictionary<int, int> _previousStates = new Dictionary<int, int>(); private static readonly HashSet<int> _aggressiveStates = new HashSet<int>(); private static FieldInfo _currentStateField; private static bool _initialized; private static bool _initFailed; private static void Initialize() { if (_initialized) { return; } _initialized = true; try { _currentStateField = typeof(EnemyElsa).GetField("currentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (_currentStateField == null) { Loc.LogError("CRITICAL: Field 'currentState' not found in EnemyElsa!", "КРИТИЧЕСКАЯ ОШИБКА: Поле 'currentState' не найдено в EnemyElsa!"); _initFailed = true; return; } Type fieldType = _currentStateField.FieldType; Loc.LogInfo("Found state field: " + _currentStateField.Name + " (type: " + fieldType.Name + ")", "Найдено поле состояния: " + _currentStateField.Name + " (тип: " + fieldType.Name + ")"); if (!fieldType.IsEnum) { Loc.LogError("CRITICAL: currentState is not an enum! Type: " + fieldType.FullName, "КРИТИЧЕСКАЯ ОШИБКА: currentState не является enum! Тип: " + fieldType.FullName); _initFailed = true; return; } string[] names; if (ModConfig.IsDebug) { Loc.LogDebug("All EnemyElsa.State values:", "Все значения EnemyElsa.State:"); names = Enum.GetNames(fieldType); foreach (string text in names) { int num = (int)Enum.Parse(fieldType, text); Loc.LogDebug($" {text} = {num}", $" {text} = {num}"); } } names = Constants.AggressiveStateNames; foreach (string text2 in names) { try { int num2 = (int)Enum.Parse(fieldType, text2); _aggressiveStates.Add(num2); Loc.LogInfo($"Aggressive state registered: {text2} = {num2}", $"Агрессивное состояние зарегистрировано: {text2} = {num2}"); } catch { Loc.LogWarning("State '" + text2 + "' not found in EnemyElsa.State enum!", "Состояние '" + text2 + "' не найдено в EnemyElsa.State enum!"); } } if (_aggressiveStates.Count == 0) { Loc.LogError("CRITICAL: No aggressive states found! Music will never play.", "КРИТИЧЕСКАЯ ОШИБКА: Агрессивные состояния не найдены! Музыка не будет играть."); _initFailed = true; } else { Loc.LogInfo($"Patch initialized OK. {_aggressiveStates.Count} aggressive states registered.", $"Патч инициализирован. Зарегистрировано {_aggressiveStates.Count} агрессивных состояний."); } } catch (Exception arg) { Loc.LogError($"Patch initialization error: {arg}", $"Ошибка инициализации патча: {arg}"); _initFailed = true; } } [HarmonyPostfix] public static void Postfix(EnemyElsa __instance) { try { if (!_initialized) { Initialize(); } if (_initFailed || !ModConfig.EnableMod.Value || (Object)(object)__instance == (Object)null) { return; } int num = (int)_currentStateField.GetValue(__instance); int instanceID = ((Object)((Component)__instance).gameObject).GetInstanceID(); int value; bool flag = _previousStates.TryGetValue(instanceID, out value); _previousStates[instanceID] = num; if (flag && value == num) { return; } bool flag2 = flag && _aggressiveStates.Contains(value); bool flag3 = _aggressiveStates.Contains(num); if (ModConfig.IsDebug) { string text = (flag ? GetStateName(value) : "none"); string stateName = GetStateName(num); Loc.LogDebug($"Elsa #{instanceID} state: {text}({value}) -> {stateName}({num}) | wasAggro={flag2} isAggro={flag3}", $"Эльза #{instanceID} состояние: {text}({value}) -> {stateName}({num}) | была_агро={flag2} агро={flag3}"); } if (flag3 && !flag2) { Loc.LogDebug($"Elsa #{instanceID} entered aggressive state! Starting music...", $"Эльза #{instanceID} вошла в агрессивное состояние! Запуск музыки..."); ElsaMusicController orAddController = GetOrAddController(((Component)__instance).gameObject); if ((Object)(object)orAddController != (Object)null) { orAddController.StartMusic(); } } else if (!flag3 && flag2) { Loc.LogDebug($"Elsa #{instanceID} left aggressive state. Stopping music...", $"Эльза #{instanceID} вышла из агрессивного состояния. Остановка музыки..."); ElsaMusicController component = ((Component)__instance).gameObject.GetComponent<ElsaMusicController>(); if ((Object)(object)component != (Object)null) { component.StopMusic(); } } } catch (Exception ex) { Loc.LogError("Error in EnemyElsa.Update Postfix: " + ex.Message, "Ошибка в EnemyElsa.Update Postfix: " + ex.Message); } } private static string GetStateName(int stateValue) { try { if (_currentStateField != null) { return Enum.GetName(_currentStateField.FieldType, stateValue) ?? $"Unknown({stateValue})"; } } catch { } return $"Unknown({stateValue})"; } private static ElsaMusicController GetOrAddController(GameObject gameObject) { if ((Object)(object)gameObject == (Object)null) { return null; } ElsaMusicController elsaMusicController = gameObject.GetComponent<ElsaMusicController>(); if ((Object)(object)elsaMusicController == (Object)null) { elsaMusicController = gameObject.AddComponent<ElsaMusicController>(); Loc.LogDebug($"ElsaMusicController added to {((Object)gameObject).name} (ID: {((Object)gameObject).GetInstanceID()})", $"ElsaMusicController добавлен к {((Object)gameObject).name} (ID: {((Object)gameObject).GetInstanceID()})"); } return elsaMusicController; } public static void CleanupInstance(int instanceId) { _previousStates.Remove(instanceId); Loc.LogDebug($"Cleaned up state tracking for instance #{instanceId}", $"Очищено отслеживание состояния для инстанса #{instanceId}"); } } [HarmonyPatch(typeof(EnemyHunter), "Update")] internal static class EnemyHunterUpdatePatch { private static readonly Dictionary<int, int> _previousStates = new Dictionary<int, int>(); private static readonly HashSet<int> _aggressiveStates = new HashSet<int>(); private static FieldInfo _currentStateField; private static bool _initialized; private static bool _initFailed; private static void Initialize() { if (_initialized) { return; } _initialized = true; try { _currentStateField = typeof(EnemyHunter).GetField("currentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (_currentStateField == null) { Loc.LogError("CRITICAL: Field 'currentState' not found in EnemyHunter!", "КРИТИЧЕСКАЯ ОШИБКА: Поле 'currentState' не найдено в EnemyHunter!"); _initFailed = true; return; } Type fieldType = _currentStateField.FieldType; Loc.LogInfo("Found state field for Hunter: " + _currentStateField.Name + " (type: " + fieldType.Name + ")", "Найдено поле состояния для Охотника: " + _currentStateField.Name + " (тип: " + fieldType.Name + ")"); if (!fieldType.IsEnum) { Loc.LogError("CRITICAL: Hunter currentState is not an enum! Type: " + fieldType.FullName, "КРИТИЧЕСКАЯ ОШИБКА: currentState Охотника не является enum! Тип: " + fieldType.FullName); _initFailed = true; return; } string[] names; if (ModConfig.IsDebug) { Loc.LogDebug("All EnemyHunter.State values:", "Все значения EnemyHunter.State:"); names = Enum.GetNames(fieldType); foreach (string text in names) { int num = (int)Enum.Parse(fieldType, text); Loc.LogDebug($" {text} = {num}", $" {text} = {num}"); } } names = Constants.AggressiveHunterStateNames; foreach (string text2 in names) { try { int num2 = (int)Enum.Parse(fieldType, text2); _aggressiveStates.Add(num2); Loc.LogInfo($"Aggressive state registered for Hunter: {text2} = {num2}", $"Агрессивное состояние зарегистрировано для Охотника: {text2} = {num2}"); } catch { Loc.LogWarning("State '" + text2 + "' not found in EnemyHunter.State enum!", "Состояние '" + text2 + "' не найдено в EnemyHunter.State enum!"); } } if (_aggressiveStates.Count == 0) { Loc.LogError("CRITICAL: No aggressive states found for Hunter! Music will never play.", "КРИТИЧЕСКАЯ ОШИБКА: Агрессивные состояния не найдены для Охотника! Музыка не будет играть."); _initFailed = true; } else { Loc.LogInfo($"Hunter Patch initialized OK. {_aggressiveStates.Count} aggressive states registered.", $"Патч Охотника инициализирован. Зарегистрировано {_aggressiveStates.Count} агрессивных состояний."); } } catch (Exception arg) { Loc.LogError($"Hunter Patch initialization error: {arg}", $"Ошибка инициализации патча Охотника: {arg}"); _initFailed = true; } } [HarmonyPostfix] public static void Postfix(EnemyHunter __instance) { try { if (!_initialized) { Initialize(); } if (_initFailed || !ModConfig.EnableMod.Value || (Object)(object)__instance == (Object)null) { return; } int num = (int)_currentStateField.GetValue(__instance); int instanceID = ((Object)((Component)__instance).gameObject).GetInstanceID(); int value; bool flag = _previousStates.TryGetValue(instanceID, out value); _previousStates[instanceID] = num; if (flag && value == num) { return; } bool flag2 = flag && _aggressiveStates.Contains(value); bool flag3 = _aggressiveStates.Contains(num); if (ModConfig.IsDebug) { string text = (flag ? GetStateName(value) : "none"); string stateName = GetStateName(num); Loc.LogDebug($"Hunter #{instanceID} state: {text}({value}) -> {stateName}({num}) | wasAggro={flag2} isAggro={flag3}", $"Охотник #{instanceID} состояние: {text}({value}) -> {stateName}({num}) | была_агро={flag2} агро={flag3}"); } if (flag3 && !flag2) { Loc.LogDebug($"Hunter #{instanceID} entered aggressive state! Playing shoot sound...", $"Охотник #{instanceID} вошел в агрессивное состояние! Запуск звука выстрела..."); HuntsmanMusicController orAddController = GetOrAddController(((Component)__instance).gameObject); if ((Object)(object)orAddController != (Object)null) { orAddController.PlayShoot(); } } } catch (Exception ex) { Loc.LogError("Error in EnemyHunter.Update Postfix: " + ex.Message, "Ошибка в EnemyHunter.Update Postfix: " + ex.Message); } } private static string GetStateName(int stateValue) { try { if (_currentStateField != null) { return Enum.GetName(_currentStateField.FieldType, stateValue) ?? $"Unknown({stateValue})"; } } catch { } return $"Unknown({stateValue})"; } private static HuntsmanMusicController GetOrAddController(GameObject gameObject) { if ((Object)(object)gameObject == (Object)null) { return null; } HuntsmanMusicController huntsmanMusicController = gameObject.GetComponent<HuntsmanMusicController>(); if ((Object)(object)huntsmanMusicController == (Object)null) { huntsmanMusicController = gameObject.AddComponent<HuntsmanMusicController>(); Loc.LogDebug($"HuntsmanMusicController added to {((Object)gameObject).name} (ID: {((Object)gameObject).GetInstanceID()})", $"HuntsmanMusicController добавлен к {((Object)gameObject).name} (ID: {((Object)gameObject).GetInstanceID()})"); } return huntsmanMusicController; } public static void CleanupInstance(int instanceId) { _previousStates.Remove(instanceId); Loc.LogDebug($"Cleaned up state tracking for Hunter instance #{instanceId}", $"Очищено отслеживание состояния для инстанса Охотника #{instanceId}"); } } [HarmonyPatch(typeof(EnemyParent), "Despawn")] internal static class EnemyParentDespawnPatch { [HarmonyPrefix] public static void Prefix(EnemyParent __instance) { try { if ((Object)(object)__instance == (Object)null) { return; } ElsaMusicController componentInChildren = ((Component)__instance).gameObject.GetComponentInChildren<ElsaMusicController>(); if ((Object)(object)componentInChildren != (Object)null) { if (componentInChildren.IsPlaying) { componentInChildren.StopMusic(); Loc.LogInfo("Elsa despawning — music stopped.", "Эльза деспавнится — музыка остановлена."); } EnemyElsaUpdatePatch.CleanupInstance(((Object)((Component)componentInChildren).gameObject).GetInstanceID()); } HuntsmanMusicController componentInChildren2 = ((Component)__instance).gameObject.GetComponentInChildren<HuntsmanMusicController>(); if ((Object)(object)componentInChildren2 != (Object)null) { EnemyHunterUpdatePatch.CleanupInstance(((Object)((Component)componentInChildren2).gameObject).GetInstanceID()); } } catch (Exception ex) { Loc.LogWarning("Error in EnemyParent.Despawn Prefix: " + ex.Message, "Ошибка в EnemyParent.Despawn Prefix: " + ex.Message); } } } } namespace ElsaMusicMod.Config { public static class ModConfig { public static ConfigEntry<bool> EnableMod { get; private set; } public static ConfigEntry<bool> EnableSoundElsa { get; private set; } public static ConfigEntry<bool> EnableSoundHuntsman { get; private set; } public static ConfigEntry<string> SoundPathElsa { get; private set; } public static ConfigEntry<string> SoundPathHuntsman { get; private set; } public static ConfigEntry<float> Volume { get; private set; } public static ConfigEntry<string> AudioMode { get; private set; } public static ConfigEntry<float> SpatialMaxDistance { get; private set; } public static ConfigEntry<bool> DebugMode { get; private set; } public static ConfigEntry<string> Language { get; private set; } public static ConfigEntry<float> FadeDuration { get; private set; } public static ConfigEntry<bool> SpatialMuffle { get; private set; } public static bool IsSpatialMode => AudioMode.Value == "Spatial"; public static bool IsDebug => DebugMode.Value; public static void Init(ConfigFile config) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Expected O, but got Unknown //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Expected O, but got Unknown //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Expected O, but got Unknown //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Expected O, but got Unknown //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Expected O, but got Unknown string text = (((int)Application.systemLanguage == 30) ? "ru" : "en"); EnableMod = config.Bind<bool>("General", "EnableMod", true, "Enable or disable the mod entirely."); Language = config.Bind<string>("General", "Language", text, new ConfigDescription("In-game language: en (English) or ru (Russian).", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "en", "ru" }), Array.Empty<object>())); EnableSoundElsa = config.Bind<bool>("General", "EnableSoundElsa", true, "Enable sound for Elsa."); EnableSoundHuntsman = config.Bind<bool>("General", "EnableSoundHuntsman", true, "Enable sound for Huntsman."); SoundPathElsa = config.Bind<string>("Audio", "SoundPathElsa", "", new ConfigDescription("Absolute path to custom Elsa audio file (.ogg/.mp3). Empty = default track.", (AcceptableValueBase)null, new object[1] { "HideFromREPOConfig" })); SoundPathHuntsman = config.Bind<string>("Audio", "SoundPathHuntsman", "", new ConfigDescription("Absolute path to custom Huntsman audio file (.ogg/.mp3). Empty = default track.", (AcceptableValueBase)null, new object[1] { "HideFromREPOConfig" })); Volume = config.Bind<float>("Audio", "Volume", 0.8f, new ConfigDescription("Playback volume.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); AudioMode = config.Bind<string>("Audio", "AudioMode", "Spatial", new ConfigDescription("Audio mode: Spatial — 3D, Global — 2D.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "Spatial", "Global" }), Array.Empty<object>())); SpatialMaxDistance = config.Bind<float>("Audio", "SpatialMaxDistance", 20f, new ConfigDescription("Max hearing distance in Spatial mode (units).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 200f), Array.Empty<object>())); FadeDuration = config.Bind<float>("Audio", "FadeDuration", 0.5f, new ConfigDescription("Fade in/out duration in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>())); SpatialMuffle = config.Bind<bool>("Audio", "SpatialMuffle", true, "Muffle sound at distance (low-pass filter)."); DebugMode = config.Bind<bool>("Debug", "DebugMode", false, "Enable verbose debug logging to BepInEx console."); } } } namespace ElsaMusicMod.Components { public class ElsaMusicController : MonoBehaviour { [CompilerGenerated] private sealed class <FadeCoroutine>d__13 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ElsaMusicController <>4__this; public float duration; public float targetVol; public bool stopAfterFade; private float <startVol>5__2; private float <elapsed>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FadeCoroutine>d__13(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; ElsaMusicController elsaMusicController = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; if ((Object)(object)elsaMusicController._audioSource == (Object)null) { return false; } <startVol>5__2 = elsaMusicController._audioSource.volume; <elapsed>5__3 = 0f; break; case 1: <>1__state = -1; break; } if (<elapsed>5__3 < duration) { <elapsed>5__3 += Time.deltaTime; float num2 = Mathf.Clamp01(<elapsed>5__3 / duration); num2 = num2 * num2 * (3f - 2f * num2); elsaMusicController._audioSource.volume = Mathf.Lerp(<startVol>5__2, targetVol, num2); <>2__current = null; <>1__state = 1; return true; } elsaMusicController._audioSource.volume = targetVol; elsaMusicController._fadeCoroutine = null; if (stopAfterFade) { elsaMusicController.StopImmediate(); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private AudioSource _audioSource; private AudioLowPassFilter _lowPassFilter; private bool _isPlaying; private int _instanceId; private float _targetVolume; private Coroutine _fadeCoroutine; public bool IsPlaying => _isPlaying; private void Awake() { _instanceId = ((Object)((Component)this).gameObject).GetInstanceID(); } public void StartMusic() { if (_isPlaying || !ModConfig.EnableMod.Value || !ModConfig.EnableSoundElsa.Value) { return; } if ((Object)(object)AudioManager.ElsaClip == (Object)null) { Loc.LogWarning($"Cannot start music: AudioClip not loaded. Elsa #{_instanceId}", $"Не удалось запустить музыку: AudioClip не загружен. Эльза #{_instanceId}"); return; } EnsureAudioSource(); ApplySettings(); _audioSource.clip = AudioManager.ElsaClip; _isPlaying = true; float value = ModConfig.FadeDuration.Value; if (value > 0.01f) { _audioSource.volume = 0f; _audioSource.Play(); StartFade(_targetVolume, value); } else { _audioSource.volume = _targetVolume; _audioSource.Play(); } Loc.LogInfo($">> Music STARTED for Elsa #{_instanceId} (fade: {value:F2}s)", $">> Музыка ЗАПУЩЕНА для Эльзы #{_instanceId} (фейд: {value:F2}с)"); } public void StopMusic() { if (_isPlaying) { float value = ModConfig.FadeDuration.Value; if (value > 0.01f && (Object)(object)_audioSource != (Object)null && _audioSource.isPlaying) { StartFade(0f, value, stopAfterFade: true); } else { StopImmediate(); } Loc.LogInfo($"[] Music STOPPING for Elsa #{_instanceId} (fade: {value:F2}s)", $"[] Музыка ОСТАНАВЛИВАЕТСЯ для Эльзы #{_instanceId} (фейд: {value:F2}с)"); } } private void StopImmediate() { if (_fadeCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_fadeCoroutine); _fadeCoroutine = null; } if ((Object)(object)_audioSource != (Object)null) { _audioSource.Stop(); _audioSource.clip = null; } _isPlaying = false; } private void StartFade(float targetVol, float duration, bool stopAfterFade = false) { if (_fadeCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_fadeCoroutine); } _fadeCoroutine = ((MonoBehaviour)this).StartCoroutine(FadeCoroutine(targetVol, duration, stopAfterFade)); } [IteratorStateMachine(typeof(<FadeCoroutine>d__13))] private IEnumerator FadeCoroutine(float targetVol, float duration, bool stopAfterFade) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FadeCoroutine>d__13(0) { <>4__this = this, targetVol = targetVol, duration = duration, stopAfterFade = stopAfterFade }; } private void Update() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) if (_isPlaying && !((Object)(object)_audioSource == (Object)null) && !((Object)(object)_lowPassFilter == (Object)null) && ModConfig.SpatialMuffle.Value && ModConfig.IsSpatialMode) { AudioListener val = Object.FindObjectOfType<AudioListener>(); if (!((Object)(object)val == (Object)null)) { float num = Vector3.Distance(((Component)this).transform.position, ((Component)val).transform.position); float value = ModConfig.SpatialMaxDistance.Value; float num2 = Mathf.Clamp01(num / value); float num3 = 1f - num2; num3 *= num3; float cutoffFrequency = Mathf.Lerp(400f, 22000f, num3); _lowPassFilter.cutoffFrequency = cutoffFrequency; } } } private void EnsureAudioSource() { if ((Object)(object)_audioSource == (Object)null) { _audioSource = ((Component)this).gameObject.AddComponent<AudioSource>(); Loc.LogDebug($"AudioSource created on Elsa #{_instanceId}", $"AudioSource создан на Эльзе #{_instanceId}"); } if ((Object)(object)_lowPassFilter == (Object)null && ModConfig.SpatialMuffle.Value && ModConfig.IsSpatialMode) { _lowPassFilter = ((Component)this).gameObject.AddComponent<AudioLowPassFilter>(); _lowPassFilter.cutoffFrequency = 22000f; _lowPassFilter.lowpassResonanceQ = 1f; Loc.LogDebug($"AudioLowPassFilter added to Elsa #{_instanceId}", $"AudioLowPassFilter добавлен к Эльзе #{_instanceId}"); } } private void ApplySettings() { if (!((Object)(object)_audioSource == (Object)null)) { _targetVolume = Mathf.Clamp01(ModConfig.Volume.Value); _audioSource.loop = true; _audioSource.playOnAwake = false; _audioSource.dopplerLevel = 0f; if (ModConfig.IsSpatialMode) { _audioSource.spatialBlend = 1f; _audioSource.minDistance = 1f; _audioSource.maxDistance = ModConfig.SpatialMaxDistance.Value; _audioSource.rolloffMode = (AudioRolloffMode)1; _audioSource.spread = 0f; } else { _audioSource.spatialBlend = 0f; } Loc.LogDebug($"AudioSource: vol={_targetVolume}, spatial={_audioSource.spatialBlend}, maxDist={_audioSource.maxDistance}, muffle={ModConfig.SpatialMuffle.Value}", $"AudioSource: громкость={_targetVolume}, 3D={_audioSource.spatialBlend}, макс_дистанция={_audioSource.maxDistance}, приглушение={ModConfig.SpatialMuffle.Value}"); } } private void OnDestroy() { if (_isPlaying) { if ((Object)(object)_audioSource != (Object)null) { _audioSource.Stop(); _audioSource.clip = null; } _isPlaying = false; Loc.LogInfo($"Elsa #{_instanceId} destroyed — music stopped.", $"Эльза #{_instanceId} уничтожена — музыка остановлена."); } } } public class HuntsmanMusicController : MonoBehaviour { private AudioSource _audioSource; private AudioLowPassFilter _lowPassFilter; private int _instanceId; private float _targetVolume; private void Awake() { _instanceId = ((Object)((Component)this).gameObject).GetInstanceID(); } public void PlayShoot() { if (ModConfig.EnableMod.Value && ModConfig.EnableSoundHuntsman.Value) { if ((Object)(object)AudioManager.HuntsmanClip == (Object)null) { Loc.LogWarning($"Cannot play sound: AudioClip not loaded. Huntsman #{_instanceId}", $"Не удалось запустить звук: AudioClip не загружен. Охотник #{_instanceId}"); return; } EnsureAudioSource(); ApplySettings(); _audioSource.volume = _targetVolume; _audioSource.PlayOneShot(AudioManager.HuntsmanClip); Loc.LogInfo($">> Sound PLAYED for Huntsman #{_instanceId}", $">> Звук ВОСПРОИЗВЕДЕН для Охотника #{_instanceId}"); } } private void Update() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_audioSource == (Object)null) && _audioSource.isPlaying && !((Object)(object)_lowPassFilter == (Object)null) && ModConfig.SpatialMuffle.Value && ModConfig.IsSpatialMode) { AudioListener val = Object.FindObjectOfType<AudioListener>(); if (!((Object)(object)val == (Object)null)) { float num = Vector3.Distance(((Component)this).transform.position, ((Component)val).transform.position); float value = ModConfig.SpatialMaxDistance.Value; float num2 = Mathf.Clamp01(num / value); float num3 = 1f - num2; num3 *= num3; float cutoffFrequency = Mathf.Lerp(400f, 22000f, num3); _lowPassFilter.cutoffFrequency = cutoffFrequency; } } } private void EnsureAudioSource() { if ((Object)(object)_audioSource == (Object)null) { _audioSource = ((Component)this).gameObject.AddComponent<AudioSource>(); Loc.LogDebug($"AudioSource created on Huntsman #{_instanceId}", $"AudioSource создан на Охотнике #{_instanceId}"); } if ((Object)(object)_lowPassFilter == (Object)null && ModConfig.SpatialMuffle.Value && ModConfig.IsSpatialMode) { _lowPassFilter = ((Component)this).gameObject.AddComponent<AudioLowPassFilter>(); _lowPassFilter.cutoffFrequency = 22000f; _lowPassFilter.lowpassResonanceQ = 1f; Loc.LogDebug($"AudioLowPassFilter added to Huntsman #{_instanceId}", $"AudioLowPassFilter добавлен к Охотнику #{_instanceId}"); } } private void ApplySettings() { if (!((Object)(object)_audioSource == (Object)null)) { _targetVolume = Mathf.Clamp01(ModConfig.Volume.Value); _audioSource.loop = false; _audioSource.playOnAwake = false; _audioSource.dopplerLevel = 0f; if (ModConfig.IsSpatialMode) { _audioSource.spatialBlend = 1f; _audioSource.minDistance = 1f; _audioSource.maxDistance = ModConfig.SpatialMaxDistance.Value; _audioSource.rolloffMode = (AudioRolloffMode)1; _audioSource.spread = 0f; } else { _audioSource.spatialBlend = 0f; } } } } } namespace ElsaMusicMod.Audio { public static class AudioManager { [CompilerGenerated] private sealed class <LoadAudioCoroutine>d__18 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public bool isElsa; public string customPath; private string <logPrefixName>5__2; private string <defaultFileName>5__3; private string <defaultPath>5__4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadAudioCoroutine>d__18(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <logPrefixName>5__2 = null; <defaultFileName>5__3 = null; <defaultPath>5__4 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <logPrefixName>5__2 = (isElsa ? "Elsa" : "Huntsman"); <defaultFileName>5__3 = (isElsa ? "Sounds/elsa_theme.ogg" : "Sounds/huntsman_shoot.ogg"); if (!string.IsNullOrEmpty(customPath)) { Loc.LogInfo("Attempting to load custom sound for " + <logPrefixName>5__2 + ": " + customPath, "Попытка загрузки кастомного звука для " + <logPrefixName>5__2 + ": " + customPath); if (File.Exists(customPath)) { <>2__current = LoadClipFromFile(customPath, isElsa); <>1__state = 1; return true; } Loc.LogWarning("Custom sound not found: " + customPath + ". Falling back to default.", "Кастомный звук не найден: " + customPath + ". Возврат к стандартному."); } goto IL_01b5; case 1: <>1__state = -1; if ((isElsa && (Object)(object)ElsaClip != (Object)null) || (!isElsa && (Object)(object)HuntsmanClip != (Object)null)) { Loc.LogInfo("Custom sound loaded successfully for " + <logPrefixName>5__2 + ": " + customPath, "Кастомный звук успешно загружен для " + <logPrefixName>5__2 + ": " + customPath); if (isElsa) { IsElsaLoaded = true; } else { IsHuntsmanLoaded = true; } return false; } Loc.LogWarning("Failed to load custom sound (corrupted?): " + customPath + ". Falling back to default.", "Не удалось загрузить кастомный звук (поврежден?): " + customPath + ". Возврат к стандартному."); goto IL_01b5; case 2: { <>1__state = -1; AudioClip val = (isElsa ? ElsaClip : HuntsmanClip); if ((Object)(object)val != (Object)null) { Loc.LogInfo($"Default sound loaded successfully for {<logPrefixName>5__2}. Duration: {val.length:F1}s", $"Стандартный звук успешно загружен для {<logPrefixName>5__2}. Длительность: {val.length:F1}с"); if (isElsa) { IsElsaLoaded = true; } else { IsHuntsmanLoaded = true; } } else { Loc.LogError("Failed to load default sound: " + <defaultPath>5__4, "Не удалось загрузить стандартный звук: " + <defaultPath>5__4); } break; } IL_01b5: <defaultPath>5__4 = Path.Combine(_pluginFolderPath, <defaultFileName>5__3); Loc.LogInfo("Loading default sound for " + <logPrefixName>5__2 + ": " + <defaultPath>5__4, "Загрузка стандартного звука для " + <logPrefixName>5__2 + ": " + <defaultPath>5__4); if (File.Exists(<defaultPath>5__4)) { <>2__current = LoadClipFromFile(<defaultPath>5__4, isElsa); <>1__state = 2; return true; } Loc.LogError("Default sound file not found: " + <defaultPath>5__4 + ". Place " + <defaultFileName>5__3 + " in plugin folder.", "Файл стандартного звука не найден: " + <defaultPath>5__4 + ". Поместите " + <defaultFileName>5__3 + " в папку плагина."); break; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <LoadClipFromFile>d__19 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string filePath; public bool isElsa; private UnityWebRequest <www>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadClipFromFile>d__19(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <www>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Invalid comparison between Unknown and I4 //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Invalid comparison between Unknown and I4 //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Invalid comparison between Unknown and I4 //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Invalid comparison between Unknown and I4 //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) try { switch (<>1__state) { default: return false; case 0: { <>1__state = -1; AudioType audioType = GetAudioType(filePath); if ((int)audioType == 0) { Loc.LogWarning("Unsupported audio format: " + filePath + ". Supported: .ogg, .mp3, .wav", "Неподдерживаемый формат аудио: " + filePath + ". Поддерживаются: .ogg, .mp3, .wav"); return false; } string text = "file:///" + filePath.Replace('\\', '/'); Loc.LogDebug($"Loading audio from URI: {text} (type: {audioType})", $"Загрузка аудио по URI: {text} (тип: {audioType})"); <www>5__2 = UnityWebRequestMultimedia.GetAudioClip(text, audioType); <>1__state = -3; ((DownloadHandlerAudioClip)<www>5__2.downloadHandler).streamAudio = false; <>2__current = <www>5__2.SendWebRequest(); <>1__state = 1; return true; } case 1: <>1__state = -3; if ((int)<www>5__2.result == 2 || (int)<www>5__2.result == 3 || (int)<www>5__2.result == 4) { Loc.LogWarning("Audio load error: " + <www>5__2.error + " (" + filePath + ")", "Ошибка загрузки аудио: " + <www>5__2.error + " (" + filePath + ")"); if (isElsa) { ElsaClip = null; } else { HuntsmanClip = null; } } else { try { AudioClip content = DownloadHandlerAudioClip.GetContent(<www>5__2); if ((Object)(object)content != (Object)null && (int)content.loadState == 2) { ((Object)content).name = Path.GetFileNameWithoutExtension(filePath); if (isElsa) { ElsaClip = content; } else { HuntsmanClip = content; } Loc.LogDebug($"AudioClip OK: name={((Object)content).name}, duration={content.length:F1}s, channels={content.channels}, freq={content.frequency}Hz", $"AudioClip ОК: имя={((Object)content).name}, длина={content.length:F1}с, каналы={content.channels}, част={content.frequency}Гц"); } else { Loc.LogWarning($"AudioClip loaded but invalid: {filePath} (loadState: {((content != null) ? new AudioDataLoadState?(content.loadState) : null)})", $"AudioClip загружен, но недействителен: {filePath} (статус: {((content != null) ? new AudioDataLoadState?(content.loadState) : null)})"); if (isElsa) { ElsaClip = null; } else { HuntsmanClip = null; } } } catch (Exception ex) { Loc.LogError("Exception processing audio: " + ex.Message, "Исключение при обработке аудио: " + ex.Message); if (isElsa) { ElsaClip = null; } else { HuntsmanClip = null; } } } <>m__Finally1(); <www>5__2 = null; return false; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<www>5__2 != null) { ((IDisposable)<www>5__2).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static string _pluginFolderPath; public static AudioClip ElsaClip { get; private set; } public static AudioClip HuntsmanClip { get; private set; } public static bool IsElsaLoaded { get; private set; } public static bool IsHuntsmanLoaded { get; private set; } public static void Initialize(string pluginFolderPath) { _pluginFolderPath = pluginFolderPath; IsElsaLoaded = false; IsHuntsmanLoaded = false; ElsaClip = null; HuntsmanClip = null; } [IteratorStateMachine(typeof(<LoadAudioCoroutine>d__18))] public static IEnumerator LoadAudioCoroutine(string customPath, bool isElsa) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LoadAudioCoroutine>d__18(0) { customPath = customPath, isElsa = isElsa }; } [IteratorStateMachine(typeof(<LoadClipFromFile>d__19))] private static IEnumerator LoadClipFromFile(string filePath, bool isElsa) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LoadClipFromFile>d__19(0) { filePath = filePath, isElsa = isElsa }; } private static AudioType GetAudioType(string filePath) { return (AudioType)(Path.GetExtension(filePath).ToLowerInvariant() switch { ".ogg" => 14, ".mp3" => 13, ".wav" => 20, _ => 0, }); } } }