Decompiled source of Megaphone v1.2.3

plugins/ESN.Megaphone/ESN.Megaphone.dll

Decompiled 2 months ago
using System;
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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ESN.Megaphone.NetcodePatcher;
using GameNetcodeStuff;
using HarmonyLib;
using LethalLib.Modules;
using Megaphone.Items;
using Megaphone.Patches;
using Megaphone.Scripts;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ESN.Megaphone")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.3.0")]
[assembly: AssemblyInformationalVersion("1.2.3+6553b1e478f8abd9e4961d5397060f3596e90eb7")]
[assembly: AssemblyProduct("Megaphone")]
[assembly: AssemblyTitle("ESN.Megaphone")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
internal class <Module>
{
	static <Module>()
	{
	}
}
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 Megaphone
{
	internal class Commands
	{
		public static string DefaultCMD()
		{
			return "Not Yet Implemented";
		}
	}
	public class MyConfig
	{
		public const int SIREN_NOISE_ID = 1880;

		private static ConfigEntry<bool> configCanBuy;

		private static ConfigEntry<bool> configIsScrap;

		private static ConfigEntry<int> configRarity;

		private static ConfigEntry<int> configPrice;

		private static ConfigEntry<float> configHearDistance;

		private static ConfigEntry<float> configSirenHearDistance;

		private static ConfigEntry<float> configSFXHearDistance;

		private static ConfigEntry<float> configSFXEnemyHearDistance;

		private static ConfigEntry<float> configLoudVoiceVolume;

		private static ConfigEntry<float> configSFXVolume;

		private static ConfigEntry<float> configRobotVoicePitch;

		private static ConfigEntry<int> configScrapMinPrice;

		private static ConfigEntry<int> configScrapMaxPrice;

		public static bool CanBuy => configCanBuy.Value;

		public static bool IsScrap => configIsScrap.Value;

		public static int Rarity => (int)MathF.Max(0f, MathF.Min(100f, configRarity.Value));

		public static int Price => (int)MathF.Max(0f, configPrice.Value);

		public static float HearDistance
		{
			get
			{
				float num = configHearDistance.Value;
				if (num <= 0f)
				{
					num = 1f;
				}
				return num;
			}
		}

		public static float SirenHearDistance
		{
			get
			{
				float num = configSirenHearDistance.Value;
				if (num <= 0f)
				{
					num = 1f;
				}
				return num;
			}
		}

		public static float SFXHearDistance
		{
			get
			{
				float num = configSFXHearDistance.Value;
				if (num <= 0f)
				{
					num = 1f;
				}
				return num;
			}
		}

		public static float SFXEnemyHearDistance
		{
			get
			{
				float num = configSFXEnemyHearDistance.Value;
				if (num <= 0f)
				{
					num = 1f;
				}
				return num;
			}
		}

		public static float LoudVoiceVolume
		{
			get
			{
				float value = configLoudVoiceVolume.Value;
				value = MathF.Min(1.2f, value);
				return MathF.Max(0f, value);
			}
		}

		public static float SFXVolume
		{
			get
			{
				float value = configSFXVolume.Value;
				value = MathF.Min(1.2f, value);
				return MathF.Max(0f, value);
			}
		}

		public static float RobotVoicePitch
		{
			get
			{
				float value = configRobotVoicePitch.Value;
				value = MathF.Min(2f, value);
				return MathF.Max(0.5f, value);
			}
		}

		public static int ScrapMinValue => (int)MathF.Max(0f, configScrapMinPrice.Value);

		public static int ScrapMaxValue => (int)MathF.Max(ScrapMinValue, configScrapMaxPrice.Value);

		public static void Setup(BaseUnityPlugin p)
		{
			configCanBuy = p.Config.Bind<bool>("Item", "CanBeBought", false, "Can the item be bought from the terminal.\r\n[Client side]");
			configIsScrap = p.Config.Bind<bool>("Item", "IsScrap", true, "Can the item spawn in interiors.\r\nNot recommended to have both this and 'CanBuy' set to true.\r\n[Host side]");
			configRarity = p.Config.Bind<int>("Item", "ScrapRarity", 10, "Rarity of the object. 0 is never, 100 is often.\r\nMin: 0      Max: 100\r\n[Host side]");
			configPrice = p.Config.Bind<int>("Item", "Price", 60, "Buy cost of the item.\r\nMin: 0\r\n[Client side]");
			configHearDistance = p.Config.Bind<float>("Audio.Distances", "HearingDistanceModifier", 2f, "Change the distance multiplier the voices can be heard from when talking in\r\n'loud mode' (switch with Q).\r\nMin: 0.0\r\n[Client side]");
			configSirenHearDistance = p.Config.Bind<float>("Audio.Distances", "SirenHearingDistanceModifier", 2f, "Change the distance multiplier the siren can be heard from (switch with Q).\r\nMin: 0.0\r\n[Client side]");
			configSFXHearDistance = p.Config.Bind<float>("Audio.Distances", "SFXHearingDistanceModifier", 2f, "Change the distance multiplier the SFX can be heard from.\r\nMin: 0.0\r\n[Client side]");
			configSFXEnemyHearDistance = p.Config.Bind<float>("Audio.Distances", "EnemySFXHearingDistanceModifier", 1f, "Change the distance multiplier the SFX can be heard from by enemies.\r\nThis multiplier is applied after the base hear distance modifier.\r\nMin: 0.0\r\n[Client side]");
			configLoudVoiceVolume = p.Config.Bind<float>("Audio.Volume", "LoudVoiceVolume", 0.9f, "Volume multiplier of the 'Loud voice' filter. Recommended below 1.0 because\r\nthe distortion increases the volume, 1.0 is already higher than normal voice.\r\nMin: 0.0    Max: 1.2\r\n[Client side]");
			configSFXVolume = p.Config.Bind<float>("Audio.Volume", "SFXVolume", 1f, "Volume multiplier of the SFX sounds.\r\nMin: 0.0    Max: 1.2\r\n[Client side]");
			configRobotVoicePitch = p.Config.Bind<float>("Audio.Pitch", "RobotVoicePitch", 0.9f, "Set the pitch for the robot voice.\r\nMin: 0.5    Max: 2.0\r\n[Client side]");
			configScrapMinPrice = p.Config.Bind<int>("Scrap", "ScrapMinPrince", 30, "Set the minimum scrap sell value.\r\nMin: 0\r\n[Host side]");
			configScrapMaxPrice = p.Config.Bind<int>("Scrap", "ScrapMaxPrince", 60, "Set the maximum scrap sell value.\r\nMin: <ScrapMinPrince>\r\n[Host side]");
		}
	}
	public class MyLog
	{
		public static void LogInfo(string message)
		{
			Plugin.Logger.LogInfo((object)message);
		}

		public static void LogWarning(string message)
		{
			Plugin.Logger.LogWarning((object)message);
		}

		public static void LogError(string message)
		{
			Plugin.Logger.LogError((object)message);
		}

		public static void LogDebug(string message)
		{
		}
	}
	[HarmonyPatch]
	public class NetworkObjectManager
	{
		private static GameObject networkPrefab;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameNetworkManager), "Start")]
		public static void Init()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			if (!((Object)(object)networkPrefab != (Object)null))
			{
				networkPrefab = (GameObject)Plugin.Assets_network.LoadAsset("Assets/Network/ExampleNetworkHandler.prefab");
				NetworkManager.Singleton.AddNetworkPrefab(networkPrefab);
				MyLog.LogDebug("ExampleNetworkHandler successfully added");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(StartOfRound), "Awake")]
		private static void SpawnNetworkHandler()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer)
			{
				GameObject val = Object.Instantiate<GameObject>(networkPrefab, Vector3.zero, Quaternion.identity);
				val.GetComponent<NetworkObject>().Spawn(false);
				MyLog.LogDebug("NetworkObject successfully spawned");
			}
		}
	}
	[BepInPlugin("ESN.Megaphone", "Megaphone", "1.2.3")]
	[BepInDependency("atomic.terminalapi", "1.5.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string ASSET_PATH_MEGAPHONE_ITEM = "Assets/Megaphone/MegaphoneItem.asset";

		public const string ASSET_PATH_MEGAPHONE_SFX = "Assets/Megaphone/sfx.mp3";

		public const string ASSET_PATH_MEGAPHONE_SIREN = "Assets/Megaphone/siren.mp3";

		public const string ASSET_PATH_MEGAPHONE_TNODE = "Assets/Megaphone/iTerminalNodeMegaphone.asset";

		public const string ASSET_PATH_NET_HANDLER = "Assets/Network/ExampleNetworkHandler.prefab";

		public static AssetBundle Assets;

		public static AssetBundle Assets_network;

		public static Plugin Instance { get; private set; }

		internal static ManualLogSource Logger { get; private set; }

		internal static Harmony Harmony { get; set; }

		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			MyConfig.Setup((BaseUnityPlugin)(object)this);
			LoadAssets();
			Patch();
			CreateTerminalCommands();
			CreateItems();
			Logger.LogInfo((object)"ESN.Megaphone v1.2.3 has loaded!");
		}

		private static void CreateItems()
		{
			Item val = Assets.LoadAsset<Item>("Assets/Megaphone/MegaphoneItem.asset");
			val.minValue = (int)Mathf.Round((float)MyConfig.ScrapMinValue / 0.4f);
			val.maxValue = (int)Mathf.Round((float)MyConfig.ScrapMaxValue / 0.4f);
			Logger.LogDebug((object)("Found item " + val.itemName));
			GrabbableObject val2 = (GrabbableObject)(object)val.spawnPrefab.AddComponent<MegaphoneItem>();
			Logger.LogDebug((object)$"Found script {val2}");
			val2.grabbable = true;
			val2.isInFactory = true;
			val2.itemProperties = val;
			val2.grabbableToEnemies = true;
			MyLog.LogDebug("Found item '" + val.itemName + "'");
			NetworkPrefabs.RegisterNetworkPrefab(val.spawnPrefab);
			if (MyConfig.IsScrap)
			{
				Items.RegisterScrap(val, MyConfig.Rarity, (LevelTypes)(-1));
			}
			if (MyConfig.CanBuy)
			{
				TerminalNode val3 = Assets.LoadAsset<TerminalNode>("Assets/Megaphone/iTerminalNodeMegaphone.asset");
				Items.RegisterShopItem(val, (TerminalNode)null, (TerminalNode)null, val3, MyConfig.Price);
			}
			else
			{
				Items.RegisterItem(val);
			}
		}

		private static void LoadAssets()
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			Assets = AssetBundle.LoadFromFile(Path.Combine(directoryName, "assets/esn_megaphone"));
			if ((Object)(object)Assets == (Object)null)
			{
				Logger.LogError((object)"Failed to load custom assets.");
				return;
			}
			Assets_network = AssetBundle.LoadFromFile(Path.Combine(directoryName, "assets/esn_network"));
			if ((Object)(object)Assets == (Object)null)
			{
				Logger.LogError((object)"Failed to load network assets.");
				return;
			}
			Logger.LogDebug((object)"Assets loaded");
			string[] allAssetNames = Assets.GetAllAssetNames();
			string[] array = allAssetNames;
			foreach (string text in array)
			{
				Logger.LogDebug((object)(text ?? ""));
			}
			allAssetNames = Assets_network.GetAllAssetNames();
			string[] array2 = allAssetNames;
			foreach (string text2 in array2)
			{
				Logger.LogDebug((object)(text2 ?? ""));
			}
			AudioMod.LoadAssets();
		}

		private static void CreateTerminalCommands()
		{
		}

		private static void NetcodePatcher()
		{
			Logger.LogDebug((object)"Patching netcode...");
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			Type[] array = types;
			foreach (Type type in array)
			{
				MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic);
				MethodInfo[] array2 = methods;
				foreach (MethodInfo methodInfo in array2)
				{
					object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false);
					if (customAttributes.Length != 0)
					{
						methodInfo.Invoke(null, null);
					}
				}
			}
			Logger.LogDebug((object)"Patching netcode... complete");
		}

		internal void Patch()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			if (Harmony == null)
			{
				Harmony = new Harmony("ESN.Megaphone");
			}
			Logger.LogDebug((object)"Patching...");
			Harmony.PatchAll(typeof(AudioPatch));
			Harmony.PatchAll(typeof(BlobPatch));
			Harmony.PatchAll(typeof(PufferPatch));
			Harmony.PatchAll(typeof(NetworkObjectManager));
			NetcodePatcher();
			Logger.LogDebug((object)"Finished patching!");
		}

		internal static void Unpatch()
		{
			Logger.LogDebug((object)"Unpatching...");
			Harmony harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Logger.LogDebug((object)"Finished unpatching!");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "ESN.Megaphone";

		public const string PLUGIN_NAME = "Megaphone";

		public const string PLUGIN_VERSION = "1.2.3";
	}
}
namespace Megaphone.Scripts
{
	public class AudioFiltering
	{
		public MegaphoneItem parent;

