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 REPOSoundBoard v0.2.0
REPOSoundBoard.dll
Decompiled a year agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Threading; using BepInEx; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; using NAudio.Wave; using Newtonsoft.Json; using Photon.Pun; using Photon.Voice.Unity; using REPOSoundBoard.Config; using REPOSoundBoard.Core; using REPOSoundBoard.Core.Exceptions; using REPOSoundBoard.Core.Hotkeys; using REPOSoundBoard.Core.Media; using REPOSoundBoard.Core.Media.Converter; using REPOSoundBoard.Patches; using REPOSoundBoard.UI; using REPOSoundBoard.UI.Components; using REPOSoundBoard.UI.Utils; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("REPOSoundBoard")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+ddae80319bf38fc5190635a3e7c05f831b16ba45")] [assembly: AssemblyProduct("REPOSoundBoard")] [assembly: AssemblyTitle("REPOSoundBoard")] [assembly: AssemblyVersion("1.0.0.0")] namespace REPOSoundBoard { [BepInPlugin("com.moli.repo-soundboard", "REPOSoundBoard", "0.2.0")] public class REPOSoundBoard : BaseUnityPlugin { public const string GUID = "com.moli.repo-soundboard"; public const string NAME = "REPOSoundBoard"; public const string VERSION = "0.2.0"; private static readonly Harmony _harmony = new Harmony("com.moli.repo-soundboard"); public static ManualLogSource Logger; public HotkeyManager HotkeyManager; public SoundBoard SoundBoard; public SoundBoardUI UI; public static REPOSoundBoard Instance { get; private set; } public AppConfig Config { get; private set; } private void Awake() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown if (!((Object)(object)Instance != (Object)null)) { Instance = this; Logger = ((BaseUnityPlugin)this).Logger; Config = AppConfig.LoadConfig(); GameObject val = new GameObject("REPOSoundBoardMod"); ((Object)val).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)val); HotkeyManager = val.AddComponent<HotkeyManager>(); SoundBoard = val.AddComponent<SoundBoard>(); SoundBoard.LoadConfig(Config.SoundBoard); UI = val.AddComponent<SoundBoardUI>(); Config.UiHotkey.OnPressed(delegate { UI.Visible = !UI.Visible; }); HotkeyManager.RegisterHotkey(Config.UiHotkey); _harmony.PatchAll(typeof(ChatManagerPatch)); _harmony.PatchAll(typeof(PlayerVoiceChatPatch)); _harmony.PatchAll(typeof(MenuCursorPatch)); } } public void SaveConfig() { SoundBoardConfig soundBoardConfig = new SoundBoardConfig(); soundBoardConfig.Enabled = SoundBoard.Instance.Enabled; soundBoardConfig.StopHotkey = SoundBoard.Instance.StopHotkey; foreach (SoundButton soundButton in SoundBoard.Instance.SoundButtons) { soundBoardConfig.SoundButtons.Add(soundButton.CreateConfig()); } Config.SoundBoard = soundBoardConfig; Config.SaveToFile(); } } } namespace REPOSoundBoard.UI { public class SoundBoardUI : MonoBehaviour { public static SoundBoardUI Instance; private bool _isVisible; private const float DefaultWindowGap = 20f; private IMGUIWindow _generalSettingsWindow; private GeneralSettingsUI _generalSettingsUI; private const float GeneralSettingsWindowWidth = 340f; private const float GeneralSettingsWindowHeight = 60f; private IMGUIWindow _soundButtonsWindow; private SoundButtonsUI _soundButtonsUI; private const float SoundButtonsWindowWidth = 600f; private const float SoundButtonsWindowHeight = 650f; public bool Visible { get { return _isVisible; } set { _isVisible = value; if (_isVisible) { UnlockCursor(); } else { LockCursor(); } } } public void Start() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) Instance = this; float num = 960f; float num2 = Mathf.Max(60f, 650f); _generalSettingsUI = new GeneralSettingsUI(); _generalSettingsWindow = new IMGUIWindow("General Settings", new Rect(((float)Screen.width - num) / 2f, ((float)Screen.height - num2) / 2f, 340f, 60f), delegate { _generalSettingsUI.Draw(); }); _soundButtonsUI = new SoundButtonsUI(); _soundButtonsWindow = new IMGUIWindow("Sound Buttons", new Rect(((float)Screen.width - num) / 2f + 340f + 20f, ((float)Screen.height - num2) / 2f, 600f, 650f), delegate { _soundButtonsUI.Draw(); }); } private void Update() { if (Visible) { InputManager.instance.DisableAiming(); InputManager.instance.DisableMovement(); } } private void OnGUI() { if (_isVisible) { Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; _generalSettingsWindow.Draw(); _soundButtonsWindow.Draw(); } } private void UnlockCursor() { MenuCursorPatch.HideInGameCursor = true; Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; } private void LockCursor() { MenuCursorPatch.HideInGameCursor = false; Cursor.lockState = (CursorLockMode)1; Cursor.visible = false; } private void OnDestroy() { REPOSoundBoard.Instance.SaveConfig(); } } } namespace REPOSoundBoard.UI.Utils { public static class HotkeySelectorUtils { private static readonly List<KeyCode> _disallowedKeys; public static List<KeyCode> PossibleKeys { get; } static HotkeySelectorUtils() { _disallowedKeys = new List<KeyCode> { (KeyCode)323, (KeyCode)324, (KeyCode)311, (KeyCode)312, (KeyCode)310, (KeyCode)309 }; PossibleKeys = UnityInput.Current.SupportedKeyCodes.Where((KeyCode code) => !_disallowedKeys.Contains(code)).ToList(); } public static List<KeyCode> GetPressedKeys() { return ((IEnumerable<KeyCode>)PossibleKeys).Where((Func<KeyCode, bool>)Input.GetKey).ToList(); } } public class IMGUITabs { private string[] tabs; private int selectedTab; private Action<int>[] tabContents; private GUIStyle tabStyle; private GUIStyle activeTabStyle; public int SelectedTab => selectedTab; public IMGUITabs(string[] tabs, Action<int>[] tabContents) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown this.tabs = tabs; this.tabContents = tabContents; tabStyle = new GUIStyle(GUI.skin.button); activeTabStyle = new GUIStyle(GUI.skin.button); activeTabStyle.normal.background = activeTabStyle.active.background; } public void SetStyles(GUIStyle tabStyle, GUIStyle activeTabStyle) { this.tabStyle = tabStyle; this.activeTabStyle = activeTabStyle; } public void Draw() { IMGUIUtils.HorizontalGroup(delegate { for (int i = 0; i < tabs.Length; i++) { bool flag = i == selectedTab; if (GUILayout.Button(tabs[i], flag ? activeTabStyle : tabStyle, Array.Empty<GUILayoutOption>())) { selectedTab = i; } } }); IMGUIUtils.BoxGroup(delegate { if (selectedTab >= 0 && selectedTab < tabContents.Length) { tabContents[selectedTab]?.Invoke(selectedTab); } }); } } public class IMGUIUtils { public static readonly GUIStyle DisabledTextStyle; public static readonly GUIStyle HeadingStyle; static IMGUIUtils() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) DisabledTextStyle = GUI.skin.label; DisabledTextStyle.normal.textColor = new Color(120f, 120f, 120f); HeadingStyle = new GUIStyle(GUI.skin.label); HeadingStyle.normal.textColor = Color.white; HeadingStyle.fontSize = 15; } public static void HorizontalGroup(Action guiAction) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); guiAction?.Invoke(); GUILayout.EndHorizontal(); } public static void VerticalGroup(Action guiAction) { GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); guiAction?.Invoke(); GUILayout.EndVertical(); } public static Vector2 ScrollGroup(Vector2 scrollPosition, Action guiAction, GUIStyle style = null) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) Vector2 result = GUILayout.BeginScrollView(scrollPosition, style ?? GUI.skin.scrollView); guiAction?.Invoke(); GUILayout.EndScrollView(); return result; } public static void BoxGroup(Action guiAction, GUIStyle style = null) { GUILayout.BeginVertical(style ?? GUI.skin.box, Array.Empty<GUILayoutOption>()); guiAction?.Invoke(); GUILayout.EndVertical(); } public static void AreaGroup(Rect rect, Action guiAction) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginArea(rect); guiAction?.Invoke(); GUILayout.EndArea(); } public static void WithColor(Color color, Action guiAction) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Color color2 = GUI.color; GUI.color = color; guiAction?.Invoke(); GUI.color = color2; } public static void WithContentColor(Color color, Action guiAction) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Color contentColor = GUI.contentColor; GUI.contentColor = color; guiAction?.Invoke(); GUI.contentColor = contentColor; } public static void WithBackgroundColor(Color color, Action guiAction) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Color backgroundColor = GUI.backgroundColor; GUI.backgroundColor = color; guiAction?.Invoke(); GUI.backgroundColor = backgroundColor; } public static void WithEnabled(bool enabled, Action guiAction) { bool enabled2 = GUI.enabled; GUI.enabled = enabled; guiAction?.Invoke(); GUI.enabled = enabled2; } public static float LabeledSlider(string label, float value, float leftValue, float rightValue) { HorizontalGroup(delegate { GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(false), GUILayout.Height(20f) }); value = GUILayout.HorizontalSlider(value, leftValue, rightValue, Array.Empty<GUILayoutOption>()); GUILayout.Label(value.ToString("F2"), (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(50f), GUILayout.Height(20f) }); }); return value; } public static string LabeledTextField(string label, string text) { HorizontalGroup(delegate { GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); text = GUILayout.TextField(text, Array.Empty<GUILayoutOption>()); }); return text; } public static bool LabeledToggle(string label, bool value) { HorizontalGroup(delegate { GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); value = GUILayout.Toggle(value, "", Array.Empty<GUILayoutOption>()); }); return value; } public static bool LabeledHotkeyInput(string label, Hotkey hotkey, bool selecting) { HorizontalGroup(delegate { GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); if (!selecting) { if (hotkey.Keys.Count == 0) { GUILayout.Label("No hotkey selected", DisabledTextStyle, Array.Empty<GUILayoutOption>()); } else { GUILayout.Label(string.Join(" + ", hotkey.Keys), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); } if (GUILayout.Button("Change", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) })) { selecting = true; GUIUtility.keyboardControl = 0; } } else { if (HotkeySelectorUtils.GetPressedKeys().Count == 0) { GUILayout.Label("Start pressing keys...", DisabledTextStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); } else { GUILayout.Label(string.Join(" + ", HotkeySelectorUtils.GetPressedKeys()), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); if (GUILayout.Button("Apply", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) })) { hotkey.Keys = HotkeySelectorUtils.GetPressedKeys(); selecting = false; } } if (GUILayout.Button("Reset", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) })) { selecting = false; } } }); return selecting; } public static string LabeledPathInput(string label, string originalPath, string inputPath, ref bool changing, Action<string> pathChanged) { bool localChanging = changing; HorizontalGroup(delegate { GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); if (!localChanging) { GUILayout.Label(originalPath, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); if (GUILayout.Button("Change", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) })) { localChanging = true; } } else { inputPath = GUILayout.TextField(inputPath.Replace("\"", ""), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); if (GUILayout.Button("Apply", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) })) { pathChanged?.Invoke(inputPath); localChanging = false; } if (GUILayout.Button("Reset", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) })) { inputPath = originalPath; localChanging = false; } } }); changing = localChanging; return inputPath; } public static bool ConfirmButton(string buttonText, string confirmationText, ref bool confirmationShown) { bool result = false; bool localConfirmationShown = confirmationShown; if (!localConfirmationShown) { if (GUILayout.Button(buttonText, Array.Empty<GUILayoutOption>())) { localConfirmationShown = true; } } else { HorizontalGroup(delegate { GUILayout.Label(confirmationText, Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Yes", Array.Empty<GUILayoutOption>())) { result = true; localConfirmationShown = false; } if (GUILayout.Button("No", Array.Empty<GUILayoutOption>())) { localConfirmationShown = false; } }); } confirmationShown = localConfirmationShown; return result; } } public class IMGUIWindow { private Rect _windowRect; private string _title; private Action<int> _drawContent; private bool _isDraggable = true; private int _id; private static int _nextId; public Rect WindowRect => _windowRect; public IMGUIWindow(string title, Rect initialRect, Action<int> drawContent) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) _title = title; _windowRect = initialRect; _drawContent = drawContent; _id = _nextId++; } public void SetDraggable(bool isDraggable) { _isDraggable = isDraggable; } public void Draw() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (_isDraggable) { _windowRect = GUILayout.Window(_id, _windowRect, new WindowFunction(WindowFunction), _title, Array.Empty<GUILayoutOption>()); return; } IMGUIUtils.AreaGroup(_windowRect, delegate { GUILayout.Label(_title, GUI.skin.box, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); _drawContent?.Invoke(_id); }); } private void WindowFunction(int windowId) { _drawContent?.Invoke(windowId); if (_isDraggable) { GUI.DragWindow(); } } } } namespace REPOSoundBoard.UI.Components { public class GeneralSettingsUI { private bool _selectionStopHotkey; public void Draw() { SoundBoard.Instance.Enabled = IMGUIUtils.LabeledToggle("Global enabled:", SoundBoard.Instance.Enabled); _selectionStopHotkey = IMGUIUtils.LabeledHotkeyInput("Stop hotkey:", SoundBoard.Instance.StopHotkey, _selectionStopHotkey); IMGUIUtils.HorizontalGroup(delegate { if (GUILayout.Button("Save changes", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) })) { REPOSoundBoard.Instance.SaveConfig(); } if (GUILayout.Button("Close", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) })) { SoundBoardUI.Instance.Visible = false; } }); } } public class SoundButtonsUI { private string _search = string.Empty; private Vector2 _scrollPosition = Vector2.zero; private List<SoundButtonUI> _soundButtonUis; private SoundButtonUI _buttonToDelete; public SoundButtonsUI() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) _soundButtonUis = SoundBoard.Instance.SoundButtons.Select(delegate(SoundButton button) { SoundButtonUI soundButtonUI = new SoundButtonUI(button); soundButtonUI.OnDeleteClicked += HandleDeleteButtonPress; return soundButtonUI; }).ToList(); } private void HandleDeleteButtonPress(SoundButtonUI buttonUI) { _buttonToDelete = buttonUI; } private void HandleCurrentDeletion() { if (_buttonToDelete != null) { _soundButtonUis.Remove(_buttonToDelete); SoundBoard.Instance.RemoveSoundButton(_buttonToDelete.SoundButton); } } public void Draw() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) HandleCurrentDeletion(); _search = IMGUIUtils.LabeledTextField("Search:", _search).ToLower(); _scrollPosition = IMGUIUtils.ScrollGroup(_scrollPosition, delegate { foreach (SoundButtonUI item in _soundButtonUis.Where((SoundButtonUI buttonUI) => buttonUI.SoundButton.Name.ToLower().Contains(_search))) { item.Draw(); } }); if (GUILayout.Button("Add new sound button", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) })) { SoundButton soundButton = new SoundButton(); SoundButtonUI soundButtonUI = new SoundButtonUI(soundButton, editing: true); soundButtonUI.OnDeleteClicked += HandleDeleteButtonPress; SoundBoard.Instance.AddSoundButton(soundButton); _soundButtonUis.Insert(0, soundButtonUI); } } } public class SoundButtonUI { private static GUIStyle _pathStyle; private static GUIStyle _disabledButtonLabelStyle; private bool _isEditing; private bool _isEditingHotkey; private bool _changingPath; private string _pathInput; private static GUIStyle PathStyle { get { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (_pathStyle == null) { _pathStyle = new GUIStyle(GUI.skin.label); _pathStyle.normal.textColor = new Color(0.6f, 0.6f, 0.6f); _pathStyle.fontStyle = (FontStyle)2; _pathStyle.fontSize = 12; } return _pathStyle; } } private static GUIStyle DisabledButtonLabelStyle { get { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (_disabledButtonLabelStyle == null) { _disabledButtonLabelStyle = new GUIStyle(GUI.skin.label); _disabledButtonLabelStyle.normal.textColor = new Color(0.6f, 0.6f, 0.6f); } return _disabledButtonLabelStyle; } } public SoundButton SoundButton { get; } [CanBeNull] public event Action<SoundButtonUI> OnDeleteClicked; public SoundButtonUI(SoundButton soundButton, bool editing = false) { SoundButton = soundButton; _isEditing = editing; _pathInput = SoundButton.Clip?.OriginalPath ?? string.Empty; } public void Draw() { IMGUIUtils.BoxGroup(delegate { DrawState(); if (!_isEditing) { DrawDetailUI(); } else { DrawEditUI(); } }); } private static Color GetStateColor(MediaClip.MediaClipState state) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) return (Color)(state switch { MediaClip.MediaClipState.Idle => Color.white, MediaClip.MediaClipState.Converting => Color.yellow, MediaClip.MediaClipState.Converted => Color.white, MediaClip.MediaClipState.FailedToConvert => Color.red, MediaClip.MediaClipState.Loading => Color.cyan, MediaClip.MediaClipState.Loaded => Color.green, MediaClip.MediaClipState.FailedToLoad => Color.red, _ => Color.white, }); } private void DrawState() { if (SoundButton.Clip != null && SoundButton.Clip.State != MediaClip.MediaClipState.Loaded) { IMGUIUtils.HorizontalGroup(delegate { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) GUILayout.Label("State:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUIStyle val = new GUIStyle(GUI.skin.label); val.normal.textColor = GetStateColor(SoundButton.Clip.State); GUILayout.Label(SoundButton.Clip.StateMessage, val, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); }); } } private void DrawDetailUI() { IMGUIUtils.HorizontalGroup(delegate { if (SoundButton.Enabled) { GUILayout.Label(SoundButton.Name, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); } else { GUILayout.Label(SoundButton.Name + " [disabled]", DisabledButtonLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); } if (GUILayout.Button((SoundButton.Hotkey.Keys.Count == 0) ? "[no hotkey]" : string.Join(" + ", SoundButton.Hotkey.Keys), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) })) { SoundBoard.Instance.Play(SoundButton, ignoreEnabledChecks: true); } if (GUILayout.Button("Edit", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) })) { _isEditing = true; } if (GUILayout.Button("Delete", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) })) { this.OnDeleteClicked?.Invoke(this); } }); if (SoundButton.Clip == null) { GUILayout.Label("No file selected...", PathStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); } else { GUILayout.Label(SoundButton.Clip.OriginalPath, PathStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); } } private void DrawEditUI() { IMGUIUtils.VerticalGroup(delegate { SoundButton.Name = IMGUIUtils.LabeledTextField("Name:", SoundButton.Name); _isEditingHotkey = IMGUIUtils.LabeledHotkeyInput("Hotkey:", SoundButton.Hotkey, _isEditingHotkey); SoundButton.Enabled = IMGUIUtils.LabeledToggle("Enabled:", SoundButton.Enabled); SoundButton.Volume = IMGUIUtils.LabeledSlider("Volume:", SoundButton.Volume, 0f, 1f); _pathInput = IMGUIUtils.LabeledPathInput("Path:", SoundButton.Clip?.OriginalPath ?? string.Empty, _pathInput, ref _changingPath, OnPathChanged); if (GUILayout.Button("Done", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) })) { _isEditing = false; } }); } private void OnPathChanged(string path) { if (SoundButton.Clip != null) { SoundButton.Clip.DeleteCacheFile(); } SoundButton.Clip = new MediaClip(path); ((MonoBehaviour)SoundBoard.Instance).StartCoroutine(SoundButton.LoadClip()); } } } namespace REPOSoundBoard.Patches { public static class ChatManagerPatch { [HarmonyPatch(typeof(ChatManager), "StateInactive")] [HarmonyPrefix] public static bool BeforeStateInactive(ref string ___chatMessage, ref bool ___chatActive) { if (SoundBoardUI.Instance.Visible) { ((SemiUI)ChatUI.instance).Hide(); ___chatMessage = ""; ___chatActive = false; return false; } return true; } } public class MenuCursorPatch { public static bool HideInGameCursor; [HarmonyPatch(typeof(CursorManager), "Update")] [HarmonyPrefix] public static bool BeforeCursorManagerUpdate() { return !HideInGameCursor; } [HarmonyPatch(typeof(CursorManager), "Unlock")] [HarmonyPrefix] public static bool BeforeCursorManagerUnlock() { return !HideInGameCursor; } } public class PlayerVoiceChatPatch { [HarmonyPatch(typeof(PlayerVoiceChat), "Start")] [HarmonyPostfix] public static void PostStart(PlayerVoiceChat __instance, ref Recorder ___recorder, ref PhotonView ___photonView) { if (___photonView.IsMine) { REPOSoundBoard.Instance.SoundBoard.ChangeRecorder(___recorder); } } } } namespace REPOSoundBoard.Core { public class SoundBoard : MonoBehaviour { [CompilerGenerated] private sealed class <StopAfterEnd>d__20 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public SoundButton soundButton; public SoundBoard <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <StopAfterEnd>d__20(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown int num = <>1__state; SoundBoard soundBoard = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; if (soundButton.Clip == null) { return false; } <>2__current = (object)new WaitForSeconds(soundButton.Clip.AudioClip.length); <>1__state = 1; return true; case 1: <>1__state = -1; soundBoard.StopCurrent(); 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(); } } public static SoundBoard Instance; public Hotkey StopHotkey; private Recorder _recorder; private AudioSource _audioSource; private bool _isPlaying; private bool _enabled; private SoundButton _currentSoundButton; private Coroutine _stopAfterEndCoroutine; public List<SoundButton> SoundButtons { get; } = new List<SoundButton>(); public bool Enabled { get { return _enabled; } set { _enabled = value; } } private void Start() { if ((Object)(object)Instance == (Object)null) { Instance = this; } _audioSource = ((Component)this).gameObject.AddComponent<AudioSource>(); } public void LoadConfig(SoundBoardConfig config) { _enabled = config.Enabled; StopHotkey = config.StopHotkey; StopHotkey.OnPressed(StopCurrent); REPOSoundBoard.Instance.HotkeyManager.RegisterHotkey(config.StopHotkey); foreach (SoundButtonConfig soundButton2 in config.SoundButtons) { if (soundButton2.Hotkey != null && soundButton2.Path != null) { SoundButton soundButton = SoundButton.FromConfig(soundButton2); ((MonoBehaviour)this).StartCoroutine(soundButton.LoadClip()); AddSoundButton(soundButton); } } } public void AddSoundButton(SoundButton soundButton) { soundButton.Hotkey.OnPressed(delegate { Play(soundButton); }); REPOSoundBoard.Instance.HotkeyManager.RegisterHotkey(soundButton.Hotkey); SoundButtons.Add(soundButton); string text = ((soundButton.Hotkey != null) ? string.Join(" + ", soundButton.Hotkey.Keys) : "none"); REPOSoundBoard.Logger.LogInfo((object)("Sound Button registered: " + soundButton.Name + ", with hotkey: " + text + " and path: " + soundButton.Clip?.OriginalPath)); } public void RemoveSoundButton(SoundButton soundButton) { SoundButtons.Remove(soundButton); REPOSoundBoard.Instance.HotkeyManager.UnregisterHotkey(soundButton.Hotkey); } public void ChangeRecorder(Recorder recorder) { StopCurrent(); _recorder = recorder; } public void Play(SoundButton soundButton, bool ignoreEnabledChecks = false) { StopCurrent(); if ((ignoreEnabledChecks || (((Behaviour)this).enabled && soundButton.Enabled)) && soundButton.Clip != null && soundButton.Clip.IsReady) { _isPlaying = true; _currentSoundButton = soundButton; _audioSource.clip = soundButton.Clip.AudioClip; _audioSource.volume = soundButton.Volume; _audioSource.Play(); if ((Object)(object)_recorder != (Object)null) { _recorder.TransmitEnabled = false; _recorder.SourceType = (InputSourceType)1; _recorder.AudioClip = soundButton.Clip.AudioClip; _recorder.TransmitEnabled = true; } _stopAfterEndCoroutine = ((MonoBehaviour)this).StartCoroutine(StopAfterEnd(soundButton)); } } [IteratorStateMachine(typeof(<StopAfterEnd>d__20))] private IEnumerator StopAfterEnd(SoundButton soundButton) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <StopAfterEnd>d__20(0) { <>4__this = this, soundButton = soundButton }; } private void StopCurrent() { if (_isPlaying) { if (_stopAfterEndCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_stopAfterEndCoroutine); _stopAfterEndCoroutine = null; } _audioSource.Stop(); if ((Object)(object)_recorder != (Object)null) { _recorder.SourceType = (InputSourceType)0; _recorder.AudioClip = null; _recorder.TransmitEnabled = true; } _isPlaying = false; _currentSoundButton = null; } } } public class SoundButton { public string Name; public bool Enabled; public float Volume; public Hotkey Hotkey; [CanBeNull] public MediaClip Clip; public SoundButton() { Name = string.Empty; Enabled = true; Volume = 1f; Hotkey = new Hotkey(); } public static SoundButton FromConfig(SoundButtonConfig config) { return new SoundButton { Name = config.Name, Enabled = config.Enabled, Volume = config.Volume, Hotkey = config.Hotkey, Clip = new MediaClip(config.Path) }; } public SoundButtonConfig CreateConfig() { return new SoundButtonConfig { Name = Name, Volume = Volume, Hotkey = Hotkey, Path = Clip?.OriginalPath, Enabled = Enabled }; } public IEnumerator LoadClip() { return Clip?.Load(); } } } namespace REPOSoundBoard.Core.Media { public static class CacheFileHelper { private static readonly string CacheDirectory = Path.Combine(Paths.PluginPath, "Moli-REPOSoundBoard-0.2.0/_cache"); public static void DeleteFromCache(string fileName) { File.Delete(Path.Combine(CacheDirectory, fileName)); } public static string GetFullCachePath(string cacheFileName) { return Path.Combine(CacheDirectory, cacheFileName); } public static bool ExistsInCache(string cacheFileName) { return File.Exists(GetFullCachePath(cacheFileName)); } public static string GetCacheFilePath(string originalFilePath, string cacheExtension = ".cache") { return Path.Combine(CacheDirectory, GetCacheFileName(originalFilePath, cacheExtension)); } public static void EnsureCacheDirectoryExists() { if (!Directory.Exists(CacheDirectory)) { Directory.CreateDirectory(CacheDirectory); } } public static string GetCacheFileName(string originalFilePath, string cacheExtension = ".cache") { using SHA256 sHA = SHA256.Create(); byte[] bytes = Encoding.UTF8.GetBytes(originalFilePath); return BitConverter.ToString(sHA.ComputeHash(bytes)).Replace("-", "").ToLowerInvariant() + cacheExtension; } } public class MediaClip { public enum MediaClipState { Idle, Converting, Converted, FailedToConvert, Loading, Loaded, FailedToLoad } [CompilerGenerated] private sealed class <Convert>d__30 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public MediaClip <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <Convert>d__30(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; MediaClip CS$<>8__locals0 = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; CS$<>8__locals0.SetState(MediaClipState.Converting, "Converting media file..."); CS$<>8__locals0._conversionComplete = false; CS$<>8__locals0._conversionException = null; ThreadPool.QueueUserWorkItem(delegate { try { IMediaConverter converterForFile = MediaConverterFactory.GetConverterForFile(CS$<>8__locals0.OriginalPath); if (converterForFile != null) { CacheFileHelper.EnsureCacheDirectoryExists(); converterForFile.Convert(CS$<>8__locals0.OriginalPath, CS$<>8__locals0._cachePath, ConversionOptions.Default); CS$<>8__locals0._isConverted = true; } } catch (Exception conversionException) { CS$<>8__locals0._conversionException = conversionException; } finally { CS$<>8__locals0._conversionComplete = true; } }); break; case 1: <>1__state = -1; break; } if (!CS$<>8__locals0._conversionComplete) { <>2__current = null; <>1__state = 1; return true; } if (CS$<>8__locals0._conversionException != null) { string message = ((CS$<>8__locals0._conversionException is AudioConversionException) ? CS$<>8__locals0._conversionException.Message : "Failed to convert to .wav. Check logs for more information."); CS$<>8__locals0.SetState(MediaClipState.FailedToConvert, message); string text = "Failed to convert to .wav. Error " + CS$<>8__locals0._conversionException.Message + ". File: " + CS$<>8__locals0.OriginalPath; REPOSoundBoard.Logger.LogError((object)text); return false; } if (MediaConverterFactory.GetConverterForFile(CS$<>8__locals0.OriginalPath) == null) { CS$<>8__locals0.SetState(MediaClipState.FailedToConvert, "Failed to convert to .wav. Invalid file format."); REPOSoundBoard.Logger.LogWarning((object)("Unsupported file format: " + CS$<>8__locals0.OriginalPath)); return false; } CS$<>8__locals0.SetState(MediaClipState.Converted, "Successfully converted to .wav. Waiting to load..."); 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 <Load>d__28 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public MediaClip <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <Load>d__28(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; MediaClip mediaClip = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; if (mediaClip.HasError || mediaClip.State == MediaClipState.Loaded) { return false; } if (!File.Exists(mediaClip.OriginalPath)) { mediaClip.SetState(MediaClipState.FailedToLoad, "Failed to load. Could not find file."); return false; } if (!mediaClip._isConverted) { <>2__current = mediaClip.Convert(); <>1__state = 1; return true; } goto IL_0085; case 1: <>1__state = -1; if (!mediaClip._isConverted) { return false; } goto IL_0085; case 2: { <>1__state = -1; return false; } IL_0085: <>2__current = mediaClip.LoadAudioClip(); <>1__state = 2; return true; } } 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 <LoadAudioClip>d__31 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public MediaClip <>4__this; private UnityWebRequest <www>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadAudioClip>d__31(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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Invalid comparison between Unknown and I4 try { int num = <>1__state; MediaClip mediaClip = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; mediaClip.SetState(MediaClipState.Loading, "Loading clip..."); <www>5__2 = UnityWebRequestMultimedia.GetAudioClip(mediaClip._cachePath, (AudioType)20); <>1__state = -3; <>2__current = <www>5__2.SendWebRequest(); <>1__state = 1; return true; case 1: <>1__state = -3; if ((int)<www>5__2.result == 1) { mediaClip.AudioClip = DownloadHandlerAudioClip.GetContent(<www>5__2); mediaClip.SetState(MediaClipState.Loaded, "Sound button loaded successfully."); } else { string text = "Failed to load media: " + <www>5__2.error + ". Path: " + mediaClip.OriginalPath + ". Cache Path: " + mediaClip._cachePath; REPOSoundBoard.Logger.LogError((object)text); mediaClip.SetState(MediaClipState.FailedToLoad, "Failed to load. Check logs for more information."); } <>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 readonly string _cachePath; private readonly string _cacheFileName; private bool _isConverted; private bool _conversionComplete; private Exception _conversionException; public MediaClipState State { get; private set; } public string StateMessage { get; private set; } public string OriginalPath { get; private set; } public AudioClip AudioClip { get; private set; } public bool IsReady => State == MediaClipState.Loaded; public bool HasError { get { if (State != MediaClipState.FailedToConvert) { return State == MediaClipState.FailedToLoad; } return true; } } public MediaClip(string path) { OriginalPath = path; _cacheFileName = CacheFileHelper.GetCacheFileName(path, ".wav"); _cachePath = CacheFileHelper.GetFullCachePath(_cacheFileName); _isConverted = CacheFileHelper.ExistsInCache(_cacheFileName); SetState(MediaClipState.Idle, "Waiting for instructions..."); } public void DeleteCacheFile() { CacheFileHelper.DeleteFromCache(_cacheFileName); SetState(MediaClipState.Idle, "Cache file deleted. Waiting for conversion to start..."); } [IteratorStateMachine(typeof(<Load>d__28))] public IEnumerator Load() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <Load>d__28(0) { <>4__this = this }; } private void SetState(MediaClipState state, string message) { State = state; StateMessage = message; } [IteratorStateMachine(typeof(<Convert>d__30))] private IEnumerator Convert() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <Convert>d__30(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<LoadAudioClip>d__31))] private IEnumerator LoadAudioClip() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LoadAudioClip>d__31(0) { <>4__this = this }; } } } namespace REPOSoundBoard.Core.Media.Converter { public class AiffConverter : IMediaConverter { public static bool IsCompatible(string path) { if (string.IsNullOrEmpty(path)) { return false; } string text = Path.GetExtension(path)?.ToLowerInvariant(); if (!string.IsNullOrEmpty(text)) { return text == ".aiff"; } return false; } public void Convert(string sourcePath, string targetPath, ConversionOptions options) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown if (!File.Exists(sourcePath)) { throw new FileNotFoundException("Source file " + sourcePath + " not found"); } AiffFileReader val = new AiffFileReader(sourcePath); try { MediaFoundationResampler val2 = new MediaFoundationResampler((IWaveProvider)(object)val, new WaveFormat(options.SampleRate, options.BitsPerSample, options.ChannelCount)); val2.ResamplerQuality = 60; WaveFileWriter.CreateWaveFile(targetPath, (IWaveProvider)(object)val2); } finally { ((IDisposable)val)?.Dispose(); } } } public struct ConversionOptions { public int SampleRate; public int ChannelCount; public int BitsPerSample; public string AudioCodec; public static ConversionOptions Default = new ConversionOptions { SampleRate = 48000, ChannelCount = 1, BitsPerSample = 16, AudioCodec = "pcm_s16le" }; } public interface IMediaConverter { static bool IsCompatible(string path) { return false; } void Convert(string sourcePath, string targetPath, ConversionOptions options); } public static class MediaConverterFactory { public static IMediaConverter GetConverterForFile(string path) { if (WavConverter.IsCompatible(path)) { return new WavConverter(); } if (Mp3Converter.IsCompatible(path)) { return new Mp3Converter(); } if (AiffConverter.IsCompatible(path)) { return new AiffConverter(); } if (VideoConverter.IsCompatible(path)) { return new VideoConverter(); } return null; } } public class Mp3Converter : IMediaConverter { public static bool IsCompatible(string path) { if (string.IsNullOrEmpty(path)) { return false; } string text = Path.GetExtension(path)?.ToLowerInvariant(); if (!string.IsNullOrEmpty(text)) { return text == ".mp3"; } return false; } public void Convert(string sourcePath, string targetPath, ConversionOptions options) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown if (!File.Exists(sourcePath)) { throw new FileNotFoundException("Source file " + sourcePath + " not found"); } AudioFileReader val = new AudioFileReader(sourcePath); try { MediaFoundationResampler val2 = new MediaFoundationResampler((IWaveProvider)(object)val, new WaveFormat(options.SampleRate, options.BitsPerSample, options.ChannelCount)); val2.ResamplerQuality = 60; WaveFileWriter.CreateWaveFile(targetPath, (IWaveProvider)(object)val2); } finally { ((IDisposable)val)?.Dispose(); } } } public class VideoConverter : IMediaConverter { private static readonly string[] _supportedExtensions = new string[5] { ".mp4", ".webm", ".avi", ".mov", ".ogg" }; private static bool? _isFfmpegInstalled; private static TimeSpan _ffmpegTimeout = TimeSpan.FromSeconds(30.0); public static bool IsCompatible(string path) { if (string.IsNullOrEmpty(path)) { return false; } string value = Path.GetExtension(path)?.ToLowerInvariant(); if (!string.IsNullOrEmpty(value)) { return _supportedExtensions.Contains(value); } return false; } private string BuildFfmpegArguments(string sourcePath, string targetPath, ConversionOptions options) { return $"-i \"{sourcePath}\" -vn -acodec {options.AudioCodec} -ar {options.SampleRate} -ac {options.ChannelCount} \"{targetPath}\""; } public void Convert(string sourcePath, string targetPath, ConversionOptions options) { if (!IsFfmpegInstalled()) { throw new AudioConversionException("Failed to convert video file. ffmpeg is not installed."); } if (!File.Exists(sourcePath)) { throw new FileNotFoundException("Source file " + sourcePath + " not found"); } RunFfmpegProcess(sourcePath, targetPath, options); } private void RunFfmpegProcess(string sourcePath, string targetPath, ConversionOptions options) { string arguments = BuildFfmpegArguments(sourcePath, targetPath, options); ProcessStartInfo startInfo = new ProcessStartInfo { FileName = "ffmpeg", Arguments = arguments, UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true }; using Process process = new Process { StartInfo = startInfo }; StringBuilder errorOutput = new StringBuilder(); process.ErrorDataReceived += delegate(object sender, DataReceivedEventArgs e) { if (!string.IsNullOrEmpty(e.Data)) { errorOutput.AppendLine(e.Data); } }; if (!process.Start()) { throw new AudioConversionException("Failed to start FFmpeg process"); } process.BeginErrorReadLine(); process.WaitForExit((int)_ffmpegTimeout.TotalMilliseconds); if (!process.HasExited) { try { process.Kill(); } catch { } throw new AudioConversionException("FFmpeg process timed out"); } if (process.ExitCode != 0) { string arg = errorOutput.ToString(); REPOSoundBoard.Logger.LogError((object)$"FFmpeg exited with error code {process.ExitCode}. Error: {arg}"); throw new AudioConversionException($"FFmpeg failed with exit code {process.ExitCode}: {arg}"); } if (!File.Exists(targetPath)) { throw new AudioConversionException("FFmpeg completed but the output file was not created"); } } private static bool IsFfmpegInstalled() { if (!_isFfmpegInstalled.HasValue) { try { using Process process = Process.Start(new ProcessStartInfo { FileName = "ffmpeg", Arguments = "-version", RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }); if (process == null) { _isFfmpegInstalled = false; } else { process.WaitForExit(2000); _isFfmpegInstalled = process.ExitCode == 0 || process.ExitCode == 1; } } catch { _isFfmpegInstalled = false; } } return _isFfmpegInstalled.Value; } } public class WavConverter : IMediaConverter { public static bool IsCompatible(string path) { if (string.IsNullOrEmpty(path)) { return false; } string text = Path.GetExtension(path)?.ToLowerInvariant(); if (!string.IsNullOrEmpty(text)) { return text == ".wav"; } return false; } public void Convert(string sourcePath, string targetPath, ConversionOptions options) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown if (!File.Exists(sourcePath)) { throw new FileNotFoundException("Source file " + sourcePath + " not found"); } AudioFileReader val = new AudioFileReader(sourcePath); try { MediaFoundationResampler val2 = new MediaFoundationResampler((IWaveProvider)(object)val, new WaveFormat(options.SampleRate, options.BitsPerSample, options.ChannelCount)); val2.ResamplerQuality = 60; WaveFileWriter.CreateWaveFile(targetPath, (IWaveProvider)(object)val2); } finally { ((IDisposable)val)?.Dispose(); } } } } namespace REPOSoundBoard.Core.Hotkeys { public class Hotkey { [JsonProperty(/*Could not decode attribute arguments.*/)] public List<KeyCode> Keys { get; set; } [CanBeNull] [JsonIgnore] private Action Callback { get; set; } [JsonIgnore] public bool IsPressed { get; set; } [JsonConstructor] public Hotkey() { Keys = new List<KeyCode>(); } public Hotkey(KeyCode key, [CanBeNull] Action callback) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) Keys = new List<KeyCode> { key }; Callback = callback; } public Hotkey(List<KeyCode> keys, [CanBeNull] Action callback) { Keys = new List<KeyCode>(keys); Callback = callback; } public Hotkey OnPressed(Action callback) { Callback = callback; return this; } public void Trigger() { if (Callback != null) { Callback(); } } public string ConcatKeys() { return string.Join(" + ", Keys); } } public class HotkeyManager : MonoBehaviour { private List<Hotkey> _hotkeys = new List<Hotkey>(); public void RegisterHotkey(Hotkey hotkey) { _hotkeys.Add(hotkey); } public void UnregisterHotkey(Hotkey hotkey) { _hotkeys.Remove(hotkey); } public void Update() { foreach (Hotkey hotkey in _hotkeys) { if (hotkey.Keys.Count != 0) { if (hotkey.IsPressed) { HandlePressedHotkey(hotkey); } else { HandleReleasedHotkey(hotkey); } } } } private static void HandlePressedHotkey(Hotkey hotkey) { if (hotkey.Keys.Any((KeyCode key) => !Input.GetKey(key))) { hotkey.IsPressed = false; } } private static void HandleReleasedHotkey(Hotkey hotkey) { if (hotkey.Keys.All((KeyCode key) => Input.GetKey(key))) { hotkey.IsPressed = true; hotkey.Trigger(); } } } } namespace REPOSoundBoard.Core.Exceptions { public class AudioConversionException : Exception { public AudioConversionException(string message) : base(message) { } } } namespace REPOSoundBoard.Config { public class AppConfig { private static string _configFilePath; public Hotkey UiHotkey; public SoundBoardConfig SoundBoard; public AppConfig() { _configFilePath = Path.Combine(Paths.ConfigPath, "Moli.REPOSoundBoard.json"); UiHotkey = new Hotkey((KeyCode)285, null); SoundBoard = new SoundBoardConfig(); } public static AppConfig LoadConfig() { AppConfig result = new AppConfig(); try { result = ConfigSerializer.DeserializeConfig(File.ReadAllText(_configFilePath)); return result; } catch (Exception ex) { REPOSoundBoard.Logger.LogWarning((object)("Failed to read config file" + ex.Message)); return result; } } public void SaveToFile() { string contents = ConfigSerializer.SerializeConfig(this); File.WriteAllText(_configFilePath, contents); } } public class ConfigSerializer { public static string SerializeConfig(AppConfig config) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown JsonSerializerSettings val = new JsonSerializerSettings { Formatting = (Formatting)1, NullValueHandling = (NullValueHandling)1 }; return JsonConvert.SerializeObject((object)config, val); } public static AppConfig DeserializeConfig(string json) { return JsonConvert.DeserializeObject<AppConfig>(json); } } public class SoundBoardConfig { public bool Enabled = true; public Hotkey StopHotkey = new Hotkey((KeyCode)104, null); public List<SoundButtonConfig> SoundButtons = new List<SoundButtonConfig>(); } public class SoundButtonConfig { public string Name; public bool Enabled = true; public string Path; public float Volume = 0.75f; public Hotkey Hotkey; } }