Decompiled source of ChaosCompany v0.8.0

ChaosCompany.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ChaosCompany.Brain;
using ChaosCompany.Effects;
using ChaosCompany.Items;
using ChaosCompany.Mobs;
using ChaosCompany.Net;
using ChaosCompany.Speech;
using ChaosCompany.Voice;
using Dissonance;
using Dissonance.Audio.Capture;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using NAudio.Wave;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Audio;
using UnityEngine.UI;

[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("ChaosCompany")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.8.0.0")]
[assembly: AssemblyInformationalVersion("0.8.0")]
[assembly: AssemblyProduct("ChaosCompany")]
[assembly: AssemblyTitle("ChaosCompany")]
[assembly: AssemblyVersion("0.8.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ChaosCompany
{
	public static class ChaosApi
	{
		public static string MyVoiceConsent => VoiceConsent.Mine;

		public static string BrainStatus => BrainClient.Status;

		public static string NetRole => ChaosNet.Role;

		public static bool EchoEnabled
		{
			get
			{
				return EchoMonitor.Enabled;
			}
			set
			{
				EchoMonitor.Enabled = value;
			}
		}

		public static float EchoVolume
		{
			get
			{
				return EchoMonitor.Volume;
			}
			set
			{
				EchoMonitor.Volume = value;
			}
		}

		public static float DuckVolume
		{
			get
			{
				return Plugin.DuckVolume.Value;
			}
			set
			{
				Plugin.DuckVolume.Value = Mathf.Clamp(value, 0f, 4f);
			}
		}

		public static float EchoLevel => EchoMonitor.Level;

		public static void ApplyEffect(PlayerControllerB player, EffectId id, float seconds)
		{
			if (!((Object)(object)player == (Object)null) && !(seconds <= 0f))
			{
				ChaosNet.RequestSet((int)player.playerClientId, id, seconds);
			}
		}

		public static void RemoveEffect(PlayerControllerB player, EffectId id)
		{
			if (!((Object)(object)player == (Object)null))
			{
				ChaosNet.RequestSet((int)player.playerClientId, id, 0f);
			}
		}

		public static void ClearEffects(PlayerControllerB player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				ChaosNet.RequestClear((int)player.playerClientId);
			}
		}

		public static bool HasEffect(PlayerControllerB player, EffectId id)
		{
			if ((Object)(object)player != (Object)null)
			{
				return EffectManager.Has((int)player.playerClientId, id);
			}
			return false;
		}

		public static float EffectSecondsLeft(PlayerControllerB player, EffectId id)
		{
			if (!((Object)(object)player == (Object)null))
			{
				return EffectManager.Remaining((int)player.playerClientId, id);
			}
			return 0f;
		}

		public static void SpawnItem(PlayerControllerB near, ChaosItem item)
		{
			if (!((Object)(object)near == (Object)null))
			{
				ChaosEvents.RequestSpawn(item, (int)near.playerClientId);
			}
		}

		public static void SpawnMob(PlayerControllerB near, ChaosMob mob)
		{
			if (!((Object)(object)near == (Object)null))
			{
				ChaosEvents.RequestMobSpawn(mob, (int)near.playerClientId);
			}
		}

		public static string GetPlayerNames(PlayerControllerB player)
		{
			return PlayerNames.GetVariants(player);
		}

		public static void SetPlayerNames(PlayerControllerB player, string csv)
		{
			PlayerNames.SetVariants(player, csv);
		}

		public static string VoiceConsentOf(PlayerControllerB player)
		{
			if (!VoiceConsent.IsAllowed(player))
			{
				return "нет согласия";
			}
			return "разрешил";
		}

		public static float RecordedVoiceSeconds(PlayerControllerB player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				return VoiceRecorder.RecordedSeconds(VoiceRecorder.Key(player));
			}
			return 0f;
		}

		public static void DeleteVoiceRecordings(PlayerControllerB player)
		{
			if ((Object)(object)player != (Object)null)
			{
				VoiceRecorder.Delete(VoiceRecorder.Key(player));
			}
		}

		public static void SetMyVoiceConsent(bool allow)
		{
			VoiceConsent.SetMine(allow);
		}

		public static void TestMyClone(Action<string> done)
		{
			StartOfRound instance = StartOfRound.Instance;
			PlayerControllerB me = (((Object)(object)instance != (Object)null) ? instance.localPlayerController : null);
			if ((Object)(object)me == (Object)null)
			{
				done("нет игрока");
				return;
			}
			string playerKey = VoiceRecorder.Key(me);
			if (!BrainClient.Available)
			{
				done("компаньон не подключён");
				return;
			}
			if (!BrainClient.HasClone(playerKey))
			{
				done("клона нет: нужно согласие и хотя бы ~8 с записей (список обновляется раз в 30 с)");
				return;
			}
			string line = DuckInserts.PickLine(instance, me) ?? "картошка в тапках";
			BrainClient.RequestSpeakAs(playerKey, line, delegate(byte[] audio)
			{
				if (audio == null)
				{
					done("не получилось (на вылазке - только заранее озвученное; попробуй на орбите)");
				}
				else
				{
					VoiceEffects.PlayInsert((int)me.playerClientId, audio);
					done("«" + line + "»");
				}
			});
		}

		public static void TestBrain(PlayerControllerB player, Action<string> done)
		{
			Dictionary<string, string> context = new Dictionary<string, string> { 
			{
				"игрок",
				((Object)(object)player != (Object)null) ? player.playerUsername : "кто-то"
			} };
			BrainClient.RequestLine("anatoly", "compare", context, done);
		}
	}
	internal class ChaosRunner : MonoBehaviour
	{
		private static ChaosRunner instance;

		internal static ChaosRunner Instance => instance;

		internal static void Ensure()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)instance != (Object)null))
			{
				instance = new GameObject("ChaosCompany_Runner").AddComponent<ChaosRunner>();
				((Component)instance).gameObject.AddComponent<ConsentPrompt>();
			}
		}

		private void Update()
		{
			EffectManager.Tick();
			EchoMonitor.EnsureState();
			VoiceEffects.Update();
			BrainClient.Update();
			VoiceRecorder.Update();
			DuckInserts.Update();
		}

		private void LateUpdate()
		{
			BodyEffects.LateUpdate();
		}

		private void OnGUI()
		{
			BodyEffects.OnGUI();
		}
	}
	[BepInPlugin("claude.chaoscompany", "ChaosCompany", "0.8.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "claude.chaoscompany";

		public const string Name = "ChaosCompany";

		public const string Version = "0.8.0";

		internal static ManualLogSource Log;

		private Harmony harmony;

		internal static ConfigEntry<bool> HitEffectsEnabled;

		internal static ConfigEntry<float> HitEffectDuration;

		internal static ConfigEntry<float> DuckVolume;

		internal static ConfigEntry<bool> BrainEnabled;

		internal static ConfigEntry<string> BrainUrl;

		internal static ConfigEntry<string> VoiceConsent;

		internal static ConfigEntry<bool> RecordVoices;

		internal static ConfigEntry<float> MaxVoiceSecondsPerPlayer;

		private void Awake()
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Expected O, but got Unknown
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			HitEffectsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Test", "VoiceEffectOnEnemyHit", true, "Temporary test hook: when an enemy hurts you, you get a random voice effect.");
			HitEffectDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Test", "VoiceEffectOnEnemyHitSeconds", 20f, "Duration of that effect in seconds.");
			BrainEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("AI", "UseChaosBrain", true, "Host only: take monster lines from the ChaosBrain companion app (local neural network). If it's not running, phrase files are used.");
			BrainUrl = ((BaseUnityPlugin)this).Config.Bind<string>("AI", "ChaosBrainUrl", "http://127.0.0.1:5077", "Address of the ChaosBrain companion app.");
			VoiceConsent = ((BaseUnityPlugin)this).Config.Bind<string>("Voice", "VoiceConsent", "Ask", new ConfigDescription("Do you allow the HOST of a ChaosCompany game to record your voice so monsters can speak with it? Recordings stay only on the host's computer. Ask = show the question in game, Allow, Deny. Changing to Deny makes the host delete your recordings.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "Ask", "Allow", "Deny" }), Array.Empty<object>()));
			RecordVoices = ((BaseUnityPlugin)this).Config.Bind<bool>("Voice", "RecordVoicesAsHost", true, "Host only: record voices of players who allowed it (for voice clones).");
			MaxVoiceSecondsPerPlayer = ((BaseUnityPlugin)this).Config.Bind<float>("Voice", "MaxVoiceSecondsPerPlayer", 300f, "Host only: how many seconds of voice to keep per player (older recordings are deleted).");
			DuckVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Sound", "DuckVolume", 2f, "Volume of the duck quack (1 = normal, up to 4).");
			VoiceConsent.SettingChanged += delegate
			{
				ChaosCompany.Voice.VoiceConsent.SendMine();
			};
			harmony = new Harmony("claude.chaoscompany");
			harmony.PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)"ChaosCompany 0.8.0 loaded");
		}
	}
}
namespace ChaosCompany.Voice
{
	internal static class DuckInserts
	{
		private static readonly string[] Categories = new string[8] { "insult", "insult_friend", "dare", "annoying", "nonsense", "confession", "offtopic", "quack" };

		private static readonly Dictionary<int, float> next = new Dictionary<int, float>();

		private static readonly HashSet<int> pending = new HashSet<int>();

		private static bool IsHost
		{
			get
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if (!((Object)(object)singleton == (Object)null) && singleton.IsListening)
				{
					return singleton.IsServer;
				}
				return true;
			}
		}