		public PlayerControllerB player;

		private const AudioFilteringMode endNode = AudioFilteringMode.Siren;

		private AudioFilteringMode _mode;

		public bool active;

		public AudioFilteringMode Mode => _mode;

		private AudioFiltering()
		{
		}

		public AudioFiltering(MegaphoneItem parent)
		{
			this.parent = parent;
		}

		public bool NextFilterMode(bool enable)
		{
			AudioFilteringMode newMode = ((_mode != AudioFilteringMode.Siren) ? (_mode + 1) : AudioFilteringMode.Robot);
			bool flag = SetFilterMode(newMode, enable);
			if (flag)
			{
				MyLog.LogInfo("Switched to mode " + Enum.GetName(typeof(AudioFilteringMode), _mode));
			}
			else
			{
				MyLog.LogError("Unable to switch to mode " + Enum.GetName(typeof(AudioFilteringMode), _mode));
			}
			return flag;
		}

		public bool SetFilterMode(AudioFilteringMode newMode, bool enable)
		{
			if (active && !Disable())
			{
				return false;
			}
			_mode = newMode;
			if (enable)
			{
				return Enable();
			}
			return true;
		}

		public bool Enable()
		{
			MyLog.LogDebug("Enabling...");
			if (active)
			{
				MyLog.LogDebug("Already enabled...");
				return true;
			}
			active = true;
			switch (_mode)
			{
			case AudioFilteringMode.Robot:
				AudioMod.EnableRobotVoice(player, on: true);
				break;
			case AudioFilteringMode.Loud:
				AudioMod.EnableLoudVoice(player, on: true);
				break;
			case AudioFilteringMode.HighPitch:
				AudioMod.EnableHighPitch(player, on: true);
				break;
			case AudioFilteringMode.LowPitch:
				AudioMod.EnableLowPitch(player, on: true);
				break;
			case AudioFilteringMode.Siren:
				AudioMod.PlaySFX(parent, AudioMod.Siren, 0, 1880);
				break;
			default:
				return false;
			}
			return true;
		}

