Decompiled source of ExplodesProximityChat v1.0.3

ExplodesProxChat.dll

Decompiled a month ago
using System;
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 AIGraph;
using Agents;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Dissonance;
using Dissonance.Audio.Capture;
using Dissonance.Audio.Playback;
using Dissonance.Config;
using ExplodesProxChat.Effects;
using ExplodesProxChat.Effects.Audio;
using ExplodesProxChat.Effects.Reverb;
using ExplodesProxChat.Effects.Reverb.Line;
using ExplodesProxChat.Effects.Reverb.Line.Presets;
using ExplodesProxChat.Noise;
using ExplodesProxChat.Spatialization;
using ExplodesProxChat.Spatialization.Fading;
using ExplodesProxChat.Voice;
using ExplodesProxChat.Voice.Handler;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppInterop.Runtime.Runtime;
using Il2CppInterop.Runtime.Runtime.VersionSpecific.Class;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using LevelGeneration;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ExplodesProxChat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+e8444e2946601af0526eac50242e635287b0bb00")]
[assembly: AssemblyProduct("ExplodesProxChat")]
[assembly: AssemblyTitle("ExplodesProxChat")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace ExplodesProxChat
{
	[BepInPlugin("Explode3.ExplodesProxChat", "ExplodesProxChat", "1.0.0")]
	public class ExplodesProxChat : BasePlugin
	{
		public static ExplodesProxChat Instance;

		private DistanceSpatializationStrategy sameRootStrategy;

		private DistanceSpatializationStrategy diffRootStrategy;

		private ConfigEntry<float> _nothingValue;

		private ConfigEntry<float> _sneakingValue;

		private ConfigEntry<float> _walkingValue;

		private ConfigEntry<float> _runningValue;

		private ConfigEntry<float> _sameRoomDistance;

		private ConfigEntry<float> _sameRoomRolloff;

		private ConfigEntry<float> _diffRoomDistance;

		private ConfigEntry<float> _diffRoomRolloff;

		public ProxChatImpl Impl { get; private set; }

		public ExplodesProxChat()
		{
			Instance = this;
		}

		public unsafe override void Load()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			ManualLogSource log = ((BasePlugin)this).Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(41, 0, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ProxChat loaded, now... will it work? >_<");
			}
			log.LogInfo(val);
			Harmony.CreateAndPatchAll(typeof(Patches), "ExplodesProxChat");
			INativeClassStruct val2 = UnityVersionHandler.Wrap((Il2CppClass*)(void*)Il2CppClassPointerStore.GetNativeClassPointer(typeof(IDissonancePlayer)));
			RegisterTypeOptions val3 = new RegisterTypeOptions();
			val3.set_Interfaces(new Il2CppInterfaceCollection((IEnumerable<INativeClassStruct>)(object)new INativeClassStruct[1] { val2 }));
			RegisterTypeOptions val4 = val3;
			((BasePlugin)this).Log.LogInfo((object)"Trying to inject ProxChatPlayer");
			ClassInjector.RegisterTypeInIl2Cpp(typeof(ProxChatPlayer), val4);
			((BasePlugin)this).Log.LogInfo((object)"Trying to inject VolumeUpdateComponent");
			ClassInjector.RegisterTypeInIl2Cpp(typeof(VolumeUpdateComponent));
			((BasePlugin)this).Log.LogInfo((object)"Trying to inject LocalTransformComponent");
			ClassInjector.RegisterTypeInIl2Cpp(typeof(LocalTransformComponent));
			((BasePlugin)this).Log.LogInfo((object)("Trying to inject CustomReverbFilter: " + typeof(ReverbVoiceFilterScript)));
			ClassInjector.RegisterTypeInIl2Cpp(typeof(ReverbVoiceFilterScript));
			((BasePlugin)this).Log.LogInfo((object)"Adding ProxChatImpl");
			Impl = ((BasePlugin)this).AddComponent<ProxChatImpl>();
			ConfigEntry<bool> reverbEntry = ((BasePlugin)this).Config.Bind<bool>("Effects", "Reverb", true, "Enable reverb effect");
			Impl.VoiceEffectsManager.Reverb.Enable = reverbEntry.Value;
			reverbEntry.SettingChanged += delegate
			{
				Impl.VoiceEffectsManager.Reverb.Enable = reverbEntry.Value;
			};
			_nothingValue = ((BasePlugin)this).Config.Bind<float>("Noises", "Nothing DB", -18f, "Decibel value at which you are ignored by sleepers.");
			_sneakingValue = ((BasePlugin)this).Config.Bind<float>("Noises", "Sneaking DB", -26f, "Decibel value at which you count as sneaking for sleepers.");
			_walkingValue = ((BasePlugin)this).Config.Bind<float>("Noises", "Walking DB", -21f, "Decibel value at which you count as walking for sleepers.");
			_runningValue = ((BasePlugin)this).Config.Bind<float>("Noises", "Running DB", -16f, "Decibel value at which you count as running for sleepers.");
			SleeperWakeUpToggle();
			_sameRoomDistance = ((BasePlugin)this).Config.Bind<float>("Distances", "Distance: Same room", 12f, "Distance value");
			_sameRoomRolloff = ((BasePlugin)this).Config.Bind<float>("Distances", "Rolloff: Same room", 5f, "Rolloff value");
			_diffRoomDistance = ((BasePlugin)this).Config.Bind<float>("Distances", "Distance: Different room", 1f, "Distance value");
			_diffRoomRolloff = ((BasePlugin)this).Config.Bind<float>("Distances", "Rolloff: Different room", 1.5f, "Rolloff value");
			sameRootStrategy = new DistanceSpatializationStrategy(new ExponentialFalloffAttenuationFormula(_sameRoomDistance.Value, _sameRoomRolloff.Value));
			diffRootStrategy = new DistanceSpatializationStrategy(new ExponentialFalloffAttenuationFormula(_diffRoomDistance.Value, _diffRoomRolloff.Value));
			_sameRoomDistance.SettingChanged += EventSameRoom;
			_sameRoomRolloff.SettingChanged += EventSameRoom;
			_diffRoomDistance.SettingChanged += EventDiffRoom;
			_diffRoomRolloff.SettingChanged += EventDiffRoom;
			void EventDiffRoom(object? o, EventArgs eventArgs)
			{
				diffRootStrategy.Formula = new ExponentialFalloffAttenuationFormula(_diffRoomDistance.Value, _diffRoomRolloff.Value);
			}
			void EventSameRoom(object? o, EventArgs eventArgs)
			{
				sameRootStrategy.Formula = new ExponentialFalloffAttenuationFormula(_sameRoomDistance.Value, _sameRoomRolloff.Value);
			}
		}

		private void SleeperWakeUpToggle()
		{
			ConfigEntry<bool> configEntry = ((BasePlugin)this).Config.Bind<bool>("Toggles", "Wake up sleepers", false, "Whether talking wakes up sleepers");
			EnableSleepers(configEntry.Value);
			configEntry.SettingChanged += delegate
			{
				EnableSleepers(configEntry.Value);
			};
			_nothingValue.SettingChanged += delegate
			{
				EnableSleepers(configEntry.Value);
			};
			_sneakingValue.SettingChanged += delegate
			{
				EnableSleepers(configEntry.Value);
			};
			_walkingValue.SettingChanged += delegate
			{
				EnableSleepers(configEntry.Value);
			};
			_runningValue.SettingChanged += delegate
			{
				EnableSleepers(configEntry.Value);
			};
		}

		private void EnableSleepers(bool enable)
		{
			if (enable)
			{
				Impl.WakeUpSleepers(new NoiseLevel[4]
				{
					new NoiseLevel(_nothingValue.Value, (NoiseType)0),
					new NoiseLevel(_sneakingValue.Value, (NoiseType)2),
					new NoiseLevel(_walkingValue.Value, (NoiseType)3),
					new NoiseLevel(_runningValue.Value, (NoiseType)4)
				});
			}
			else
			{
				Impl.WakeUpSleepers(null);
			}
		}

		public ProximityVoiceHandler CreatePair(PlayerAgent local, PlayerAgent player, DissonanceComms comms)
		{
			return new ProximityVoiceHandler(new PlayerAgentsPair(local, player), comms, new RoomSpatializationStrategy(sameRootStrategy, diffRootStrategy));
		}

		[HideFromIl2Cpp]
		public void Reload()
		{
			Debug.Log(Object.op_Implicit("Reloading config from file..."));
			((BasePlugin)this).Config.Reload();
		}

		[HideFromIl2Cpp]
		public bool IsReload()
		{
			return Input.GetKeyDown((KeyCode)282);
		}
	}
	public class Patches
	{
		[HarmonyPatch(typeof(DissonanceComms), "Start")]
		[HarmonyPrefix]
		public static void DissonanceCommsStartPatch(DissonanceComms __instance)
		{
			__instance.LocalPlayerName = SteamManager.LocalPlayerName;
		}

		[HarmonyPatch(typeof(SNet_SyncManager), "OnPlayerSpawnedAgent")]
		[HarmonyPostfix]
		public static void AddedPlayer(SNet_Player player)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			PlayerAgent local = new PlayerAgent(((Il2CppObjectBase)player.PlayerAgent).Pointer);
			((BasePlugin)ExplodesProxChat.Instance).Log.LogInfo((object)"Player joined");
			if (player.IsLocal)
			{
				ExplodesProxChat.Instance.Impl.VoicePlayerManager.Start(local);
			}
			else
			{
				ExplodesProxChat.Instance.Impl.VoicePlayerManager.Joined(ProxChatImpl.GetAgentOfName(player.GetName()));
			}
		}

		[HarmonyPatch(typeof(PlayerManager), "OnPlayerDespawned")]
		[HarmonyPrefix]
		public static void RemovePlayer(SNet_Player snetPlayer)
		{
			((BasePlugin)ExplodesProxChat.Instance).Log.LogInfo((object)"Player removed");
			if (snetPlayer.IsLocal)
			{
				ExplodesProxChat.Instance.Impl.VoicePlayerManager.Reset();
			}
			else
			{
				ExplodesProxChat.Instance.Impl.VoicePlayerManager.Left(snetPlayer.GetName());
			}
		}

		[HarmonyPatch(typeof(SNet_SyncManager), "OnResetSession")]
		[HarmonyPrefix]
		public static void ResetSession()
		{
			((BasePlugin)ExplodesProxChat.Instance).Log.LogInfo((object)"Session reset");
			ExplodesProxChat.Instance.Impl.VoicePlayerManager.Reset();
		}
	}
	public class ProxChatImpl : MonoBehaviour
	{
		private const bool PositionalInLobby = false;

		public readonly VoicePlayerManager VoicePlayerManager = new VoicePlayerManager();

		private VoiceChatNoiseMaker? _voiceChatNoiseMaker;

		private DissonanceComms _comms;

		public VoiceEffectsManager VoiceEffectsManager { get; } = new VoiceEffectsManager();


		public void Start()
		{
			_comms = Object.FindObjectOfType<DissonanceComms>();
			VoiceSettings.Instance.VadSensitivity = (VadSensitivityLevels)1;
			VoiceSettings.Instance.DenoiseAmount = (NoiseSuppressionLevels)1;
			VoiceSettings.Instance.Quality = (AudioQuality)2;
			VoiceSettings.Instance.FrameSize = (FrameSize)2;
			VoiceSettings.Instance.ForwardErrorCorrection = false;
			VoiceSettings.Instance.AecSuppressionAmount = (AecSuppressionLevels)1;
			VoiceSettings.Instance.AecmRoutingMode = (AecmRoutingMode)0;
			((BasePlugin)ExplodesProxChat.Instance).Log.LogInfo((object)("Using microphone: " + _comms.MicrophoneName));
			VoiceEffectsManager.Start();
			_comms.OnPlayerStartedSpeaking += Action<VoicePlayerState>.op_Implicit((Action<VoicePlayerState>)delegate(VoicePlayerState s)
			{
				((BasePlugin)ExplodesProxChat.Instance).Log.LogInfo((object)("Speaking currently " + s.Name));
			});
		}

		[HideFromIl2Cpp]
		public void WakeUpSleepers(NoiseLevel[]? levels)
		{
			if (levels == null)
			{
				_voiceChatNoiseMaker = null;
			}
			else
			{
				_voiceChatNoiseMaker = new VoiceChatNoiseMaker(_comms, new NoiseLevels(levels, (NoiseType)8));
			}
		}

		public void Update()
		{
			if (ExplodesProxChat.Instance.IsReload())
			{
				ExplodesProxChat.Instance.Reload();
			}
			VoiceEffectsManager?.Update();
			_voiceChatNoiseMaker?.Update();
		}

		public static bool InLevel(PlayerAgent playerAgent)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			if (((Component)playerAgent).gameObject.activeInHierarchy && playerAgent.IsEnabled && (int)GameStateManager.CurrentStateName == 10)
			{
				return ((Agent)playerAgent).CourseNode != null;
			}
			return false;
		}

		public static bool CanTrack(PlayerAgent playerAgent)
		{
			return InLevel(playerAgent);
		}

		public static PlayerAgent GetAgentOfName(string voiceName)
		{
			Enumerator<PlayerAgent> enumerator = PlayerManager.PlayerAgentsInLevel.GetEnumerator();
			while (enumerator.MoveNext())
			{
				PlayerAgent current = enumerator.Current;
				if (current.PlayerName == voiceName)
				{
					return current;
				}
			}
			throw new ArgumentException("Player with name " + voiceName + " is not in level");
		}

		public static PlayerAgent? TryGetAgentOfName(string voiceName)
		{
			Enumerator<PlayerAgent> enumerator = PlayerManager.PlayerAgentsInLevel.GetEnumerator();
			while (enumerator.MoveNext())
			{
				PlayerAgent current = enumerator.Current;
				if (current.PlayerName == voiceName)
				{
					return current;
				}
			}
			return null;
		}
	}
}
namespace ExplodesProxChat.Voice
{
	public class LocalTransformComponent : MonoBehaviour
	{
		public Transform transform;