		internal static void Update()
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null || !IsHost || !BrainClient.Available)
			{
				return;
			}
			float time = Time.time;
			for (int i = 0; i < instance.allPlayerScripts.Length; i++)
			{
				PlayerControllerB val = instance.allPlayerScripts[i];
				if ((Object)(object)val == (Object)null || !val.isPlayerControlled || val.isPlayerDead || !EffectManager.Has(i, EffectId.Duck) || pending.Contains(i))
				{
					continue;
				}
				string playerKey = VoiceRecorder.Key(val);
				if (!BrainClient.HasClone(playerKey))
				{
					continue;
				}
				if (!next.TryGetValue(i, out var value))
				{
					value = (next[i] = time + Random.Range(1.5f, 3f));
				}
				if (!IsSpeaking(instance, val))
				{
					if (value < time + 1f)
					{
						next[i] = time + 1f;
					}
				}
				else
				{
					if (time < value)
					{
						continue;
					}
					next[i] = time + Random.Range(4f, 9f);
					string text = PickLine(instance, val);
					if (text == null)
					{
						continue;
					}
					int player = i;
					pending.Add(player);
					BrainClient.RequestSpeakAs(playerKey, text, delegate(byte[] audio)
					{
						pending.Remove(player);
						PlayerControllerB val2 = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.allPlayerScripts[player] : null);
						if (audio != null && (Object)(object)val2 != (Object)null && IsSpeaking(StartOfRound.Instance, val2))
						{
							ChaosEvents.ServerPlayerInsert(player, MatchLoudness(audio, VoiceRecorder.VoiceRms(val2)));
						}
					});
				}
			}
		}

		private static bool IsSpeaking(StartOfRound sor, PlayerControllerB p)
		{
			if ((Object)(object)p == (Object)(object)sor.localPlayerController)
			{
				DissonanceComms voiceChatModule = sor.voiceChatModule;
				VoicePlayerState val = (((Object)(object)voiceChatModule != (Object)null) ? voiceChatModule.FindPlayer(voiceChatModule.LocalPlayerName) : null);
				if (val != null)
				{
					return val.IsSpeaking;
				}
				return false;
			}
			if (p.voicePlayerState != null)
			{
				return p.voicePlayerState.IsSpeaking;
			}
			return false;
		}

		internal static string PickLine(StartOfRound sor, PlayerControllerB speaker)
		{
			PhraseBank phraseBank = PhraseBank.Get("duck", Mobs_.DuckDefaults);
			for (int i = 0; i < 8; i++)
			{
				string text = Categories[Random.Range(0, Categories.Length)];
				string playerName = null;
				if (text == "insult_friend")
				{
					List<PlayerControllerB> list = new List<PlayerControllerB>();
					PlayerControllerB[] allPlayerScripts = sor.allPlayerScripts;
					foreach (PlayerControllerB val in allPlayerScripts)
					{
						if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)speaker && val.isPlayerControlled)
						{
							list.Add(val);
						}
					}
					if (list.Count == 0)
					{
						continue;
					}
					playerName = PlayerNames.Spoken(list[Random.Range(0, list.Count)]);
				}
				string text2 = phraseBank.Pick(text, playerName, allowRepeat: true);
				if (!string.IsNullOrEmpty(text2))
				{
					return text2;
				}
			}
			return null;
		}

		internal static byte[] MatchLoudness(byte[] ulaw, float targetRms)
		{
			if (targetRms <= 0f)
			{
				return ulaw;
			}
			float[] array = MobSpeaker.DecodeUlaw(ulaw);
			float num = 0f;
			float[] array2 = array;
			foreach (float num2 in array2)
			{
				num = Mathf.Max(num, Mathf.Abs(num2));
			}
			double num3 = 0.0;
			int num4 = 0;
			array2 = array;
			foreach (float num5 in array2)
			{
				if (Mathf.Abs(num5) > num * 0.1f)
				{
					num3 += (double)(num5 * num5);
					num4++;
				}
			}
			if (num4 == 0)
			{
				return ulaw;
			}
			float num6 = (float)Math.Sqrt(num3 / (double)num4);
			float num7 = Mathf.Clamp(targetRms / num6, 0.15f, 4f);
			for (int j = 0; j < array.Length; j++)
			{
				array[j] = Mathf.Clamp(array[j] * num7, -0.99f, 0.99f);
			}
			return MobSpeaker.EncodeUlaw(array);
		}

		internal static void Reset()
		{
			next.Clear();
			pending.Clear();
		}
	}
	internal static class DuckSound
	{
		private static AudioClip[] clips;

		private static bool searched;

		internal static AudioClip Get()
		{
			if (!searched)
			{
				Find();
			}
			if (clips == null || clips.Length == 0)
			{
				return null;
			}
			return clips[Random.Range(0, clips.Length)];
		}

		private static void Find()
		{
			searched = true;
			AudioClip val = LoadEmbeddedWav("ChaosCompany.quack.wav");
			if ((Object)(object)val != (Object)null)
			{
				clips = (AudioClip[])(object)new AudioClip[1] { val };
				Plugin.Log.LogInfo((object)"Duck sound: embedded quack");
				return;
			}
			List<Item> list = (((Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)StartOfRound.Instance.allItemsList != (Object)null) ? StartOfRound.Instance.allItemsList.itemsList : null);
			if (list != null)
			{
				foreach (Item item in list)
				{
					if (!((Object)(object)item == (Object)null) && !((Object)(object)item.spawnPrefab == (Object)null) && item.itemName != null && item.itemName.ToLowerInvariant().IndexOf("duck") >= 0)
					{
						NoisemakerProp component = item.spawnPrefab.GetComponent<NoisemakerProp>();
						if ((Object)(object)component != (Object)null && component.noiseSFX != null && component.noiseSFX.Length != 0)
						{
							clips = component.noiseSFX;
							Plugin.Log.LogInfo((object)$"Duck sound: using '{item.itemName}' ({clips.Length} clips)");
							return;
						}
					}
				}
			}
			clips = (AudioClip[])(object)new AudioClip[1] { Synth() };
			Plugin.Log.LogWarning((object)"Duck sound: Rubber Ducky not found, using synthesized quack");
		}

		private static AudioClip LoadEmbeddedWav(string name)
		{
			try
			{
				using Stream stream = typeof(DuckSound).Assembly.GetManifestResourceStream(name);
				if (stream == null)
				{
					return null;
				}
				byte[] array = new byte[stream.Length];
				stream.Read(array, 0, array.Length);
				int num = BitConverter.ToInt16(array, 22);
				int num2 = BitConverter.ToInt32(array, 24);
				int i = 12;
				int num3 = -1;
				int num4 = 0;
				int num5;
				for (; i + 8 <= array.Length; i += 8 + num5)
				{
					string text = Encoding.ASCII.GetString(array, i, 4);
					num5 = BitConverter.ToInt32(array, i + 4);
					if (text == "data")
					{
						num3 = i + 8;
						num4 = num5;
						break;
					}
				}
				if (num3 < 0)
				{
					return null;
				}
				int num6 = num4 / 2 / num;
				float[] array2 = new float[num6];
				for (int j = 0; j < num6; j++)
				{
					array2[j] = (float)BitConverter.ToInt16(array, num3 + j * 2 * num) / 32768f;
				}
				AudioClip obj = AudioClip.Create("chaos_quack", num6, 1, num2, false);
				obj.SetData(array2, 0);
				return obj;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Embedded sound " + name + ": " + ex.Message));
				return null;
			}
		}

		private static AudioClip Synth()
		{
			int num = 44100;
			int num2 = (int)((float)num * 0.22f);
			float[] array = new float[num2];
			float num3 = 0f;
			float num4 = 0f;
			for (int i = 0; i < num2; i++)
			{
				float num5 = (float)i / (float)num2;
				float num6 = Mathf.Lerp(620f, 380f, num5);
				num3 += num6 / (float)num;
				num3 -= Mathf.Floor(num3);
				float num7 = num3 * 2f - 1f;
				num4 += 0.35f * (num7 - num4);
				float num8 = Mathf.Min(1f, num5 * 25f) * (1f - num5) * (1f - num5);
				array[i] = (num7 - num4) * num8 * 0.8f;
			}
			AudioClip obj = AudioClip.Create("chaos_quack", num2, 1, num, false);
			obj.SetData(array, 0);
			return obj;
		}
	}
	internal class EchoMonitor : MonoBehaviour, IMicrophoneSubscriber
	{
		private static EchoMonitor instance;

		private static bool wanted;

		public static float Volume = 1f;

		private AudioSource source;

		private VoiceFilter filter;

		private DissonanceComms comms;

		private const int RingSize = 65536;

		private readonly float[] ring = new float[65536];

		private readonly object sync = new object();

		private long writePos;

		private double readPos;

		private volatile int micRate = 48000;

		private int outRate = 48000;

		private volatile bool transmitting;

		private volatile float volume = 1f;

		private float gate;

		private float peak;

		public static float Level { get; private set; }

		public static bool Enabled
		{
			get
			{
				return wanted;
			}
			set
			{
				wanted = value;
				if (value)
				{
					TryCreate();
				}
				else
				{
					Shutdown();
				}
			}
		}

		internal static VoiceFilter Filter
		{
			get
			{
				if (!((Object)(object)instance != (Object)null))
				{
					return null;
				}
				return instance.filter;
			}
		}

		internal static void EnsureState()
		{
			if (wanted && (Object)(object)instance == (Object)null)
			{
				TryCreate();
			}
		}

		internal static void Shutdown()
		{
			if ((Object)(object)instance != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)instance).gameObject);
			}
			instance = null;
			Level = 0f;
		}

		private static void TryCreate()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			if (!((Object)(object)instance != (Object)null))
			{
				DissonanceComms val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.voiceChatModule : null);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)SoundManager.Instance == (Object)null))
				{
					GameObject val2 = new GameObject("ChaosCompany_EchoMonitor");
					AudioSource val3 = val2.AddComponent<AudioSource>();
					instance = val2.AddComponent<EchoMonitor>();
					instance.filter = val2.AddComponent<VoiceFilter>();
					instance.source = val3;
					instance.comms = val;
					int outputSampleRate = AudioSettings.outputSampleRate;
					val3.clip = AudioClip.Create("chaos_silence", outputSampleRate, 1, outputSampleRate, false);
					val3.loop = true;
					val3.spatialBlend = 0f;
					val3.playOnAwake = false;
					val3.Play();
					val.SubscribeToRecordedAudio((IMicrophoneSubscriber)(object)instance);
					Plugin.Log.LogInfo((object)"Echo monitor ON");
				}
			}
		}

		private void Awake()
		{
			outRate = AudioSettings.outputSampleRate;
		}

		private void Update()
		{
			PlayerControllerB val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.localPlayerController : null);
			if ((Object)(object)val != (Object)null && (Object)(object)SoundManager.Instance != (Object)null)
			{
				AudioMixerGroup[] playerVoiceMixers = SoundManager.Instance.playerVoiceMixers;
				int num = (int)val.playerClientId;
				if (playerVoiceMixers != null && num < playerVoiceMixers.Length && (Object)(object)source.outputAudioMixerGroup != (Object)(object)playerVoiceMixers[num])
				{
					source.outputAudioMixerGroup = playerVoiceMixers[num];
				}
			}
			VoicePlayerState val2 = (((Object)(object)comms != (Object)null) ? comms.FindPlayer(comms.LocalPlayerName) : null);
			transmitting = val2 != null && val2.IsSpeaking;
			volume = Volume;
			Level = Mathf.Lerp(Level, peak, 0.3f);
			peak *= 0.8f;
		}

		private void OnDestroy()
		{
			if ((Object)(object)comms != (Object)null)
			{
				comms.UnsubscribeFromRecordedAudio((IMicrophoneSubscriber)(object)this);
			}
			Plugin.Log.LogInfo((object)"Echo monitor OFF");
		}

		public void ReceiveMicrophoneData(ArraySegment<float> buffer, WaveFormat format)
		{
			int num = Math.Max(1, format.Channels);
			micRate = format.SampleRate;
			float num2 = 0f;
			lock (sync)
			{
				for (int i = buffer.Offset; i < buffer.Offset + buffer.Count; i += num)
				{
					float num3 = buffer.Array[i];
					ring[writePos & 0xFFFF] = num3;
					writePos++;
					if (num3 > num2)
					{
						num2 = num3;
					}
					else if (0f - num3 > num2)
					{
						num2 = 0f - num3;
					}
				}
			}
			if (num2 > peak)
			{
				peak = num2;
			}
		}

		public void Reset()
		{
			lock (sync)
			{
				writePos = 0L;
				readPos = 0.0;
			}
		}

		private void OnAudioFilterRead(float[] data, int channels)
		{
			double num = (double)micRate / (double)outRate;
			float num2 = (transmitting ? 1f : 0f);
			float num3 = volume;
			lock (sync)
			{
				if ((double)writePos - readPos > (double)micRate * 0.3)
				{
					readPos = (double)writePos - (double)micRate * 0.06;
				}
				if (readPos < (double)(writePos - 65536 + 2))
				{
					readPos = writePos - 65536 + 2;
				}
				for (int i = 0; i < data.Length; i += channels)
				{
					float num4 = 0f;
					long num5 = (long)readPos;
					if (num5 + 1 < writePos)
					{
						float num6 = (float)(readPos - (double)num5);
						float num7 = ring[num5 & 0xFFFF];
						float num8 = ring[(num5 + 1) & 0xFFFF];
						num4 = num7 + (num8 - num7) * num6;
						readPos += num;
					}
					gate += (num2 - gate) * 0.002f;
					num4 *= gate * num3;
					for (int j = 0; j < channels; j++)
					{
						data[i + j] = num4;
					}
				}
			}
		}
	}
	internal static class VoiceConsent
	{
		private static readonly Dictionary<int, bool> allowed = new Dictionary<int, bool>();

		internal static string Mine => Plugin.VoiceConsent.Value;

		internal static bool NeedsAnswer => Mine == "Ask";

		internal static void Reset()
		{
			allowed.Clear();
		}

		internal static bool IsAllowed(PlayerControllerB p)
		{
			bool value = default(bool);
			return (Object)(object)p != (Object)null && allowed.TryGetValue((int)p.playerClientId, out value) && value;
		}

		internal static void SetMine(bool allow)
		{
			Plugin.VoiceConsent.Value = (allow ? "Allow" : "Deny");
			SendMine();
		}

		internal static void SendMine()
		{
			PlayerControllerB val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.localPlayerController : null);
			if (!((Object)(object)val == (Object)null) && !NeedsAnswer)
			{
				ChaosEvents.SendConsent((int)val.playerClientId, Mine == "Allow");
			}
		}

		internal static void OnConsent(int player, bool allow)
		{
			StartOfRound instance = StartOfRound.Instance;
			if (!((Object)(object)instance == (Object)null) && player >= 0 && player < instance.allPlayerScripts.Length)
			{
				allowed[player] = allow;
				PlayerControllerB val = instance.allPlayerScripts[player];
				Plugin.Log.LogInfo((object)("Voice consent: " + val.playerUsername + " -> " + (allow ? "allowed" : "denied")));
				if (!allow)
				{
					VoiceRecorder.Delete(VoiceRecorder.Key(val));
				}
			}
		}
	}
	internal class ConsentPrompt : MonoBehaviour
	{
		private float showAt;

		private bool visible;

		private Rect window;

		private bool sent;

		private void Start()
		{
			showAt = Time.time + 6f;
		}

		private void Update()
		{
			if (!sent && !VoiceConsent.NeedsAnswer && (Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)StartOfRound.Instance.localPlayerController != (Object)null)
			{
				VoiceConsent.SendMine();
				sent = true;
			}
			bool flag = VoiceConsent.NeedsAnswer && Time.time >= showAt && (Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)StartOfRound.Instance.localPlayerController != (Object)null;
			if (flag != visible)
			{
				visible = flag;
				SetInputBlocked(visible);
			}
			if (visible)
			{
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
		}

		private static void SetInputBlocked(bool blocked)
		{
			PlayerControllerB val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.localPlayerController : null);
			if (!((Object)(object)val == (Object)null))
			{
				val.disableLookInput = blocked;
				val.disableMoveInput = blocked;
				val.disableInteract = blocked;
				if (!blocked)
				{
					Cursor.lockState = (CursorLockMode)1;
					Cursor.visible = false;
				}
			}
		}

		private void OnGUI()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			if (visible)
			{
				GUI.depth = -10;
				float num = (float)Screen.height / 1080f * 1.6f;
				GUI.matrix = Matrix4x4.Scale(new Vector3(num, num, 1f));
				float num2 = 560f;
				float num3 = 300f;
				window = new Rect(((float)Screen.width / num - num2) / 2f, ((float)Screen.height / num - num3) / 2f, num2, num3);
				GUILayout.Window(805382, window, new WindowFunction(Draw), "ChaosCompany", Array.Empty<GUILayoutOption>());
			}
		}

		private void Draw(int id)
		{
			//IL_000a: 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)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				wordWrap = true,
				fontSize = 15
			};
			GUILayout.Label("На этом сервере стоит мод ChaosCompany: монстры могут говорить голосами игроков.\n\nРазрешаешь хосту записывать твой голос для этого? Записи хранятся только у хоста. Согласие можно отозвать в любой момент в настройках мода (VoiceConsent) - тогда хост удалит твои записи.\n\nThis server runs ChaosCompany: monsters can speak with players' voices. Allow the host to record your voice for that? Stored only on the host's PC, can be revoked any time.", val, Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Разрешаю / Allow", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) }))
			{
				Answer(allow: true);
			}
			if (GUILayout.Button("Не разрешаю / Deny", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) }))
			{
				Answer(allow: false);
			}
			GUILayout.EndHorizontal();
		}

		private void Answer(bool allow)
		{
			VoiceConsent.SetMine(allow);
			sent = true;
			visible = false;
			SetInputBlocked(blocked: false);
		}
	}
	internal static class VoiceEffects
	{
		internal static float[] PitchMul = new float[0];

		private static bool[] pitchOverridden = new bool[0];

		private static float[] nextQuack = new float[0];

		private static float[] muteUntil = new float[0];

		private static readonly Dictionary<int, AudioSource> quackSources = new Dictionary<int, AudioSource>();

		private static readonly Dictionary<AudioSource, VoiceFilter> filters = new Dictionary<AudioSource, VoiceFilter>();

		private static readonly Dictionary<int, AudioSource> insertSources = new Dictionary<int, AudioSource>();

		internal static void Reset()
		{
			PitchMul = new float[0];
			pitchOverridden = new bool[0];
			nextQuack = new float[0];
			muteUntil = new float[0];
			quackSources.Clear();
			insertSources.Clear();
			filters.Clear();
		}

		internal static void Update()
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null || instance.allPlayerScripts == null)
			{
				return;
			}
			PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts;
			EnsureArrays(allPlayerScripts.Length);
			float time = Time.time;
			PlayerControllerB localPlayerController = instance.localPlayerController;
			bool flag = (Object)(object)localPlayerController != (Object)null && !localPlayerController.isPlayerDead && EffectManager.Has((int)localPlayerController.playerClientId, EffectId.Drunk);
			for (int i = 0; i < allPlayerScripts.Length; i++)
			{
				PlayerControllerB val = allPlayerScripts[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				bool num = val.isPlayerControlled && !val.isPlayerDead;
				float num2 = 1f;
				float num3 = 0f;
				if (num)
				{
					if (EffectManager.Has(i, EffectId.PitchUp))
					{
						num2 *= 1.45f;
					}
					if (EffectManager.Has(i, EffectId.PitchDown))
					{
						num2 *= 0.72f;
					}
					if (EffectManager.Has(i, EffectId.Wave))
					{
						num2 *= 1f + 0.28f * Mathf.Sin(time * 2f * MathF.PI * 0.6f + (float)i);
					}
					if (EffectManager.Has(i, EffectId.Drunk))
					{
						num2 *= 1f + 0.18f * (Mathf.PerlinNoise(time * 0.7f, (float)i * 3.1f) * 2f - 1f);
						num3 = 2200f;
					}
					if (EffectManager.Has(i, EffectId.Muffled))
					{
						num3 = 500f;
					}
				}
				PitchMul[i] = num2;
				bool flag2 = (Object)(object)val == (Object)(object)instance.localPlayerController;
				if (!flag2 && flag)
				{
					num3 = ((num3 > 0f) ? Mathf.Min(num3, 1200f) : 1200f);
				}
				VoiceFilter voiceFilter = (flag2 ? EchoMonitor.Filter : GetFilter(val.currentVoiceChatAudioSource));
				if (num && EffectManager.Has(i, EffectId.Duck))
				{
					UpdateDuck(val, i, flag2, time);
				}
				if ((Object)(object)voiceFilter != (Object)null)
				{
					voiceFilter.LowpassHz = num3;
					voiceFilter.Gain = ((time < muteUntil[i]) ? 0f : 1f);
				}
			}
		}

		internal static void ApplyPitch(SoundManager sm)
		{
			float[] playerVoicePitches = sm.playerVoicePitches;
			if (playerVoicePitches == null)
			{
				return;
			}
			int num = Mathf.Min(PitchMul.Length, playerVoicePitches.Length);
			for (int i = 0; i < num; i++)
			{
				if (!Mathf.Approximately(PitchMul[i], 1f))
				{
					sm.SetPlayerPitch(playerVoicePitches[i] * PitchMul[i], i);
					pitchOverridden[i] = true;
				}
				else if (pitchOverridden[i])
				{
					sm.SetPlayerPitch(playerVoicePitches[i], i);
					pitchOverridden[i] = false;
				}
			}
		}

		private static VoiceFilter GetFilter(AudioSource src)
		{
			if ((Object)(object)src == (Object)null)
			{
				return null;
			}
			if (filters.TryGetValue(src, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			value = ((Component)src).GetComponent<VoiceFilter>();
			if ((Object)(object)((Component)src).GetComponent<VoiceTap>() == (Object)null)
			{
				if ((Object)(object)value != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)value);
				}
				((Component)src).gameObject.AddComponent<VoiceTap>();
				value = null;
			}
			if ((Object)(object)value == (Object)null)
			{
				value = ((Component)src).gameObject.AddComponent<VoiceFilter>();
			}
			filters[src] = value;
			return value;
		}

		private static void UpdateDuck(PlayerControllerB p, int i, bool isLocal, float t)
		{
			bool flag;
			if (isLocal)
			{
				DissonanceComms voiceChatModule = StartOfRound.Instance.voiceChatModule;
				VoicePlayerState val = (((Object)(object)voiceChatModule != (Object)null) ? voiceChatModule.FindPlayer(voiceChatModule.LocalPlayerName) : null);
				flag = val != null && val.IsSpeaking;
			}
			else
			{
				flag = p.voicePlayerState != null && p.voicePlayerState.IsSpeaking;
			}
			if (!flag)
			{
				if (nextQuack[i] < t + 0.7f)
				{
					nextQuack[i] = t + 0.7f;
				}
			}
			else if (!(t < nextQuack[i]))
			{
				AudioClip val2 = DuckSound.Get();
				if (!((Object)(object)val2 == (Object)null))
				{
					AudioSource quackSource = GetQuackSource(p, i, isLocal);
					quackSource.pitch = Random.Range(0.9f, 1.2f);
					quackSource.PlayOneShot(val2, Mathf.Clamp(Plugin.DuckVolume.Value, 0f, 4f));
					float num = Mathf.Clamp(val2.length / quackSource.pitch, 0.35f, 1f);
					muteUntil[i] = t + num;
					nextQuack[i] = t + num + Random.Range(1.2f, 3f);
				}
			}
		}

		internal static void PlayInsert(int player, byte[] ulaw)
		{
			StartOfRound instance = StartOfRound.Instance;
			if (!((Object)(object)instance == (Object)null) && ulaw != null && player >= 0 && player < instance.allPlayerScripts.Length)
			{
				PlayerControllerB val = instance.allPlayerScripts[player];
				EnsureArrays(instance.allPlayerScripts.Length);
				AudioClip val2 = MobSpeaker.DecodeVoice(ulaw);
				GetInsertSource(val, player, (Object)(object)val == (Object)(object)instance.localPlayerController).PlayOneShot(val2, 1f);
				muteUntil[player] = Time.time + val2.length + 0.15f;
				Object.Destroy((Object)(object)val2, val2.length + 1f);
			}
		}

		private static AudioSource GetInsertSource(PlayerControllerB p, int i, bool isLocal)
		{
			//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)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Invalid comparison between Unknown and I4
			if (!insertSources.TryGetValue(i, out var value) || (Object)(object)value == (Object)null)
			{
				GameObject val = new GameObject("ChaosCompany_VoiceInsert");
				val.transform.SetParent(((Component)p).transform, false);
				val.transform.localPosition = new Vector3(0f, 1.6f, 0f);
				value = val.AddComponent<AudioSource>();
				value.playOnAwake = false;
				insertSources[i] = value;
			}
			AudioSource currentVoiceChatAudioSource = p.currentVoiceChatAudioSource;
			if (isLocal || (Object)(object)currentVoiceChatAudioSource == (Object)null)
			{
				value.spatialBlend = 0f;
				return value;
			}
			value.outputAudioMixerGroup = currentVoiceChatAudioSource.outputAudioMixerGroup;
			value.volume = currentVoiceChatAudioSource.volume;
			value.spatialBlend = currentVoiceChatAudioSource.spatialBlend;
			value.rolloffMode = currentVoiceChatAudioSource.rolloffMode;
			value.minDistance = currentVoiceChatAudioSource.minDistance;
			value.maxDistance = currentVoiceChatAudioSource.maxDistance;
			value.spread = currentVoiceChatAudioSource.spread;
			value.dopplerLevel = currentVoiceChatAudioSource.dopplerLevel;
			if ((int)currentVoiceChatAudioSource.rolloffMode == 2)
			{
				value.SetCustomCurve((AudioSourceCurveType)0, currentVoiceChatAudioSource.GetCustomCurve((AudioSourceCurveType)0));
			}
			return value;
		}

		private static AudioSource GetQuackSource(PlayerControllerB p, int i, bool isLocal)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (quackSources.TryGetValue(i, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			GameObject val = new GameObject("ChaosCompany_Quack");
			val.transform.SetParent(((Component)p).transform, false);
			val.transform.localPosition = new Vector3(0f, 1.6f, 0f);
			value = val.AddComponent<AudioSource>();
			value.playOnAwake = false;
			value.spatialBlend = (isLocal ? 0f : 1f);
			value.rolloffMode = (AudioRolloffMode)1;
			value.minDistance = 2f;
			value.maxDistance = 35f;
			quackSources[i] = value;
			return value;
		}

		private static void EnsureArrays(int n)
		{
			if (PitchMul.Length != n)
			{
				PitchMul = new float[n];
				for (int i = 0; i < n; i++)
				{
					PitchMul[i] = 1f;
				}
				pitchOverridden = new bool[n];
				nextQuack = new float[n];
				muteUntil = new float[n];
			}
		}
	}
	internal class VoiceFilter : MonoBehaviour
	{
		public volatile float LowpassHz;

		public volatile float Gain = 1f;

		private int sampleRate = 48000;

		private float gain = 1f;

		private readonly float[] z1 = new float[8];

		private readonly float[] z2 = new float[8];

		private void Awake()
		{
			sampleRate = AudioSettings.outputSampleRate;
		}

		private void OnAudioFilterRead(float[] data, int channels)
		{
			float lowpassHz = LowpassHz;
			float num = Gain;
			if (channels > 8)
			{
				return;
			}
			if (lowpassHz <= 0f && num >= 1f && gain >= 0.999f)
			{
				gain = 1f;
				return;
			}
			float num2 = ((lowpassHz > 0f) ? (1f - Mathf.Exp(MathF.PI * -2f * lowpassHz / (float)sampleRate)) : 0f);
			float num3 = 1f / (0.005f * (float)sampleRate);
			for (int i = 0; i < data.Length; i += channels)
			{
				gain = Mathf.MoveTowards(gain, num, num3);
				for (int j = 0; j < channels; j++)
				{
					float num4 = data[i + j];
					if (lowpassHz > 0f)
					{
						z1[j] += num2 * (num4 - z1[j]);
						z2[j] += num2 * (z1[j] - z2[j]);
						num4 = z2[j] * 1.4f;
					}
					data[i + j] = num4 * gain;
				}
			}
		}
	}
	internal static class VoiceRecorder
	{
		private class Segment
		{
			public readonly List<float> Samples = new List<float>();

			public int Rate;

			public float LastSpeech;
		}

		private const int OutRate = 24000;

		private const float MinSegment = 2f;

		private const float MaxSegment = 12f;

		private const float SilenceGap = 0.8f;

		private static readonly Dictionary<string, Segment> segments = new Dictionary<string, Segment>();

		private static readonly Dictionary<string, float> seconds = new Dictionary<string, float>();

		private static MicTap mic;

		internal static string Root => Path.Combine(Application.persistentDataPath, "ChaosCompany_voices");

		private static bool IsHost
		{
			get
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if (!((Object)(object)singleton == (Object)null) && singleton.IsListening)
				{
					return singleton.IsServer;
				}
				return true;
			}
		}

		internal static string Key(PlayerControllerB p)
		{
			if (p.playerSteamId != 0L)
			{
				return p.playerSteamId.ToString();
			}
			StringBuilder stringBuilder = new StringBuilder();
			string playerUsername = p.playerUsername;
			foreach (char c in playerUsername)
			{
				stringBuilder.Append(char.IsLetterOrDigit(c) ? c : '_');
			}
			return "nick_" + stringBuilder;
		}

		internal static void Update()
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null || !Plugin.RecordVoices.Value || !IsHost)
			{
				return;
			}
			float time = Time.time;
			EnsureMic(instance);
			PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if ((Object)(object)val == (Object)null || !val.isPlayerControlled)
				{
					continue;
				}
				bool flag = (Object)(object)val == (Object)(object)instance.localPlayerController;
				bool flag2 = VoiceConsent.IsAllowed(val);
				VoiceTap voiceTap = (flag ? null : (((Object)(object)val.currentVoiceChatAudioSource != (Object)null) ? ((Component)val.currentVoiceChatAudioSource).GetComponent<VoiceTap>() : null));
				if (!flag2)
				{
					if (flag && mic != null)
					{
						mic.Capture = false;
					}
					if ((Object)(object)voiceTap != (Object)null)
					{
						voiceTap.Capture = false;
					}
					continue;
				}
				string key = Key(val);
				bool flag3 = RecordedSeconds(key) >= Plugin.MaxVoiceSecondsPerPlayer.Value;
				bool flag4;
				ConcurrentQueue<float[]> chunks;
				int rate;
				if (flag)
				{
					if (mic == null)
					{
						continue;
					}
					DissonanceComms voiceChatModule = instance.voiceChatModule;
					VoicePlayerState val2 = (((Object)(object)voiceChatModule != (Object)null) ? voiceChatModule.FindPlayer(voiceChatModule.LocalPlayerName) : null);
					flag4 = val2 != null && val2.IsSpeaking && !val.isPlayerDead;
					mic.Capture = flag4 && !flag3;
					chunks = mic.Chunks;
					rate = mic.Rate;
				}
				else
				{
					if ((Object)(object)voiceTap == (Object)null)
					{
						continue;
					}
					flag4 = val.voicePlayerState != null && val.voicePlayerState.IsSpeaking && IsClean(val.currentVoiceChatAudioSource);
					voiceTap.Capture = flag4 && !flag3;
					chunks = voiceTap.Chunks;
					rate = voiceTap.Rate;
				}
				if (!segments.TryGetValue(key, out var value))
				{
					value = (segments[key] = new Segment());
				}
				float[] result;
				while (chunks.TryDequeue(out result))
				{
					value.Rate = rate;
					value.Samples.AddRange(result);
				}
				if (flag4)
				{
					value.LastSpeech = time;
				}
				float num = ((value.Rate > 0) ? ((float)value.Samples.Count / (float)value.Rate) : 0f);
				if (num > 0f && (time - value.LastSpeech > 0.8f || num >= 12f))
				{
					if (num >= 2f)
					{
						Save(key, value.Samples.ToArray(), value.Rate, val.playerUsername);
					}
					value.Samples.Clear();
				}
			}
		}

		internal static float UpdateRms(float current, float[] chunk)
		{
			double num = 0.0;
			foreach (float num2 in chunk)
			{
				num += (double)(num2 * num2);
			}
			float num3 = (float)Math.Sqrt(num / (double)Math.Max(1, chunk.Length));
			if (num3 < 0.005f)
			{
				return current;
			}
			if (!(current <= 0f))
			{
				return current * 0.97f + num3 * 0.03f;
			}
			return num3;
		}

		internal static float VoiceRms(PlayerControllerB p)
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)p == (Object)null)
			{
				return 0f;
			}
			if ((Object)(object)p == (Object)(object)instance.localPlayerController)
			{
				if (mic == null)
				{
					return 0f;
				}
				return mic.Rms;
			}
			VoiceTap voiceTap = (((Object)(object)p.currentVoiceChatAudioSource != (Object)null) ? ((Component)p.currentVoiceChatAudioSource).GetComponent<VoiceTap>() : null);
			if (!((Object)(object)voiceTap != (Object)null))
			{
				return 0f;
			}
			return voiceTap.Rms;
		}

		private static bool IsClean(AudioSource src)
		{
			AudioLowPassFilter component = ((Component)src).GetComponent<AudioLowPassFilter>();
			AudioHighPassFilter component2 = ((Component)src).GetComponent<AudioHighPassFilter>();
			bool num = (Object)(object)component == (Object)null || !((Behaviour)component).enabled || component.cutoffFrequency >= 15000f;
			bool flag = (Object)(object)component2 == (Object)null || !((Behaviour)component2).enabled;
			return num && flag;
		}

		private static void EnsureMic(StartOfRound sor)
		{
			if (mic == null && !((Object)(object)sor.voiceChatModule == (Object)null))
			{
				mic = new MicTap();
				sor.voiceChatModule.SubscribeToRecordedAudio((IMicrophoneSubscriber)(object)mic);
			}
		}

		internal static void OnSessionEnd()
		{
			if (mic != null && (Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)StartOfRound.Instance.voiceChatModule != (Object)null)
			{
				StartOfRound.Instance.voiceChatModule.UnsubscribeFromRecordedAudio((IMicrophoneSubscriber)(object)mic);
			}
			mic = null;
			segments.Clear();
		}

		private static void Save(string key, float[] samples, int rate, string nick)
		{
			float num = (float)samples.Length / (float)rate;
			seconds[key] = RecordedSeconds(key) + num;
			Task.Run(delegate
			{
				try
				{
					float[] array = Resample(samples, rate, 24000);
					Normalize(array);
					string text = Path.Combine(Root, key);
					Directory.CreateDirectory(text);
					File.WriteAllText(Path.Combine(text, "player.txt"), nick);
					WriteWav(Path.Combine(text, DateTime.Now.ToString("yyyyMMdd_HHmmss_fff") + ".wav"), array, 24000);
					TrimOldest(key, text);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Voice record: " + ex.Message));
				}
			});
			Plugin.Log.LogInfo((object)$"Voice recorded (consent given): {nick} +{num:0.0}s");
		}

		private static void TrimOldest(string key, string dir)
		{
			List<string> list = new List<string>(Directory.GetFiles(dir, "*.wav"));
			list.Sort(StringComparer.Ordinal);
			float num = 0f;
			foreach (string item in list)
			{
				num += WavSeconds(item);
			}
			while (num > Plugin.MaxVoiceSecondsPerPlayer.Value && list.Count > 1)
			{
				num -= WavSeconds(list[0]);
				File.Delete(list[0]);
				list.RemoveAt(0);
			}
			seconds[key] = num;
		}

		private static float WavSeconds(string file)
		{
			return (float)Math.Max(0L, new FileInfo(file).Length - 44) / 2f / 24000f;
		}

		internal static float RecordedSeconds(string key)
		{
			if (seconds.TryGetValue(key, out var value))
			{
				return value;
			}
			float num = 0f;
			string path = Path.Combine(Root, key);
			if (Directory.Exists(path))
			{
				string[] files = Directory.GetFiles(path, "*.wav");
				foreach (string file in files)
				{
					num += WavSeconds(file);
				}
			}
			seconds[key] = num;
			return num;
		}

		internal static void Delete(string key)
		{
			try
			{
				string path = Path.Combine(Root, key);
				if (Directory.Exists(path))
				{
					Directory.Delete(path, recursive: true);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Voice delete: " + ex.Message));
			}
			seconds[key] = 0f;
			if (segments.TryGetValue(key, out var value))
			{
				value.Samples.Clear();
			}
			Plugin.Log.LogInfo((object)("Voice recordings deleted: " + key));
		}

		private static float[] Resample(float[] src, int from, int to)
		{
			if (from == to)
			{
				return src;
			}
			int num = (int)((long)src.Length * (long)to / from);
			float[] array = new float[num];
			double num2 = (double)from / (double)to;
			for (int i = 0; i < num; i++)
			{
				double num3 = (double)i * num2;
				int num4 = (int)num3;
				int num5 = Math.Min(num4 + 1, src.Length - 1);
				float num6 = (float)(num3 - (double)num4);
				array[i] = src[num4] + (src[num5] - src[num4]) * num6;
			}
			return array;
		}

		private static void Normalize(float[] a)
		{
			float num = 0f;
			foreach (float value in a)
			{
				num = Math.Max(num, Math.Abs(value));
			}
			if (!(num < 0.0001f))
			{
				float num2 = 0.9f / num;
				for (int j = 0; j < a.Length; j++)
				{
					a[j] *= num2;
				}
			}
		}

		private static void WriteWav(string path, float[] data, int rate)
		{
			using BinaryWriter binaryWriter = new BinaryWriter(File.Create(path));
			int num = data.Length * 2;
			binaryWriter.Write(new char[4] { 'R', 'I', 'F', 'F' });
			binaryWriter.Write(36 + num);
			binaryWriter.Write(new char[4] { 'W', 'A', 'V', 'E' });
			binaryWriter.Write(new char[4] { 'f', 'm', 't', ' ' });
			binaryWriter.Write(16);
			binaryWriter.Write((short)1);
			binaryWriter.Write((short)1);
			binaryWriter.Write(rate);
			binaryWriter.Write(rate * 2);
			binaryWriter.Write((short)2);
			binaryWriter.Write((short)16);
			binaryWriter.Write(new char[4] { 'd', 'a', 't', 'a' });
			binaryWriter.Write(num);
			foreach (float num2 in data)
			{
				binaryWriter.Write((short)(Mathf.Clamp(num2, -1f, 1f) * 32767f));
			}
		}
	}
	internal class VoiceTap : MonoBehaviour
	{
		public volatile bool Capture;

		public volatile float Rms;

		public readonly ConcurrentQueue<float[]> Chunks = new ConcurrentQueue<float[]>();

		public int Rate = 48000;

		private void Awake()
		{
			Rate = AudioSettings.outputSampleRate;
		}

		private void OnAudioFilterRead(float[] data, int channels)
		{
			if (Capture && Chunks.Count <= 2000)
			{
				float[] array = new float[data.Length / channels];
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = data[i * channels];
				}
				Rms = VoiceRecorder.UpdateRms(Rms, array);
				Chunks.Enqueue(array);
			}
		}
	}
	internal class MicTap : IMicrophoneSubscriber
	{
		public volatile bool Capture;

		public volatile float Rms;

		public readonly ConcurrentQueue<float[]> Chunks = new ConcurrentQueue<float[]>();

		public volatile int Rate = 48000;

		public void ReceiveMicrophoneData(ArraySegment<float> buffer, WaveFormat format)
		{
			if (Capture && Chunks.Count <= 2000)
			{
				int num = Math.Max(1, format.Channels);
				Rate = format.SampleRate;
				float[] array = new float[buffer.Count / num];
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = buffer.Array[buffer.Offset + i * num];
				}
				Rms = VoiceRecorder.UpdateRms(Rms, array);
				Chunks.Enqueue(array);
			}
		}

		public void Reset()
		{
		}
	}
}
namespace ChaosCompany.Speech
{
	internal class MobSpeaker : MonoBehaviour
	{
		public float VoicePitch = 150f;

