Decompiled source of Mimics v1.0.3

TFS_Mimics.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using Photon.Voice;
using RepoSteamNetworking.API;
using RepoSteamNetworking.Networking;
using RepoSteamNetworking.Networking.Serialization;
using TFS_Mimics.patches;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Networking;
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: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace TFS_Mimics
{
	public static class MimicsAPI
	{
		private sealed class PendingEntry
		{
			public string ModGuid;

			public string ModDisplayName;

			public AudioClip Clip;
		}

		private static readonly List<PendingEntry> _pending = new List<PendingEntry>();

		private static readonly object _lock = new object();

		public static void RegisterClip(string modGuid, string modDisplayName, AudioClip clip)
		{
			if (string.IsNullOrWhiteSpace(modGuid))
			{
				throw new ArgumentException("modGuid must not be empty.", "modGuid");
			}
			if ((Object)(object)clip == (Object)null)
			{
				throw new ArgumentNullException("clip");
			}
			string modDisplayName2 = (string.IsNullOrWhiteSpace(modDisplayName) ? modGuid : modDisplayName);
			lock (_lock)
			{
				_pending.Add(new PendingEntry
				{
					ModGuid = modGuid,
					ModDisplayName = modDisplayName2,
					Clip = clip
				});
			}
			TFS_Mimics.Instance?.ConsumeApiClips();
		}

		public static void RegisterClips(string modGuid, string modDisplayName, IEnumerable<AudioClip> clips)
		{
			if (clips == null)
			{
				throw new ArgumentNullException("clips");
			}
			foreach (AudioClip clip in clips)
			{
				if ((Object)(object)clip != (Object)null)
				{
					RegisterClip(modGuid, modDisplayName, clip);
				}
			}
		}

		internal static List<(string modGuid, string modDisplayName, AudioClip clip)> TakePending()
		{
			lock (_lock)
			{
				if (_pending.Count == 0)
				{
					return null;
				}
				List<(string, string, AudioClip)> list = new List<(string, string, AudioClip)>(_pending.Count);
				foreach (PendingEntry item in _pending)
				{
					list.Add((item.ModGuid, item.ModDisplayName, item.Clip));
				}
				_pending.Clear();
				return list;
			}
		}
	}
	[BepInPlugin("TFS_Mimics", "TFS_Mimics", "1.0.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource PluginLogger;

		private static Harmony harmony;

		public static ConfigEntry<bool> configDebugVerbose;

		public static ConfigEntry<int> configVoiceVolume;

		public static ConfigEntry<int> configPlaybackNearRadius;

		public static ConfigEntry<int> configMinDelay;

		public static ConfigEntry<int> configMaxDelay;

		public static ConfigEntry<bool> configHearYourself;

		public static ConfigEntry<bool> configFilterEnabled;

		public static ConfigEntry<bool> configPlaybackVoiceFilterEnabled;

		public static ConfigEntry<int> configSamplingRate;

		public static ConfigEntry<bool> configPersistAudioCache;

		public static ConfigEntry<int> configPersistMaxFilesPerPlayer;

		public static ConfigEntry<int> configNormalizeTarget;

		public static readonly Dictionary<string, ConfigEntry<bool>> enemyConfigEntries = new Dictionary<string, ConfigEntry<bool>>();

		private void Awake()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Expected O, but got Unknown
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Expected O, but got Unknown
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Expected O, but got Unknown
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Expected O, but got Unknown
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Expected O, but got Unknown
			PluginLogger = ((BaseUnityPlugin)this).Logger;
			PluginLogger.LogInfo((object)"Plugin TFS_Mimics loaded.");
			configVoiceVolume = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Volume", 30, new ConfigDescription("Volume of mimic voices (percent).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			configPlaybackNearRadius = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Playback Near Radius", 15, new ConfigDescription("Preferred radius around local player for selecting a mimic playback enemy.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 100), Array.Empty<object>()));
			configMinDelay = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MinDelay", 10, new ConfigDescription("Minimum delay before record/play.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 300), Array.Empty<object>()));
			configMaxDelay = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxDelay", 20, new ConfigDescription("Maximum delay before record/play.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 600), Array.Empty<object>()));
			configHearYourself = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Hear Yourself?", false, "If false, only other clients hear mimic playback.");
			configPlaybackVoiceFilterEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Playback Voice Filters Enabled", true, "If false, playback never applies pitch/alien voice filters.");
			configPersistAudioCache = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Persist Audio Cache", false, "If true, received mimic audio clips are saved to disk and loaded on world entry.");
			configPersistMaxFilesPerPlayer = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Persist Max Files Per Player", 100, new ConfigDescription("Maximum number of persisted recordings to keep per player folder.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5000), Array.Empty<object>()));
			configNormalizeTarget = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Normalize Target", 85, new ConfigDescription("Peak normalization target for voice and custom audio (0 = off, 100 = 0 dBFS).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			configDebugVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Verbose Logging", false, "Enable very detailed debug logs for the whole mimic pipeline.");
			configSamplingRate = ((BaseUnityPlugin)this).Config.Bind<int>("Experimental", "Sampling Rate", 48000, new ConfigDescription("Microphone/sample rate.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(16000, 48000), Array.Empty<object>()));
			configFilterEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Filter", "Filter Enabled?", false, "Enable per-enemy mimic filter.");
			RepoSteamNetwork.RegisterPacket<MimicsAudioPacket>();
			RepoSteamNetwork.AddCallback<MimicsAudioPacket>((Action<MimicsAudioPacket>)TFS_Mimics.OnMimicsAudioPacketReceived);
			harmony = new Harmony("TFS_Mimics");
			harmony.PatchAll();
			EnemyDirectorStartPatch.Initialize(((BaseUnityPlugin)this).Config);
			EnsureDataFolders();
		}

		private void EnsureDataFolders()
		{
			string text = Path.Combine(Paths.BepInExRootPath, "plugins", "ToxesFoxes-Mimics");
			Directory.CreateDirectory(Path.Combine(text, "audio-cache"));
			string text2 = Path.Combine(text, "custom-audio");
			Directory.CreateDirectory(text2);
			string path = Path.Combine(text2, "HOW TO USE.txt");
			if (!File.Exists(path))
			{
				File.WriteAllText(path, "=== Mimics — Custom Audio ===\r\n\r\nDrop .mp3 or .wav files into this folder.\r\nThey will be loaded automatically when you join a level.\r\n\r\nCustom clips are played through nearby enemies just like recorded\r\nplayer voices, but without any online-player restriction.\r\n\r\nTips:\r\n  - Mono or stereo files both work.\r\n  - Volume is normalized automatically (configurable in Settings tab).\r\n  - Use the 'Reload Custom' button in the Debug HUD (Cache tab) to\r\n    reload files without restarting the game.\r\n  - This file (HOW TO USE.txt) is ignored by the mod.\r\n");
			}
			PluginLogger.LogInfo((object)("[Mimics] Data folders ready: " + text));
		}
	}
	internal sealed class MimicsAudioMarker : MonoBehaviour
	{
		private static Sprite s_sprite;

		private static Font s_font;

		private static readonly Color CAccent = new Color(0.35f, 0.65f, 1f);

		private static readonly Color CBg = new Color(0.05f, 0.07f, 0.11f, 0.82f);

		private static readonly Color CGreen = new Color(0.3f, 0.85f, 0.4f);

		private static readonly Color CDim = new Color(0.5f, 0.55f, 0.6f, 0.75f);

		private static readonly Color CText = new Color(0.88f, 0.91f, 0.95f);

		private static readonly Color CYellow = new Color(1f, 0.8f, 0.2f);

		private const float PanelW = 100f;

		private const float PanelH = 38f;

		private const float WorldScale = 0.01f;

		private const float YOffset = 0.6f;

		private AudioSource _source;

		private Canvas _canvas;

		private RectTransform _canvasRect;

		private Image _bg;

		private Image _border;

		private Text _iconText;

		private Text _stateText;

		private float _pulse;

		private static Sprite GetSprite()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			if ((Object)(object)s_sprite != (Object)null)
			{
				return s_sprite;
			}
			Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false);
			val.SetPixel(0, 0, Color.white);
			val.Apply();
			s_sprite = Sprite.Create(val, new Rect(0f, 0f, 1f, 1f), Vector2.one * 0.5f);
			return s_sprite;
		}

		private static Font GetFont()
		{
			if ((Object)(object)s_font == (Object)null)
			{
				s_font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			}
			return s_font;
		}

		public void Init(AudioSource src)
		{
			_source = src;
			BuildUI();
			SetAlwaysOnTop();
		}

		public void SetVisible(bool v)
		{
			if ((Object)(object)_canvas != (Object)null)
			{
				((Component)_canvas).gameObject.SetActive(v);
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_canvas != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_canvas).gameObject);
			}
		}

		private void Update()
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: 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_0072: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: 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_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_source == (Object)null || (Object)(object)_canvas == (Object)null)
			{
				return;
			}
			bool isPlaying = _source.isPlaying;
			_pulse = (isPlaying ? (0.55f + 0.45f * Mathf.Sin(Time.time * 7f)) : 1f);
			if ((Object)(object)_border != (Object)null)
			{
				Color color = (isPlaying ? CAccent : CDim);
				color.a = (isPlaying ? _pulse : 0.4f);
				((Graphic)_border).color = color;
			}
			if ((Object)(object)_bg != (Object)null)
			{
				Color color2 = (Color)(isPlaying ? new Color(0.03f, 0.08f, 0.16f, 0.88f) : CBg);
				((Graphic)_bg).color = color2;
			}
			if ((Object)(object)_iconText != (Object)null)
			{
				_iconText.text = (isPlaying ? "♫" : "♪");
				Color color3 = (isPlaying ? CGreen : CDim);
				color3.a = _pulse;
				((Graphic)_iconText).color = color3;
			}
			if ((Object)(object)_stateText != (Object)null)
			{
				if (isPlaying)
				{
					((Graphic)_stateText).color = CText;
					float num = Mathf.Max(0f, ((Object)(object)_source.clip != (Object)null) ? (_source.clip.length - _source.time) : 0f);
					_stateText.text = ((num > 0.05f) ? $"PLAYING\n{num:F1}s left" : "PLAYING");
				}
				else
				{
					((Graphic)_stateText).color = CDim;
					_stateText.text = "AUDIO\nSOURCE";
				}
			}
		}

		private void LateUpdate()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_canvas == (Object)null))
			{
				Camera main = Camera.main;
				if (!((Object)(object)main == (Object)null))
				{
					((Transform)_canvasRect).position = ((Component)this).transform.position + Vector3.up * 0.6f;
					((Transform)_canvasRect).rotation = ((Component)main).transform.rotation;
				}
			}
		}

		private void BuildUI()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("_MimicsAudioMarkerCanvas");
			val.transform.SetParent(((Component)this).transform, false);
			_canvas = val.AddComponent<Canvas>();
			_canvas.renderMode = (RenderMode)2;
			_canvas.sortingOrder = 101;
			_canvasRect = val.GetComponent<RectTransform>();
			_canvasRect.sizeDelta = new Vector2(100f, 38f);
			((Transform)_canvasRect).localScale = Vector3.one * 0.01f;
			val.AddComponent<CanvasScaler>().dynamicPixelsPerUnit = 10f;
			_bg = MkImg(val.transform, "bg", CBg, 0f, 1f, 0f, 1f);
			_border = MkImg(val.transform, "border", CAccent, 0f, 1f, 0.9f, 1f);
			_iconText = MkText(val.transform, "icon", 18, (FontStyle)1, CGreen);
			SetAnch(((Graphic)_iconText).rectTransform, 0.02f, 0.28f, 0f, 1f);
			_iconText.alignment = (TextAnchor)4;
			_iconText.text = "♪";
			_stateText = MkText(val.transform, "state", 8, (FontStyle)1, CDim);
			SetAnch(((Graphic)_stateText).rectTransform, 0.3f, 0.98f, 0f, 1f);
			_stateText.alignment = (TextAnchor)3;
			_stateText.text = "AUDIO\nSOURCE";
			_stateText.lineSpacing = 1.1f;
		}

		private Image MkImg(Transform parent, string name, Color color, float xMin, float xMax, float yMin, float yMax)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			Image obj = val.AddComponent<Image>();
			obj.sprite = GetSprite();
			((Graphic)obj).color = color;
			SetAnch(val.GetComponent<RectTransform>(), xMin, xMax, yMin, yMax);
			return obj;
		}

		private Text MkText(Transform parent, string name, int fontSize, FontStyle style, Color color)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			Text obj = val.AddComponent<Text>();
			obj.font = GetFont();
			obj.fontSize = fontSize;
			obj.fontStyle = style;
			((Graphic)obj).color = color;
			((Graphic)obj).raycastTarget = false;
			obj.supportRichText = false;
			return obj;
		}

		private static void SetAnch(RectTransform r, float xMin, float xMax, float yMin, float yMax)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			r.anchorMin = new Vector2(xMin, yMin);
			r.anchorMax = new Vector2(xMax, yMax);
			Vector2 offsetMin = (r.offsetMax = Vector2.zero);
			r.offsetMin = offsetMin;
		}

		private void SetAlwaysOnTop()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			Graphic[] componentsInChildren = ((Component)_canvas).GetComponentsInChildren<Graphic>(true);
			foreach (Graphic obj in componentsInChildren)
			{
				Material val = new Material(obj.defaultMaterial);
				val.SetInt("unity_GUIZTestMode", 8);
				obj.material = val;
			}
		}
	}
	public class TFS_Mimics : MonoBehaviour
	{
		private sealed class FpmPlayerEntry
		{
			public string PlayerId;

			public string DisplayName;

			public bool IsLocalPlayer;

			public bool IsOnline;

			public readonly List<int> CacheIndices = new List<int>();
		}

		private sealed class FpmEnemyEntry
		{
			public GameObject Enemy;

			public GameObject Target;

			public string Name;

			public float Distance;

			public bool IsPlaying;
		}

		private sealed class VoiceLogEntry
		{
			public bool IsIncoming;

			public string TransmissionId;

			public string PlayerId;

			public string PlayerName;

			public int Bytes;

			public bool IsComplete;

			public bool IsFailed;

			public float ReceivedAt;

			public float UpdatedAt;

			public int ChunksDone;

			public int ChunksTotal;
		}

		private sealed class CachedAudioEntry
		{
			public byte[] AudioData;

			public bool ApplyVoiceFilter;

			public int SampleRate;

			public int SourceActor;

			public string SourcePlayerId;

			public string SourceName;

			public float ReceivedAt;
		}

		private sealed class HudPlaybackCandidate
		{
			public GameObject Enemy;

			public GameObject Target;

			public Vector3 Position;

			public float Distance;

			public string EnemyName;

			public bool IsPlaying;

			public float PlaybackEndsAt;
		}

		private sealed class PlayersIndexData
		{
			public List<PlayerIndexEntry> players { get; set; } = new List<PlayerIndexEntry>();

		}

		private sealed class PlayerIndexEntry
		{
			public string id { get; set; }

			public string name { get; set; }
		}

		private sealed class IncomingAudioTransmission
		{
			public int ExpectedChunkCount;

			public bool ApplyFilter;

			public int SampleRate;

			public int SenderActor;

			public string SenderPlayerId;

			public string SenderName;

			public float LastUpdatedAt;

			public readonly List<byte[]> Chunks = new List<byte[]>();
		}

		private sealed class CustomAudioEntry
		{
			public AudioClip Clip;

			public string FileName;

			public string FilePath;

			public string SourceMod;

			public bool IsNormalized;
		}

		private sealed class PlayerJsonEntry
		{
			public string id;

			public string name;

			public int volumeOverride = -1;
		}

		[CompilerGenerated]
		private sealed class <EnsureEnemyAudioSourcesLoop>d__201 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public TFS_Mimics <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <EnsureEnemyAudioSourcesLoop>d__201(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Expected O, but got Unknown
				//IL_00df: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				TFS_Mimics tFS_Mimics = <>4__this;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
					if (SemiFunc.RunIsLevel())
					{
						List<GameObject> list = (from e in tFS_Mimics.GetEnemiesList()
							where (Object)(object)e != (Object)null
							select e).ToList();
						int num2 = 0;
						foreach (GameObject item in list)
						{
							Transform enemyAudioAnchor = tFS_Mimics.GetEnemyAudioAnchor(item);
							if (!((Object)(object)enemyAudioAnchor == (Object)null))
							{
								int instanceID = ((Object)((Component)enemyAudioAnchor).gameObject).GetInstanceID();
								if (!tFS_Mimics.reusableEnemyAudioSources.TryGetValue(instanceID, out var value) || !((Object)(object)value != (Object)null) || !((Object)(object)((Component)value).gameObject != (Object)null))
								{
									tFS_Mimics.GetOrCreateReusableEnemyAudioSource(item, ((Component)enemyAudioAnchor).gameObject, enemyAudioAnchor.position);
									num2++;
								}
							}
						}
						if (num2 > 0)
						{
							tFS_Mimics.DLog($"EnsureEnemyAudioSourcesLoop: attached audio proxies to {num2} new enemies, total tracked={tFS_Mimics.reusableEnemyAudioSources.Count} {tFS_Mimics.DebugContext()}");
						}
					}
				}
				else
				{
					<>1__state = -1;
				}
				<>2__current = (object)new WaitForSeconds(10f);
				<>1__state = 1;
				return true;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <FollowAudioSourceDuringPlayback>d__243 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public float duration;

			public AudioSource source;

			public TFS_Mimics <>4__this;

			public GameObject enemy;

			public GameObject target;

			private float <endAt>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <FollowAudioSourceDuringPlayback>d__243(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_004a: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				TFS_Mimics tFS_Mimics = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<endAt>5__2 = Time.time + duration;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if ((Object)(object)source != (Object)null && (Object)(object)((Component)source).gameObject != (Object)null && Time.time <= <endAt>5__2)
				{
					((Component)source).transform.position = tFS_Mimics.GetEnemyDistancePosition(enemy, target);
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <InitializeVoiceChat>d__199 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public TFS_Mimics <>4__this;

			public PlayerAvatar avatar;

			private FieldInfo <field>5__2;

			private int <waits>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <InitializeVoiceChat>d__199(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<field>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				TFS_Mimics tFS_Mimics = <>4__this;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
				}
				else
				{
					<>1__state = -1;
					tFS_Mimics.playerVoiceChat = ((Component)tFS_Mimics).GetComponentInChildren<PlayerVoiceChat>(true);
					if ((Object)(object)tFS_Mimics.playerVoiceChat == (Object)null)
					{
						tFS_Mimics.playerVoiceChat = ((Component)tFS_Mimics).GetComponentInParent<PlayerVoiceChat>();
					}
					if (!((Object)(object)tFS_Mimics.playerVoiceChat == (Object)null))
					{
						tFS_Mimics.DLog("PlayerVoiceChat found via component search " + tFS_Mimics.DebugContext());
						goto IL_015d;
					}
					<field>5__2 = typeof(PlayerAvatar).GetField("voiceChat", BindingFlags.Instance | BindingFlags.NonPublic);
					<waits>5__3 = 0;
				}
				while ((Object)(object)tFS_Mimics.playerVoiceChat == (Object)null)
				{
					if (<field>5__2 != null)
					{
						ref PlayerVoiceChat playerVoiceChat = ref tFS_Mimics.playerVoiceChat;
						object? value = <field>5__2.GetValue(avatar);
						playerVoiceChat = (PlayerVoiceChat)((value is PlayerVoiceChat) ? value : null);
					}
					if ((Object)(object)tFS_Mimics.playerVoiceChat == (Object)null)
					{
						<waits>5__3++;
						if (<waits>5__3 % 120 == 0)
						{
							tFS_Mimics.DLog($"Waiting for PlayerVoiceChat via reflection... frames={<waits>5__3} {tFS_Mimics.DebugContext()}");
						}
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
				}
				tFS_Mimics.DLog($"PlayerVoiceChat found via reflection after waitFrames={<waits>5__3} {tFS_Mimics.DebugContext()}");
				<field>5__2 = null;
				goto IL_015d;
				IL_015d:
				if (tFS_Mimics.photonView.IsMine && SemiFunc.RunIsLevel())
				{
					tFS_Mimics.EnsurePersistenceInitialized();
					tFS_Mimics.EnsureCustomAudioLoaded();
					tFS_Mimics.StartRecording();
					((MonoBehaviour)tFS_Mimics).StartCoroutine(tFS_Mimics.PlayCachedAudioAtRandomIntervals());
					((MonoBehaviour)tFS_Mimics).StartCoroutine(tFS_Mimics.EnsureEnemyAudioSourcesLoop());
					tFS_Mimics.DLog("Local loops started: speech capture + random playback + audio source warmup " + tFS_Mimics.DebugContext());
				}
				else
				{
					tFS_Mimics.DLog($"Not starting local loops because isMine={tFS_Mimics.photonView.IsMine} runIsLevel={SemiFunc.RunIsLevel()} {tFS_Mimics.DebugContext()}");
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <LoadCustomAudioClipsCoroutine>d__209 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public TFS_Mimics <>4__this;

			private List<string> <files>5__2;

			private int <loaded>5__3;

			private List<string>.Enumerator <>7__wrap3;

			private string <filePath>5__5;

			private UnityWebRequest <req>5__6;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadCustomAudioClipsCoroutine>d__209(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if ((uint)(num - -4) <= 1u || num == 1)
				{
					try
					{
						if (num == -4 || num == 1)
						{
							try
							{
							}
							finally
							{
								<>m__Finally2();
							}
						}
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<files>5__2 = null;
				<>7__wrap3 = default(List<string>.Enumerator);
				<filePath>5__5 = null;
				<req>5__6 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c2: Invalid comparison between Unknown and I4
				//IL_015b: Unknown result type (might be due to invalid IL or missing references)
				//IL_017b: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					int num = <>1__state;
					TFS_Mimics tFS_Mimics = <>4__this;
					switch (num)
					{
					default:
						return false;
					case 0:
					{
						<>1__state = -1;
						string customAudioDirectoryPath = tFS_Mimics.GetCustomAudioDirectoryPath();
						if (!Directory.Exists(customAudioDirectoryPath))
						{
							Directory.CreateDirectory(customAudioDirectoryPath);
							Log.LogInfo((object)("[Mimics] Custom audio: created folder at " + customAudioDirectoryPath));
							return false;
						}
						<files>5__2 = new List<string>();
						string[] array = new string[2] { "*.mp3", "*.wav" };
						foreach (string searchPattern in array)
						{
							<files>5__2.AddRange(Directory.GetFiles(customAudioDirectoryPath, searchPattern, SearchOption.TopDirectoryOnly));
						}
						<files>5__2.Sort(StringComparer.OrdinalIgnoreCase);
						if (<files>5__2.Count == 0)
						{
							tFS_Mimics.DLog("CustomAudio: no mp3/wav files found in " + customAudioDirectoryPath);
							return false;
						}
						Log.LogInfo((object)$"[Mimics] Custom audio: found {<files>5__2.Count} file(s) in {customAudioDirectoryPath}");
						<loaded>5__3 = 0;
						<>7__wrap3 = <files>5__2.GetEnumerator();
						<>1__state = -3;
						break;
					}
					case 1:
						<>1__state = -4;
						if ((int)<req>5__6.result != 1)
						{
							Log.LogWarning((object)("[Mimics] Custom audio: failed to load '" + Path.GetFileName(<filePath>5__5) + "': " + <req>5__6.error));
						}
						else
						{
							AudioClip content = DownloadHandlerAudioClip.GetContent(<req>5__6);
							if (!((Object)(object)content == (Object)null))
							{
								((Object)content).name = Path.GetFileNameWithoutExtension(<filePath>5__5);
								tFS_Mimics._customAudioClips.Add(new CustomAudioEntry
								{
									Clip = content,
									FileName = Path.GetFileName(<filePath>5__5),
									FilePath = <filePath>5__5,
									SourceMod = null,
									IsNormalized = false
								});
								<loaded>5__3++;
								tFS_Mimics.DLog($"CustomAudio: loaded '{((Object)content).name}' length={content.length:F1}s freq={content.frequency}Hz channels={content.channels}");
								<>m__Finally2();
								<req>5__6 = null;
								<filePath>5__5 = null;
								break;
							}
							Log.LogWarning((object)("[Mimics] Custom audio: null clip from '" + Path.GetFileName(<filePath>5__5) + "'"));
						}
						<>m__Finally2();
						break;
					}
					if (<>7__wrap3.MoveNext())
					{
						<filePath>5__5 = <>7__wrap3.Current;
						AudioType val = (AudioType)((Path.GetExtension(<filePath>5__5).ToLowerInvariant() == ".mp3") ? 13 : 20);
						string text = "file:///" + <filePath>5__5.Replace('\\', '/');
						<req>5__6 = UnityWebRequestMultimedia.GetAudioClip(text, val);
						<>1__state = -4;
						<>2__current = <req>5__6.SendWebRequest();
						<>1__state = 1;
						return true;
					}
					<>m__Finally1();
					<>7__wrap3 = default(List<string>.Enumerator);
					Log.LogInfo((object)$"[Mimics] Custom audio: loaded {<loaded>5__3}/{<files>5__2.Count} file(s) successfully");
					tFS_Mimics.ConsumeApiClips();
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				((IDisposable)<>7__wrap3).Dispose();
			}

			private void <>m__Finally2()
			{
				<>1__state = -3;
				if (<req>5__6 != null)
				{
					((IDisposable)<req>5__6).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <PlayCachedAudioAtRandomIntervals>d__200 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public TFS_Mimics <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <PlayCachedAudioAtRandomIntervals>d__200(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: Expected O, but got Unknown
				int num = <>1__state;
				TFS_Mimics tFS_Mimics = <>4__this;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
					tFS_Mimics.TryPlayRandomCachedAudio();
				}
				else
				{
					<>1__state = -1;
				}
				int num2 = Random.Range(Plugin.configMinDelay.Value, Plugin.configMaxDelay.Value);
				tFS_Mimics.DLog($"Next random playback check in {num2:F2}s, cachedClips={cachedAudio.Count} {tFS_Mimics.DebugContext()}");
				<>2__current = (object)new WaitForSeconds((float)num2);
				<>1__state = 1;
				return true;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <ResetReusableAudioSourceAfterDelay>d__248 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public float delay;

			public AudioSource source;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ResetReusableAudioSourceAfterDelay>d__248(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(delay);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if ((Object)(object)source != (Object)null)
					{
						source.clip = null;
					}
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <SendAudioInChunks>d__276 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public TFS_Mimics <>4__this;

			public byte[] audioData;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <SendAudioInChunks>d__276(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0070: 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_0164: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				TFS_Mimics tFS_Mimics = <>4__this;
				if (num != 0)
				{
					return false;
				}
				<>1__state = -1;
				tFS_Mimics._isSendingAudio = true;
				List<byte[]> list = tFS_Mimics.ChunkAudioData(audioData, 204800);
				string text = Guid.NewGuid().ToString("N");
				Player localPlayer = PhotonNetwork.LocalPlayer;
				string playerPersistentId = GetPlayerPersistentId(localPlayer);
				string playerDisplayName = GetPlayerDisplayName(localPlayer);
				NetworkDestination val = (NetworkDestination)(Plugin.configHearYourself.Value ? 2 : 4);
				Log.LogInfo((object)$"Start sending audio [{playerDisplayName}]({playerPersistentId}) tx={text} bytes={audioData.Length} chunks={list.Count} destination={val} {tFS_Mimics.DebugContext()}");
				tFS_Mimics.DLog($"SendAudioInChunks begin: totalBytes={audioData.Length} chunks={list.Count} chunkSize={204800} {tFS_Mimics.DebugContext()}");
				for (int i = 0; i < list.Count; i++)
				{
					RepoSteamNetwork.SendPacket<MimicsAudioPacket>(new MimicsAudioPacket
					{
						ChunkData = list[i],
						ChunkIndex = i,
						TotalChunks = list.Count,
						SampleRate = tFS_Mimics.sampleRate,
						TransmissionId = text,
						SenderActorNumber = localPlayer.ActorNumber
					}, val);
					tFS_Mimics.DLog($"Steam packet sent: tx={text} chunk={i + 1}/{list.Count} bytes={list[i].Length} destination={val} {tFS_Mimics.DebugContext()}");
					tFS_Mimics.PushVoiceLog(isIncoming: false, text, playerPersistentId, playerDisplayName, audioData.Length, isComplete: false, i + 1, list.Count);
				}
				Log.LogInfo((object)$"Finished sending audio [{playerDisplayName}]({playerPersistentId}) tx={text} chunksSent={list.Count} {tFS_Mimics.DebugContext()}");
				tFS_Mimics.PushVoiceLog(isIncoming: false, text, playerPersistentId, playerDisplayName, audioData.Length, isComplete: true, list.Count, list.Count);
				tFS_Mimics._isSendingAudio = false;
				if (tFS_Mimics._sendQueue.Count > 0)
				{
					byte[] array = tFS_Mimics._sendQueue.Dequeue();
					Log.LogInfo((object)$"SendQueue: starting next transmission ({array.Length} bytes, remaining={tFS_Mimics._sendQueue.Count}) {tFS_Mimics.DebugContext()}");
					((MonoBehaviour)tFS_Mimics).StartCoroutine(tFS_Mimics.SendAudioInChunks(array));
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private bool _debugWindowOpen;

		private bool _showGizmos;

		private Rect _debugWindowRect = new Rect(20f, 20f, 520f, 500f);

		private int _debugTab;

		private Vector2 _scrollMobs;

		private Vector2 _scrollPlayers;

		private Vector2 _scrollCache;

		private Vector2 _scrollVoiceLog;

		private Vector2 _scrollVoiceLogOut;

		private Vector2 _scrollOverlays;

		private const int VoiceLogMaxEntries = 200;

		private readonly List<VoiceLogEntry> _voiceLog = new List<VoiceLogEntry>();

		private readonly HashSet<string> _cacheExpandedPlayers = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private bool _isResizing;

		private Vector2 _resizeMouseStart;

		private Rect _resizeRectStart;

		private readonly Dictionary<int, MimicsEnemyOverlay> _enemyOverlays = new Dictionary<int, MimicsEnemyOverlay>();

		private readonly Dictionary<int, MimicsAudioMarker> _audioMarkers = new Dictionary<int, MimicsAudioMarker>();

		private float _overlayNextRefresh;

		private static readonly string[] TabNames = new string[6] { "Mobs", "Players", "Cache", "Voice Log", "Overlays", "Settings" };

		private string _settingVolumeBuf;

		private string _settingRadiusBuf;

		private string _settingMinDelayBuf;

		private string _settingMaxDelayBuf;

		private string _settingMaxFilesBuf;

		private string _settingSamplingRateBuf;

		private string _settingNormalizeBuf;

		private bool _settingsDirty;

		private Vector2 _scrollSettings;

		private readonly Dictionary<string, string> _playerVolBuf = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		private bool _fpmOpen;

		private int _fpmPage;

		private int _fpmPlayerIdx;

		private int _fpmClipIdx;

		private int _fpmEnemyIdx;

		private bool _fpmHearYourself;

		private Vector2 _fpmScrollPlayer;

		private Vector2 _fpmScrollClip;

		private Vector2 _fpmScrollEnemy;

		private List<FpmPlayerEntry> _fpmPlayers;

		private List<FpmEnemyEntry> _fpmEnemies;

		private bool _guiStylesInit;

		private GUIStyle _gsWindow;

		private GUIStyle _gsH1;

		private GUIStyle _gsLabel;

		private GUIStyle _gsLabelDim;

		private GUIStyle _gsSmall;

		private GUIStyle _gsBtn;

		private GUIStyle _gsBtnPrimary;

		private GUIStyle _gsBtnDanger;

		private GUIStyle _gsBtnYellow;

		private GUIStyle _gsTabBtn;

		private GUIStyle _gsTabBtnActive;

		private GUIStyle _gsListItem;

		private GUIStyle _gsListItemSel;

		private GUIStyle _gsPanelBox;

		private GUIStyle _gsModalTitle;

		private Texture2D _txWhite;

		private Texture2D _txBgDark;

		private Texture2D _txBgPanel;

		private Texture2D _txBgHover;

		private Texture2D _txAccent;

		private Texture2D _txAccentDim;

		private Texture2D _txGreen;

		private Texture2D _txRed;

		private Texture2D _txYellow;

		private static readonly Color CAccent = new Color(0.29f, 0.67f, 1f);

		private static readonly Color CAccentDim = new Color(0.16f, 0.38f, 0.62f);

		private static readonly Color CGreen = new Color(0.27f, 0.87f, 0.42f);

		private static readonly Color CRed = new Color(1f, 0.33f, 0.33f);

		private static readonly Color CYellow = new Color(1f, 0.84f, 0.2f);

		private static readonly Color CText = new Color(0.9f, 0.92f, 0.94f);

		private static readonly Color CTextDim = new Color(0.5f, 0.54f, 0.58f);

		private static readonly Color CBgDark = new Color(0.07f, 0.09f, 0.11f, 0.97f);

		private static readonly Color CBgPanel = new Color(0.11f, 0.14f, 0.17f, 1f);

		private static readonly Color CBgHover = new Color(0.18f, 0.22f, 0.27f, 1f);

		private CursorLockMode _savedCursorLockMode;

		private bool _savedCursorVisible;

		private bool _cursorOverrideActive;

		private bool _debugWindowFocused = true;

		private GUIStyle _gsGizmoLabel;

		private const float NormalizeTarget = 0.85f;

		private static readonly ManualLogSource Log = Logger.CreateLogSource("TFS_Mimics");

		public PhotonView photonView;

		private PlayerVoiceChat playerVoiceChat;

		private int sampleRate;

		private float[] audioBuffer;

		private int bufferPosition;

		private float[] preSpeechBuffer;

		private int preSpeechWritePos;

		private int preSpeechCount;

		private int postSpeechSamplesRemaining;

		private int pendingSilenceSamples;

		private const int RecordingBufferSeconds = 30;

		private const int MaxSendBytes = 262144;

		private const int MaxSendQueueDepth = 3;

		private bool isRecording;

		private bool capturingSpeech;

		private bool fileSaved;

		private bool _isSendingAudio;

		private readonly Queue<byte[]> _sendQueue = new Queue<byte[]>();

		private float vadHoldUntil;

		private Dictionary<string, bool> filter;

		private readonly Dictionary<string, IncomingAudioTransmission> incomingAudioTransmissions = new Dictionary<string, IncomingAudioTransmission>();

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

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

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

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

		private static readonly List<CachedAudioEntry> cachedAudio = new List<CachedAudioEntry>();

		private string currentPlaybackEnemyName = "None";

		private string currentPlaybackSourcePlayerId = "None";

		private float currentPlaybackEndsAt;

		private readonly List<string> nearestPlaybackTargetsHud = new List<string>();

		private readonly List<HudPlaybackCandidate> nearestPlaybackCandidatesHud = new List<HudPlaybackCandidate>();

		private Vector3 hudLastSelectedEnemyPos;

		private bool hudHasSelectedEnemyPos;

		private GameObject hudTrackedEnemy;

		private GameObject hudTrackedTarget;

		private float hudNextRefreshAt;

		private bool wasInLevel;

		private bool persistenceInitialized;

		private static readonly HashSet<string> loadedPersistedFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, string> playerNameById = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, int> playerVolumeOverrides = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);

		private const float IncomingTransmissionTimeoutSeconds = 30f;

		private readonly List<CustomAudioEntry> _customAudioClips = new List<CustomAudioEntry>();

		private bool _customAudioLoaded;

		private static FieldInfo _steamIdField;

		private FieldInfo _recorderField;

		private PropertyInfo _recorderTransmitProp;

		private bool _recorderReflectionDone;

		private const float VadEnergyThreshold = 0.012f;

		private const float VadHoldSeconds = 0.5f;

		private const int SteamChunkSize = 204800;

		internal static TFS_Mimics Instance { get; private set; }

		private void SetCursorForGui(bool guiActive)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (guiActive && !_cursorOverrideActive)
			{
				_savedCursorLockMode = Cursor.lockState;
				_savedCursorVisible = Cursor.visible;
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
				_cursorOverrideActive = true;
			}
			else if (!guiActive && _cursorOverrideActive)
			{
				Cursor.lockState = _savedCursorLockMode;
				Cursor.visible = _savedCursorVisible;
				_cursorOverrideActive = false;
			}
		}

		private void DebugGuiUpdate()
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown((KeyCode)289))
			{
				if ((Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303)) && _debugWindowOpen)
				{
					_debugWindowFocused = !_debugWindowFocused;
				}
				else
				{
					_debugWindowOpen = !_debugWindowOpen;
					_debugWindowFocused = _debugWindowOpen;
					if (_debugWindowOpen)
					{
						hudNextRefreshAt = 0f;
					}
					else
					{
						_fpmOpen = false;
					}
				}
			}
			if (_debugWindowOpen && !_debugWindowFocused && Input.GetMouseButtonDown(0))
			{
				Vector2 val = default(Vector2);
				((Vector2)(ref val))..ctor(Input.mousePosition.x, (float)Screen.height - Input.mousePosition.y);
				if (((Rect)(ref _debugWindowRect)).Contains(val))
				{
					_debugWindowFocused = true;
				}
			}
			bool cursorForGui = _debugWindowOpen && _debugWindowFocused;
			SetCursorForGui(cursorForGui);
			if (_debugWindowOpen)
			{
				if (Time.time >= hudNextRefreshAt)
				{
					hudNextRefreshAt = Time.time + 0.25f;
					RefreshHudTargetsSnapshot();
				}
				if (_showGizmos)
				{
					RefreshEnemyOverlays();
				}
			}
		}

		private void OnGUI()
		{
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Expected O, but got Unknown
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)photonView == (Object)null || !photonView.IsMine || !SemiFunc.RunIsLevel())
			{
				return;
			}
			EnsureGuiStyles();
			if (_debugWindowOpen)
			{
				if (_showGizmos)
				{
					DrawWorldGizmos();
				}
				if (_fpmOpen)
				{
					GUI.color = new Color(0f, 0f, 0f, 0.65f);
					GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)_txWhite);
					GUI.color = Color.white;
					float num = 440f;
					float num2 = 390f;
					Rect val = default(Rect);
					((Rect)(ref val))..ctor(((float)Screen.width - num) * 0.5f, ((float)Screen.height - num2) * 0.5f, num, num2);
					GUI.Window(9901, val, new WindowFunction(DrawForcePlayModal), string.Empty, _gsWindow);
				}
				else
				{
					_debugWindowRect = GUI.Window(9900, _debugWindowRect, new WindowFunction(DrawMainWindow), string.Empty, _gsWindow);
					HandleResizeInput();
					Rect val2 = new Rect(((Rect)(ref _debugWindowRect)).x + ((Rect)(ref _debugWindowRect)).width - 18f, ((Rect)(ref _debugWindowRect)).y + ((Rect)(ref _debugWindowRect)).height - 18f, 18f, 18f);
					GUI.color = (_isResizing ? CAccent : CTextDim);
					GUI.Label(val2, "◢", _gsSmall);
					GUI.color = Color.white;
				}
			}
		}

		private void HandleResizeInput()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Invalid comparison between Unknown and I4
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Invalid comparison between Unknown and I4
			//IL_00b2: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(((Rect)(ref _debugWindowRect)).x + ((Rect)(ref _debugWindowRect)).width - 18f, ((Rect)(ref _debugWindowRect)).y + ((Rect)(ref _debugWindowRect)).height - 18f, 18f, 18f);
			Event current = Event.current;
			if (!_isResizing && (int)current.type == 0 && current.button == 0 && ((Rect)(ref val)).Contains(current.mousePosition))
			{
				_isResizing = true;
				_resizeMouseStart = current.mousePosition;
				_resizeRectStart = _debugWindowRect;
				current.Use();
			}
			if (_isResizing)
			{
				if ((int)current.type == 3)
				{
					Vector2 val2 = current.mousePosition - _resizeMouseStart;
					((Rect)(ref _debugWindowRect)).width = Mathf.Max(420f, ((Rect)(ref _resizeRectStart)).width + val2.x);
					((Rect)(ref _debugWindowRect)).height = Mathf.Max(320f, ((Rect)(ref _resizeRectStart)).height + val2.y);
					current.Use();
				}
				if ((int)current.type == 1)
				{
					_isResizing = false;
					current.Use();
				}
			}
		}

		private void DrawMainWindow(int id)
		{
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			DrawWindowTitleBar("MIMICS  DEBUG", "[F8]");
			GUILayout.Space(4f);
			DrawPlaybackHeader();
			GUILayout.Space(4f);
			DrawTabRow();
			GUILayout.Space(4f);
			float scrollH = Mathf.Max(100f, ((Rect)(ref _debugWindowRect)).height - 168f);
			switch (_debugTab)
			{
			case 0:
				DrawNearestMobsTab(scrollH);
				break;
			case 1:
				DrawPlayersTab(scrollH);
				break;
			case 2:
				DrawCacheTab(scrollH);
				break;
			case 3:
				DrawVoiceLogTab(scrollH);
				break;
			case 4:
				DrawOverlaysTab(scrollH);
				break;
			case 5:
				DrawSettingsTab(scrollH);
				break;
			}
			GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref _debugWindowRect)).width - 28f, 26f));
		}

		private void EnsureGuiStyles()
		{
			//IL_0013: 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_0037: 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_005b: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Expected O, but got Unknown
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Expected O, but got Unknown
			//IL_015f: 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_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Expected O, but got Unknown
			//IL_019b: Expected O, but got Unknown
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Expected O, but got Unknown
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Expected O, but got Unknown
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Expected O, but got Unknown
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Expected O, but got Unknown
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Expected O, but got Unknown
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0309: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0320: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Expected O, but got Unknown
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_0382: Unknown result type (might be due to invalid IL or missing references)
			//IL_0397: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Expected O, but got Unknown
			//IL_03ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f9: Expected O, but got Unknown
			//IL_0400: Unknown result type (might be due to invalid IL or missing references)
			//IL_0405: Unknown result type (might be due to invalid IL or missing references)
			//IL_040c: Unknown result type (might be due to invalid IL or missing references)
			//IL_041d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0423: Unknown result type (might be due to invalid IL or missing references)
			//IL_0432: Expected O, but got Unknown
			//IL_0448: Unknown result type (might be due to invalid IL or missing references)
			//IL_045e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0463: Unknown result type (might be due to invalid IL or missing references)
			//IL_046b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0472: Unknown result type (might be due to invalid IL or missing references)
			//IL_0477: Unknown result type (might be due to invalid IL or missing references)
			//IL_0481: Expected O, but got Unknown
			//IL_0481: Unknown result type (might be due to invalid IL or missing references)
			//IL_048d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0493: Unknown result type (might be due to invalid IL or missing references)
			//IL_049d: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04be: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e4: Expected O, but got Unknown
			//IL_04eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0508: Unknown result type (might be due to invalid IL or missing references)
			//IL_050e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0518: Unknown result type (might be due to invalid IL or missing references)
			//IL_0529: Unknown result type (might be due to invalid IL or missing references)
			//IL_052f: Unknown result type (might be due to invalid IL or missing references)
			//IL_053e: Expected O, but got Unknown
			//IL_0545: Unknown result type (might be due to invalid IL or missing references)
			//IL_054a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0552: Unknown result type (might be due to invalid IL or missing references)
			//IL_0559: Unknown result type (might be due to invalid IL or missing references)
			//IL_055f: Unknown result type (might be due to invalid IL or missing references)
			//IL_056e: Expected O, but got Unknown
			//IL_0579: Unknown result type (might be due to invalid IL or missing references)
			//IL_057e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0583: Unknown result type (might be due to invalid IL or missing references)
			//IL_058d: Expected O, but got Unknown
			//IL_058d: Unknown result type (might be due to invalid IL or missing references)
			//IL_059e: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b3: Expected O, but got Unknown
			if (!_guiStylesInit)
			{
				_guiStylesInit = true;
				_txWhite = MakeTex(1, 1, Color.white);
				_txBgDark = MakeTex(1, 1, CBgDark);
				_txBgPanel = MakeTex(1, 1, CBgPanel);
				_txBgHover = MakeTex(1, 1, CBgHover);
				_txAccent = MakeTex(1, 1, CAccent);
				_txAccentDim = MakeTex(1, 1, CAccentDim);
				_txGreen = MakeTex(1, 1, CGreen);
				_txRed = MakeTex(1, 1, CRed);
				_txYellow = MakeTex(1, 1, CYellow);
				GUIStyle val = new GUIStyle(GUI.skin.window)
				{
					padding = new RectOffset(10, 10, 10, 10)
				};
				val.normal.background = _txBgDark;
				val.normal.textColor = CText;
				val.onNormal.background = _txBgDark;
				val.onNormal.textColor = CText;
				_gsWindow = val;
				GUIStyle val2 = new GUIStyle(GUI.skin.label)
				{
					fontSize = 12,
					fontStyle = (FontStyle)1
				};
				val2.normal.textColor = CText;
				val2.padding = new RectOffset(0, 0, 2, 2);
				_gsH1 = val2;
				GUIStyle val3 = new GUIStyle(GUI.skin.label)
				{
					fontSize = 11
				};
				val3.normal.textColor = CText;
				val3.padding = new RectOffset(2, 2, 1, 1);
				_gsLabel = val3;
				GUIStyle val4 = new GUIStyle(_gsLabel);
				val4.normal.textColor = CTextDim;
				_gsLabelDim = val4;
				GUIStyle val5 = new GUIStyle(_gsLabel)
				{
					fontSize = 10
				};
				val5.normal.textColor = CTextDim;
				_gsSmall = val5;
				GUIStyle val6 = new GUIStyle(GUI.skin.button)
				{
					fontSize = 11,
					padding = new RectOffset(8, 8, 4, 4)
				};
				val6.normal.background = _txBgPanel;
				val6.normal.textColor = CText;
				val6.hover.background = _txBgHover;
				val6.hover.textColor = Color.white;
				val6.active.background = _txAccent;
				val6.active.textColor = Color.white;
				_gsBtn = val6;
				GUIStyle val7 = new GUIStyle(_gsBtn);
				val7.normal.background = _txAccentDim;
				val7.normal.textColor = Color.white;
				val7.hover.background = _txAccent;
				val7.hover.textColor = Color.white;
				_gsBtnPrimary = val7;
				GUIStyle val8 = new GUIStyle(_gsBtn);
				val8.normal.background = MakeTex(1, 1, new Color(0.4f, 0.08f, 0.08f));
				val8.normal.textColor = CRed;
				val8.hover.background = _txRed;
				val8.hover.textColor = Color.white;
				_gsBtnDanger = val8;
				GUIStyle val9 = new GUIStyle(_gsBtn);
				val9.normal.background = MakeTex(1, 1, new Color(0.3f, 0.24f, 0.04f));
				val9.normal.textColor = CYellow;
				val9.hover.background = _txYellow;
				val9.hover.textColor = new Color(0.08f, 0.06f, 0f);
				_gsBtnYellow = val9;
				GUIStyle val10 = new GUIStyle(_gsBtn);
				val10.normal.background = _txBgPanel;
				val10.normal.textColor = CTextDim;
				val10.hover.background = _txBgHover;
				val10.hover.textColor = CText;
				_gsTabBtn = val10;
				GUIStyle val11 = new GUIStyle(_gsTabBtn)
				{
					fontStyle = (FontStyle)1
				};
				val11.normal.background = _txAccentDim;
				val11.normal.textColor = Color.white;
				_gsTabBtnActive = val11;
				Texture2D background = MakeTex(1, 1, new Color(0f, 0f, 0f, 0f));
				GUIStyle val12 = new GUIStyle(GUI.skin.button)
				{
					fontSize = 11,
					alignment = (TextAnchor)3,
					padding = new RectOffset(6, 6, 4, 4)
				};
				val12.normal.background = background;
				val12.normal.textColor = CText;
				val12.hover.background = _txBgHover;
				val12.hover.textColor = Color.white;
				val12.active.background = _txAccentDim;
				val12.active.textColor = Color.white;
				_gsListItem = val12;
				GUIStyle val13 = new GUIStyle(_gsListItem)
				{
					fontStyle = (FontStyle)1
				};
				val13.normal.background = _txAccentDim;
				val13.normal.textColor = Color.white;
				val13.hover.background = _txAccent;
				val13.hover.textColor = Color.white;
				_gsListItemSel = val13;
				GUIStyle val14 = new GUIStyle(_gsH1)
				{
					fontSize = 13,
					alignment = (TextAnchor)4
				};
				val14.normal.textColor = CAccent;
				_gsModalTitle = val14;
				GUIStyle val15 = new GUIStyle(GUI.skin.box)
				{
					padding = new RectOffset(6, 6, 5, 5)
				};
				val15.normal.background = _txBgPanel;
				val15.normal.textColor = CText;
				_gsPanelBox = val15;
			}
		}

		private static Texture2D MakeTex(int w, int h, Color col)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: 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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			Color[] array = (Color[])(object)new Color[w * h];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = col;
			}
			Texture2D val = new Texture2D(w, h);
			val.SetPixels(array);
			val.Apply();
			return val;
		}

		private void OpenForcePlayModal()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			_fpmOpen = true;
			_fpmPage = 0;
			_fpmPlayerIdx = -1;
			_fpmClipIdx = -1;
			_fpmEnemyIdx = -1;
			_fpmHearYourself = false;
			_fpmScrollPlayer = Vector2.zero;
			_fpmScrollClip = Vector2.zero;
			_fpmScrollEnemy = Vector2.zero;
			BuildFpmPlayerList();
		}

		private void BuildFpmPlayerList()
		{
			string b = ((PhotonNetwork.LocalPlayer != null) ? GetPlayerPersistentId(PhotonNetwork.LocalPlayer) : string.Empty);
			HashSet<string> onlinePlayerIds = GetOnlinePlayerIds();
			Dictionary<string, FpmPlayerEntry> dictionary = new Dictionary<string, FpmPlayerEntry>(StringComparer.OrdinalIgnoreCase);
			for (int i = 0; i < cachedAudio.Count; i++)
			{
				CachedAudioEntry cachedAudioEntry = cachedAudio[i];
				if (cachedAudioEntry != null)
				{
					string text = ((!string.IsNullOrWhiteSpace(cachedAudioEntry.SourcePlayerId)) ? cachedAudioEntry.SourcePlayerId : $"actor_{cachedAudioEntry.SourceActor}");
					string displayName = ((!string.IsNullOrWhiteSpace(cachedAudioEntry.SourceName)) ? cachedAudioEntry.SourceName : text);
					if (!dictionary.TryGetValue(text, out var value))
					{
						value = (dictionary[text] = new FpmPlayerEntry
						{
							PlayerId = text,
							DisplayName = displayName,
							IsLocalPlayer = string.Equals(text, b, StringComparison.OrdinalIgnoreCase),
							IsOnline = onlinePlayerIds.Contains(text)
						});
					}
					value.CacheIndices.Add(i);
				}
			}
			_fpmPlayers = (from p in dictionary.Values
				orderby p.IsOnline descending, p.DisplayName
				select p).ToList();
		}

		private void BuildFpmEnemyList()
		{
			//IL_0011: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			_fpmEnemies = new List<FpmEnemyEntry>();
			Vector3 position = ((Component)this).transform.position;
			foreach (GameObject item in (from e in GetEnemiesList()
				where (Object)(object)e != (Object)null
				select e).ToList())
			{
				GameObject enemyAudioTarget = GetEnemyAudioTarget(item);
				Vector3 enemyDistancePosition = GetEnemyDistancePosition(item, enemyAudioTarget);
				int playbackTargetKey = GetPlaybackTargetKey(item, enemyAudioTarget);
				float value;
				bool isPlaying = playbackTargetKey != 0 && playbackBusyUntilByTargetKey.TryGetValue(playbackTargetKey, out value) && value > Time.time;
				_fpmEnemies.Add(new FpmEnemyEntry
				{
					Enemy = item,
					Target = enemyAudioTarget,
					Name = NormalizeEnemyName(((Object)item).name),
					Distance = Vector3.Distance(enemyDistancePosition, position),
					IsPlaying = isPlaying
				});
			}
			_fpmEnemies = _fpmEnemies.OrderBy((FpmEnemyEntry e) => e.Distance).ToList();
		}

		private void DrawForcePlayModal(int id)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUI.color = CAccent;
			GUILayout.Label("FORCE  PLAY", _gsH1, Array.Empty<GUILayoutOption>());
			GUI.color = Color.white;
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("×", _gsBtnDanger, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(24f),
				GUILayout.Height(20f)
			}))
			{
				_fpmOpen = false;
			}
			GUILayout.EndHorizontal();
			DrawHRule();
			GUILayout.Space(2f);
			DrawFpmPageIndicator();
			GUILayout.Space(2f);
			DrawHRule();
			GUILayout.Space(4f);
			switch (_fpmPage)
			{
			case 0:
				DrawFpmPagePlayer();
				break;
			case 1:
				DrawFpmPageClip();
				break;
			case 2:
				DrawFpmPageEnemy();
				break;
			}
		}

		private void DrawFpmPageIndicator()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			string[] array = new string[3] { "1. Player", "2. Clip", "3. Enemy" };
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			for (int i = 0; i < array.Length; i++)
			{
				if (i != 0 || _fpmPlayerIdx != -1 || _fpmPage <= 0 || i != 1)
				{
					if (i < _fpmPage)
					{
						GUI.color = CGreen;
					}
					else if (i == _fpmPage)
					{
						GUI.color = CAccent;
					}
					else
					{
						GUI.color = CTextDim;
					}
					GUILayout.Label((i < _fpmPage) ? ("✓ " + array[i]) : array[i], _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) });
					GUI.color = Color.white;
					if (i < array.Length - 1)
					{
						GUI.color = CTextDim;
						GUILayout.Label(" ›", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) });
						GUI.color = Color.white;
					}
				}
			}
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
		}

		private void DrawFpmPagePlayer()
		{
			//IL_0000: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: 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)
			GUI.color = CTextDim;
			GUILayout.Label("Select player to play from:", _gsSmall, Array.Empty<GUILayoutOption>());
			GUI.color = Color.white;
			GUILayout.Space(4f);
			_fpmScrollPlayer = GUILayout.BeginScrollView(_fpmScrollPlayer, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(210f) });
			if (GUILayout.Button("▶  Random  (any player in cache)", (_fpmPlayerIdx == -1) ? _gsListItemSel : _gsListItem, Array.Empty<GUILayoutOption>()))
			{
				_fpmPlayerIdx = -1;
			}
			GUILayout.Space(2f);
			if (_fpmPlayers == null || _fpmPlayers.Count == 0)
			{
				GUI.color = CTextDim;
				GUILayout.Label("  Cache is empty — no players available.", _gsLabel, Array.Empty<GUILayoutOption>());
				GUI.color = Color.white;
			}
			else
			{
				for (int i = 0; i < _fpmPlayers.Count; i++)
				{
					FpmPlayerEntry fpmPlayerEntry = _fpmPlayers[i];
					bool flag = _fpmPlayerIdx == i;
					string text = (fpmPlayerEntry.IsOnline ? "●" : "○");
					string text2 = (fpmPlayerEntry.IsLocalPlayer ? " (you)" : string.Empty);
					string text3 = string.Format("{0}  {1}{2}  [{3} clip{4}]", text, fpmPlayerEntry.DisplayName, text2, fpmPlayerEntry.CacheIndices.Count, (fpmPlayerEntry.CacheIndices.Count != 1) ? "s" : string.Empty);
					Color color = GUI.color;
					if (GUILayout.Button(text3, flag ? _gsListItemSel : _gsListItem, Array.Empty<GUILayoutOption>()))
					{
						_fpmPlayerIdx = i;
					}
					GUI.color = color;
					GUILayout.Space(2f);
				}
			}
			GUILayout.EndScrollView();
			if (_fpmPlayerIdx == -1 || (_fpmPlayers != null && _fpmPlayerIdx >= 0 && _fpmPlayerIdx < _fpmPlayers.Count && _fpmPlayers[_fpmPlayerIdx].IsLocalPlayer))
			{
				GUILayout.Space(4f);
				GUILayout.BeginVertical(_gsPanelBox, Array.Empty<GUILayoutOption>());
				string text4 = ((_fpmPlayerIdx == -1) ? "Hear Yourself  (allow own clips in random)" : "Hear Yourself  (this is your clip)");
				_fpmHearYourself = GUILayout.Toggle(_fpmHearYourself, "  " + text4, _gsLabel, Array.Empty<GUILayoutOption>());
				GUILayout.EndVertical();
			}
			else
			{
				_fpmHearYourself = true;
			}
			DrawHRule();
			GUILayout.Space(4f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Cancel", _gsBtn, (GUILayoutOption[])(object)new GUILayoutOption[3]
			{
				GUILayout.Height(28f),
				GUILayout.ExpandWidth(false),
				GUILayout.Width(80f)
			}))
			{
				_fpmOpen = false;
			}
			GUILayout.FlexibleSpace();
			GUI.enabled = _fpmPlayerIdx == -1 || (_fpmPlayers != null && _fpmPlayerIdx >= 0 && _fpmPlayerIdx < _fpmPlayers.Count);
			if (GUILayout.Button((_fpmPlayerIdx == -1) ? "Next: Enemy →" : "Next: Clip →", _gsBtnPrimary, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(28f),
				GUILayout.Width(130f)
			}))
			{
				if (_fpmPlayerIdx == -1)
				{
					BuildFpmEnemyList();
					_fpmPage = 2;
				}
				else
				{
					_fpmClipIdx = -1;
					_fpmPage = 1;
				}
			}
			GUI.enabled = true;
			GUILayout.EndHorizontal();
		}

		private void DrawFpmPageClip()
		{
			//IL_0044: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			FpmPlayerEntry fpmPlayerEntry = ((_fpmPlayers != null && _fpmPlayerIdx >= 0 && _fpmPlayerIdx < _fpmPlayers.Count) ? _fpmPlayers[_fpmPlayerIdx] : null);
			if (fpmPlayerEntry == null)
			{
				_fpmPage = 0;
				return;
			}
			GUI.color = CTextDim;
			GUILayout.Label("Clips from:  ", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) });
			GUI.color = Color.white;
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUI.color = CAccent;
			GUILayout.Label(fpmPlayerEntry.DisplayName, _gsLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) });
			GUI.color = CTextDim;
			GUILayout.Label($"  ({fpmPlayerEntry.CacheIndices.Count} clips)", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) });
			GUI.color = Color.white;
			GUILayout.EndHorizontal();
			GUILayout.Space(4f);
			_fpmScrollClip = GUILayout.BeginScrollView(_fpmScrollClip, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(230f) });
			for (int i = 0; i < fpmPlayerEntry.CacheIndices.Count; i++)
			{
				int num = fpmPlayerEntry.CacheIndices[i];
				if (num < 0 || num >= cachedAudio.Count)
				{
					continue;
				}
				CachedAudioEntry cachedAudioEntry = cachedAudio[num];
				if (cachedAudioEntry != null)
				{
					float num2 = ((cachedAudioEntry.SampleRate > 0 && cachedAudioEntry.AudioData != null) ? ((float)cachedAudioEntry.AudioData.Length / (float)(cachedAudioEntry.SampleRate * 2)) : 0f);
					float num3 = Time.time - cachedAudioEntry.ReceivedAt;
					string arg = ((num3 < 60f) ? $"{num3:F0}s ago" : $"{num3 / 60f:F1}m ago");
					if (GUILayout.Button($"  [{i + 1:D2}]   {num2:F2}s   received {arg}", (_fpmClipIdx == i) ? _gsListItemSel : _gsListItem, Array.Empty<GUILayoutOption>()))
					{
						_fpmClipIdx = i;
					}
					GUILayout.Space(2f);
				}
			}
			GUILayout.EndScrollView();
			DrawHRule();
			GUILayout.Space(4f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("← Back", _gsBtn, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(28f),
				GUILayout.Width(80f)
			}))
			{
				_fpmPage = 0;
			}
			GUILayout.FlexibleSpace();
			GUI.enabled = _fpmClipIdx >= 0 && _fpmClipIdx < fpmPlayerEntry.CacheIndices.Count;
			if (GUILayout.Button("Next: Enemy →", _gsBtnPrimary, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(28f),
				GUILayout.Width(130f)
			}))
			{
				BuildFpmEnemyList();
				_fpmPage = 2;
			}
			GUI.enabled = true;
			GUILayout.EndHorizontal();
		}

		private void DrawFpmPageEnemy()
		{
			//IL_0000: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			GUI.color = CTextDim;
			GUILayout.Label("Select enemy to play on:", _gsSmall, Array.Empty<GUILayoutOption>());
			GUI.color = Color.white;
			GUILayout.Space(4f);
			_fpmScrollEnemy = GUILayout.BeginScrollView(_fpmScrollEnemy, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(210f) });
			if (GUILayout.Button("★  Nearest available  (auto-select)", (_fpmEnemyIdx == -1) ? _gsListItemSel : _gsListItem, Array.Empty<GUILayoutOption>()))
			{
				_fpmEnemyIdx = -1;
			}
			GUILayout.Space(2f);
			if (_fpmEnemies == null || _fpmEnemies.Count == 0)
			{
				GUI.color = CTextDim;
				GUILayout.Label("  No enemies in scene.", _gsLabel, Array.Empty<GUILayoutOption>());
				GUI.color = Color.white;
			}
			else
			{
				for (int i = 0; i < _fpmEnemies.Count; i++)
				{
					FpmEnemyEntry fpmEnemyEntry = _fpmEnemies[i];
					bool flag = _fpmEnemyIdx == i;
					string arg = (fpmEnemyEntry.IsPlaying ? "  ▶ playing" : string.Empty);
					GUI.color = (fpmEnemyEntry.IsPlaying ? CGreen : Color.white);
					if (GUILayout.Button($"  {fpmEnemyEntry.Name}   {fpmEnemyEntry.Distance:F1}m{arg}", flag ? _gsListItemSel : _gsListItem, Array.Empty<GUILayoutOption>()))
					{
						_fpmEnemyIdx = i;
					}
					GUI.color = Color.white;
					GUILayout.Space(2f);
				}
			}
			GUILayout.EndScrollView();
			DrawHRule();
			GUILayout.Space(4f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("← Back", _gsBtn, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(28f),
				GUILayout.Width(80f)
			}))
			{
				_fpmPage = ((_fpmPlayerIdx != -1) ? 1 : 0);
			}
			GUILayout.FlexibleSpace();
			GUI.color = CYellow;
			if (GUILayout.Button("▶  Play!", _gsBtnYellow, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(28f),
				GUILayout.Width(100f)
			}))
			{
				ExecuteForcePlay();
			}
			GUI.color = Color.white;
			GUILayout.EndHorizontal();
		}

		private void ExecuteForcePlay()
		{
			_fpmOpen = false;
			CachedAudioEntry cachedAudioEntry = null;
			string localId = ((PhotonNetwork.LocalPlayer != null) ? GetPlayerPersistentId(PhotonNetwork.LocalPlayer) : string.Empty);
			if (_fpmPlayerIdx == -1)
			{
				List<CachedAudioEntry> list = cachedAudio.Where((CachedAudioEntry e) => e != null && e.AudioData != null && e.AudioData.Length != 0).ToList();
				if (!_fpmHearYourself && !string.IsNullOrEmpty(localId))
				{
					list = list.Where((CachedAudioEntry e) => !string.Equals(e.SourcePlayerId, localId, StringComparison.OrdinalIgnoreCase)).ToList();
				}
				if (list.Count == 0)
				{
					DLog($"ForcePlay: no eligible clips (hearYourself={_fpmHearYourself}) {DebugContext()}");
					return;
				}
				cachedAudioEntry = list[Random.Range(0, list.Count)];
			}
			else if (_fpmPlayers != null && _fpmPlayerIdx >= 0 && _fpmPlayerIdx < _fpmPlayers.Count)
			{
				FpmPlayerEntry fpmPlayerEntry = _fpmPlayers[_fpmPlayerIdx];
				if (_fpmClipIdx >= 0 && _fpmClipIdx < fpmPlayerEntry.CacheIndices.Count)
				{
					int num = fpmPlayerEntry.CacheIndices[_fpmClipIdx];
					if (num >= 0 && num < cachedAudio.Count)
					{
						cachedAudioEntry = cachedAudio[num];
					}
				}
			}
			if (cachedAudioEntry == null || cachedAudioEntry.AudioData == null || cachedAudioEntry.AudioData.Length == 0)
			{
				DLog("ForcePlay: entry is null or empty " + DebugContext());
				return;
			}
			GameObject val = null;
			GameObject target = null;
			if (_fpmEnemyIdx == -1)
			{
				HudPlaybackCandidate hudPlaybackCandidate = (from c in nearestPlaybackCandidatesHud
					where c != null && !c.IsPlaying
					orderby c.Distance
					select c).FirstOrDefault();
				if (hudPlaybackCandidate != null)
				{
					val = hudPlaybackCandidate.Enemy;
					target = hudPlaybackCandidate.Target;
				}
			}
			else if (_fpmEnemies != null && _fpmEnemyIdx >= 0 && _fpmEnemyIdx < _fpmEnemies.Count)
			{
				val = _fpmEnemies[_fpmEnemyIdx].Enemy;
				target = _fpmEnemies[_fpmEnemyIdx].Target;
			}
			if ((Object)(object)val == (Object)null)
			{
				DLog("ForcePlay: could not resolve enemy target " + DebugContext());
				return;
			}
			DLog($"ForcePlay: entry={cachedAudioEntry.SourceActor}:{cachedAudioEntry.SourceName} enemy={((Object)val).name} bytes={cachedAudioEntry.AudioData.Length} {DebugContext()}");
			PlayReceivedAudioOnTarget(cachedAudioEntry, val, target);
		}

		private void PlayReceivedAudioOnTarget(CachedAudioEntry entry, GameObject enemy, GameObject target)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			bool applyVoiceFilter = (Plugin.configPlaybackVoiceFilterEnabled == null || Plugin.configPlaybackVoiceFilterEnabled.Value) && Random.value > 0.9f;
			float[] array = ConvertByteArrayToFloatArray(entry.AudioData, applyVoiceFilter, entry.SampleRate);
			AudioClip val = AudioClip.Create("ForcePlayClip", array.Length, 1, entry.SampleRate, false);
			val.SetData(array, 0);
			Vector3 enemyDistancePosition = GetEnemyDistancePosition(enemy, target);
			AudioSource orCreateReusableEnemyAudioSource = GetOrCreateReusableEnemyAudioSource(enemy, target, enemyDistancePosition);
			if ((Object)(object)orCreateReusableEnemyAudioSource == (Object)null)
			{
				DLog("ForcePlay: failed to get audio source for enemy=" + ((Object)enemy).name + " " + DebugContext());
				return;
			}
			orCreateReusableEnemyAudioSource.clip = val;
			orCreateReusableEnemyAudioSource.volume = GetVolumeForPlayer(entry.SourcePlayerId);
			orCreateReusableEnemyAudioSource.mute = false;
			orCreateReusableEnemyAudioSource.pitch = 1f;
			orCreateReusableEnemyAudioSource.loop = false;
			orCreateReusableEnemyAudioSource.bypassEffects = false;
			orCreateReusableEnemyAudioSource.bypassListenerEffects = false;
			orCreateReusableEnemyAudioSource.spatialBlend = 1f;
			orCreateReusableEnemyAudioSource.dopplerLevel = 0.5f;
			orCreateReusableEnemyAudioSource.minDistance = 1f;
			orCreateReusableEnemyAudioSource.maxDistance = 20f;
			orCreateReusableEnemyAudioSource.rolloffMode = (AudioRolloffMode)1;
			orCreateReusableEnemyAudioSource.outputAudioMixerGroup = null;
			orCreateReusableEnemyAudioSource.Play();
			float value = Time.time + val.length + 0.1f;
			int playbackTargetKey = GetPlaybackTargetKey(enemy, target);
			if (playbackTargetKey != 0)
			{
				playbackBusyUntilByTargetKey[playbackTargetKey] = value;
				playbackStartedAtByTargetKey[playbackTargetKey] = Time.time;
				playbackClipLengthByTargetKey[playbackTargetKey] = val.length;
			}
			currentPlaybackEnemyName = NormalizeEnemyName(((Object)enemy).name);
			currentPlaybackSourcePlayerId = ((!string.IsNullOrWhiteSpace(entry.SourcePlayerId)) ? entry.SourcePlayerId : ((entry.SourceActor >= 0) ? $"actor_{entry.SourceActor}" : "unknown"));
			hudTrackedEnemy = enemy;
			hudTrackedTarget = target;
			hudLastSelectedEnemyPos = enemyDistancePosition;
			hudHasSelectedEnemyPos = true;
			currentPlaybackEndsAt = value;
			DLog($"ForcePlay: playing on enemy={((Object)enemy).name} source={entry.SourceActor}:{entry.SourceName} clipLen={val.length:F2}s {DebugContext()}");
			((MonoBehaviour)this).StartCoroutine(ResetReusableAudioSourceAfterDelay(orCreateReusableEnemyAudioSource, val.length + 0.1f));
		}

		private void DrawWorldGizmos()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_0078: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			if (!((Object)(object)main == (Object)null))
			{
				if (_gsGizmoLabel == null)
				{
					GUIStyle val = new GUIStyle(GUI.skin.label)
					{
						fontSize = 10,
						fontStyle = (FontStyle)1,
						alignment = (TextAnchor)1
					};
					val.normal.textColor = Color.white;
					_gsGizmoLabel = val;
				}
				Vector3 val2 = main.WorldToScreenPoint(((Component)this).transform.position);
				if (val2.z > 0f)
				{
					float num = (float)Screen.height - val2.y;
					GUI.color = CYellow;
					DrawScreenRect(val2.x - 5f, num - 5f, 10f, 10f, 1f);
					GUI.color = Color.white;
					GUI.Label(new Rect(val2.x - 30f, num + 7f, 60f, 16f), "YOU", _gsGizmoLabel);
				}
			}
		}

		private void DrawScreenRect(float x, float y, float w, float h, float thickness)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			GUI.DrawTexture(new Rect(x, y, w, thickness), (Texture)(object)_txWhite);
			GUI.DrawTexture(new Rect(x, y + h - thickness, w, thickness), (Texture)(object)_txWhite);
			GUI.DrawTexture(new Rect(x, y, thickness, h), (Texture)(object)_txWhite);
			GUI.DrawTexture(new Rect(x + w - thickness, y, thickness, h), (Texture)(object)_txWhite);
		}

		private void RefreshEnemyOverlays()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time < _overlayNextRefresh)
			{
				return;
			}
			_overlayNextRefresh = Time.time + 0.5f;
			EnemyParent[] array = Object.FindObjectsByType<EnemyParent>((FindObjectsSortMode)0);
			HashSet<int> hashSet = new HashSet<int>();
			EnemyParent[] array2 = array;
			foreach (EnemyParent val in array2)
			{
				if (!((Object)(object)val == (Object)null))
				{
					int instanceID = ((Object)val).GetInstanceID();
					hashSet.Add(instanceID);
					if (!_enemyOverlays.TryGetValue(instanceID, out var value) || (Object)(object)value == (Object)null)
					{
						value = new GameObject("_MimicsOverlayHost").AddComponent<MimicsEnemyOverlay>();
						value.Init(val, ((Component)this).transform);
						_enemyOverlays[instanceID] = value;
					}
					else
					{
						value.IsPlayingAudio = IsEnemyCurrentlyPlaying(((Component)val).gameObject);
					}
				}
			}
			List<int> list = new List<int>();
			foreach (KeyValuePair<int, MimicsEnemyOverlay> enemyOverlay in _enemyOverlays)
			{
				if (!hashSet.Contains(enemyOverlay.Key))
				{
					if ((Object)(object)enemyOverlay.Value != (Object)null)
					{
						Object.Destroy((Object)(object)((Component)enemyOverlay.Value).gameObject);
					}
					list.Add(enemyOverlay.Key);
				}
			}
			foreach (int item in list)
			{
				_enemyOverlays.Remove(item);
			}
			HashSet<int> hashSet2 = new HashSet<int>();
			foreach (KeyValuePair<int, AudioSource> reusableEnemyAudioSource in reusableEnemyAudioSources)
			{
				AudioSource value2 = reusableEnemyAudioSource.Value;
				if (!((Object)(object)value2 == (Object)null) && !((Object)(object)((Component)value2).gameObject == (Object)null))
				{
					int key = reusableEnemyAudioSource.Key;
					hashSet2.Add(key);
					if (!_audioMarkers.TryGetValue(key, out var value3) || (Object)(object)value3 == (Object)null)
					{
						value3 = ((Component)value2).gameObject.AddComponent<MimicsAudioMarker>();
						value3.Init(value2);
						_audioMarkers[key] = value3;
					}
					value3.SetVisible(OverlaySettings.ShowAudioMarker);
				}
			}
			List<int> list2 = new List<int>();
			foreach (KeyValuePair<int, MimicsAudioMarker> audioMarker in _audioMarkers)
			{
				if (!hashSet2.Contains(audioMarker.Key))
				{
					if ((Object)(object)audioMarker.Value != (Object)null)
					{
						Object.Destroy((Object)(object)audioMarker.Value);
					}
					list2.Add(audioMarker.Key);
				}
			}
			foreach (int item2 in list2)
			{
				_audioMarkers.Remove(item2);
			}
		}

		private bool IsEnemyCurrentlyPlaying(GameObject enemy)
		{
			foreach (HudPlaybackCandidate item in nearestPlaybackCandidatesHud)
			{
				if (item != null && (Object)(object)item.Enemy == (Object)(object)enemy && item.IsPlaying)
				{
					return true;
				}
			}
			return false;
		}

		internal void DestroyAllOverlays()
		{
			foreach (KeyValuePair<int, MimicsEnemyOverlay> enemyOverlay in _enemyOverlays)
			{
				if ((Object)(object)enemyOverlay.Value != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)enemyOverlay.Value).gameObject);
				}
			}
			_enemyOverlays.Clear();
			foreach (KeyValuePair<int, MimicsAudioMarker> audioMarker in _audioMarkers)
			{
				if ((Object)(object)audioMarker.Value != (Object)null)
				{
					Object.Destroy((Object)(object)audioMarker.Value);
				}
			}
			_audioMarkers.Clear();
			_overlayNextRefresh = 0f;
		}

		private void DrawOverlaysTab(float scrollH)
		{
			//IL_0002: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			_scrollOverlays = GUILayout.BeginScrollView(_scrollOverlays, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(scrollH) });
			DrawSettingsSection("Billboard Overlays");
			GUILayout.BeginHorizontal(_gsPanelBox, Array.Empty<GUILayoutOption>());
			GUI.color = CText;
			GUILayout.Label("Show Overlays", _gsLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) });
			GUI.color = Color.white;
			GUILayout.FlexibleSpace(