		public PlayerAgent PlayerAgent;

		public void Update()
		{
			//IL_0045: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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)
			if (!((Object)(object)transform == (Object)null) && !((Object)(object)PlayerAgent == (Object)null))
			{
				if (!CanTrack())
				{
					transform.SetPositionAndRotation(default(Vector3), Quaternion.identityQuaternion);
					return;
				}
				Quaternion val = Quaternion.LookRotation(((Agent)PlayerAgent).TargetLookDir, new Vector3(0f, 1f, 0f));
				transform.SetPositionAndRotation(((Agent)PlayerAgent).EyePosition, val);
			}
		}

		private bool CanTrack()
		{
			return ProxChatImpl.CanTrack(PlayerAgent);
		}
	}
	public class ProxChatPlayer : MonoBehaviour
	{
		public bool IsLocalPlayer;

		public PlayerAgent Player;

		public Quaternion Rotation
		{
			get
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				if (!CanTrack())
				{
					return Quaternion.identityQuaternion;
				}
				return Quaternion.LookRotation(((Agent)Player).TargetLookDir, new Vector3(0f, 1f, 0f));
			}
		}

		public Vector3 Position
		{
			get
			{
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: 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)
				if (!CanTrack())
				{
					return default(Vector3);
				}
				return ((Agent)Player).EyePosition;
			}
		}

		public string PlayerId => Player.PlayerName;

		public bool IsTracking => true;

		public NetworkPlayerType Type
		{
			get
			{
				if (IsLocalPlayer)
				{
					return (NetworkPlayerType)1;
				}
				return (NetworkPlayerType)2;
			}
		}

		public ProxChatPlayer(IntPtr pointer)
			: base(pointer)
		{
		}

		public ProxChatPlayer()
			: base(ClassInjector.DerivedConstructorPointer<ProxChatPlayer>())
		{
			ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this);
		}

		private bool CanTrack()
		{
			return ProxChatImpl.CanTrack(Player);
		}
	}
	public class VoicePlayerManager
	{
		private readonly Dictionary<string, ProximityVoiceHandler> _proxVoiceDict = new Dictionary<string, ProximityVoiceHandler>();

		private readonly List<PlayerAgent> _toBeCreated = new List<PlayerAgent>();

		private GameObject _fakeLocalGameObject;

		private PlayerAgent _local;

		private LocalTransformComponent _localTransformComponent;

		private bool _managerStarted;

		private DissonanceComms comms;

		public void Start(PlayerAgent local)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			if (_managerStarted)
			{
				return;
			}
			_fakeLocalGameObject = new GameObject("Fake local player");
			comms = Object.FindObjectOfType<DissonanceComms>();
			LeaveAllRooms();
			SetupLocalPlayer(local);
			_local = local;
			_managerStarted = true;
			foreach (PlayerAgent item in _toBeCreated)
			{
				Joined(item);
			}
			_toBeCreated.Clear();
			DebugState();
		}

		private void SetupLocalPlayer(PlayerAgent player)
		{
			_localTransformComponent = _fakeLocalGameObject.AddComponent<LocalTransformComponent>();
			_localTransformComponent.transform = ((Component)comms).gameObject.transform;
			_localTransformComponent.PlayerAgent = player;
			((BasePlugin)ExplodesProxChat.Instance).Log.LogInfo((object)("Registered local tracked player to Dissonance " + player.PlayerName));
		}

		public void Joined(PlayerAgent player)
		{
			if (((Agent)player).IsLocallyOwned)
			{
				((BasePlugin)ExplodesProxChat.Instance).Log.LogError((object)"Tried to make local player join");
				return;
			}
			if (!_managerStarted)
			{
				_toBeCreated.Add(player);
				return;
			}
			ProximityVoiceHandler proximityVoiceHandler = ExplodesProxChat.Instance.CreatePair(_local, player, comms);
			proximityVoiceHandler.Init();
			_proxVoiceDict.Add(player.PlayerName, proximityVoiceHandler);
			((BasePlugin)ExplodesProxChat.Instance).Log.LogInfo((object)("Registered remote tracked player to Dissonance: " + player.PlayerName));
			DebugState();
		}

		public void Left(string name)
		{
			if (!_managerStarted)
			{
				((BasePlugin)ExplodesProxChat.Instance).Log.LogError((object)("Failed to remove " + name + ", manager is not started"));
				return;
			}
			if (name == SteamManager.LocalPlayerName)
			{
				((BasePlugin)ExplodesProxChat.Instance).Log.LogError((object)("Tried to remove local player: " + name));
				return;
			}
			if (!_proxVoiceDict.Remove(name, out ProximityVoiceHandler value))
			{
				((BasePlugin)ExplodesProxChat.Instance).Log.LogError((object)("Tried to remove absent player: " + name));
				return;
			}
			value.Finish();
			((BasePlugin)ExplodesProxChat.Instance).Log.LogInfo((object)("Removed player " + name));
			DebugState();
		}

		public void DebugState()
		{
			((BasePlugin)ExplodesProxChat.Instance).Log.LogInfo((object)("manager started: " + _managerStarted));
			((BasePlugin)ExplodesProxChat.Instance).Log.LogInfo((object)"players: ");
			foreach (var (text2, proximityVoiceHandler2) in _proxVoiceDict)
			{
				((BasePlugin)ExplodesProxChat.Instance).Log.LogInfo((object)("- " + text2 + " " + proximityVoiceHandler2));
			}
		}

		public void Reset()
		{
			if (_managerStarted)
			{
				DestroyAllVoices();
				_proxVoiceDict.Clear();
				Object.Destroy((Object)(object)_fakeLocalGameObject);
				_toBeCreated.Clear();
				_managerStarted = false;
				DebugState();
			}
		}

		private void DestroyAllVoices()
		{
			foreach (KeyValuePair<string, ProximityVoiceHandler> item in _proxVoiceDict)
			{
				try
				{
					item.Value.Finish();
				}
				catch (Exception ex)
				{
					((BasePlugin)ExplodesProxChat.Instance).Log.LogError((object)"Couldn't destroy voice properly, probably due to object already being garaged collected");
					((BasePlugin)ExplodesProxChat.Instance).Log.LogError((object)ex);
				}
			}
		}

		private void LeaveAllRooms()
		{
			int num;
			for (num = 0; num < comms.Rooms._rooms.Count; num++)
			{
				RoomMembership val = comms.Rooms._rooms[num];
				comms.Rooms.Leave(val);
				num--;
			}
		}
	}
}
namespace ExplodesProxChat.Voice.Handler
{
	public class ProximityVoiceHandler
	{
		private readonly DissonanceComms _comms;

