using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Photon.Pun; using Photon.Realtime; using UnityEngine; using UnityEngine.AI; using UnityEngine.Rendering; [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace MimicReplay; [BepInPlugin("com.schetnikov.repo.mimicreplay", "MimicReplay", "0.12.6")] public class Plugin : BaseUnityPlugin { private sealed class RigidbodyState { internal bool UseGravity; internal bool IsKinematic; internal bool DetectCollisions; } private sealed class PendingNetworkSpawn { internal int ActorNumber; internal float Delay; internal float Expires; internal bool Authoritative; } private const byte NetworkSpawnEventCode = 197; private const string NetworkSpawnSignature = "MimicReplaySpawnV1"; internal static ManualLogSource Log; internal static Plugin Instance; internal ConfigEntry Enabled; internal ConfigEntry SpawnKey; internal ConfigEntry RemoveKey; internal ConfigEntry RecordingRateHz; internal ConfigEntry HistorySeconds; internal ConfigEntry ReplayDelayMinSeconds; internal ConfigEntry ReplayDelayMaxSeconds; internal ConfigEntry PositionInterpolationSpeed; internal ConfigEntry RotationInterpolationSpeed; internal ConfigEntry ShowCopiedName; internal ConfigEntry HostOnlySpawn; internal ConfigEntry VerboseLogging; internal ConfigEntry VerticalOffset; internal ConfigEntry TemporaryVisualDesyncDistance; internal ConfigEntry DebugTrail; internal ConfigEntry DebugTrailKey; internal ConfigEntry PlaybackSpeed; internal ConfigEntry ChaseSpeed; internal ConfigEntry VisionDistance; internal ConfigEntry AttackRange; internal ConfigEntry AttackDamage; internal ConfigEntry AttackCooldown; internal ConfigEntry TurnSpeed; internal ConfigEntry SpectatorKey; internal ConfigEntry NoclipKey; internal ConfigEntry NoclipSpeed; internal ConfigEntry AddMoneyKey; internal ConfigEntry AddMoneyAmount; internal ConfigEntry KnockbackForce; private readonly List _recorders = new List(); private readonly List _mimics = new List(); private float _nextPlayerScan; private float _nextSpawnAllowedTime; private float _nextDebugToggleAllowedTime; private float _nextSpectatorToggleAllowedTime; private float _nextNoclipToggleAllowedTime; private float _nextMoneyAllowedTime; private float _moneyNoticeUntil; private string _moneyNotice; private bool _previousGodMode; private GUIStyle _spectatorStyle; private GUIStyle _spectatorShadowStyle; private readonly Dictionary _noclipColliderStates = new Dictionary(); private readonly Dictionary _noclipBodyStates = new Dictionary(); private bool _networkSubscribed; private readonly List _pendingNetworkSpawns = new List(); private static readonly FieldInfo PlayerHealthField = typeof(PlayerAvatar).GetField("playerHealth", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo GodModeField = typeof(PlayerHealth).GetField("godMode", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo AvatarPhotonViewField = typeof(PlayerAvatar).GetField("photonView", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo StatGetRunCurrencyMethod = AccessTools.Method(typeof(SemiFunc), "StatGetRunCurrency", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo StatSetRunCurrencyMethod = AccessTools.Method(typeof(SemiFunc), "StatSetRunCurrency", new Type[1] { typeof(int) }, (Type[])null); internal bool SpectatorMode { get; private set; } internal bool NoclipMode { get; private set; } private void Awake() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_00c2: Expected O, but got Unknown //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Expected O, but got Unknown //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Expected O, but got Unknown //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Expected O, but got Unknown //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Expected O, but got Unknown //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Expected O, but got Unknown //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Expected O, but got Unknown //IL_036e: Unknown result type (might be due to invalid IL or missing references) //IL_0378: Expected O, but got Unknown //IL_03ad: Unknown result type (might be due to invalid IL or missing references) //IL_03b7: Expected O, but got Unknown //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_03f6: Expected O, but got Unknown //IL_0421: Unknown result type (might be due to invalid IL or missing references) //IL_042b: Expected O, but got Unknown //IL_0460: Unknown result type (might be due to invalid IL or missing references) //IL_046a: Expected O, but got Unknown //IL_049f: Unknown result type (might be due to invalid IL or missing references) //IL_04a9: Expected O, but got Unknown //IL_04ca: Unknown result type (might be due to invalid IL or missing references) //IL_04fa: Unknown result type (might be due to invalid IL or missing references) //IL_053e: Unknown result type (might be due to invalid IL or missing references) //IL_0548: Expected O, but got Unknown //IL_0569: Unknown result type (might be due to invalid IL or missing references) //IL_05ad: Unknown result type (might be due to invalid IL or missing references) //IL_05b7: Expected O, but got Unknown //IL_05ec: Unknown result type (might be due to invalid IL or missing references) //IL_05f6: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Enable the mod"); SpawnKey = ((BaseUnityPlugin)this).Config.Bind("General", "SpawnKey", new KeyboardShortcut((KeyCode)288, (KeyCode[])(object)new KeyCode[0]), "Spawn a mimic"); RemoveKey = ((BaseUnityPlugin)this).Config.Bind("General", "RemoveKey", new KeyboardShortcut((KeyCode)289, (KeyCode[])(object)new KeyCode[0]), "Remove all mimics"); RecordingRateHz = ((BaseUnityPlugin)this).Config.Bind("General", "RecordingRateHz", 10, new ConfigDescription("Record snapshots per second", (AcceptableValueBase)(object)new AcceptableValueRange(1, 30), new object[0])); HistorySeconds = ((BaseUnityPlugin)this).Config.Bind("General", "HistorySeconds", 60, new ConfigDescription("History buffer length in seconds", (AcceptableValueBase)(object)new AcceptableValueRange(5, 300), new object[0])); ReplayDelayMinSeconds = ((BaseUnityPlugin)this).Config.Bind("General", "ReplayDelayMinSeconds", 15, new ConfigDescription("Minimum replay delay", (AcceptableValueBase)(object)new AcceptableValueRange(1, 120), new object[0])); ReplayDelayMaxSeconds = ((BaseUnityPlugin)this).Config.Bind("General", "ReplayDelayMaxSeconds", 30, new ConfigDescription("Maximum replay delay", (AcceptableValueBase)(object)new AcceptableValueRange(1, 120), new object[0])); PositionInterpolationSpeed = ((BaseUnityPlugin)this).Config.Bind("General", "PositionInterpolationSpeed", 2f, new ConfigDescription("Position interpolation speed", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 20f), new object[0])); RotationInterpolationSpeed = ((BaseUnityPlugin)this).Config.Bind("General", "RotationInterpolationSpeed", 2f, new ConfigDescription("Rotation interpolation speed", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 20f), new object[0])); ShowCopiedName = ((BaseUnityPlugin)this).Config.Bind("General", "ShowCopiedName", true, "Show the copied player name above mimic"); HostOnlySpawn = ((BaseUnityPlugin)this).Config.Bind("General", "HostOnlySpawn", false, "Only host spawns mimics (mimics are currently client-local)"); VerboseLogging = ((BaseUnityPlugin)this).Config.Bind("General", "VerboseLogging", false, "Log extra details"); VerticalOffset = ((BaseUnityPlugin)this).Config.Bind("Appearance", "VerticalOffset", 0f, "Manual vertical correction applied after automatic bounds alignment"); TemporaryVisualDesyncDistance = ((BaseUnityPlugin)this).Config.Bind("Appearance", "TemporaryVisualDesyncDistance", 0f, new ConfigDescription("Temporary horizontal offset between visible mimic and its real collider/hitbox; set 0 to disable", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 20f), new object[0])); DebugTrail = ((BaseUnityPlugin)this).Config.Bind("Debug", "DebugTrail", false, "Draw the recorded and replayed trajectory"); DebugTrailKey = ((BaseUnityPlugin)this).Config.Bind("Debug", "DebugTrailKey", new KeyboardShortcut((KeyCode)287, (KeyCode[])(object)new KeyCode[0]), "Toggle trajectory visualization"); PlaybackSpeed = ((BaseUnityPlugin)this).Config.Bind("Movement", "PlaybackSpeed", 0.65f, new ConfigDescription("Replay speed multiplier", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 2f), new object[0])); ChaseSpeed = ((BaseUnityPlugin)this).Config.Bind("Enemy", "ChaseSpeed", 2.5f, new ConfigDescription("Movement speed while chasing", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 8f), new object[0])); VisionDistance = ((BaseUnityPlugin)this).Config.Bind("Enemy", "VisionDistance", 12f, new ConfigDescription("Player detection distance", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 50f), new object[0])); AttackRange = ((BaseUnityPlugin)this).Config.Bind("Enemy", "AttackRange", 1.5f, new ConfigDescription("Attack distance", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 5f), new object[0])); AttackDamage = ((BaseUnityPlugin)this).Config.Bind("Enemy", "AttackDamage", 10, new ConfigDescription("Damage per attack", (AcceptableValueBase)(object)new AcceptableValueRange(1, 100), new object[0])); AttackCooldown = ((BaseUnityPlugin)this).Config.Bind("Enemy", "AttackCooldown", 2f, new ConfigDescription("Seconds between attacks", (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 10f), new object[0])); TurnSpeed = ((BaseUnityPlugin)this).Config.Bind("Movement", "TurnSpeed", 540f, new ConfigDescription("Turning speed in degrees per second", (AcceptableValueBase)(object)new AcceptableValueRange(30f, 1080f), new object[0])); SpectatorKey = ((BaseUnityPlugin)this).Config.Bind("Spectator", "SpectatorKey", new KeyboardShortcut((KeyCode)291, (KeyCode[])(object)new KeyCode[0]), "Toggle spectator mode"); NoclipKey = ((BaseUnityPlugin)this).Config.Bind("Noclip", "NoclipKey", new KeyboardShortcut((KeyCode)290, (KeyCode[])(object)new KeyCode[0]), "Toggle flight and wall noclip"); NoclipSpeed = ((BaseUnityPlugin)this).Config.Bind("Noclip", "NoclipSpeed", 8f, new ConfigDescription("Flight speed", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 30f), new object[0])); AddMoneyKey = ((BaseUnityPlugin)this).Config.Bind("Cheats", "AddMoneyKey", new KeyboardShortcut((KeyCode)286, (KeyCode[])(object)new KeyCode[0]), "Add money (host/singleplayer only)"); AddMoneyAmount = ((BaseUnityPlugin)this).Config.Bind("Cheats", "AddMoneyAmount", 10000, new ConfigDescription("Dollars added per key press", (AcceptableValueBase)(object)new AcceptableValueRange(1000, 1000000), new object[0])); KnockbackForce = ((BaseUnityPlugin)this).Config.Bind("Enemy", "KnockbackForce", 6f, new ConfigDescription("Player knockback force", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 20f), new object[0])); Log.LogMessage((object)"MimicReplay loaded"); Log.LogMessage((object)("Game version: " + Application.version)); Harmony.CreateAndPatchAll(typeof(EnvironmentDirectorDisconnectPatch), "com.schetnikov.repo.mimicreplay.environment"); Harmony.CreateAndPatchAll(typeof(LocalVoiceShortInputPatch), "com.schetnikov.repo.mimicreplay.voice.short"); ((MonoBehaviour)this).StartCoroutine(PeriodicUpdate()); } private IEnumerator PeriodicUpdate() { while (true) { yield return (object)new WaitForSeconds(0.25f); if (Enabled.Value) { DiscoverPlayers(); ProcessPendingNetworkSpawns(); } } } private void Update() { //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_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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: 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_0131: 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_0174: Unknown result type (might be due to invalid IL or missing references) if (Enabled.Value) { MaintainNetworkSubscription(); UpdateRecorders(); UpdateMimics(); KeyboardShortcut value = SpawnKey.Value; if (((KeyboardShortcut)(ref value)).IsDown() && Time.unscaledTime >= _nextSpawnAllowedTime) { _nextSpawnAllowedTime = Time.unscaledTime + 0.75f; SpawnMimic(); } KeyboardShortcut value2 = RemoveKey.Value; if (((KeyboardShortcut)(ref value2)).IsDown()) { RemoveAllMimics(); } KeyboardShortcut value3 = DebugTrailKey.Value; if (((KeyboardShortcut)(ref value3)).IsDown() && Time.unscaledTime >= _nextDebugToggleAllowedTime) { _nextDebugToggleAllowedTime = Time.unscaledTime + 0.75f; DebugTrail.Value = !DebugTrail.Value; Log.LogMessage((object)("DebugTrail: " + DebugTrail.Value)); } KeyboardShortcut value4 = SpectatorKey.Value; if (((KeyboardShortcut)(ref value4)).IsDown() && Time.unscaledTime >= _nextSpectatorToggleAllowedTime) { _nextSpectatorToggleAllowedTime = Time.unscaledTime + 0.75f; SetSpectatorMode(!SpectatorMode); } KeyboardShortcut value5 = NoclipKey.Value; if (((KeyboardShortcut)(ref value5)).IsDown() && Time.unscaledTime >= _nextNoclipToggleAllowedTime) { _nextNoclipToggleAllowedTime = Time.unscaledTime + 0.5f; SetNoclipMode(!NoclipMode); } KeyboardShortcut value6 = AddMoneyKey.Value; if (((KeyboardShortcut)(ref value6)).IsDown() && Time.unscaledTime >= _nextMoneyAllowedTime) { _nextMoneyAllowedTime = Time.unscaledTime + 0.75f; AddMoney(); } MaintainSpectatorMode(); MaintainNoclipMode(); } } private void OnGUI() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: 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_0201: Unknown result type (might be due to invalid IL or missing references) if (Enabled.Value && (SpectatorMode || NoclipMode || !(Time.unscaledTime >= _moneyNoticeUntil))) { if (_spectatorStyle == null) { _spectatorStyle = new GUIStyle(GUI.skin.label); _spectatorStyle.alignment = (TextAnchor)4; _spectatorStyle.fontSize = 22; _spectatorStyle.fontStyle = (FontStyle)1; _spectatorStyle.normal.textColor = new Color(0.25f, 1f, 0.9f, 1f); _spectatorShadowStyle = new GUIStyle(_spectatorStyle); _spectatorShadowStyle.normal.textColor = new Color(0f, 0f, 0f, 0.9f); } string text = ((SpectatorMode && NoclipMode) ? "SPECTATOR [F10] | NOCLIP [F9]" : (SpectatorMode ? "SPECTATOR MODE [F10]" : "NOCLIP / FLIGHT [F9]")); if (!SpectatorMode && !NoclipMode) { text = _moneyNotice ?? "MONEY UPDATED"; } float num = Mathf.Min(420f, (float)Screen.width - 20f); Rect val = default(Rect); ((Rect)(ref val))..ctor(((float)Screen.width - num) * 0.5f, 18f, num, 38f); Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(((Rect)(ref val)).x - 8f, ((Rect)(ref val)).y - 3f, ((Rect)(ref val)).width + 16f, ((Rect)(ref val)).height + 6f); Color color = GUI.color; GUI.color = new Color(0.02f, 0.06f, 0.08f, 0.78f); GUI.Box(val2, GUIContent.none); GUI.color = color; GUI.Label(new Rect(((Rect)(ref val)).x + 2f, ((Rect)(ref val)).y + 2f, ((Rect)(ref val)).width, ((Rect)(ref val)).height), text, _spectatorShadowStyle); GUI.Label(val, text, _spectatorStyle); } } private void SetSpectatorMode(bool enabled) { PlayerAvatar val = SemiFunc.PlayerAvatarLocal(); PlayerHealth val2 = (PlayerHealth)(((Object)(object)val != (Object)null && PlayerHealthField != null) ? /*isinst with value type is only supported in some contexts*/: null); if (enabled && (Object)(object)val2 != (Object)null && GodModeField != null) { _previousGodMode = (bool)GodModeField.GetValue(val2); } SpectatorMode = enabled; if (!enabled && (Object)(object)val2 != (Object)null && GodModeField != null) { GodModeField.SetValue(val2, _previousGodMode); } Log.LogMessage((object)("Spectator mode: " + (enabled ? "ON" : "OFF"))); } private void MaintainSpectatorMode() { if (!SpectatorMode) { return; } PlayerAvatar val = SemiFunc.PlayerAvatarLocal(); if (!((Object)(object)val == (Object)null)) { val.EnemyVisionFreezeTimerSet(1f); val.OverrideDisableEnemyInvestigate(1f); PlayerHealth val2 = (PlayerHealth)((PlayerHealthField != null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val2 != (Object)null && GodModeField != null) { GodModeField.SetValue(val2, true); } } } private void SetNoclipMode(bool enabled) { if (NoclipMode != enabled) { NoclipMode = enabled; if (enabled) { CaptureAndDisableLocalPhysics(); } else { RestoreLocalPhysics(); } Log.LogMessage((object)("Noclip mode: " + (enabled ? "ON [WASD/Space/Ctrl]" : "OFF"))); } } private void CaptureAndDisableLocalPhysics() { //IL_00bf: 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) PlayerAvatar val = SemiFunc.PlayerAvatarLocal(); if ((Object)(object)val == (Object)null) { return; } _noclipColliderStates.Clear(); _noclipBodyStates.Clear(); Collider[] componentsInChildren = ((Component)val).GetComponentsInChildren(true); foreach (Collider val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null)) { _noclipColliderStates[val2] = val2.enabled; val2.enabled = false; } } Rigidbody[] componentsInChildren2 = ((Component)val).GetComponentsInChildren(true); foreach (Rigidbody val3 in componentsInChildren2) { if (!((Object)(object)val3 == (Object)null)) { _noclipBodyStates[val3] = new RigidbodyState { UseGravity = val3.useGravity, IsKinematic = val3.isKinematic, DetectCollisions = val3.detectCollisions }; val3.velocity = Vector3.zero; val3.angularVelocity = Vector3.zero; val3.useGravity = false; val3.detectCollisions = false; val3.isKinematic = true; } } } private void MaintainNoclipMode() { //IL_005b: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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_00bb: 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_00c1: 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_00ce: 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_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00df: 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_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: 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_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: 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_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: 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_01d3: 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) if (!NoclipMode) { return; } PlayerAvatar val = SemiFunc.PlayerAvatarLocal(); if ((Object)(object)val == (Object)null) { return; } if (_noclipColliderStates.Count == 0 && _noclipBodyStates.Count == 0) { CaptureAndDisableLocalPhysics(); } Camera main = Camera.main; Vector3 val2 = (((Object)(object)main != (Object)null) ? ((Component)main).transform.forward : ((Component)val).transform.forward); Vector3 val3 = (((Object)(object)main != (Object)null) ? ((Component)main).transform.right : ((Component)val).transform.right); Vector3 val4 = Vector3.zero; if (Input.GetKey((KeyCode)119)) { val4 += val2; } if (Input.GetKey((KeyCode)115)) { val4 -= val2; } if (Input.GetKey((KeyCode)100)) { val4 += val3; } if (Input.GetKey((KeyCode)97)) { val4 -= val3; } if (Input.GetKey((KeyCode)32)) { val4 += Vector3.up; } if (Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)99)) { val4 -= Vector3.up; } Rigidbody[] array = _noclipBodyStates.Keys.ToArray(); foreach (Rigidbody val5 in array) { if (!((Object)(object)val5 == (Object)null)) { val5.velocity = Vector3.zero; val5.angularVelocity = Vector3.zero; } } if (!(((Vector3)(ref val4)).sqrMagnitude < 0.001f)) { float num = NoclipSpeed.Value * (Input.GetKey((KeyCode)304) ? 2f : 1f); Vector3 val6 = ((Vector3)(ref val4)).normalized * num * Time.unscaledDeltaTime; Transform val7 = (((Object)(object)val.playerTransform != (Object)null) ? val.playerTransform : ((Component)val).transform); val7.position += val6; } } private void RestoreLocalPhysics() { //IL_00c8: 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) foreach (KeyValuePair noclipColliderState in _noclipColliderStates) { if ((Object)(object)noclipColliderState.Key != (Object)null) { noclipColliderState.Key.enabled = noclipColliderState.Value; } } foreach (KeyValuePair noclipBodyState in _noclipBodyStates) { if (!((Object)(object)noclipBodyState.Key == (Object)null)) { noclipBodyState.Key.useGravity = noclipBodyState.Value.UseGravity; noclipBodyState.Key.isKinematic = noclipBodyState.Value.IsKinematic; noclipBodyState.Key.detectCollisions = noclipBodyState.Value.DetectCollisions; noclipBodyState.Key.velocity = Vector3.zero; noclipBodyState.Key.angularVelocity = Vector3.zero; } } _noclipColliderStates.Clear(); _noclipBodyStates.Clear(); } private void AddMoney() { if (!SemiFunc.IsMasterClientOrSingleplayer()) { ShowMoneyNotice("MONEY: HOST ONLY"); Log.LogWarning((object)"F5 money ignored: only the host can change run currency"); return; } if (StatGetRunCurrencyMethod == null || StatSetRunCurrencyMethod == null) { ShowMoneyNotice("MONEY API NOT FOUND"); Log.LogError((object)"Run currency API was not found"); return; } try { int num = Convert.ToInt32(StatGetRunCurrencyMethod.Invoke(null, null)); int num2 = Mathf.Max(1, Mathf.RoundToInt((float)AddMoneyAmount.Value / 1000f)); int num3 = ((num > int.MaxValue - num2) ? int.MaxValue : (num + num2)); StatSetRunCurrencyMethod.Invoke(null, new object[1] { num3 }); RefreshCurrencyUi(); int num4 = num2 * 1000; ShowMoneyNotice("+$" + num4.ToString("N0") + " [F5]"); Log.LogMessage((object)("Money added: $" + num4 + ", balance=$" + (long)num3 * 1000L)); } catch (Exception ex) { ShowMoneyNotice("MONEY ERROR — CHECK LOG"); Log.LogError((object)("Failed to add money: " + ex)); } } private void ShowMoneyNotice(string text) { _moneyNotice = text; _moneyNoticeUntil = Time.unscaledTime + 2.5f; } private static void RefreshCurrencyUi() { Type type = AccessTools.TypeByName("CurrencyUI"); if (!(type == null)) { FieldInfo fieldInfo = AccessTools.Field(type, "instance"); object obj = ((fieldInfo != null) ? fieldInfo.GetValue(null) : null); MethodInfo methodInfo = AccessTools.Method(type, "FetchCurrency", Type.EmptyTypes, (Type[])null); if (obj != null && methodInfo != null) { methodInfo.Invoke(obj, null); } } } internal void RegisterRecorder(PlayerRecorder recorder) { _recorders.Add(recorder); } internal PlayerRecorder FindRecorderForPlayer(GameObject playerGo) { return _recorders.FirstOrDefault((PlayerRecorder r) => (Object)(object)r.TargetPlayer == (Object)(object)playerGo); } internal void RegisterMimic(MimicController mimic) { _mimics.Add(mimic); } internal void RemoveMimic(MimicController mimic) { _mimics.Remove(mimic); } internal void RemoveAllMimics() { MimicController[] array = _mimics.ToArray(); MimicController[] array2 = array; foreach (MimicController mimicController in array2) { mimicController.Dispose(); } _mimics.Clear(); } private void DiscoverPlayers() { if (Time.unscaledTime < _nextPlayerScan) { return; } _nextPlayerScan = Time.unscaledTime + 1f; PlayerAvatar[] array = Object.FindObjectsOfType(); foreach (PlayerAvatar val in array) { if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy && FindRecorderForPlayer(((Component)val).gameObject) == null) { RegisterRecorder(new PlayerRecorder(val, this)); if (VerboseLogging.Value) { Log.LogInfo((object)("Recording player: " + ((Object)((Component)val).gameObject).name)); } } } _recorders.RemoveAll((PlayerRecorder r) => (Object)(object)r.TargetPlayer == (Object)null); } private void UpdateRecorders() { foreach (PlayerRecorder item in _recorders.ToList()) { item.Tick(); } } private void UpdateMimics() { foreach (MimicController item in _mimics.ToList()) { item.Tick(); } } internal void SpawnMimic() { //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Expected O, but got Unknown //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) if (!Enabled.Value) { return; } if (HostOnlySpawn.Value && !IsHost()) { Log.LogWarning((object)"F7 ignored: HostOnlySpawn is enabled and this client is not the host"); return; } PlayerRecorder playerRecorder = FindRandomMimicSource(); if (playerRecorder == null) { Log.LogWarning((object)"No active player has enough recorded history to spawn a mimic yet"); return; } _ = playerRecorder.TargetPlayer; PlayerSnapshot playerSnapshot = playerRecorder.History[0]; PlayerSnapshot playerSnapshot2 = playerRecorder.History[playerRecorder.History.Count - 1]; float num = playerSnapshot2.Timestamp - playerSnapshot.Timestamp; if (num < (float)ReplayDelayMinSeconds.Value) { Log.LogWarning((object)("Not enough recorded history. Available: " + num.ToString("F1") + "s, required: " + ReplayDelayMinSeconds.Value + "s")); return; } float num2 = Mathf.Min((float)ReplayDelayMaxSeconds.Value, num); float num3 = Mathf.Min((float)ReplayDelayMinSeconds.Value, num2); float num4 = Random.Range(num3, num2); PhotonView val = (PhotonView)((AvatarPhotonViewField != null) ? /*isinst with value type is only supported in some contexts*/: null); if (PhotonNetwork.InRoom && (Object)(object)val != (Object)null && val.Owner != null) { object[] array = new object[3] { "MimicReplaySpawnV1", val.OwnerActorNr, num4 }; RaiseEventOptions val2 = new RaiseEventOptions(); val2.Receivers = (ReceiverGroup)1; val2.CachingOption = (EventCaching)0; RaiseEventOptions val3 = val2; bool flag = PhotonNetwork.RaiseEvent((byte)197, (object)array, val3, SendOptions.SendReliable); Log.LogMessage((object)("Network mimic spawn sent=" + flag + " sourceActor=" + val.OwnerActorNr + " delay=" + num4.ToString("F2"))); } else { SpawnMimicForRecorder(playerRecorder, num4, "local", authoritative: true); } } private void SpawnMimicForRecorder(PlayerRecorder recorder, float selectedDelay, string origin, bool authoritative) { if (recorder == null || (Object)(object)recorder.TargetPlayer == (Object)null || recorder.History.Count < 2) { return; } GameObject targetPlayer = recorder.TargetPlayer; PlayerSnapshot playerSnapshot = recorder.History[0]; PlayerSnapshot playerSnapshot2 = recorder.History[recorder.History.Count - 1]; ManualLogSource log = Log; object[] array = new object[14] { "Mimic spawn origin=", origin, " source=", ((Object)targetPlayer).name, " id=", ((Object)targetPlayer).GetInstanceID(), " snapshots=", recorder.History.Count, " oldest=", null, null, null, null, null }; float timestamp = playerSnapshot.Timestamp; array[9] = timestamp.ToString("F3"); array[10] = " newest="; float timestamp2 = playerSnapshot2.Timestamp; array[11] = timestamp2.ToString("F3"); array[12] = " delay="; array[13] = selectedDelay.ToString("F3"); log.LogMessage((object)string.Concat(array)); try { MimicController item = new MimicController(targetPlayer, recorder, selectedDelay, this, authoritative); _mimics.Add(item); Log.LogMessage((object)("Spawned mimic for " + ((Object)targetPlayer).name)); } catch (Exception ex) { Log.LogError((object)("Failed to create mimic: " + ex)); } } private void OnNetworkEvent(EventData eventData) { if (eventData != null && eventData.Code == 197 && eventData.CustomData is object[] array && array.Length >= 3 && array[0] is string && !((string)array[0] != "MimicReplaySpawnV1")) { int num = Convert.ToInt32(array[1]); float num2 = Convert.ToSingle(array[2]); bool authoritative = PhotonNetwork.LocalPlayer != null && eventData.Sender == PhotonNetwork.LocalPlayer.ActorNumber; PlayerRecorder playerRecorder = FindRecorderForActor(num); if (playerRecorder != null && playerRecorder.History.Count >= 2) { float num3 = playerRecorder.History[playerRecorder.History.Count - 1].Timestamp - playerRecorder.History[0].Timestamp; SpawnMimicForRecorder(playerRecorder, Mathf.Min(num2, num3), "network actor=" + num, authoritative); return; } _pendingNetworkSpawns.Add(new PendingNetworkSpawn { ActorNumber = num, Delay = num2, Expires = Time.unscaledTime + 15f, Authoritative = authoritative }); Log.LogInfo((object)("Network mimic spawn queued sourceActor=" + num)); } } private void MaintainNetworkSubscription() { LoadBalancingClient networkingClient = PhotonNetwork.NetworkingClient; bool flag = PhotonNetwork.InRoom && networkingClient != null; if (flag && !_networkSubscribed) { networkingClient.EventReceived += OnNetworkEvent; _networkSubscribed = true; Log.LogInfo((object)"MimicReplay network listener enabled after room join"); } else if (!flag && _networkSubscribed) { if (networkingClient != null) { networkingClient.EventReceived -= OnNetworkEvent; } _networkSubscribed = false; Log.LogInfo((object)"MimicReplay network listener disabled outside room"); } } private PlayerRecorder FindRecorderForActor(int actorNumber) { foreach (PlayerRecorder recorder in _recorders) { if (recorder != null && !((Object)(object)recorder.Avatar == (Object)null)) { PhotonView val = (PhotonView)((AvatarPhotonViewField != null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val != (Object)null && val.OwnerActorNr == actorNumber) { return recorder; } } } return null; } private void ProcessPendingNetworkSpawns() { for (int num = _pendingNetworkSpawns.Count - 1; num >= 0; num--) { PendingNetworkSpawn pendingNetworkSpawn = _pendingNetworkSpawns[num]; if (Time.unscaledTime >= pendingNetworkSpawn.Expires) { Log.LogWarning((object)("Network mimic spawn expired sourceActor=" + pendingNetworkSpawn.ActorNumber)); _pendingNetworkSpawns.RemoveAt(num); } else { PlayerRecorder playerRecorder = FindRecorderForActor(pendingNetworkSpawn.ActorNumber); if (playerRecorder != null && playerRecorder.History.Count >= 2) { float num2 = playerRecorder.History[playerRecorder.History.Count - 1].Timestamp - playerRecorder.History[0].Timestamp; if (!(num2 < Mathf.Min((float)ReplayDelayMinSeconds.Value, pendingNetworkSpawn.Delay))) { SpawnMimicForRecorder(playerRecorder, Mathf.Min(pendingNetworkSpawn.Delay, num2), "queued network actor=" + pendingNetworkSpawn.ActorNumber, pendingNetworkSpawn.Authoritative); _pendingNetworkSpawns.RemoveAt(num); } } } } } private PlayerRecorder FindRandomMimicSource() { List list = new List(); foreach (PlayerRecorder recorder in _recorders) { if (recorder != null && !((Object)(object)recorder.Avatar == (Object)null) && !((Object)(object)recorder.TargetPlayer == (Object)null) && recorder.TargetPlayer.activeInHierarchy && recorder.History.Count >= 2) { PlayerSnapshot playerSnapshot = recorder.History[0]; PlayerSnapshot playerSnapshot2 = recorder.History[recorder.History.Count - 1]; if (playerSnapshot2.Timestamp - playerSnapshot.Timestamp >= (float)ReplayDelayMinSeconds.Value) { list.Add(recorder); } } } if (list.Count == 0) { return null; } PlayerRecorder playerRecorder = list[Random.Range(0, list.Count)]; Log.LogMessage((object)("Random mimic source selected index=" + list.IndexOf(playerRecorder) + "/" + list.Count + " object=" + ((Object)playerRecorder.TargetPlayer).name + " avatarId=" + ((Object)playerRecorder.Avatar).GetInstanceID())); return playerRecorder; } private bool IsHost() { return SemiFunc.IsMasterClientOrSingleplayer(); } private void OnDestroy() { if (_networkSubscribed && PhotonNetwork.NetworkingClient != null) { PhotonNetwork.NetworkingClient.EventReceived -= OnNetworkEvent; } _networkSubscribed = false; if (NoclipMode) { SetNoclipMode(enabled: false); } if (SpectatorMode) { SetSpectatorMode(enabled: false); } RemoveAllMimics(); } } [HarmonyPatch(typeof(EnvironmentDirector), "AmbientLightLogic")] internal static class EnvironmentDirectorDisconnectPatch { private static Exception Finalizer(Exception __exception) { if (__exception is NullReferenceException && !PhotonNetwork.IsConnected) { return null; } return __exception; } } [HarmonyPatch] internal static class LocalVoiceInputPatch { private static IEnumerable TargetMethods() { Type type = AccessTools.TypeByName("Photon.Voice.LocalVoiceAudioFloat"); if (!(type == null)) { MethodInfo push = AccessTools.Method(type, "PushData", new Type[1] { typeof(float[]) }, (Type[])null); MethodInfo pushAsync = AccessTools.Method(type, "PushDataAsync", new Type[1] { typeof(float[]) }, (Type[])null); if (push != null) { yield return push; } if (pushAsync != null) { yield return pushAsync; } } } private static void Prefix(float[] __0) { VoicePhraseCapture.AcceptLocalFrame(__0); } } [HarmonyPatch] internal static class LocalVoiceShortInputPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("Photon.Voice.LocalVoiceFramed`1"); if (type == null) { return null; } Type type2 = type.MakeGenericType(typeof(short)); return AccessTools.Method(type2, "PushDataAsync", new Type[1] { typeof(short[]) }, (Type[])null); } private static void Prefix(short[] __0) { VoicePhraseCapture.AcceptLocalShortFrame(__0); } } [HarmonyPatch] internal static class WindowsMicrophoneInputPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("Photon.Voice.Windows.WindowsAudioInPusher"); if (!(type != null)) { return null; } return AccessTools.Method(type, "push", (Type[])null, (Type[])null); } private static void Prefix(object __instance, IntPtr __0, int __1) { Type type = __instance.GetType(); MethodInfo methodInfo = AccessTools.PropertyGetter(type, "Channels"); MethodInfo methodInfo2 = AccessTools.PropertyGetter(type, "SamplingRate"); int channels = ((!(methodInfo != null)) ? 1 : ((int)methodInfo.Invoke(__instance, null))); int sampleRate = ((methodInfo2 != null) ? ((int)methodInfo2.Invoke(__instance, null)) : 48000); VoicePhraseCapture.AcceptLocalPcm16(__0, __1, channels, sampleRate); } } [HarmonyPatch] internal static class UnityMicrophoneReaderPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("Photon.Voice.Unity.MicWrapper"); if (!(type != null)) { return null; } return AccessTools.Method(type, "Read", (Type[])null, (Type[])null); } private static void Postfix(float[] __0, bool __result) { if (__result) { VoicePhraseCapture.AcceptLocalFrame(__0); } } } [HarmonyPatch] internal static class UnityMicrophonePusherPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("Photon.Voice.Unity.MicWrapperPusherOnAudioFilterRead"); if (!(type != null)) { return null; } return AccessTools.Method(type, "OnAudioFilterRead", (Type[])null, (Type[])null); } private static void Prefix(float[] __0) { VoicePhraseCapture.AcceptLocalFrame(__0); } } public static class MeshFactory { public static Mesh CreateCubeMesh() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0024: 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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_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_0084: 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_00a4: 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_00c4: 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_00e4: 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_0109: Unknown result type (might be due to invalid IL or missing references) Mesh val = new Mesh(); val.vertices = (Vector3[])(object)new Vector3[8] { new Vector3(-0.5f, -0.5f, -0.5f), new Vector3(0.5f, -0.5f, -0.5f), new Vector3(0.5f, 0.5f, -0.5f), new Vector3(-0.5f, 0.5f, -0.5f), new Vector3(-0.5f, 0.5f, 0.5f), new Vector3(0.5f, 0.5f, 0.5f), new Vector3(0.5f, -0.5f, 0.5f), new Vector3(-0.5f, -0.5f, 0.5f) }; val.triangles = new int[36] { 0, 2, 1, 0, 3, 2, 2, 3, 4, 2, 4, 5, 1, 2, 5, 1, 5, 6, 0, 7, 4, 0, 4, 3, 5, 4, 7, 5, 7, 6, 0, 1, 6, 0, 6, 7 }; val.RecalculateNormals(); return val; } } internal sealed class MimicAppearanceResult { internal bool Success; internal string Error; internal Animator Animator; internal Transform FacingTransform; } internal static class MimicAppearance { internal static MimicAppearanceResult Create(PlayerAvatar avatar, Transform destination) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) MimicAppearanceResult mimicAppearanceResult = new MimicAppearanceResult(); if ((Object)(object)avatar == (Object)null) { mimicAppearanceResult.Error = "PlayerAvatar is null"; return mimicAppearanceResult; } GameObject val = FindVisualRoot(avatar); if ((Object)(object)val == (Object)null) { mimicAppearanceResult.Error = "playerAvatarVisuals was not found"; return mimicAppearanceResult; } GameObject val2 = Object.Instantiate(val); ((Object)val2).name = ((Object)val).name + "_MimicClone"; val2.transform.SetParent(destination, false); val2.transform.localPosition = val.transform.localPosition; val2.transform.localRotation = val.transform.localRotation; val2.transform.localScale = val.transform.localScale; SetLayerRecursively(val2, 0); Transform val3 = null; Transform[] componentsInChildren = val2.GetComponentsInChildren(true); foreach (Transform val4 in componentsInChildren) { if (((Object)val4).name == "ANIM BOT") { val3 = val4; break; } } List list = new List(); Component[] componentsInChildren2 = val2.GetComponentsInChildren(true); foreach (Component val5 in componentsInChildren2) { if (!((Object)(object)val5 == (Object)null) && !(val5 is Transform) && !(val5 is Renderer) && !(val5 is Animator) && !(val5 is MeshFilter) && (val5 is Camera || val5 is AudioListener || val5 is Collider || val5 is Rigidbody || val5 is MonoBehaviour)) { list.Add(((object)val5).GetType().FullName); Behaviour val6 = (Behaviour)(object)((val5 is Behaviour) ? val5 : null); if ((Object)(object)val6 != (Object)null) { val6.enabled = false; } Object.Destroy((Object)(object)val5); } } Renderer[] componentsInChildren3 = val2.GetComponentsInChildren(true); foreach (Renderer val7 in componentsInChildren3) { if ((Object)(object)val3 != (Object)null && (Object)(object)((Component)val7).transform != (Object)(object)val3 && !((Component)val7).transform.IsChildOf(val3)) { val7.enabled = false; continue; } val7.enabled = true; val7.shadowCastingMode = (ShadowCastingMode)1; val7.receiveShadows = true; Material[] sharedMaterials = val7.sharedMaterials; Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; for (int l = 0; l < sharedMaterials.Length; l++) { array[l] = (((Object)(object)sharedMaterials[l] != (Object)null) ? new Material(sharedMaterials[l]) : ((Material)null)); } val7.materials = array; } Renderer[] componentsInChildren4 = val2.GetComponentsInChildren(true); SkinnedMeshRenderer[] componentsInChildren5 = val2.GetComponentsInChildren(true); Animator componentInChildren = val2.GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.applyRootMotion = false; componentInChildren.cullingMode = (AnimatorCullingMode)0; } mimicAppearanceResult.Animator = componentInChildren; mimicAppearanceResult.FacingTransform = (((Object)(object)val3 != (Object)null) ? val3 : (((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).transform : val2.transform)); Plugin.Log.LogMessage((object)("Mimic appearance source=" + ((Object)((Component)avatar).gameObject).name + " visualPath=" + GetPath(val.transform) + " renderers=" + componentsInChildren4.Length + " skinnedRenderers=" + componentsInChildren5.Length + " animator=" + ((Object)(object)componentInChildren != (Object)null) + " disabled=[" + string.Join(",", list.ToArray()) + "]")); if (componentsInChildren4.Length == 0) { mimicAppearanceResult.Error = "visual root contains no Renderer"; return mimicAppearanceResult; } mimicAppearanceResult.Success = true; return mimicAppearanceResult; } private static void SetLayerRecursively(GameObject root, int layer) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown root.layer = layer; foreach (Transform item in root.transform) { Transform val = item; SetLayerRecursively(((Component)val).gameObject, layer); } } private static GameObject FindVisualRoot(PlayerAvatar avatar) { FieldInfo field = typeof(PlayerAvatar).GetField("playerAvatarVisuals", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object? value = field.GetValue(avatar); Component val = (Component)((value is Component) ? value : null); if ((Object)(object)val != (Object)null) { return val.gameObject; } } Renderer[] componentsInChildren = ((Component)avatar).GetComponentsInChildren(true); if (componentsInChildren.Length == 0) { return null; } Transform val2 = ((Component)componentsInChildren[0]).transform; while ((Object)(object)val2.parent != (Object)null && (Object)(object)val2.parent != (Object)(object)((Component)avatar).transform) { val2 = val2.parent; } return ((Component)val2).gameObject; } internal static Bounds GetCombinedBounds(GameObject root) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = root.GetComponentsInChildren(true); List list = new List(); Renderer[] array = componentsInChildren; foreach (Renderer val in array) { if (val.enabled && ((Component)val).gameObject.activeInHierarchy) { list.Add(val); } } if (list.Count == 0) { list.AddRange(componentsInChildren); } Bounds bounds = list[0].bounds; for (int j = 1; j < list.Count; j++) { ((Bounds)(ref bounds)).Encapsulate(list[j].bounds); } return bounds; } private static string GetPath(Transform transform) { string text = ((Object)transform).name; while ((Object)(object)transform.parent != (Object)null) { transform = transform.parent; text = ((Object)transform).name + "/" + text; } return text; } } public class MimicController { private enum MimicMode { Replay, Chase, Attack, StuckRecovery } private readonly GameObject _mimicObject; private readonly GameObject _visualContainer; private readonly Plugin _plugin; private readonly bool _authoritative; private readonly PlayerRecorder _recorder; private readonly Animator _animator; private readonly Transform _visualFacing; private readonly AudioSource _voiceSource; private readonly CapsuleCollider _capsule; private readonly NavMeshAgent _agent; private readonly EnemyNavMeshAgent _enemyNavigation; private List _segment; private float _sourceStartTime; private float _sourceEndTime; private bool _reversePlayback; private float _localStartTime; private float _nextVerboseLogTime; private float _nextVisionCheck; private float _lastSeenTime; private float _nextAttackTime; private float _attackStateUntil; private float _nextRepathTime; private float _nextDoorCheck; private float _nextStuckCheck; private float _stuckSince; private Vector3 _recoveryStartPosition; private int _recoveryAttempts; private float _lastInteractionTimestamp = -1f; private Vector3 _lastProgressPosition; private Vector3 _retreatDirection; private Vector3 _retreatDestination; private Vector3 _lastMovementPosition; private Vector3 _lastReplayPosition; private float _nextVoiceTime; private Vector3 _lastPathDestination; private bool _hasPathDestination; private PlayerAvatar _chaseTarget; private MimicMode _mode; private LineRenderer _recordedTrail; private LineRenderer _replayTrail; private bool _wasJumping; private bool _wasSprinting; private bool _chaseCrouching; private bool _chaseCrawling; private GameObject _fakeHeldObject; private int _fakeHeldSourceId; private static readonly FieldInfo PlayerHealthField = typeof(PlayerAvatar).GetField("playerHealth", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo PlayerCrouchingField = typeof(PlayerAvatar).GetField("isCrouching", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo PlayerCrawlingField = typeof(PlayerAvatar).GetField("isCrawling", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo DoorOpenMethod = typeof(PhysGrabHinge).GetMethod("OpenImpulse", BindingFlags.Instance | BindingFlags.NonPublic); public MimicController(GameObject source, PlayerRecorder recorder, float selectedDelay, Plugin plugin, bool authoritative) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_015b: 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) //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_0178: 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_0368: Unknown result type (might be due to invalid IL or missing references) //IL_037e: 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_055e: Unknown result type (might be due to invalid IL or missing references) //IL_0565: Unknown result type (might be due to invalid IL or missing references) //IL_056a: Unknown result type (might be due to invalid IL or missing references) //IL_0571: Unknown result type (might be due to invalid IL or missing references) //IL_0576: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: 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) //IL_02fa: 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_0301: 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) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: 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_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) _plugin = plugin; _authoritative = authoritative; _recorder = recorder; _segment = new List(recorder.History.Items); PlayerSnapshot playerSnapshot = _segment[_segment.Count - 1]; _sourceStartTime = playerSnapshot.Timestamp - selectedDelay; _sourceEndTime = playerSnapshot.Timestamp; TrimToReplayWindow(); _mimicObject = new GameObject("MimicReplay_Mimic"); _visualContainer = new GameObject("Visual"); _visualContainer.transform.SetParent(_mimicObject.transform, false); PlayerSnapshot playerSnapshot2 = _segment[0]; _mimicObject.transform.position = playerSnapshot2.Position; _mimicObject.transform.rotation = playerSnapshot2.Rotation; MimicAppearanceResult mimicAppearanceResult = MimicAppearance.Create(source.GetComponent(), _visualContainer.transform); if (!mimicAppearanceResult.Success) { Object.Destroy((Object)(object)_mimicObject); throw new InvalidOperationException("Mimic visual clone failed: " + mimicAppearanceResult.Error); } _animator = mimicAppearanceResult.Animator; _visualFacing = mimicAppearanceResult.FacingTransform; if ((Object)(object)mimicAppearanceResult.FacingTransform != (Object)null) { Vector3 forward = mimicAppearanceResult.FacingTransform.forward; forward.y = 0f; Vector3 val = playerSnapshot2.Rotation * Vector3.forward; val.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude > 0.001f && ((Vector3)(ref val)).sqrMagnitude > 0.001f) { Quaternion val2 = Quaternion.FromToRotation(((Vector3)(ref forward)).normalized, ((Vector3)(ref val)).normalized); _visualContainer.transform.rotation = val2 * _visualContainer.transform.rotation; ManualLogSource log = Plugin.Log; float y = ((Quaternion)(ref val2)).eulerAngles.y; log.LogInfo((object)("Mimic visual facing calibrated yaw=" + y.ToString("F1"))); } } Bounds combinedBounds = MimicAppearance.GetCombinedBounds(_visualContainer); Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(((Bounds)(ref combinedBounds)).center.x, ((Bounds)(ref combinedBounds)).min.y, ((Bounds)(ref combinedBounds)).center.z); Vector3 val4 = playerSnapshot2.Position + Vector3.up * _plugin.VerticalOffset.Value; Transform transform = _visualContainer.transform; transform.position += val4 - val3; if (_plugin.TemporaryVisualDesyncDistance.Value > 0.01f) { float num = Random.Range(0f, (float)Math.PI * 2f); Vector3 val5 = new Vector3(Mathf.Cos(num), 0f, Mathf.Sin(num)) * _plugin.TemporaryVisualDesyncDistance.Value; Transform transform2 = _visualContainer.transform; transform2.position += val5; Plugin.Log.LogWarning((object)("Temporary visual desync enabled: visible body offset=" + ((Vector3)(ref val5)).ToString("F2") + " while collider/hitbox remains on mimic root")); } _capsule = _mimicObject.AddComponent(); _capsule.radius = 0.36f; _capsule.height = playerSnapshot2.CapsuleHeight; _capsule.center = Vector3.up * (_capsule.height * 0.5f); ((Collider)_capsule).isTrigger = false; Rigidbody val6 = _mimicObject.AddComponent(); val6.isKinematic = true; val6.useGravity = false; _agent = _mimicObject.AddComponent(); ((Behaviour)_agent).enabled = false; _agent.radius = 0.36f; _agent.height = 1.8f; _agent.speed = _plugin.ChaseSpeed.Value; _agent.acceleration = 12f; _agent.angularSpeed = _plugin.TurnSpeed.Value; _agent.stoppingDistance = Mathf.Max(0.2f, _plugin.AttackRange.Value * 0.75f); _agent.autoRepath = true; _agent.autoTraverseOffMeshLink = true; _agent.updateRotation = false; _agent.autoBraking = true; _agent.obstacleAvoidanceType = (ObstacleAvoidanceType)4; _agent.avoidancePriority = Random.Range(25, 60); _enemyNavigation = _mimicObject.AddComponent(); ((Behaviour)_enemyNavigation).enabled = false; _voiceSource = _mimicObject.AddComponent(); _voiceSource.playOnAwake = false; _voiceSource.loop = false; _voiceSource.spatialBlend = 1f; _voiceSource.minDistance = 2f; _voiceSource.maxDistance = 18f; _voiceSource.rolloffMode = (AudioRolloffMode)1; _nextVoiceTime = Time.time + Random.Range(6f, 14f); _localStartTime = Time.time; _lastProgressPosition = playerSnapshot2.Position; _lastMovementPosition = playerSnapshot2.Position; _lastReplayPosition = playerSnapshot2.Position; BuildTrails(); LogMode("created", null); } private void TrimToReplayWindow() { while (_segment.Count > 2 && _segment[1].Timestamp < _sourceStartTime) { _segment.RemoveAt(0); } } public void Tick() { //IL_006d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_mimicObject == (Object)null) && _segment.Count >= 2) { UpdateVision(); if (_mode == MimicMode.Replay) { TickReplay(); } else if (_mode == MimicMode.Chase) { TickChase(); } else if (_mode == MimicMode.Attack) { TickAttack(); } else { TickStuckRecovery(); } TickVoiceReplay(); UpdateReplayTrail(_mimicObject.transform.position); if (_plugin.VerboseLogging.Value && Time.unscaledTime >= _nextVerboseLogTime) { _nextVerboseLogTime = Time.unscaledTime + 1f; LogPath("periodic"); } } } private void TickReplay() { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: 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_0104: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: 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_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014f: 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_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_015e: 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_0174: 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) if ((Object)(object)_chaseTarget != (Object)null) { EnterChase("target detected"); return; } float num = _sourceEndTime - _sourceStartTime; if (num <= 0f) { return; } float num2 = (Time.time - _localStartTime) * _plugin.PlaybackSpeed.Value; if (num2 >= num) { ChooseNextRoute(); num = _sourceEndTime - _sourceStartTime; num2 = 0f; } float num3 = (_reversePlayback ? (_sourceEndTime - num2) : (_sourceStartTime + num2)); FindNeighbours(num3, out var previous, out var next); float num4 = next.Timestamp - previous.Timestamp; float num5 = ((num4 > 0.0001f) ? Mathf.Clamp01((num3 - previous.Timestamp) / num4) : 0f); _mimicObject.transform.position = Vector3.Lerp(previous.Position, next.Position, num5); Vector3 direction = _mimicObject.transform.position - _lastReplayPosition; direction.y = 0f; _lastReplayPosition = _mimicObject.transform.position; if (((Vector3)(ref direction)).sqrMagnitude > 4E-06f) { UpdateFacing(direction); } else { Quaternion val = Quaternion.Slerp(previous.Rotation, next.Rotation, num5); if (_reversePlayback) { val *= Quaternion.Euler(0f, 180f, 0f); } _mimicObject.transform.rotation = val; } ApplyCapsule(previous.CapsuleHeight); UpdateFakeHeldObject(previous, next, num5); if (next.InteractStarted && next.Timestamp != _lastInteractionTimestamp) { _lastInteractionTimestamp = next.Timestamp; TryOpenNearbyDoor("recorded interaction"); } UpdateAnimation(previous, next, num4); } private void EnterChase(string reason) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_chaseTarget == (Object)null)) { NavMeshHit val = default(NavMeshHit); if (!NavMesh.SamplePosition(_mimicObject.transform.position, ref val, 0.75f, -1)) { EnterStuckRecovery(reason + "; replay endpoint is not on NavMesh"); return; } ((Behaviour)_agent).enabled = true; ((Behaviour)_enemyNavigation).enabled = true; _agent.Warp(((NavMeshHit)(ref val)).position); ApplyCapsule(1.8f); _lastProgressPosition = _mimicObject.transform.position; _lastMovementPosition = _mimicObject.transform.position; _nextStuckCheck = Time.time + 0.75f; Transition(MimicMode.Chase, reason); Repath("enter chase"); } } private void TickChase() { //IL_003d: 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_006f: 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) if ((Object)(object)_chaseTarget == (Object)null) { EnterReplay("target lost"); return; } Transform targetTransform = GetTargetTransform(_chaseTarget); UpdateChasePosture(_chaseTarget); float num = Vector3.Distance(_mimicObject.transform.position, targetTransform.position); if (num <= _plugin.AttackRange.Value) { Transition(MimicMode.Attack, "target entered attack range"); BeginAttack(targetTransform.position); return; } if (Time.time >= _nextRepathTime) { Repath("interval"); } if (Time.time >= _nextDoorCheck) { TryOpenNearbyDoor("chase proximity"); } UpdateFacing(GetNavigationFacingDirection()); CheckStuck(num); UpdateChaseAnimation(); } private void TickAttack() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_chaseTarget != (Object)null) { UpdateChasePosture(_chaseTarget); } if (Time.time < _attackStateUntil) { if (((Behaviour)_agent).enabled && _agent.isOnNavMesh) { _agent.speed = _plugin.ChaseSpeed.Value; UpdateFacing(GetNavigationFacingDirection()); } } else if ((Object)(object)_chaseTarget == (Object)null) { EnterReplay("attack retreat complete; target lost"); } else { Transition(MimicMode.Chase, "attack retreat complete"); Repath("after attack"); } } private void BeginAttack(Vector3 targetPosition) { //IL_00b0: 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_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: 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) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: 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_012f: Unknown result type (might be due to invalid IL or missing references) //IL_013c: 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_0146: 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_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: 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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_018e: 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) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_chaseTarget == (Object)null) { return; } PlayerAvatar chaseTarget = _chaseTarget; if (_authoritative && (!_plugin.SpectatorMode || !((Object)(object)chaseTarget == (Object)(object)SemiFunc.PlayerAvatarLocal())) && Time.time >= _nextAttackTime) { PlayerHealth val = (PlayerHealth)((PlayerHealthField != null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val != (Object)null) { _nextAttackTime = Time.time + _plugin.AttackCooldown.Value; val.Hurt(_plugin.AttackDamage.Value, false, -1, false); Vector3 val2 = targetPosition - _mimicObject.transform.position; val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude < 0.01f) { val2 = _mimicObject.transform.forward; } chaseTarget.ForceImpulse(((Vector3)(ref val2)).normalized * _plugin.KnockbackForce.Value + Vector3.up * (_plugin.KnockbackForce.Value * 0.3f)); _retreatDirection = -((Vector3)(ref val2)).normalized; _retreatDestination = _mimicObject.transform.position + _retreatDirection * 4f; NavMeshHit val3 = default(NavMeshHit); if (NavMesh.SamplePosition(_retreatDestination, ref val3, 2f, -1)) { _retreatDestination = ((NavMeshHit)(ref val3)).position; } if (((Behaviour)_agent).enabled && _agent.isOnNavMesh) { _agent.SetDestination(_retreatDestination); } _attackStateUntil = Time.time + Random.Range(3f, 5f); Plugin.Log.LogMessage((object)("Mimic attack target=" + ((Object)((Component)chaseTarget).gameObject).name + " retreatUntil=" + _attackStateUntil.ToString("F2"))); return; } } _attackStateUntil = Time.time + 0.25f; } private void TickStuckRecovery() { //IL_001b: 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_004a: 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_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_chaseTarget == (Object)null) { EnterReplay("stuck recovery has no target"); return; } float num = Vector3.Distance(_recoveryStartPosition, _mimicObject.transform.position); if (num >= 0.2f) { _lastProgressPosition = _mimicObject.transform.position; _nextStuckCheck = Time.time + 0.75f; Transition(MimicMode.Chase, "stock navigation restored progress after attempts=" + _recoveryAttempts); return; } if (Time.time >= _nextDoorCheck) { TryOpenNearbyDoor("stuck recovery"); } if (!(Time.time < _nextRepathTime)) { NavMeshHit val = default(NavMeshHit); if (!((Behaviour)_agent).enabled && NavMesh.SamplePosition(_mimicObject.transform.position, ref val, 0.75f, -1)) { ((Behaviour)_agent).enabled = true; ((Behaviour)_enemyNavigation).enabled = true; _agent.Warp(((NavMeshHit)(ref val)).position); } if (((Behaviour)_agent).enabled && _agent.isOnNavMesh) { _enemyNavigation.ResetPath(); Repath("stuck recovery"); _recoveryAttempts++; } _nextRepathTime = Time.time + 0.5f; } } private void Repath(string reason) { //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_004b: 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_00bf: Expected O, but got Unknown //IL_00ca: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Invalid comparison between Unknown and I4 //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Invalid comparison between Unknown and I4 //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) _nextRepathTime = Time.time + 0.3f; if ((Object)(object)_chaseTarget == (Object)null || !((Behaviour)_agent).enabled || !_agent.isOnNavMesh) { return; } Vector3 position = GetTargetTransform(_chaseTarget).position; NavMeshHit val = default(NavMeshHit); if (!NavMesh.SamplePosition(position, ref val, 1.5f, -1)) { Plugin.Log.LogWarning((object)("Mimic path target is outside NavMesh: " + ((Vector3)(ref position)).ToString("F2"))); } else { if (_hasPathDestination && Vector3.Distance(_lastPathDestination, ((NavMeshHit)(ref val)).position) < 0.2f && _agent.hasPath && (int)_agent.pathStatus != 2) { return; } NavMeshPath val2 = new NavMeshPath(); if (!NavMesh.CalculatePath(_mimicObject.transform.position, ((NavMeshHit)(ref val)).position, -1, val2) || (int)val2.status == 2 || val2.corners.Length < 2) { Plugin.Log.LogWarning((object)string.Concat("Mimic path rejected reason=", reason, " status=", val2.status, " corners=", val2.corners.Length, " target=", ((Object)((Component)_chaseTarget).gameObject).name)); return; } _agent.speed = _plugin.ChaseSpeed.Value; _enemyNavigation.SetDestination(((NavMeshHit)(ref val)).position); bool flag = _agent.hasPath || _agent.pathPending; if (flag) { _lastPathDestination = ((NavMeshHit)(ref val)).position; _hasPathDestination = true; } Plugin.Log.LogInfo((object)string.Concat("Mimic repath reason=", reason, " accepted=", flag, " calculatedStatus=", val2.status, " calculatedCorners=", val2.corners.Length, " target=", ((Object)((Component)_chaseTarget).gameObject).name)); LogPath(reason); } } private void CheckStuck(float targetDistance) { //IL_0039: 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_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) if (Time.time < _nextStuckCheck || targetDistance < _plugin.AttackRange.Value * 1.2f) { return; } _nextStuckCheck = Time.time + 0.75f; float num = Vector3.Distance(_lastProgressPosition, _mimicObject.transform.position); if (num < 0.12f) { if (_stuckSince <= 0f) { _stuckSince = Time.time; } if (Time.time - _stuckSince >= 2.25f) { string text = FindBlockingObjectName(); object[] array = new object[8] { "no progress for ", (Time.time - _stuckSince).ToString("F1"), "s; obstacle=", text, "; path=", _agent.pathStatus, "; desiredSpeed=", null }; Vector3 desiredVelocity = _agent.desiredVelocity; array[7] = ((Vector3)(ref desiredVelocity)).magnitude.ToString("F2"); EnterStuckRecovery(string.Concat(array)); } } else { _stuckSince = 0f; _lastProgressPosition = _mimicObject.transform.position; } } private void EnterStuckRecovery(string reason) { //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) _recoveryStartPosition = _mimicObject.transform.position; _recoveryAttempts = 0; _stuckSince = 0f; if (((Behaviour)_agent).enabled && _agent.isOnNavMesh) { _enemyNavigation.ResetPath(); } _nextRepathTime = Time.time + 0.1f; Transition(MimicMode.StuckRecovery, reason); } private string FindBlockingObjectName() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_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_0046: Unknown result type (might be due to invalid IL or missing references) Vector3 desiredVelocity = _agent.desiredVelocity; if (((Vector3)(ref desiredVelocity)).sqrMagnitude < 0.01f) { return "path/no desired velocity"; } RaycastHit val = default(RaycastHit); if (Physics.Raycast(_mimicObject.transform.position + Vector3.up * 0.8f, ((Vector3)(ref desiredVelocity)).normalized, ref val, 0.8f, -5, (QueryTriggerInteraction)1)) { return ((Object)((Component)((RaycastHit)(ref val)).collider).gameObject).name; } return "unknown"; } private void TryOpenNearbyDoor(string reason) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) _nextDoorCheck = Time.time + 0.5f; if (!_authoritative || DoorOpenMethod == null) { return; } PhysGrabHinge val = null; float num = 1.8f; PhysGrabHinge[] array = Object.FindObjectsOfType(); foreach (PhysGrabHinge val2 in array) { if (!((Object)(object)val2 == (Object)null)) { float num2 = Vector3.Distance(_mimicObject.transform.position, ((Component)val2).transform.position); if (num2 < num) { num = num2; val = val2; } } } if ((Object)(object)val == (Object)null) { return; } try { PhysGrabObject componentInParent = ((Component)val).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { componentInParent.EnemyInteractTimeSet(); } DoorOpenMethod.Invoke(val, null); Plugin.Log.LogInfo((object)("Mimic door detected=" + ((Object)((Component)val).gameObject).name + " distance=" + num.ToString("F2") + " action=PhysGrabHinge.OpenImpulse reason=" + reason)); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Mimic door open failed object=" + ((Object)((Component)val).gameObject).name + " error=" + ex.GetBaseException().Message)); } } private void EnterReplay(string reason) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (((Behaviour)_agent).enabled) { if (_agent.isOnNavMesh) { _agent.ResetPath(); } ((Behaviour)_agent).enabled = false; } ((Behaviour)_enemyNavigation).enabled = false; _hasPathDestination = false; _localStartTime = Time.time; _lastReplayPosition = _mimicObject.transform.position; Transition(MimicMode.Replay, reason); } private void Transition(MimicMode next, string reason) { if (_mode != next || !(reason != "created")) { MimicMode mode = _mode; _mode = next; Plugin.Log.LogMessage((object)string.Concat("Mimic mode ", mode, " -> ", next, " reason=", reason, " target=", TargetName())); } } private void LogMode(string reason, PlayerAvatar target) { Plugin.Log.LogMessage((object)string.Concat("Mimic mode=", _mode, " reason=", reason, " target=", ((Object)(object)target != (Object)null) ? ((Object)((Component)target).gameObject).name : "none")); } private void LogPath(string reason) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) string text = "agent-disabled"; int num = 0; if ((Object)(object)_agent != (Object)null && ((Behaviour)_agent).enabled && _agent.isOnNavMesh) { text = (_agent.pathPending ? "Pending" : ((object)_agent.pathStatus).ToString()); if (!_agent.pathPending && _agent.hasPath) { num = _agent.path.corners.Length; } } Plugin.Log.LogInfo((object)string.Concat("Mimic debug mode=", _mode, " target=", TargetName(), " pathStatus=", text, " corners=", num, " reason=", reason)); } private string TargetName() { if (!((Object)(object)_chaseTarget != (Object)null)) { return "none"; } return ((Object)((Component)_chaseTarget).gameObject).name; } private static Transform GetTargetTransform(PlayerAvatar avatar) { if (!((Object)(object)avatar.playerTransform != (Object)null)) { return ((Component)avatar).transform; } return avatar.playerTransform; } private void ApplyCapsule(float height) { //IL_0024: 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) height = Mathf.Clamp(height, 0.65f, 1.8f); _capsule.height = height; _capsule.center = Vector3.up * (height * 0.5f); _agent.height = height; } private void UpdateChasePosture(PlayerAvatar target) { bool flag = ReadAvatarBool(PlayerCrawlingField, target); bool flag2 = flag || ReadAvatarBool(PlayerCrouchingField, target); float num = (flag ? 0.65f : (flag2 ? 1.05f : 1.8f)); if (_chaseCrouching != flag2 || _chaseCrawling != flag || !(Mathf.Abs(_capsule.height - num) < 0.01f)) { _chaseCrouching = flag2; _chaseCrawling = flag; ApplyCapsule(num); if (_plugin.VerboseLogging.Value) { Plugin.Log.LogInfo((object)("Mimic chase posture=" + (flag ? "crawl" : (flag2 ? "crouch" : "stand")) + " target=" + (((Object)(object)target != (Object)null) ? ((Object)((Component)target).gameObject).name : "none") + " capsule=" + num.ToString("F2"))); } } } private static bool ReadAvatarBool(FieldInfo field, PlayerAvatar avatar) { if (field == null || (Object)(object)avatar == (Object)null) { return false; } try { return Convert.ToBoolean(field.GetValue(avatar)); } catch { return false; } } private void UpdateVision() { //IL_0094: 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_009e: 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_00a5: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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) if (Time.time < _nextVisionCheck) { return; } _nextVisionCheck = Time.time + 0.2f; PlayerAvatar chaseTarget = _chaseTarget; PlayerAvatar val = null; float num = _plugin.VisionDistance.Value; PlayerAvatar[] array = Object.FindObjectsOfType(); foreach (PlayerAvatar val2 in array) { if (!((Object)(object)val2 == (Object)null) && ((Component)val2).gameObject.activeInHierarchy && (!_plugin.SpectatorMode || !((Object)(object)val2 == (Object)(object)SemiFunc.PlayerAvatarLocal()))) { Transform targetTransform = GetTargetTransform(val2); Vector3 val3 = _mimicObject.transform.position + Vector3.up; float num2 = Vector3.Distance(val3, targetTransform.position + Vector3.up); if (!(num2 >= num) && HasLineOfSight(val3, targetTransform, ((Component)val2).transform)) { num = num2; val = val2; } } } if ((Object)(object)val != (Object)null) { _chaseTarget = val; _lastSeenTime = Time.time; } else if ((Object)(object)chaseTarget != (Object)null && Time.time - _lastSeenTime <= 5f) { _chaseTarget = chaseTarget; } else { _chaseTarget = null; } } private static bool HasLineOfSight(Vector3 origin, Transform target, Transform root) { //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_000b: 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_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) Vector3 val = target.position + Vector3.up; Vector3 val2 = val - origin; RaycastHit val3 = default(RaycastHit); if (!Physics.Raycast(origin, ((Vector3)(ref val2)).normalized, ref val3, ((Vector3)(ref val2)).magnitude, -5, (QueryTriggerInteraction)1)) { return true; } if (!((Object)(object)((RaycastHit)(ref val3)).transform == (Object)(object)root) && !((RaycastHit)(ref val3)).transform.IsChildOf(root) && !((Object)(object)((RaycastHit)(ref val3)).transform == (Object)(object)target)) { return ((RaycastHit)(ref val3)).transform.IsChildOf(target); } return true; } private void UpdateFacing(Vector3 direction) { //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_0027: 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_0038: 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) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_00d2: 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) direction.y = 0f; if (!(((Vector3)(ref direction)).sqrMagnitude < 0.0025f)) { Quaternion val = Quaternion.LookRotation(((Vector3)(ref direction)).normalized, Vector3.up); Vector3 forward = _mimicObject.transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude < 0.001f || Vector3.Dot(((Vector3)(ref forward)).normalized, ((Vector3)(ref direction)).normalized) < 0.2f) { _mimicObject.transform.rotation = val; return; } float num = 1f - Mathf.Exp((0f - Mathf.Max(2f, _plugin.TurnSpeed.Value / 90f)) * Time.deltaTime); _mimicObject.transform.rotation = Quaternion.Slerp(_mimicObject.transform.rotation, val, num); } } private Vector3 GetNavigationFacingDirection() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: 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_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_agent == (Object)null || !((Behaviour)_agent).enabled || !_agent.isOnNavMesh) { return Vector3.zero; } Vector3 result = _mimicObject.transform.position - _lastMovementPosition; result.y = 0f; _lastMovementPosition = _mimicObject.transform.position; if (((Vector3)(ref result)).sqrMagnitude > 4E-06f) { return result; } Vector3 result2 = _agent.steeringTarget - _mimicObject.transform.position; result2.y = 0f; if (((Vector3)(ref result2)).sqrMagnitude > 0.01f) { return result2; } if (_agent.hasPath && !_agent.pathPending) { Vector3[] corners = _agent.path.corners; for (int i = 0; i < corners.Length; i++) { Vector3 result3 = corners[i] - _mimicObject.transform.position; result3.y = 0f; if (((Vector3)(ref result3)).sqrMagnitude > 0.04f) { return result3; } } } Vector3 velocity = _agent.velocity; velocity.y = 0f; if (((Vector3)(ref velocity)).sqrMagnitude > 0.01f) { return velocity; } return Vector3.zero; } private void TickVoiceReplay() { if ((Object)(object)_voiceSource == (Object)null || _voiceSource.isPlaying || Time.time < _nextVoiceTime) { return; } _nextVoiceTime = Time.time + Random.Range(8f, 20f); VoicePhraseCapture voiceCapture = _recorder.VoiceCapture; if ((Object)(object)voiceCapture == (Object)null) { return; } if (!voiceCapture.TryGetRandomPhrase(out var samples, out var channels, out var sampleRate)) { _nextVoiceTime = Time.time + 1f; return; } if ((Object)(object)_voiceSource.clip != (Object)null) { Object.Destroy((Object)(object)_voiceSource.clip); } int num = samples.Length / Math.Max(1, channels); float num2 = 0f; for (int i = 0; i < samples.Length; i++) { num2 = Mathf.Max(num2, Mathf.Abs(samples[i])); } if (num2 > 0.0001f) { float num3 = Mathf.Min(5f, 0.88f / num2); for (int j = 0; j < samples.Length; j++) { samples[j] = Mathf.Clamp(samples[j] * num3, -1f, 1f); } } AudioClip val = AudioClip.Create("MimicPhrase_" + voiceCapture.OwnerName, num, channels, sampleRate, false); val.SetData(samples, 0); _voiceSource.clip = val; _voiceSource.pitch = Random.Range(0.96f, 1.04f); _voiceSource.volume = 1f; _voiceSource.Play(); Plugin.Log.LogInfo((object)("Mimic voice phrase player=" + voiceCapture.OwnerName + " duration=" + val.length.ToString("F2") + "s")); } private void UpdateChaseAnimation() { //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) if (!((Object)(object)_animator == (Object)null)) { Vector3 velocity = _agent.velocity; float magnitude = ((Vector3)(ref velocity)).magnitude; _animator.SetBool("Moving", magnitude > 0.12f); _animator.SetBool("Sprinting", magnitude > 3.2f); _animator.SetBool("Crouching", _chaseCrouching); _animator.SetBool("Crawling", _chaseCrawling); _animator.speed = ((magnitude > 0.12f) ? Mathf.Clamp(magnitude / 1.8f, 0.65f, 1.8f) : 1f); } } private void UpdateAnimation(PlayerSnapshot previous, PlayerSnapshot next, float span) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_animator == (Object)null) && !(span <= 0.0001f)) { Vector3 val = Vector3.Lerp(previous.Velocity, next.Velocity, 0.5f); if (_reversePlayback) { val = -val; } Vector2 val2 = new Vector2(val.x, val.z); float magnitude = ((Vector2)(ref val2)).magnitude; bool flag = next.JumpStarted || (!next.IsGrounded && val.y > 0.25f); bool flag2 = !next.IsGrounded && val.y < -0.25f; bool flag3 = magnitude > 3.2f; _animator.SetBool("Moving", magnitude > 0.12f); _animator.SetBool("Sprinting", flag3); _animator.SetBool("Jumping", flag); _animator.SetBool("Falling", flag2); _animator.SetBool("Crouching", previous.IsCrouching); _animator.SetBool("Crawling", previous.IsCrawling); _animator.speed = ((magnitude > 0.12f) ? Mathf.Clamp(magnitude / 1.8f, 0.65f, 1.8f) : 1f); if (flag && !_wasJumping) { _animator.SetTrigger("JumpingImpulse"); } if (flag3 && !_wasSprinting) { _animator.SetTrigger("SprintingImpulse"); } _wasJumping = flag; _wasSprinting = flag3; } } private void UpdateFakeHeldObject(PlayerSnapshot previous, PlayerSnapshot next, float t) { //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013e: 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_015f: 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_016b: 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) PlayerSnapshot playerSnapshot = ((t < 0.5f) ? previous : next); GameObject heldObjectSource = playerSnapshot.HeldObjectSource; if ((Object)(object)heldObjectSource == (Object)null) { ClearFakeHeldObject(); return; } int instanceID = ((Object)heldObjectSource).GetInstanceID(); if ((Object)(object)_fakeHeldObject == (Object)null || instanceID != _fakeHeldSourceId) { ClearFakeHeldObject(); _fakeHeldObject = CreateVisualOnlyHeldObject(heldObjectSource); _fakeHeldSourceId = instanceID; if ((Object)(object)_fakeHeldObject != (Object)null) { _fakeHeldObject.transform.SetParent(_mimicObject.transform, false); Plugin.Log.LogInfo((object)("Mimic fake held visual created source=" + ((Object)heldObjectSource).name + " renderers=" + _fakeHeldObject.GetComponentsInChildren(true).Length)); } } if (!((Object)(object)_fakeHeldObject == (Object)null)) { bool flag = (Object)(object)previous.HeldObjectSource != (Object)null && (Object)(object)next.HeldObjectSource != (Object)null && ((Object)previous.HeldObjectSource).GetInstanceID() == ((Object)next.HeldObjectSource).GetInstanceID(); _fakeHeldObject.transform.localPosition = (flag ? Vector3.Lerp(previous.HeldLocalPosition, next.HeldLocalPosition, t) : playerSnapshot.HeldLocalPosition); _fakeHeldObject.transform.localRotation = (flag ? Quaternion.Slerp(previous.HeldLocalRotation, next.HeldLocalRotation, t) : playerSnapshot.HeldLocalRotation); } } private static GameObject CreateVisualOnlyHeldObject(GameObject source) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00d4: 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_00f0: 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) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: 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_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0122: 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_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("FakeHeld_" + ((Object)source).name); Renderer[] componentsInChildren = source.GetComponentsInChildren(true); foreach (Renderer val2 in componentsInChildren) { if (!val2.enabled) { continue; } Mesh val3 = null; MeshRenderer val4 = (MeshRenderer)(object)((val2 is MeshRenderer) ? val2 : null); if ((Object)(object)val4 != (Object)null) { MeshFilter component = ((Component)val2).GetComponent(); if ((Object)(object)component != (Object)null) { val3 = component.sharedMesh; } } else { SkinnedMeshRenderer val5 = (SkinnedMeshRenderer)(object)((val2 is SkinnedMeshRenderer) ? val2 : null); if ((Object)(object)val5 != (Object)null) { val3 = new Mesh(); val5.BakeMesh(val3); } } if (!((Object)(object)val3 == (Object)null)) { GameObject val6 = new GameObject(((Object)((Component)val2).gameObject).name + "_FakeVisual"); val6.transform.SetParent(val.transform, false); val6.transform.localPosition = source.transform.InverseTransformPoint(((Component)val2).transform.position); val6.transform.localRotation = Quaternion.Inverse(source.transform.rotation) * ((Component)val2).transform.rotation; Vector3 lossyScale = source.transform.lossyScale; Vector3 lossyScale2 = ((Component)val2).transform.lossyScale; val6.transform.localScale = new Vector3((Mathf.Abs(lossyScale.x) > 0.0001f) ? (lossyScale2.x / lossyScale.x) : lossyScale2.x, (Mathf.Abs(lossyScale.y) > 0.0001f) ? (lossyScale2.y / lossyScale.y) : lossyScale2.y, (Mathf.Abs(lossyScale.z) > 0.0001f) ? (lossyScale2.z / lossyScale.z) : lossyScale2.z); val6.AddComponent().sharedMesh = val3; MeshRenderer val7 = val6.AddComponent(); ((Renderer)val7).sharedMaterials = val2.sharedMaterials; ((Renderer)val7).shadowCastingMode = val2.shadowCastingMode; ((Renderer)val7).receiveShadows = val2.receiveShadows; } } if (val.GetComponentsInChildren(true).Length == 0) { Object.Destroy((Object)(object)val); return null; } return val; } private void ClearFakeHeldObject() { if ((Object)(object)_fakeHeldObject != (Object)null) { Object.Destroy((Object)(object)_fakeHeldObject); } _fakeHeldObject = null; _fakeHeldSourceId = 0; } private void ChooseNextRoute() { if (_reversePlayback || Random.value < 0.5f || !TryContinueWithNewHistory()) { _reversePlayback = !_reversePlayback; _localStartTime = Time.time; Plugin.Log.LogMessage((object)("Replay route choice: reverse=" + _reversePlayback)); } } private bool TryContinueWithNewHistory() { IList items = _recorder.History.Items; if (items.Count < 2 || items[items.Count - 1].Timestamp <= _sourceEndTime + 0.2f) { return false; } List list = new List(); for (int i = 0; i < items.Count; i++) { if (items[i].Timestamp >= _sourceEndTime - 0.15f) { list.Add(items[i]); } } if (list.Count < 2) { return false; } _segment = list; _sourceStartTime = list[0].Timestamp; _sourceEndTime = list[list.Count - 1].Timestamp; _reversePlayback = false; _localStartTime = Time.time; return true; } private void FindNeighbours(float time, out PlayerSnapshot previous, out PlayerSnapshot next) { previous = _segment[0]; next = _segment[_segment.Count - 1]; for (int i = 1; i < _segment.Count; i++) { if (_segment[i].Timestamp >= time) { previous = _segment[i - 1]; next = _segment[i]; break; } } } private void BuildTrails() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) _recordedTrail = CreateTrail("RecordedTrail", new Color(0f, 0.8f, 1f, 0.8f), 0.035f); _recordedTrail.positionCount = _segment.Count; for (int i = 0; i < _segment.Count; i++) { _recordedTrail.SetPosition(i, _segment[i].Position); } _replayTrail = CreateTrail("ReplayTrail", new Color(1f, 0.2f, 0.7f, 0.9f), 0.06f); _replayTrail.positionCount = 1; _replayTrail.SetPosition(0, _segment[0].Position); } private LineRenderer CreateTrail(string name, Color color, float width) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); LineRenderer val2 = val.AddComponent(); val2.useWorldSpace = true; val2.startWidth = width; val2.endWidth = width; ((Renderer)val2).material = new Material(Shader.Find("Sprites/Default")); val2.startColor = color; val2.endColor = color; ((Renderer)val2).enabled = _plugin.DebugTrail.Value; return val2; } private void UpdateReplayTrail(Vector3 position) { //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: 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_00af: 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) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_recordedTrail != (Object)null) { ((Renderer)_recordedTrail).enabled = _plugin.DebugTrail.Value; } if ((Object)(object)_replayTrail == (Object)null) { return; } ((Renderer)_replayTrail).enabled = _plugin.DebugTrail.Value; if (!_plugin.DebugTrail.Value) { return; } int num = Mathf.Min(_replayTrail.positionCount + 1, 300); Vector3[] array = (Vector3[])(object)new Vector3[num]; int positions = _replayTrail.GetPositions(array); if (positions >= num) { for (int i = 1; i < num; i++) { ref Vector3 reference = ref array[i - 1]; reference = array[i]; } array[num - 1] = position; } else { array[positions] = position; } _replayTrail.positionCount = num; _replayTrail.SetPositions(array); } public void Dispose() { if ((Object)(object)_recordedTrail != (Object)null) { Object.Destroy((Object)(object)((Component)_recordedTrail).gameObject); } if ((Object)(object)_replayTrail != (Object)null) { Object.Destroy((Object)(object)((Component)_replayTrail).gameObject); } if ((Object)(object)_mimicObject != (Object)null) { Object.Destroy((Object)(object)_mimicObject); } _plugin.RemoveMimic(this); } } public class PlayerRecorder { private readonly Plugin _plugin; private readonly SnapshotRingBuffer _history; private float _lastRecordTime; private float _nextVerboseLogTime; private readonly Transform _trackedTransform; private readonly Transform _facingTransform; private bool _previousGrounded = true; private bool _previousInteract; private float _nextVoiceAttachTime; private float _nextVoiceDiagnosticTime; private static readonly BindingFlags StateFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private static readonly FieldInfo VelocityField = typeof(PlayerAvatar).GetField("rbVelocity", StateFlags); private static readonly FieldInfo GroundedField = typeof(PlayerAvatar).GetField("isGrounded", StateFlags); private static readonly FieldInfo CrouchingField = typeof(PlayerAvatar).GetField("isCrouching", StateFlags); private static readonly FieldInfo CrawlingField = typeof(PlayerAvatar).GetField("isCrawling", StateFlags); private static readonly FieldInfo InteractField = typeof(PlayerAvatar).GetField("Interact", StateFlags); private static readonly FieldInfo VoiceChatField = typeof(PlayerAvatar).GetField("voiceChat", StateFlags); private static readonly FieldInfo VoiceAudioSourceField = typeof(PlayerVoiceChat).GetField("audioSource", StateFlags); private static readonly FieldInfo PhysGrabberField = typeof(PlayerAvatar).GetField("physGrabber", StateFlags); private static readonly FieldInfo GrabbedPhysObjectField = typeof(PhysGrabber).GetField("grabbedPhysGrabObject", StateFlags); public PlayerAvatar Avatar { get; private set; } public GameObject TargetPlayer { get; private set; } public SnapshotRingBuffer History => _history; public Transform TrackedTransform => _trackedTransform; public VoicePhraseCapture VoiceCapture { get; private set; } public PlayerRecorder(PlayerAvatar avatar, Plugin plugin) { Avatar = avatar; TargetPlayer = ((Component)avatar).gameObject; _plugin = plugin; _trackedTransform = (((Object)(object)avatar.playerTransform != (Object)null) ? avatar.playerTransform : ((Component)avatar).transform); _facingTransform = ResolveFacingTransform(avatar) ?? _trackedTransform; _history = new SnapshotRingBuffer(Math.Max(2, plugin.RecordingRateHz.Value * plugin.HistorySeconds.Value)); _lastRecordTime = Time.time; VoiceCapture = AttachVoiceCapture(avatar); } public void Tick() { //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_0200: 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) if ((Object)(object)TargetPlayer == (Object)null || !TargetPlayer.activeInHierarchy) { return; } if ((Object)(object)VoiceCapture == (Object)null && Time.time >= _nextVoiceAttachTime) { _nextVoiceAttachTime = Time.time + 2f; VoiceCapture = AttachVoiceCapture(Avatar); } if (_plugin.VerboseLogging.Value && (Object)(object)VoiceCapture != (Object)null && Time.time >= _nextVoiceDiagnosticTime) { _nextVoiceDiagnosticTime = Time.time + 5f; Plugin.Log.LogInfo((object)("Voice capture stats player=" + VoiceCapture.OwnerName + " frames=" + VoiceCapture.FramesReceived + " peak=" + VoiceCapture.PeakLevel.ToString("F5") + " phrases=" + VoiceCapture.PhrasesCompleted)); } float time = Time.time; float num = 1f / (float)Math.Max(1, _plugin.RecordingRateHz.Value); if (!(time - _lastRecordTime < num)) { _lastRecordTime = time; PlayerSnapshot playerSnapshot = CreateSnapshot(time); _history.Add(playerSnapshot); if (_plugin.VerboseLogging.Value && Time.unscaledTime >= _nextVerboseLogTime) { _nextVerboseLogTime = Time.unscaledTime + 1f; ManualLogSource log = Plugin.Log; object[] array = new object[8] { "Recorder player=", ((Object)TargetPlayer).name, " playerPos=", null, null, null, null, null }; Vector3 position = _trackedTransform.position; array[3] = ((Vector3)(ref position)).ToString("F3"); array[4] = " latestPos="; Vector3 position2 = playerSnapshot.Position; array[5] = ((Vector3)(ref position2)).ToString("F3"); array[6] = " snapshots="; array[7] = _history.Count; log.LogInfo((object)string.Concat(array)); } } } private PlayerSnapshot CreateSnapshot(float timestamp) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_0020: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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_004a: 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_0116: 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_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: 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_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: 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_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: 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_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: 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) Vector3 position = _trackedTransform.position; Quaternion rotation = _facingTransform.rotation; Quaternion val = Quaternion.Euler(0f, ((Quaternion)(ref rotation)).eulerAngles.y, 0f); Quaternion headRotation = val; Vector3 velocity = ReadVector3(VelocityField, Avatar); string animationState = ((((Vector3)(ref velocity)).sqrMagnitude > 0.05f) ? "moving" : "idle"); bool flag = ReadBool(GroundedField, Avatar); bool flag2 = ReadBool(CrouchingField, Avatar); bool flag3 = ReadBool(CrawlingField, Avatar); bool jumpStarted = _previousGrounded && !flag && velocity.y > 0.1f; bool flag4 = ReadBool(InteractField, Avatar); bool interactStarted = flag4 && !_previousInteract; _previousGrounded = flag; _previousInteract = flag4; float capsuleHeight = (flag3 ? 0.65f : (flag2 ? 1.05f : 1.8f)); GameObject heldObjectSource = null; Vector3 heldLocalPosition = Vector3.zero; Quaternion heldLocalRotation = Quaternion.identity; PhysGrabber val2 = (PhysGrabber)((PhysGrabberField != null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val2 != (Object)null && val2.grabbed && (Object)(object)val2.grabbedObjectTransform != (Object)null) { PhysGrabObject val3 = (PhysGrabObject)((GrabbedPhysObjectField != null) ? /*isinst with value type is only supported in some contexts*/: null); Transform val4 = (((Object)(object)val3 != (Object)null) ? ((Component)val3).transform : val2.grabbedObjectTransform); heldObjectSource = ((Component)val4).gameObject; heldLocalPosition = Quaternion.Inverse(val) * (val4.position - position); heldLocalRotation = Quaternion.Inverse(val) * val4.rotation; } return new PlayerSnapshot(timestamp, position, val, headRotation, flag2, flag3, flag, jumpStarted, interactStarted, capsuleHeight, velocity, animationState, heldObjectSource, heldLocalPosition, heldLocalRotation); } private static bool ReadBool(FieldInfo field, object instance) { if (field != null) { return (bool)field.GetValue(instance); } return false; } private static Vector3 ReadVector3(FieldInfo field, object instance) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (!(field != null)) { return Vector3.zero; } return (Vector3)field.GetValue(instance); } private static Transform ResolveFacingTransform(PlayerAvatar avatar) { FieldInfo field = typeof(PlayerAvatar).GetField("playerAvatarVisuals", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); Component val = (Component)((field != null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val == (Object)null) { return null; } FieldInfo field2 = ((object)val).GetType().GetField("animBotRoot", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); GameObject val2 = (GameObject)((field2 != null) ? /*isinst with value type is only supported in some contexts*/: null); if (!((Object)(object)val2 != (Object)null)) { return val.transform; } return val2.transform; } private static VoicePhraseCapture AttachVoiceCapture(PlayerAvatar avatar) { PlayerVoiceChat val = (PlayerVoiceChat)((VoiceChatField != null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val == (Object)null) { val = ((Component)avatar).GetComponentInChildren(true); } AudioSource val2 = (AudioSource)(((Object)(object)val != (Object)null && VoiceAudioSourceField != null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val2 == (Object)null) { return null; } VoicePhraseCapture voicePhraseCapture = ((Component)val2).GetComponent(); if ((Object)(object)voicePhraseCapture == (Object)null) { voicePhraseCapture = ((Component)val2).gameObject.AddComponent(); } bool isLocalInput = (Object)(object)avatar == (Object)(object)SemiFunc.PlayerAvatarLocal(); voicePhraseCapture.Initialize(((Object)((Component)avatar).gameObject).name, isLocalInput); Plugin.Log.LogInfo((object)("Voice phrase capture attached player=" + ((Object)((Component)avatar).gameObject).name + " source=" + ((Object)((Component)val2).gameObject).name)); return voicePhraseCapture; } } public class PlayerSnapshot { public readonly float Timestamp; public readonly Vector3 Position; public readonly Quaternion Rotation; public readonly Quaternion HeadRotation; public readonly bool IsCrouching; public readonly bool IsCrawling; public readonly bool IsGrounded; public readonly bool JumpStarted; public readonly bool InteractStarted; public readonly float CapsuleHeight; public readonly Vector3 Velocity; public readonly string AnimationState; public readonly GameObject HeldObjectSource; public readonly Vector3 HeldLocalPosition; public readonly Quaternion HeldLocalRotation; public PlayerSnapshot(float timestamp, Vector3 position, Quaternion rotation, Quaternion headRotation, bool isCrouching, bool isCrawling, bool isGrounded, bool jumpStarted, bool interactStarted, float capsuleHeight, Vector3 velocity, string animationState, GameObject heldObjectSource, Vector3 heldLocalPosition, Quaternion heldLocalRotation) { //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_0015: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_0056: 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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) Timestamp = timestamp; Position = position; Rotation = rotation; HeadRotation = headRotation; IsCrouching = isCrouching; IsCrawling = isCrawling; IsGrounded = isGrounded; JumpStarted = jumpStarted; InteractStarted = interactStarted; CapsuleHeight = capsuleHeight; Velocity = velocity; AnimationState = animationState; HeldObjectSource = heldObjectSource; HeldLocalPosition = heldLocalPosition; HeldLocalRotation = heldLocalRotation; } } public class SnapshotRingBuffer { private readonly List _items = new List(); private readonly int _capacity; public int Count => _items.Count; public IList Items => _items; public PlayerSnapshot this[int index] => _items[index]; public SnapshotRingBuffer(int capacity) { _capacity = capacity; } public void Add(PlayerSnapshot snapshot) { _items.Add(snapshot); if (_items.Count > _capacity) { _items.RemoveAt(0); } } public void Clear() { _items.Clear(); } public IEnumerable GetRange(int start, int count) { return _items.Skip(start).Take(count).ToList(); } } public sealed class VoicePhraseCapture : MonoBehaviour { private sealed class Phrase { internal float[] Samples; internal int Channels; internal int SampleRate; } private readonly object _sync = new object(); private readonly List _active = new List(); private readonly List _phrases = new List(); private int _silentSamples; private int _lastSpeechSample; private int _channels = 1; private int _sampleRate = 48000; private string _ownerName = "unknown"; private bool _isLocalInput; private static VoicePhraseCapture _localCapture; private int _framesReceived; private int _phrasesCompleted; private int _peakMilli; internal string OwnerName => _ownerName; internal int FramesReceived => _framesReceived; internal int PhrasesCompleted => _phrasesCompleted; internal float PeakLevel => (float)_peakMilli / 1000000f; internal void Initialize(string ownerName, bool isLocalInput) { _ownerName = ownerName; _isLocalInput = isLocalInput; if (isLocalInput) { _localCapture = this; } } private void OnAudioFilterRead(float[] data, int channels) { if (!_isLocalInput) { AcceptSamples(data, channels, AudioSettings.outputSampleRate); } } internal static void AcceptLocalFrame(float[] data) { VoicePhraseCapture localCapture = _localCapture; if ((Object)(object)localCapture != (Object)null) { localCapture.AcceptSamples(data, 1, 48000); } } internal static void AcceptLocalShortFrame(short[] data) { VoicePhraseCapture localCapture = _localCapture; if (!((Object)(object)localCapture == (Object)null) && data != null && data.Length != 0) { float[] array = new float[data.Length]; for (int i = 0; i < data.Length; i++) { array[i] = (float)data[i] / 32768f; } localCapture.AcceptSamples(array, 1, 48000); } } internal static void AcceptLocalPcm16(IntPtr buffer, int byteLength, int channels, int sampleRate) { VoicePhraseCapture localCapture = _localCapture; if (!((Object)(object)localCapture == (Object)null) && !(buffer == IntPtr.Zero) && byteLength >= 2) { int num = byteLength / 2; short[] array = new short[num]; Marshal.Copy(buffer, array, 0, num); float[] array2 = new float[num]; for (int i = 0; i < num; i++) { array2[i] = (float)array[i] / 32768f; } localCapture.AcceptSamples(array2, channels, sampleRate); } } private void AcceptSamples(float[] data, int channels, int sampleRate) { if (data == null || data.Length == 0) { return; } Interlocked.Increment(ref _framesReceived); _channels = Math.Max(1, channels); _sampleRate = Math.Max(8000, sampleRate); double num = 0.0; for (int i = 0; i < data.Length; i++) { num += (double)(data[i] * data[i]); } double num2 = Math.Sqrt(num / (double)data.Length); int num3 = (int)(num2 * 1000000.0); int num4 = _peakMilli; while (num3 > num4) { int num5 = Interlocked.CompareExchange(ref _peakMilli, num3, num4); if (num5 == num4) { break; } num4 = num5; } bool flag = num2 >= 0.0045; lock (_sync) { if (flag || _active.Count > 0) { _active.AddRange(data); if (flag) { _silentSamples = 0; _lastSpeechSample = _active.Count; } else { _silentSamples += data.Length; } } int num6 = (int)((float)(_sampleRate * _channels) * 0.55f); int num7 = _sampleRate * _channels * 12; if (_active.Count >= num7 || (_active.Count > 0 && _silentSamples >= num6)) { FinishPhrase(); } } } private void OnDestroy() { if ((Object)(object)_localCapture == (Object)(object)this) { _localCapture = null; } } private void FinishPhrase() { int num = (int)((float)(_sampleRate * _channels) * 0.28f); if (_lastSpeechSample >= num) { float[] array = new float[_lastSpeechSample]; _active.CopyTo(0, array, 0, _lastSpeechSample); _phrases.Add(new Phrase { Samples = array, Channels = _channels, SampleRate = _sampleRate }); Interlocked.Increment(ref _phrasesCompleted); while (_phrases.Count > 12) { _phrases.RemoveAt(0); } } _active.Clear(); _silentSamples = 0; _lastSpeechSample = 0; } internal bool TryGetRandomPhrase(out float[] samples, out int channels, out int sampleRate) { lock (_sync) { if (_phrases.Count == 0) { samples = null; channels = 1; sampleRate = 48000; return false; } Phrase phrase = _phrases[Random.Range(0, _phrases.Count)]; samples = (float[])phrase.Samples.Clone(); channels = phrase.Channels; sampleRate = phrase.SampleRate; return true; } } }