		public bool Disable()
		{
			MyLog.LogDebug("Disabling...");
			if (!active)
			{
				MyLog.LogDebug("Already disabled...");
				return true;
			}
			switch (_mode)
			{
			case AudioFilteringMode.Robot:
				AudioMod.EnableRobotVoice(player, on: false);
				break;
			case AudioFilteringMode.Loud:
				AudioMod.EnableLoudVoice(player, on: false);
				break;
			case AudioFilteringMode.HighPitch:
				AudioMod.EnableHighPitch(player, on: false);
				break;
			case AudioFilteringMode.LowPitch:
				AudioMod.EnableLowPitch(player, on: false);
				break;
			case AudioFilteringMode.Siren:
				AudioMod.StopSFX(parent);
				break;
			default:
				return false;
			}
			active = false;
			return true;
		}

		public void PlaySirenAudibleNoiseIfApplicable(MegaphoneItem item, int counter)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (active && _mode == AudioFilteringMode.Siren)
			{
				RoundManager.Instance.PlayAudibleNoise(((Component)item).transform.position, MyConfig.SFXHearDistance * MyConfig.SFXEnemyHearDistance * 50f, 1f, counter, ((GrabbableObject)item).isInElevator && StartOfRound.Instance.hangarDoorsClosed, 1880);
			}
		}
	}
	public enum AudioFilteringMode
	{
		Robot,
		Loud,
		HighPitch,
		LowPitch,
		Siren
	}
	public class AudioMod
	{
		protected static List<ulong> setupPlayersID = new List<ulong>();

		protected static AudioClip sfx;

		protected static AudioClip siren;

		public static AudioClip SFX => sfx;

		public static AudioClip Siren => siren;

		public static void LoadAssets()
		{
			sfx = Plugin.Assets.LoadAsset<AudioClip>("Assets/Megaphone/sfx.mp3");
			siren = Plugin.Assets.LoadAsset<AudioClip>("Assets/Megaphone/siren.mp3");
		}

		public static void RegisterNewPlayer(PlayerControllerB player)
		{
			if (setupPlayersID.Contains(player.playerClientId))
			{
				setupPlayersID.Remove(player.playerClientId);
			}
		}

		public static bool SetupGameobjects(PlayerControllerB player)
		{
			if ((Object)(object)player == (Object)null)
			{
				MyLog.LogError("Unable to continue, player is null... Owner must re-equip the item");
				return false;
			}
			if (setupPlayersID.Contains(player.playerClientId))
			{
				return true;
			}
			setupPlayersID.Add(player.actualClientId);
			MyLog.LogDebug($"Setting gameobjects for player {((Object)player).name} - {player.playerClientId}");
			MyLog.LogInfo($"Settings up audio components for player {player.playerUsername} ; ID({player.playerClientId})");
			AudioSource currentVoiceChatAudioSource = player.currentVoiceChatAudioSource;
			if ((Object)(object)currentVoiceChatAudioSource == (Object)null)
			{
				MyLog.LogInfo("No AudioSource found...");
				return false;
			}
			AudioEchoFilter component = ((Component)currentVoiceChatAudioSource).GetComponent<AudioEchoFilter>();
			if ((Object)(object)component == (Object)null)
			{
				MyLog.LogDebug("AudioEchoFilter missing");
				((Component)currentVoiceChatAudioSource).gameObject.AddComponent<AudioEchoFilter>();
				component = ((Component)currentVoiceChatAudioSource).GetComponent<AudioEchoFilter>();
			}
			((Behaviour)component).enabled = false;
			MyLog.LogDebug("Echo ready");
			AudioHighPassFilter component2 = ((Component)currentVoiceChatAudioSource).GetComponent<AudioHighPassFilter>();
			if ((Object)(object)component2 == (Object)null)
			{
				MyLog.LogDebug("AudioHighPassFilter missing");
				((Component)currentVoiceChatAudioSource).gameObject.AddComponent<AudioHighPassFilter>();
				component2 = ((Component)currentVoiceChatAudioSource).GetComponent<AudioHighPassFilter>();
			}
			((Behaviour)component2).enabled = false;
			MyLog.LogDebug("HighPass ready");
			AudioDistortionFilter component3 = ((Component)currentVoiceChatAudioSource).GetComponent<AudioDistortionFilter>();
			if ((Object)(object)component3 == (Object)null)
			{
				MyLog.LogDebug("AudioDistortionFilter missing");
				((Component)currentVoiceChatAudioSource).gameObject.AddComponent<AudioDistortionFilter>();
				component3 = ((Component)currentVoiceChatAudioSource).GetComponent<AudioDistortionFilter>();
			}
			((Behaviour)component3).enabled = false;
			MyLog.LogDebug("Distortion ready");
			AudioChorusFilter component4 = ((Component)currentVoiceChatAudioSource).GetComponent<AudioChorusFilter>();
			if ((Object)(object)component4 == (Object)null)
			{
				MyLog.LogDebug("AudioHighPassFilter missing");
				((Component)currentVoiceChatAudioSource).gameObject.AddComponent<AudioChorusFilter>();
				component4 = ((Component)currentVoiceChatAudioSource).GetComponent<AudioChorusFilter>();
			}
			((Behaviour)component4).enabled = false;
			MyLog.LogDebug("Chorus ready");
			MyLog.LogInfo($"Player {player.playerUsername} ; ID({player.playerClientId}) ready !");
			return true;
		}

		protected static bool AreAllComponentsAdded(AudioSource src)
		{
			AudioEchoFilter component = ((Component)src).GetComponent<AudioEchoFilter>();
			OccludeAudio component2 = ((Component)src).GetComponent<OccludeAudio>();
			AudioHighPassFilter component3 = ((Component)src).GetComponent<AudioHighPassFilter>();
			AudioChorusFilter component4 = ((Component)src).GetComponent<AudioChorusFilter>();
			AudioDistortionFilter component5 = ((Component)src).GetComponent<AudioDistortionFilter>();
			if ((Object)(object)component == (Object)null)
			{
				MyLog.LogError("AudioEchoFilter missing");
				return false;
			}
			if ((Object)(object)component2 == (Object)null)
			{
				MyLog.LogError("OccludeAudio missing");
				return false;
			}
			if ((Object)(object)component3 == (Object)null)
			{
				MyLog.LogError("AudioHighPassFilter missing");
				return false;
			}
			if ((Object)(object)component4 == (Object)null)
			{
				MyLog.LogError("AudioChorusFilter missing");
				return false;
			}
			if ((Object)(object)component5 == (Object)null)
			{
				MyLog.LogError("AudioDistortionFilter missing");
				return false;
			}
			return true;
		}

		protected static bool CheckComponents(PlayerControllerB player)
		{
			AudioSource currentVoiceChatAudioSource = player.currentVoiceChatAudioSource;
			if ((Object)(object)currentVoiceChatAudioSource == (Object)null)
			{
				return false;
			}
			if (!AreAllComponentsAdded(currentVoiceChatAudioSource))
			{
				RegisterNewPlayer(player);
				return SetupGameobjects(player);
			}
			return true;
		}

		internal static bool EnableRobotVoice(PlayerControllerB player, bool on)
		{
			MyLog.LogInfo((on ? "Enabling" : "Disabling") + " robot voice for player " + player.playerUsername);
			if (!CheckComponents(player))
			{
				return false;
			}
			AudioSource currentVoiceChatAudioSource = player.currentVoiceChatAudioSource;
			AudioEchoFilter component = ((Component)currentVoiceChatAudioSource).GetComponent<AudioEchoFilter>();
			AudioHighPassFilter component2 = ((Component)currentVoiceChatAudioSource).GetComponent<AudioHighPassFilter>();
			AudioChorusFilter component3 = ((Component)currentVoiceChatAudioSource).GetComponent<AudioChorusFilter>();
			if (on)
			{
				component.delay = 10f;
				component.decayRatio = 0.75f;
				component2.cutoffFrequency = 500f;
				component3.dryMix = 0.75f;
				float wetMix = (component3.wetMix2 = 0.75f);
				component3.wetMix1 = wetMix;
				component3.delay = 40f;
				component3.depth = 0.7f;
				component3.rate = 1.2f;
			}
			bool flag2 = (((Behaviour)component3).enabled = on);
			bool enabled = (((Behaviour)component2).enabled = flag2);
			((Behaviour)component).enabled = enabled;
			AudioPatch.playersPitchTargets[player.playerClientId] = (on ? MyConfig.RobotVoicePitch : (-1f));
			return true;
		}

		internal static bool EnableLoudVoice(PlayerControllerB player, bool on)
		{
			MyLog.LogInfo((on ? "Enabling" : "Disabling") + " loud voice for player " + player.playerUsername);
			if (!CheckComponents(player))
			{
				return false;
			}
			AudioSource currentVoiceChatAudioSource = player.currentVoiceChatAudioSource;
			AudioEchoFilter component = ((Component)currentVoiceChatAudioSource).GetComponent<AudioEchoFilter>();
			OccludeAudio component2 = ((Component)currentVoiceChatAudioSource).GetComponent<OccludeAudio>();
			AudioHighPassFilter component3 = ((Component)currentVoiceChatAudioSource).GetComponent<AudioHighPassFilter>();
			AudioChorusFilter component4 = ((Component)currentVoiceChatAudioSource).GetComponent<AudioChorusFilter>();
			AudioDistortionFilter component5 = ((Component)currentVoiceChatAudioSource).GetComponent<AudioDistortionFilter>();
			((Behaviour)component).enabled = false;
			((Behaviour)component4).enabled = false;
			if (on)
			{
				component3.cutoffFrequency = 800f;
				component5.distortionLevel = 0.9f;
			}
			currentVoiceChatAudioSource.volume = (on ? MyConfig.LoudVoiceVolume : 1f);
			player.voiceMuffledByEnemy = true;
			component2.overridingLowPass = on;
			component2.lowPassOverride = (on ? 3500f : 20000f);
			bool enabled = (((Behaviour)component5).enabled = on);
			((Behaviour)component3).enabled = enabled;
			AudioPatch.EnableHighpass(player.actualClientId, on);
			currentVoiceChatAudioSource.maxDistance = (on ? (MyConfig.HearDistance * 50f) : 50f);
			return true;
		}

		internal static void EnableHighPitch(PlayerControllerB player, bool on)
		{
			MyLog.LogInfo((on ? "Enabling" : "Disabling") + " high pitch voice for player " + player.playerUsername);
			AudioPatch.playersPitchTargets[player.playerClientId] = (on ? 2 : (-1));
		}

		internal static void EnableLowPitch(PlayerControllerB player, bool on)
		{
			MyLog.LogInfo((on ? "Enabling" : "Disabling") + " low pitch voice for player " + player.playerUsername);
			AudioPatch.playersPitchTargets[player.playerClientId] = (on ? 0.5f : (-1f));
		}

		internal static bool PlaySFX(MegaphoneItem item, AudioClip sound, int counter = 0, int noiseID = 0)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)sound == (Object)null)
			{
				MyLog.LogError("SFX is null");
				return false;
			}
			MyLog.LogInfo("Playing SFX...");
			AudioSource component = ((Component)item).GetComponent<AudioSource>();
			if ((Object)(object)component == (Object)null)
			{
				MyLog.LogError("No AudioSource to play SFX...");
				return false;
			}
			component.maxDistance = MyConfig.SFXHearDistance * 50f;
			component.volume = MyConfig.SFXVolume;
			component.PlayOneShot(sound);
			RoundManager.Instance.PlayAudibleNoise(((Component)item).transform.position, component.maxDistance * MyConfig.SFXEnemyHearDistance, 1f, counter, ((GrabbableObject)item).isInElevator && StartOfRound.Instance.hangarDoorsClosed, noiseID);
			return true;
		}

		internal static bool StopSFX(MegaphoneItem item)
		{
			if ((Object)(object)sfx == (Object)null)
			{
				MyLog.LogError("SFX is null");
				return false;
			}
			MyLog.LogInfo("Stopping SFX...");
			AudioSource component = ((Component)item).GetComponent<AudioSource>();
			if ((Object)(object)component == (Object)null)
			{
				MyLog.LogError("No AudioSource to play SFX...");
				return false;
			}
			component.maxDistance = 50f;
			component.volume = 1f;
			component.Stop(true);
			return true;
		}
	}
}
namespace Megaphone.Patches
{
	[HarmonyPatch]
	public class AudioPatch
	{
		public static List<ulong> EnableHighPassIndexes = new List<ulong>();