		private readonly GameObject _fakePlayer;

		private readonly PlayerAgentsPair _playerAgentsPair;

		private readonly ISpatializationStrategy _spatializationStrategy;

		private ProxChatPlayer _proxChatPlayer;

		private VoiceBroadcastTrigger _trigger;

		private VolumeUpdateComponent _volumeUpdateComponent;

		public ProximityVoiceHandler(PlayerAgentsPair pair, DissonanceComms comms, ISpatializationStrategy spatializationStrategy)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			_playerAgentsPair = pair;
			_comms = comms;
			_spatializationStrategy = spatializationStrategy;
			_fakePlayer = new GameObject("Fake player " + pair.OtherAgent.PlayerName);
		}

		public void Init()
		{
			AddProxChatPlayer();
			AddTrigger();
			AddVolumeUpdate();
			((BasePlugin)ExplodesProxChat.Instance).Log.LogInfo((object)"Initiated prox chat handler");
		}

		private void AddVolumeUpdate()
		{
			_volumeUpdateComponent = _fakePlayer.AddComponent<VolumeUpdateComponent>();
			_volumeUpdateComponent.pair = this;
		}

		private void AddTrigger()
		{
			VoiceBroadcastTrigger component = _fakePlayer.GetComponent<VoiceBroadcastTrigger>();
			if ((Object)(object)component != (Object)null)
			{
				((BasePlugin)ExplodesProxChat.Instance).Log.LogError((object)"Old trigger is present on the object, removing now");
				Object.Destroy((Object)(object)component);
			}
			_trigger = _fakePlayer.AddComponent<VoiceBroadcastTrigger>();
			_trigger.Mode = (CommActivationMode)1;
			_trigger.BroadcastPosition = true;
			_trigger.ChannelType = (CommTriggerTarget)2;
			_trigger.MicrophoneVolume = 4f;
		}

