using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using 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);
}
}
}