		public static Dictionary<ulong, float> playersPitchTargets = new Dictionary<ulong, float>();

		public static void EnableHighpass(ulong index, bool on)
		{
			if (on)
			{
				EnableHighPassIndexes.Add(index);
			}
			else if (EnableHighPassIndexes.Contains(index))
			{
				EnableHighPassIndexes.Remove(index);
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "OnPlayerConnectedClientRpc")]
		[HarmonyPostfix]
		private static void ConnectClientToPlayerObjectPatch(StartOfRound __instance, ulong clientId, int connectedPlayers, ulong[] connectedPlayerIdsOrdered, int assignedPlayerObjectId, int serverMoneyAmount, int levelID, int profitQuota, int timeUntilDeadline, int quotaFulfilled, int randomSeed, bool isChallenge)
		{
			PlayerControllerB val = __instance.allPlayerScripts[assignedPlayerObjectId];
			MyLog.LogDebug("Player " + ((Object)val).name + " connected");
			AudioMod.RegisterNewPlayer(val);
		}

		[HarmonyPatch(typeof(StartOfRound), "UpdatePlayerVoiceEffects")]
		[HarmonyPostfix]
		private static void UpdatePlayerVoiceEffectsPostfix(StartOfRound __instance)
		{
			foreach (ulong enableHighPassIndex in EnableHighPassIndexes)
			{
				AudioSource currentVoiceChatAudioSource = __instance.allPlayerScripts[enableHighPassIndex].currentVoiceChatAudioSource;
				if ((Object)(object)currentVoiceChatAudioSource == (Object)null)
				{
					MyLog.LogError("voiceChatAudioSource is null...");
				}
				((Behaviour)((Component)currentVoiceChatAudioSource).GetComponent<AudioHighPassFilter>()).enabled = true;
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Update")]
		[HarmonyPostfix]
		private static void PlayerControllerBUpdatePostFix(PlayerControllerB __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return;
			}
			ulong playerClientId = __instance.playerClientId;
			if (playersPitchTargets.ContainsKey(playerClientId))
			{
				float num = playersPitchTargets[playerClientId];
				if (!(num < 0.5f) && !(num > 2f) && num != 1f)
				{
					MyLog.LogDebug($"Overwriting pitch for {playerClientId} to {num}");
					SoundManager.Instance.playerVoicePitchTargets[playerClientId] = num;
				}
			}
		}
	}
	[HarmonyPatch(typeof(BlobAI))]
	public class BlobPatch
	{
		[HarmonyPatch("DetectNoise")]
		[HarmonyPostfix]
		private static void DetectNoisePatch(BlobAI __instance, Vector3 noisePosition, float noiseLoudness, int timesPlayedInOneSpot = 0, int noiseID = 0)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (noiseID == 1880 && !Physics.Linecast(((Component)__instance).transform.position, noisePosition, StartOfRound.Instance.collidersAndRoomMask) && !((double)Vector3.Distance(((Component)__instance).transform.position, noisePosition) >= 12.0))
			{
				__instance.tamedTimer = 2f;
			}
		}
	}
	[HarmonyPatch(typeof(PufferAI))]
	public class PufferPatch
	{
		[HarmonyPatch("DetectNoise")]
		[HarmonyPostfix]
		private static void DetectNoisePatch(PufferAI __instance, Vector3 noisePosition, float noiseLoudness, int timesPlayedInOneSpot = 0, int noiseID = 0)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			if (noiseID != 1880)
			{
				return;
			}
			float num = Vector3.Distance(noisePosition, ((Component)__instance).transform.position);
			if (!(num > 25f))
			{
				if (Physics.Linecast(((EnemyAI)__instance).eye.position, noisePosition, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1))
				{
					noiseLoudness /= 2f;
				}
				if (!(noiseLoudness / num <= 0.045f) && !(__instance.timeSinceLookingAtNoise <= 4f))
				{
					__instance.timeSinceLookingAtNoise = 0f;
					__instance.lookAtNoise = noisePosition;
				}
			}
		}
	}
}
namespace Megaphone.Items
{
	public class MegaphoneItem : GrabbableObject
	{
		public AudioFiltering audioFiltering;