		public bool Sad;

		public float HeadHeight = 1.2f;

		public Transform Head;

		private AudioSource source;

		private TextMeshPro text;

		private float hideAt;

		private float speakingUntil;

		private float pendingUntil;

		private AudioClip lastClip;

		private static TMP_FontAsset cyrillicFont;

		internal bool IsBusy
		{
			get
			{
				if (!(Time.time < speakingUntil))
				{
					return Time.time < pendingUntil;
				}
				return true;
			}
		}

		internal float BusyUntil => Mathf.Max(speakingUntil, pendingUntil);

		internal void MarkPending(float timeout)
		{
			pendingUntil = Time.time + timeout;
		}

		private void Awake()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			source = ((Component)this).gameObject.AddComponent<AudioSource>();
			source.spatialBlend = 1f;
			source.rolloffMode = (AudioRolloffMode)1;
			source.minDistance = 4f;
			source.maxDistance = 35f;
			source.playOnAwake = false;
			GameObject val = new GameObject("ChaosCompany_Subtitle");
			val.transform.SetParent(((Component)this).transform, false);
			text = val.AddComponent<TextMeshPro>();
			((TMP_Text)text).font = GetFont();
			((TMP_Text)text).fontSize = 2.2f;
			((TMP_Text)text).alignment = (TextAlignmentOptions)514;
			((TMP_Text)text).enableWordWrapping = true;
			((TMP_Text)text).rectTransform.sizeDelta = new Vector2(4f, 2f);
			((Graphic)text).color = new Color(1f, 0.95f, 0.75f);
			((TMP_Text)text).outlineWidth = 0.2f;
			((TMP_Text)text).outlineColor = Color32.op_Implicit(Color.black);
			((TMP_Text)text).text = "";
		}

