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 FenchikMemeSounds v3.1.11
FenchikMemeSounds.dll
Decompiled 10 months agousing 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 BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using MenuLib; using MenuLib.MonoBehaviors; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using TMPro; using UnityEngine; using UnityEngine.Networking; [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.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("FenchikMemeSounds")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("FenchikMemeSounds")] [assembly: AssemblyTitle("FenchikMemeSounds")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } [BepInPlugin("fenchik.memesounds", "Fenchik Meme Sounds", "3.5.0")] public class FenchikMemeSounds : BaseUnityPlugin { private enum AllAudioToggle { Enable, Disable } [HarmonyPatch(typeof(AudioSource), "PlayOneShot", new Type[] { typeof(AudioClip) })] private class Patch_PlayOneShot { private static bool Prefix(AudioSource __instance, AudioClip clip) { if ((Object)(object)__instance == (Object)null || (Object)(object)clip == (Object)null) { return true; } if (clipCache.ContainsKey(((Object)clip).name)) { return true; } if (lastCheckedFrame.TryGetValue(__instance, out var value) && value == Time.frameCount) { return true; } lastCheckedFrame[__instance] = Time.frameCount; if ((Object)(object)__instance == (Object)null || !((Behaviour)__instance).isActiveAndEnabled) { lastCheckedFrame.Remove(__instance); } if (TryReplace(__instance, ((Object)clip).name, out var newClip, out var volume, out var enabled) && enabled) { __instance.Stop(); __instance.time = 0f; __instance.timeSamples = 0; __instance.PlayOneShot(newClip, Mathf.Clamp01(volume)); if (!replacedSources.Contains(__instance)) { replacedSources.Add(__instance); } return false; } return true; } } [HarmonyPatch(typeof(AudioSource), "Stop", new Type[] { })] private class Patch_AudioSource_Stop { private static void Prefix(AudioSource __instance) { if (!((Object)(object)__instance == (Object)null) && __instance.isPlaying && !((Object)(object)__instance.clip == (Object)null) && __instance.loop && !(__instance.time < 0.2f) && !(__instance.time >= __instance.clip.length - 0.2f)) { savedPositions[__instance] = __instance.time; } } } [HarmonyPatch(typeof(AudioSource), "Play", new Type[] { })] private class Patch_AudioSource_Play { private static void Prefix(AudioSource __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.clip == (Object)null || clipCache.ContainsKey(((Object)__instance.clip).name) || (lastCheckedFrame.TryGetValue(__instance, out var value) && value == Time.frameCount)) { return; } lastCheckedFrame[__instance] = Time.frameCount; if ((Object)(object)__instance == (Object)null || !((Behaviour)__instance).isActiveAndEnabled) { lastCheckedFrame.Remove(__instance); } if (TryReplace(__instance, ((Object)__instance.clip).name, out var newClip, out var volume, out var enabled) && enabled) { if ((Object)(object)__instance.clip != (Object)(object)newClip) { __instance.clip = newClip; } __instance.volume = Mathf.Clamp01(volume); if (!replacedSources.Contains(__instance)) { replacedSources.Add(__instance); } } } } [HarmonyPatch(typeof(Sound), "PlayLoop")] private class Patch_SoundPlayLoop { private static void Postfix(Sound __instance) { if ((Object)(object)__instance?.Source == (Object)null || __instance.Sounds == null || __instance.Sounds.Length == 0) { return; } AudioClip obj = __instance.Sounds[0]; string text = ((obj != null) ? ((Object)obj).name : null); if (!string.IsNullOrEmpty(text) && TryReplace(__instance.Source, text, out var newClip, out var volume, out var enabled) && enabled) { __instance.Sounds[0] = newClip; __instance.Source.clip = newClip; __instance.Source.volume = volume; if (!replacedSources.Contains(__instance.Source)) { replacedSources.Add(__instance.Source); } } } } private class ReplacementContainer { public List<Replacement> replacements = new List<Replacement>(); } private class Replacement { public string category; public List<string> matches = new List<string>(); public List<SoundEntry> sounds = new List<SoundEntry>(); } private class SoundEntry { public string sound; public string category; public string displayName; public float weight = 1f; public bool loop = false; } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static Func<AudioSource, bool> <>9__2_0; public static Func<AudioSource, bool> <>9__3_0; public static Func<KeyValuePair<ConfigDefinition, ConfigEntryBase>, string> <>9__16_0; public static Func<string, bool> <>9__16_1; public static Func<string, string> <>9__16_2; public static ScrollViewBuilderDelegate <>9__24_0; public static Func<KeyValuePair<ConfigDefinition, ConfigEntryBase>, bool> <>9__24_10; public static Func<KeyValuePair<ConfigDefinition, ConfigEntryBase>, bool> <>9__24_11; public static ScrollViewBuilderDelegate <>9__24_5; public static Func<KeyValuePair<ConfigDefinition, ConfigEntryBase>, string> <>9__25_0; public static Func<string, bool> <>9__25_1; public static Predicate<AudioSource> <>9__28_0; public static Func<AudioSource, bool> <>9__52_0; internal bool <Update>b__2_0(AudioSource a) { return (Object)(object)a != (Object)null && a.isPlaying; } internal bool <CleanDeadAudioSources>b__3_0(AudioSource src) { return (Object)(object)src != (Object)null && (Object)(object)((Component)src).gameObject != (Object)null; } internal string <CreateCategoryNavigation>b__16_0(KeyValuePair<ConfigDefinition, ConfigEntryBase> kvp) { return kvp.Key.Section; } internal bool <CreateCategoryNavigation>b__16_1(string section) { return !section.StartsWith("__"); } internal string <CreateCategoryNavigation>b__16_2(string s) { return s; } internal RectTransform <OpenCategoryPage>b__24_0(Transform scroll) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) REPOLabel val = MenuAPI.CreateREPOLabel("Volume Presets:", scroll, new Vector2(0f, 10f)); return ((REPOElement)val).rectTransform; } internal bool <OpenCategoryPage>b__24_10(KeyValuePair<ConfigDefinition, ConfigEntryBase> kvp) { ConfigEntry<bool> val = kvp.Value as ConfigEntry<bool>; return val != null; } internal bool <OpenCategoryPage>b__24_11(KeyValuePair<ConfigDefinition, ConfigEntryBase> kvp) { return ((ConfigEntry<bool>)(object)kvp.Value).Value; } internal RectTransform <OpenCategoryPage>b__24_5(Transform scroll) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) REPOLabel val = MenuAPI.CreateREPOLabel("Sounds of category", scroll, new Vector2(0f, 30f)); return ((REPOElement)val).rectTransform; } internal string <GetAllCategories>b__25_0(KeyValuePair<ConfigDefinition, ConfigEntryBase> kvp) { return kvp.Key.Section; } internal bool <GetAllCategories>b__25_1(string section) { return !section.StartsWith("__"); } internal bool <UpdateVolumes>b__28_0(AudioSource src) { return (Object)(object)src == (Object)null || (Object)(object)src.clip == (Object)null; } internal bool <CleanupSavedPositions>b__52_0(AudioSource src) { return (Object)(object)src == (Object)null || (Object)(object)((Component)src).gameObject == (Object)null; } } private static float processedClipsCleanupTimer = 0f; private static readonly HashSet<string> noReplacementCache = new HashSet<string>(); private REPOPopupPage _mainSettingsPage; private Dictionary<string, REPOPopupPage> _categoryPages = new Dictionary<string, REPOPopupPage>(); private REPOPopupPage _currentRightPage = null; private string _currentCategory = null; private static ManualLogSource log; private static ConfigFile config; private static AudioSource globalSource; private static readonly Dictionary<AudioSource, float> savedPositions = new Dictionary<AudioSource, float>(); private static readonly Dictionary<AudioSource, string> lastCheckedClips = new Dictionary<AudioSource, string>(); private static readonly Dictionary<AudioSource, int> lastCheckedFrame = new Dictionary<AudioSource, int>(); private static readonly Dictionary<AudioSource, string> audioSourceCache = new Dictionary<AudioSource, string>(); private static readonly Dictionary<string, List<SoundEntry>> replacementMap = new Dictionary<string, List<SoundEntry>>(); private static readonly Dictionary<string, bool> processedResultCache = new Dictionary<string, bool>(); private static readonly Dictionary<string, (ConfigEntry<bool>, ConfigEntry<float>)> configEntryCache = new Dictionary<string, (ConfigEntry<bool>, ConfigEntry<float>)>(); private static readonly Dictionary<string, AudioClip> clipCache = new Dictionary<string, AudioClip>(); private static readonly Dictionary<string, (AudioClip, float, bool)> tryReplaceCache = new Dictionary<string, (AudioClip, float, bool)>(); private static readonly Dictionary<string, (bool, float)> configCache = new Dictionary<string, (bool, float)>(); private static readonly Dictionary<string, SoundEntry> directMatchCache = new Dictionary<string, SoundEntry>(); private static readonly Dictionary<string, (AudioClip clip, float volume, bool enabled)> processedClips = new Dictionary<string, (AudioClip, float, bool)>(); private static readonly List<AudioSource> replacedSources = new List<AudioSource>(); private static readonly Queue<AudioSource> audioPool = new Queue<AudioSource>(); private const int PoolInitialSize = 20; private const int PoolMaxSize = 50; private float poolCleanupTimer = 0f; public static FenchikMemeSounds Instance { get; private set; } private void Awake() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown //IL_00dc: Unknown result type (might be due to invalid IL or missing references) Instance = this; MenuAPI.AddElementToMainMenu((BuilderDelegate)delegate(Transform parent) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) REPOButton val2 = MenuAPI.CreateREPOButton("♪ Sound replacers", (Action)delegate { CreateCategoryNavigation(); }, parent, new Vector2(550f, 0f)); TextMeshProUGUI labelTMP2 = val2.labelTMP; if ((Object)(object)labelTMP2 != (Object)null) { ((TMP_Text)labelTMP2).enableVertexGradient = true; ((TMP_Text)labelTMP2).colorGradient = new VertexGradient(Color32.op_Implicit(new Color32((byte)210, (byte)166, (byte)121, byte.MaxValue)), Color32.op_Implicit(new Color32((byte)210, (byte)166, (byte)121, byte.MaxValue)), Color32.op_Implicit(new Color32((byte)90, (byte)56, (byte)37, byte.MaxValue)), Color32.op_Implicit(new Color32((byte)90, (byte)56, (byte)37, byte.MaxValue))); } }); MenuAPI.AddElementToEscapeMenu((BuilderDelegate)delegate(Transform parent) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) REPOButton val = MenuAPI.CreateREPOButton("Sound Replacers", (Action)delegate { CreateCategoryNavigation(); }, parent, new Vector2(126f, 61f)); TextMeshProUGUI labelTMP = val.labelTMP; if ((Object)(object)labelTMP != (Object)null) { ((TMP_Text)labelTMP).enableVertexGradient = true; ((TMP_Text)labelTMP).colorGradient = new VertexGradient(Color32.op_Implicit(new Color32((byte)210, (byte)166, (byte)121, byte.MaxValue)), Color32.op_Implicit(new Color32((byte)210, (byte)166, (byte)121, byte.MaxValue)), Color32.op_Implicit(new Color32((byte)90, (byte)56, (byte)37, byte.MaxValue)), Color32.op_Implicit(new Color32((byte)90, (byte)56, (byte)37, byte.MaxValue))); } }); poolCleanupTimer += Time.deltaTime; if (poolCleanupTimer > 5f) { CleanDeadAudioSources(); CleanupSavedPositions(); poolCleanupTimer = 0f; } log = ((BaseUnityPlugin)this).Logger; config = new ConfigFile(Path.Combine(Paths.ConfigPath, "FenchikMemeSound.cfg"), true); log.LogInfo((object)"\ud83d\udd27 FenchikMemeSounds инициализируется..."); LoadReplacements(); InitAudioPool(); globalSource = ((Component)this).gameObject.AddComponent<AudioSource>(); globalSource.spatialBlend = 0f; globalSource.playOnAwake = false; new Harmony("fenchik.memesounds").PatchAll(); } private void Update() { if ((Input.GetKeyDown((KeyCode)27) || Input.GetKeyDown((KeyCode)8)) && ((Object)(object)_mainSettingsPage != (Object)null || (Object)(object)_currentRightPage != (Object)null)) { CloseAllMenuPages(); } if ((Object)(object)_mainSettingsPage == (Object)null && (Object)(object)_currentRightPage == (Object)null && !Cursor.visible) { Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; log.LogWarning((object)"\ud83e\uddef Курсор вернули автоматически (меню закрыты)"); } poolCleanupTimer += Time.deltaTime; if (poolCleanupTimer > 5f) { CleanDeadAudioSources(); CleanupSavedPositions(); poolCleanupTimer = 0f; } if (Time.frameCount % 60 == 0) { int num = audioPool.Count((AudioSource a) => (Object)(object)a != (Object)null && a.isPlaying); log.LogInfo((object)$"\ud83d\udd0a Активных AudioSource: {num}/{audioPool.Count}"); } processedClipsCleanupTimer += Time.deltaTime; if (processedClipsCleanupTimer > 300f) { processedClips.Clear(); processedClipsCleanupTimer = 0f; } if (Time.frameCount % 300 == 0) { lastCheckedFrame.Clear(); } } private void CleanDeadAudioSources() { int count = audioPool.Count; List<AudioSource> list = audioPool.Where((AudioSource src) => (Object)(object)src != (Object)null && (Object)(object)((Component)src).gameObject != (Object)null).ToList(); audioPool.Clear(); foreach (AudioSource item in list) { audioPool.Enqueue(item); } log.LogInfo((object)$"\ud83e\uddf9 Очищено {count - list.Count} мёртвых источников"); } public static void ReloadConfigAndClearCache() { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Expected O, but got Unknown config.Reload(); tryReplaceCache.Clear(); configCache.Clear(); processedClips.Clear(); foreach (KeyValuePair<string, List<SoundEntry>> item in replacementMap) { foreach (SoundEntry item2 in item.Value) { string text = item2.category ?? "Default"; string text2 = item2.displayName ?? Path.GetFileNameWithoutExtension(item2.sound); string key = text + "::" + text2; ConfigEntry<bool> val = config.Bind<bool>(text, text2, true, "Включить звук"); ConfigEntry<float> val2 = config.Bind<float>(text, text2 + "_volume", 1f, new ConfigDescription("Громкость от 0.0 до 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); configCache[key] = (val.Value, val2.Value); } } log.LogInfo((object)"\ud83d\udd01 Конфиг перезагружен и ConfigEntry пересозданы"); UpdateVolumes(); } public static bool TryReplace(AudioSource source, string clipName, out AudioClip newClip, out float volume, out bool enabled) { newClip = null; volume = 1f; enabled = true; if (string.IsNullOrEmpty(clipName)) { return false; } if (noReplacementCache.Contains(clipName)) { return false; } if (!processedClips.TryGetValue(clipName, out (AudioClip, float, bool) value)) { string key = clipName.ToLowerInvariant(); if (directMatchCache.TryGetValue(key, out var value2)) { newClip = GetClip(value2.sound); bool result = ValidateConfig(value2, clipName, newClip, out volume, out enabled); processedClips[clipName] = (newClip, volume, enabled); return result; } foreach (KeyValuePair<string, List<SoundEntry>> item in replacementMap) { if (clipName.IndexOf(item.Key, StringComparison.OrdinalIgnoreCase) < 0) { continue; } List<SoundEntry> value3 = item.Value; SoundEntry soundEntry = PickWeighted(value3); if (soundEntry == null) { break; } newClip = GetClip(soundEntry.sound); bool result2 = ValidateConfig(soundEntry, clipName, newClip, out volume, out enabled); if (value3.Count == 1) { processedClips[clipName] = (newClip, volume, enabled); } return result2; } noReplacementCache.Add(clipName); return false; } (newClip, volume, enabled) = value; return enabled && (Object)(object)newClip != (Object)null; } private static bool ValidateConfig(SoundEntry entry, string cacheKey, AudioClip clip, out float volume, out bool enabled) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown volume = 1f; enabled = true; string key = entry.category + "::" + entry.displayName; if (!configEntryCache.TryGetValue(key, out var value)) { ConfigEntry<bool> item = config.Bind<bool>(entry.category, entry.displayName, true, "Включить звук"); ConfigEntry<float> item2 = config.Bind<float>(entry.category, entry.displayName + "_volume", 1f, new ConfigDescription("Громкость от 0.0 до 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); value = (item, item2); configEntryCache[key] = value; } enabled = value.Item1.Value; volume = value.Item2.Value; if (!enabled || (Object)(object)clip == (Object)null) { return false; } tryReplaceCache[cacheKey] = (clip, volume, enabled); return true; } private static void InitAudioPool() { for (int i = 0; i < 20; i++) { AudioSource item = CreateAudioSource($"PooledAudioSource_{i}"); audioPool.Enqueue(item); } log.LogInfo((object)$"\ud83d\udd04 Инициализирован пул аудио: {audioPool.Count} источников"); } private static AudioSource CreateAudioSource(string name) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown GameObject val = new GameObject(name); Object.DontDestroyOnLoad((Object)(object)val); AudioSource val2 = val.AddComponent<AudioSource>(); val2.playOnAwake = false; val2.spatialBlend = 0f; return val2; } public static void PlayPooledSound(AudioClip clip, float volume = 1f, bool loop = false) { if ((Object)(object)clip == (Object)null) { return; } AudioSource val = null; foreach (AudioSource item in audioPool) { if (!item.isPlaying) { val = item; break; } } if ((Object)(object)val == (Object)null) { if (audioPool.Count >= 50) { return; } val = CreateAudioSource("PooledAudioSource_Dynamic"); audioPool.Enqueue(val); } val.loop = loop; val.clip = clip; val.volume = Mathf.Clamp01(volume); val.time = 0f; val.timeSamples = 0; val.Play(); } private static AudioClip LoadClipSync(string path) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Invalid comparison between Unknown and I4 string text = "file:///" + path.Replace("\\", "/"); AudioType val = (AudioType)(path.EndsWith(".mp3") ? 13 : (path.EndsWith(".wav") ? 20 : 14)); UnityWebRequest audioClip = UnityWebRequestMultimedia.GetAudioClip(text, val); try { UnityWebRequestAsyncOperation val2 = audioClip.SendWebRequest(); while (!((AsyncOperation)val2).isDone) { } if ((int)audioClip.result != 1) { log.LogWarning((object)("Не удалось загрузить звук: " + path)); return null; } AudioClip content = DownloadHandlerAudioClip.GetContent(audioClip); ((Object)content).name = Path.GetFileName(path); return content; } finally { ((IDisposable)audioClip)?.Dispose(); } } private static AudioClip GetClip(string filename) { if (clipCache.TryGetValue(filename, out var value)) { return value; } string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "sounds", filename); if (!File.Exists(text)) { log.LogWarning((object)("❌ Звук не найден: " + text)); return null; } AudioClip val = LoadClipSync(text); if ((Object)(object)val != (Object)null) { clipCache[filename] = val; } return val; } private static SoundEntry PickWeighted(List<SoundEntry> entries) { if (entries == null || entries.Count == 0) { return null; } if (entries.Count == 1) { return entries[0]; } float num = 0f; foreach (SoundEntry entry in entries) { num += ((entry.weight > 0f) ? entry.weight : 1f); } float num2 = Random.Range(0f, num); float num3 = 0f; foreach (SoundEntry entry2 in entries) { num3 += ((entry2.weight > 0f) ? entry2.weight : 1f); if (num2 <= num3) { return entry2; } } return entries[entries.Count - 1]; } private void CreateCategoryNavigation() { //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Expected O, but got Unknown List<string> list = (from s in (from kvp in (IEnumerable<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)config select kvp.Key.Section into section where !section.StartsWith("__") select section).Distinct() orderby s select s).ToList(); _mainSettingsPage = MenuAPI.CreateREPOPopupPage("Fenchik Meme Sounds", true, true, 1.5f, (Vector2?)new Vector2(-300f, 10f)); _mainSettingsPage.OpenPage(false); foreach (string category in list) { _mainSettingsPage.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scroll) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) REPOButton val = MenuAPI.CreateREPOButton("♫ " + category, (Action)delegate { OpenCategoryPage(category); }, scroll, Vector2.zero); return ((REPOElement)val).rectTransform; }, 0f, 0f); } } private void CloseAllMenuPages() { _currentCategory = null; Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; log.LogInfo((object)"\ud83d\udd1a Меню полностью закрыто, курсор восстановлен"); } private void OpenCategoryPage(string category) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Expected O, but got Unknown //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Expected O, but got Unknown //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Expected O, but got Unknown //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Expected O, but got Unknown //IL_00b1: 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_00bc: Expected O, but got Unknown //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Expected O, but got Unknown //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Expected O, but got Unknown //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Expected O, but got Unknown config.Reload(); if ((Object)(object)_currentRightPage != (Object)null) { _currentRightPage.ClosePage(true); Object.Destroy((Object)(object)((Component)_currentRightPage).gameObject); _currentRightPage = null; } _currentCategory = category; REPOPopupPage val = MenuAPI.CreateREPOPopupPage("Settings: " + category, true, false, 1.5f, (Vector2?)new Vector2(70f, 10f)); val.OpenPage(true); _currentRightPage = val; object obj = <>c.<>9__24_0; if (obj == null) { ScrollViewBuilderDelegate val2 = delegate(Transform scroll) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) REPOLabel val13 = MenuAPI.CreateREPOLabel("Volume Presets:", scroll, new Vector2(0f, 10f)); return ((REPOElement)val13).rectTransform; }; <>c.<>9__24_0 = val2; obj = (object)val2; } val.AddElementToScrollView((ScrollViewBuilderDelegate)obj, 0f, 0f); val.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scroll) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) REPOButton val12 = MenuAPI.CreateREPOButton("■ Volume 1.0", (Action)delegate { ApplyVolumePreset(category, 1f); }, scroll, new Vector2(0f, 10f)); return ((REPOElement)val12).rectTransform; }, 0f, 0f); val.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scroll) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) REPOButton val11 = MenuAPI.CreateREPOButton("● Volume 0.5", (Action)delegate { ApplyVolumePreset(category, 0.5f); }, scroll, new Vector2(0f, 10f)); return ((REPOElement)val11).rectTransform; }, 0f, 0f); val.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scroll) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) REPOButton val10 = MenuAPI.CreateREPOButton("◦ Volume 0.1", (Action)delegate { ApplyVolumePreset(category, 0.1f); }, scroll, new Vector2(0f, 10f)); return ((REPOElement)val10).rectTransform; }, 0f, 0f); _categoryPages[category] = val; val.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scroll) { //IL_00c6: Unknown result type (might be due to invalid IL or missing references) string text = (((IEnumerable<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)config).Where((KeyValuePair<ConfigDefinition, ConfigEntryBase> kvp) => kvp.Key.Section == category && !kvp.Key.Key.StartsWith("__") && !kvp.Key.Key.EndsWith("_volume")).Where(delegate(KeyValuePair<ConfigDefinition, ConfigEntryBase> kvp) { ConfigEntry<bool> val9 = kvp.Value as ConfigEntry<bool>; return val9 != null; }).All((KeyValuePair<ConfigDefinition, ConfigEntryBase> kvp) => ((ConfigEntry<bool>)(object)kvp.Value).Value) ? "Enable" : "Disable"); REPOSlider val7 = MenuAPI.CreateREPOSlider("Category", "Enable/Disable all", (Action<string>)delegate(string choice) { bool value2 = choice == "Enable"; foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in config) { if (!(item.Key.Section != category) && !item.Key.Key.StartsWith("__") && !item.Key.Key.EndsWith("_volume") && item.Value is ConfigEntry<bool> val8) { val8.Value = value2; } } config.Save(); UpdateVolumes(); }, scroll, new string[2] { "Enable", "Disable" }, text, Vector2.zero, "", "", (BarBehavior)0); return ((REPOElement)val7).rectTransform; }, 0f, 0f); object obj2 = <>c.<>9__24_5; if (obj2 == null) { ScrollViewBuilderDelegate val3 = delegate(Transform scroll) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) REPOLabel val6 = MenuAPI.CreateREPOLabel("Sounds of category", scroll, new Vector2(0f, 30f)); return ((REPOElement)val6).rectTransform; }; <>c.<>9__24_5 = val3; obj2 = (object)val3; } val.AddElementToScrollView((ScrollViewBuilderDelegate)obj2, 0f, 0f); foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item2 in config) { if (item2.Key.Section != category) { continue; } string key = item2.Key.Key; ConfigEntryBase value = item2.Value; ConfigEntry<bool> boolEntry = value as ConfigEntry<bool>; if (boolEntry != null && !key.EndsWith("_volume") && !key.StartsWith("__")) { val.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scroll) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) REPOToggle val5 = MenuAPI.CreateREPOToggle(key, (Action<bool>)delegate(bool b) { boolEntry.Value = b; config.Save(); }, scroll, Vector2.zero, "On", "Off", boolEntry.Value); return ((REPOElement)val5).rectTransform; }, 0f, 0f); continue; } value = item2.Value; ConfigEntry<float> floatEntry = value as ConfigEntry<float>; if (floatEntry == null || !key.EndsWith("_volume")) { continue; } val.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scroll) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) REPOSlider val4 = MenuAPI.CreateREPOSlider(key, "Volume", (Action<float>)delegate(float f) { floatEntry.Value = f; config.Save(); }, scroll, Vector2.zero, 0f, 1f, 2, floatEntry.Value, "", "", (BarBehavior)0); return ((REPOElement)val4).rectTransform; }, 0f, 0f); } } private List<string> GetAllCategories() { return (from kvp in (IEnumerable<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)config select kvp.Key.Section into section where !section.StartsWith("__") select section).Distinct().ToList(); } private static void ApplyVolumePreset(string category, float volume) { foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in config) { if (item.Key.Section == category && item.Key.Key.EndsWith("_volume") && item.Value is ConfigEntry<float> val) { val.Value = volume; } } config.Save(); UpdateVolumes(); log.LogInfo((object)$"\ud83d\udce2 Пресет громкости {volume} применён к категории [{category}]"); } private void AddPresetButtons(string category) { ConfigEntry<bool> def = config.Bind<bool>(category, "__Preset_Default", false, "Установить громкость всех звуков этой категории на 1.0"); ConfigEntry<bool> mid = config.Bind<bool>(category, "__Preset_Mid", false, "Установить громкость всех звуков этой категории на 0.5"); ConfigEntry<bool> low = config.Bind<bool>(category, "__Preset_Quiet", false, "Установить громкость всех звуков этой категории на 0.1"); ConfigEntry<AllAudioToggle> allToggle = config.Bind<AllAudioToggle>(category, "All Audio", AllAudioToggle.Enable, "Включить или выключить все звуки в категории"); def.SettingChanged += delegate { ApplyPresetVolume(def, 1f); }; mid.SettingChanged += delegate { ApplyPresetVolume(mid, 0.5f); }; low.SettingChanged += delegate { ApplyPresetVolume(low, 0.1f); }; allToggle.SettingChanged += delegate { HandleAllToggle(allToggle); }; void ApplyPresetVolume(ConfigEntry<bool> entry, float volume) { if (entry.Value) { log.LogInfo((object)$"\ud83d\udd27 Применяется пресет громкости {volume} для категории [{category}]"); foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in config) { if (!(item.Key.Section != category) && item.Key.Key.EndsWith("_volume") && item.Value is ConfigEntry<float> val3) { val3.Value = volume; } } entry.Value = false; config.Save(); UpdateVolumes(); } } void HandleAllToggle(ConfigEntry<AllAudioToggle> entry) { switch (entry.Value) { case AllAudioToggle.Enable: log.LogInfo((object)("✅ Включаются все звуки в категории [" + category + "]")); foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item2 in config) { if (!(item2.Key.Section != category) && !item2.Key.Key.StartsWith("__") && !item2.Key.Key.EndsWith("_volume") && item2.Value is ConfigEntry<bool> val2) { val2.Value = true; } } break; case AllAudioToggle.Disable: log.LogInfo((object)("\ud83d\udeab Отключаются все звуки в категории [" + category + "]")); foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item3 in config) { if (!(item3.Key.Section != category) && !item3.Key.Key.StartsWith("__") && !item3.Key.Key.EndsWith("_volume") && item3.Value is ConfigEntry<bool> val) { val.Value = false; } } break; } config.Save(); UpdateVolumes(); } } public static void UpdateVolumes() { if (replacedSources.Count == 0) { return; } tryReplaceCache.Clear(); processedClips.Clear(); noReplacementCache.Clear(); configCache.Clear(); replacedSources.RemoveAll((AudioSource src) => (Object)(object)src == (Object)null || (Object)(object)src.clip == (Object)null); foreach (AudioSource replacedSource in replacedSources) { if (!((Object)(object)replacedSource.clip == (Object)null)) { string name = ((Object)replacedSource.clip).name; if (TryReplace(replacedSource, name, out var _, out var volume, out var enabled) && enabled) { float volume2 = Mathf.Clamp01(Mathf.Pow(Mathf.Clamp(volume, 0.0001f, 1f), 2.2f)); replacedSource.volume = volume2; } else { replacedSource.volume = 0f; } } } log.LogInfo((object)"\ud83d\udd04 Громкости обновлены"); } private void LoadReplacements() { //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Expected O, but got Unknown string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "replacers"); if (!Directory.Exists(text)) { log.LogWarning((object)("❌ Папка с заменами не найдена: " + text)); return; } HashSet<string> hashSet = new HashSet<string>(); string[] files = Directory.GetFiles(text, "*.json"); foreach (string text2 in files) { try { ReplacementContainer replacementContainer = JsonConvert.DeserializeObject<ReplacementContainer>(File.ReadAllText(text2)); foreach (Replacement replacement in replacementContainer.replacements) { foreach (string match in replacement.matches) { if (!replacementMap.ContainsKey(match)) { replacementMap[match] = new List<SoundEntry>(); } foreach (SoundEntry sound in replacement.sounds) { SoundEntry soundEntry = sound; if (soundEntry.category == null) { soundEntry.category = replacement.category ?? "Default"; } soundEntry = sound; if (soundEntry.displayName == null) { soundEntry.displayName = Path.GetFileNameWithoutExtension(sound.sound); } if (hashSet.Add(sound.category)) { AddPresetButtons(sound.category); } if (!clipCache.ContainsKey(sound.sound)) { AudioClip clip = GetClip(sound.sound); if ((Object)(object)clip != (Object)null) { clipCache[sound.sound] = clip; } } string key = sound.sound.ToLowerInvariant(); directMatchCache[key] = sound; replacementMap[match].Add(sound); } } } } catch (Exception ex) { log.LogError((object)("⚠\ufe0f Ошибка при чтении " + text2 + ": " + ex.Message)); } } foreach (KeyValuePair<string, List<SoundEntry>> item3 in replacementMap) { foreach (SoundEntry item4 in item3.Value) { string text3 = item4.category ?? "Default"; string text4 = item4.displayName ?? Path.GetFileNameWithoutExtension(item4.sound); ConfigEntry<bool> item = config.Bind<bool>(text3, text4, true, "Включить звук"); ConfigEntry<float> item2 = config.Bind<float>(text3, text4 + "_volume", 1f, new ConfigDescription("Громкость от 0.0 до 1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); configEntryCache[text3 + "::" + text4] = (item, item2); } } } private static void CleanupSavedPositions() { List<AudioSource> list = savedPositions.Keys.Where((AudioSource src) => (Object)(object)src == (Object)null || (Object)(object)((Component)src).gameObject == (Object)null).ToList(); foreach (AudioSource item in list) { savedPositions.Remove(item); } } }