		protected bool isSynced;

		protected int TimesPlayedWithoutTurnedOff;

		public override void OnNetworkSpawn()
		{
			MyLog.LogDebug("OnNetworkSpawn() called");
			((NetworkBehaviour)this).OnNetworkSpawn();
		}

		public override void Start()
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			MyLog.LogDebug("MegaphoneItem item created !");
			((GrabbableObject)this).Start();
			base.itemProperties.itemIsTrigger = false;
			base.itemProperties.batteryUsage = 120f;
			base.itemProperties.syncUseFunction = true;
			base.itemProperties.syncInteractLRFunction = true;
			base.itemProperties.syncDiscardFunction = true;
			base.itemProperties.holdButtonUse = true;
			base.insertedBattery.charge = 1f;
			base.itemProperties.positionOffset = new Vector3(0.08f, 0.2f, -0.1f);
			base.itemProperties.rotationOffset = new Vector3(-90f, 180f, 38f);
			TimesPlayedWithoutTurnedOff = 0;
			audioFiltering = new AudioFiltering(this);
			isSynced = NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer;
		}

		public override void ItemInteractLeftRight(bool right)
		{
			((GrabbableObject)this).ItemInteractLeftRight(right);
			if (!right)
			{
				audioFiltering.NextFilterMode(base.isBeingUsed);
				UpdateTooltips();
			}
		}