		private static TMP_FontAsset GetFont()
		{
			if ((Object)(object)cyrillicFont == (Object)null)
			{
				try
				{
					cyrillicFont = TMP_FontAsset.CreateFontAsset(Font.CreateDynamicFontFromOSFont(new string[3] { "Arial", "Segoe UI", "Tahoma" }, 64));
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Subtitle font: " + ex.Message));
				}
			}
			return cyrillicFont;
		}

		internal void Show(string line, byte[] voice = null)
		{
			if (!string.IsNullOrEmpty(line))
			{
				((TMP_Text)text).text = line;
				AudioClip val = ((voice != null && voice.Length > 100) ? DecodeVoice(voice) : Mumble.Make(line, VoicePitch, Sad));
				hideAt = Time.time + Mathf.Max(val.length + 1f, Mathf.Clamp((float)line.Length * 0.07f, 2.5f, 7f));
				speakingUntil = Time.time + val.length + 0.4f;
				pendingUntil = 0f;
				source.Stop();
				source.clip = val;
				source.Play();
				if ((Object)(object)lastClip != (Object)null)
				{
					Object.Destroy((Object)(object)lastClip);
				}
				lastClip = val;
			}
		}

		internal static float[] DecodeUlaw(byte[] ulaw)
		{
			float[] array = new float[ulaw.Length];
			for (int i = 0; i < ulaw.Length; i++)
			{
				float num = (float)(int)ulaw[i] / 127.5f - 1f;
				array[i] = Mathf.Sign(num) * (Mathf.Pow(256f, Mathf.Abs(num)) - 1f) / 255f;
			}
			return array;
		}