		private void AddProxChatPlayer()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			_proxChatPlayer = _fakePlayer.AddComponent<ProxChatPlayer>();
			_proxChatPlayer.Player = _playerAgentsPair.OtherAgent;
			_proxChatPlayer.IsLocalPlayer = false;
			_comms.TrackPlayerPosition(new IDissonancePlayer(((Il2CppObjectBase)_proxChatPlayer).Pointer));
		}

		public void Update()
		{
			if (!((Object)_fakePlayer.GetComponent<VoiceBroadcastTrigger>()).Equals((Object)(object)_trigger))
			{
				AddTrigger();
			}
			_trigger.MicrophoneVolume = _spatializationStrategy.GetFadingFactor(_playerAgentsPair) * CellSettingsManager.SettingsData.VoiceChat.MicrophoneVolume.Value * 10f;
		}

		public void Finish()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			((BasePlugin)ExplodesProxChat.Instance).Log.LogInfo((object)"Destroyed voice");
			_comms.StopTracking(new IDissonancePlayer(((Il2CppObjectBase)_proxChatPlayer).Pointer));
			Object.Destroy((Object)(object)_fakePlayer);
		}

		public override string ToString()
		{
			return $"{"_playerAgentsPair"}: {_playerAgentsPair}, {"_trigger"}: {_trigger}, {"_proxChatPlayer"}: {_proxChatPlayer}, {"_volumeUpdateComponent"}: {_volumeUpdateComponent}";
		}
	}
	public class VolumeUpdateComponent : MonoBehaviour
	{
		public ProximityVoiceHandler pair;

		public void Update()
		{
			pair.Update();
		}

		public void OnEnable()
		{
			((BasePlugin)ExplodesProxChat.Instance).Log.LogInfo((object)"Started volume component");
		}

		public void OnDestroy()
		{
			((BasePlugin)ExplodesProxChat.Instance).Log.LogInfo((object)"Destroyed volume component");
		}
	}
}
namespace ExplodesProxChat.Spatialization
{
	public class DistanceSpatializationStrategy : ISpatializationStrategy
	{
		public IAttenuationFormula Formula { get; set; }

		public DistanceSpatializationStrategy(IAttenuationFormula formula)
		{
			Formula = formula;
		}

