Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LethalPursuer v1.0.0
LethalPursuer.dll
Decompiled 6 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using LethalNetworkAPI; using LethalPursuer.Abilities; using LethalPursuer.Config; using LethalPursuer.Core; using LethalPursuer.Net; using LethalPursuer.Pursuer; using LethalPursuer.UI; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("ClientNetworkTransform")] [assembly: IgnoresAccessChecksTo("com.olegknyazev.softmask")] [assembly: IgnoresAccessChecksTo("DissonanceVoip")] [assembly: IgnoresAccessChecksTo("DunGen")] [assembly: IgnoresAccessChecksTo("DunGen.Integration.ASPP")] [assembly: IgnoresAccessChecksTo("DunGen.Integration.UnityNav")] [assembly: IgnoresAccessChecksTo("EasyTextEffects")] [assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")] [assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")] [assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")] [assembly: IgnoresAccessChecksTo("Unity.Burst")] [assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")] [assembly: IgnoresAccessChecksTo("Unity.Collections")] [assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")] [assembly: IgnoresAccessChecksTo("Unity.Jobs")] [assembly: IgnoresAccessChecksTo("Unity.Mathematics")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")] [assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")] [assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Components")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")] [assembly: IgnoresAccessChecksTo("Unity.Services.QoS")] [assembly: IgnoresAccessChecksTo("Unity.Services.Relay")] [assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")] [assembly: IgnoresAccessChecksTo("Unity.Timeline")] [assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.XR.CoreUtils")] [assembly: IgnoresAccessChecksTo("Unity.XR.Management")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.ConformanceAutomation")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.MetaQuestSupport")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.MockRuntime")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.OculusQuestSupport")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.RuntimeDebugger")] [assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.SpatialTracking")] [assembly: IgnoresAccessChecksTo("UnityEngine.UI")] [assembly: IgnoresAccessChecksTo("UnityEngine.XR.LegacyInputHelpers")] [assembly: AssemblyCompany("LethalPursuer")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+96bc9575a36f3de16bb18576f9e796cc4bf9a404")] [assembly: AssemblyProduct("LethalPursuer")] [assembly: AssemblyTitle("LethalPursuer")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace LethalPursuer { [BepInPlugin("LethalPursuer", "LethalPursuer", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private readonly Harmony _harmony = new Harmony("LethalPursuer"); public static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; PursuerConfig.Init(((BaseUnityPlugin)this).Config); WarnOnInvalidBinds(); NetworkHandler.Initialize(); _harmony.PatchAll(); Log.LogInfo((object)"LethalPursuer 1.0.0 loaded."); } private static void WarnOnInvalidBinds() { Check("ghost_toggle_key", PursuerConfig.GhostToggle); Check("phantom_state_key", PursuerConfig.Phantom); Check("monster_swap_key", PursuerConfig.MonsterSwap); Check("sound_emitter_key", PursuerConfig.SoundEmitter); Check("light_flicker_key", PursuerConfig.LightFlicker); Check("door_lock_key", PursuerConfig.DoorLock); Check("fake_blip_key", PursuerConfig.FakeBlip); Check("ghost_voice_key", PursuerConfig.GhostVoice); Check("masked_cycle_item_key", PursuerConfig.MaskedCycle); Check("leash_key", PursuerConfig.Leash); Check("breaker_key", PursuerConfig.Breaker); Check("vent_key", PursuerConfig.Vent); Check("item_curse_key", PursuerConfig.ItemCurse); Check("puppet_waypoint_button", PursuerConfig.PuppetWaypoint); Check("director_mode_key", PursuerConfig.DirectorMode); Check("countdown_toggle_key", PursuerConfig.CountdownToggle); static void Check(string name, KeyBind b) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!b.IsValid) { Log.LogWarning((object)$"Keybind '{name}' was unparseable; using fallback {b.Key}."); } } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "LethalPursuer"; public const string PLUGIN_NAME = "LethalPursuer"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace LethalPursuer.UI { public sealed class PursuerHud : MonoBehaviour { private static PursuerHud? _instance; private static bool IsHost { get { if ((Object)(object)StartOfRound.Instance != (Object)null) { return ((NetworkBehaviour)StartOfRound.Instance).IsHost; } return false; } } public static PursuerHud GetOrCreate() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if ((Object)(object)_instance != (Object)null) { return _instance; } GameObject val = new GameObject("LethalPursuer_PursuerHud"); Object.DontDestroyOnLoad((Object)val); _instance = val.AddComponent<PursuerHud>(); return _instance; } private void OnGUI() { //IL_0050: 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_006e: 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) //IL_007e: Expected O, but got Unknown //IL_00a1: Unknown result type (might be due to invalid IL or missing references) try { if (!IsHost) { return; } ModeManager instance = ModeManager.Instance; if (!((Object)(object)instance == (Object)null) && instance.Mode != PursuerMode.Player) { string[] array = BuildLines(instance); float num = 8f + (float)array.Length * 18f; GUI.Box(new Rect(12f, 48f, 190f, num), string.Empty); GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = 13, alignment = (TextAnchor)3 }; for (int i = 0; i < array.Length; i++) { GUI.Label(new Rect(20f, 54f + (float)i * 18f, 174f, 18f), array[i], val); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"PursuerHud.OnGUI: {arg}"); } } private static string[] BuildLines(ModeManager mode) { DirectorModeAbility instance = DirectorModeAbility.Instance; bool flag = instance?.CurrentBudget.HasValue ?? false; string[] array = new string[2 + (flag ? 2 : 0)]; array[0] = $"Mode: {mode.Mode}"; array[1] = "Phantom: " + (mode.IsPhantom ? "ON" : "off"); if (flag) { array[2] = $"Director: {instance.CurrentBudget}/{instance.MaxBudget} spawns"; array[3] = "Selected: " + (instance.SelectedEnemyName ?? "--"); } return array; } } } namespace LethalPursuer.Pursuer { [HarmonyPatch] internal static class EnemySuppressionPatches { [HarmonyPatch(typeof(EnemyAI), "DoAIInterval")] [HarmonyPrefix] private static bool SuppressPossessedAI(EnemyAI __instance) { try { EnemyAI val = (((Object)(object)PossessionController.Instance != (Object)null) ? PossessionController.Instance.Possessed : null); return (Object)(object)val == (Object)null || val != __instance; } catch (Exception arg) { Plugin.Log.LogError((object)$"EnemySuppressionPatches.SuppressPossessedAI: {arg}"); return true; } } } public sealed class MonsterCamera : MonoBehaviour { private const float FollowDistance = 4.5f; private const float FollowHeight = 2f; private const float PositionLerpSpeed = 12f; private static MonsterCamera? _instance; private Camera _cam; private Transform? _target; private bool _active; public Transform CameraTransform => ((Component)_cam).transform; public static MonsterCamera GetOrCreate() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if ((Object)(object)_instance != (Object)null) { return _instance; } GameObject val = new GameObject("LethalPursuer_MonsterCamera"); Object.DontDestroyOnLoad((Object)val); _instance = val.AddComponent<MonsterCamera>(); _instance.BuildCamera(); return _instance; } private void BuildCamera() { _cam = ((Component)this).gameObject.AddComponent<Camera>(); _cam.cullingMask = -1; _cam.nearClipPlane = 0.05f; ((Behaviour)_cam).enabled = false; } public void Activate(Transform target) { _target = target; _active = true; ((Behaviour)_cam).enabled = true; PlayerControllerB val = StartOfRound.Instance?.localPlayerController; if ((Object)(object)val != (Object)null && (Object)(object)val.gameplayCamera != (Object)null) { ((Behaviour)val.gameplayCamera).enabled = false; } SnapToTarget(); } public void Deactivate() { _active = false; ((Behaviour)_cam).enabled = false; _target = null; PlayerControllerB val = StartOfRound.Instance?.localPlayerController; if ((Object)(object)val != (Object)null && (Object)(object)val.gameplayCamera != (Object)null) { ((Behaviour)val.gameplayCamera).enabled = true; } } public void Pause() { if (_active) { ((Behaviour)_cam).enabled = false; } } public void Resume() { if (_active && !((Object)(object)_target == (Object)null)) { ((Behaviour)_cam).enabled = true; SnapToTarget(); } } public void Tick() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_006c: 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) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_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_0133: 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_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_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: 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_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) if (_active && !((Object)(object)_target == (Object)null)) { PossessionController instance = PossessionController.Instance; float num = (((Object)(object)instance != (Object)null) ? instance.Yaw : _target.eulerAngles.y); Quaternion val = Quaternion.Euler(((Object)(object)instance != (Object)null) ? instance.Pitch : 0f, num, 0f); Vector3 val2 = _target.position + Vector3.up * 2f - val * Vector3.forward * 4.5f; RaycastHit val3 = default(RaycastHit); if (Physics.Linecast(_target.position + Vector3.up * 2f, val2, ref val3, ((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.collidersAndRoomMaskAndDefault : (-1), (QueryTriggerInteraction)1)) { Vector3 point = ((RaycastHit)(ref val3)).point; Vector3 val4 = val2 - ((RaycastHit)(ref val3)).point; val2 = point + ((Vector3)(ref val4)).normalized * 0.3f; } ((Component)_cam).transform.position = Vector3.Lerp(((Component)_cam).transform.position, val2, 12f * Time.deltaTime); ((Component)_cam).transform.rotation = val; } } private void SnapToTarget() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: 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_009c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_target == (Object)null)) { PossessionController instance = PossessionController.Instance; float num = (((Object)(object)instance != (Object)null) ? instance.Yaw : _target.eulerAngles.y); Quaternion val = Quaternion.Euler(0f, num, 0f); ((Component)_cam).transform.position = _target.position + Vector3.up * 2f - val * Vector3.forward * 4.5f; ((Component)_cam).transform.rotation = val; } } } public sealed class PossessionController : MonoBehaviour { private const float DriveTurnDegreesPerSecond = 220f; private const float MouseLookSensitivity = 2f; private const float MinAgentSpeed = 0.01f; private MonsterCamera _monsterCam; private float _yaw; private float _pitch; private float _defaultAgentSpeed = 1f; private float _defaultAgentAngularSpeed = 1f; private bool _defaultAgentUpdateRotation = true; public static PossessionController? Instance { get; private set; } public EnemyAI? Possessed { get; private set; } public string? PositionOverrideOwner { get; private set; } public bool PositionOverrideActive => PositionOverrideOwner != null; public bool FollowCamSuppressed { get; private set; } private static bool IsHost { get { if ((Object)(object)StartOfRound.Instance != (Object)null) { return ((NetworkBehaviour)StartOfRound.Instance).IsHost; } return false; } } public bool IsPossessing => (Object)(object)Possessed != (Object)null; public float Yaw => _yaw; public float Pitch => _pitch; public Transform CameraTransform => _monsterCam.CameraTransform; public static Transform ActiveAimTransform { get { if (!((Object)(object)Instance != (Object)null) || !Instance.IsPossessing) { return GhostCamera.GetOrCreate().CameraTransform; } return Instance.CameraTransform; } } public event Action? Released; public bool TryClaimPositionOverride(string owner) { if (PositionOverrideOwner != null && PositionOverrideOwner != owner) { return false; } PositionOverrideOwner = owner; return true; } public void ReleasePositionOverride(string owner) { if (PositionOverrideOwner == owner) { PositionOverrideOwner = null; } } public static PossessionController GetOrCreate() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if ((Object)(object)Instance != (Object)null) { return Instance; } GameObject val = new GameObject("LethalPursuer_PossessionController"); Object.DontDestroyOnLoad((Object)val); Instance = val.AddComponent<PossessionController>(); Instance._monsterCam = MonsterCamera.GetOrCreate(); return Instance; } public bool TryPossess(EnemyAI enemy) { //IL_00d7: Unknown result type (might be due to invalid IL or missing references) if (!IsHost || (Object)(object)enemy == (Object)null) { return false; } try { if ((Object)(object)Possessed != (Object)null) { ReleaseCurrent(); } if ((Object)(object)enemy.agent == (Object)null) { enemy.agent = ((Component)enemy).GetComponentInChildren<NavMeshAgent>(); } if ((Object)(object)enemy.agent == (Object)null) { Plugin.Log.LogWarning((object)("PossessionController.TryPossess: " + ((Object)enemy).name + " has no NavMeshAgent, aborting.")); return false; } Possessed = enemy; enemy.movingTowardsTargetPlayer = false; enemy.targetPlayer = null; enemy.moveTowardsDestination = false; _defaultAgentSpeed = enemy.agent.speed; _defaultAgentAngularSpeed = enemy.agent.angularSpeed; _defaultAgentUpdateRotation = enemy.agent.updateRotation; enemy.agent.updateRotation = false; _yaw = ((Component)enemy).transform.eulerAngles.y; _pitch = 0f; PositionOverrideOwner = null; FollowCamSuppressed = false; _monsterCam.Activate(((Component)enemy).transform); return true; } catch (Exception arg) { Plugin.Log.LogError((object)$"PossessionController.TryPossess: {arg}"); return false; } } public void ReleaseCurrent() { try { this.Released?.Invoke(); } catch (Exception arg) { Plugin.Log.LogError((object)$"PossessionController.ReleaseCurrent Released subscriber: {arg}"); } try { _monsterCam.Deactivate(); PositionOverrideOwner = null; FollowCamSuppressed = false; EnemyAI possessed = Possessed; Possessed = null; if ((Object)(object)possessed == (Object)null) { return; } if ((Object)(object)possessed.agent != (Object)null) { ((Behaviour)possessed.agent).enabled = true; possessed.agent.speed = _defaultAgentSpeed; possessed.agent.angularSpeed = _defaultAgentAngularSpeed; possessed.agent.updateRotation = _defaultAgentUpdateRotation; if (possessed.agent.isOnNavMesh) { possessed.agent.ResetPath(); } } possessed.inSpecialAnimation = false; if ((Object)(object)possessed.creatureAnimator != (Object)null) { possessed.creatureAnimator.SetBool("inSpawningAnimation", false); } possessed.moveTowardsDestination = true; possessed.movingTowardsTargetPlayer = false; possessed.targetPlayer = null; } catch (Exception arg2) { Plugin.Log.LogError((object)$"PossessionController.ReleaseCurrent: {arg2}"); } } private void Update() { try { if (!IsHost || (Object)(object)Possessed == (Object)null) { return; } EnemyAI possessed = Possessed; if ((Object)(object)possessed == (Object)null || possessed.isEnemyDead) { ReleaseCurrent(); return; } DriveFromInput(possessed); if (!FollowCamSuppressed) { _monsterCam.Tick(); } } catch (Exception arg) { Plugin.Log.LogError((object)$"PossessionController.Update: {arg}"); } } public void SuppressFollowCam() { FollowCamSuppressed = true; _monsterCam.Pause(); } public void ResumeFollowCam() { FollowCamSuppressed = false; _monsterCam.Resume(); } private void DriveFromInput(EnemyAI enemy) { //IL_00a3: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: 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_00d3: 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_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_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_00f3: 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_00f5: 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_0104: 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_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0115: 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_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: 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_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0155: 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_0160: 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_016a: 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_018a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)enemy.agent == (Object)null || !((Behaviour)enemy.agent).enabled) { return; } _yaw += Input.GetAxis("Mouse X") * 2f * 60f * Time.deltaTime; _pitch = Mathf.Clamp(_pitch - Input.GetAxis("Mouse Y") * 2f * 60f * Time.deltaTime, -40f, 40f); if (!PositionOverrideActive && enemy.agent.isOnNavMesh) { Vector3 val = Quaternion.Euler(0f, _yaw, 0f) * Vector3.forward; Vector3 val2 = Quaternion.Euler(0f, _yaw, 0f) * Vector3.right; Vector3 val3 = Vector3.zero; if (Input.GetKey((KeyCode)119)) { val3 += val; } if (Input.GetKey((KeyCode)115)) { val3 -= val; } if (Input.GetKey((KeyCode)100)) { val3 += val2; } if (Input.GetKey((KeyCode)97)) { val3 -= val2; } float num = Mathf.Max(_defaultAgentSpeed, 0.01f); if (((Vector3)(ref val3)).sqrMagnitude > 0.0001f) { ((Vector3)(ref val3)).Normalize(); enemy.agent.Move(val3 * num * Time.deltaTime); Quaternion val4 = Quaternion.LookRotation(val3, Vector3.up); ((Component)enemy).transform.rotation = Quaternion.RotateTowards(((Component)enemy).transform.rotation, val4, 220f * Time.deltaTime); } else { ((Component)enemy).transform.rotation = Quaternion.RotateTowards(((Component)enemy).transform.rotation, Quaternion.Euler(0f, _yaw, 0f), 220f * Time.deltaTime); } enemy.SyncPositionToClients(); } } } } namespace LethalPursuer.Phantom { [HarmonyPatch] internal static class PhantomPatches { [HarmonyPatch(typeof(PlayerControllerB), "Update")] [HarmonyPostfix] private static void HideGhostingBody(PlayerControllerB __instance) { try { bool flag = PresenceRegistry.Instance.IsGhosting(__instance.actualClientId); if ((Object)(object)__instance.thisPlayerModel != (Object)null && ((Renderer)__instance.thisPlayerModel).enabled == flag) { ((Renderer)__instance.thisPlayerModel).enabled = !flag; } if ((Object)(object)__instance.thisPlayerModelLOD1 != (Object)null) { ((Renderer)__instance.thisPlayerModelLOD1).enabled = !flag; } if ((Object)(object)__instance.thisPlayerModelLOD2 != (Object)null) { ((Renderer)__instance.thisPlayerModelLOD2).enabled = !flag; } if ((Object)(object)__instance.thisPlayerModelArms != (Object)null) { ((Renderer)__instance.thisPlayerModelArms).enabled = !flag; } } catch (Exception arg) { Plugin.Log.LogError((object)$"HideGhostingBody: {arg}"); } } [HarmonyPatch(typeof(ManualCameraRenderer), "Update")] [HarmonyPostfix] private static void ScrubPhantomRadarTargets(ManualCameraRenderer __instance) { try { List<TransformAndName> radarTargets = __instance.radarTargets; if (radarTargets == null) { return; } for (int num = radarTargets.Count - 1; num >= 0; num--) { PlayerControllerB val = (((Object)(object)radarTargets[num].transform != (Object)null) ? ((Component)radarTargets[num].transform).GetComponent<PlayerControllerB>() : null); if ((Object)(object)val != (Object)null && PresenceRegistry.Instance.IsPhantom(val.actualClientId)) { radarTargets.RemoveAt(num); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"ScrubPhantomRadarTargets: {arg}"); } } [HarmonyPatch(typeof(PlayerControllerB), "DamagePlayer")] [HarmonyPrefix] private static bool BlockDamageWhileGhosting(PlayerControllerB __instance) { try { return !PresenceRegistry.Instance.IsGhosting(__instance.actualClientId); } catch (Exception arg) { Plugin.Log.LogError((object)$"BlockDamageWhileGhosting: {arg}"); return true; } } [HarmonyPatch(typeof(PlayerControllerB), "KillPlayer")] [HarmonyPrefix] private static bool BlockKillWhileGhosting(PlayerControllerB __instance) { try { return !PresenceRegistry.Instance.IsGhosting(__instance.actualClientId); } catch (Exception arg) { Plugin.Log.LogError((object)$"BlockKillWhileGhosting: {arg}"); return true; } } } } namespace LethalPursuer.Net { public static class NetworkHandler { private static LNetworkMessage<PresenceMessage>? _presence; public static void Initialize() { _presence = LNetworkMessage<PresenceMessage>.Connect("LethalPursuer.Presence", (Action<PresenceMessage, ulong>)null, (Action<PresenceMessage>)null, (Action<PresenceMessage, ulong>)null); _presence.OnClientReceived += delegate(PresenceMessage msg) { PresenceRegistry.Instance.SetGhosting(msg.ClientId, msg.Ghosting); PresenceRegistry.Instance.SetPhantom(msg.ClientId, msg.Phantom); }; } public static void BroadcastPresence(ulong clientId, bool ghosting, bool phantom) { PresenceMessage presenceMessage = new PresenceMessage { ClientId = clientId, Ghosting = ghosting, Phantom = phantom }; PresenceRegistry.Instance.SetGhosting(clientId, ghosting); PresenceRegistry.Instance.SetPhantom(clientId, phantom); _presence?.SendClients(presenceMessage); } } public struct PresenceMessage { public ulong ClientId; public bool Ghosting; public bool Phantom; } } namespace LethalPursuer.Lifecycle { [HarmonyPatch] internal static class RoundLifecyclePatches { [HarmonyPatch(typeof(StartOfRound), "StartGame")] [HarmonyPostfix] private static void OnRoundStart() { try { ModeManager.Instance?.ForceReset(); ResetDirectorAndCountdown(); if ((Object)(object)StartOfRound.Instance != (Object)null && ((NetworkBehaviour)StartOfRound.Instance).IsHost && (Object)(object)ModeManager.Instance != (Object)null) { NetworkHandler.BroadcastPresence(ModeManager.Instance.LocalId, ghosting: false, phantom: false); } } catch (Exception arg) { Plugin.Log.LogError((object)$"OnRoundStart: {arg}"); } } [HarmonyPatch(typeof(StartOfRound), "ShipHasLeft")] [HarmonyPostfix] private static void OnRoundEnd() { try { ModeManager.Instance?.ForceReset(); ResetDirectorAndCountdown(); } catch (Exception arg) { Plugin.Log.LogError((object)$"OnRoundEnd: {arg}"); } } private static void ResetDirectorAndCountdown() { DirectorModeAbility.Instance?.ForceReset(); CountdownAbility.Instance?.ForceStop(); } [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] private static void EnsureManagers() { try { if ((Object)(object)StartOfRound.Instance != (Object)null && ((NetworkBehaviour)StartOfRound.Instance).IsHost) { ModeManager.GetOrCreate(); PursuerHud.GetOrCreate(); } AbilityBootstrap.RegisterAll(InputRouter.GetOrCreate()); } catch (Exception arg) { Plugin.Log.LogError((object)$"EnsureManagers: {arg}"); } } } } namespace LethalPursuer.Core { public abstract class AbilityBase : IPursuerAbility { protected static bool IsHostActive { get { if ((Object)(object)StartOfRound.Instance != (Object)null) { return ((NetworkBehaviour)StartOfRound.Instance).IsHost; } return false; } } protected static ModeManager? Mode => ModeManager.Instance; protected static bool InGhostOrPursuer { get { if ((Object)(object)Mode != (Object)null) { return Mode.Mode != PursuerMode.Player; } return false; } } protected static Vector3 GhostPosition => GhostCamera.GetOrCreate().CameraTransform.position; protected static ulong LocalId { get { if (!((Object)(object)Mode != (Object)null)) { return 0uL; } return Mode.LocalId; } } public abstract void Tick(); } public static class AbilityBootstrap { private static bool _registered; public static void RegisterAll(InputRouter router) { if (_registered) { return; } _registered = true; try { foreach (Type item in from t in Assembly.GetExecutingAssembly().GetTypes() where (object)t != null && t.IsClass && !t.IsAbstract && typeof(IPursuerAbility).IsAssignableFrom(t) && t.GetConstructor(Type.EmptyTypes) != null select t) { try { if (Activator.CreateInstance(item) is IPursuerAbility ability) { router.Register(ability); } } catch (Exception arg) { Plugin.Log.LogError((object)$"AbilityBootstrap: failed to register {item.FullName}: {arg}"); } } } catch (Exception arg2) { Plugin.Log.LogError((object)$"AbilityBootstrap.RegisterAll: {arg2}"); } } } public sealed class GhostCamera : MonoBehaviour { private static GhostCamera? _instance; private Camera _cam; private Light _nightVision; private float _pitch; private float _yaw; private bool _active; public Transform CameraTransform => ((Component)_cam).transform; public static GhostCamera GetOrCreate() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if ((Object)(object)_instance != (Object)null) { return _instance; } GameObject val = new GameObject("LethalPursuer_GhostCamera"); Object.DontDestroyOnLoad((Object)val); _instance = val.AddComponent<GhostCamera>(); _instance.BuildCamera(); return _instance; } private void BuildCamera() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown _cam = ((Component)this).gameObject.AddComponent<Camera>(); _cam.cullingMask = -1; _cam.nearClipPlane = 0.05f; ((Behaviour)_cam).enabled = false; GameObject val = new GameObject("LethalPursuer_NightVision"); val.transform.SetParent(((Component)_cam).transform, false); _nightVision = val.AddComponent<Light>(); _nightVision.type = (LightType)1; _nightVision.intensity = 1.2f; _nightVision.range = 1000f; ((Behaviour)_nightVision).enabled = false; } public void Activate(Vector3 startPos) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) _active = true; ((Component)_cam).transform.position = startPos; _yaw = ((Component)_cam).transform.eulerAngles.y; _pitch = 0f; ((Behaviour)_cam).enabled = true; ((Behaviour)_nightVision).enabled = true; PlayerControllerB val = StartOfRound.Instance?.localPlayerController; if ((Object)(object)val != (Object)null && (Object)(object)val.gameplayCamera != (Object)null) { ((Behaviour)val.gameplayCamera).enabled = false; } } public void Deactivate() { _active = false; ((Behaviour)_cam).enabled = false; ((Behaviour)_nightVision).enabled = false; PlayerControllerB val = StartOfRound.Instance?.localPlayerController; if ((Object)(object)val != (Object)null && (Object)(object)val.gameplayCamera != (Object)null) { ((Behaviour)val.gameplayCamera).enabled = true; } } private void Update() { //IL_006e: 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: 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_00c6: 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_00d7: 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_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0126: 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_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_0156: 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_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) if (_active) { _yaw += Input.GetAxis("Mouse X") * 2f; _pitch = Mathf.Clamp(_pitch - Input.GetAxis("Mouse Y") * 2f, -89f, 89f); ((Component)_cam).transform.rotation = Quaternion.Euler(_pitch, _yaw, 0f); float num = PursuerConfig.GhostFlySpeed * (Input.GetKey((KeyCode)304) ? 3f : 1f); Vector3 val = Vector3.zero; if (Input.GetKey((KeyCode)119)) { val += ((Component)_cam).transform.forward; } if (Input.GetKey((KeyCode)115)) { val -= ((Component)_cam).transform.forward; } if (Input.GetKey((KeyCode)100)) { val += ((Component)_cam).transform.right; } if (Input.GetKey((KeyCode)97)) { val -= ((Component)_cam).transform.right; } if (Input.GetKey((KeyCode)32)) { val += Vector3.up; } if (Input.GetKey((KeyCode)306)) { val += Vector3.down; } Transform transform = ((Component)_cam).transform; transform.position += ((Vector3)(ref val)).normalized * num * Time.deltaTime; } } } public enum HoldResult { None, Tap, HoldTriggered } public sealed class HoldTracker { private readonly float _holdSeconds; private bool _isDown; private float _downAt; private bool _holdFired; public HoldTracker(float holdSeconds) { _holdSeconds = holdSeconds; } public HoldResult Update(bool isDown, float now) { if (isDown && !_isDown) { _isDown = true; _downAt = now; _holdFired = false; return HoldResult.None; } if (isDown && _isDown) { if (!_holdFired && now - _downAt >= _holdSeconds) { _holdFired = true; return HoldResult.HoldTriggered; } return HoldResult.None; } if (!isDown && _isDown) { _isDown = false; bool num = !_holdFired; _holdFired = false; if (!num) { return HoldResult.None; } return HoldResult.Tap; } return HoldResult.None; } } public sealed class InputRouter : MonoBehaviour { private static InputRouter? _instance; private readonly List<IPursuerAbility> _abilities = new List<IPursuerAbility>(); private static bool IsHost { get { if ((Object)(object)StartOfRound.Instance != (Object)null) { return ((NetworkBehaviour)StartOfRound.Instance).IsHost; } return false; } } public static InputRouter GetOrCreate() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if ((Object)(object)_instance != (Object)null) { return _instance; } GameObject val = new GameObject("LethalPursuer_InputRouter"); Object.DontDestroyOnLoad((Object)val); _instance = val.AddComponent<InputRouter>(); return _instance; } public void Register(IPursuerAbility ability) { _abilities.Add(ability); } private void Update() { if (!IsHost) { return; } ModeManager orCreate = ModeManager.GetOrCreate(); if (PursuerConfig.GhostToggle.Pressed()) { orCreate.EnterGhostOrExit(); } if (PursuerConfig.Phantom.Pressed()) { orCreate.TogglePhantom(); } if (PursuerConfig.MonsterSwap.Pressed()) { orCreate.SwapMonster(); } foreach (IPursuerAbility ability in _abilities) { ability.Tick(); } } } public interface IPursuerAbility { void Tick(); } public sealed class ModeManager : MonoBehaviour { private readonly ModeStateMachine _sm = new ModeStateMachine(); private GhostCamera _ghostCam; private bool _bodyHidden; public static ModeManager? Instance { get; private set; } public PursuerMode Mode => _sm.Mode; public bool IsPhantom => _sm.IsPhantom; public ulong LocalId { get { if (!((Object)(object)StartOfRound.Instance?.localPlayerController != (Object)null)) { return 0uL; } return StartOfRound.Instance.localPlayerController.actualClientId; } } private static bool IsHost { get { if ((Object)(object)StartOfRound.Instance != (Object)null) { return ((NetworkBehaviour)StartOfRound.Instance).IsHost; } return false; } } public static ModeManager GetOrCreate() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if ((Object)(object)Instance != (Object)null) { return Instance; } GameObject val = new GameObject("LethalPursuer_ModeManager"); Object.DontDestroyOnLoad((Object)val); Instance = val.AddComponent<ModeManager>(); Instance._ghostCam = GhostCamera.GetOrCreate(); return Instance; } private void Update() { //IL_008b: 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_009d: Unknown result type (might be due to invalid IL or missing references) if (IsHost && _sm.Mode == PursuerMode.Pursuer) { PossessionController instance = PossessionController.Instance; if ((!((Object)(object)instance != (Object)null) || !instance.IsPossessing) && _sm.TrySwapToGhost()) { instance?.ReleaseCurrent(); PlayerControllerB val = StartOfRound.Instance?.localPlayerController; _ghostCam.Activate(((Object)(object)val != (Object)null && (Object)(object)val.gameplayCamera != (Object)null) ? ((Component)val.gameplayCamera).transform.position : (((Object)(object)val != (Object)null) ? ((Component)val).transform.position : Vector3.zero)); Plugin.Log.LogWarning((object)"ModeManager: possession ended unexpectedly (likely the possessed enemy died); recovered to Ghost mode."); } } } public void EnterGhostOrExit() { if (!IsHost) { return; } if (_sm.Mode == PursuerMode.Player) { if (_sm.TryEnterGhost()) { OnEnteredGhost(); } } else if (_sm.TryExitToPlayer()) { OnReturnedToPlayer(); } } public void TogglePhantom() { if (IsHost && _sm.TryTogglePhantom()) { NetworkHandler.BroadcastPresence(LocalId, ghosting: true, _sm.IsPhantom); } } public bool EnterPursuer(EnemyAI enemy) { //IL_003b: 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 (!IsHost || Mode != PursuerMode.Ghost || (Object)(object)enemy == (Object)null) { return false; } PossessionController orCreate = PossessionController.GetOrCreate(); _ghostCam.Deactivate(); if (!orCreate.TryPossess(enemy)) { _ghostCam.Activate(GetGhostCamFallbackPosition()); return false; } if (!_sm.TryEnterPursuer()) { orCreate.ReleaseCurrent(); _ghostCam.Activate(GetGhostCamFallbackPosition()); return false; } return true; } private static Vector3 GetGhostCamFallbackPosition() { //IL_001b: 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) //IL_0035: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB val = StartOfRound.Instance?.localPlayerController; if ((Object)(object)val == (Object)null) { return Vector3.zero; } if (!((Object)(object)val.gameplayCamera != (Object)null)) { return ((Component)val).transform.position; } return ((Component)val.gameplayCamera).transform.position; } public void SwapMonster() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) if (IsHost && _sm.TrySwapToGhost()) { PossessionController.GetOrCreate().ReleaseCurrent(); PlayerControllerB val = StartOfRound.Instance?.localPlayerController; _ghostCam.Activate(((Object)(object)val != (Object)null && (Object)(object)val.gameplayCamera != (Object)null) ? ((Component)val.gameplayCamera).transform.position : (((Object)(object)val != (Object)null) ? ((Component)val).transform.position : Vector3.zero)); } } private void OnEnteredGhost() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB localPlayerController = StartOfRound.Instance.localPlayerController; _ghostCam.Activate(((Object)(object)localPlayerController.gameplayCamera != (Object)null) ? ((Component)localPlayerController.gameplayCamera).transform.position : ((Component)localPlayerController).transform.position); SetLocalBodyHidden(hidden: true); NetworkHandler.BroadcastPresence(LocalId, ghosting: true, phantom: false); } private void OnReturnedToPlayer() { PossessionController.GetOrCreate().ReleaseCurrent(); _ghostCam.Deactivate(); SetLocalBodyHidden(hidden: false); NetworkHandler.BroadcastPresence(LocalId, ghosting: false, phantom: false); } private void SetLocalBodyHidden(bool hidden) { _bodyHidden = hidden; PlayerControllerB val = StartOfRound.Instance?.localPlayerController; if (!((Object)(object)val == (Object)null)) { val.disableMoveInput = hidden; } } public void ForceReset() { PossessionController.GetOrCreate().ReleaseCurrent(); if (_sm.Mode != PursuerMode.Player) { _ghostCam.Deactivate(); SetLocalBodyHidden(hidden: false); } _sm.ResetToPlayer(); PresenceRegistry.Instance.Clear(); } } public sealed class ModeStateMachine { public PursuerMode Mode { get; private set; } public bool IsPhantom { get; private set; } public bool TryEnterGhost() { if (Mode != PursuerMode.Player) { return false; } Mode = PursuerMode.Ghost; return true; } public bool TryEnterPursuer() { if (Mode != PursuerMode.Ghost) { return false; } Mode = PursuerMode.Pursuer; return true; } public bool TrySwapToGhost() { if (Mode != PursuerMode.Pursuer) { return false; } Mode = PursuerMode.Ghost; return true; } public bool TryExitToPlayer() { if (Mode == PursuerMode.Player) { return false; } Mode = PursuerMode.Player; IsPhantom = false; return true; } public bool TryTogglePhantom() { if (Mode == PursuerMode.Player) { return false; } IsPhantom = !IsPhantom; return true; } public void ResetToPlayer() { Mode = PursuerMode.Player; IsPhantom = false; } } public sealed class PresenceRegistry { private readonly HashSet<ulong> _ghosting = new HashSet<ulong>(); private readonly HashSet<ulong> _phantom = new HashSet<ulong>(); public static PresenceRegistry Instance { get; } = new PresenceRegistry(); public bool IsGhosting(ulong clientId) { return _ghosting.Contains(clientId); } public bool IsPhantom(ulong clientId) { return _phantom.Contains(clientId); } public void SetGhosting(ulong clientId, bool on) { if (on) { _ghosting.Add(clientId); } else { _ghosting.Remove(clientId); } } public void SetPhantom(ulong clientId, bool on) { if (on) { _phantom.Add(clientId); } else { _phantom.Remove(clientId); } } public void Clear() { _ghosting.Clear(); _phantom.Clear(); } } public enum PursuerMode { Player, Ghost, Pursuer } public sealed class SpawnBudget { private readonly int _max; private readonly float _rechargeIntervalSeconds; private int _current; private float _lastRechargeAt; public int Max => _max; public SpawnBudget(int max, float rechargeIntervalSeconds, float now) { _max = Math.Max(1, max); _rechargeIntervalSeconds = Math.Max(1f, rechargeIntervalSeconds); _current = _max; _lastRechargeAt = now; } public int Current(float now) { ApplyRecharge(now); return _current; } public bool TrySpend(float now) { ApplyRecharge(now); if (_current <= 0) { return false; } _current--; return true; } public void Reset(float now) { _current = _max; _lastRechargeAt = now; } private void ApplyRecharge(float now) { if (_current >= _max) { _lastRechargeAt = now; return; } float num = now - _lastRechargeAt; if (!(num < _rechargeIntervalSeconds)) { int num2 = (int)(num / _rechargeIntervalSeconds); _current = Math.Min(_max, _current + num2); _lastRechargeAt += (float)num2 * _rechargeIntervalSeconds; } } } } namespace LethalPursuer.Config { public readonly struct KeyBind { public KeyCode Key { get; } public bool IsValid { get; } private KeyBind(KeyCode key, bool isValid) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) Key = key; IsValid = isValid; } public static KeyBind Parse(string raw, KeyCode fallback) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (Enum.TryParse<KeyCode>((raw ?? string.Empty).Trim(), ignoreCase: true, out KeyCode result) && Enum.IsDefined(typeof(KeyCode), result)) { return new KeyBind(result, isValid: true); } return new KeyBind(fallback, isValid: false); } public bool Pressed() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return Input.GetKeyDown(Key); } public bool Held() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return Input.GetKey(Key); } } public static class PursuerConfig { public static KeyBind GhostToggle; public static KeyBind Phantom; public static KeyBind MonsterSwap; public static KeyBind SoundEmitter; public static KeyBind LightFlicker; public static KeyBind DoorLock; public static KeyBind FakeBlip; public static KeyBind GhostVoice; public static KeyBind MaskedCycle; public static KeyBind Leash; public static KeyBind Breaker; public static KeyBind Vent; public static KeyBind ItemCurse; public static KeyBind PuppetWaypoint; public static KeyBind DirectorMode; public static KeyBind CountdownToggle; public static bool GhostVoiceEnabled; public static bool GhostVoiceDistortion; public static bool AsymmetricMode; public static bool BlackoutRequiresBreakerReset; public static int GhostPlayerIndex; public static int CountdownDuration; public static int DoorLockDuration; public static int FakeBlipDuration; public static int VentSealDuration; public static int ItemCurseAggroDuration; public static int SpawnBudgetMax; public static int SpawnBudgetRechargeInterval; public static int MaxSoundEmitters; public static int MaxFakeBlips; public static float SoundEmitterRadius; public static float GhostFlySpeed; private static string _keyGhostToggle = "F1"; private static string _keyPhantom = "F5"; private static string _keyMonsterSwap = "F2"; private static string _keySound = "Z"; private static string _keyFlicker = "X"; private static string _keyDoor = "C"; private static string _keyBlip = "V"; private static string _keyVoice = "T"; private static string _keyMasked = "G"; private static string _keyLeash = "L"; private static string _keyBreaker = "B"; private static string _keyVent = "N"; private static string _keyCurse = "I"; private static string _keyPuppet = "Mouse1"; private static string _keyDirector = "F3"; private static string _keyCountdown = "F4"; public static void Init(ConfigFile cfg) { _keyGhostToggle = cfg.Bind<string>("Keybinds", "ghost_toggle_key", "F1", "Toggle Ghost mode.").Value; _keyPhantom = cfg.Bind<string>("Keybinds", "phantom_state_key", "F5", "Toggle Phantom State.").Value; _keyMonsterSwap = cfg.Bind<string>("Keybinds", "monster_swap_key", "F2", "Exit current monster back to Ghost.").Value; _keySound = cfg.Bind<string>("Keybinds", "sound_emitter_key", "Z", "Sound emitter radial menu.").Value; _keyFlicker = cfg.Bind<string>("Keybinds", "light_flicker_key", "X", "Light flicker (tap) / blackout (hold).").Value; _keyDoor = cfg.Bind<string>("Keybinds", "door_lock_key", "C", "Door lock.").Value; _keyBlip = cfg.Bind<string>("Keybinds", "fake_blip_key", "V", "Fake radar blip.").Value; _keyVoice = cfg.Bind<string>("Keybinds", "ghost_voice_key", "T", "Ghost voice push-to-talk.").Value; _keyMasked = cfg.Bind<string>("Keybinds", "masked_cycle_item_key", "G", "Cycle Masked held-item cosmetic.").Value; _keyLeash = cfg.Bind<string>("Keybinds", "leash_key", "L", "Leash mode.").Value; _keyBreaker = cfg.Bind<string>("Keybinds", "breaker_key", "B", "Breaker panel remote.").Value; _keyVent = cfg.Bind<string>("Keybinds", "vent_key", "N", "Vent cover (tap) / vent hide (hold).").Value; _keyCurse = cfg.Bind<string>("Keybinds", "item_curse_key", "I", "Item curse.").Value; _keyPuppet = cfg.Bind<string>("Keybinds", "puppet_waypoint_button", "Mouse1", "AI puppet waypoint button.").Value; _keyDirector = cfg.Bind<string>("Keybinds", "director_mode_key", "F3", "Director mode (deferred).").Value; _keyCountdown = cfg.Bind<string>("Keybinds", "countdown_toggle_key", "F4", "Countdown toggle (deferred).").Value; GhostVoiceEnabled = cfg.Bind<bool>("Toggles", "ghost_voice_enabled", true, "Enable ghost voice.").Value; GhostVoiceDistortion = cfg.Bind<bool>("Toggles", "ghost_voice_distortion", true, "Distort ghost voice.").Value; AsymmetricMode = cfg.Bind<bool>("Toggles", "asymmetric_mode", false, "Designate a non-host as ghost (deferred).").Value; BlackoutRequiresBreakerReset = cfg.Bind<bool>("Toggles", "blackout_requires_breaker_reset", true, "Blackout stays until breaker reset.").Value; GhostPlayerIndex = cfg.Bind<int>("Ghost", "ghost_player_index", 0, "Ghost player index (deferred).").Value; GhostFlySpeed = cfg.Bind<float>("Ghost", "ghost_fly_speed", 12f, "Ghost free-fly camera speed (m/s).").Value; CountdownDuration = cfg.Bind<int>("Durations", "countdown_duration", 240, "Countdown seconds (deferred).").Value; DoorLockDuration = cfg.Bind<int>("Durations", "door_lock_duration", 15, "Door lock seconds.").Value; FakeBlipDuration = cfg.Bind<int>("Durations", "fake_blip_duration", 30, "Fake blip seconds.").Value; VentSealDuration = cfg.Bind<int>("Durations", "vent_seal_duration", 20, "Vent seal seconds.").Value; ItemCurseAggroDuration = cfg.Bind<int>("Durations", "item_curse_aggro_duration", 5, "Item curse aggro seconds.").Value; SpawnBudgetRechargeInterval = cfg.Bind<int>("Durations", "spawn_budget_recharge_interval", 60, "Spawn budget recharge seconds (deferred).").Value; SpawnBudgetMax = cfg.Bind<int>("Limits", "spawn_budget_max", 5, "Max spawn budget (deferred).").Value; SoundEmitterRadius = cfg.Bind<float>("Limits", "sound_emitter_radius", 10f, "Sound emitter 3D falloff radius (m).").Value; MaxSoundEmitters = cfg.Bind<int>("Limits", "max_sound_emitters", 3, "Max active sound emitters.").Value; MaxFakeBlips = cfg.Bind<int>("Limits", "max_fake_blips", 2, "Max active fake blips.").Value; GhostToggle = KeyBind.Parse(_keyGhostToggle, (KeyCode)282); Phantom = KeyBind.Parse(_keyPhantom, (KeyCode)286); MonsterSwap = KeyBind.Parse(_keyMonsterSwap, (KeyCode)283); SoundEmitter = KeyBind.Parse(_keySound, (KeyCode)122); LightFlicker = KeyBind.Parse(_keyFlicker, (KeyCode)120); DoorLock = KeyBind.Parse(_keyDoor, (KeyCode)99); FakeBlip = KeyBind.Parse(_keyBlip, (KeyCode)118); GhostVoice = KeyBind.Parse(_keyVoice, (KeyCode)116); MaskedCycle = KeyBind.Parse(_keyMasked, (KeyCode)103); Leash = KeyBind.Parse(_keyLeash, (KeyCode)108); Breaker = KeyBind.Parse(_keyBreaker, (KeyCode)98); Vent = KeyBind.Parse(_keyVent, (KeyCode)110); ItemCurse = KeyBind.Parse(_keyCurse, (KeyCode)105); PuppetWaypoint = KeyBind.Parse(_keyPuppet, (KeyCode)324); DirectorMode = KeyBind.Parse(_keyDirector, (KeyCode)284); CountdownToggle = KeyBind.Parse(_keyCountdown, (KeyCode)285); } } } namespace LethalPursuer.Abilities { public sealed class BlackoutAbility : AbilityBase { private const float HoldThresholdSeconds = 2f; private const float AutoRestoreDelaySeconds = 5f; private readonly HoldTracker _tracker = new HoldTracker(2f); private bool _autoRestorePending; private float _autoRestoreAt; public override void Tick() { try { if (!AbilityBase.IsHostActive || !AbilityBase.InGhostOrPursuer) { _autoRestorePending = false; return; } if (_tracker.Update(PursuerConfig.LightFlicker.Held(), Time.time) == HoldResult.HoldTriggered) { RoundManager instance = RoundManager.Instance; if (instance != null) { instance.SwitchPower(false); } if (!PursuerConfig.BlackoutRequiresBreakerReset) { _autoRestorePending = true; _autoRestoreAt = Time.time + 5f; } } if (_autoRestorePending && Time.time >= _autoRestoreAt) { _autoRestorePending = false; RoundManager instance2 = RoundManager.Instance; if (instance2 != null) { instance2.SwitchPower(true); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"BlackoutAbility.Tick: {arg}"); } } } public sealed class BreakerAbility : AbilityBase { private const float CooldownSeconds = 10f; private float _cooldownUntil; public override void Tick() { try { if (AbilityBase.IsHostActive && AbilityBase.InGhostOrPursuer && PursuerConfig.Breaker.Pressed() && !(Time.time < _cooldownUntil)) { _cooldownUntil = Time.time + 10f; RoundManager instance = RoundManager.Instance; if (instance != null) { instance.SwitchPower(false); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"BreakerAbility.Tick: {arg}"); } } } public sealed class CountdownAbility : AbilityBase { public struct CountdownMessage { public bool On; public float StartTime; public int Duration; } private static readonly LNetworkMessage<CountdownMessage> Msg; private bool _hostToggledOn; public static CountdownAbility? Instance { get; private set; } public CountdownAbility() { Instance = this; } static CountdownAbility() { Msg = LNetworkMessage<CountdownMessage>.Connect("LethalPursuer.Countdown", (Action<CountdownMessage, ulong>)null, (Action<CountdownMessage>)null, (Action<CountdownMessage, ulong>)null); try { Msg.OnClientReceived += delegate(CountdownMessage msg) { if (msg.On) { CountdownOverlay.GetOrCreate().Show(msg.StartTime, msg.Duration); } else { CountdownOverlay.GetOrCreate().Hide(); } }; } catch (Exception arg) { Plugin.Log.LogError((object)$"CountdownAbility static init: {arg}"); } } public override void Tick() { try { if (!AbilityBase.IsHostActive) { if (_hostToggledOn) { _hostToggledOn = false; } } else if (PursuerConfig.CountdownToggle.Pressed()) { Toggle(); } } catch (Exception arg) { Plugin.Log.LogError((object)$"CountdownAbility.Tick: {arg}"); } } private void Toggle() { _hostToggledOn = !_hostToggledOn; if (_hostToggledOn) { float time = Time.time; int duration = Math.Max(1, PursuerConfig.CountdownDuration); CountdownOverlay.GetOrCreate().Show(time, duration); Msg.SendClients(new CountdownMessage { On = true, StartTime = time, Duration = duration }); } else { CountdownOverlay.GetOrCreate().Hide(); Msg.SendClients(new CountdownMessage { On = false }); } } public void ForceStop() { if (_hostToggledOn) { _hostToggledOn = false; CountdownOverlay.GetOrCreate().Hide(); Msg.SendClients(new CountdownMessage { On = false }); } } } public sealed class CountdownOverlay : MonoBehaviour { private static CountdownOverlay? _instance; private bool _visible; private float _startTime; private int _duration; public static CountdownOverlay GetOrCreate() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if ((Object)(object)_instance != (Object)null) { return _instance; } GameObject val = new GameObject("LethalPursuer_CountdownOverlay"); Object.DontDestroyOnLoad((Object)val); _instance = val.AddComponent<CountdownOverlay>(); return _instance; } public void Show(float startTime, int duration) { _startTime = startTime; _duration = Math.Max(1, duration); _visible = true; } public void Hide() { _visible = false; } private void OnGUI() { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown //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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) if (!_visible) { return; } try { float num = Mathf.Max(0f, (float)_duration - (Time.time - _startTime)); int num2 = Mathf.CeilToInt(num); int num3 = num2 / 60; string text = string.Format(arg1: num2 % 60, format: "{0:00}:{1:00}", arg0: num3); float num4 = Mathf.Max(10f, (float)_duration * 0.1f); Color textColor = ((num <= num4) ? new Color(0.85f, 0.1f, 0.1f) : new Color(0.9f, 0.85f, 0.75f)); GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = 54, fontStyle = (FontStyle)1, alignment = (TextAnchor)1 }; Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(((float)Screen.width - 300f) * 0.5f, 18f, 300f, 70f); GUIStyle val3 = new GUIStyle(val); val3.normal.textColor = Color.black; GUIStyle val4 = val3; GUI.Label(new Rect(((Rect)(ref val2)).x + 2f, ((Rect)(ref val2)).y + 2f, ((Rect)(ref val2)).width, ((Rect)(ref val2)).height), text, val4); val.normal.textColor = textColor; GUI.Label(val2, text, val); } catch (Exception arg) { Plugin.Log.LogError((object)$"CountdownOverlay.OnGUI: {arg}"); } } } public sealed class DirectorModeAbility : AbilityBase { private const float RaycastDistance = 120f; private readonly List<EnemyType> _cycle = new List<EnemyType>(); private bool _active; private int _selectedIndex; private SpawnBudget? _budget; public static bool IsActive { get; private set; } public static DirectorModeAbility? Instance { get; private set; } public int? CurrentBudget { get { if (!_active || _budget == null) { return null; } return _budget.Current(Time.time); } } public int? MaxBudget { get { if (!_active || _budget == null) { return null; } return _budget.Max; } } public string? SelectedEnemyName { get { if (!_active || _cycle.Count <= 0) { return null; } return _cycle[Mathf.Clamp(_selectedIndex, 0, _cycle.Count - 1)].enemyName; } } public DirectorModeAbility() { Instance = this; } public override void Tick() { try { if (!AbilityBase.IsHostActive) { if (_active) { Deactivate(); } return; } if (PursuerConfig.DirectorMode.Pressed()) { if (_active) { Deactivate(); } else { TryActivate(); } } if (_active && ((Object)(object)AbilityBase.Mode == (Object)null || AbilityBase.Mode.Mode != PursuerMode.Ghost)) { Deactivate(); } else if (_active) { HandleCycleInput(); if (Input.GetMouseButtonDown(0)) { TrySpawn(); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"DirectorModeAbility.Tick: {arg}"); } } private void TryActivate() { if ((Object)(object)AbilityBase.Mode == (Object)null || AbilityBase.Mode.Mode != PursuerMode.Ghost) { Plugin.Log.LogInfo((object)"DirectorModeAbility: Director mode only available while ghosting."); return; } RebuildCycle(); if (_cycle.Count == 0) { Plugin.Log.LogWarning((object)"DirectorModeAbility: current level has no spawnable enemy types; Director mode not activated."); return; } _selectedIndex = Mathf.Clamp(_selectedIndex, 0, _cycle.Count - 1); if (_budget == null) { _budget = new SpawnBudget(PursuerConfig.SpawnBudgetMax, PursuerConfig.SpawnBudgetRechargeInterval, Time.time); } _active = true; IsActive = true; } private void Deactivate() { _active = false; IsActive = false; } public void ForceReset() { Deactivate(); _budget = null; } private void RebuildCycle() { _cycle.Clear(); SelectableLevel val = (((Object)(object)RoundManager.Instance != (Object)null) ? RoundManager.Instance.currentLevel : null); if ((Object)(object)val == (Object)null || val.Enemies == null) { return; } foreach (SpawnableEnemyWithRarity enemy in val.Enemies) { EnemyType val2 = enemy?.enemyType; if (!((Object)(object)val2 == (Object)null) && !val2.spawningDisabled && !((Object)(object)val2.enemyPrefab == (Object)null)) { _cycle.Add(val2); } } } private void HandleCycleInput() { if (_cycle.Count != 0) { float axis = Input.GetAxis("Mouse ScrollWheel"); int num = ((axis > 0f) ? 1 : ((axis < 0f) ? (-1) : 0)); if (Input.GetKeyDown((KeyCode)93)) { num = 1; } else if (Input.GetKeyDown((KeyCode)91)) { num = -1; } if (num != 0) { _selectedIndex = ((_selectedIndex + num) % _cycle.Count + _cycle.Count) % _cycle.Count; } } } private void TrySpawn() { //IL_0057: 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_008b: 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_00a9: Unknown result type (might be due to invalid IL or missing references) if (_cycle.Count == 0 || _budget == null || (Object)(object)RoundManager.Instance == (Object)null) { return; } if (!_budget.TrySpend(Time.time)) { Plugin.Log.LogInfo((object)"DirectorModeAbility: spawn budget empty."); return; } Vector3? val = FindFloorPoint(); if (val.HasValue) { Vector3 valueOrDefault = val.GetValueOrDefault(); EnemyType val2 = _cycle[_selectedIndex]; try { RoundManager.Instance.SpawnEnemyGameObject(valueOrDefault, 0f, -1, val2); Plugin.Log.LogInfo((object)$"DirectorModeAbility: spawned {val2.enemyName} at {valueOrDefault}."); return; } catch (Exception arg) { Plugin.Log.LogError((object)$"DirectorModeAbility.TrySpawn: {arg}"); RefundLastSpend(); return; } } Plugin.Log.LogInfo((object)"DirectorModeAbility: no floor point under aim; spawn cancelled."); RefundLastSpend(); } private static void RefundLastSpend() { } private static Vector3? FindFloorPoint() { //IL_000c: 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_0033: Unknown result type (might be due to invalid IL or missing references) Transform cameraTransform = GhostCamera.GetOrCreate().CameraTransform; RaycastHit val = default(RaycastHit); if (!Physics.Raycast(cameraTransform.position, cameraTransform.forward, ref val, 120f, -1, (QueryTriggerInteraction)1)) { return null; } return ((RaycastHit)(ref val)).point; } } public sealed class DoorLockAbility : AbilityBase { private const float RaycastDistance = 5f; private static readonly LNetworkMessage<ulong> Msg; private readonly Dictionary<ulong, float> _expiryByDoorId = new Dictionary<ulong, float>(); static DoorLockAbility() { Msg = LNetworkMessage<ulong>.Connect("LethalPursuer.DoorLock", (Action<ulong, ulong>)null, (Action<ulong>)null, (Action<ulong, ulong>)null); try { Msg.OnClientReceived += delegate(ulong doorNetworkObjectId) { ApplyLock(doorNetworkObjectId); }; } catch (Exception arg) { Plugin.Log.LogError((object)$"DoorLockAbility static init: {arg}"); } } public override void Tick() { try { if (AbilityBase.IsHostActive && AbilityBase.InGhostOrPursuer) { if (PursuerConfig.DoorLock.Pressed()) { TryLockDoorAhead(); } TickExpiry(); } } catch (Exception arg) { Plugin.Log.LogError((object)$"DoorLockAbility.Tick: {arg}"); } } private void TryLockDoorAhead() { DoorLock val = FindDoorAhead(); if (!((Object)(object)val == (Object)null) && val.canBeLocked && !val.isLocked) { ulong networkObjectId = ((NetworkBehaviour)val).NetworkObjectId; ApplyLock(networkObjectId); Msg.SendClients(networkObjectId); _expiryByDoorId[networkObjectId] = Time.time + (float)PursuerConfig.DoorLockDuration; } } private void TickExpiry() { if (_expiryByDoorId.Count == 0) { return; } List<ulong> list = null; foreach (KeyValuePair<ulong, float> item in _expiryByDoorId) { if (!(Time.time < item.Value)) { (list ?? (list = new List<ulong>())).Add(item.Key); } } if (list == null) { return; } foreach (ulong item2 in list) { _expiryByDoorId.Remove(item2); UnlockDoorById(item2); } } private static DoorLock? FindDoorAhead() { //IL_000c: 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) Transform cameraTransform = GhostCamera.GetOrCreate().CameraTransform; RaycastHit val = default(RaycastHit); if (!Physics.Raycast(cameraTransform.position, cameraTransform.forward, ref val, 5f, -1, (QueryTriggerInteraction)2)) { return null; } return ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<DoorLock>(); } private static void ApplyLock(ulong doorNetworkObjectId) { try { DoorLock val = ResolveDoor(doorNetworkObjectId); if (!((Object)(object)val == (Object)null) && val.canBeLocked) { val.LockDoor((float)PursuerConfig.DoorLockDuration); } } catch (Exception arg) { Plugin.Log.LogError((object)$"DoorLockAbility.ApplyLock: {arg}"); } } private static void UnlockDoorById(ulong doorNetworkObjectId) { try { DoorLock val = ResolveDoor(doorNetworkObjectId); if ((Object)(object)val != (Object)null && val.isLocked) { val.UnlockDoorSyncWithServer(); } } catch (Exception arg) { Plugin.Log.LogError((object)$"DoorLockAbility.UnlockDoorById: {arg}"); } } private static DoorLock? ResolveDoor(ulong doorNetworkObjectId) { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || singleton.SpawnManager == null) { return null; } if (!singleton.SpawnManager.SpawnedObjects.TryGetValue(doorNetworkObjectId, out var value) || (Object)(object)value == (Object)null) { return null; } return ((Component)value).GetComponent<DoorLock>(); } } public sealed class FakeRadarBlipAbility : AbilityBase { public struct BlipMessage { public ulong BlipId; public bool Add; public Vector3 Position; public string Label; } private static readonly string[] FakePlayerLabels; private static readonly LNetworkMessage<BlipMessage> Msg; private static readonly Dictionary<ulong, GameObject> ActiveBlipObjects; private readonly Dictionary<ulong, float> _expiryById = new Dictionary<ulong, float>(); private readonly List<ulong> _activeOrder = new List<ulong>(); private bool _toggledOn; private ulong _nextId = 1uL; static FakeRadarBlipAbility() { FakePlayerLabels = new string[6] { "??? #1", "??? #2", "??? #3", "SIGNAL LOST", "UNKNOWN", "static" }; Msg = LNetworkMessage<BlipMessage>.Connect("LethalPursuer.FakeBlip", (Action<BlipMessage, ulong>)null, (Action<BlipMessage>)null, (Action<BlipMessage, ulong>)null); ActiveBlipObjects = new Dictionary<ulong, GameObject>(); try { Msg.OnClientReceived += delegate(BlipMessage msg) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (msg.Add) { ApplyAdd(msg.BlipId, msg.Position, msg.Label); } else { ApplyRemove(msg.BlipId); } }; } catch (Exception arg) { Plugin.Log.LogError((object)$"FakeRadarBlipAbility static init: {arg}"); } } public override void Tick() { try { if (!AbilityBase.IsHostActive || !AbilityBase.InGhostOrPursuer) { if (_toggledOn) { RemoveAllOwnedByHost(); } return; } if (PursuerConfig.FakeBlip.Pressed()) { _toggledOn = !_toggledOn; if (_toggledOn) { SpawnOne(); } else { RemoveAllOwnedByHost(); } } TickExpiry(); } catch (Exception arg) { Plugin.Log.LogError((object)$"FakeRadarBlipAbility.Tick: {arg}"); } } private void SpawnOne() { //IL_0080: 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_00c5: 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_00ec: Unknown result type (might be due to invalid IL or missing references) while (_activeOrder.Count >= Math.Max(1, PursuerConfig.MaxFakeBlips)) { ulong num = _activeOrder[0]; _activeOrder.RemoveAt(0); _expiryById.Remove(num); ApplyRemove(num); Msg.SendClients(new BlipMessage { BlipId = num, Add = false }); } ulong num2 = _nextId++; Vector3 position = PlausibleSpawnPosition(); string label = FakePlayerLabels[Random.Range(0, FakePlayerLabels.Length)]; _activeOrder.Add(num2); _expiryById[num2] = Time.time + (float)Math.Max(1, PursuerConfig.FakeBlipDuration); ApplyAdd(num2, position, label); Msg.SendClients(new BlipMessage { BlipId = num2, Add = true, Position = position, Label = label }); } private static Vector3 PlausibleSpawnPosition() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return AbilityBase.GhostPosition; } private void TickExpiry() { if (_expiryById.Count == 0) { return; } List<ulong> list = null; foreach (KeyValuePair<ulong, float> item in _expiryById) { if (!(Time.time < item.Value)) { (list ?? (list = new List<ulong>())).Add(item.Key); } } if (list == null) { return; } foreach (ulong item2 in list) { _expiryById.Remove(item2); _activeOrder.Remove(item2); ApplyRemove(item2); Msg.SendClients(new BlipMessage { BlipId = item2, Add = false }); } if (_activeOrder.Count == 0) { _toggledOn = false; } } private void RemoveAllOwnedByHost() { if (_activeOrder.Count == 0) { _toggledOn = false; return; } foreach (ulong item in _activeOrder) { _expiryById.Remove(item); ApplyRemove(item); Msg.SendClients(new BlipMessage { BlipId = item, Add = false }); } _activeOrder.Clear(); _toggledOn = false; } private static void ApplyAdd(ulong blipId, Vector3 position, string label) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown try { if (!ActiveBlipObjects.ContainsKey(blipId)) { ManualCameraRenderer val = Object.FindObjectOfType<ManualCameraRenderer>(); if (!((Object)(object)val == (Object)null) && val.radarTargets != null) { GameObject val2 = new GameObject($"LethalPursuer_FakeBlip_{blipId}"); Object.DontDestroyOnLoad((Object)(object)val2); val2.transform.position = position; val.radarTargets.Add(new TransformAndName(val2.transform, label, true)); ActiveBlipObjects[blipId] = val2; } } } catch (Exception arg) { Plugin.Log.LogError((object)$"FakeRadarBlipAbility.ApplyAdd: {arg}"); } } private static void ApplyRemove(ulong blipId) { try { if (!ActiveBlipObjects.TryGetValue(blipId, out GameObject value)) { return; } ActiveBlipObjects.Remove(blipId); ManualCameraRenderer val = Object.FindObjectOfType<ManualCameraRenderer>(); if ((Object)(object)val != (Object)null && val.radarTargets != null && (Object)(object)value != (Object)null) { for (int num = val.radarTargets.Count - 1; num >= 0; num--) { if ((Object)(object)val.radarTargets[num].transform == (Object)(object)value.transform) { val.radarTargets.RemoveAt(num); } } } if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } } catch (Exception arg) { Plugin.Log.LogError((object)$"FakeRadarBlipAbility.ApplyRemove: {arg}"); } } } public sealed class GhostVoiceAbility : AbilityBase { public struct VoiceStateMessage { public ulong HostClientId; public bool Active; public Vector3 GhostPosition; public bool Distortion; } private static readonly LNetworkMessage<VoiceStateMessage> Msg; private bool _wasHeld; static GhostVoiceAbility() { Msg = LNetworkMessage<VoiceStateMessage>.Connect("LethalPursuer.GhostVoice", (Action<VoiceStateMessage, ulong>)null, (Action<VoiceStateMessage>)null, (Action<VoiceStateMessage, ulong>)null); try { Msg.OnClientReceived += delegate(VoiceStateMessage msg) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (msg.Active) { GhostVoiceRelocator.GetOrCreate().BeginRelocate(msg.HostClientId, msg.GhostPosition, msg.Distortion); } else { GhostVoiceRelocator.GetOrCreate().EndRelocate(msg.HostClientId); } }; } catch (Exception arg) { Plugin.Log.LogError((object)$"GhostVoiceAbility static init: {arg}"); } } public override void Tick() { try { if (!AbilityBase.IsHostActive || !AbilityBase.InGhostOrPursuer) { if (_wasHeld) { StopBroadcast(); } return; } if (!PursuerConfig.GhostVoiceEnabled) { if (_wasHeld) { StopBroadcast(); } return; } bool flag = PursuerConfig.GhostVoice.Held(); if (flag && !_wasHeld) { StartBroadcast(); } else if (!flag && _wasHeld) { StopBroadcast(); } else if (flag) { UpdateBroadcastPosition(); } _wasHeld = flag; } catch (Exception arg) { Plugin.Log.LogError((object)$"GhostVoiceAbility.Tick: {arg}"); } } private void StartBroadcast() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) VoiceStateMessage voiceStateMessage = new VoiceStateMessage { HostClientId = AbilityBase.LocalId, Active = true, GhostPosition = AbilityBase.GhostPosition, Distortion = PursuerConfig.GhostVoiceDistortion }; Msg.SendClients(voiceStateMessage); } private void UpdateBroadcastPosition() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) Msg.SendClients(new VoiceStateMessage { HostClientId = AbilityBase.LocalId, Active = true, GhostPosition = AbilityBase.GhostPosition, Distortion = PursuerConfig.GhostVoiceDistortion }); } private void StopBroadcast() { _wasHeld = false; Msg.SendClients(new VoiceStateMessage { HostClientId = AbilityBase.LocalId, Active = false }); } } public sealed class GhostVoiceRelocator : MonoBehaviour { private static GhostVoiceRelocator? _instance; private bool _active; private ulong _hostClientId; private Vector3 _targetPosition; private bool _distortion; private AudioSource? _voiceAudio; private AudioLowPassFilter? _lowPass; private float _originalSpatialBlend; private float _originalLowPassCutoff; private bool _originalLowPassEnabled; private bool _capturedOriginal; public static GhostVoiceRelocator GetOrCreate() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if ((Object)(object)_instance != (Object)null) { return _instance; } GameObject val = new GameObject("LethalPursuer_GhostVoiceRelocator"); Object.DontDestroyOnLoad((Object)val); _instance = val.AddComponent<GhostVoiceRelocator>(); return _instance; } public void BeginRelocate(ulong hostClientId, Vector3 ghostPosition, bool distortion) { //IL_0008: 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) try { _hostClientId = hostClientId; _targetPosition = ghostPosition; _distortion = distortion; if (!_active) { _active = true; ResolveVoiceSource(); CaptureOriginalIfNeeded(); ApplyActiveState(); } } catch (Exception arg) { Plugin.Log.LogError((object)$"GhostVoiceRelocator.BeginRelocate: {arg}"); } } public void EndRelocate(ulong hostClientId) { try { if (_active && hostClientId == _hostClientId) { _active = false; RestoreOriginal(); } } catch (Exception arg) { Plugin.Log.LogError((object)$"GhostVoiceRelocator.EndRelocate: {arg}"); } } private void ResolveVoiceSource() { _voiceAudio = null; _lowPass = null; PlayerControllerB[] array = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.allPlayerScripts : null); if (array == null) { return; } PlayerControllerB[] array2 = array; foreach (PlayerControllerB val in array2) { if (!((Object)(object)val == (Object)null) && val.actualClientId == _hostClientId) { _voiceAudio = val.currentVoiceChatAudioSource; break; } } if ((Object)(object)_voiceAudio != (Object)null) { _lowPass = ((Component)_voiceAudio).GetComponent<AudioLowPassFilter>(); } } private void CaptureOriginalIfNeeded() { if (!_capturedOriginal && !((Object)(object)_voiceAudio == (Object)null)) { _originalSpatialBlend = _voiceAudio.spatialBlend; if ((Object)(object)_lowPass != (Object)null) { _originalLowPassEnabled = ((Behaviour)_lowPass).enabled; _originalLowPassCutoff = _lowPass.cutoffFrequency; } _capturedOriginal = true; } } private void ApplyActiveState() { if (!((Object)(object)_voiceAudio == (Object)null)) { _voiceAudio.spatialBlend = 1f; if (_distortion && (Object)(object)_lowPass != (Object)null) { ((Behaviour)_lowPass).enabled = true; _lowPass.cutoffFrequency = 800f; } } } private void RestoreOriginal() { if ((Object)(object)_voiceAudio != (Object)null && _capturedOriginal) { _voiceAudio.spatialBlend = _originalSpatialBlend; } if ((Object)(object)_lowPass != (Object)null && _capturedOriginal) { ((Behaviour)_lowPass).enabled = _originalLowPassEnabled; _lowPass.cutoffFrequency = _originalLowPassCutoff; } _capturedOriginal = false; _voiceAudio = null; _lowPass = null; } private void LateUpdate() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (!_active) { return; } try { if ((Object)(object)_voiceAudio == (Object)null) { ResolveVoiceSource(); } if (!((Object)(object)_voiceAudio == (Object)null)) { ((Component)_voiceAudio).transform.position = _targetPosition; } } catch (Exception arg) { Plugin.Log.LogError((object)$"GhostVoiceRelocator.LateUpdate: {arg}"); } } } public sealed class ItemCurseAbility : AbilityBase { public struct CueMessage { public ulong VictimClientId; } private const float RaycastDistance = 6f; private const float AggroRadius = 60f; internal static readonly LNetworkMessage<ulong> GrabReportMsg; private static readonly LNetworkMessage<CueMessage> CueMsg; internal static ulong? CursedItemNetworkObjectId; private static readonly Dictionary<EnemyAI, float> ActiveAggro; private static readonly Dictionary<EnemyAI, PlayerControllerB> AggroVictim; static ItemCurseAbility() { GrabReportMsg = LNetworkMessage<ulong>.Connect("LethalPursuer.ItemCurse.GrabReport", (Action<ulong, ulong>)null, (Action<ulong>)null, (Action<ulong, ulong>)null); CueMsg = LNetworkMessage<CueMessage>.Connect("LethalPursuer.ItemCurse.Cue", (Action<CueMessage, ulong>)null, (Action<CueMessage>)null, (Action<CueMessage, ulong>)null); ActiveAggro = new Dictionary<EnemyAI, float>(); AggroVictim = new Dictionary<EnemyAI, PlayerControllerB>(); try { GrabReportMsg.OnServerReceived += delegate(ulong grabbedNetworkObjectId, ulong grabberClientId) { OnGrabReported(grabbedNetworkObjectId, grabberClientId); }; CueMsg.OnClientReceived += delegate(CueMessage msg) { PlayCue(msg.VictimClientId); }; } catch (Exception arg) { Plugin.Log.LogError((object)$"ItemCurseAbility static init: {arg}"); } } public override void Tick() { try { if (AbilityBase.IsHostActive && AbilityBase.InGhostOrPursuer) { if (PursuerConfig.ItemCurse.Pressed()) { TryCurseItemAhead(); } TickAggro(); } } catch (Exception arg) { Plugin.Log.LogError((object)$"ItemCurseAbility.Tick: {arg}"); } } private void TryCurseItemAhead() { GrabbableObject val = FindGrabbableAhead(); if (!((Object)(object)val == (Object)null)) { CursedItemNetworkObjectId = ((NetworkBehaviour)val).NetworkObjectId; } } private static GrabbableObject? FindGrabbableAhead() { //IL_000c: 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) Transform cameraTransform = GhostCamera.GetOrCreate().CameraTransform; RaycastHit val = default(RaycastHit); if (!Physics.Raycast(cameraTransform.position, cameraTransform.forward, ref val, 6f, -1, (QueryTriggerInteraction)2)) { return null; } return ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<GrabbableObject>(); } private static void OnGrabReported(ulong grabbedNetworkObjectId, ulong grabberClientId) { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) try { ulong? cursedItemNetworkObjectId = CursedItemNetworkObjectId; if (!cursedItemNetworkObjectId.HasValue) { return; } ulong valueOrDefault = cursedItemNetworkObjectId.GetValueOrDefault(); if (valueOrDefault != grabbedNetworkObjectId) { return; } CursedItemNetworkObjectId = null; PlayerControllerB val = ResolvePlayerByClientId(grabberClientId); if ((Object)(object)val == (Object)null) { return; } float value = Time.time + (float)Math.Max(1, PursuerConfig.ItemCurseAggroDuration); List<EnemyAI> list = (((Object)(object)RoundManager.Instance != (Object)null) ? RoundManager.Instance.SpawnedEnemies : null); if (list != null) { foreach (EnemyAI item in list) { if (!((Object)(object)item == (Object)null) && !item.isEnemyDead && !(Vector3.Distance(((Component)item).transform.position, ((Component)val).transform.position) > 60f)) { item.SetMovingTowardsTargetPlayer(val); ActiveAggro[item] = value; AggroVictim[item] = val; } } } CueMsg.SendClients(new CueMessage { VictimClientId = val.actualClientId }); } catch (Exception arg) { Plugin.Log.LogError((object)$"ItemCurseAbility.OnGrabReported: {arg}"); } } private static void TickAggro() { //IL_0097: Unknown result type (might be due to invalid IL or missing references) if (ActiveAggro.Count == 0) { return; } List<EnemyAI> list = null; foreach (KeyValuePair<EnemyAI, float> item in ActiveAggro) { EnemyAI key = item.Key; PlayerControllerB value; if ((Object)(object)key == (Object)null || key.isEnemyDead) { (list ?? (list = new List<EnemyAI>())).Add(key); } else if (Time.time >= item.Value) { (list ?? (list = new List<EnemyAI>())).Add(key); } else if (AggroVictim.TryGetValue(key, out value) && (Object)(object)value != (Object)null) { key.SetDestinationToPosition(((Component)value).transform.position, true); } } if (list == null) { return; } foreach (EnemyAI item2 in list) { ActiveAggro.Remove(item2); AggroVictim.Remove(item2); } } private static PlayerControllerB? ResolvePlayerByClientId(ulong clientId) { PlayerControllerB[] array = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.allPlayerScripts : null); if (array == null) { return null; } PlayerControllerB[] array2 = array; foreach (PlayerControllerB val in array2) { if ((Object)(object)val != (Object)null && val.actualClientId == clientId) { return val; } } return null; } private static void PlayCue(ulong victimClientId) { try { PlayerControllerB val = ResolvePlayerByClientId(victimClientId); if (!((Object)(object)val == (Object)null) && !((Object)(object)val.itemAudio == (Object)null)) { AudioClip[] array = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.playerGrabSFX : null); if (array != null && array.Length != 0) { AudioClip val2 = array[Random.Range(0, array.Length)]; val.itemAudio.PlayOneShot(val2, 1f); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"ItemCurseAbility.PlayCue: {arg}"); } } } [HarmonyPatch] internal static class ItemCursePatches { [HarmonyPatch(typeof(GrabbableObject), "GrabItemOnClient")] [HarmonyPostfix] private static void OnGrabItemOnClient(GrabbableObject __instance) { try { if (!((Object)(object)__instance == (Object)null)) { ItemCurseAbility.GrabReportMsg.SendServer(((NetworkBehaviour)__instance).NetworkObjectId); } } catch (Exception arg) { Plugin.Log.LogError((object)$"ItemCursePatches.OnGrabItemOnClient: {arg}"); } } } public sealed class LeashAbility : AbilityBase { private const float RaycastDistance = 60f; private const float FollowOffset = 3f; private const float RepathInterval = 0.25f; private EnemyAI? _first; private EnemyAI? _second; private float _repathTimer; public bool IsLeashActive { get { if ((Object)(object)_first != (Object)null) { return (Object)(object)_second != (Object)null; } return false; } } public override void Tick() { try { if (AbilityBase.IsHostActive && AbilityBase.InGhostOrPursuer) { if (PursuerConfig.Leash.Pressed()) { HandleClick(); } TickFollow(); } } catch (Exception arg) { Plugin.Log.LogError((object)$"LeashAbility.Tick: {arg}"); } } private void HandleClick() { EnemyAI val = FindEnemyAhead(); if (!((Object)(object)val == (Object)null)) { if ((Object)(object)_first == (Object)null) { _first = val; _second = null; } else if (val != _first) { _second = val; LeashGuiIcon.GetOrCreate().SetActive(active: true); } } } private void TickFollow() { //IL_0087: 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_008d: 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_00ba: 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_00c1: Unknown result type (might be due to invalid IL or missing references