		internal static byte[] EncodeUlaw(float[] data)
		{
			byte[] array = new byte[data.Length];
			float num = Mathf.Log(256f);
			for (int i = 0; i < data.Length; i++)
			{
				float num2 = Mathf.Clamp(data[i], -1f, 1f);
				float num3 = Mathf.Sign(num2) * Mathf.Log(1f + 255f * Mathf.Abs(num2)) / num;
				array[i] = (byte)Mathf.Clamp(Mathf.RoundToInt((num3 + 1f) * 127.5f), 0, 255);
			}
			return array;
		}

		internal static AudioClip DecodeVoice(byte[] ulaw)
		{
			float[] array = new float[ulaw.Length];
			for (int i = 0; i < ulaw.Length; i++)
			{
				float num = (float)(int)ulaw[i] / 127.5f - 1f;
				array[i] = Mathf.Sign(num) * (Mathf.Pow(256f, Mathf.Abs(num)) - 1f) / 255f;
			}
			AudioClip obj = AudioClip.Create("chaos_voice", array.Length, 1, 16000, false);
			obj.SetData(array, 0);
			return obj;
		}

		private void LateUpdate()
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: 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)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)text == (Object)null)
			{
				return;
			}
			if (((TMP_Text)text).text.Length > 0 && Time.time > hideAt)
			{
				((TMP_Text)text).text = "";
			}
			if (((TMP_Text)text).text.Length != 0)
			{
				Transform val = (((Object)(object)Head != (Object)null) ? Head : ((Component)this).transform);
				text.transform.position = val.position + Vector3.up * HeadHeight;
				Camera val2 = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.activeCamera : Camera.main);
				if ((Object)(object)val2 != (Object)null)
				{
					text.transform.rotation = Quaternion.LookRotation(text.transform.position - ((Component)val2).transform.position);
				}
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)lastClip != (Object)null)
			{
				Object.Destroy((Object)(object)lastClip);
			}
		}
	}
	internal static class Mumble
	{
		private const int Rate = 44100;

		internal static AudioClip Make(string text, float basePitch, bool sad)
		{
			int num = 0;
			string text2 = text.ToLowerInvariant();
			foreach (char value in text2)
			{
				if ("аеёиоуыэюяaeiouy".IndexOf(value) >= 0)
				{
					num++;
				}
			}
			num = Mathf.Clamp(num, 2, 40);
			float num2 = 0.12f;
			float num3 = 0.03f;
			int num4 = (int)(44100f * ((float)num * (num2 + num3) + 0.1f));
			float[] array = new float[num4];
			int num5 = 0;
			float num6 = 0f;
			for (int j = 0; j < num; j++)
			{
				float num7 = (float)j / (float)num;
				float num8 = (sad ? Mathf.Lerp(1.05f, 0.8f, num7) : 1f);
				float num9 = basePitch * num8 * Random.Range(0.88f, 1.12f);
				float num10 = num2 * Random.Range(0.8f, 1.25f);
				int num11 = (int)(44100f * num10);
				float num12 = Random.Range(0.3f, 1f);
				for (int k = 0; k < num11 && num5 + k < num4; k++)
				{
					float num13 = (float)k / (float)num11;
					float num14 = num9 * (1f - 0.08f * num13);
					num6 += num14 / 44100f;
					num6 -= Mathf.Floor(num6);
					float num15 = Mathf.Sin(MathF.PI * 2f * num6) + 0.5f * num12 * Mathf.Sin(MathF.PI * 4f * num6) + 0.25f * num12 * Mathf.Sin(MathF.PI * 6f * num6) + 0.12f * (1f - num12) * Mathf.Sin(MathF.PI * 10f * num6);
					float num16 = Mathf.Min(1f, num13 * 12f) * Mathf.Min(1f, (1f - num13) * 6f);
					array[num5 + k] = num15 * num16 * 0.28f;
				}
				num5 += num11 + (int)(44100f * num3);
				if (num5 >= num4)
				{
					break;
				}
			}
			AudioClip obj = AudioClip.Create("chaos_mumble", num4, 1, 44100, false);
			obj.SetData(array, 0);
			return obj;
		}
	}
	internal class PhraseBank
	{
		private readonly Dictionary<string, List<string>> lines = new Dictionary<string, List<string>>();

		private readonly Dictionary<string, List<string>> aiLines = new Dictionary<string, List<string>>();

		private readonly Dictionary<string, List<string>> fileBag = new Dictionary<string, List<string>>();

		private readonly HashSet<string> usedAi = new HashSet<string>();

		private string mob;

		private static readonly Dictionary<string, PhraseBank> banks = new Dictionary<string, PhraseBank>();

		internal static string Folder => Path.Combine(Paths.ConfigPath, "ChaosCompany");

		internal static PhraseBank Get(string mob, string defaults)
		{
			if (!banks.TryGetValue(mob, out var value))
			{
				value = (banks[mob] = Load(mob, defaults));
				value.mob = mob;
			}
			return value;
		}

		internal static void ResetSession()
		{
			foreach (PhraseBank value in banks.Values)
			{
				value.fileBag.Clear();
			}
		}

		internal void SetAi(string category, List<string> list)
		{
			aiLines[category] = list.FindAll((string l) => !usedAi.Contains(l));
		}

		internal static PhraseBank Load(string mob, string defaults)
		{
			PhraseBank phraseBank = new PhraseBank();
			Dictionary<string, string> sections;
			foreach (KeyValuePair<string, List<string>> item in Parse(defaults, out sections))
			{
				phraseBank.lines[item.Key] = item.Value;
			}
			try
			{
				Directory.CreateDirectory(Folder);
				string path = Path.Combine(Folder, "phrases_" + mob + ".txt");
				if (!File.Exists(path))
				{
					File.WriteAllText(path, defaults, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
					return phraseBank;
				}
				Dictionary<string, string> sections2;
				Dictionary<string, List<string>> dictionary = Parse(File.ReadAllText(path, Encoding.UTF8), out sections2);
				foreach (KeyValuePair<string, List<string>> item2 in dictionary)
				{
					phraseBank.lines[item2.Key] = item2.Value;
				}
				StringBuilder stringBuilder = new StringBuilder();
				foreach (KeyValuePair<string, string> item3 in sections)
				{
					if (!dictionary.ContainsKey(item3.Key))
					{
						stringBuilder.Append("\n").Append(item3.Value);
					}
				}
				if (stringBuilder.Length > 0)
				{
					File.AppendAllText(path, stringBuilder.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Phrases for " + mob + ": can't use file, using built-in (" + ex.Message + ")"));
			}
			return phraseBank;
		}

		private static Dictionary<string, List<string>> Parse(string text, out Dictionary<string, string> sections)
		{
			Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>();
			sections = new Dictionary<string, string>();
			string key = "default";
			StringBuilder stringBuilder = new StringBuilder();
			string[] array = text.Replace("\r", "").Split('\n');
			foreach (string text2 in array)
			{
				string text3 = text2.Trim();
				if (text3.StartsWith("[") && text3.EndsWith("]"))
				{
					if (stringBuilder.Length > 0)
					{
						sections[key] = stringBuilder.ToString();
					}
					key = text3.Substring(1, text3.Length - 2).Trim().ToLowerInvariant();
					stringBuilder.Clear();
					stringBuilder.Append(text3).Append("\n");
					continue;
				}
				stringBuilder.Append(text2).Append("\n");
				if (text3.Length != 0 && !text3.StartsWith("#"))
				{
					if (!dictionary.TryGetValue(key, out var value))
					{
						value = (dictionary[key] = new List<string>());
					}
					value.Add(text3);
				}
			}
			if (stringBuilder.Length > 0)
			{
				sections[key] = stringBuilder.ToString();
			}
			return dictionary;
		}

		internal string Pick(string category, string playerName = null, bool allowRepeat = false)
		{
			string text = null;
			List<string> value2;
			if (aiLines.TryGetValue(category, out var value) && value.Count > 0)
			{
				int index = Random.Range(0, value.Count);
				text = value[index];
				value.RemoveAt(index);
				usedAi.Add(text);
				BrainClient.ReportUsed(mob, category, text);
				if (value.Count < 3)
				{
					BrainClient.RequestRefresh(mob);
				}
			}
			else if (lines.TryGetValue(category, out value2) && value2.Count > 0)
			{
				if (aiLines.ContainsKey(category))
				{
					BrainClient.RequestRefresh(mob);
				}
				if (!fileBag.TryGetValue(category, out var value3))
				{
					value3 = (fileBag[category] = new List<string>(value2));
				}
				else if (value3.Count == 0)
				{
					if (!allowRepeat)
					{
						return null;
					}
					value3.AddRange(value2);
				}
				int index2 = Random.Range(0, value3.Count);
				text = value3[index2];
				value3.RemoveAt(index2);
			}
			return text?.Replace("{name}", string.IsNullOrEmpty(playerName) ? "эй ты" : playerName);
		}
	}
	internal static class PlayerNames
	{
		private static readonly string[] Anonymous = new string[4] { "дружище", "приятель", "эй, ты", "товарищ" };

		private static Dictionary<string, string> variants;

		private static Dictionary<string, string> nicks;

		private static string FilePath => Path.Combine(Application.persistentDataPath, "ChaosCompany_names.txt");

		private static string Key(PlayerControllerB p)
		{
			if (p.playerSteamId == 0L)
			{
				return "nick:" + p.playerUsername;
			}
			return p.playerSteamId.ToString();
		}

		private static void EnsureLoaded()
		{
			if (variants != null)
			{
				return;
			}
			variants = new Dictionary<string, string>();
			nicks = new Dictionary<string, string>();
			try
			{
				if (!File.Exists(FilePath))
				{
					return;
				}
				string[] array = File.ReadAllLines(FilePath, Encoding.UTF8);
				for (int i = 0; i < array.Length; i++)
				{
					string text = array[i];
					string text2 = null;
					int num = text.IndexOf('#');
					if (num >= 0)
					{
						text2 = text.Substring(num + 1).Trim();
						text = text.Substring(0, num);
					}
					int num2 = text.IndexOf('=');
					if (num2 > 0)
					{
						string key = text.Substring(0, num2).Trim();
						variants[key] = text.Substring(num2 + 1).Trim();
						if (text2 != null)
						{
							nicks[key] = text2;
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Names file: " + ex.Message));
			}
		}

		internal static string GetVariants(PlayerControllerB p)
		{
			if ((Object)(object)p == (Object)null)
			{
				return "";
			}
			EnsureLoaded();
			if (!variants.TryGetValue(Key(p), out var value))
			{
				return "";
			}
			return value;
		}

		internal static void SetVariants(PlayerControllerB p, string csv)
		{
			if (!((Object)(object)p == (Object)null))
			{
				EnsureLoaded();
				string key = Key(p);
				variants[key] = (csv ?? "").Trim();
				nicks[key] = p.playerUsername;
				Save();
			}
		}

		private static void Save()
		{
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("# Как мобы ChaosCompany называют игроков. Варианты через запятую.");
				stringBuilder.AppendLine("# Формат: steamId = Вася, Васёк   # ник");
				foreach (KeyValuePair<string, string> variant in variants)
				{
					if (!string.IsNullOrEmpty(variant.Value))
					{
						stringBuilder.Append(variant.Key).Append(" = ").Append(variant.Value);
						if (nicks.TryGetValue(variant.Key, out var value))
						{
							stringBuilder.Append("   # ").Append(value);
						}
						stringBuilder.AppendLine();
					}
				}
				File.WriteAllText(FilePath, stringBuilder.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
				Plugin.Log.LogInfo((object)("Player names saved: " + FilePath));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Names file: " + ex.Message));
			}
		}

		internal static string Spoken(PlayerControllerB p)
		{
			List<string> list = new List<string>();
			string[] array = GetVariants(p).Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0)
				{
					list.Add(text);
				}
			}
			if (list.Count == 0)
			{
				return Anonymous[Random.Range(0, Anonymous.Length)];
			}
			return list[Random.Range(0, list.Count)];
		}

		internal static bool HasNames(PlayerControllerB p)
		{
			return GetVariants(p).Length > 0;
		}
	}
}
namespace ChaosCompany.Patches
{
	[HarmonyPatch(typeof(PlayerControllerB), "DamagePlayer")]
	internal static class HitEffectPatch
	{
		private static void Postfix(PlayerControllerB __instance, int damageNumber, CauseOfDeath causeOfDeath, bool fallDamage)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Invalid comparison between Unknown and I4
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Invalid comparison between Unknown and I4
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Invalid comparison between Unknown and I4
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Invalid comparison between Unknown and I4
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.HitEffectsEnabled.Value && !((Object)(object)__instance != (Object)(object)GameNetworkManager.Instance?.localPlayerController) && !(__instance.isPlayerDead || damageNumber <= 0 || fallDamage) && (int)causeOfDeath != 2 && (int)causeOfDeath != 9 && (int)causeOfDeath != 5 && (int)causeOfDeath != 3)
			{
				EffectId effectId = EffectInfo.Bad[Random.Range(0, EffectInfo.Bad.Length)];
				Plugin.Log.LogInfo((object)$"Hit by {causeOfDeath} ({damageNumber} dmg) -> {effectId}");
				ChaosApi.ApplyEffect(__instance, effectId, Plugin.HitEffectDuration.Value);
			}
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager), "Start")]
	internal static class ItemCreatePatch
	{
		private static void Postfix(GameNetworkManager __instance)
		{
			NetworkManager component = ((Component)__instance).GetComponent<NetworkManager>();
			ItemFactory.CreateAll(component);
			MobFactory.CreateAll(component);
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "Awake")]
	internal static class ItemRegisterPatch
	{
		private static void Postfix(StartOfRound __instance)
		{
			ItemFactory.RegisterInRound(__instance);
			MobFactory.RegisterInRound(__instance);
		}
	}
	[HarmonyPatch(typeof(ItemCharger), "ChargeItem")]
	internal static class PortalGunNoChargePatch
	{
		private static bool Prefix()
		{
			if (GameNetworkManager.Instance?.localPlayerController?.currentlyHeldObjectServer is PortalGun)
			{
				if ((Object)(object)HUDManager.Instance != (Object)null)
				{
					HUDManager.Instance.DisplayTip("Portal gun", "It can't be recharged.", true, false, "LC_Tip1");
				}
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "Start")]
	internal static class LoadedTipPatch
	{
		private static void Postfix(StartOfRound __instance)
		{
			Plugin.Log.LogInfo((object)"StartOfRound.Start - ship loaded");
			((MonoBehaviour)__instance).StartCoroutine(ShowTip());
		}

		private static IEnumerator ShowTip()
		{
			yield return (object)new WaitForSeconds(3f);
			if ((Object)(object)HUDManager.Instance != (Object)null)
			{
				HUDManager.Instance.DisplayTip("ChaosCompany", "v0.8.0 loaded - chaos is coming", false, false, "LC_Tip1");
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound))]
	internal static class SessionPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void OnStart()
		{
			EffectManager.ClearAll();
			VoiceEffects.Reset();
			BodyEffects.Reset();
			PhraseBank.ResetSession();
			VoiceConsent.Reset();
			DuckInserts.Reset();
			ChaosNet.Register();
			ChaosRunner.Ensure();
			BrainClient.OnSessionStart();
			VoiceConsent.SendMine();
		}

		[HarmonyPostfix]
		[HarmonyPatch("OnDestroy")]
		private static void OnDestroy()
		{
			ChaosNet.Unregister();
			EchoMonitor.Shutdown();
			VoiceRecorder.OnSessionEnd();
			BodyEffects.Reset();
			EffectManager.ClearAll();
			VoiceEffects.Reset();
			Plugin.Log.LogInfo((object)"Session ended - effects cleared");
		}
	}
	[HarmonyPatch(typeof(SoundManager), "SetPlayerVoiceFilters")]
	internal static class VoicePitchPatch
	{
		private static void Postfix(SoundManager __instance)
		{
			VoiceEffects.ApplyPitch(__instance);
		}
	}
}
namespace ChaosCompany.Net
{
	internal interface IMobStateSync
	{
		void ReadState(FastBufferReader reader);
	}
	internal static class ChaosEvents
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static HandleNamedMessageDelegate <>9__19_0;