		public float GetFadingFactor(PlayerAgentsPair pair)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			return Formula.GetFading(pair.PositionA, pair.PositionB);
		}
	}
	public interface ISpatializationStrategy
	{
		float GetFadingFactor(PlayerAgentsPair pair);
	}
	public class MuteSpatializationStrategy : ISpatializationStrategy
	{
		public float GetFadingFactor(PlayerAgentsPair pair)
		{
			return 0f;
		}
	}
	public class PlayerAgentsPair
	{
		public readonly PlayerAgent LocalPlayer;

		public readonly PlayerAgent OtherAgent;

		public Vector3 PositionA => ((Agent)LocalPlayer).EyePosition;

		public Vector3 PositionB => ((Agent)OtherAgent).EyePosition;

		public PlayerAgentsPair(PlayerAgent localPlayer, PlayerAgent otherAgent)
		{
			LocalPlayer = localPlayer;
			OtherAgent = otherAgent;
		}
	}
	public class RoomSpatializationStrategy : ISpatializationStrategy
	{
		private readonly ISpatializationStrategy _doorStrategy;

		private readonly ISpatializationStrategy _internalStrategy;

		public RoomSpatializationStrategy(ISpatializationStrategy internalStrategy, ISpatializationStrategy doorStrategy)
		{
			_internalStrategy = internalStrategy;
			_doorStrategy = doorStrategy;
		}

		public float GetFadingFactor(PlayerAgentsPair pair)
		{
			if (((Agent)pair.LocalPlayer).CourseNode != null && !ArePlayerInTheSameRoom(pair))
			{
				return _doorStrategy.GetFadingFactor(pair);
			}
			return _internalStrategy.GetFadingFactor(pair);
		}

		private static bool ArePlayerInTheSameRoom(PlayerAgentsPair pair)
		{
			return CanReachNodes(new List<int>(), areaID: ((Agent)pair.LocalPlayer).CourseNode.NodeID, testedNode: ((Agent)pair.OtherAgent).CourseNode);
		}

		private static bool CanReachNodes(ICollection<int> visited, AIG_CourseNode testedNode, int areaID)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Invalid comparison between Unknown and I4
			if (testedNode.NodeID == areaID)
			{
				return true;
			}
			Enumerator<AIG_CoursePortal> enumerator = testedNode.m_portals.GetEnumerator();
			while (enumerator.MoveNext())
			{
				AIG_CoursePortal current = enumerator.Current;
				if (!current.IsTraversable && (!current.m_hasGate || (int)current.Gate.SpawnedDoor.LastStatus != 16))
				{
					continue;
				}
				AIG_CourseNode oppositeNode = current.GetOppositeNode(testedNode);
				if (!visited.Contains(oppositeNode.NodeID))
				{
					visited.Add(oppositeNode.NodeID);
					if (CanReachNodes(visited, oppositeNode, areaID))
					{
						return true;
					}
				}
			}
			return false;
		}
	}
}
namespace ExplodesProxChat.Spatialization.Fading
{
	public abstract class DistanceAttenuationFormula : IAttenuationFormula
	{
		public float GetFading(Vector3 a, Vector3 b)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = a - b;
			float magnitude = ((Vector3)(ref val)).magnitude;
			return GetFadingFromDistance(magnitude);
		}

		protected abstract float GetFadingFromDistance(float distance);
	}
	public class ExponentialFalloffAttenuationFormula : DistanceAttenuationFormula
	{
		private readonly float _radius;

		private readonly float _rolloffFactor;

		public ExponentialFalloffAttenuationFormula(float radius, float rolloffFactor)
		{
			_radius = radius;
			_rolloffFactor = rolloffFactor;
		}

		protected override float GetFadingFromDistance(float distance)
		{
			return Math.Min((float)Math.Pow(distance / _radius, 0f - _rolloffFactor), 1f);
		}
	}
	public interface IAttenuationFormula
	{
		float GetFading(Vector3 a, Vector3 b);
	}
	public class LinearFalloffAttenuationFormula : DistanceAttenuationFormula
	{
		private readonly float _maxDistance;

		private readonly float _referenceDistance;

		private readonly float _rolloffFactor;

		public LinearFalloffAttenuationFormula(float referenceDistance, float maxDistance, float rolloffFactor)
		{
			_referenceDistance = referenceDistance;
			_maxDistance = maxDistance;
			_rolloffFactor = rolloffFactor;
		}

		protected override float GetFadingFromDistance(float distance)
		{
			return Math.Min(1f - _rolloffFactor * (distance - _referenceDistance) / (_maxDistance - _referenceDistance), 1f);
		}
	}
}
namespace ExplodesProxChat.Noise
{
	public class NoiseLevel : Object
	{
		public readonly NoiseType AgentNoiseType;

		public readonly float Limit;

		public NoiseLevel(float limit, NoiseType agentNoiseType)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			Limit = limit;
			AgentNoiseType = agentNoiseType;
		}

		public override string ToString()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			return $"{"Limit"}: {Limit}, {"AgentNoiseType"}: {AgentNoiseType}";
		}
	}
	public class NoiseLevels
	{
		private readonly NoiseType _defaultNoiseType;

		private readonly IEnumerable<NoiseLevel> _noiseLevelsList;

		public NoiseLevels(IEnumerable<NoiseLevel> noiseLevelsList, NoiseType defaultNoiseType)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			_noiseLevelsList = noiseLevelsList;
			_defaultNoiseType = defaultNoiseType;
		}

		public NoiseType GetNoiseTypeForAmplitude(float amplitude)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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)
			NoiseType result = _defaultNoiseType;
			float num = float.MaxValue;
			foreach (NoiseLevel noiseLevels in _noiseLevelsList)
			{
				if (!(amplitude >= noiseLevels.Limit) && !(noiseLevels.Limit > num))
				{
					result = noiseLevels.AgentNoiseType;
					num = noiseLevels.Limit;
				}
			}
			return result;
		}
	}
	public class VoiceChatNoiseMaker
	{
		private class VoiceAverage
		{
			public float Amplitude;

			public int Added;
		}

		private const float MinVolume = -220f;

		private const double TimeBasedOn = 0.25;

		private readonly Dictionary<string, VoiceAverage> _accumulatedVolume = new Dictionary<string, VoiceAverage>();

		private readonly DissonanceComms _comms;

		private readonly NoiseLevels _noiseLevels;

		private float _timer;

		public VoiceChatNoiseMaker(DissonanceComms comms, NoiseLevels noiseLevels)
		{
			_comms = comms;
			_noiseLevels = noiseLevels;
		}

		public void Update()
		{
			if (SNet.IsMaster)
			{
				_timer += Time.deltaTime;
				Accumulate();
				if (!((double)_timer < 0.25))
				{
					MakeNoiseBasedOnAverageAmplitude();
				}
			}
		}

		private void MakeNoiseBasedOnAverageAmplitude()
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < _comms.Players.Count; i++)
			{
				VoicePlayerState val = _comms.Players[i];
				VoiceAverage valueOrDefault = _accumulatedVolume.GetValueOrDefault(val.Name, new VoiceAverage());
				float val2 = AmplitudeTodB(valueOrDefault.Amplitude / (float)valueOrDefault.Added);
				if (valueOrDefault.Added == 0)
				{
					val2 = float.NegativeInfinity;
				}
				val2 = Math.Max(val2, -220f);
				NoiseType noiseTypeForAmplitude = _noiseLevels.GetNoiseTypeForAmplitude(val2);
				PlayerAgent val3 = ProxChatImpl.TryGetAgentOfName(val.Name);
				if ((int)noiseTypeForAmplitude != 0)
				{
					((BasePlugin)ExplodesProxChat.Instance).Log.LogInfo((object)("Making noise: " + ((val3 != null) ? val3.PlayerName : null) + " level is " + ((object)(NoiseType)(ref noiseTypeForAmplitude)).ToString() + " average decibels are " + val2 + " dB"));
					if (val3 != null)
					{
						val3.ForcePlayerNoiseChange(noiseTypeForAmplitude);
					}
				}
			}
			_accumulatedVolume.Clear();
			_timer = 0f;
		}

		private void Accumulate()
		{
			for (int i = 0; i < _comms.Players.Count; i++)
			{
				VoicePlayerState val = _comms.Players[i];
				float amplitude = val.Amplitude;
				VoiceAverage valueOrDefault = _accumulatedVolume.GetValueOrDefault(val.Name, new VoiceAverage());
				valueOrDefault.Amplitude += amplitude;
				valueOrDefault.Added++;
				_accumulatedVolume[val.Name] = valueOrDefault;
			}
		}

		private static float AmplitudeTodB(float amplitude)
		{
			return (float)(20.0 * Math.Log10(amplitude));
		}
	}
}
namespace ExplodesProxChat.Effects
{
	public interface IVoiceEffect
	{
		void Start(VoicePlayback playback);

