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 _pending = new List(); 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 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 configDebugVerbose; public static ConfigEntry configVoiceVolume; public static ConfigEntry configPlaybackNearRadius; public static ConfigEntry configMinDelay; public static ConfigEntry configMaxDelay; public static ConfigEntry configHearYourself; public static ConfigEntry configFilterEnabled; public static ConfigEntry configPlaybackVoiceFilterEnabled; public static ConfigEntry configSamplingRate; public static ConfigEntry configPersistAudioCache; public static ConfigEntry configPersistMaxFilesPerPlayer; public static ConfigEntry configNormalizeTarget; public static readonly Dictionary> enemyConfigEntries = new Dictionary>(); 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("General", "Volume", 30, new ConfigDescription("Volume of mimic voices (percent).", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); configPlaybackNearRadius = ((BaseUnityPlugin)this).Config.Bind("General", "Playback Near Radius", 15, new ConfigDescription("Preferred radius around local player for selecting a mimic playback enemy.", (AcceptableValueBase)(object)new AcceptableValueRange(5, 100), Array.Empty())); configMinDelay = ((BaseUnityPlugin)this).Config.Bind("General", "MinDelay", 10, new ConfigDescription("Minimum delay before record/play.", (AcceptableValueBase)(object)new AcceptableValueRange(5, 300), Array.Empty())); configMaxDelay = ((BaseUnityPlugin)this).Config.Bind("General", "MaxDelay", 20, new ConfigDescription("Maximum delay before record/play.", (AcceptableValueBase)(object)new AcceptableValueRange(10, 600), Array.Empty())); configHearYourself = ((BaseUnityPlugin)this).Config.Bind("General", "Hear Yourself?", false, "If false, only other clients hear mimic playback."); configPlaybackVoiceFilterEnabled = ((BaseUnityPlugin)this).Config.Bind("General", "Playback Voice Filters Enabled", true, "If false, playback never applies pitch/alien voice filters."); configPersistAudioCache = ((BaseUnityPlugin)this).Config.Bind("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("General", "Persist Max Files Per Player", 100, new ConfigDescription("Maximum number of persisted recordings to keep per player folder.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 5000), Array.Empty())); configNormalizeTarget = ((BaseUnityPlugin)this).Config.Bind("General", "Normalize Target", 85, new ConfigDescription("Peak normalization target for voice and custom audio (0 = off, 100 = 0 dBFS).", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); configDebugVerbose = ((BaseUnityPlugin)this).Config.Bind("Debug", "Verbose Logging", false, "Enable very detailed debug logs for the whole mimic pipeline."); configSamplingRate = ((BaseUnityPlugin)this).Config.Bind("Experimental", "Sampling Rate", 48000, new ConfigDescription("Microphone/sample rate.", (AcceptableValueBase)(object)new AcceptableValueRange(16000, 48000), Array.Empty())); configFilterEnabled = ((BaseUnityPlugin)this).Config.Bind("Filter", "Filter Enabled?", false, "Enable per-enemy mimic filter."); RepoSteamNetwork.RegisterPacket(); RepoSteamNetwork.AddCallback((Action)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("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.renderMode = (RenderMode)2; _canvas.sortingOrder = 101; _canvasRect = val.GetComponent(); _canvasRect.sizeDelta = new Vector2(100f, 38f); ((Transform)_canvasRect).localScale = Vector3.one * 0.01f; val.AddComponent().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(); obj.sprite = GetSprite(); ((Graphic)obj).color = color; SetAnch(val.GetComponent(), 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(); 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(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 CacheIndices = new List(); } 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 players { get; set; } = new List(); } 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 Chunks = new List(); } 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 d__201 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public TFS_Mimics <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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 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 d__243 : IEnumerator, 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 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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; 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 <= 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 d__199 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public TFS_Mimics <>4__this; public PlayerAvatar avatar; private FieldInfo 5__2; private int 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__199(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 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(true); if ((Object)(object)tFS_Mimics.playerVoiceChat == (Object)null) { tFS_Mimics.playerVoiceChat = ((Component)tFS_Mimics).GetComponentInParent(); } if (!((Object)(object)tFS_Mimics.playerVoiceChat == (Object)null)) { tFS_Mimics.DLog("PlayerVoiceChat found via component search " + tFS_Mimics.DebugContext()); goto IL_015d; } 5__2 = typeof(PlayerAvatar).GetField("voiceChat", BindingFlags.Instance | BindingFlags.NonPublic); 5__3 = 0; } while ((Object)(object)tFS_Mimics.playerVoiceChat == (Object)null) { if (5__2 != null) { ref PlayerVoiceChat playerVoiceChat = ref tFS_Mimics.playerVoiceChat; object? value = 5__2.GetValue(avatar); playerVoiceChat = (PlayerVoiceChat)((value is PlayerVoiceChat) ? value : null); } if ((Object)(object)tFS_Mimics.playerVoiceChat == (Object)null) { 5__3++; if (5__3 % 120 == 0) { tFS_Mimics.DLog($"Waiting for PlayerVoiceChat via reflection... frames={5__3} {tFS_Mimics.DebugContext()}"); } <>2__current = null; <>1__state = 1; return true; } } tFS_Mimics.DLog($"PlayerVoiceChat found via reflection after waitFrames={5__3} {tFS_Mimics.DebugContext()}"); 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 d__209 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public TFS_Mimics <>4__this; private List 5__2; private int 5__3; private List.Enumerator <>7__wrap3; private string 5__5; private UnityWebRequest 5__6; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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(); } } 5__2 = null; <>7__wrap3 = default(List.Enumerator); 5__5 = null; 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; } 5__2 = new List(); string[] array = new string[2] { "*.mp3", "*.wav" }; foreach (string searchPattern in array) { 5__2.AddRange(Directory.GetFiles(customAudioDirectoryPath, searchPattern, SearchOption.TopDirectoryOnly)); } 5__2.Sort(StringComparer.OrdinalIgnoreCase); if (5__2.Count == 0) { tFS_Mimics.DLog("CustomAudio: no mp3/wav files found in " + customAudioDirectoryPath); return false; } Log.LogInfo((object)$"[Mimics] Custom audio: found {5__2.Count} file(s) in {customAudioDirectoryPath}"); 5__3 = 0; <>7__wrap3 = 5__2.GetEnumerator(); <>1__state = -3; break; } case 1: <>1__state = -4; if ((int)5__6.result != 1) { Log.LogWarning((object)("[Mimics] Custom audio: failed to load '" + Path.GetFileName(5__5) + "': " + 5__6.error)); } else { AudioClip content = DownloadHandlerAudioClip.GetContent(5__6); if (!((Object)(object)content == (Object)null)) { ((Object)content).name = Path.GetFileNameWithoutExtension(5__5); tFS_Mimics._customAudioClips.Add(new CustomAudioEntry { Clip = content, FileName = Path.GetFileName(5__5), FilePath = 5__5, SourceMod = null, IsNormalized = false }); 5__3++; tFS_Mimics.DLog($"CustomAudio: loaded '{((Object)content).name}' length={content.length:F1}s freq={content.frequency}Hz channels={content.channels}"); <>m__Finally2(); 5__6 = null; 5__5 = null; break; } Log.LogWarning((object)("[Mimics] Custom audio: null clip from '" + Path.GetFileName(5__5) + "'")); } <>m__Finally2(); break; } if (<>7__wrap3.MoveNext()) { 5__5 = <>7__wrap3.Current; AudioType val = (AudioType)((Path.GetExtension(5__5).ToLowerInvariant() == ".mp3") ? 13 : 20); string text = "file:///" + 5__5.Replace('\\', '/'); 5__6 = UnityWebRequestMultimedia.GetAudioClip(text, val); <>1__state = -4; <>2__current = 5__6.SendWebRequest(); <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap3 = default(List.Enumerator); Log.LogInfo((object)$"[Mimics] Custom audio: loaded {5__3}/{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 (5__6 != null) { ((IDisposable)5__6).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__200 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public TFS_Mimics <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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 d__248 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public float delay; public AudioSource source; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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 d__276 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public TFS_Mimics <>4__this; public byte[] audioData; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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 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(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 _voiceLog = new List(); private readonly HashSet _cacheExpandedPlayers = new HashSet(StringComparer.OrdinalIgnoreCase); private bool _isResizing; private Vector2 _resizeMouseStart; private Rect _resizeRectStart; private readonly Dictionary _enemyOverlays = new Dictionary(); private readonly Dictionary _audioMarkers = new Dictionary(); 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 _playerVolBuf = new Dictionary(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 _fpmPlayers; private List _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 _sendQueue = new Queue(); private float vadHoldUntil; private Dictionary filter; private readonly Dictionary incomingAudioTransmissions = new Dictionary(); private readonly Dictionary reusableEnemyAudioSources = new Dictionary(); private readonly Dictionary playbackBusyUntilByTargetKey = new Dictionary(); private readonly Dictionary playbackStartedAtByTargetKey = new Dictionary(); private readonly Dictionary playbackClipLengthByTargetKey = new Dictionary(); private static readonly List cachedAudio = new List(); private string currentPlaybackEnemyName = "None"; private string currentPlaybackSourcePlayerId = "None"; private float currentPlaybackEndsAt; private readonly List nearestPlaybackTargetsHud = new List(); private readonly List nearestPlaybackCandidatesHud = new List(); 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 loadedPersistedFiles = new HashSet(StringComparer.OrdinalIgnoreCase); private readonly Dictionary playerNameById = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly Dictionary playerVolumeOverrides = new Dictionary(StringComparer.OrdinalIgnoreCase); private const float IncomingTransmissionTimeoutSeconds = 30f; private readonly List _customAudioClips = new List(); 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 onlinePlayerIds = GetOnlinePlayerIds(); Dictionary dictionary = new Dictionary(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(); 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()); GUI.color = CAccent; GUILayout.Label("FORCE PLAY", _gsH1, Array.Empty()); 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()); 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()); 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())) { _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()); 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())) { _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()); 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()); GUILayout.EndVertical(); } else { _fpmHearYourself = true; } DrawHRule(); GUILayout.Space(4f); GUILayout.BeginHorizontal(Array.Empty()); 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()); 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())) { _fpmClipIdx = i; } GUILayout.Space(2f); } } GUILayout.EndScrollView(); DrawHRule(); GUILayout.Space(4f); GUILayout.BeginHorizontal(Array.Empty()); 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()); 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())) { _fpmEnemyIdx = -1; } GUILayout.Space(2f); if (_fpmEnemies == null || _fpmEnemies.Count == 0) { GUI.color = CTextDim; GUILayout.Label(" No enemies in scene.", _gsLabel, Array.Empty()); 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())) { _fpmEnemyIdx = i; } GUI.color = Color.white; GUILayout.Space(2f); } } GUILayout.EndScrollView(); DrawHRule(); GUILayout.Space(4f); GUILayout.BeginHorizontal(Array.Empty()); 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 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((FindObjectsSortMode)0); HashSet hashSet = new HashSet(); 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(); value.Init(val, ((Component)this).transform); _enemyOverlays[instanceID] = value; } else { value.IsPlayingAudio = IsEnemyCurrentlyPlaying(((Component)val).gameObject); } } } List list = new List(); foreach (KeyValuePair 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 hashSet2 = new HashSet(); foreach (KeyValuePair 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(); value3.Init(value2); _audioMarkers[key] = value3; } value3.SetVisible(OverlaySettings.ShowAudioMarker); } } List list2 = new List(); foreach (KeyValuePair 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 enemyOverlay in _enemyOverlays) { if ((Object)(object)enemyOverlay.Value != (Object)null) { Object.Destroy((Object)(object)((Component)enemyOverlay.Value).gameObject); } } _enemyOverlays.Clear(); foreach (KeyValuePair 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()); GUI.color = CText; GUILayout.Label("Show Overlays", _gsLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) }); GUI.color = Color.white; GUILayout.FlexibleSpace(); bool showGizmos = _showGizmos; bool flag = GUILayout.Toggle(showGizmos, showGizmos ? " ON" : " OFF", _gsLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); if (flag != showGizmos) { _showGizmos = flag; if (!_showGizmos) { DestroyAllOverlays(); } } GUILayout.EndHorizontal(); GUILayout.Space(2f); GUI.color = CTextDim; GUILayout.Label(" Floating billboards above each mob — name, HP, state, distance, playback status.", _gsSmall, Array.Empty()); GUI.color = Color.white; GUILayout.Space(6f); DrawSettingsSection("Visible Sections"); DrawOverlayToggle("Mob Name", ref OverlaySettings.ShowName); DrawOverlayToggle("HP Bar", ref OverlaySettings.ShowHp); DrawOverlayToggle("AI State", ref OverlaySettings.ShowState); DrawOverlayToggle("Distance", ref OverlaySettings.ShowDistance); DrawOverlayToggle("Playing Indicator", ref OverlaySettings.ShowPlaying); GUILayout.Space(6f); DrawSettingsSection("Audio Source Marker"); DrawOverlayToggle("Show Audio Marker", ref OverlaySettings.ShowAudioMarker); GUI.color = CTextDim; GUILayout.Label(" ♫ billboard at the exact AudioSource position on each mob.", _gsSmall, Array.Empty()); GUI.color = Color.white; GUILayout.Space(8f); GUILayout.EndScrollView(); } private void DrawOverlayToggle(string label, ref bool value) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginHorizontal(_gsPanelBox, Array.Empty()); GUI.color = CText; GUILayout.Label(label, _gsLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) }); GUI.color = Color.white; GUILayout.FlexibleSpace(); value = GUILayout.Toggle(value, value ? " ON" : " OFF", _gsLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUILayout.EndHorizontal(); GUILayout.Space(2f); } private void DrawSettingsTab(float scrollH) { //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) if (_settingVolumeBuf == null) { _settingVolumeBuf = (Plugin.configVoiceVolume?.Value ?? 20).ToString(); } if (_settingRadiusBuf == null) { _settingRadiusBuf = (Plugin.configPlaybackNearRadius?.Value ?? 12).ToString(); } if (_settingMinDelayBuf == null) { _settingMinDelayBuf = (Plugin.configMinDelay?.Value ?? 5).ToString(); } if (_settingMaxDelayBuf == null) { _settingMaxDelayBuf = (Plugin.configMaxDelay?.Value ?? 15).ToString(); } if (_settingMaxFilesBuf == null) { _settingMaxFilesBuf = (Plugin.configPersistMaxFilesPerPlayer?.Value ?? 100).ToString(); } if (_settingSamplingRateBuf == null) { _settingSamplingRateBuf = (Plugin.configSamplingRate?.Value ?? 48000).ToString(); } if (_settingNormalizeBuf == null) { _settingNormalizeBuf = (Plugin.configNormalizeTarget?.Value ?? 85).ToString(); } _scrollSettings = GUILayout.BeginScrollView(_scrollSettings, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(scrollH) }); DrawSettingsSection("General"); DrawSettingSliderInt("Voice Volume", ref _settingVolumeBuf, Plugin.configVoiceVolume, 0, 100, "%"); DrawSettingSliderInt("Playback Radius", ref _settingRadiusBuf, Plugin.configPlaybackNearRadius, 5, 100, "m"); DrawSettingSliderInt("Min Delay", ref _settingMinDelayBuf, Plugin.configMinDelay, 5, 300, "s"); DrawSettingSliderInt("Max Delay", ref _settingMaxDelayBuf, Plugin.configMaxDelay, 10, 600, "s"); DrawSettingToggle("Hear Yourself", Plugin.configHearYourself); DrawSettingToggle("Playback Voice Filter", Plugin.configPlaybackVoiceFilterEnabled); DrawSettingSliderInt("Normalize Target", ref _settingNormalizeBuf, Plugin.configNormalizeTarget, 0, 100, "% (0=off)"); GUILayout.Space(4f); DrawSettingsSection("Persistence"); DrawSettingToggle("Persist Audio Cache", Plugin.configPersistAudioCache); DrawSettingSliderInt("Max Files Per Player", ref _settingMaxFilesBuf, Plugin.configPersistMaxFilesPerPlayer, 1, 5000, ""); GUILayout.Space(4f); DrawSettingsSection("Experimental"); DrawSettingSliderInt("Sampling Rate", ref _settingSamplingRateBuf, Plugin.configSamplingRate, 16000, 48000, "Hz"); GUILayout.Space(4f); DrawSettingsSection("Debug"); DrawSettingToggle("Verbose Logging", Plugin.configDebugVerbose); GUILayout.Space(8f); if (_settingsDirty) { GUI.color = CYellow; GUILayout.Label("⚠ Some integer/slider values were not applied. Press Enter or click Apply next to them.", _gsSmall, Array.Empty()); GUI.color = Color.white; GUILayout.Space(4f); } GUILayout.EndScrollView(); } private void DrawSettingsSection(string label) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) GUILayout.Space(4f); GUILayout.BeginHorizontal(Array.Empty()); GUI.color = CAccent; GUILayout.Label(label, _gsLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUI.color = Color.white; GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); DrawHRule(); } private void DrawSettingToggle(string label, ConfigEntry entry) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) if (entry != null) { GUILayout.BeginHorizontal(_gsPanelBox, Array.Empty()); GUI.color = CText; GUILayout.Label(label, _gsLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) }); GUI.color = Color.white; GUILayout.FlexibleSpace(); bool value = entry.Value; bool flag = GUILayout.Toggle(value, value ? " ON" : " OFF", _gsLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); if (flag != value) { entry.Value = flag; } GUILayout.EndHorizontal(); GUILayout.Space(2f); } } private void DrawSettingSliderInt(string label, ref string textBuf, ConfigEntry entry, int min, int max, string unit) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) if (entry != null) { int value = entry.Value; GUILayout.BeginVertical(_gsPanelBox, Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); GUI.color = CText; GUILayout.Label(label, _gsLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) }); GUI.color = Color.white; GUILayout.FlexibleSpace(); GUI.SetNextControlName("sf_" + label); textBuf = GUILayout.TextField(textBuf, 6, _gsLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }); if (!string.IsNullOrEmpty(unit)) { GUI.color = CTextDim; GUILayout.Label(unit, _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUI.color = Color.white; } GUILayout.Space(4f); if (GUILayout.Button("Apply", _gsBtn, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(46f), GUILayout.Height(18f) })) { TryApplyIntField(textBuf, entry, min, max); _settingsDirty = false; } GUILayout.EndHorizontal(); GUILayout.Space(2f); int num = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)value, (float)min, (float)max, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(12f) })); if (num != value) { entry.Value = Mathf.Clamp(num, min, max); textBuf = entry.Value.ToString(); } GUILayout.BeginHorizontal(Array.Empty()); GUI.color = CTextDim; GUILayout.Label(min.ToString(), _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUILayout.FlexibleSpace(); GUI.color = CText; GUILayout.Label(string.Format("Current: {0}{1}", value, string.IsNullOrEmpty(unit) ? "" : (" " + unit)), _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUILayout.FlexibleSpace(); GUI.color = CTextDim; GUILayout.Label(max.ToString(), _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUI.color = Color.white; GUILayout.EndHorizontal(); GUILayout.Space(2f); GUILayout.EndVertical(); GUILayout.Space(3f); } } private static void TryApplyIntField(string text, ConfigEntry entry, int min, int max) { if (int.TryParse(text, out var result)) { entry.Value = Mathf.Clamp(result, min, max); } } private void DrawWindowTitleBar(string title, string hint) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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) GUILayout.BeginHorizontal(Array.Empty()); GUI.color = CAccent; GUILayout.Label(title, _gsH1, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUI.color = Color.white; GUILayout.FlexibleSpace(); GUILayout.Space(6f); GUI.color = CTextDim; GUILayout.Label(hint, _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUI.color = Color.white; GUILayout.Space(4f); if (GUILayout.Button("×", _gsBtnDanger, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(24f), GUILayout.Height(20f) })) { _debugWindowOpen = false; } GUILayout.EndHorizontal(); DrawHRule(); } private void DrawHRule() { //IL_0030: 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_0059: Unknown result type (might be due to invalid IL or missing references) GUILayout.Space(2f); Rect rect = GUILayoutUtility.GetRect(GUIContent.none, GUIStyle.none, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(1f) }); GUI.color = new Color(0.22f, 0.28f, 0.36f); GUI.DrawTexture(rect, (Texture)(object)_txWhite); GUI.color = Color.white; GUILayout.Space(2f); } private void DrawProgressBar(float t, string label, Color barColor) { //IL_0026: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: 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_0084: Unknown result type (might be due to invalid IL or missing references) Rect rect = GUILayoutUtility.GetRect(GUIContent.none, GUIStyle.none, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(13f) }); GUI.color = new Color(0.15f, 0.19f, 0.24f); GUI.DrawTexture(rect, (Texture)(object)_txWhite); float num = ((Rect)(ref rect)).width * Mathf.Clamp01(t); if (num > 0f) { GUI.color = barColor; GUI.DrawTexture(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, num, ((Rect)(ref rect)).height), (Texture)(object)_txWhite); } GUI.color = Color.white; GUI.Label(new Rect(((Rect)(ref rect)).x + 4f, ((Rect)(ref rect)).y - 1f, ((Rect)(ref rect)).width - 8f, ((Rect)(ref rect)).height + 2f), label, _gsSmall); } private static string FitHudText(string value, int maxChars) { if (string.IsNullOrEmpty(value)) { return "—"; } if (value.Length > maxChars) { return value.Substring(0, maxChars - 2) + "…"; } return value; } private void DrawPlaybackHeader() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: 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_0108: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) bool flag = Time.time <= currentPlaybackEndsAt; GUILayout.BeginVertical(_gsPanelBox, Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); GUI.color = (flag ? CGreen : CTextDim); GUILayout.Label(flag ? "▶ NOW PLAYING" : "■ IDLE", _gsH1, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUI.color = Color.white; GUILayout.FlexibleSpace(); if (capturingSpeech) { float num = ((sampleRate > 0) ? ((float)bufferPosition / (float)sampleRate) : 0f); string value = ((PhotonNetwork.LocalPlayer != null && !string.IsNullOrWhiteSpace(PhotonNetwork.LocalPlayer.NickName)) ? PhotonNetwork.LocalPlayer.NickName : "You"); GUI.color = CRed; GUILayout.Label($"● REC {FitHudText(value, 16)} {num:F1}s", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUI.color = Color.white; } GUILayout.EndHorizontal(); if (flag) { GUILayout.BeginHorizontal(Array.Empty()); GUI.color = CTextDim; GUILayout.Label("Enemy:", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(44f) }); GUI.color = Color.white; GUILayout.Label(FitHudText(currentPlaybackEnemyName, 20), _gsLabel, Array.Empty()); GUILayout.Space(12f); GUI.color = CTextDim; GUILayout.Label("Source:", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(44f) }); GUI.color = Color.white; GUILayout.Label(FitHudText(currentPlaybackSourcePlayerId, 24), _gsLabel, Array.Empty()); GUILayout.EndHorizontal(); float num2 = 0f; float num3 = 0f; using (Dictionary.Enumerator enumerator = playbackClipLengthByTargetKey.GetEnumerator()) { if (enumerator.MoveNext()) { num2 = enumerator.Current.Value; } } using (Dictionary.Enumerator enumerator = playbackStartedAtByTargetKey.GetEnumerator()) { if (enumerator.MoveNext()) { num3 = enumerator.Current.Value; } } if (num2 <= 0f) { num2 = Mathf.Max(0f, currentPlaybackEndsAt - Time.time); } float num4 = Mathf.Clamp(Time.time - num3, 0f, num2); GUILayout.Space(3f); DrawProgressBar((num2 > 0f) ? (num4 / num2) : 0f, $"{num4:F1}s / {num2:F1}s", CGreen); } else { GUI.color = CTextDim; GUILayout.Label("No active playback", _gsSmall, Array.Empty()); GUI.color = Color.white; } GUILayout.EndVertical(); } private void DrawTabRow() { GUILayout.BeginHorizontal(Array.Empty()); for (int i = 0; i < TabNames.Length; i++) { GUIStyle val = ((_debugTab == i) ? _gsTabBtnActive : _gsTabBtn); if (GUILayout.Button(TabNames[i], val, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f) })) { _debugTab = i; } } GUILayout.FlexibleSpace(); if (GUILayout.Button("▶ Force Play…", _gsBtnYellow, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Height(26f), GUILayout.ExpandWidth(false) })) { OpenForcePlayModal(); } GUILayout.EndHorizontal(); DrawHRule(); } private void DrawNearestMobsTab(float scrollH) { //IL_0024: 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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_00a4: 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) float num = ((Plugin.configPlaybackNearRadius != null) ? ((float)Plugin.configPlaybackNearRadius.Value) : 12f); GUILayout.BeginHorizontal(Array.Empty()); GUI.color = CTextDim; GUILayout.Label($"Radius: {num:F0}m Player: {FormatHudVector(((Component)this).transform.position)}", _gsSmall, Array.Empty()); GUI.color = Color.white; GUILayout.EndHorizontal(); GUILayout.Space(3f); _scrollMobs = GUILayout.BeginScrollView(_scrollMobs, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(scrollH) }); if (nearestPlaybackCandidatesHud.Count == 0) { GUI.color = CTextDim; GUILayout.Label(" No eligible enemies in scene.", _gsLabel, Array.Empty()); GUI.color = Color.white; } else { foreach (HudPlaybackCandidate item in nearestPlaybackCandidatesHud) { if (item != null) { DrawMobRow(item, num); GUILayout.Space(2f); } } } GUILayout.EndScrollView(); } private void DrawMobRow(HudPlaybackCandidate c, float nearRadius) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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_00ca: 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_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_021f: 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_0205: Unknown result type (might be due to invalid IL or missing references) bool flag = c.Distance <= nearRadius; GUILayout.BeginVertical(_gsPanelBox, Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); GUI.color = (c.IsPlaying ? CGreen : (flag ? CAccent : CTextDim)); GUILayout.Label(c.IsPlaying ? "▶" : (flag ? "●" : "○"), _gsLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(14f) }); GUI.color = Color.white; object obj = c.EnemyName; obj = ((!c.IsPlaying) ? ((object)_gsLabel) : ((object)new GUIStyle(_gsLabel) { fontStyle = (FontStyle)1 })); GUILayout.Label((string)obj, (GUIStyle)obj, Array.Empty()); GUILayout.FlexibleSpace(); GUI.color = (flag ? CText : CTextDim); GUILayout.Label($"{c.Distance:F1}m", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(46f) }); GUI.color = Color.white; if (!flag) { GUI.color = new Color(0.35f, 0.35f, 0.35f); GUILayout.Label("out of radius", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(78f) }); GUI.color = Color.white; } GUILayout.EndHorizontal(); if (c.IsPlaying) { int playbackTargetKey = GetPlaybackTargetKey(c.Enemy, c.Target); float value; float num = (playbackStartedAtByTargetKey.TryGetValue(playbackTargetKey, out value) ? value : Time.time); float value2; float num2 = (playbackClipLengthByTargetKey.TryGetValue(playbackTargetKey, out value2) ? value2 : 0f); float num3 = Mathf.Clamp(Time.time - num, 0f, num2); GUILayout.Space(2f); DrawProgressBar((num2 > 0f) ? (num3 / num2) : 0f, $"{num3:F1}s / {num2:F1}s", CGreen); } GUI.color = CTextDim; GUILayout.Label(" " + FormatHudVector(c.Position), _gsSmall, Array.Empty()); GUI.color = Color.white; GUILayout.EndVertical(); } private void DrawPlayersTab(float scrollH) { //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) HashSet onlineIds = GetOnlinePlayerIds(); string b = ((PhotonNetwork.LocalPlayer != null) ? GetPlayerPersistentId(PhotonNetwork.LocalPlayer) : string.Empty); Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (CachedAudioEntry item4 in cachedAudio) { if (item4 != null) { string text = ((!string.IsNullOrWhiteSpace(item4.SourcePlayerId)) ? item4.SourcePlayerId : $"actor_{item4.SourceActor}"); string item = ((!string.IsNullOrWhiteSpace(item4.SourceName)) ? item4.SourceName : text); dictionary[text] = (dictionary.TryGetValue(text, out var value) ? (value.Item1, value.Item2 + 1) : (item, 1)); } } if (PhotonNetwork.PlayerList != null) { Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (val != null) { string playerPersistentId = GetPlayerPersistentId(val); if (!dictionary.ContainsKey(playerPersistentId)) { dictionary[playerPersistentId] = (string.IsNullOrWhiteSpace(val.NickName) ? playerPersistentId : val.NickName, 0); } } } } GUILayout.BeginHorizontal(Array.Empty()); GUI.color = CTextDim; GUILayout.Label($"Online: {onlineIds.Count} Players with clips: {dictionary.Count>((KeyValuePair kv) => kv.Value.count > 0)}", _gsSmall, Array.Empty()); GUI.color = Color.white; GUILayout.EndHorizontal(); GUILayout.Space(3f); _scrollPlayers = GUILayout.BeginScrollView(_scrollPlayers, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(scrollH) }); List> list = (from kv in dictionary orderby onlineIds.Contains(kv.Key) descending, kv.Value.name select kv).ToList(); if (list.Count == 0) { GUI.color = CTextDim; GUILayout.Label(" No player data available.", _gsLabel, Array.Empty()); GUI.color = Color.white; } foreach (KeyValuePair item5 in list) { string key = item5.Key; (string, int) value2 = item5.Value; string item2 = value2.Item1; int item3 = value2.Item2; bool isOnline = onlineIds.Contains(key); bool isLocal = string.Equals(key, b, StringComparison.OrdinalIgnoreCase); DrawPlayerRow(key, item2, item3, isOnline, isLocal); GUILayout.Space(2f); } GUILayout.EndScrollView(); } private void DrawPlayerRow(string pid, string name, int clipCount, bool isOnline, bool isLocal) { //IL_001e: 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_0029: 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_009a: 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_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_017e: 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_0143: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(_gsPanelBox, Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); GUI.color = ((!isOnline) ? CTextDim : (isLocal ? CYellow : CGreen)); GUILayout.Label(isOnline ? "●" : "○", _gsLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(14f) }); GUI.color = Color.white; object obj = name + (isLocal ? " (you)" : string.Empty); obj = ((!isLocal) ? ((object)_gsLabel) : ((object)new GUIStyle(_gsLabel) { fontStyle = (FontStyle)1 })); GUILayout.Label((string)obj, (GUIStyle)obj, Array.Empty()); GUILayout.FlexibleSpace(); GUI.color = ((clipCount > 0) ? CAccent : CTextDim); GUILayout.Label(string.Format("{0} clip{1}", clipCount, (clipCount != 1) ? "s" : string.Empty), _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(56f) }); GUI.color = Color.white; if (!isOnline) { GUI.color = CTextDim; GUILayout.Label("[offline]", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(52f) }); GUI.color = Color.white; } GUILayout.EndHorizontal(); GUI.color = CTextDim; GUILayout.Label(" id: " + FitHudText(pid, 40), _gsSmall, Array.Empty()); GUI.color = Color.white; GUILayout.EndVertical(); } private void DrawCacheTab(float scrollH) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_025b: 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_0327: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_03a3: Unknown result type (might be due to invalid IL or missing references) //IL_0444: Unknown result type (might be due to invalid IL or missing references) //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_03dd: Unknown result type (might be due to invalid IL or missing references) //IL_0496: Unknown result type (might be due to invalid IL or missing references) //IL_04f2: 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_0509: Unknown result type (might be due to invalid IL or missing references) //IL_0525: Unknown result type (might be due to invalid IL or missing references) //IL_0544: Unknown result type (might be due to invalid IL or missing references) //IL_0779: Unknown result type (might be due to invalid IL or missing references) //IL_0798: Unknown result type (might be due to invalid IL or missing references) //IL_05a1: Unknown result type (might be due to invalid IL or missing references) //IL_05e5: Unknown result type (might be due to invalid IL or missing references) //IL_05f9: Unknown result type (might be due to invalid IL or missing references) //IL_0634: Unknown result type (might be due to invalid IL or missing references) //IL_0677: Unknown result type (might be due to invalid IL or missing references) //IL_0857: Unknown result type (might be due to invalid IL or missing references) //IL_08b7: Unknown result type (might be due to invalid IL or missing references) //IL_08c1: Unknown result type (might be due to invalid IL or missing references) //IL_08dd: Unknown result type (might be due to invalid IL or missing references) //IL_08ec: Unknown result type (might be due to invalid IL or missing references) //IL_0916: Unknown result type (might be due to invalid IL or missing references) //IL_0701: Unknown result type (might be due to invalid IL or missing references) //IL_06ba: Unknown result type (might be due to invalid IL or missing references) //IL_096a: Unknown result type (might be due to invalid IL or missing references) //IL_098d: Unknown result type (might be due to invalid IL or missing references) //IL_09ba: Unknown result type (might be due to invalid IL or missing references) //IL_072e: Unknown result type (might be due to invalid IL or missing references) //IL_0a4c: Unknown result type (might be due to invalid IL or missing references) //IL_0a79: Unknown result type (might be due to invalid IL or missing references) //IL_0b9b: Unknown result type (might be due to invalid IL or missing references) //IL_0bc8: Unknown result type (might be due to invalid IL or missing references) //IL_0c82: Unknown result type (might be due to invalid IL or missing references) //IL_0c87: Unknown result type (might be due to invalid IL or missing references) //IL_0c99: Unknown result type (might be due to invalid IL or missing references) //IL_0d77: Unknown result type (might be due to invalid IL or missing references) //IL_0dbb: Unknown result type (might be due to invalid IL or missing references) //IL_0dcf: Unknown result type (might be due to invalid IL or missing references) //IL_0e0a: Unknown result type (might be due to invalid IL or missing references) //IL_0e43: Unknown result type (might be due to invalid IL or missing references) //IL_0ef2: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginHorizontal(Array.Empty()); GUI.color = CTextDim; GUILayout.Label($"Total: {cachedAudio.Count} clips In-progress: {incomingAudioTransmissions.Count} transmissions Custom: {_customAudioClips.Count}", _gsSmall, Array.Empty()); GUI.color = Color.white; GUILayout.FlexibleSpace(); GUI.color = CAccentDim; if (GUILayout.Button("↺ Reload Custom", _gsBtn, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Height(22f), GUILayout.ExpandWidth(false) })) { ReloadCustomAudio(); } GUI.color = Color.white; GUILayout.Space(4f); if (GUILayout.Button("Clear Cache", _gsBtnDanger, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Height(22f), GUILayout.ExpandWidth(false) })) { cachedAudio.Clear(); _cacheExpandedPlayers.Clear(); DLog("Debug HUD: cache manually cleared " + DebugContext()); } GUILayout.EndHorizontal(); GUILayout.Space(3f); Dictionary, float)> dictionary = new Dictionary, float)>(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 item = ((!string.IsNullOrWhiteSpace(cachedAudioEntry.SourceName)) ? cachedAudioEntry.SourceName : text); if (dictionary.TryGetValue(text, out var value)) { value.Item2.Add(i); dictionary[text] = (value.Item1, value.Item2, Mathf.Max(value.Item3, cachedAudioEntry.ReceivedAt)); } else { dictionary[text] = (item, new List { i }, cachedAudioEntry.ReceivedAt); } } } List, float)>> list = dictionary.OrderByDescending, float)>, int>((KeyValuePair indices, float lastAt)> kv) => kv.Value.indices.Count).ToList(); _scrollCache = GUILayout.BeginScrollView(_scrollCache, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(scrollH) }); List customAudioClips = _customAudioClips; bool flag = _cacheExpandedPlayers.Contains("__custom__"); string obj = (flag ? "▼" : "▶"); GUILayout.BeginVertical(_gsPanelBox, Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); GUI.color = new Color(0.55f, 0.85f, 0.4f); if (GUILayout.Button(obj, _gsBtn, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(22f), GUILayout.Height(20f) })) { if (flag) { _cacheExpandedPlayers.Remove("__custom__"); } else { _cacheExpandedPlayers.Add("__custom__"); } flag = !flag; } GUI.color = new Color(0.55f, 0.85f, 0.4f); GUILayout.Label("Custom Audio", _gsLabel, Array.Empty()); GUI.color = Color.white; GUILayout.FlexibleSpace(); int num = customAudioClips.Count((CustomAudioEntry e) => e?.SourceMod == null); int num2 = customAudioClips.Count((CustomAudioEntry e) => e?.SourceMod != null); GUI.color = CTextDim; if (num > 0) { GUILayout.Label($"{num} folder", _gsSmall, Array.Empty()); } if (num2 > 0) { if (num > 0) { GUI.color = CTextDim; GUILayout.Label("|", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(10f) }); } GUI.color = CAccent; GUILayout.Label($"{num2} mod", _gsSmall, Array.Empty()); } GUI.color = new Color(0.55f, 0.85f, 0.4f); GUILayout.Label(string.Format("{0} file{1}", customAudioClips.Count, (customAudioClips.Count != 1) ? "s" : string.Empty), _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) }); GUI.color = Color.white; GUILayout.EndHorizontal(); if (flag) { GUILayout.Space(2f); Color color = default(Color); ((Color)(ref color))..ctor(0.22f, 0.36f, 0.24f); Rect rect = GUILayoutUtility.GetRect(GUIContent.none, GUIStyle.none, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(1f) }); GUI.color = color; GUI.DrawTexture(rect, (Texture)(object)_txWhite); GUI.color = Color.white; GUILayout.Space(2f); if (customAudioClips.Count == 0) { GUI.color = CTextDim; GUILayout.Label(" Drop .mp3 or .wav files into BepInEx/plugins/ToxesFoxes-Mimics/custom-audio/", _gsSmall, Array.Empty()); GUI.color = Color.white; } else { for (int j = 0; j < customAudioClips.Count; j++) { CustomAudioEntry customAudioEntry = customAudioClips[j]; if (!((Object)(object)customAudioEntry?.Clip == (Object)null)) { GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Space(4f); GUI.color = new Color(0.55f, 0.85f, 0.4f); if (GUILayout.Button("▶", _gsBtnYellow, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(24f), GUILayout.Height(18f) })) { PlayCustomAudioEntry(customAudioEntry); } GUI.color = Color.white; GUILayout.Space(4f); GUI.color = CTextDim; GUILayout.Label($"#{j + 1:D2}", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(30f) }); GUI.color = CText; GUILayout.Label($"{customAudioEntry.Clip.length:F2}s", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(44f) }); GUI.color = CTextDim; GUILayout.Label(FitHudText(customAudioEntry.FileName, (customAudioEntry.SourceMod != null) ? 22 : 30), _gsSmall, Array.Empty()); GUILayout.FlexibleSpace(); if (customAudioEntry.SourceMod != null) { GUI.color = CAccent; GUILayout.Label("[" + FitHudText(customAudioEntry.SourceMod, 20) + "]", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(130f) }); } else { GUI.color = CTextDim; GUILayout.Label("[folder]", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(55f) }); } GUI.color = Color.white; GUILayout.EndHorizontal(); } } } GUILayout.Space(2f); } GUILayout.EndVertical(); GUILayout.Space(2f); if (list.Count == 0 && customAudioClips.Count == 0) { GUI.color = CTextDim; GUILayout.Label(" Cache is empty.", _gsLabel, Array.Empty()); GUI.color = Color.white; } Color color2 = default(Color); foreach (KeyValuePair, float)> item5 in list) { string key = item5.Key; (string, List, float) value2 = item5.Value; string item2 = value2.Item1; List item3 = value2.Item2; float item4 = value2.Item3; float num3 = Time.time - item4; string text2 = ((num3 < 60f) ? $"{num3:F0}s ago" : $"{num3 / 60f:F1}m ago"); bool flag2 = _cacheExpandedPlayers.Contains(key); string obj2 = (flag2 ? "▼" : "▶"); GUILayout.BeginVertical(_gsPanelBox, Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); GUI.color = CAccentDim; if (GUILayout.Button(obj2, _gsBtn, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(22f), GUILayout.Height(20f) })) { if (flag2) { _cacheExpandedPlayers.Remove(key); } else { _cacheExpandedPlayers.Add(key); } flag2 = !flag2; } GUI.color = Color.white; GUI.color = CAccent; GUILayout.Label(item2, _gsLabel, Array.Empty()); GUI.color = Color.white; GUILayout.FlexibleSpace(); GUI.color = CTextDim; GUILayout.Label(text2, _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(58f) }); GUI.color = CYellow; GUILayout.Label(string.Format("{0} clip{1}", item3.Count, (item3.Count != 1) ? "s" : string.Empty), _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) }); GUI.color = Color.white; GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Space(26f); GUI.color = CTextDim; GUILayout.Label("id: " + FitHudText(key, 38), _gsSmall, Array.Empty()); GUI.color = Color.white; GUILayout.EndHorizontal(); if (!_playerVolBuf.TryGetValue(key, out var value3)) { int value4; int num4 = ((playerVolumeOverrides.TryGetValue(key, out value4) && value4 >= 0) ? value4 : (-1)); value3 = ((num4 >= 0) ? num4.ToString() : string.Empty); _playerVolBuf[key] = value3; } int value5; int num5 = ((playerVolumeOverrides.TryGetValue(key, out value5) && value5 >= 0) ? value5 : (-1)); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Space(26f); GUI.color = CTextDim; GUILayout.Label("Vol:", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(26f) }); GUI.color = Color.white; int num6 = ((num5 >= 0) ? num5 : (Plugin.configVoiceVolume?.Value ?? 100)); int num7 = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)num6, 0f, 100f, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(90f), GUILayout.Height(12f) })); if (num7 != num5 && num7 != num6) { playerVolumeOverrides[key] = Mathf.Clamp(num7, 0, 100); _playerVolBuf[key] = playerVolumeOverrides[key].ToString(); SavePlayersIndexToDisk(); } GUI.SetNextControlName("pvol_" + key); string text3 = GUILayout.TextField(value3, 3, _gsLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(32f) }); if (text3 != value3) { _playerVolBuf[key] = text3; if (int.TryParse(text3, out var result)) { playerVolumeOverrides[key] = Mathf.Clamp(result, 0, 100); SavePlayersIndexToDisk(); } } GUI.color = CTextDim; GUILayout.Label("%", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(14f) }); GUI.color = Color.white; if (num5 >= 0 && GUILayout.Button("↺", _gsBtn, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(20f), GUILayout.Height(16f) })) { playerVolumeOverrides.Remove(key); _playerVolBuf.Remove(key); SavePlayersIndexToDisk(); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); if (flag2) { GUILayout.Space(2f); ((Color)(ref color2))..ctor(0.22f, 0.28f, 0.36f); Rect rect2 = GUILayoutUtility.GetRect(GUIContent.none, GUIStyle.none, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(1f) }); GUI.color = color2; GUI.DrawTexture(rect2, (Texture)(object)_txWhite); GUI.color = Color.white; GUILayout.Space(2f); for (int k = 0; k < item3.Count; k++) { int num8 = item3[k]; if (num8 < 0 || num8 >= cachedAudio.Count) { continue; } CachedAudioEntry cachedAudioEntry2 = cachedAudio[num8]; if (cachedAudioEntry2 != null) { float num9 = ((cachedAudioEntry2.SampleRate > 0 && cachedAudioEntry2.AudioData != null) ? ((float)cachedAudioEntry2.AudioData.Length / (float)(cachedAudioEntry2.SampleRate * 2)) : 0f); float num10 = Time.time - cachedAudioEntry2.ReceivedAt; string text4 = ((num10 < 60f) ? $"{num10:F0}s" : $"{num10 / 60f:F1}m"); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Space(4f); GUI.color = CYellow; if (GUILayout.Button("▶", _gsBtnYellow, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(24f), GUILayout.Height(18f) })) { PlayCacheEntryOnNearest(cachedAudioEntry2); } GUI.color = Color.white; GUILayout.Space(4f); GUI.color = CTextDim; GUILayout.Label($"#{k + 1:D2}", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(30f) }); GUI.color = CText; GUILayout.Label($"{num9:F2}s", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(44f) }); GUI.color = CTextDim; GUILayout.Label(text4 + " ago", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(52f) }); float num11 = ((cachedAudioEntry2.AudioData != null) ? ((float)cachedAudioEntry2.AudioData.Length / 1024f) : 0f); string text5; if (!(num11 >= 1f)) { byte[] audioData = cachedAudioEntry2.AudioData; text5 = $"{((audioData != null) ? audioData.Length : 0)}b"; } else { text5 = $"{num11:F1}kb"; } GUILayout.Label(text5, _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) }); GUI.color = Color.white; GUILayout.EndHorizontal(); } } GUILayout.Space(2f); } GUILayout.EndVertical(); GUILayout.Space(2f); } GUILayout.EndScrollView(); } private void PlayCacheEntryOnNearest(CachedAudioEntry entry) { if (entry == null || entry.AudioData == null || entry.AudioData.Length == 0) { DLog("PlayCacheEntryOnNearest: entry empty " + DebugContext()); return; } RefreshHudTargetsSnapshot(); HudPlaybackCandidate hudPlaybackCandidate = (from c in nearestPlaybackCandidatesHud where c != null orderby c.Distance select c).FirstOrDefault(); if (hudPlaybackCandidate == null) { DLog("PlayCacheEntryOnNearest: no enemy targets found " + DebugContext()); return; } DLog($"PlayCacheEntryOnNearest: playing on {hudPlaybackCandidate.EnemyName} dist={hudPlaybackCandidate.Distance:F1}m {DebugContext()}"); PlayReceivedAudioOnTarget(entry, hudPlaybackCandidate.Enemy, hudPlaybackCandidate.Target); } internal void PushVoiceLog(bool isIncoming, string txId, string playerId, string playerName, int bytes, bool isComplete, int chunksDone = 0, int chunksTotal = 0, bool isFailed = false) { int num = _voiceLog.FindIndex((VoiceLogEntry e) => e.TransmissionId == txId); if (num >= 0) { VoiceLogEntry voiceLogEntry = _voiceLog[num]; if (bytes > 0) { voiceLogEntry.Bytes = bytes; } voiceLogEntry.IsComplete = isComplete; voiceLogEntry.IsFailed = isFailed; voiceLogEntry.UpdatedAt = Time.time; if (chunksDone > 0) { voiceLogEntry.ChunksDone = chunksDone; } if (chunksTotal > 0) { voiceLogEntry.ChunksTotal = chunksTotal; } return; } if (_voiceLog.Count >= 200) { _voiceLog.RemoveAt(0); } _voiceLog.Add(new VoiceLogEntry { IsIncoming = isIncoming, TransmissionId = txId, PlayerId = playerId, PlayerName = (string.IsNullOrWhiteSpace(playerName) ? playerId : playerName), Bytes = bytes, IsComplete = isComplete, ReceivedAt = Time.time, UpdatedAt = Time.time, ChunksDone = chunksDone, ChunksTotal = chunksTotal }); } private void DrawVoiceLogTab(float scrollH) { //IL_0095: 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_00e1: 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_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) List list = _voiceLog.Where((VoiceLogEntry e) => e.IsIncoming).ToList(); List list2 = _voiceLog.Where((VoiceLogEntry e) => !e.IsIncoming).ToList(); int num = _voiceLog.Count((VoiceLogEntry e) => !e.IsComplete); GUILayout.BeginHorizontal(Array.Empty()); GUI.color = CTextDim; GUILayout.Label($"Total: {_voiceLog.Count}", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); if (num > 0) { GUILayout.Space(6f); GUI.color = CYellow; GUILayout.Label($"● {num} in progress", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); } GUI.color = Color.white; GUILayout.FlexibleSpace(); if (GUILayout.Button("Clear", _gsBtn, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Height(20f), GUILayout.ExpandWidth(false) })) { _voiceLog.Clear(); } GUILayout.EndHorizontal(); GUILayout.Space(3f); float num2 = (scrollH - 24f) * 0.5f; GUILayout.BeginHorizontal(Array.Empty()); GUI.color = CAccent; GUILayout.Label($"▼ INCOMING {list.Count}", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUI.color = Color.white; GUILayout.EndHorizontal(); _scrollVoiceLog = GUILayout.BeginScrollView(_scrollVoiceLog, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(num2) }); if (list.Count == 0) { GUI.color = CTextDim; GUILayout.Label(" No incoming transmissions recorded yet.", _gsLabel, Array.Empty()); GUI.color = Color.white; } else { for (int num3 = list.Count - 1; num3 >= 0; num3--) { DrawVoiceLogRow(list[num3]); } } GUILayout.EndScrollView(); GUILayout.Space(4f); GUILayout.BeginHorizontal(Array.Empty()); GUI.color = CYellow; GUILayout.Label($"▲ OUTGOING {list2.Count}", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }); GUI.color = Color.white; GUILayout.EndHorizontal(); _scrollVoiceLogOut = GUILayout.BeginScrollView(_scrollVoiceLogOut, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(num2) }); if (list2.Count == 0) { GUI.color = CTextDim; GUILayout.Label(" No outgoing transmissions recorded yet.", _gsLabel, Array.Empty()); GUI.color = Color.white; } else { for (int num4 = list2.Count - 1; num4 >= 0; num4--) { DrawVoiceLogRow(list2[num4]); } } GUILayout.EndScrollView(); } private void DrawVoiceLogRow(VoiceLogEntry e) { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_0130: 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_019a: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) float num = Time.time - e.ReceivedAt; string text = ((num < 60f) ? $"{num:F0}s" : $"{num / 60f:F1}m"); float num2 = (float)e.Bytes / 1024f; string text2 = ((e.Bytes == 0) ? "—" : ((num2 >= 1f) ? $"{num2:F1}kb" : $"{e.Bytes}b")); GUILayout.BeginHorizontal(Array.Empty()); if (e.IsFailed) { GUI.color = CRed; GUILayout.Label("✗", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(14f) }); } else if (e.IsComplete) { GUI.color = CGreen; GUILayout.Label("✓", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(14f) }); } else { GUI.color = CYellow; GUILayout.Label("…", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(14f) }); } GUI.color = Color.white; GUILayout.Label(FitHudText(e.PlayerName, 16), _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) }); GUI.color = CTextDim; GUILayout.Label(FitHudText(e.TransmissionId, 10), _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(76f) }); GUI.color = Color.white; if (!e.IsComplete && e.ChunksTotal > 0) { DrawChunkProgressBar(e.ChunksDone, e.ChunksTotal, 80f); GUI.color = CYellow; GUILayout.Label($"{e.ChunksDone}/{e.ChunksTotal}", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(38f) }); GUI.color = Color.white; } else { GUI.color = CTextDim; GUILayout.Label(text2, _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(44f) }); GUILayout.Label(text + " ago", _gsSmall, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(54f) }); GUI.color = Color.white; } GUILayout.EndHorizontal(); } private void DrawChunkProgressBar(int done, int total, float width) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) Rect rect = GUILayoutUtility.GetRect(width, 14f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(width) }); float num = ((total > 0) ? ((float)done / (float)total) : 0f); Color color = GUI.color; GUI.color = new Color(0.15f, 0.18f, 0.22f, 1f); GUI.DrawTexture(rect, (Texture)(object)_txWhite); Rect val = new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width * num, ((Rect)(ref rect)).height); GUI.color = ((done >= total) ? CGreen : CYellow); GUI.DrawTexture(val, (Texture)(object)_txWhite); GUI.color = color; } private static void WriteWavHeader(BinaryWriter writer, int sampleCount, int sampleRate) { writer.Write("RIFF".ToCharArray()); writer.Write(36 + sampleCount * 2); writer.Write("WAVE".ToCharArray()); writer.Write("fmt ".ToCharArray()); writer.Write(16); writer.Write((short)1); writer.Write((short)1); writer.Write(sampleRate); writer.Write(sampleRate * 2); writer.Write((short)2); writer.Write((short)16); writer.Write("data".ToCharArray()); writer.Write(sampleCount * 2); } private static byte[] ConvertFloatArrayToByteArray(float[] audioData) { byte[] array = new byte[audioData.Length * 2]; for (int i = 0; i < audioData.Length; i++) { BitConverter.GetBytes((short)(audioData[i] * 32767f)).CopyTo(array, i * 2); } return array; } private byte[] CombineChunks(List chunks) { int num = chunks.Sum((byte[] chunk) => chunk.Length); byte[] array = new byte[num]; int num2 = 0; foreach (byte[] chunk in chunks) { Array.Copy(chunk, 0, array, num2, chunk.Length); num2 += chunk.Length; } DLog($"CombineChunks: chunkCount={chunks.Count} totalBytes={num} {DebugContext()}"); return array; } private List ChunkAudioData(byte[] audioData, int chunkSize) { List list = new List(); for (int i = 0; i < audioData.Length; i += chunkSize) { int num = Mathf.Min(chunkSize, audioData.Length - i); byte[] array = new byte[num]; Array.Copy(audioData, i, array, 0, num); list.Add(array); } DLog($"ChunkAudioData: inputBytes={audioData.Length} chunkSize={chunkSize} chunkCount={list.Count} {DebugContext()}"); return list; } private float[] ConvertByteArrayToFloatArray(byte[] bytes, bool applyVoiceFilter, int senderSampleRate) { int num = (int)((float)senderSampleRate * 0.02f); int num2 = (int)((float)senderSampleRate * 0.5f); int num3 = bytes.Length / 2; float[] array = new float[num3]; for (int i = 0; i < num3; i++) { array[i] = (float)BitConverter.ToInt16(bytes, i * 2) / 32768f; } array = ApplyLowPassFilter(array, 4500f); if (applyVoiceFilter) { array = Random.Range(0, 3) switch { 0 => ApplyPitchShift(array, 0.5f), 1 => ApplyPitchShift(array, 1.2f), _ => ApplyAlienFilter(array), }; } NormalizeSamples(array); float[] array2 = new float[array.Length + num2 * 2]; for (int j = 0; j < array.Length; j++) { float num4 = 1f; if (j < num) { num4 = (float)j / (float)num; } else if (j >= array.Length - num) { num4 = (float)(array.Length - j) / (float)num; } array2[j + num2] = array[j] * num4; } return array2; } private static float[] ApplyPitchShift(float[] samples, float pitchFactor) { int num = (int)((float)samples.Length / pitchFactor); float[] array = new float[num]; for (int i = 0; i < num; i++) { float num2 = (float)i * pitchFactor; int num3 = (int)num2; float num4 = num2 - (float)num3; float num5 = ((num3 > 0) ? samples[num3 - 1] : samples[0]); float num6 = ((num3 < samples.Length) ? samples[num3] : 0f); float num7 = ((num3 + 1 < samples.Length) ? samples[num3 + 1] : 0f); float num8 = ((num3 + 2 < samples.Length) ? samples[num3 + 2] : 0f); float num9 = -0.5f * num5 + 1.5f * num6 - 1.5f * num7 + 0.5f * num8; float num10 = num5 - 2.5f * num6 + 2f * num7 - 0.5f * num8; float num11 = -0.5f * num5 + 0.5f * num7; float num12 = num6; array[i] = Mathf.Clamp(((num9 * num4 + num10) * num4 + num11) * num4 + num12, -1f, 1f); } return array; } private float[] ApplyAlienFilter(float[] samples) { float[] array = new float[samples.Length]; int num = (int)((float)sampleRate * 8f / 1000f) + 2; float[] array2 = new float[num]; int num2 = 0; for (int i = 0; i < samples.Length; i++) { float num3 = (float)i / (float)sampleRate; int num4 = (int)((float)sampleRate * 8f / 1000f); float num5 = (Mathf.Sin(8.16814f * num3) + 1f) * 0.5f; int num6 = (int)((float)num4 * num5) + 1; int num7 = (num2 - num6 + num) % num; float num8 = (array2[num2] = samples[i]); num2 = (num2 + 1) % num; float num9 = Mathf.Round(array2[num7] * 1024f) / 1024f; array[i] = Mathf.Clamp(num8 * 0.55f + num9 * 0.45f, -1f, 1f); } return array; } internal static void NormalizeSamples(float[] samples) { if (samples == null || samples.Length == 0) { return; } int num = ((Plugin.configNormalizeTarget != null) ? Plugin.configNormalizeTarget.Value : 85); if (num <= 0) { return; } float num2 = Mathf.Clamp((float)num / 100f, 0.001f, 1f); float num3 = 0f; for (int i = 0; i < samples.Length; i++) { float num4 = Mathf.Abs(samples[i]); if (num4 > num3) { num3 = num4; } } if (num3 < 0.0001f) { return; } float num5 = num2 / num3; if (!(num5 >= 1f) || !(num3 >= num2)) { for (int j = 0; j < samples.Length; j++) { samples[j] *= num5; } } } private void TryWriteDebugWav(string prefix, byte[] pcmBytes, int wavSampleRate) { if (Plugin.configDebugVerbose == null || !Plugin.configDebugVerbose.Value) { return; } try { string text = Path.Combine(GetAudioCacheDirectoryPath(), "debug"); Directory.CreateDirectory(text); string text2 = DateTime.UtcNow.ToString("yyyyMMdd_HHmmss_fff"); string text3 = prefix + "_" + text2 + ".wav"; string path = Path.Combine(text, text3); int num = pcmBytes.Length / 2; using (FileStream output = new FileStream(path, FileMode.CreateNew, FileAccess.Write, FileShare.Read)) { using BinaryWriter binaryWriter = new BinaryWriter(output); WriteWavHeader(binaryWriter, num, wavSampleRate); binaryWriter.Write(pcmBytes); } DLog($"Debug WAV written: file={text3} samples={num} sampleRate={wavSampleRate} {DebugContext()}"); } catch (Exception ex) { Log.LogWarning((object)("Debug WAV write failed: " + ex.Message)); } } private float[] ApplyLowPassFilter(float[] samples, float cutoffFreq) { float[] array = new float[samples.Length]; if (samples.Length == 0) { return array; } float num = ((sampleRate > 0) ? ((float)sampleRate) : 48000f); float num2 = Mathf.Tan(MathF.PI * cutoffFreq / num); float num3 = num2 * num2; float num4 = MathF.Sqrt(2f) * num2; float num5 = 1f / (num3 + num4 + 1f); float num6 = num3 * num5; float num7 = 2f * num3 * num5; float num8 = num3 * num5; float num9 = 2f * (num3 - 1f) * num5; float num10 = (num3 - num4 + 1f) * num5; float num11 = 0f; float num12 = 0f; float num13 = 0f; float num14 = 0f; for (int i = 0; i < samples.Length; i++) { float num15 = samples[i]; float num16 = num6 * num15 + num7 * num11 + num8 * num12 - num9 * num13 - num10 * num14; num12 = num11; num11 = num15; num14 = num13; num13 = num16; array[i] = Mathf.Clamp(num16, -1f, 1f); } return array; } private string DebugContext() { Player localPlayer = PhotonNetwork.LocalPlayer; int num = ((localPlayer != null) ? localPlayer.ActorNumber : (-1)); string text = ((localPlayer != null) ? localPlayer.NickName : "null"); Player val = (((Object)(object)photonView != (Object)null) ? photonView.Owner : null); int num2 = ((val != null) ? val.ActorNumber : (-1)); string text2 = ((val != null) ? val.NickName : "null"); return $"[ctx local={num}:{text} owner={num2}:{text2} isMine={(Object)(object)photonView != (Object)null && photonView.IsMine} time={Time.time:F2}]"; } private void DLog(string message) { if (Plugin.configDebugVerbose != null && Plugin.configDebugVerbose.Value) { Log.LogInfo((object)message); } } private static string FormatHudVector(Vector3 value) { //IL_0005: 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_001b: Unknown result type (might be due to invalid IL or missing references) return $"({value.x:F1}, {value.y:F1}, {value.z:F1})"; } private void Update() { if (!((Object)(object)photonView == (Object)null) && photonView.IsMine) { bool flag = SemiFunc.RunIsLevel(); if (flag && !wasInLevel) { OnEnteredLevel(); } else if (!flag && wasInLevel) { wasInLevel = false; persistenceInitialized = false; _fpmOpen = false; _debugWindowFocused = _debugWindowOpen; DestroyAllOverlays(); SetCursorForGui(guiActive: false); } if (flag) { DebugGuiUpdate(); } } } private void OnEnteredLevel() { wasInLevel = true; EnsurePersistenceInitialized(); LogPlayerRecordingSummaryForWorldEntry(); } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void Awake() { Instance = this; photonView = ((Component)this).GetComponent(); if ((Object)(object)photonView == (Object)null) { Log.LogError((object)"PhotonView not found on Mimics."); return; } DLog("Mimics Awake " + DebugContext() + " object=" + ((Object)((Component)this).gameObject).name); PlayerAvatar component = ((Component)this).GetComponent(); if ((Object)(object)component == (Object)null) { Log.LogError((object)"PlayerAvatar not found on Mimics."); return; } sampleRate = Plugin.configSamplingRate.Value; DLog($"Configured sampleRate={sampleRate} minDelay={Plugin.configMinDelay.Value} maxDelay={Plugin.configMaxDelay.Value} volume={Plugin.configVoiceVolume.Value} hearSelf={Plugin.configHearYourself.Value} filterEnabled={Plugin.configFilterEnabled.Value} {DebugContext()}"); if (Plugin.configFilterEnabled.Value) { filter = new Dictionary(); SetEnemyFilter(); } else { DLog("Filter disabled, all enemies can mimic."); } ((MonoBehaviour)this).StartCoroutine(InitializeVoiceChat(component)); } [IteratorStateMachine(typeof(d__199))] private IEnumerator InitializeVoiceChat(PlayerAvatar avatar) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__199(0) { <>4__this = this, avatar = avatar }; } [IteratorStateMachine(typeof(d__200))] private IEnumerator PlayCachedAudioAtRandomIntervals() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__200(0) { <>4__this = this }; } [IteratorStateMachine(typeof(d__201))] private IEnumerator EnsureEnemyAudioSourcesLoop() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__201(0) { <>4__this = this }; } private string GetCustomAudioDirectoryPath() { return Path.Combine(Paths.BepInExRootPath, "plugins", "ToxesFoxes-Mimics", "custom-audio"); } internal void EnsureCustomAudioLoaded() { if (!_customAudioLoaded) { _customAudioLoaded = true; ((MonoBehaviour)this).StartCoroutine(LoadCustomAudioClipsCoroutine()); } } internal void ReloadCustomAudio() { foreach (CustomAudioEntry customAudioClip in _customAudioClips) { if ((customAudioClip == null || customAudioClip.SourceMod == null) && (Object)(object)customAudioClip?.Clip != (Object)null) { Object.Destroy((Object)(object)customAudioClip.Clip); } } _customAudioClips.RemoveAll((CustomAudioEntry e) => e?.SourceMod == null); _customAudioLoaded = false; EnsureCustomAudioLoaded(); } internal void ConsumeApiClips() { List<(string, string, AudioClip)> list = MimicsAPI.TakePending(); if (list == null) { return; } foreach (var (text, text2, val) in list) { if (!((Object)(object)val == (Object)null)) { _customAudioClips.Add(new CustomAudioEntry { Clip = val, FileName = ((!string.IsNullOrEmpty(((Object)val).name)) ? ((Object)val).name : text), FilePath = null, SourceMod = text2, IsNormalized = false }); Log.LogInfo((object)("[Mimics] API: registered clip '" + ((Object)val).name + "' from mod '" + text2 + "' (guid=" + text + ")")); } } } [IteratorStateMachine(typeof(d__209))] private IEnumerator LoadCustomAudioClipsCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__209(0) { <>4__this = this }; } private void PlayCustomAudioEntry(CustomAudioEntry entry) { //IL_00a6: 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_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)entry?.Clip == (Object)null) { return; } List enemies = (from e in GetEnemiesList() where (Object)(object)e != (Object)null select e).ToList(); List<(GameObject, GameObject)> list = BuildPlaybackTargets(enemies, warnOnMissingTarget: true); if (list.Count == 0) { hudHasSelectedEnemyPos = false; nearestPlaybackTargetsHud.Clear(); nearestPlaybackTargetsHud.Add("No candidates"); DLog("PlayCustomAudioEntry '" + entry.FileName + "': no targets " + DebugContext()); return; } Vector3 position = ((Component)this).transform.position; float nearRadius = ((Plugin.configPlaybackNearRadius != null) ? ((float)Plugin.configPlaybackNearRadius.Value) : 25f); UpdateNearestPlaybackTargetsHud(list, position, nearRadius); List list2 = nearestPlaybackCandidatesHud.Where((HudPlaybackCandidate c) => c != null && c.Distance <= nearRadius && !c.IsPlaying).ToList(); if (list2.Count == 0) { DLog($"PlayCustomAudioEntry '{entry.FileName}': no candidates inside radius={nearRadius:F1} {DebugContext()}"); return; } HudPlaybackCandidate hudPlaybackCandidate = list2[Random.Range(0, list2.Count)]; if (!entry.IsNormalized) { NormalizeClip(entry.Clip); entry.IsNormalized = true; } AudioSource orCreateReusableEnemyAudioSource = GetOrCreateReusableEnemyAudioSource(hudPlaybackCandidate.Enemy, hudPlaybackCandidate.Target, hudPlaybackCandidate.Position); if ((Object)(object)orCreateReusableEnemyAudioSource == (Object)null) { Log.LogWarning((object)("[Mimics] PlayCustomAudioEntry '" + entry.FileName + "': failed to get AudioSource " + DebugContext())); return; } orCreateReusableEnemyAudioSource.clip = entry.Clip; orCreateReusableEnemyAudioSource.volume = GetVolumeForPlayer("custom"); 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 + entry.Clip.length + 0.1f; int playbackTargetKey = GetPlaybackTargetKey(hudPlaybackCandidate.Enemy, hudPlaybackCandidate.Target); if (playbackTargetKey != 0) { playbackBusyUntilByTargetKey[playbackTargetKey] = value; playbackStartedAtByTargetKey[playbackTargetKey] = Time.time; playbackClipLengthByTargetKey[playbackTargetKey] = entry.Clip.length; } currentPlaybackEnemyName = hudPlaybackCandidate.EnemyName; currentPlaybackSourcePlayerId = "custom"; hudTrackedEnemy = hudPlaybackCandidate.Enemy; hudTrackedTarget = hudPlaybackCandidate.Target; hudLastSelectedEnemyPos = hudPlaybackCandidate.Position; hudHasSelectedEnemyPos = true; currentPlaybackEndsAt = value; DLog($"PlayCustomAudioEntry: playing '{entry.FileName}' length={entry.Clip.length:F1}s on '{hudPlaybackCandidate.EnemyName}' dist={hudPlaybackCandidate.Distance:F1} {DebugContext()}"); } private static void NormalizeClip(AudioClip clip) { if (!((Object)(object)clip == (Object)null)) { float[] array = new float[clip.samples * clip.channels]; if (clip.GetData(array, 0)) { NormalizeSamples(array); clip.SetData(array, 0); } } } private void EnsurePersistenceInitialized() { if (!persistenceInitialized) { persistenceInitialized = true; if (Plugin.configPersistAudioCache != null && Plugin.configPersistAudioCache.Value) { LoadPersistedAudioEntriesFromDisk(); } } } private string GetAudioCacheDirectoryPath() { return Path.Combine(Paths.BepInExRootPath, "plugins", "ToxesFoxes-Mimics", "audio-cache"); } private void LoadPersistedAudioEntriesFromDisk() { string audioCacheDirectoryPath = GetAudioCacheDirectoryPath(); if (!Directory.Exists(audioCacheDirectoryPath)) { return; } LoadPlayersIndexFromDisk(); string[] files = Directory.GetFiles(audioCacheDirectoryPath, "audio_*_*.bin", SearchOption.AllDirectories); int num = 0; string[] array = files; foreach (string text in array) { if (!string.IsNullOrWhiteSpace(text) && !loadedPersistedFiles.Contains(text) && TryReadAudioEntryFromDisk(text, out var entry) && entry != null) { cachedAudio.Add(entry); RegisterPlayerInIndex(entry.SourcePlayerId, entry.SourceName); loadedPersistedFiles.Add(text); num++; } } SavePlayersIndexToDisk(); DLog($"Persistence load complete: loaded={num} totalCached={cachedAudio.Count} path={audioCacheDirectoryPath} {DebugContext()}"); } private void SaveAudioEntryToDisk(CachedAudioEntry entry) { try { if (entry == null || entry.AudioData == null || entry.AudioData.Length == 0) { return; } string audioCacheDirectoryPath = GetAudioCacheDirectoryPath(); Directory.CreateDirectory(audioCacheDirectoryPath); int sourceActor = entry.SourceActor; string text = ((!string.IsNullOrWhiteSpace(entry.SourcePlayerId)) ? entry.SourcePlayerId : $"actor_{sourceActor}"); string text2 = SanitizePlayerIdForFileName(text); string text3 = Path.Combine(audioCacheDirectoryPath, text2); Directory.CreateDirectory(text3); string text4 = $"audio_{text2}_{Guid.NewGuid():N}.bin"; string text5 = Path.Combine(text3, text4); using (FileStream output = new FileStream(text5, FileMode.CreateNew, FileAccess.Write, FileShare.Read)) { using BinaryWriter binaryWriter = new BinaryWriter(output); binaryWriter.Write("MIMC2"); binaryWriter.Write(sourceActor); binaryWriter.Write(text); binaryWriter.Write(entry.SampleRate); binaryWriter.Write(entry.ApplyVoiceFilter); binaryWriter.Write(entry.SourceName ?? string.Empty); binaryWriter.Write(entry.AudioData.Length); binaryWriter.Write(entry.AudioData); } RegisterPlayerInIndex(text, entry.SourceName); SavePlayersIndexToDisk(); EnforcePlayerAudioFileLimit(text3); loadedPersistedFiles.Add(text5); DLog($"Persistence save: file={text4} playerId={text} actor={sourceActor} bytes={entry.AudioData.Length} {DebugContext()}"); } catch (Exception ex) { Log.LogWarning((object)("Persistence save failed: " + ex.Message + " " + DebugContext())); } } private bool TryReadAudioEntryFromDisk(string path, out CachedAudioEntry entry) { entry = null; try { using FileStream input = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); using BinaryReader binaryReader = new BinaryReader(input); string a = binaryReader.ReadString(); if (!string.Equals(a, "MIMC1", StringComparison.Ordinal) && !string.Equals(a, "MIMC2", StringComparison.Ordinal)) { return false; } int num = binaryReader.ReadInt32(); string text = string.Empty; if (string.Equals(a, "MIMC2", StringComparison.Ordinal)) { text = binaryReader.ReadString(); } int num2 = binaryReader.ReadInt32(); bool applyVoiceFilter = binaryReader.ReadBoolean(); string sourceName = binaryReader.ReadString(); int num3 = binaryReader.ReadInt32(); if (num3 <= 0 || num3 > 52428800) { return false; } byte[] array = binaryReader.ReadBytes(num3); if (array.Length != num3) { return false; } if (num < 0 && TryParsePlayerIdFromAudioFileName(path, out var playerId)) { text = playerId; } if (string.IsNullOrWhiteSpace(text)) { text = ((num >= 0) ? $"actor_{num}" : "unknown"); } entry = new CachedAudioEntry { AudioData = array, ApplyVoiceFilter = applyVoiceFilter, SampleRate = num2, SourceActor = num, SourcePlayerId = text, SourceName = sourceName, ReceivedAt = Time.time }; return true; } catch (Exception ex) { Log.LogWarning((object)("Persistence read failed file=" + Path.GetFileName(path) + " error=" + ex.Message + " " + DebugContext())); return false; } } private static string SanitizePlayerIdForFileName(string playerId) { if (string.IsNullOrWhiteSpace(playerId)) { return "unknown"; } char[] invalidChars = Path.GetInvalidFileNameChars(); string text = new string(playerId.Select((char ch) => (!invalidChars.Contains(ch)) ? ch : '_').ToArray()); if (!string.IsNullOrWhiteSpace(text)) { return text; } return "unknown"; } private static bool TryParsePlayerIdFromAudioFileName(string filePath, out string playerId) { playerId = string.Empty; string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath); if (string.IsNullOrWhiteSpace(fileNameWithoutExtension)) { return false; } if (!fileNameWithoutExtension.StartsWith("audio_", StringComparison.OrdinalIgnoreCase)) { return false; } string text = fileNameWithoutExtension.Substring("audio_".Length); int num = text.LastIndexOf('_'); if (num <= 0) { return false; } playerId = text.Substring(0, num); return !string.IsNullOrWhiteSpace(playerId); } private string GetPlayersIndexPath() { return Path.Combine(GetAudioCacheDirectoryPath(), "players.json"); } private void RegisterPlayerInIndex(string playerId, string playerName) { if (!string.IsNullOrWhiteSpace(playerId)) { string value = (string.IsNullOrWhiteSpace(playerName) ? "unknown" : playerName); if (!playerNameById.TryGetValue(playerId, out var value2) || string.IsNullOrWhiteSpace(value2) || string.Equals(value2, "unknown", StringComparison.OrdinalIgnoreCase)) { playerNameById[playerId] = value; } } } private void LoadPlayersIndexFromDisk() { string playersIndexPath = GetPlayersIndexPath(); if (!File.Exists(playersIndexPath)) { return; } try { List list = ParsePlayersJson(File.ReadAllText(playersIndexPath)); foreach (PlayerJsonEntry item in list) { if (!string.IsNullOrWhiteSpace(item.id) && item.volumeOverride >= 0) { playerVolumeOverrides[item.id] = item.volumeOverride; } } DLog($"LoadPlayersIndexFromDisk: loaded volumeOverrides for {list.Count} player(s)"); } catch (Exception ex) { Log.LogWarning((object)("Failed to load players index: " + ex.Message)); } } private static List ParsePlayersJson(string json) { List list = new List(); if (string.IsNullOrWhiteSpace(json)) { return list; } int num = 0; while (num < json.Length) { int num2 = json.IndexOf('{', num); if (num2 < 0) { break; } int num3 = json.IndexOf('}', num2); if (num3 < 0) { break; } string obj = json.Substring(num2 + 1, num3 - num2 - 1); PlayerJsonEntry playerJsonEntry = new PlayerJsonEntry(); playerJsonEntry.id = ExtractJsonString(obj, "id"); playerJsonEntry.name = ExtractJsonString(obj, "name"); if (int.TryParse(ExtractJsonString(obj, "volumeOverride"), out var result)) { playerJsonEntry.volumeOverride = result; } if (!string.IsNullOrWhiteSpace(playerJsonEntry.id)) { list.Add(playerJsonEntry); } num = num3 + 1; } return list; } private static string ExtractJsonString(string obj, string key) { string text = "\"" + key + "\""; int num = obj.IndexOf(text, StringComparison.OrdinalIgnoreCase); if (num < 0) { return string.Empty; } int num2 = obj.IndexOf(':', num + text.Length); if (num2 < 0) { return string.Empty; } string text2 = obj.Substring(num2 + 1).TrimStart(); if (text2.Length == 0) { return string.Empty; } if (text2[0] == '"') { int num3 = text2.IndexOf('"', 1); if (num3 >= 0) { return text2.Substring(1, num3 - 1); } return string.Empty; } int i; for (i = 0; i < text2.Length && text2[i] != ',' && text2[i] != '}' && text2[i] != '\n'; i++) { } return text2.Substring(0, i).Trim(); } private void SavePlayersIndexToDisk() { try { Directory.CreateDirectory(GetAudioCacheDirectoryPath()); Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (CachedAudioEntry item in cachedAudio) { if (item != null) { string key = ((!string.IsNullOrWhiteSpace(item.SourcePlayerId)) ? item.SourcePlayerId : $"actor_{item.SourceActor}"); dictionary[key] = ((!dictionary.TryGetValue(key, out var value)) ? 1 : (value + 1)); } } List> list = playerNameById.OrderBy, string>((KeyValuePair kv) => kv.Key, StringComparer.OrdinalIgnoreCase).ToList(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("{"); stringBuilder.AppendLine(" \"players\": ["); for (int i = 0; i < list.Count; i++) { KeyValuePair keyValuePair = list[i]; string text = EscapeJsonString(keyValuePair.Key); string text2 = EscapeJsonString(string.IsNullOrWhiteSpace(keyValuePair.Value) ? "unknown" : keyValuePair.Value); dictionary.TryGetValue(keyValuePair.Key, out var value2); playerVolumeOverrides.TryGetValue(keyValuePair.Key, out var value3); string text3 = ((i < list.Count - 1) ? "," : string.Empty); stringBuilder.AppendLine($" {{ \"id\": \"{text}\", \"name\": \"{text2}\", \"clipCount\": {value2}, \"volumeOverride\": {value3} }}{text3}"); } stringBuilder.AppendLine(" ]"); stringBuilder.AppendLine("}"); File.WriteAllText(GetPlayersIndexPath(), stringBuilder.ToString()); } catch (Exception ex) { Log.LogWarning((object)("Failed to save players index JSON: " + ex.Message + " " + DebugContext())); } } private static string EscapeJsonString(string value) { if (value == null) { return string.Empty; } return value.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\r", "\\r") .Replace("\n", "\\n") .Replace("\t", "\\t"); } private void EnforcePlayerAudioFileLimit(string playerDir) { if (string.IsNullOrWhiteSpace(playerDir) || !Directory.Exists(playerDir)) { return; } int num = ((Plugin.configPersistMaxFilesPerPlayer != null) ? Plugin.configPersistMaxFilesPerPlayer.Value : 200); if (num < 1) { return; } try { List list = (from path in Directory.GetFiles(playerDir, "audio_*_*.bin", SearchOption.TopDirectoryOnly) orderby File.GetCreationTimeUtc(path) select path).ToList(); int num2 = list.Count - num; if (num2 > 0) { for (int i = 0; i < num2; i++) { string text = list[i]; File.Delete(text); loadedPersistedFiles.Remove(text); } } } catch (Exception ex) { Log.LogWarning((object)("Failed to enforce per-player audio file limit: " + ex.Message + " dir=" + playerDir + " " + DebugContext())); } } private static string GetPlayerPersistentId(Player player) { if (player == null) { return "unknown"; } string text = TryGetSteamIdFromPlayerAvatar(player); if (!string.IsNullOrWhiteSpace(text) && text != "0") { return text; } if (!string.IsNullOrWhiteSpace(player.UserId)) { return player.UserId; } if (player.CustomProperties != null) { string[] array = new string[6] { "steamid", "steam_id", "SteamId", "SteamID", "playerId", "PlayerId" }; foreach (string key in array) { if (((Dictionary)(object)player.CustomProperties).TryGetValue((object)key, out object value) && value != null) { string text2 = value.ToString(); if (!string.IsNullOrWhiteSpace(text2) && text2 != "0") { return text2; } } } } return $"actor_{player.ActorNumber}"; } private static string TryGetSteamIdFromPlayerAvatar(Player player) { if (player == null) { return null; } PlayerAvatar[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (PlayerAvatar val in array) { if ((Object)(object)val == (Object)null) { continue; } PhotonView component = ((Component)val).GetComponent(); if (!((Object)(object)component == (Object)null) && component.Owner != null && component.Owner.ActorNumber == player.ActorNumber) { if (_steamIdField == null) { _steamIdField = typeof(PlayerAvatar).GetField("steamID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (_steamIdField == null) { return null; } string text = _steamIdField.GetValue(val) as string; if (!string.IsNullOrWhiteSpace(text)) { return text; } return null; } } return null; } private static string GetPlayerDisplayName(Player player) { if (player == null) { return "unknown"; } if (!string.IsNullOrWhiteSpace(player.NickName)) { return player.NickName; } return $"actor_{player.ActorNumber}"; } private HashSet GetOnlinePlayerIds() { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); if (PhotonNetwork.PlayerList != null) { Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (val != null) { hashSet.Add(GetPlayerPersistentId(val)); } } } return hashSet; } private float GetVolumeForPlayer(string playerId) { if (!string.IsNullOrWhiteSpace(playerId) && playerVolumeOverrides.TryGetValue(playerId, out var value) && value >= 0) { return Mathf.Clamp01((float)value / 100f); } return Mathf.Clamp01((float)(Plugin.configVoiceVolume?.Value ?? 20) / 100f); } private void LogPlayerRecordingSummaryForWorldEntry() { List values = (from x in GetOnlinePlayerIds() orderby x select x).ToList(); Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (CachedAudioEntry item in cachedAudio) { if (item != null) { string key = ((!string.IsNullOrWhiteSpace(item.SourcePlayerId)) ? item.SourcePlayerId : $"actor_{item.SourceActor}"); dictionary[key] = ((!dictionary.TryGetValue(key, out var value)) ? 1 : (value + 1)); } } string text = ((dictionary.Count == 0) ? "none" : string.Join(", ", from kv in dictionary orderby kv.Key select $"{kv.Key}:{kv.Value}")); Log.LogInfo((object)("World entry player IDs online=[" + string.Join(",", values) + "] recordingsByPlayer=[" + text + "] " + DebugContext())); } [PunRPC] public void ReceiveAudioChunkV2(byte[] chunk, int chunkIndex, int totalChunks, bool applyFilter, int senderSampleRate, string transmissionId, PhotonMessageInfo info) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) ReceiveAudioChunkInternal(chunk, chunkIndex, totalChunks, applyFilter, senderSampleRate, transmissionId, info.Sender); } internal void ReceiveAudioChunkInternal(byte[] chunk, int chunkIndex, int totalChunks, bool applyFilter, int senderSampleRate, string transmissionId, Player sender) { int num = ((sender != null) ? sender.ActorNumber : (-1)); string text = ((sender != null) ? GetPlayerPersistentId(sender) : "unknown"); string text2 = ((sender != null) ? sender.NickName : "unknown"); string text3 = (string.IsNullOrWhiteSpace(transmissionId) ? "legacy" : transmissionId); CleanupStaleIncomingTransmissions(); if (chunk == null || totalChunks <= 0 || chunkIndex < 0 || chunkIndex >= totalChunks) { Log.LogWarning((object)$"ReceiveAudioChunk: invalid packet tx={text3} chunkIndex={chunkIndex} totalChunks={totalChunks} dropping sender={num}:{text2} {DebugContext()}"); return; } string key = num + ":" + text3; if (!incomingAudioTransmissions.TryGetValue(key, out var value) || value == null) { value = new IncomingAudioTransmission { ExpectedChunkCount = totalChunks, ApplyFilter = false, SampleRate = senderSampleRate, SenderActor = num, SenderPlayerId = text, SenderName = text2, LastUpdatedAt = Time.time }; incomingAudioTransmissions[key] = value; DLog($"ReceiveAudioChunk: transmission start tx={text3} expectedChunks={totalChunks} sender={num}:{text2} playerId={text} {DebugContext()}"); } if (value.ExpectedChunkCount != totalChunks) { DLog($"ReceiveAudioChunk: resetting tx={text3} because totalChunks changed old={value.ExpectedChunkCount} new={totalChunks} sender={num}:{text2} {DebugContext()}"); value.ExpectedChunkCount = totalChunks; value.Chunks.Clear(); } value.ApplyFilter = false; value.SampleRate = senderSampleRate; value.SenderPlayerId = text; value.SenderName = text2; value.LastUpdatedAt = Time.time; while (value.Chunks.Count < value.ExpectedChunkCount) { value.Chunks.Add(null); } value.Chunks[chunkIndex] = chunk; DLog($"ReceiveAudioChunk: got tx={text3} chunk={chunkIndex + 1}/{value.ExpectedChunkCount} bytes={chunk.Length} sender={num}:{text2} playerId={text} {DebugContext()}"); int chunksDone = value.Chunks.Count((byte[] c) => c != null); PushVoiceLog(isIncoming: true, text3, text, text2, 0, isComplete: false, chunksDone, value.ExpectedChunkCount); if (!value.Chunks.Any((byte[] c) => c == null)) { byte[] array = CombineChunks(value.Chunks); CachedAudioEntry cachedAudioEntry = new CachedAudioEntry { AudioData = array, ApplyVoiceFilter = false, SampleRate = value.SampleRate, SourceActor = value.SenderActor, SourcePlayerId = value.SenderPlayerId, SourceName = value.SenderName, ReceivedAt = Time.time }; cachedAudio.Add(cachedAudioEntry); if (Plugin.configPersistAudioCache != null && Plugin.configPersistAudioCache.Value) { SaveAudioEntryToDisk(cachedAudioEntry); } DLog($"ReceiveAudioChunk: complete tx={text3} totalBytes={array.Length} source={cachedAudioEntry.SourceActor}:{cachedAudioEntry.SourceName} playerId={cachedAudioEntry.SourcePlayerId} cachedTotal={cachedAudio.Count} {DebugContext()}"); incomingAudioTransmissions.Remove(key); PushVoiceLog(isIncoming: true, text3, cachedAudioEntry.SourcePlayerId, cachedAudioEntry.SourceName, array.Length, isComplete: true, value.ExpectedChunkCount, value.ExpectedChunkCount); } } private void CleanupStaleIncomingTransmissions() { if (incomingAudioTransmissions.Count == 0) { return; } float now = Time.time; foreach (string item in (from kv in incomingAudioTransmissions where kv.Value == null || now - kv.Value.LastUpdatedAt > 30f select kv.Key).ToList()) { incomingAudioTransmissions.Remove(item); } } private void TryPlayRandomCachedAudio() { HashSet onlinePlayerIds = GetOnlinePlayerIds(); List list = cachedAudio.Where(delegate(CachedAudioEntry e) { if (e == null || e.AudioData == null || e.AudioData.Length == 0) { return false; } string item = ((!string.IsNullOrWhiteSpace(e.SourcePlayerId)) ? e.SourcePlayerId : ((e.SourceActor >= 0) ? $"actor_{e.SourceActor}" : "unknown")); return onlinePlayerIds.Contains(item); }).ToList(); List list2 = _customAudioClips.Where((CustomAudioEntry e) => (Object)(object)e?.Clip != (Object)null).ToList(); int num = list.Count + list2.Count; if (num == 0) { DLog(string.Format("TryPlayRandomCachedAudio: nothing to play — cached={0} onlineFiltered={1} custom={2} onlineIds=[{3}] {4}", cachedAudio.Count, list.Count, list2.Count, string.Join(",", onlinePlayerIds.OrderBy((string x) => x)), DebugContext())); return; } int num2 = Random.Range(0, num); if (num2 < list.Count) { CachedAudioEntry cachedAudioEntry = list[num2]; DLog($"TryPlayRandomCachedAudio: selected cached clip idx={num2} source={cachedAudioEntry.SourceActor}:{cachedAudioEntry.SourceName} playerId={cachedAudioEntry.SourcePlayerId} bytes={cachedAudioEntry.AudioData.Length} age={Time.time - cachedAudioEntry.ReceivedAt:F1}s {DebugContext()}"); PlayReceivedAudio(cachedAudioEntry.AudioData, cachedAudioEntry.SampleRate, cachedAudioEntry.SourceActor, cachedAudioEntry.SourcePlayerId, cachedAudioEntry.SourceName); } else { CustomAudioEntry customAudioEntry = list2[num2 - list.Count]; DLog($"TryPlayRandomCachedAudio: selected custom clip '{customAudioEntry.FileName}' length={customAudioEntry.Clip.length:F1}s {DebugContext()}"); PlayCustomAudioEntry(customAudioEntry); } } private void PlayReceivedAudio(byte[] audioData, int senderSampleRate, int sourceActor, string sourcePlayerId, string sourceName) { //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_0453: Unknown result type (might be due to invalid IL or missing references) //IL_052b: Unknown result type (might be due to invalid IL or missing references) //IL_0530: Unknown result type (might be due to invalid IL or missing references) //IL_055e: Unknown result type (might be due to invalid IL or missing references) bool flag = (Plugin.configPlaybackVoiceFilterEnabled == null || Plugin.configPlaybackVoiceFilterEnabled.Value) && Random.value > 0.9f; DLog($"PlayReceivedAudio start: bytes={audioData.Length} applyVoiceFilter={flag} senderSampleRate={senderSampleRate} source={sourceActor}:{sourceName} {DebugContext()}"); float[] array = ConvertByteArrayToFloatArray(audioData, flag, senderSampleRate); AudioClip val = AudioClip.Create("ReceivedClip", array.Length, 1, senderSampleRate, false); val.SetData(array, 0); if (Plugin.configDebugVerbose != null && Plugin.configDebugVerbose.Value) { float num = 0f; for (int i = 0; i < array.Length; i++) { num += array[i] * array[i]; } float num2 = Mathf.Sqrt(num / (float)Mathf.Max(1, array.Length)); DLog($"AudioClip created: samples={array.Length} lengthSec={val.length:F2} channels=1 frequency={senderSampleRate} rms={num2:F5} {DebugContext()}"); } List list = (from e in GetEnemiesList() where (Object)(object)e != (Object)null select e).ToList(); DLog($"Eligible enemies for playback: count={list.Count} filterEnabled={Plugin.configFilterEnabled.Value} {DebugContext()}"); List<(GameObject, GameObject)> list2 = BuildPlaybackTargets(list, warnOnMissingTarget: true); if (list2.Count == 0) { hudHasSelectedEnemyPos = false; nearestPlaybackTargetsHud.Clear(); nearestPlaybackTargetsHud.Add("No candidates"); DLog("No playback targets found, clip will not be played " + DebugContext()); return; } Vector3 position = ((Component)this).transform.position; float nearRadius = ((Plugin.configPlaybackNearRadius != null) ? ((float)Plugin.configPlaybackNearRadius.Value) : 25f); UpdateNearestPlaybackTargetsHud(list2, position, nearRadius); if (nearestPlaybackCandidatesHud.Count == 0) { DLog("No nearest HUD candidates after refresh, clip will not be played " + DebugContext()); return; } List list3 = nearestPlaybackCandidatesHud.Where((HudPlaybackCandidate c) => c != null && c.Distance <= nearRadius && !c.IsPlaying).ToList(); if (list3.Count == 0) { DLog($"Skipping playback: no candidates inside playback radius radius={nearRadius:F1} nearestCount={nearestPlaybackCandidatesHud.Count} {DebugContext()}"); return; } HudPlaybackCandidate hudPlaybackCandidate = list3[Random.Range(0, list3.Count)]; DLog($"Selecting random target inside playback radius: inRadiusCount={list3.Count} radius={nearRadius:F1} selected={hudPlaybackCandidate.EnemyName} dist={hudPlaybackCandidate.Distance:F1} pos={FormatHudVector(hudPlaybackCandidate.Position)} {DebugContext()}"); AudioSource orCreateReusableEnemyAudioSource = GetOrCreateReusableEnemyAudioSource(hudPlaybackCandidate.Enemy, hudPlaybackCandidate.Target, hudPlaybackCandidate.Position); if ((Object)(object)orCreateReusableEnemyAudioSource == (Object)null) { Log.LogWarning((object)("Playback skipped: failed to get reusable audio source enemy=" + hudPlaybackCandidate.EnemyName + " " + DebugContext())); return; } orCreateReusableEnemyAudioSource.clip = val; orCreateReusableEnemyAudioSource.volume = GetVolumeForPlayer(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(); DLog($"AudioSource.Play() called: isActiveAndEnabled={((Behaviour)orCreateReusableEnemyAudioSource).isActiveAndEnabled} mute={orCreateReusableEnemyAudioSource.mute} pitch={orCreateReusableEnemyAudioSource.pitch} volume={orCreateReusableEnemyAudioSource.volume:F2} spatialBlend={orCreateReusableEnemyAudioSource.spatialBlend} pos={FormatHudVector(((Component)orCreateReusableEnemyAudioSource).transform.position)} {DebugContext()}"); float value = Time.time + val.length + 0.1f; int playbackTargetKey = GetPlaybackTargetKey(hudPlaybackCandidate.Enemy, hudPlaybackCandidate.Target); if (playbackTargetKey != 0) { playbackBusyUntilByTargetKey[playbackTargetKey] = value; playbackStartedAtByTargetKey[playbackTargetKey] = Time.time; playbackClipLengthByTargetKey[playbackTargetKey] = val.length; } currentPlaybackEnemyName = hudPlaybackCandidate.EnemyName; currentPlaybackSourcePlayerId = ((!string.IsNullOrWhiteSpace(sourcePlayerId)) ? sourcePlayerId : ((sourceActor >= 0) ? $"actor_{sourceActor}" : "unknown")); hudTrackedEnemy = hudPlaybackCandidate.Enemy; hudTrackedTarget = hudPlaybackCandidate.Target; hudLastSelectedEnemyPos = hudPlaybackCandidate.Position; hudHasSelectedEnemyPos = true; currentPlaybackEndsAt = value; DLog($"Playback started on enemy={hudPlaybackCandidate.EnemyName} pos={FormatHudVector(hudPlaybackCandidate.Position)} volume={orCreateReusableEnemyAudioSource.volume:F2} clipLen={val.length:F2} source={sourceActor}:{sourceName} {DebugContext()}"); ((MonoBehaviour)this).StartCoroutine(ResetReusableAudioSourceAfterDelay(orCreateReusableEnemyAudioSource, val.length + 0.1f)); } private static AudioMixerGroup FindEnemyAudioMixerGroup(GameObject enemy, GameObject target) { GameObject val = (((Object)(object)target != (Object)null) ? target : enemy); if ((Object)(object)val != (Object)null) { AudioSource[] componentsInChildren = val.GetComponentsInChildren(true); foreach (AudioSource val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null && (Object)(object)val2.outputAudioMixerGroup != (Object)null) { return val2.outputAudioMixerGroup; } } } return null; } private int GetPlaybackTargetKey(GameObject enemy, GameObject target) { if ((Object)(object)target != (Object)null) { return ((Object)target).GetInstanceID(); } if ((Object)(object)enemy != (Object)null) { return ((Object)enemy).GetInstanceID(); } return 0; } private void CleanupFinishedPlaybackBusyFlags() { if (playbackBusyUntilByTargetKey.Count == 0) { return; } float now = Time.time; foreach (int item in (from kv in playbackBusyUntilByTargetKey where kv.Value <= now select kv.Key).ToList()) { playbackBusyUntilByTargetKey.Remove(item); playbackStartedAtByTargetKey.Remove(item); playbackClipLengthByTargetKey.Remove(item); } } [IteratorStateMachine(typeof(d__243))] private IEnumerator FollowAudioSourceDuringPlayback(AudioSource source, GameObject enemy, GameObject target, float duration) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__243(0) { <>4__this = this, source = source, enemy = enemy, target = target, duration = duration }; } private AudioSource GetOrCreateReusableEnemyAudioSource(GameObject enemy, GameObject target, Vector3 position) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_0088: Unknown result type (might be due to invalid IL or missing references) Transform enemyAudioAnchor = GetEnemyAudioAnchor(enemy); if ((Object)(object)enemyAudioAnchor == (Object)null) { return null; } int instanceID = ((Object)((Component)enemyAudioAnchor).gameObject).GetInstanceID(); if (reusableEnemyAudioSources.TryGetValue(instanceID, out var value) && (Object)(object)value != (Object)null && (Object)(object)((Component)value).gameObject != (Object)null) { return value; } Transform val = enemyAudioAnchor.Find("MimicsAudio"); GameObject val2; if ((Object)(object)val != (Object)null) { val2 = ((Component)val).gameObject; } else { val2 = new GameObject("MimicsAudio"); val2.transform.SetParent(enemyAudioAnchor, false); val2.transform.localPosition = Vector3.zero; } value = val2.GetComponent() ?? val2.AddComponent(); reusableEnemyAudioSources[instanceID] = value; return value; } private void RefreshHudTargetsSnapshot() { //IL_0086: 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_00a8: 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_00de: Unknown result type (might be due to invalid IL or missing references) List enemies = (from e in GetEnemiesList() where (Object)(object)e != (Object)null select e).ToList(); List<(GameObject, GameObject)> list = BuildPlaybackTargets(enemies, warnOnMissingTarget: false); if (list.Count == 0) { nearestPlaybackTargetsHud.Clear(); nearestPlaybackTargetsHud.Add("No candidates"); if ((Object)(object)hudTrackedEnemy == (Object)null && (Object)(object)hudTrackedTarget == (Object)null) { hudHasSelectedEnemyPos = false; } return; } Vector3 position = ((Component)this).transform.position; float nearRadius = ((Plugin.configPlaybackNearRadius != null) ? ((float)Plugin.configPlaybackNearRadius.Value) : 25f); UpdateNearestPlaybackTargetsHud(list, position, nearRadius); if ((Object)(object)hudTrackedEnemy != (Object)null || (Object)(object)hudTrackedTarget != (Object)null) { hudLastSelectedEnemyPos = GetEnemyDistancePosition(hudTrackedEnemy, hudTrackedTarget); hudHasSelectedEnemyPos = true; } } private List<(GameObject enemy, GameObject target)> BuildPlaybackTargets(IEnumerable enemies, bool warnOnMissingTarget) { List<(GameObject, GameObject)> list = new List<(GameObject, GameObject)>(); foreach (GameObject enemy in enemies) { if ((Object)(object)enemy == (Object)null) { continue; } if (Plugin.configFilterEnabled.Value) { string text = ((Object)enemy).name.Replace("(Clone)", string.Empty).Trim(); if (!IsEnemyEnabledInFilter(text)) { DLog("Enemy skipped by filter: enemy=" + ((Object)enemy).name + " normalized=" + text + " " + DebugContext()); continue; } } GameObject enemyAudioTarget = GetEnemyAudioTarget(enemy); if ((Object)(object)enemyAudioTarget == (Object)null) { if (warnOnMissingTarget) { Log.LogWarning((object)("Enemy audio target missing: enemy=" + ((Object)enemy).name + " " + DebugContext())); } } else { list.Add((enemy, enemyAudioTarget)); } } return list; } private void UpdateNearestPlaybackTargetsHud(List<(GameObject enemy, GameObject target)> playbackTargets, Vector3 listenerPos, float nearRadius) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: 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) CleanupFinishedPlaybackBusyFlags(); nearestPlaybackTargetsHud.Clear(); nearestPlaybackCandidatesHud.Clear(); foreach (var item in (from p in playbackTargets select new { Enemy = p.enemy, Target = p.target, EnemyName = NormalizeEnemyName(((Object)(object)p.enemy != (Object)null) ? ((Object)p.enemy).name : "Unknown"), Position = GetEnemyDistancePosition(p.enemy, p.target), Distance = Vector3.Distance(GetEnemyDistancePosition(p.enemy, p.target), listenerPos), TargetKey = GetPlaybackTargetKey(p.enemy, p.target) } into x orderby x.Distance select x).Take(5).ToList()) { float value = 0f; bool flag = item.TargetKey != 0 && playbackBusyUntilByTargetKey.TryGetValue(item.TargetKey, out value) && value > Time.time; string text = ((item.Distance <= nearRadius) ? "*" : "-"); string text2 = string.Empty; if (flag) { float value2; float num = (playbackStartedAtByTargetKey.TryGetValue(item.TargetKey, out value2) ? value2 : (value - 0.1f)); float value3; float num2 = (playbackClipLengthByTargetKey.TryGetValue(item.TargetKey, out value3) ? value3 : Mathf.Max(0f, value - num - 0.1f)); float num3 = Mathf.Clamp(Time.time - num, 0f, num2); text2 = $" play={num3:F1}/{num2:F1}s"; } nearestPlaybackTargetsHud.Add($"{text} {item.EnemyName} ({item.Distance:F1}m) pos={FormatHudVector(item.Position)}{text2}"); nearestPlaybackCandidatesHud.Add(new HudPlaybackCandidate { Enemy = item.Enemy, Target = item.Target, EnemyName = item.EnemyName, Position = item.Position, Distance = item.Distance, IsPlaying = flag, PlaybackEndsAt = (flag ? value : 0f) }); } if (nearestPlaybackTargetsHud.Count == 0) { nearestPlaybackTargetsHud.Add("No candidates"); } } [IteratorStateMachine(typeof(d__248))] private IEnumerator ResetReusableAudioSourceAfterDelay(AudioSource source, float delay) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__248(0) { source = source, delay = delay }; } private bool IsEnemyEnabledInFilter(string enemyName) { if (filter == null || filter.Count == 0) { return true; } if (filter.TryGetValue(enemyName, out var value)) { return value; } string key = "Enemy - " + enemyName; if (filter.TryGetValue(key, out value)) { return value; } string key2 = enemyName.Replace("Enemy - ", string.Empty).Trim(); if (filter.TryGetValue(key2, out value)) { return value; } return true; } private Transform GetEnemyAudioAnchor(GameObject enemy) { EnemyParent component = enemy.GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)component.Enemy != (Object)null) { Enemy enemy2 = component.Enemy; if ((Object)(object)enemy2.CenterTransform != (Object)null) { return enemy2.CenterTransform; } if (enemy2.HasVision && (Object)(object)enemy2.Vision != (Object)null && (Object)(object)enemy2.Vision.VisionTransform != (Object)null) { return enemy2.Vision.VisionTransform; } return ((Component)enemy2).transform; } Transform val = enemy.transform.Find("Enable/Controller") ?? enemy.transform.Find("Controller"); if (!((Object)(object)val != (Object)null)) { return enemy.transform; } return val; } private GameObject GetEnemyAudioTarget(GameObject enemy) { return ((Component)GetEnemyAudioAnchor(enemy)).gameObject; } private Vector3 GetEnemyDistancePosition(GameObject enemy, GameObject fallbackTarget) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)enemy != (Object)null) { EnemyParent componentInChildren = enemy.GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { if (TryGetRuntimeEnemyObject(componentInChildren, out var runtimeEnemy) && TryGetRuntimeEnemyPosition(runtimeEnemy, out var position)) { return position; } return ((Component)componentInChildren).transform.position; } Component[] componentsInChildren = enemy.GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && string.Equals(((object)val).GetType().Name, "Animator", StringComparison.OrdinalIgnoreCase)) { return val.transform.position; } } } if ((Object)(object)fallbackTarget != (Object)null) { return fallbackTarget.transform.position; } if (!((Object)(object)enemy != (Object)null)) { return Vector3.zero; } return enemy.transform.position; } private static bool TryGetRuntimeEnemyPosition(object runtimeEnemy, out Vector3 position) { //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_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_00a2: 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_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) position = Vector3.zero; if (runtimeEnemy == null) { return false; } Component val = (Component)((runtimeEnemy is Component) ? runtimeEnemy : null); if (val != null) { position = val.transform.position; return true; } Type type = runtimeEnemy.GetType(); PropertyInfo propertyInfo = type.GetProperty("CenterTransform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetProperty("centerTransform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetProperty("Transform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetProperty("transform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (propertyInfo != null && propertyInfo.CanRead) { object? value = propertyInfo.GetValue(runtimeEnemy, null); Transform val2 = (Transform)((value is Transform) ? value : null); if ((Object)(object)val2 != (Object)null) { position = val2.position; return true; } } FieldInfo fieldInfo = type.GetField("CenterTransform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetField("centerTransform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetField("Transform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetField("transform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo != null) { object? value2 = fieldInfo.GetValue(runtimeEnemy); Transform val3 = (Transform)((value2 is Transform) ? value2 : null); if ((Object)(object)val3 != (Object)null) { position = val3.position; return true; } } return false; } private void SetEnemyFilter() { filter.Clear(); foreach (KeyValuePair> enemyConfigEntry in Plugin.enemyConfigEntries) { filter[enemyConfigEntry.Key ?? string.Empty] = enemyConfigEntry.Value.Value; } DLog($"Enemy filter loaded: entries={filter.Count} enabled={filter.Count((KeyValuePair kv) => kv.Value)} disabled={filter.Count((KeyValuePair kv) => !kv.Value)} {DebugContext()}"); } private static string NormalizeEnemyName(string value) { if (string.IsNullOrWhiteSpace(value)) { return string.Empty; } return value.Replace("(Clone)", string.Empty).Replace("Enemy - ", string.Empty).Trim(); } private static bool TryGetRuntimeEnemyObject(EnemyParent enemyParent, out object runtimeEnemy) { runtimeEnemy = null; if ((Object)(object)enemyParent == (Object)null) { return false; } Type type = ((object)enemyParent).GetType(); PropertyInfo propertyInfo = type.GetProperty("Enemy", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetProperty("enemy", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (propertyInfo != null && propertyInfo.CanRead) { runtimeEnemy = propertyInfo.GetValue(enemyParent, null); if (runtimeEnemy != null) { return true; } } FieldInfo fieldInfo = type.GetField("Enemy", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetField("enemy", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo != null) { runtimeEnemy = fieldInfo.GetValue(enemyParent); } return runtimeEnemy != null; } private static string GetEnemyIdentityName(GameObject enemy, EnemyParent enemyParent) { string text = (((Object)(object)enemyParent != (Object)null) ? enemyParent.enemyName : null); if (!string.IsNullOrWhiteSpace(text)) { return text; } if (!((Object)(object)enemy != (Object)null)) { return string.Empty; } return ((Object)enemy).name; } private bool IsEnemyInDespawnState(GameObject enemy) { if ((Object)(object)enemy == (Object)null) { return true; } EnemyParent componentInChildren = enemy.GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null && TryGetRuntimeEnemyObject(componentInChildren, out var runtimeEnemy)) { object obj = null; Type type = runtimeEnemy.GetType(); PropertyInfo propertyInfo = type.GetProperty("CurrentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetProperty("currentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (propertyInfo != null && propertyInfo.CanRead) { obj = propertyInfo.GetValue(runtimeEnemy, null); } else { FieldInfo fieldInfo = type.GetField("CurrentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetField("currentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo != null) { obj = fieldInfo.GetValue(runtimeEnemy); } } if (obj != null) { string text = obj.ToString(); if (!string.IsNullOrWhiteSpace(text) && text.IndexOf("Despawn", StringComparison.OrdinalIgnoreCase) >= 0) { DLog("Skipping despawned enemy via EnemyParent object=" + ((Object)enemy).name + " enemyName=" + componentInChildren.enemyName + " state=" + text + " " + DebugContext()); return true; } } } Component[] componentsInChildren = enemy.GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } Type type2 = ((object)val).GetType(); object obj2 = null; PropertyInfo propertyInfo2 = type2.GetProperty("CurrentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type2.GetProperty("currentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (propertyInfo2 != null && propertyInfo2.CanRead) { obj2 = propertyInfo2.GetValue(val, null); } else { FieldInfo fieldInfo2 = type2.GetField("CurrentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type2.GetField("currentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo2 != null) { obj2 = fieldInfo2.GetValue(val); } } if (obj2 != null) { string text2 = obj2.ToString(); if (!string.IsNullOrWhiteSpace(text2) && text2.IndexOf("Despawn", StringComparison.OrdinalIgnoreCase) >= 0) { DLog("Skipping despawned enemy object=" + ((Object)enemy).name + " state=" + text2 + " component=" + type2.Name + " " + DebugContext()); return true; } } } return false; } private List GetEnemiesList() { List list = new List(); IReadOnlyCollection knownEnemyNames = EnemyDirectorStartPatch.KnownEnemyNames; HashSet hashSet = ((knownEnemyNames != null) ? new HashSet(from n in knownEnemyNames.Select(NormalizeEnemyName) where !string.IsNullOrWhiteSpace(n) select n) : new HashSet()); EnemyParent[] array = Object.FindObjectsByType((FindObjectsSortMode)0); if (array == null || array.Length == 0) { DLog("GetEnemiesList: no EnemyParent objects found in scene " + DebugContext()); return list; } EnemyParent[] array2 = array; foreach (EnemyParent val in array2) { GameObject val2 = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null); if ((Object)(object)val2 == (Object)null) { continue; } if (!TryGetRuntimeEnemyObject(val, out var _)) { DLog("GetEnemiesList: skipping object without runtime Enemy reference " + ((Object)val2).name + " enemyName=" + val.enemyName); continue; } string text = NormalizeEnemyName(GetEnemyIdentityName(val2, val)); string text2 = NormalizeEnemyName(((Object)val2).name); if (hashSet.Count != 0 && !hashSet.Contains(text) && !hashSet.Contains(text2)) { DLog("GetEnemiesList: skipping non-registered enemy object=" + ((Object)val2).name + " identity=" + text + " objectName=" + text2); } else if (!IsEnemyInDespawnState(val2)) { list.Add(val2); } } DLog($"GetEnemiesList: found {list.Count} enemies in scene {DebugContext()}"); return list; } private void StartRecording() { if (!isRecording) { audioBuffer = new float[sampleRate * 30]; preSpeechBuffer = new float[Mathf.Max(1, (int)((float)sampleRate * 0.25f))]; bufferPosition = 0; preSpeechWritePos = 0; preSpeechCount = 0; postSpeechSamplesRemaining = 0; pendingSilenceSamples = 0; isRecording = true; capturingSpeech = false; fileSaved = false; DLog($"StartRecording: bufferSamples={audioBuffer.Length} (~{(float)audioBuffer.Length / (float)sampleRate:F2}s) {DebugContext()}"); } } private void PushToPreSpeechBuffer(short[] voiceData) { if (preSpeechBuffer == null || preSpeechBuffer.Length == 0 || voiceData == null || voiceData.Length == 0) { return; } for (int i = 0; i < voiceData.Length; i++) { preSpeechBuffer[preSpeechWritePos] = (float)voiceData[i] / 32768f; preSpeechWritePos = (preSpeechWritePos + 1) % preSpeechBuffer.Length; if (preSpeechCount < preSpeechBuffer.Length) { preSpeechCount++; } } } private void PrependPreSpeechToCapture() { if (preSpeechBuffer == null || preSpeechCount <= 0 || audioBuffer == null) { return; } int num = audioBuffer.Length - bufferPosition; int num2 = Mathf.Min(preSpeechCount, num); if (num2 > 0) { int num3 = (preSpeechWritePos - preSpeechCount + preSpeechBuffer.Length) % preSpeechBuffer.Length; for (int i = 0; i < num2; i++) { int num4 = (num3 + i) % preSpeechBuffer.Length; audioBuffer[bufferPosition + i] = preSpeechBuffer[num4]; } bufferPosition += num2; } } private int AppendVoiceDataToCapture(short[] voiceData) { if (voiceData == null || voiceData.Length == 0 || audioBuffer == null || bufferPosition >= audioBuffer.Length) { return 0; } int num = Mathf.Min(voiceData.Length, audioBuffer.Length - bufferPosition); for (int i = 0; i < num; i++) { audioBuffer[bufferPosition + i] = (float)voiceData[i] / 32768f; } bufferPosition += num; return num; } private int AppendSilenceToCapture(int sampleCount) { if (sampleCount <= 0 || audioBuffer == null || bufferPosition >= audioBuffer.Length) { return 0; } int num = Mathf.Min(sampleCount, audioBuffer.Length - bufferPosition); for (int i = 0; i < num; i++) { audioBuffer[bufferPosition + i] = 0f; } bufferPosition += num; return num; } private bool IsMicrophoneMuted() { if ((Object)(object)playerVoiceChat == (Object)null) { return false; } if (!_recorderReflectionDone) { _recorderReflectionDone = true; _recorderField = typeof(PlayerVoiceChat).GetField("recorder", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (_recorderField != null) { object value = _recorderField.GetValue(playerVoiceChat); if (value != null) { _recorderTransmitProp = value.GetType().GetProperty("TransmitEnabled", BindingFlags.Instance | BindingFlags.Public); } } DLog($"IsMicrophoneMuted init: recorderField={_recorderField != null} transmitProp={_recorderTransmitProp != null} {DebugContext()}"); } if (_recorderField == null || _recorderTransmitProp == null) { return false; } try { object value2 = _recorderField.GetValue(playerVoiceChat); if (value2 == null) { return false; } return !(bool)_recorderTransmitProp.GetValue(value2); } catch { return false; } } private void AbortCapture() { if (capturingSpeech) { DLog($"AbortCapture: discarding bufferedSamples={bufferPosition} {DebugContext()}"); capturingSpeech = false; bufferPosition = 0; fileSaved = false; vadHoldUntil = 0f; pendingSilenceSamples = 0; postSpeechSamplesRemaining = 0; } } public void ProcessVoiceData(short[] voiceData) { if (!isRecording || !photonView.IsMine) { return; } if (IsMicrophoneMuted()) { AbortCapture(); return; } PushToPreSpeechBuffer(voiceData); if (ComputeRmsEnergy(voiceData) > 0.012f) { vadHoldUntil = Time.time + 0.5f; } bool flag = Time.time < vadHoldUntil; if (flag && !capturingSpeech) { capturingSpeech = true; bufferPosition = 0; PrependPreSpeechToCapture(); pendingSilenceSamples = 0; postSpeechSamplesRemaining = 0; Player localPlayer = PhotonNetwork.LocalPlayer; string playerPersistentId = GetPlayerPersistentId(localPlayer); string playerDisplayName = GetPlayerDisplayName(localPlayer); Log.LogInfo((object)("Started recording player [" + playerDisplayName + "](" + playerPersistentId + ") " + DebugContext())); DLog($"Speech detected: begin capture voiceDataSamples={voiceData.Length} {DebugContext()}"); } if (capturingSpeech) { int num = 0; if (flag) { pendingSilenceSamples = 0; num = AppendVoiceDataToCapture(voiceData); } else if (bufferPosition > sampleRate / 4 && !fileSaved) { DLog($"Speech ended (VAD hold expired): finalize bufferedSamples={bufferPosition} {DebugContext()}"); FinalizeCaptureAndSend(bufferPosition); return; } if (bufferPosition % (sampleRate / 2) < num) { DLog($"Capture progress: bufferPosition={bufferPosition}/{audioBuffer.Length} copiedNow={num} {DebugContext()}"); } if (bufferPosition >= audioBuffer.Length && !fileSaved) { DLog($"Capture finished by full buffer: totalSamples={audioBuffer.Length} {DebugContext()}"); FinalizeCaptureAndSend(audioBuffer.Length); } } } private void FinalizeCaptureAndSend(int usedSamples) { if (fileSaved || usedSamples <= 0) { return; } float[] array = new float[usedSamples]; Array.Copy(audioBuffer, array, usedSamples); isRecording = false; capturingSpeech = false; fileSaved = true; byte[] array2 = ConvertFloatArrayToByteArray(array); float num = ((sampleRate > 0) ? ((float)usedSamples / (float)sampleRate) : 0f); Player localPlayer = PhotonNetwork.LocalPlayer; string playerPersistentId = GetPlayerPersistentId(localPlayer); string playerDisplayName = GetPlayerDisplayName(localPlayer); Log.LogInfo((object)$"Finished recording player [{playerDisplayName}]({playerPersistentId}) duration={num:F2}s bytes={array2.Length} {DebugContext()}"); DLog($"FinalizeCaptureAndSend: usedSamples={usedSamples} bytes={array2.Length} {DebugContext()}"); if (_isSendingAudio) { if (_sendQueue.Count >= 3) { byte[] array3 = _sendQueue.Dequeue(); Log.LogWarning((object)$"SendQueue full (depth={3}): dropped oldest entry ({array3.Length} bytes) {DebugContext()}"); } _sendQueue.Enqueue(array2); Log.LogInfo((object)$"SendQueue: enqueued {array2.Length} bytes (queued={_sendQueue.Count}) {DebugContext()}"); } else { ((MonoBehaviour)this).StartCoroutine(SendAudioInChunks(array2)); } StartRecording(); } private static float ComputeRmsEnergy(short[] samples) { if (samples == null || samples.Length == 0) { return 0f; } double num = 0.0; for (int i = 0; i < samples.Length; i++) { double num2 = (double)samples[i] / 32768.0; num += num2 * num2; } return (float)Math.Sqrt(num / (double)samples.Length); } [IteratorStateMachine(typeof(d__276))] private IEnumerator SendAudioInChunks(byte[] audioData) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__276(0) { <>4__this = this, audioData = audioData }; } internal static void OnMimicsAudioPacketReceived(MimicsAudioPacket packet) { TFS_Mimics instance = Instance; if (!((Object)(object)instance == (Object)null)) { Player val = PhotonNetwork.PlayerList?.FirstOrDefault((Func)((Player p) => p.ActorNumber == packet.SenderActorNumber)); if (val != null) { instance.ReceiveAudioChunkInternal(packet.ChunkData, packet.ChunkIndex, packet.TotalChunks, applyFilter: false, packet.SampleRate, packet.TransmissionId, val); } } } } internal static class OverlaySettings { public static bool ShowName = true; public static bool ShowHp = true; public static bool ShowState = true; public static bool ShowDistance = true; public static bool ShowPlaying = true; public static bool ShowAudioMarker = true; } internal sealed class MimicsEnemyOverlay : MonoBehaviour { private static Font s_font; private static Sprite s_whiteSprite; private static readonly Color CAccent = new Color(0.35f, 0.65f, 1f); private static readonly Color CBgDark = new Color(0.06f, 0.08f, 0.12f, 0.88f); private static readonly Color CBgPanel = new Color(0.1f, 0.13f, 0.18f, 0.72f); private static readonly Color CGreen = new Color(0.3f, 0.85f, 0.4f); private static readonly Color CYellow = new Color(1f, 0.8f, 0.2f); private static readonly Color CRed = new Color(0.9f, 0.25f, 0.25f); private static readonly Color CText = new Color(0.9f, 0.92f, 0.95f); private static readonly Color CDim = new Color(0.55f, 0.6f, 0.65f); private const float PanelW = 160f; private const float PanelH = 82f; private const float WorldScale = 0.012f; private const float HeadOffset = 0.8f; private const float DataHz = 0.2f; private EnemyParent _enemyParent; private Transform _playerTransform; private Canvas _canvas; private RectTransform _canvasRect; private Image _hpFill; private Text _nameText; private Text _hpText; private Text _stateText; private Text _distText; private Image _playingBg; private Text _playingText; private float _nextRefresh; private float _smoothHp = 1f; public bool IsPlayingAudio { get; set; } private static Font GetFont() { if ((Object)(object)s_font == (Object)null) { s_font = Resources.GetBuiltinResource("Arial.ttf"); } return s_font; } 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_whiteSprite != (Object)null) { return s_whiteSprite; } Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false); val.SetPixel(0, 0, Color.white); val.Apply(); s_whiteSprite = Sprite.Create(val, new Rect(0f, 0f, 1f, 1f), Vector2.one * 0.5f); return s_whiteSprite; } public void Init(EnemyParent enemyParent, Transform playerTransform) { _enemyParent = enemyParent; _playerTransform = playerTransform; BuildUI(); } private void Update() { if ((Object)(object)_enemyParent == (Object)null) { ((Component)this).gameObject.SetActive(false); } else if (!(Time.time < _nextRefresh)) { _nextRefresh = Time.time + 0.2f; RefreshData(); } } private Transform GetAnchor() { if ((Object)(object)_enemyParent == (Object)null || (Object)(object)_enemyParent.Enemy == (Object)null) { return null; } Enemy enemy = _enemyParent.Enemy; if ((Object)(object)enemy.CenterTransform != (Object)null) { return enemy.CenterTransform; } if (enemy.HasVision && (Object)(object)enemy.Vision != (Object)null && (Object)(object)enemy.Vision.VisionTransform != (Object)null) { return enemy.Vision.VisionTransform; } return ((Component)enemy).transform; } private void LateUpdate() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_canvas == (Object)null || (Object)(object)_enemyParent == (Object)null) { return; } Camera main = Camera.main; if (!((Object)(object)main == (Object)null)) { Transform anchor = GetAnchor(); if (!((Object)(object)anchor == (Object)null)) { ((Transform)_canvasRect).position = anchor.position + Vector3.up * 0.8f; ((Transform)_canvasRect).rotation = ((Component)main).transform.rotation; } } } public void SetVisible(bool visible) { if ((Object)(object)_canvas != (Object)null) { ((Component)_canvas).gameObject.SetActive(visible); } } 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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Expected O, but got Unknown //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("_MimicsOverlayCanvas"); val.transform.SetParent(((Component)this).transform, false); _canvas = val.AddComponent(); _canvas.renderMode = (RenderMode)2; _canvas.sortingOrder = 100; _canvasRect = val.GetComponent(); _canvasRect.sizeDelta = new Vector2(160f, 82f); ((Transform)_canvasRect).localScale = Vector3.one * 0.012f; val.AddComponent().dynamicPixelsPerUnit = 10f; MkImg(val.transform, "bg", CBgDark, 0f, 1f, 0f, 1f); MkImg(val.transform, "border_top", CAccent, 0f, 1f, 0.965f, 1f); _nameText = MkText(val.transform, "name", 12, (FontStyle)1, CAccent); SetAnch(((Graphic)_nameText).rectTransform, 0.05f, 0.85f, 0.78f, 1f); _nameText.alignment = (TextAnchor)3; Image val2 = MkImg(val.transform, "hp_bg", new Color(0.08f, 0.1f, 0.15f), 0.05f, 0.95f, 0.53f, 0.73f); GameObject val3 = new GameObject("hp_fill"); val3.transform.SetParent(((Component)val2).transform, false); _hpFill = val3.AddComponent(); _hpFill.sprite = GetSprite(); _hpFill.type = (Type)3; _hpFill.fillMethod = (FillMethod)0; _hpFill.fillAmount = 1f; ((Graphic)_hpFill).color = CGreen; RectTransform component = val3.GetComponent(); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; Vector2 offsetMin = (component.offsetMax = Vector2.zero); component.offsetMin = offsetMin; _hpText = MkText(val.transform, "hp_text", 9, (FontStyle)0, CText); SetAnch(((Graphic)_hpText).rectTransform, 0.05f, 0.95f, 0.53f, 0.73f); _hpText.alignment = (TextAnchor)4; _stateText = MkText(val.transform, "state", 9, (FontStyle)0, CDim); SetAnch(((Graphic)_stateText).rectTransform, 0.05f, 0.58f, 0.29f, 0.51f); _stateText.alignment = (TextAnchor)3; _distText = MkText(val.transform, "dist", 9, (FontStyle)0, CDim); SetAnch(((Graphic)_distText).rectTransform, 0.58f, 0.95f, 0.29f, 0.51f); _distText.alignment = (TextAnchor)5; _playingBg = MkImg(val.transform, "playing_bg", new Color(0f, 0f, 0f, 0f), 0f, 1f, 0f, 0.26f); _playingText = MkText(val.transform, "playing_text", 10, (FontStyle)1, new Color(0f, 0f, 0f, 0f)); SetAnch(((Graphic)_playingText).rectTransform, 0.04f, 0.96f, 0f, 0.26f); _playingText.text = "▶ MIMICS PLAYING"; _playingText.alignment = (TextAnchor)4; } private void RefreshData() { //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: 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_00fb: 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_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0357: Unknown result type (might be due to invalid IL or missing references) //IL_0350: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_enemyParent == (Object)null) { return; } if ((Object)(object)_nameText != (Object)null) { ((Component)_nameText).gameObject.SetActive(OverlaySettings.ShowName); if (OverlaySettings.ShowName) { string text = _enemyParent.enemyName; if (string.IsNullOrWhiteSpace(text)) { text = ((Object)((Component)_enemyParent).gameObject).name; } _nameText.text = text; } } TryGetHealth(out var current, out var max); bool showHp = OverlaySettings.ShowHp; if ((Object)(object)_hpFill != (Object)null) { ((Component)((Component)_hpFill).transform.parent).gameObject.SetActive(showHp); if (showHp) { if (max > 0) { float num = Mathf.Clamp01((float)current / (float)max); _smoothHp = Mathf.Lerp(_smoothHp, num, 0.35f); _hpFill.fillAmount = _smoothHp; ((Graphic)_hpFill).color = ((_smoothHp > 0.5f) ? Color.Lerp(CYellow, CGreen, (_smoothHp - 0.5f) * 2f) : Color.Lerp(CRed, CYellow, _smoothHp * 2f)); } else { _hpFill.fillAmount = 1f; ((Graphic)_hpFill).color = CDim; } } } if ((Object)(object)_hpText != (Object)null) { ((Component)_hpText).gameObject.SetActive(showHp); if (showHp) { _hpText.text = ((max > 0) ? $"{current} / {max} HP" : "HP: —"); } } if ((Object)(object)_stateText != (Object)null) { ((Component)_stateText).gameObject.SetActive(OverlaySettings.ShowState); if (OverlaySettings.ShowState) { _stateText.text = (((Object)(object)_enemyParent.Enemy != (Object)null) ? ((object)(EnemyState)(ref _enemyParent.Enemy.CurrentState)).ToString() : "—"); } } if ((Object)(object)_distText != (Object)null) { ((Component)_distText).gameObject.SetActive(OverlaySettings.ShowDistance); if (OverlaySettings.ShowDistance && (Object)(object)_playerTransform != (Object)null) { Transform anchor = GetAnchor(); Vector3 val = (((Object)(object)anchor != (Object)null) ? anchor.position : ((Component)_enemyParent).transform.position); _distText.text = $"{Vector3.Distance(val, _playerTransform.position):F1} m"; } } if ((Object)(object)_playingBg != (Object)null && (Object)(object)_playingText != (Object)null) { bool flag = OverlaySettings.ShowPlaying && IsPlayingAudio; ((Graphic)_playingBg).color = (flag ? new Color(CGreen.r, CGreen.g, CGreen.b, 0.18f) : new Color(0f, 0f, 0f, 0f)); ((Graphic)_playingText).color = (Color)(flag ? CGreen : new Color(0f, 0f, 0f, 0f)); } if ((Object)(object)_canvas != (Object)null) { bool active = OverlaySettings.ShowName || OverlaySettings.ShowHp || OverlaySettings.ShowState || OverlaySettings.ShowDistance || OverlaySettings.ShowPlaying; ((Component)_canvas).gameObject.SetActive(active); } } private void TryGetHealth(out int current, out int max) { current = (max = -1); if (!((Object)(object)_enemyParent == (Object)null) && !((Object)(object)_enemyParent.Enemy == (Object)null)) { EnemyHealth health = _enemyParent.Enemy.Health; if (!((Object)(object)health == (Object)null)) { current = health.healthCurrent; max = health.health; } } } 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(); obj.sprite = GetSprite(); ((Graphic)obj).color = color; SetAnch(val.GetComponent(), 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(); 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(true); foreach (Graphic obj in componentsInChildren) { Material val = new Material(obj.defaultMaterial); val.SetInt("unity_GUIZTestMode", 8); obj.material = val; } } } public class MimicsAudioPacket : NetworkPacket { public byte[] ChunkData { get; set; } public int ChunkIndex { get; set; } public int TotalChunks { get; set; } public int SampleRate { get; set; } public string TransmissionId { get; set; } public int SenderActorNumber { get; set; } protected override void WriteData(SocketMessage socketMessage) { socketMessage.Write(SenderActorNumber); socketMessage.Write(TransmissionId); socketMessage.Write(ChunkIndex); socketMessage.Write(TotalChunks); socketMessage.Write(SampleRate); socketMessage.Write(ChunkData); } protected override void ReadData(SocketMessage socketMessage) { SenderActorNumber = socketMessage.Read(); TransmissionId = socketMessage.Read(); ChunkIndex = socketMessage.Read(); TotalChunks = socketMessage.Read(); SampleRate = socketMessage.Read(); ChunkData = socketMessage.Read(); } } } namespace TFS_Mimics.patches { [HarmonyPatch(typeof(EnemyDirector))] internal class EnemyDirectorStartPatch { private static readonly ManualLogSource Log = Logger.CreateLogSource("TFS_Mimics"); private static HashSet filterEnemies = new HashSet(); private static bool setupComplete; private static ConfigFile configFile; public static IReadOnlyCollection KnownEnemyNames => filterEnemies; private static void DLog(string message) { if (Plugin.configDebugVerbose != null && Plugin.configDebugVerbose.Value) { Log.LogInfo((object)message); } } public static void Initialize(ConfigFile config) { configFile = config; } [HarmonyPatch("Start")] [HarmonyPostfix] public static void SetupEnemies(EnemyDirector __instance) { if (setupComplete || configFile == null) { return; } List[] obj = new List[3] { __instance.enemiesDifficulty1, __instance.enemiesDifficulty2, __instance.enemiesDifficulty3 }; filterEnemies = new HashSet(); List[] array = obj; foreach (List list in array) { if (list == null) { continue; } foreach (EnemySetup item2 in list) { if ((Object)(object)item2 == (Object)null || item2.spawnObjects == null || item2.spawnObjects.Count == 0) { continue; } PrefabRef val = item2.spawnObjects[0]; if (val == null) { continue; } string prefabName = ((PrefabRef)(object)val).PrefabName; if (!string.IsNullOrWhiteSpace(prefabName)) { string item = prefabName; if (prefabName.Contains("Director") && item2.spawnObjects.Count > 1 && item2.spawnObjects[1] != null && !string.IsNullOrWhiteSpace(((PrefabRef)(object)item2.spawnObjects[1]).PrefabName)) { item = ((PrefabRef)(object)item2.spawnObjects[1]).PrefabName; } filterEnemies.Add(item); } } } foreach (string filterEnemy in filterEnemies) { Plugin.enemyConfigEntries[filterEnemy] = configFile.Bind("Enemies", filterEnemy, true, "Enables/disables mimic for " + filterEnemy); } List list2 = (from n in filterEnemies where !string.IsNullOrWhiteSpace(n) orderby n select n).ToList(); Log.LogInfo((object)$"Registered enemy entities: count={list2.Count}"); Log.LogInfo((object)("Registered enemy entities list: " + string.Join(", ", list2))); if (Plugin.configDebugVerbose != null && Plugin.configDebugVerbose.Value) { foreach (string item3 in list2) { Log.LogInfo((object)("Registered enemy entity -> " + item3)); } } setupComplete = true; DLog("Enemy filter config initialized."); } } [HarmonyPatch(typeof(LocalVoiceFramed), "PushDataAsync")] internal class LocalVoiceFramedPatch { [HarmonyPrefix] private static void Prefix(short[] buf) { VoiceDataBus.Dispatch(buf); } } internal static class VoiceDataBus { private static TFS_Mimics _localMimics; internal static TFS_Mimics LocalMimics { get { return _localMimics; } set { _localMimics = value; } } internal static void Dispatch(short[] voiceData) { TFS_Mimics localMimics = _localMimics; if (!((Object)(object)localMimics == (Object)null) && !((Object)(object)localMimics.photonView == (Object)null) && localMimics.photonView.IsMine) { localMimics.ProcessVoiceData(voiceData); } } } [HarmonyPatch(typeof(PlayerAvatar), "Awake")] internal class PlayerAvatarPatch { [HarmonyPostfix] private static void Postfix(PlayerAvatar __instance) { if (PhotonNetwork.IsConnectedAndReady) { TFS_Mimics tFS_Mimics = ((Component)__instance).GetComponent(); if ((Object)(object)tFS_Mimics == (Object)null) { tFS_Mimics = ((Component)__instance).gameObject.AddComponent(); } PhotonView component = ((Component)__instance).GetComponent(); if ((Object)(object)component != (Object)null && component.IsMine) { VoiceDataBus.LocalMimics = tFS_Mimics; } } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }