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<string, AudioClip> _cleanClipCache = new Dictionary<string, AudioClip>();
private static readonly Dictionary<string, AudioClip> _muffledClipCache = new Dictionary<string, AudioClip>();
private static readonly Dictionary<string, Task<float[]>> _pendingMuffleTasks = new Dictionary<string, Task<float[]>>();
private static readonly Dictionary<string, (int channels, int sampleRate)> _pendingMuffleInfo = new Dictionary<string, (int, int)>();
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<NetworkedPlayerInfo> 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<DanganronpaVotesRunner>();
Harmony val = new Harmony("com.kris.danganronpavotes");
val.PatchAll(Assembly.GetExecutingAssembly());
SceneManager.activeSceneChanged += UnityAction<Scene, Scene>.op_Implicit((Action<Scene, Scene>)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<AudioSource>();
_sourceA.playOnAwake = false;
_sourceA.loop = true;
_sourceA.volume = 0f;
_sourceB = val.AddComponent<AudioSource>();
_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<Exception>(ex);
}
log.LogError(val3);
}
_usingA = true;
_runner = val.AddComponent<DanganronpaVotesRunner>();
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<string>(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<string>(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<string>(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<Exception>(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<string> list = null;
foreach (KeyValuePair<string, Task<float[]>> pendingMuffleTask in _pendingMuffleTasks)
{
if (pendingMuffleTask.Value.IsCompleted)
{
(list ?? (list = new List<string>())).Add(pendingMuffleTask.Key);
}
}
if (list == null)
{
return;
}
bool flag = default(bool);
foreach (string item in list)
{
Task<float[]> 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<string>(item);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<AggregateException>(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<string>(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<string>(_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<int>(_matchTotalImpostors);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" impostores / ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_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<string>(reason);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] Impostores vivos: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(item);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" (de ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_matchTotalImpostors);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" iniciales) | Tripulantes vivos: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(item2);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" (de ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_matchTotalCrewmates);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" iniciales) | Margen: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" | Primera votación sin muertes: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(flag3);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" | Bonus 1ª votación: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num2);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" -> rol: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(flag4 ? "Impostor" : "Tripulante");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" -> pista: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(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<float>.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();
}
}
}