			public static HandleNamedMessageDelegate <>9__19_1;

			public static HandleNamedMessageDelegate <>9__19_2;

			public static HandleNamedMessageDelegate <>9__19_3;

			public static HandleNamedMessageDelegate <>9__19_4;

			public static HandleNamedMessageDelegate <>9__19_5;

			public static HandleNamedMessageDelegate <>9__19_6;

			public static HandleNamedMessageDelegate <>9__19_7;

			public static HandleNamedMessageDelegate <>9__19_8;

			public static HandleNamedMessageDelegate <>9__19_9;

			public static HandleNamedMessageDelegate <>9__19_10;

			internal void <Register>b__19_0(ulong s, FastBufferReader r)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: 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)
				if (Net.IsServer)
				{
					byte kind = default(byte);
					((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref kind, default(ForPrimitives));
					ulong id = default(ulong);
					((FastBufferReader)(ref r)).ReadValueSafe<ulong>(ref id, default(ForPrimitives));
					ServerTeleport(kind, id);
				}
			}

			internal void <Register>b__19_1(ulong s, FastBufferReader r)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: 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_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				if (!Net.IsServer)
				{
					byte kind = default(byte);
					((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref kind, default(ForPrimitives));
					ulong id = default(ulong);
					((FastBufferReader)(ref r)).ReadValueSafe<ulong>(ref id, default(ForPrimitives));
					Vector3 val = default(Vector3);
					((FastBufferReader)(ref r)).ReadValueSafe(ref val);
					Vector3 to = default(Vector3);
					((FastBufferReader)(ref r)).ReadValueSafe(ref to);
					ApplyTeleport(kind, id, val, to);
				}
			}

			internal void <Register>b__19_2(ulong s, FastBufferReader r)
			{
				//IL_001c: 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)
				//IL_002e: 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)
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				if (Net.IsServer)
				{
					Vector3 pos = default(Vector3);
					((FastBufferReader)(ref r)).ReadValueSafe(ref pos);
					float range = default(float);
					((FastBufferReader)(ref r)).ReadValueSafe<float>(ref range, default(ForPrimitives));
					float loud = default(float);
					((FastBufferReader)(ref r)).ReadValueSafe<float>(ref loud, default(ForPrimitives));
					ServerNoise(pos, range, loud);
				}
			}

			internal void <Register>b__19_3(ulong s, FastBufferReader r)
			{
				//IL_001c: 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)
				//IL_002e: 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)
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				if (!Net.IsServer)
				{
					Vector3 pos = default(Vector3);
					((FastBufferReader)(ref r)).ReadValueSafe(ref pos);
					float range = default(float);
					((FastBufferReader)(ref r)).ReadValueSafe<float>(ref range, default(ForPrimitives));
					float loud = default(float);
					((FastBufferReader)(ref r)).ReadValueSafe<float>(ref loud, default(ForPrimitives));
					ApplyNoise(pos, range, loud);
				}
			}

			internal void <Register>b__19_4(ulong s, FastBufferReader r)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: 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)
				if (Net.IsServer)
				{
					byte item = default(byte);
					((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref item, default(ForPrimitives));
					int player = default(int);
					((FastBufferReader)(ref r)).ReadValueSafe<int>(ref player, default(ForPrimitives));
					ServerSpawn((ChaosItem)item, player);
				}
			}

			internal void <Register>b__19_5(ulong s, FastBufferReader r)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: 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_0036: Unknown result type (might be due to invalid IL or missing references)
				if (!Net.IsServer)
				{
					ulong id = default(ulong);
					((FastBufferReader)(ref r)).ReadValueSafe<ulong>(ref id, default(ForPrimitives));
					string line = default(string);
					((FastBufferReader)(ref r)).ReadValueSafe(ref line, false);
					int num = default(int);
					((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num, default(ForPrimitives));
					byte[] audio = null;
					if (num != 0 && voiceParts.TryGetValue(num, out var value))
					{
						voiceParts.Remove(num);
						audio = Join(value);
					}
					ShowSay(id, line, audio);
				}
			}

			internal void <Register>b__19_6(ulong s, FastBufferReader r)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: 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)
				if (Net.IsServer)
				{
					return;
				}
				int player = default(int);
				((FastBufferReader)(ref r)).ReadValueSafe<int>(ref player, default(ForPrimitives));
				int key = default(int);
				((FastBufferReader)(ref r)).ReadValueSafe<int>(ref key, default(ForPrimitives));
				if (voiceParts.TryGetValue(key, out var value))
				{
					voiceParts.Remove(key);
					byte[] array = Join(value);
					if (array != null)
					{
						VoiceEffects.PlayInsert(player, array);
					}
				}
			}

			internal void <Register>b__19_7(ulong s, FastBufferReader r)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: 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)
				if (Net.IsServer)
				{
					int num = default(int);
					((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num, default(ForPrimitives));
					bool allow = default(bool);
					((FastBufferReader)(ref r)).ReadValueSafe<bool>(ref allow, default(ForPrimitives));
					StartOfRound instance = StartOfRound.Instance;
					if (!((Object)(object)instance != (Object)null) || !instance.ClientPlayerList.TryGetValue(s, out var value) || value == num)
					{
						VoiceConsent.OnConsent(num, allow);
					}
				}
			}

			internal void <Register>b__19_8(ulong s, FastBufferReader r)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: 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_0039: 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)
				//IL_004c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				if (!Net.IsServer)
				{
					int key = default(int);
					((FastBufferReader)(ref r)).ReadValueSafe<int>(ref key, default(ForPrimitives));
					int num = default(int);
					((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num, default(ForPrimitives));
					int num2 = default(int);
					((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num2, default(ForPrimitives));
					byte[] array = default(byte[]);
					((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref array, default(ForPrimitives));
					if (!voiceParts.TryGetValue(key, out var value) || value.Length != num2)
					{
						value = (voiceParts[key] = new byte[num2][]);
					}
					if (num >= 0 && num < num2)
					{
						value[num] = array;
					}
					if (voiceParts.Count > 20)
					{
						voiceParts.Clear();
					}
				}
			}

			internal void <Register>b__19_9(ulong s, FastBufferReader r)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0055: Unknown result type (might be due to invalid IL or missing references)
				if (!Net.IsServer)
				{
					ulong key = default(ulong);
					((FastBufferReader)(ref r)).ReadValueSafe<ulong>(ref key, default(ForPrimitives));
					if (Net.SpawnManager != null && Net.SpawnManager.SpawnedObjects.TryGetValue(key, out var value) && ((Component)value).GetComponent<EnemyAI>() is IMobStateSync mobStateSync)
					{
						mobStateSync.ReadState(r);
					}
				}
			}

			internal void <Register>b__19_10(ulong s, FastBufferReader r)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: 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)
				if (Net.IsServer)
				{
					byte kind = default(byte);
					((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref kind, default(ForPrimitives));
					int num = default(int);
					((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num, default(ForPrimitives));
					PlayerControllerB val = FindPlayer((ulong)num);
					if ((Object)(object)val != (Object)null)
					{
						MobFactory.ServerSpawnNear((ChaosMob)kind, val);
					}
				}
			}
		}

		private const string MsgTeleportReq = "ChaosCompany.TeleportReq";

		private const string MsgTeleportDo = "ChaosCompany.TeleportDo";

		private const string MsgNoiseReq = "ChaosCompany.NoiseReq";

		private const string MsgNoiseDo = "ChaosCompany.NoiseDo";

		private const string MsgSpawnReq = "ChaosCompany.SpawnReq";

		private const string MsgSay = "ChaosCompany.Say";

		private const string MsgVoiceChunk = "ChaosCompany.VoiceChunk";

		private const string MsgConsent = "ChaosCompany.Consent";

		private const string MsgPlayerInsert = "ChaosCompany.PlayerInsert";

		private const string MsgMobSpawnReq = "ChaosCompany.MobSpawnReq";

		private const string MsgMobState = "ChaosCompany.MobState";

		internal const byte TargetEnemy = 1;

		internal const byte TargetPlayer = 2;

		private static int nextUtterance = 1;

		private static readonly Dictionary<int, byte[][]> voiceParts = new Dictionary<int, byte[][]>();

		private const int ChunkSize = 12000;

		private static NetworkManager Net => NetworkManager.Singleton;

		private static bool Online
		{
			get
			{
				if ((Object)(object)Net != (Object)null && Net.IsListening)
				{
					return Net.CustomMessagingManager != null;
				}
				return false;
			}
		}

		private static bool IsServerOrOffline
		{
			get
			{
				if (Online)
				{
					return Net.IsServer;
				}
				return true;
			}
		}

		internal static void Register(CustomMessagingManager cmm)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Expected O, but got Unknown
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Expected O, but got Unknown
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Expected O, but got Unknown
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Expected O, but got Unknown
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Expected O, but got Unknown
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Expected O, but got Unknown
			object obj = <>c.<>9__19_0;
			if (obj == null)
			{
				HandleNamedMessageDelegate val = delegate(ulong s, FastBufferReader r)
				{
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					//IL_0019: Unknown result type (might be due to invalid IL or missing references)
					//IL_0025: 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)
					if (Net.IsServer)
					{
						byte kind = default(byte);
						((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref kind, default(ForPrimitives));
						ulong id = default(ulong);
						((FastBufferReader)(ref r)).ReadValueSafe<ulong>(ref id, default(ForPrimitives));
						ServerTeleport(kind, id);
					}
				};
				<>c.<>9__19_0 = val;
				obj = (object)val;
			}
			cmm.RegisterNamedMessageHandler("ChaosCompany.TeleportReq", (HandleNamedMessageDelegate)obj);
			object obj2 = <>c.<>9__19_1;
			if (obj2 == null)
			{
				HandleNamedMessageDelegate val2 = delegate(ulong s, FastBufferReader r)
				{
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					//IL_0019: Unknown result type (might be due to invalid IL or missing references)
					//IL_0026: 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_0047: Unknown result type (might be due to invalid IL or missing references)
					//IL_0048: Unknown result type (might be due to invalid IL or missing references)
					if (!Net.IsServer)
					{
						byte kind = default(byte);
						((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref kind, default(ForPrimitives));
						ulong id = default(ulong);
						((FastBufferReader)(ref r)).ReadValueSafe<ulong>(ref id, default(ForPrimitives));
						Vector3 val12 = default(Vector3);
						((FastBufferReader)(ref r)).ReadValueSafe(ref val12);
						Vector3 to = default(Vector3);
						((FastBufferReader)(ref r)).ReadValueSafe(ref to);
						ApplyTeleport(kind, id, val12, to);
					}
				};
				<>c.<>9__19_1 = val2;
				obj2 = (object)val2;
			}
			cmm.RegisterNamedMessageHandler("ChaosCompany.TeleportDo", (HandleNamedMessageDelegate)obj2);
			object obj3 = <>c.<>9__19_2;
			if (obj3 == null)
			{
				HandleNamedMessageDelegate val3 = delegate(ulong s, FastBufferReader r)
				{
					//IL_001c: 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)
					//IL_002e: 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)
					//IL_003a: Unknown result type (might be due to invalid IL or missing references)
					if (Net.IsServer)
					{
						Vector3 pos = default(Vector3);
						((FastBufferReader)(ref r)).ReadValueSafe(ref pos);
						float range = default(float);
						((FastBufferReader)(ref r)).ReadValueSafe<float>(ref range, default(ForPrimitives));
						float loud = default(float);
						((FastBufferReader)(ref r)).ReadValueSafe<float>(ref loud, default(ForPrimitives));
						ServerNoise(pos, range, loud);
					}
				};
				<>c.<>9__19_2 = val3;
				obj3 = (object)val3;
			}
			cmm.RegisterNamedMessageHandler("ChaosCompany.NoiseReq", (HandleNamedMessageDelegate)obj3);
			object obj4 = <>c.<>9__19_3;
			if (obj4 == null)
			{
				HandleNamedMessageDelegate val4 = delegate(ulong s, FastBufferReader r)
				{
					//IL_001c: 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)
					//IL_002e: 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)
					//IL_003a: Unknown result type (might be due to invalid IL or missing references)
					if (!Net.IsServer)
					{
						Vector3 pos = default(Vector3);
						((FastBufferReader)(ref r)).ReadValueSafe(ref pos);
						float range = default(float);
						((FastBufferReader)(ref r)).ReadValueSafe<float>(ref range, default(ForPrimitives));
						float loud = default(float);
						((FastBufferReader)(ref r)).ReadValueSafe<float>(ref loud, default(ForPrimitives));
						ApplyNoise(pos, range, loud);
					}
				};
				<>c.<>9__19_3 = val4;
				obj4 = (object)val4;
			}
			cmm.RegisterNamedMessageHandler("ChaosCompany.NoiseDo", (HandleNamedMessageDelegate)obj4);
			object obj5 = <>c.<>9__19_4;
			if (obj5 == null)
			{
				HandleNamedMessageDelegate val5 = delegate(ulong s, FastBufferReader r)
				{
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					//IL_0019: Unknown result type (might be due to invalid IL or missing references)
					//IL_0025: 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)
					if (Net.IsServer)
					{
						byte item = default(byte);
						((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref item, default(ForPrimitives));
						int player = default(int);
						((FastBufferReader)(ref r)).ReadValueSafe<int>(ref player, default(ForPrimitives));
						ServerSpawn((ChaosItem)item, player);
					}
				};
				<>c.<>9__19_4 = val5;
				obj5 = (object)val5;
			}
			cmm.RegisterNamedMessageHandler("ChaosCompany.SpawnReq", (HandleNamedMessageDelegate)obj5);
			object obj6 = <>c.<>9__19_5;
			if (obj6 == null)
			{
				HandleNamedMessageDelegate val6 = delegate(ulong s, FastBufferReader r)
				{
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					//IL_0019: 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_0036: Unknown result type (might be due to invalid IL or missing references)
					if (!Net.IsServer)
					{
						ulong id = default(ulong);
						((FastBufferReader)(ref r)).ReadValueSafe<ulong>(ref id, default(ForPrimitives));
						string line = default(string);
						((FastBufferReader)(ref r)).ReadValueSafe(ref line, false);
						int num = default(int);
						((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num, default(ForPrimitives));
						byte[] audio = null;
						if (num != 0 && voiceParts.TryGetValue(num, out var value))
						{
							voiceParts.Remove(num);
							audio = Join(value);
						}
						ShowSay(id, line, audio);
					}
				};
				<>c.<>9__19_5 = val6;
				obj6 = (object)val6;
			}
			cmm.RegisterNamedMessageHandler("ChaosCompany.Say", (HandleNamedMessageDelegate)obj6);
			object obj7 = <>c.<>9__19_6;
			if (obj7 == null)
			{
				HandleNamedMessageDelegate val7 = delegate(ulong s, FastBufferReader r)
				{
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					//IL_0019: Unknown result type (might be due to invalid IL or missing references)
					//IL_0025: 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)
					if (!Net.IsServer)
					{
						int player = default(int);
						((FastBufferReader)(ref r)).ReadValueSafe<int>(ref player, default(ForPrimitives));
						int key = default(int);
						((FastBufferReader)(ref r)).ReadValueSafe<int>(ref key, default(ForPrimitives));
						if (voiceParts.TryGetValue(key, out var value))
						{
							voiceParts.Remove(key);
							byte[] array = Join(value);
							if (array != null)
							{
								VoiceEffects.PlayInsert(player, array);
							}
						}
					}
				};
				<>c.<>9__19_6 = val7;
				obj7 = (object)val7;
			}
			cmm.RegisterNamedMessageHandler("ChaosCompany.PlayerInsert", (HandleNamedMessageDelegate)obj7);
			object obj8 = <>c.<>9__19_7;
			if (obj8 == null)
			{
				HandleNamedMessageDelegate val8 = delegate(ulong s, FastBufferReader r)
				{
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					//IL_0019: Unknown result type (might be due to invalid IL or missing references)
					//IL_0026: 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)
					if (Net.IsServer)
					{
						int num = default(int);
						((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num, default(ForPrimitives));
						bool allow = default(bool);
						((FastBufferReader)(ref r)).ReadValueSafe<bool>(ref allow, default(ForPrimitives));
						StartOfRound instance = StartOfRound.Instance;
						if (!((Object)(object)instance != (Object)null) || !instance.ClientPlayerList.TryGetValue(s, out var value) || value == num)
						{
							VoiceConsent.OnConsent(num, allow);
						}
					}
				};
				<>c.<>9__19_7 = val8;
				obj8 = (object)val8;
			}
			cmm.RegisterNamedMessageHandler("ChaosCompany.Consent", (HandleNamedMessageDelegate)obj8);
			object obj9 = <>c.<>9__19_8;
			if (obj9 == null)
			{
				HandleNamedMessageDelegate val9 = delegate(ulong s, FastBufferReader r)
				{
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					//IL_0019: Unknown result type (might be due to invalid IL or missing references)
					//IL_0026: 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_0039: 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)
					//IL_004c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0052: Unknown result type (might be due to invalid IL or missing references)
					if (!Net.IsServer)
					{
						int key = default(int);
						((FastBufferReader)(ref r)).ReadValueSafe<int>(ref key, default(ForPrimitives));
						int num = default(int);
						((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num, default(ForPrimitives));
						int num2 = default(int);
						((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num2, default(ForPrimitives));
						byte[] array = default(byte[]);
						((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref array, default(ForPrimitives));
						if (!voiceParts.TryGetValue(key, out var value) || value.Length != num2)
						{
							value = (voiceParts[key] = new byte[num2][]);
						}
						if (num >= 0 && num < num2)
						{
							value[num] = array;
						}
						if (voiceParts.Count > 20)
						{
							voiceParts.Clear();
						}
					}
				};
				<>c.<>9__19_8 = val9;
				obj9 = (object)val9;
			}
			cmm.RegisterNamedMessageHandler("ChaosCompany.VoiceChunk", (HandleNamedMessageDelegate)obj9);
			object obj10 = <>c.<>9__19_9;
			if (obj10 == null)
			{
				HandleNamedMessageDelegate val10 = delegate(ulong s, FastBufferReader r)
				{
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					//IL_0019: Unknown result type (might be due to invalid IL or missing references)
					//IL_0055: Unknown result type (might be due to invalid IL or missing references)
					if (!Net.IsServer)
					{
						ulong key = default(ulong);
						((FastBufferReader)(ref r)).ReadValueSafe<ulong>(ref key, default(ForPrimitives));
						if (Net.SpawnManager != null && Net.SpawnManager.SpawnedObjects.TryGetValue(key, out var value) && ((Component)value).GetComponent<EnemyAI>() is IMobStateSync mobStateSync)
						{
							mobStateSync.ReadState(r);
						}
					}
				};
				<>c.<>9__19_9 = val10;
				obj10 = (object)val10;
			}
			cmm.RegisterNamedMessageHandler("ChaosCompany.MobState", (HandleNamedMessageDelegate)obj10);
			object obj11 = <>c.<>9__19_10;
			if (obj11 == null)
			{
				HandleNamedMessageDelegate val11 = delegate(ulong s, FastBufferReader r)
				{
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					//IL_0019: Unknown result type (might be due to invalid IL or missing references)
					//IL_0025: 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)
					if (Net.IsServer)
					{
						byte kind = default(byte);
						((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref kind, default(ForPrimitives));
						int num = default(int);
						((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num, default(ForPrimitives));
						PlayerControllerB val12 = FindPlayer((ulong)num);
						if ((Object)(object)val12 != (Object)null)
						{
							MobFactory.ServerSpawnNear((ChaosMob)kind, val12);
						}
					}
				};
				<>c.<>9__19_10 = val11;
				obj11 = (object)val11;
			}
			cmm.RegisterNamedMessageHandler("ChaosCompany.MobSpawnReq", (HandleNamedMessageDelegate)obj11);
		}

		internal static void Unregister(CustomMessagingManager cmm)
		{
			cmm.UnregisterNamedMessageHandler("ChaosCompany.TeleportReq");
			cmm.UnregisterNamedMessageHandler("ChaosCompany.TeleportDo");
			cmm.UnregisterNamedMessageHandler("ChaosCompany.NoiseReq");
			cmm.UnregisterNamedMessageHandler("ChaosCompany.NoiseDo");
			cmm.UnregisterNamedMessageHandler("ChaosCompany.SpawnReq");
			cmm.UnregisterNamedMessageHandler("ChaosCompany.Say");
			cmm.UnregisterNamedMessageHandler("ChaosCompany.VoiceChunk");
			cmm.UnregisterNamedMessageHandler("ChaosCompany.Consent");
			cmm.UnregisterNamedMessageHandler("ChaosCompany.PlayerInsert");
			cmm.UnregisterNamedMessageHandler("ChaosCompany.MobSpawnReq");
			cmm.UnregisterNamedMessageHandler("ChaosCompany.MobState");
		}

		internal static void PlaySoundLocal(ChaosSounds id, Vector3 pos)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			ChaosSoundBank.PlayAt(id, pos);
		}

		internal unsafe static void RequestTeleport(byte kind, ulong id)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (IsServerOrOffline)
			{
				ServerTeleport(kind, id);
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(16, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref kind, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref id, default(ForPrimitives));
				Net.CustomMessagingManager.SendNamedMessage("ChaosCompany.TeleportReq", 0uL, val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private unsafe static void ServerTeleport(byte kind, ulong id)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_009f: 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)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing