using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading.Tasks; using BepInEx; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using BepInEx.Unity.IL2CPP.Utils.Collections; using HarmonyLib; using Il2CppInterop.Runtime.Attributes; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem.Collections.Generic; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Audio; using UnityEngine.Events; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("DanganronpaVotes")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("DanganronpaVotes")] [assembly: AssemblyTitle("DanganronpaVotes")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DanganronpaVotes { [BepInPlugin("com.kris.danganronpavotes", "DanganronpaVotes", "1.1.0")] public class DanganronpaVotesPlugin : BasePlugin { private enum Tier { Calm, Tense, Climax } public const string PluginGuid = "com.kris.danganronpavotes"; public const string PluginName = "DanganronpaVotes"; public const string PluginVersion = "1.1.0"; private static readonly string[] CrewmateTrackFiles = new string[3] { "trial_calm.wav", "trial_tense.wav", "trial_climax.wav" }; private static readonly string[] ImpostorTrackFiles = new string[3] { "trial_impostor_calm.wav", "trial_impostor_tense.wav", "trial_impostor_climax.wav" }; private const float FadeInSeconds = 2f; private const float FadeOutSeconds = 1f; private const float CrossfadeSeconds = 1.5f; private const float TargetVolume = 0.8f; private const float MuffledCutoffFrequency = 800f; private const float MuffleTransitionSeconds = 0.4f; private const string MainMenuSceneName = "MainMenu"; private static AudioSource _sourceA; private static AudioSource _sourceB; private static bool _usingA = true; private static DanganronpaVotesRunner _runner; private static string _currentTrackName; private static bool _isMuffled; private static bool _pendingLocalVoteMuffle; private static bool _meetingActive; private static bool _isFirstMeetingOfMatch = true; private static bool _anyDeathObservedThisMatch; private static bool _matchTotalsCaptured; private static int _matchTotalImpostors; private static int _matchTotalCrewmates; private static readonly Dictionary _cleanClipCache = new Dictionary(); private static readonly Dictionary _muffledClipCache = new Dictionary(); private static readonly Dictionary> _pendingMuffleTasks = new Dictionary>(); private static readonly Dictionary _pendingMuffleInfo = new Dictionary(); internal static ManualLogSource Log; private const int FirstMeetingMarginBonus = 2; private static AudioSource ActiveSource => _usingA ? _sourceA : _sourceB; private static AudioSource InactiveSource => _usingA ? _sourceB : _sourceA; private static Tier BaseTierForMargin(int margin) { if (margin >= 5) { return Tier.Calm; } if (margin >= 3) { return Tier.Tense; } return Tier.Climax; } public static bool IsLocalPlayerImpostor() { PlayerControl localPlayer = PlayerControl.LocalPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)localPlayer.Data == (Object)null || (Object)(object)localPlayer.Data.Role == (Object)null) { return false; } return localPlayer.Data.Role.IsImpostor; } public static bool IsLocalPlayerGhost() { PlayerControl localPlayer = PlayerControl.LocalPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)localPlayer.Data == (Object)null) { return false; } return localPlayer.Data.IsDead; } public static (int aliveImpostors, int aliveCrewmates, int totalImpostors, int totalCrewmates) CountRoles() { int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; Enumerator enumerator = GameData.Instance.AllPlayers.GetEnumerator(); while (enumerator.MoveNext()) { NetworkedPlayerInfo current = enumerator.Current; if (current.Disconnected) { continue; } if ((Object)(object)current.Role != (Object)null && current.Role.IsImpostor) { num3++; if (!current.IsDead) { num++; } } else { num4++; if (!current.IsDead) { num2++; } } } return (aliveImpostors: num, aliveCrewmates: num2, totalImpostors: num3, totalCrewmates: num4); } public static string PickTrackForVote(int aliveImpostors, int aliveCrewmates, int totalImpostors, bool isLocalImpostor, bool forceCalmBase = false, int marginBonus = 0) { int num = aliveCrewmates - aliveImpostors; Tier tier = ((!forceCalmBase) ? BaseTierForMargin(num + marginBonus) : Tier.Calm); if (!isLocalImpostor) { return CrewmateTrackFiles[(int)tier]; } Tier tier2; if (totalImpostors <= 1) { tier2 = tier; } else { bool flag = aliveImpostors <= 1; tier2 = ((num <= 1) ? Tier.Climax : ((Tier)((!flag) ? Math.Min(1, (int)tier) : Math.Min(2, (int)(tier + 1))))); } return ImpostorTrackFiles[(int)tier2]; } private static void NormalizeAudioState() { if (!((Object)(object)_runner == (Object)null) && !((Object)(object)_sourceA == (Object)null) && !((Object)(object)_sourceB == (Object)null)) { _runner.CancelFade(); if (ActiveSource.isPlaying) { ActiveSource.volume = 0.8f; } if (InactiveSource.isPlaying) { _runner.StopAndSilenceImmediate(InactiveSource); } } } public override void Load() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown Log = ((BasePlugin)this).Log; ClassInjector.RegisterTypeInIl2Cpp(); Harmony val = new Harmony("com.kris.danganronpavotes"); val.PatchAll(Assembly.GetExecutingAssembly()); SceneManager.activeSceneChanged += UnityAction.op_Implicit((Action)OnActiveSceneChanged); Log.LogInfo((object)"DanganronpaVotes cargado correctamente (IL2CPP)."); } private static void OnActiveSceneChanged(Scene oldScene, Scene newScene) { if (((Scene)(ref newScene)).name == "MainMenu") { Log.LogInfo((object)"Vuelta al menú principal detectada, parando música en seco."); StopVoteMusicImmediate(); } } private static void EnsureAudioSetup() { //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Expected O, but got Unknown //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown if ((Object)(object)_sourceA != (Object)null && (Object)(object)_sourceB != (Object)null) { return; } GameObject val = new GameObject("DanganronpaVotesAudio"); Object.DontDestroyOnLoad((Object)(object)val); _sourceA = val.AddComponent(); _sourceA.playOnAwake = false; _sourceA.loop = true; _sourceA.volume = 0f; _sourceB = val.AddComponent(); _sourceB.playOnAwake = false; _sourceB.loop = true; _sourceB.volume = 0f; try { AudioMixerGroup val2 = (((Object)(object)SoundManager.Instance != (Object)null) ? SoundManager.Instance.MusicChannel : null); if ((Object)(object)val2 != (Object)null) { _sourceA.outputAudioMixerGroup = val2; _sourceB.outputAudioMixerGroup = val2; Log.LogInfo((object)"AudioSources enrutados al canal de música del juego: el slider de volumen ahora nos afecta."); } else { Log.LogWarning((object)"SoundManager.Instance.MusicChannel es null; la música del mod no seguirá el slider de volumen del juego."); } } catch (Exception ex) { ManualLogSource log = Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(39, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("No se pudo enrutar al canal de música: "); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted(ex); } log.LogError(val3); } _usingA = true; _runner = val.AddComponent(); Log.LogInfo((object)"Objeto de audio (re)creado."); } public static void PlayVoteMusic() { EnsureAudioSetup(); _meetingActive = true; _pendingLocalVoteMuffle = false; UpdateVoteMusic("Inicio de votación"); } private static AudioClip GetOrLoadCleanClip(string track) { //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Expected O, but got Unknown //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Expected O, but got Unknown bool flag = default(bool); if (_cleanClipCache.TryGetValue(track, out var value)) { if ((Object)(object)value != (Object)null) { return value; } _cleanClipCache.Remove(track); ManualLogSource log = Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(92, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("El clip limpio en caché de '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(track); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' ya no era válido (liberado por Unity); recargando desde disco."); } log.LogInfo(val); } string text = Path.Combine(Paths.PluginPath, "DanganronpaVotes", "Audio", track); if (!File.Exists(text)) { ManualLogSource log2 = Log; BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(36, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("No se encontro el archivo de audio: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(text); } log2.LogWarning(val2); return null; } try { byte[] fileBytes = File.ReadAllBytes(text); if (!WavUtility.TryParse(fileBytes, out var samples, out var channels, out var sampleRate)) { ManualLogSource log3 = Log; BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(54, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("No se pudo decodificar el wav (formato no soportado): "); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted(text); } log3.LogError(val3); return null; } AudioClip val4 = WavUtility.CreateClip(track, samples, channels, sampleRate); _cleanClipCache[track] = val4; EnsureMuffledClipQueued(track, samples, channels, sampleRate); return val4; } catch (Exception ex) { ManualLogSource log4 = Log; BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(22, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Error cargando audio: "); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted(ex); } log4.LogError(val3); return null; } } private static void EnsureMuffledClipQueued(string track, float[] samples, int channels, int sampleRate) { if (_muffledClipCache.TryGetValue(track, out var value)) { if ((Object)(object)value != (Object)null) { return; } _muffledClipCache.Remove(track); } if (!_pendingMuffleTasks.ContainsKey(track)) { _pendingMuffleInfo[track] = (channels, sampleRate); _pendingMuffleTasks[track] = Task.Run(() => WavUtility.ApplyLowPass(samples, channels, sampleRate, 800f)); } } internal static void PollPendingMuffleClips() { //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Expected O, but got Unknown //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown if (_pendingMuffleTasks.Count == 0) { return; } List list = null; foreach (KeyValuePair> pendingMuffleTask in _pendingMuffleTasks) { if (pendingMuffleTask.Value.IsCompleted) { (list ?? (list = new List())).Add(pendingMuffleTask.Key); } } if (list == null) { return; } bool flag = default(bool); foreach (string item in list) { Task task = _pendingMuffleTasks[item]; _pendingMuffleTasks.Remove(item); var (channels, sampleRate) = _pendingMuffleInfo[item]; _pendingMuffleInfo.Remove(item); if (task.IsFaulted) { ManualLogSource log = Log; BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(46, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error generando la versión amortiguada de '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(item); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(task.Exception); } log.LogError(val); continue; } AudioClip value = WavUtility.CreateClip(item + "_muffled", task.Result, channels, sampleRate); _muffledClipCache[item] = value; ManualLogSource log2 = Log; BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(32, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Versión amortiguada de '"); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(item); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' lista."); } log2.LogInfo(val2); bool flag2 = IsLocalPlayerGhost(); bool pendingLocalVoteMuffle = _pendingLocalVoteMuffle; if (item == _currentTrackName && !_isMuffled && (flag2 || pendingLocalVoteMuffle) && TryApplyMuffle()) { _pendingLocalVoteMuffle = false; Log.LogInfo((object)(flag2 ? "Eres un fantasma: música difuminada en cuanto ha terminado de calcularse." : "Voto pendiente: música difuminada en cuanto ha terminado de calcularse (llegó tarde al votar).")); } } } private static bool TryApplyMuffle() { if ((Object)(object)_runner == (Object)null || _currentTrackName == null) { return false; } NormalizeAudioState(); if ((Object)(object)ActiveSource == (Object)null || !ActiveSource.isPlaying || _isMuffled) { return false; } if (!_muffledClipCache.TryGetValue(_currentTrackName, out var value)) { return false; } if ((Object)(object)value == (Object)null) { _muffledClipCache.Remove(_currentTrackName); return false; } AudioSource activeSource = ActiveSource; AudioSource inactiveSource = InactiveSource; inactiveSource.clip = value; inactiveSource.time = activeSource.time % value.length; inactiveSource.volume = 0f; inactiveSource.Play(); _runner.StartCrossfade(activeSource, inactiveSource, 0.4f, 0.8f); _usingA = !_usingA; _isMuffled = true; return true; } public static void OnLocalVoteCast() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown Log.LogInfo((object)"OnLocalVoteCast() invocado."); if (IsLocalPlayerGhost()) { return; } if (!TryApplyMuffle()) { _pendingLocalVoteMuffle = true; ManualLogSource log = Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(191, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("OnLocalVoteCast: no se aplica todavía (runner/pista nulos, nada sonando, ya difuminado, o la versión amortiguada de '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(_currentTrackName); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' aún no está lista); queda pendiente para aplicarse en cuanto esté lista."); } log.LogInfo(val); } else { Log.LogInfo((object)"Voto emitido: difuminando la música."); } } public static void OnPlayerLeft() { if (!((Object)(object)_sourceA == (Object)null) && !((Object)(object)_sourceB == (Object)null) && _meetingActive) { Log.LogInfo((object)"Jugador abandonó la partida, recalculando nivel de tensión."); UpdateVoteMusic("Recalculo por abandono de jugador"); } } private static void UpdateVoteMusic(string reason) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown (int aliveImpostors, int aliveCrewmates, int totalImpostors, int totalCrewmates) tuple = CountRoles(); int item = tuple.aliveImpostors; int item2 = tuple.aliveCrewmates; int item3 = tuple.totalImpostors; int item4 = tuple.totalCrewmates; int num = item2 - item; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val; if (!_matchTotalsCaptured) { _matchTotalImpostors = item3; _matchTotalCrewmates = item4; _matchTotalsCaptured = true; ManualLogSource log = Log; val = new BepInExInfoLogInterpolatedStringHandler(65, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Snapshot de partida fijado: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(_matchTotalImpostors); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" impostores / "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(_matchTotalCrewmates); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" tripulantes iniciales."); } log.LogInfo(val); } if (item2 < _matchTotalCrewmates || item < _matchTotalImpostors) { _anyDeathObservedThisMatch = true; } bool flag2 = !_anyDeathObservedThisMatch; bool flag3 = _isFirstMeetingOfMatch && flag2; int num2 = ((_isFirstMeetingOfMatch && !flag2) ? 2 : 0); bool flag4 = IsLocalPlayerImpostor(); string text = PickTrackForVote(item, item2, _matchTotalImpostors, flag4, flag3, num2); ManualLogSource log2 = Log; val = new BepInExInfoLogInterpolatedStringHandler(161, 10, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("["); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(reason); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] Impostores vivos: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(item); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" (de "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(_matchTotalImpostors); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" iniciales) | Tripulantes vivos: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(item2); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" (de "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(_matchTotalCrewmates); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" iniciales) | Margen: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(num); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" | Primera votación sin muertes: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(flag3); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" | Bonus 1ª votación: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(num2); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" -> rol: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(flag4 ? "Impostor" : "Tripulante"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" -> pista: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(text); } log2.LogInfo(val); SwitchToTrack(text); if (IsLocalPlayerGhost() && TryApplyMuffle()) { Log.LogInfo((object)"Eres un fantasma: música difuminada desde el inicio de la votación."); } } private static void SwitchToTrack(string track) { NormalizeAudioState(); bool isPlaying = ActiveSource.isPlaying; if (isPlaying && _currentTrackName == track) { return; } AudioClip orLoadCleanClip = GetOrLoadCleanClip(track); if (!((Object)(object)orLoadCleanClip == (Object)null)) { if (!isPlaying) { ActiveSource.clip = orLoadCleanClip; ActiveSource.volume = 0f; ActiveSource.Play(); _runner.StartFadeIn(ActiveSource, 2f, 0.8f); } else { AudioSource activeSource = ActiveSource; AudioSource inactiveSource = InactiveSource; inactiveSource.clip = orLoadCleanClip; inactiveSource.volume = 0f; inactiveSource.Play(); _runner.StartCrossfade(activeSource, inactiveSource, 1.5f, 0.8f); _usingA = !_usingA; } _currentTrackName = track; _isMuffled = false; } } public static void StopVoteMusic() { if (!((Object)(object)_sourceA == (Object)null) && !((Object)(object)_sourceB == (Object)null)) { _meetingActive = false; _pendingLocalVoteMuffle = false; _isFirstMeetingOfMatch = false; if (ActiveSource.isPlaying) { _runner.StartFadeOut(ActiveSource, 1f); } if (InactiveSource.isPlaying) { _runner.StopAndSilenceImmediate(InactiveSource); } } } public static void StopVoteMusicImmediate() { if (!((Object)(object)_sourceA == (Object)null) && !((Object)(object)_sourceB == (Object)null)) { _meetingActive = false; _pendingLocalVoteMuffle = false; _runner?.CancelFade(); _runner?.StopAndSilenceImmediate(_sourceA); _runner?.StopAndSilenceImmediate(_sourceB); _currentTrackName = null; _isMuffled = false; _isFirstMeetingOfMatch = true; _anyDeathObservedThisMatch = false; _matchTotalsCaptured = false; _matchTotalImpostors = 0; _matchTotalCrewmates = 0; } } } public class DanganronpaVotesRunner : MonoBehaviour { private Coroutine _activeFade; public DanganronpaVotesRunner(IntPtr ptr) : base(ptr) { } public void Update() { DanganronpaVotesPlugin.PollPendingMuffleClips(); } public void StartFadeIn(AudioSource source, float duration, float targetVolume) { CancelFade(); _activeFade = ((MonoBehaviour)this).StartCoroutine(CollectionExtensions.WrapToIl2Cpp(FadeInRoutine(source, duration, targetVolume))); } public void StartFadeOut(AudioSource source, float duration) { CancelFade(); _activeFade = ((MonoBehaviour)this).StartCoroutine(CollectionExtensions.WrapToIl2Cpp(FadeOutRoutine(source, duration))); } public void StartCrossfade(AudioSource outSource, AudioSource inSource, float duration, float targetVolume) { CancelFade(); _activeFade = ((MonoBehaviour)this).StartCoroutine(CollectionExtensions.WrapToIl2Cpp(CrossfadeRoutine(outSource, inSource, duration, targetVolume))); } public void StopAndSilenceImmediate(AudioSource source) { if (!((Object)(object)source == (Object)null)) { if (source.isPlaying) { source.Stop(); } source.volume = 0f; } } public void CancelFade() { if (_activeFade != null) { ((MonoBehaviour)this).StopCoroutine(_activeFade); _activeFade = null; } } [HideFromIl2Cpp] private IEnumerator FadeInRoutine(AudioSource source, float duration, float targetVolume) { float elapsed = 0f; float startVolume = source.volume; while (elapsed < duration) { elapsed += Time.deltaTime; source.volume = Mathf.Lerp(startVolume, targetVolume, elapsed / duration); yield return null; } source.volume = targetVolume; _activeFade = null; } [HideFromIl2Cpp] private IEnumerator FadeOutRoutine(AudioSource source, float duration) { float elapsed = 0f; float startVolume = source.volume; while (elapsed < duration) { elapsed += Time.deltaTime; source.volume = Mathf.Lerp(startVolume, 0f, elapsed / duration); yield return null; } source.volume = 0f; source.Stop(); _activeFade = null; } [HideFromIl2Cpp] private IEnumerator CrossfadeRoutine(AudioSource outSource, AudioSource inSource, float duration, float targetVolume) { float elapsed = 0f; float outStartVolume = outSource.volume; float inStartVolume = inSource.volume; while (elapsed < duration) { elapsed += Time.deltaTime; float t = elapsed / duration; outSource.volume = Mathf.Lerp(outStartVolume, 0f, t); inSource.volume = Mathf.Lerp(inStartVolume, targetVolume, t); yield return null; } outSource.volume = 0f; outSource.Stop(); inSource.volume = targetVolume; _activeFade = null; } } public static class WavUtility { public static bool TryParse(byte[] fileBytes, out float[] samples, out int channels, out int sampleRate) { samples = null; channels = 0; sampleRate = 0; if (fileBytes.Length < 44) { return false; } string text = Encoding.ASCII.GetString(fileBytes, 0, 4); string text2 = Encoding.ASCII.GetString(fileBytes, 8, 4); if (text != "RIFF" || text2 != "WAVE") { return false; } int num = 0; int num2 = -1; int num3 = 0; int num4 = 12; while (num4 + 8 <= fileBytes.Length) { string text3 = Encoding.ASCII.GetString(fileBytes, num4, 4); int num5 = BitConverter.ToInt32(fileBytes, num4 + 4); int num6 = num4 + 8; if (text3 == "fmt ") { channels = BitConverter.ToInt16(fileBytes, num6 + 2); sampleRate = BitConverter.ToInt32(fileBytes, num6 + 4); num = BitConverter.ToInt16(fileBytes, num6 + 14); } else if (text3 == "data") { num2 = num6; num3 = ((num5 >= 0 && num6 + num5 <= fileBytes.Length) ? num5 : (fileBytes.Length - num6)); break; } if (num5 < 0 || num6 + num5 > fileBytes.Length) { break; } num4 = num6 + num5 + num5 % 2; } if (num2 < 0 || channels <= 0 || sampleRate <= 0 || num <= 0) { return false; } int num7 = num / 8; if (num7 <= 0 || num2 + num3 > fileBytes.Length) { return false; } int num8 = num3 / num7; samples = new float[num8]; switch (num) { case 16: { for (int j = 0; j < num8; j++) { short num10 = BitConverter.ToInt16(fileBytes, num2 + j * 2); samples[j] = (float)num10 / 32768f; } break; } case 8: { for (int k = 0; k < num8; k++) { samples[k] = (float)(fileBytes[num2 + k] - 128) / 128f; } break; } case 32: { for (int i = 0; i < num8; i++) { int num9 = BitConverter.ToInt32(fileBytes, num2 + i * 4); samples[i] = (float)num9 / 2.1474836E+09f; } break; } default: return false; } return true; } public static AudioClip CreateClip(string name, float[] samples, int channels, int sampleRate) { int num = samples.Length / channels; AudioClip val = AudioClip.Create(name, num, channels, sampleRate, false); val.SetData(Il2CppStructArray.op_Implicit(samples), 0); return val; } public static float[] ApplyLowPass(float[] samples, int channels, int sampleRate, float cutoffHz) { float[] array = new float[samples.Length]; float num = 1f / ((float)Math.PI * 2f * Mathf.Max(cutoffHz, 10f)); float num2 = 1f / (float)Mathf.Max(sampleRate, 1); float num3 = num2 / (num + num2); for (int i = 0; i < channels; i++) { float num4 = 0f; for (int j = i; j < samples.Length; j += channels) { num4 = (array[j] = num4 + num3 * (samples[j] - num4)); } } return array; } } [HarmonyPatch(typeof(MeetingHud), "Start")] public static class MeetingHudStartPatch { public static void Postfix(MeetingHud __instance) { DanganronpaVotesPlugin.PlayVoteMusic(); } } [HarmonyPatch(typeof(MeetingHud), "Close")] public static class MeetingHudClosePatch { public static void Postfix(MeetingHud __instance) { DanganronpaVotesPlugin.StopVoteMusic(); } } [HarmonyPatch(typeof(MeetingHud), "VotingComplete")] public static class MeetingHudVotingCompletePatch { public static void Postfix() { DanganronpaVotesPlugin.Log.LogInfo((object)"VotingComplete disparado: empieza la pantalla de resultados, parando música."); DanganronpaVotesPlugin.StopVoteMusic(); } } [HarmonyPatch(typeof(AmongUsClient), "OnPlayerLeft")] public static class AmongUsClientOnPlayerLeftPatch { public static void Postfix() { DanganronpaVotesPlugin.OnPlayerLeft(); } } [HarmonyPatch(typeof(PlayerVoteArea), "VoteForMe")] public static class PlayerVoteAreaVoteForMePatch { public static void Postfix(PlayerVoteArea __instance) { DanganronpaVotesPlugin.Log.LogInfo((object)"VoteForMe Postfix disparado: voto local confirmado."); DanganronpaVotesPlugin.OnLocalVoteCast(); } } }