using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using Dissonance.Audio.Playback;
using GameNetcodeStuff;
using HarmonyLib;
using ReverbOnDeath.Configuration;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("ReverbOnDeath")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Adds a heavy reverb effect to the final sounds made before death.")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("ReverbOnDeath")]
[assembly: AssemblyTitle("ReverbOnDeath")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
namespace ReverbOnDeath
{
[BepInPlugin("ReverbOnDeath", "ReverbOnDeath", "1.0.1")]
public class Plugin : BaseUnityPlugin
{
private static Plugin Instance;
private readonly Harmony harmony = new Harmony("ReverbOnDeath");
private void Awake()
{
if ((Object)(object)Instance == (Object)null)
{
Instance = this;
}
harmony.PatchAll();
((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin ReverbOnDeath is loaded!");
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "ReverbOnDeath";
public const string PLUGIN_NAME = "ReverbOnDeath";
public const string PLUGIN_VERSION = "1.0.1";
}
}
namespace ReverbOnDeath.Patches
{
[HarmonyPatch]
internal class DissonancePatch
{
public static MethodBase TargetMethod()
{
return AccessTools.FirstMethod(typeof(VoicePlayback), (Func<MethodInfo, bool>)((MethodInfo method) => method.Name.Contains("SetTransform")));
}
private static bool Prefix(object __instance)
{
foreach (AudioConfig value in UpdatePlayerVoiceEffectsPatch.Configs.Values)
{
if (!value.EchoOn || !((object)((Component)((__instance is VoicePlayback) ? __instance : null)).transform).Equals((object?)value.AudioSourceT))
{
continue;
}
return false;
}
return true;
}
}
[HarmonyPatch(typeof(StartOfRound), "UpdatePlayerVoiceEffects")]
internal class UpdatePlayerVoiceEffectsPatch
{
private static bool updateStarted = false;
private static Dictionary<PlayerControllerB, AudioConfig> configs = new Dictionary<PlayerControllerB, AudioConfig>();
public static Dictionary<PlayerControllerB, AudioConfig> Configs => configs;
private static void Prefix()
{
if (configs == null)
{
configs = new Dictionary<PlayerControllerB, AudioConfig>();
}
if (!updateStarted)
{
((MonoBehaviour)HUDManager.Instance).StartCoroutine(UpdateNumerator());
updateStarted = true;
}
if ((Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null)
{
return;
}
for (int i = 0; i < StartOfRound.Instance.allPlayerScripts.Length; i++)
{
PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[i];
if ((Object)(object)val == (Object)null || (!val.isPlayerControlled && !val.isPlayerDead) || !((Object)(object)val != (Object)(object)GameNetworkManager.Instance.localPlayerController))
{
continue;
}
AudioSource currentVoiceChatAudioSource = val.currentVoiceChatAudioSource;
if (!((Object)(object)currentVoiceChatAudioSource == (Object)null))
{
if ((Object)(object)((Component)currentVoiceChatAudioSource).gameObject.GetComponent<AudioEchoFilter>() == (Object)null)
{
((Component)currentVoiceChatAudioSource).gameObject.AddComponent<AudioEchoFilter>();
AudioEchoFilter component = ((Component)currentVoiceChatAudioSource).gameObject.GetComponent<AudioEchoFilter>();
component.delay = 25f;
component.decayRatio = 0.94f;
component.wetMix = 1f;
component.dryMix = 0f;
((Behaviour)component).enabled = false;
}
if (val.isPlayerDead && !configs.ContainsKey(val))
{
configs.Add(val, new AudioConfig(val, Time.time + 2f, Time.time + 0.1f, ((Behaviour)((Component)currentVoiceChatAudioSource).GetComponent<AudioLowPassFilter>()).enabled, ((Behaviour)((Component)currentVoiceChatAudioSource).GetComponent<AudioHighPassFilter>()).enabled, currentVoiceChatAudioSource.panStereo, SoundManager.Instance.playerVoicePitchTargets[(int)(IntPtr)(long)val.playerClientId], GetPitch(val)));
}
}
}
}
private static void Postfix()
{
//IL_011a: Unknown result type (might be due to invalid IL or missing references)
if (configs == null)
{
configs = new Dictionary<PlayerControllerB, AudioConfig>();
}
if ((Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null)
{
return;
}
PlayerControllerB[] array = configs.Keys.ToArray();
foreach (PlayerControllerB val in array)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
AudioConfig audioConfig = configs[val];
if (audioConfig == null)
{
continue;
}
if ((val.isPlayerControlled || val.isPlayerDead) && !((Object)(object)val == (Object)(object)GameNetworkManager.Instance.localPlayerController))
{
if ((Object)(object)val.currentVoiceChatAudioSource == (Object)null)
{
continue;
}
AudioSource currentVoiceChatAudioSource = val.currentVoiceChatAudioSource;
if (audioConfig.EchoOn)
{
if ((Object)(object)val.deadBody != (Object)null)
{
((Component)currentVoiceChatAudioSource).transform.position = ((Component)val.deadBody).transform.position;
}
((Behaviour)((Component)currentVoiceChatAudioSource).gameObject.GetComponent<AudioEchoFilter>()).enabled = true;
if ((Object)(object)((Component)currentVoiceChatAudioSource).GetComponent<AudioLowPassFilter>() != (Object)null)
{
((Behaviour)((Component)currentVoiceChatAudioSource).GetComponent<AudioLowPassFilter>()).enabled = audioConfig.LpOn;
}
if ((Object)(object)((Component)currentVoiceChatAudioSource).GetComponent<AudioHighPassFilter>() != (Object)null)
{
((Behaviour)((Component)currentVoiceChatAudioSource).GetComponent<AudioHighPassFilter>()).enabled = audioConfig.HpOn;
}
currentVoiceChatAudioSource.panStereo = audioConfig.PanStereo;
if ((Object)(object)SoundManager.Instance != (Object)null)
{
SoundManager.Instance.playerVoicePitchTargets[(int)(IntPtr)(long)val.playerClientId] = audioConfig.PlayerVoicePitchTarget;
SoundManager.Instance.SetPlayerPitch(audioConfig.PlayerPitch, (int)val.playerClientId);
}
currentVoiceChatAudioSource.spatialBlend = 1f;
val.currentVoiceChatIngameSettings.set2D = false;
val.voicePlayerState.Volume = (audioConfig.VoiceOn ? 1f : 0f);
currentVoiceChatAudioSource.volume = 1f;
}
else if (((Behaviour)((Component)currentVoiceChatAudioSource).gameObject.GetComponent<AudioEchoFilter>()).enabled)
{
((Behaviour)((Component)currentVoiceChatAudioSource).gameObject.GetComponent<AudioEchoFilter>()).enabled = false;
}
}
else if (!val.isPlayerDead)
{
configs.Remove(val);
}
}
}
private static IEnumerator UpdateNumerator()
{
yield return 0;
while (true)
{
UpdatePlayersStatus();
yield return (object)new WaitForFixedUpdate();
}
}
private static void UpdatePlayersStatus()
{
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
if (configs == null)
{
return;
}
bool flag = false;
KeyValuePair<PlayerControllerB, AudioConfig>[] array = configs.ToArray();
for (int i = 0; i < array.Length; i++)
{
KeyValuePair<PlayerControllerB, AudioConfig> keyValuePair = array[i];
if (!((Object)(object)keyValuePair.Key == (Object)null))
{
if (!keyValuePair.Key.isPlayerDead)
{
configs.Remove(keyValuePair.Key);
flag = true;
}
else if ((Object)(object)keyValuePair.Value.DeadBodyT != (Object)null && (Object)(object)keyValuePair.Value.AudioSourceT != (Object)null)
{
keyValuePair.Value.AudioSourceT.position = keyValuePair.Value.DeadBodyT.position;
}
}
}
if (flag)
{
StartOfRound.Instance.UpdatePlayerVoiceEffects();
}
}
private static float GetPitch(PlayerControllerB playerControllerB)
{
int num = (int)playerControllerB.playerClientId;
float result = default(float);
SoundManager.Instance.diageticMixer.GetFloat($"PlayerPitch{num}", ref result);
return result;
}
}
}
namespace ReverbOnDeath.Configuration
{
public class AudioConfig
{
private PlayerControllerB playerControllerB;
private float stopEchoAt = 0f;
private float stopVoiceAt = 0f;
private bool lpOn;
private bool hpOn;
private float panStereo;
private float playerVoicePitchTarget;
private float playerPitch;
public bool EchoOn => Time.time < stopEchoAt;
public bool VoiceOn => Time.time < stopVoiceAt;
public float StopEchoAt => stopEchoAt;
public float StopVoiceAt => stopVoiceAt;
public bool LpOn => lpOn;
public bool HpOn => hpOn;
public float PanStereo => panStereo;
public float PlayerVoicePitchTarget => playerVoicePitchTarget;
public float PlayerPitch => playerPitch;
public Transform DeadBodyT => ((Component)playerControllerB.deadBody).transform;
public Transform AudioSourceT => ((Component)playerControllerB.currentVoiceChatAudioSource).transform;
public AudioConfig(PlayerControllerB playerControllerB, float stopEchoAt, float stopVoiceAt, bool lpOn, bool hpOn, float panStereo, float playerVoicePitchTarget, float playerPitch)
{
this.playerControllerB = playerControllerB;
this.stopEchoAt = stopEchoAt;
this.stopVoiceAt = stopVoiceAt;
this.lpOn = lpOn;
this.hpOn = hpOn;
this.panStereo = panStereo;
this.playerVoicePitchTarget = playerVoicePitchTarget;
this.playerPitch = playerPitch;
}
}
}