		public override void PocketItem()
		{
			MyLog.LogDebug("PocketItem()");
			if ((Object)(object)base.playerHeldBy != (Object)null)
			{
				base.playerHeldBy.equippedUsableItemQE = false;
				base.isBeingUsed = false;
				audioFiltering.Disable();
			}
			((GrabbableObject)this).PocketItem();
		}

		public override void EquipItem()
		{
			MyLog.LogDebug("Equipped");
			((GrabbableObject)this).EquipItem();
			audioFiltering.player = base.playerHeldBy;
			if ((Object)(object)base.playerHeldBy == (Object)null)
			{
				MyLog.LogWarning("Unable to continue, player is null... Owner must re-equip the item");
				return;
			}
			base.playerHeldBy.equippedUsableItemQE = true;
			AudioMod.SetupGameobjects(base.playerHeldBy);
			UpdateTooltips();
			if (!isSynced)
			{
				MyLog.LogDebug("Syncing mode...");
				SyncAudioModeToClientsServerRpc();
			}
		}

		[ServerRpc(RequireOwnership = false)]
		public void SyncAudioModeToClientsServerRpc()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					ServerRpcParams val = default(ServerRpcParams);
					FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendServerRpc(358012765u, val, (RpcDelivery)0);
					((NetworkBehaviour)this).__endSendServerRpc(ref val2, 358012765u, val, (RpcDelivery)0);
				}
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost) && (NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer))
				{
					MyLog.LogInfo($"Sending RPC... mode='{audioFiltering.Mode}'");
					SyncAudioModeClientRpc(audioFiltering.Mode);
				}
			}
		}

		[ClientRpc]
		public void SyncAudioModeClientRpc(AudioFilteringMode mode)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val = default(ClientRpcParams);
				FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(3614960129u, val, (RpcDelivery)0);
				((FastBufferWriter)(ref val2)).WriteValueSafe<AudioFilteringMode>(ref mode, default(ForEnums));
				((NetworkBehaviour)this).__endSendClientRpc(ref val2, 3614960129u, val, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 2 && (networkManager.IsClient || networkManager.IsHost))
			{
				MyLog.LogDebug("EventClientRpc() called");
				MyLog.LogDebug($"isSynced={isSynced}");
				if (!isSynced)
				{
					isSynced = true;
					audioFiltering.SetFilterMode(mode, enable: false);
					UpdateTooltips();
					MyLog.LogInfo($"Synced to mode '{mode}'");
				}
			}
		}

		protected void UpdateTooltips()
		{
			if (((NetworkBehaviour)this).IsOwner)
			{
				string text = audioFiltering.Mode switch
				{
					AudioFilteringMode.Robot => "Robot", 
					AudioFilteringMode.Siren => "Siren", 
					AudioFilteringMode.Loud => "Loud", 
					AudioFilteringMode.HighPitch => "High Pitch", 
					AudioFilteringMode.LowPitch => "Low Pitch", 
					_ => "Unknown", 
				};
				string[] toolTips = new string[2]
				{
					"Change mode : [Q]",
					"Mode : " + text
				};
				base.itemProperties.toolTips = toolTips;
				HUDManager.Instance.ChangeControlTipMultiple(base.itemProperties.toolTips, true, base.itemProperties);
			}
		}

		public override void DiscardItem()
		{
			MyLog.LogDebug("DiscardItem()");
			base.playerHeldBy.equippedUsableItemQE = false;
			audioFiltering.Disable();
			if (base.playerHeldBy.isPlayerDead && base.isBeingUsed)
			{
				AudioMod.PlaySFX(this, AudioMod.SFX, TimesPlayedWithoutTurnedOff);
			}
			((GrabbableObject)this).DiscardItem();
		}

		public override void Update()
		{
			((GrabbableObject)this).Update();
			if (base.isBeingUsed)
			{
				TimesPlayedWithoutTurnedOff++;
				audioFiltering.PlaySirenAudibleNoiseIfApplicable(this, TimesPlayedWithoutTurnedOff);
			}
			else
			{
				TimesPlayedWithoutTurnedOff = 0;
			}
		}

		public override void ItemActivate(bool used, bool buttonDown = true)
		{
			SwitchOnOff(buttonDown);
		}

		public override void UseUpBatteries()
		{
			MyLog.LogDebug("UseUpBatteries()");
			SwitchOnOff(on: false);
			((GrabbableObject)this).UseUpBatteries();
		}

		public void SwitchOnOff(bool on)
		{
			MyLog.LogDebug($"SwitchOnOff({on})");
			AudioMod.SetupGameobjects(base.playerHeldBy);
			base.isBeingUsed = on;
			if (!((NetworkBehaviour)this).IsOwner)
			{
				if ((Object)(object)base.playerHeldBy != (Object)null)
				{
					if (!(on ? audioFiltering.Enable() : audioFiltering.Disable()))
					{
						MyLog.LogError("Unable to " + (on ? "enable" : "disable"));
					}
				}
				else
				{
					MyLog.LogWarning("playerHeldBy: null");
				}
			}
			else
			{
				MyLog.LogInfo("Megaphone click by owner");
				if (audioFiltering.Mode == AudioFilteringMode.Siren && !(on ? audioFiltering.Enable() : audioFiltering.Disable()))
				{
					MyLog.LogError("Unable to " + (on ? "enable" : "disable"));
				}
			}
		}

		protected override void __initializeVariables()
		{
			((GrabbableObject)this).__initializeVariables();
		}

		[RuntimeInitializeOnLoadMethod]
		internal static void InitializeRPCS_MegaphoneItem()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			NetworkManager.__rpc_func_table.Add(358012765u, new RpcReceiveHandler(__rpc_handler_358012765));
			NetworkManager.__rpc_func_table.Add(3614960129u, new RpcReceiveHandler(__rpc_handler_3614960129));
		}

		private static void __rpc_handler_358012765(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				target.__rpc_exec_stage = (__RpcExecStage)1;
				((MegaphoneItem)(object)target).SyncAudioModeToClientsServerRpc();
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		private static void __rpc_handler_3614960129(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_002f: 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_0044: 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)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				AudioFilteringMode mode = default(AudioFilteringMode);
				((FastBufferReader)(ref reader)).ReadValueSafe<AudioFilteringMode>(ref mode, default(ForEnums));
				target.__rpc_exec_stage = (__RpcExecStage)2;
				((MegaphoneItem)(object)target).SyncAudioModeClientRpc(mode);
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		protected internal override string __getTypeName()
		{
			return "MegaphoneItem";
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}
namespace ESN.Megaphone.NetcodePatcher
{
	[AttributeUsage(AttributeTargets.Module)]
	internal class NetcodePatchedAssemblyAttribute : Attribute
	{
	}
}