		void Update(VoicePlayback playback, PlayerAgent agent);
	}
	public class MainTest
	{
		public static void Main()
		{
			ReverbAudioFilter reverbAudioFilter = new ReverbAudioFilter(48000f);
			for (float num = 0f; num < 480000f; num += 0.021333333f)
			{
				float[] array = new float[1024];
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = i;
				}
				reverbAudioFilter.FillData(array, 1, num);
				Console.WriteLine("[{0}]", string.Join(", ", array));
			}
		}
	}
	public class VoiceEffectsManager
	{
		private readonly List<IVoiceEffect> _voiceEffects = new List<IVoiceEffect>();

		private DissonanceComms _comms;

		public RoomReverbVoiceEffect Reverb = new RoomReverbVoiceEffect();

		public void Start()
		{
			_voiceEffects.Add(Reverb);
			_comms = Object.FindObjectOfType<DissonanceComms>();
			_comms.OnPlayerJoinedSession += Action<VoicePlayerState>.op_Implicit((Action<VoicePlayerState>)delegate(VoicePlayerState s)
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Expected O, but got Unknown
				if (s != null && !s.IsLocalPlayer)
				{
					VoicePlayback voicePlayback = new VoicePlayback(((Il2CppObjectBase)new RemoteVoicePlayerState(((Il2CppObjectBase)s).Pointer)._playback).Pointer);
					InitPlayback(voicePlayback);
				}
			});
		}

		private void InitPlayback(VoicePlayback voicePlayback)
		{
			foreach (IVoiceEffect voiceEffect in _voiceEffects)
			{
				voiceEffect.Start(voicePlayback);
			}
		}

		public void Update()
		{
			//IL_002d: 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_0042: Expected O, but got Unknown
			Enumerator<VoicePlayerState> enumerator = _comms._players._players.GetEnumerator();
			while (enumerator.MoveNext())
			{
				VoicePlayerState current = enumerator.Current;
				if (!current.IsLocalPlayer)
				{
					VoicePlayback val = new VoicePlayback(((Il2CppObjectBase)new RemoteVoicePlayerState(((Il2CppObjectBase)current).Pointer)._playback).Pointer);
					PlayerAgent val2 = ProxChatImpl.TryGetAgentOfName(current.Name);
					if ((Object)(object)val2 != (Object)null && (Object)(object)val != (Object)null)
					{
						UpdateFilters(val2, val);
					}
				}
			}
		}

		private void UpdateFilters(PlayerAgent agent, VoicePlayback playback)
		{
			foreach (IVoiceEffect voiceEffect in _voiceEffects)
			{
				voiceEffect.Update(playback, agent);
			}
		}
	}
}
namespace ExplodesProxChat.Effects.Reverb
{
	public class ReverbAudioFilter
	{
		private List<ReverbDelayLine> _lines = new List<ReverbDelayLine>();

		private readonly float _sampleRate;

		private readonly StreamedAudioCache _streamedAudioCache = new StreamedAudioCache();

		private IReverbLinePreset _preset = ReverbPresetsEnum.NO_REVERB;

		public IReverbLinePreset Preset
		{
			set
			{
				if (!value.Equals(_preset))
				{
					_preset = value;
					List<ReverbDelayLine> list = new List<ReverbDelayLine>();
					list.Clear();
					list.AddRange(value.Build(_streamedAudioCache, _sampleRate));
					_lines = list;
				}
			}
		}

		public ReverbAudioFilter(float sampleRate)
		{
			_sampleRate = sampleRate;
		}

		public void FillData(IList<float> data, int channels, double dspTime)
		{
			double num = dspTime * (double)_sampleRate;
			long num2 = (long)Math.Floor(num);
			int num3 = data.Count / channels;
			_streamedAudioCache.Add(data, num2, num3);
			double num4 = num;
			for (int i = 0; i < num3; i++)
			{
				foreach (ReverbDelayLine line in _lines)
				{
					num4 = Math.Min(line.EchoSampleBasedOnCurrent(num2), num4);
					if (_streamedAudioCache.HasData(line.GetPreDelaySamples(), num3))
					{
						line.AddReverb(data, channels, num2 + i, i);
					}
				}
			}
			_streamedAudioCache.RemoveTooOld(num4);
		}
	}
	public class ReverbVoiceFilterScript : MonoBehaviour
	{
		private bool _running;

		[HideFromIl2Cpp]
		public ReverbAudioFilter? Filter { get; private set; }

		private void Start()
		{
			Filter = new ReverbAudioFilter(AudioSettings.outputSampleRate);
		}

		public void OnAudioFilterRead(Il2CppStructArray<float> data, int channels)
		{
			Filter?.FillData((IList<float>)data, channels, AudioSettings.dspTime);
		}
	}
	public class RoomReverbVoiceEffect : IVoiceEffect
	{
		public bool Enable;

		public void Start(VoicePlayback playback)
		{
			((Component)playback).gameObject.AddComponent<ReverbVoiceFilterScript>();
		}

		public void Update(VoicePlayback playback, PlayerAgent agent)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected I4, but got Unknown
			ReverbVoiceFilterScript component = ((Component)playback).gameObject.GetComponent<ReverbVoiceFilterScript>();
			if (!ProxChatImpl.InLevel(agent) || !Enable)
			{
				component.Filter.Preset = ReverbPresetsEnum.NO_REVERB;
				return;
			}
			LG_Area area = ((Agent)agent).CourseNode.m_area;
			Bounds bounds = area.m_bounds;
			Vector3 size = ((Bounds)(ref bounds)).size;
			bool isOutside = area.m_zone.Dimension.DimensionData.IsOutside;
			ReverbAudioFilter filter = component.Filter;
			LG_AreaSize size2 = area.m_size;
			filter.Preset = (size2 - 1) switch
			{
				3 => isOutside ? ReverbPresetsEnum.HUGE : ReverbPresetsEnum.HUGE, 
				2 => isOutside ? ReverbPresetsEnum.LARGE : ReverbPresetsEnum.LARGE, 
				1 => isOutside ? ReverbPresetsEnum.MEDIUM : ReverbPresetsEnum.MEDIUM, 
				0 => isOutside ? ReverbPresetsEnum.SMALL : ReverbPresetsEnum.SMALL, 
				4 => isOutside ? ReverbPresetsEnum.TINY : ReverbPresetsEnum.TINY, 
				_ => ReverbPresetsEnum.NO_REVERB, 
			};
		}
	}
}
namespace ExplodesProxChat.Effects.Reverb.Line
{
	public class ReverbDelayLine
	{
		private readonly ReverbDelayLineProperties _properties;

		private readonly float _sampleRate;

		private readonly StreamedAudioCache _streamedAudioCache;

		private AudioData? _current;

		public ReverbDelayLine(ReverbDelayLineProperties properties, StreamedAudioCache streamedAudioCache, float sampleRate)
		{
			_properties = properties;
			_streamedAudioCache = streamedAudioCache;
			_sampleRate = sampleRate;
		}

		public void AddReverb(IList<float> data, int channels, long currentStartSample, int currentN)
		{
			long num = EchoSampleBasedOnCurrent(currentStartSample);
			if (_current == null || !_current.IsInRange(num))
			{
				_current = ((_current == null) ? _streamedAudioCache.GetDataAtSample(num) : _current.Next);
				if (_current == null || !_current.IsInRange(num))
				{
					_current = _streamedAudioCache.GetDataAtSample(num);
				}
			}
			if (_current != null)
			{
				for (int i = 0; i < channels; i++)
				{
					float dataAtSample = _current.GetDataAtSample(num, i, channels);
					data[currentN * channels + i] += dataAtSample * _properties.WetDryMix;
				}
			}
		}

		private static void LogInfo(string info)
		{
			Console.WriteLine(info);
		}

		public long EchoSampleBasedOnCurrent(long currentStartSample)
		{
			double preDelaySamples = GetPreDelaySamples();
			return (long)((double)currentStartSample - preDelaySamples);
		}

		public double GetPreDelaySamples()
		{
			return _properties.PreDelay * _sampleRate;
		}
	}
	public class ReverbDelayLineProperties
	{
		public readonly float PreDelay;

		public readonly float WetDryMix;

		public ReverbDelayLineProperties(float preDelay, float wetDryMix)
		{
			PreDelay = preDelay;
			WetDryMix = wetDryMix;
		}
	}
}
namespace ExplodesProxChat.Effects.Reverb.Line.Presets
{
	public interface IReverbLinePreset
	{
		IEnumerable<ReverbDelayLine> Build(StreamedAudioCache audioCache, float sampleRate);
	}
	public class ListReverbLinePreset : IReverbLinePreset
	{
		private readonly IEnumerable<ReverbDelayLineProperties> _properties;

		public ListReverbLinePreset(IEnumerable<ReverbDelayLineProperties> properties)
		{
			_properties = properties;
		}

		public IEnumerable<ReverbDelayLine> Build(StreamedAudioCache audioCache, float sampleRate)
		{
			StreamedAudioCache audioCache2 = audioCache;
			return _properties.Select((ReverbDelayLineProperties reverbDelayLineProperties) => new ReverbDelayLine(reverbDelayLineProperties, audioCache2, sampleRate)).ToList();
		}
	}
	public class ReverbPresetsEnum
	{
		public static readonly IReverbLinePreset EXTRA_HUGE = new ListReverbLinePreset(new ReverbDelayLineProperties[3]
		{
			new ReverbDelayLineProperties(0.3f, 0.2f),
			new ReverbDelayLineProperties(0.6f, 0.1f),
			new ReverbDelayLineProperties(0.9f, 0.05f)
		});

		public static readonly IReverbLinePreset HUGE = new ListReverbLinePreset(new ReverbDelayLineProperties[3]
		{
			new ReverbDelayLineProperties(0.25f, 0.1f),
			new ReverbDelayLineProperties(0.4f, 0.05f),
			new ReverbDelayLineProperties(0.55f, 0.02f)
		});

		public static readonly IReverbLinePreset LARGE = new ListReverbLinePreset(new ReverbDelayLineProperties[3]
		{
			new ReverbDelayLineProperties(0.2f, 0.05f),
			new ReverbDelayLineProperties(0.3f, 0.02f),
			new ReverbDelayLineProperties(0.4f, 0.01f)
		});

		public static readonly IReverbLinePreset MEDIUM = new ListReverbLinePreset(new ReverbDelayLineProperties[2]
		{
			new ReverbDelayLineProperties(0.1f, 0.2f),
			new ReverbDelayLineProperties(0.15f, 0.1f)
		});

		public static readonly IReverbLinePreset SMALL = new ListReverbLinePreset(new ReverbDelayLineProperties[1]
		{
			new ReverbDelayLineProperties(0.05f, 0.1f)
		});

		public static readonly IReverbLinePreset TINY = new ListReverbLinePreset(Array.Empty<ReverbDelayLineProperties>());

		public static readonly IReverbLinePreset NO_REVERB = new ListReverbLinePreset(Array.Empty<ReverbDelayLineProperties>());
	}
}
namespace ExplodesProxChat.Effects.EQ
{
	public class DigitalAudioFilter
	{
		private readonly DigitalAudioFilterProperties _properties;

		public DigitalAudioFilter(DigitalAudioFilterProperties properties)
		{
			_properties = properties;
		}

		public float[] Filter(IList<float> data, int dataLength, int channelCount)
		{
			float[] array = new float[data.Count];
			for (int i = 0; i < dataLength; i++)
			{
				ApplyFilter(data, array, i, channelCount);
			}
			return array;
		}

		private void ApplyFilter(IList<float> data, IList<float> resultData, int n, int channelCount)
		{
			int num = _properties.Ord - 1;
			float[] a = _properties.A;
			float[] b = _properties.B;
			for (int i = 0; i < num + 1; i++)
			{
				if (n - i >= 0)
				{
					for (int j = 0; j < channelCount; j++)
					{
						int index = IndexFromN(n, channelCount, j);
						int index2 = IndexFromN(n - i, channelCount, j);
						resultData[index] += b[i] * data[index2];
					}
				}
			}
			for (int k = 0; k < num - 1; k++)
			{
				if (n - k - 1 >= 0)
				{
					for (int l = 0; l < channelCount; l++)
					{
						int index3 = IndexFromN(n, channelCount, l);
						int index4 = IndexFromN(n - k - 1, channelCount, l);
						resultData[index3] -= a[k + 1] * resultData[index4];
					}
				}
			}
			for (int m = 0; m < channelCount; m++)
			{
				resultData[IndexFromN(n, channelCount, m)] /= a[0];
			}
		}

		private static int IndexFromN(int n, int channelCount, int currentChannel)
		{
			return n * channelCount + currentChannel;
		}
	}
	public class DigitalAudioFilterProperties
	{
		public readonly float[] A;

		public readonly float[] B;

		public int Ord => A.Length;

		public DigitalAudioFilterProperties(float[] a, float[] b)
		{
			A = a;
			B = b;
		}

		public static DigitalAudioFilterProperties build(float sampleRate, float centerFrequency, float bandwidth, float bandwidthGain, float referenceGain, float boostGain)
		{
			double num = Math.Tan((double)(bandwidth / 2f) * Math.PI / (double)(sampleRate / 2f));
			double num2 = GainExp(bandwidthGain);
			double num3 = GainExp(referenceGain);
			double num4 = GainExp(boostGain);
			double num5 = Math.Sqrt(Math.Abs(num2 - num3));
			double num6 = Math.Sqrt(Math.Abs(num4 - num2));
			double num7 = num * num5 / num6;
			double num8 = (Math.Pow(10.0, referenceGain / 20f) + Math.Pow(10.0, boostGain / 20f) * num7) / (1.0 + num7);
			double num9 = -2.0 * Math.Pow(10.0, referenceGain / 20f) * Math.Cos((double)centerFrequency * Math.PI / (double)(sampleRate / 2f)) / (1.0 + num7);
			double num10 = (Math.Pow(10.0, referenceGain / 20f) - Math.Pow(10.0, boostGain / 20f) * num7) / (1.0 + num7);
			int num11 = 1;
			double num12 = -2.0 * Math.Cos((double)centerFrequency * Math.PI / (double)(sampleRate / 2f)) / (1.0 + num7);
			double num13 = (1.0 - num7) / (1.0 + num7);
			return new DigitalAudioFilterProperties(new float[3]
			{
				num11,
				(float)num12,
				(float)num13
			}, new float[3]
			{
				(float)num8,
				(float)num9,
				(float)num10
			});
		}

		private static double GainExp(float gain)
		{
			return Math.Pow(Math.Pow(10.0, gain / 20f), 2.0);
		}
	}
	public class ParametricEqualizer
	{
		private readonly DigitalAudioFilter[] _filters;

		public ParametricEqualizer(DigitalAudioFilter[] filters)
		{
			_filters = filters;
		}

		public IList<float> Apply(IList<float> data, int dataLength, int channelCount)
		{
			return _filters.Aggregate(data, (IList<float> current, DigitalAudioFilter digitalAudioFilter) => digitalAudioFilter.Filter(current, dataLength, channelCount));
		}
	}
}
namespace ExplodesProxChat.Effects.Audio
{
	public class AudioData
	{
		private readonly float[] _data;

		private readonly int _dataLen;

		private readonly long _endSample;

		private readonly long _startSample;

		public AudioData? Next;

		public AudioData(float[] data, long startSample, int dataLen)
		{
			_data = data;
			_startSample = startSample;
			_dataLen = dataLen;
			_endSample = _startSample + _dataLen;
		}

		public bool IsInRange(long sample)
		{
			if (sample >= _startSample)
			{
				return sample < _endSample;
			}
			return false;
		}

		public float GetDataAtSample(long sample, int currentChannel, int channels)
		{
			return _data[(sample - _startSample) * channels + currentChannel];
		}

		public bool IsOutdated(double sample)
		{
			return sample >= (double)_endSample;
		}

		public override string ToString()
		{
			return $"{"_data"}: {_data}, {"_startSample"}: {_startSample}, {"_dataLen"}: {_dataLen}";
		}
	}
	public class StreamedAudioCache
	{
		private readonly List<AudioData> _oldData = new List<AudioData>();

		public void Add(IList<float> data, long currentStartSample, int dataLen)
		{
			float[] array = new float[data.Count];
			for (int i = 0; i < data.Count; i++)
			{
				array[i] = data[i];
			}
			AddToOldData(new AudioData(array, currentStartSample, dataLen));
		}

		private void AddToOldData(AudioData audioData)
		{
			int num = _oldData.Count - 1;
			if (num > 0)
			{
				_oldData[num].Next = audioData;
			}
			_oldData.Add(audioData);
		}

		public void RemoveTooOld(double sample)
		{
			int count = 0;
			for (int num = _oldData.Count - 1; num >= 0; num--)
			{
				if (_oldData[num].IsOutdated(sample))
				{
					count = num;
					break;
				}
			}
			_oldData.RemoveRange(0, count);
		}

		public AudioData? GetDataAtSample(long sampleTime)
		{
			for (int num = _oldData.Count - 1; num >= 0; num--)
			{
				AudioData audioData = _oldData[num];
				if (audioData.IsInRange(sampleTime))
				{
					return audioData;
				}
			}
			return null;
		}

		public bool HasData(double delay, int dataLen)
		{
			return (double)((_oldData.Count - 1) * dataLen) > delay;
		}
	}
}