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 GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using Overlay; using SpectateEnemy.UI; using TMPro; using Unity.Netcode; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SpectateEnemy")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("My first plugin")] [assembly: AssemblyFileVersion("2.8.0.0")] [assembly: AssemblyInformationalVersion("2.8.0")] [assembly: AssemblyProduct("SpectateEnemy")] [assembly: AssemblyTitle("SpectateEnemy")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.8.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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SpectateEnemy { internal static class Doorways { internal const float Reach = 5f; private const float AimDot = 0.85f; private const float MarkerSize = 18f; private static EntranceTeleport[] doors; private static float nextScan; private static bool useHeld; internal static EntranceTeleport Aimed { get; private set; } internal static void Forget() { doors = null; nextScan = 0f; useHeld = false; Aimed = null; } internal static void Tick() { //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) Camera val = ActiveCamera(); if ((Object)(object)val == (Object)null) { Forget(); return; } if (Time.time >= nextScan) { nextScan = Time.time + 2f; doors = Object.FindObjectsByType((FindObjectsSortMode)0); } Aimed = AimedAt(val); PlayerControllerB val2 = Local(); if ((Object)(object)val2 == (Object)null || val2.playerActions == null || SpectateEnemies.Instance.IsMenuOpen()) { useHeld = false; return; } MovementActions movement = val2.playerActions.Movement; bool flag = ((MovementActions)(ref movement)).Interact.IsPressed(); bool flag2 = flag && !useHeld; useHeld = flag; if (flag2 && (Object)(object)Aimed != (Object)null) { Use(Aimed); } } private static void Use(EntranceTeleport door) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) SpectateEnemies instance = SpectateEnemies.Instance; door.TeleportPlayer(); if (instance.Mode == SpectateMode.Ghost) { GhostBody.Settle(); return; } if ((Object)(object)door.exitScript != (Object)null && (Object)(object)door.exitScript.entrancePoint != (Object)null) { instance.SetFreeCamPosition(door.exitScript.entrancePoint.position); } Aimed = null; } private static EntranceTeleport AimedAt(Camera camera) { //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) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) if (doors == null) { return null; } Vector3 position = ((Component)camera).transform.position; Vector3 forward = ((Component)camera).transform.forward; EntranceTeleport result = null; float num = 0.85f; EntranceTeleport[] array = doors; foreach (EntranceTeleport val in array) { if ((Object)(object)val == (Object)null) { continue; } Vector3 val2 = PointOf(val) - position; if (!(((Vector3)(ref val2)).sqrMagnitude > 25f)) { float num2 = Vector3.Dot(forward, ((Vector3)(ref val2)).normalized); if (num2 > num) { num = num2; result = val; } } } return result; } internal static Vector3 PointOf(EntranceTeleport door) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) return ((Object)(object)door.entrancePoint != (Object)null) ? door.entrancePoint.position : ((Component)door).transform.position; } internal static string NameOf(EntranceTeleport door) { if (door.entranceId != 0) { return "FIRE EXIT"; } return door.isEntranceToBuilding ? "ENTRANCE" : "EXIT"; } internal static Camera ActiveCamera() { if ((Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null) { return null; } SpectateEnemies instance = SpectateEnemies.Instance; if ((Object)(object)instance == (Object)null) { return null; } if (instance.Mode == SpectateMode.Ghost) { PlayerControllerB val = Local(); return ((Object)(object)val == (Object)null) ? null : val.gameplayCamera; } return (instance.Mode == SpectateMode.FreeCam) ? StartOfRound.Instance.spectateCamera : null; } internal static void DrawMarkers() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_0110: 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_013a: 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_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Expected O, but got Unknown //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) Camera val = ActiveCamera(); if ((Object)(object)val == (Object)null || doors == null) { return; } Color color = GUI.color; GUI.color = OverlayStyles.Primary; Vector3 position = ((Component)val).transform.position; EntranceTeleport[] array = doors; Rect val5 = default(Rect); foreach (EntranceTeleport val2 in array) { if (!((Object)(object)val2 == (Object)null)) { Vector3 val3 = PointOf(val2); Vector3 val4 = val.WorldToScreenPoint(val3); if (!(val4.z <= 0f)) { float x = val4.x; float num = (float)Screen.height - val4.y; bool flag = (Object)(object)val2 == (Object)(object)Aimed; float num2 = 9f; float num3 = (flag ? 3f : 1f); ((Rect)(ref val5))..ctor(x - num2, num - num2, 18f, 18f); OverlayStyles.Fill(new Rect(((Rect)(ref val5)).x, ((Rect)(ref val5)).y, ((Rect)(ref val5)).width, num3), OverlayStyles.Primary); OverlayStyles.Fill(new Rect(((Rect)(ref val5)).x, ((Rect)(ref val5)).yMax - num3, ((Rect)(ref val5)).width, num3), OverlayStyles.Primary); OverlayStyles.Fill(new Rect(((Rect)(ref val5)).x, ((Rect)(ref val5)).y, num3, ((Rect)(ref val5)).height), OverlayStyles.Primary); OverlayStyles.Fill(new Rect(((Rect)(ref val5)).xMax - num3, ((Rect)(ref val5)).y, num3, ((Rect)(ref val5)).height), OverlayStyles.Primary); string text = $"{NameOf(val2)} {Vector3.Distance(position, val3):F0}m"; GUIContent val6 = new GUIContent(text); Vector2 val7 = OverlayStyles.Label.CalcSize(val6); GUI.Label(new Rect(x - val7.x / 2f, ((Rect)(ref val5)).yMax + 2f, val7.x, val7.y), val6, flag ? OverlayStyles.LabelStrong : OverlayStyles.Label); } } } GUI.color = color; } private static PlayerControllerB Local() { return ((Object)(object)GameNetworkManager.Instance == (Object)null) ? null : GameNetworkManager.Instance.localPlayerController; } } internal static class GhostBody { private const int FloorLayer = 2; private const float FloorThickness = 4f; private const float FloorWidth = 6f; private const float ProbeAbove = 1.2f; private const float ProbeBelow = 4f; private const float DoubleTapWindow = 0.35f; private const float FlySprintMultiplier = 2.5f; internal static float FlySpeed = 9f; private static readonly FieldRef CameraDisabled = AccessTools.FieldRefAccess("isCameraDisabled"); private static GameObject floor; private static BoxCollider floorBox; private static LayerMask savedExcludeLayers; private static bool savedDeadPosition; private static float savedMovementSpeed; private static bool savedTestingPlayer; private static int savedLayer; private static bool jumpHeld; private static float lastJumpTime; private static float flyHeight; internal static bool Active { get; private set; } internal static bool Flying { get; private set; } internal static bool NoClip { get; private set; } private static PlayerControllerB Local() { return ((Object)(object)GameNetworkManager.Instance == (Object)null) ? null : GameNetworkManager.Instance.localPlayerController; } internal static bool Enter(Vector3 at) { //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_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) PlayerControllerB val = Local(); if (Active || (Object)(object)val == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)HUDManager.Instance == (Object)null) { return false; } Active = true; Flying = false; NoClip = false; jumpHeld = false; lastJumpTime = 0f; EnsureFloor(val); savedDeadPosition = val.setPositionOfDeadPlayer; savedExcludeLayers = ((Collider)val.thisController).excludeLayers; savedMovementSpeed = val.movementSpeed; savedTestingPlayer = val.isTestingPlayer; savedLayer = ((Component)val).gameObject.layer; val.isTestingPlayer = true; ((Component)val).gameObject.layer = 2; val.setPositionOfDeadPlayer = false; val.isClimbingLadder = false; val.inSpecialInteractAnimation = false; val.disableMoveInput = false; val.disableLookInput = false; val.disableInteract = true; val.ResetZAndXRotation(); ((Collider)val.thisController).enabled = true; ApplyCollision(val); val.TeleportPlayer(GroundUnder(at), false, 0f, false, true); val.DisablePlayerModel(((Component)val).gameObject, true, true); val.Crouch(false); CameraDisabled.Invoke(val) = true; HUDManager.Instance.HideHUD(false); HUDManager.Instance.SetNearDepthOfFieldEnabled(false); PlaceFloor(val); return true; } internal static void Exit() { //IL_0079: Unknown result type (might be due to invalid IL or missing references) if (!Active) { return; } Active = false; Flying = false; NoClip = false; DestroyFloor(); PlayerControllerB val = Local(); if (!((Object)(object)val == (Object)null)) { val.isTestingPlayer = savedTestingPlayer; ((Component)val).gameObject.layer = savedLayer; val.setPositionOfDeadPlayer = savedDeadPosition; val.disableInteract = false; ((Collider)val.thisController).excludeLayers = savedExcludeLayers; val.movementSpeed = savedMovementSpeed; val.DisablePlayerModel(((Component)val).gameObject, false, false); ((Renderer)val.thisPlayerModelArms).enabled = false; val.hasBegunSpectating = false; if ((Object)(object)StartOfRound.Instance != (Object)null) { StartOfRound.Instance.SwitchCamera(StartOfRound.Instance.spectateCamera); val.ChangeAudioListenerToObject(((Component)StartOfRound.Instance.spectateCamera).gameObject); } if ((Object)(object)HUDManager.Instance != (Object)null) { HUDManager.Instance.HideHUD(true); } } } internal static bool Warp(Vector3 point) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB val = Local(); if (!Active || (Object)(object)val == (Object)null) { return false; } val.TeleportPlayer((NoClip || Flying) ? point : GroundUnder(point), false, 0f, false, true); flyHeight = ((Component)val).transform.position.y; PlaceFloor(val); return true; } internal static void SetNoClip(bool on) { if (Active) { NoClip = on; PlayerControllerB val = Local(); if ((Object)(object)val != (Object)null) { ApplyCollision(val); } } } internal static void Settle() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB val = Local(); if (Active && !((Object)(object)val == (Object)null)) { flyHeight = ((Component)val).transform.position.y; PlaceFloor(val); } } private static void ApplyCollision(PlayerControllerB player) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) ((Collider)player.thisController).excludeLayers = (NoClip ? LayerMask.op_Implicit(-5) : savedExcludeLayers); if ((Object)(object)floorBox != (Object)null) { ((Collider)floorBox).enabled = NoClip || Flying; } } private static Vector3 GroundUnder(Vector3 point) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)StartOfRound.Instance == (Object)null) { return point; } Ray val = default(Ray); ((Ray)(ref val))..ctor(point + Vector3.up * 1.2f, Vector3.down); RaycastHit val2 = default(RaycastHit); return Physics.Raycast(val, ref val2, 200f, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1) ? ((RaycastHit)(ref val2)).point : point; } internal static void LateTick() { PlayerControllerB val = Local(); if (Active && !((Object)(object)val == (Object)null)) { val.sprintMeter = 1f; val.isExhausted = false; HideLivingHud(); ReadFlightToggle(val); if (Flying) { Fly(val); return; } val.movementSpeed = savedMovementSpeed; PlaceFloor(val); } } private static void HideLivingHud() { HUDManager instance = HUDManager.Instance; if (!((Object)(object)instance == (Object)null)) { if (instance.Inventory != null && (Object)(object)instance.Inventory.canvasGroup != (Object)null) { instance.Inventory.canvasGroup.alpha = 0f; } if (instance.PlayerInfo != null && (Object)(object)instance.PlayerInfo.canvasGroup != (Object)null) { instance.PlayerInfo.canvasGroup.alpha = 0f; } } } private static void ReadFlightToggle(PlayerControllerB player) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) if (player.playerActions == null || ((Object)(object)SpectateEnemies.Instance != (Object)null && SpectateEnemies.Instance.IsMenuOpen())) { jumpHeld = false; return; } MovementActions movement = player.playerActions.Movement; bool flag = ((MovementActions)(ref movement)).Jump.IsPressed(); bool flag2 = flag && !jumpHeld; jumpHeld = flag; if (!flag2) { return; } if (Time.time - lastJumpTime <= 0.35f) { Flying = !Flying; if (Flying) { player.Crouch(false); flyHeight = ((Component)player).transform.position.y; } ApplyCollision(player); lastJumpTime = 0f; } else { lastJumpTime = Time.time; } } private static void Fly(PlayerControllerB player) { //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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0134: 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_00a8: Unknown result type (might be due to invalid IL or missing references) player.movementSpeed = FlySpeed; if (player.playerActions != null && ((Object)(object)SpectateEnemies.Instance == (Object)null || !SpectateEnemies.Instance.IsMenuOpen())) { float flySpeed = FlySpeed; MovementActions movement = player.playerActions.Movement; float num = flySpeed * (((MovementActions)(ref movement)).Sprint.IsPressed() ? 2.5f : 1f); movement = player.playerActions.Movement; if (((MovementActions)(ref movement)).Jump.IsPressed()) { flyHeight += num * Time.deltaTime; } movement = player.playerActions.Movement; if (((MovementActions)(ref movement)).Crouch.IsPressed()) { flyHeight -= num * Time.deltaTime; } } Vector3 position = ((Component)player).transform.position; SetFloor(position.x, flyHeight, position.z); float num2 = flyHeight - position.y; if (Mathf.Abs(num2) > 0.001f && ((Collider)player.thisController).enabled) { player.thisController.Move(Vector3.up * num2); } } private static void PlaceFloor(PlayerControllerB player) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_007c: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)floor == (Object)null) && !((Object)(object)StartOfRound.Instance == (Object)null)) { Vector3 position = ((Component)player).transform.position; Ray val = default(Ray); ((Ray)(ref val))..ctor(position + Vector3.up * 1.2f, Vector3.down); RaycastHit val2 = default(RaycastHit); float top = (Physics.Raycast(val, ref val2, 5.2f, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1) ? ((RaycastHit)(ref val2)).point.y : (position.y - 500f)); SetFloor(position.x, top, position.z); } } private static void SetFloor(float x, float top, float z) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)floor != (Object)null) { floor.transform.position = new Vector3(x, top - 2f, z); } } private static void EnsureFloor(PlayerControllerB player) { //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_002a: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)floor != (Object)null)) { floor = new GameObject("SpectateEnemiesGhostFloor") { layer = 2 }; floorBox = floor.AddComponent(); floorBox.size = new Vector3(6f, 4f, 6f); ((Collider)floorBox).excludeLayers = LayerMask.op_Implicit(-5); Object.DontDestroyOnLoad((Object)(object)floor); } } private static void DestroyFloor() { if (!((Object)(object)floor == (Object)null)) { Object.Destroy((Object)(object)floor); floor = null; floorBox = null; } } } [BepInPlugin("SpectateEnemy", "SpectateEnemy", "2.9.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] internal class Plugin : BaseUnityPlugin { public static MethodInfo raycastSpectate; public static MethodInfo displaySpectatorTip; public static ConfigFile Configuration; private Harmony harmony; private void Awake() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown Configuration = ((BaseUnityPlugin)this).Config; harmony = new Harmony("SpectateEnemy"); harmony.PatchAll(); raycastSpectate = AccessTools.Method(typeof(PlayerControllerB), "RaycastSpectateCameraAroundPivot", (Type[])null, (Type[])null); displaySpectatorTip = AccessTools.Method(typeof(HUDManager), "DisplaySpectatorTip", (Type[])null, (Type[])null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"SpectateEnemy loaded!"); } } internal static class RenderView { internal const float MaxBrightness = 5f; internal static ConfigEntry Brightness; internal static ConfigEntry FogOff; private static readonly Type FogType = AccessTools.TypeByName("UnityEngine.Rendering.HighDefinition.LocalVolumetricFog"); private static readonly List silenced = new List(); private static Light light; private static Component lightData; private static MethodInfo setIntensity; private static float baseIntensity; private static float nextFogScan; private static bool applied; internal static void Init() { Brightness = Plugin.Configuration.Bind("Render", "Brightness", 0f, "How bright the world is while you are dead, inside and out. 0 leaves it as the game lit it; 1 is about what the night vision in the facility gives you. Kept between deaths."); FogOff = Plugin.Configuration.Bind("Render", "Disable Fog", false, "Takes the volumetric fog out while you are dead - the weather's and the facility's both. Kept between deaths."); } internal static string Summary() { bool flag = Brightness.Value > 0.01f; if (flag && FogOff.Value) { return $"{Brightness.Value:0.##}x, no fog"; } if (FogOff.Value) { return "no fog"; } return flag ? $"{Brightness.Value:0.##}x" : "as it comes"; } internal static void Tick(Vector3 viewpoint) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) applied = true; ApplyLight(viewpoint); ApplyFog(); } internal static void Restore() { if (applied) { applied = false; if ((Object)(object)light != (Object)null) { ((Behaviour)light).enabled = false; } ReleaseFog(); } } private static void ApplyLight(Vector3 viewpoint) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp(Brightness.Value, 0f, 5f); if (num <= 0.01f) { if ((Object)(object)light != (Object)null) { ((Behaviour)light).enabled = false; } return; } EnsureLight(); if ((Object)(object)light == (Object)null) { return; } ((Component)light).transform.position = viewpoint; ((Behaviour)light).enabled = true; float num2 = baseIntensity * num; light.intensity = num2; if (setIntensity == null || (Object)(object)lightData == (Object)null) { return; } try { setIntensity.Invoke(lightData, new object[1] { num2 }); } catch (Exception) { setIntensity = null; } } private static void EnsureLight() { if ((Object)(object)light != (Object)null) { return; } PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance == (Object)null) ? null : GameNetworkManager.Instance.localPlayerController); if ((Object)(object)val == (Object)null || (Object)(object)val.nightVision == (Object)null) { return; } GameObject val2 = Object.Instantiate(((Component)val.nightVision).gameObject); ((Object)val2).name = "SpectateEnemiesViewLight"; val2.transform.SetParent((Transform)null, true); Object.DontDestroyOnLoad((Object)(object)val2); light = val2.GetComponent(); if ((Object)(object)light == (Object)null) { Object.Destroy((Object)(object)val2); return; } light.shadows = (LightShadows)0; ((Behaviour)light).enabled = false; baseIntensity = Mathf.Max(light.intensity, 1f); Type type = AccessTools.TypeByName("UnityEngine.Rendering.HighDefinition.HDAdditionalLightData"); if (!(type == null)) { lightData = val2.GetComponent(type); if ((Object)(object)lightData != (Object)null) { setIntensity = AccessTools.Method(type, "SetIntensity", new Type[1] { typeof(float) }, (Type[])null); } } } private static void ApplyFog() { if (FogType == null) { return; } if (!FogOff.Value) { ReleaseFog(); } else { if (Time.time < nextFogScan) { return; } nextFogScan = Time.time + 2f; Object[] array = Object.FindObjectsByType(FogType, (FindObjectsSortMode)0); foreach (Object val in array) { Behaviour val2 = (Behaviour)(object)((val is Behaviour) ? val : null); if (val2 != null && val2.enabled) { val2.enabled = false; silenced.Add(val2); } } } } private static void ReleaseFog() { nextFogScan = 0f; if (silenced.Count == 0) { return; } foreach (Behaviour item in silenced) { if ((Object)(object)item != (Object)null) { item.enabled = true; } } silenced.Clear(); } } internal class Spectatable : MonoBehaviour { public SpectatableType type = SpectatableType.Enemy; public string enemyName = "Enemy"; public string maskedName = string.Empty; public EnemyAI enemyInstance = null; } internal enum SpectatableType { Enemy, Masked, GhostGirl } internal enum SpectateMode { Spectate, FreeCam, Ghost } internal class SpectateEnemies : MonoBehaviour { public static SpectateEnemies Instance; public int SpectatedEnemyIndex = -1; public bool SpectatingEnemies = false; public Spectatable[] SpectatorList; public float ZoomLevel = 1f; public ConfigEntry HideControls; public SpectateMode Mode = SpectateMode.Spectate; public float FreeCamSpeed = 8f; private Vector3 camPosition; private float camYaw; private float camPitch; private Transform anchor; private string anchorName = string.Empty; private float lastScroll; internal bool LightOn { get { Light val = CurrentLight(); return (Object)(object)val != (Object)null && ((Behaviour)val).enabled; } } internal Spectatable CurrentTarget => (SpectatingEnemies && (Object)(object)anchor == (Object)null && SpectatorList != null) ? SpectatorList.ElementAtOrDefault(SpectatedEnemyIndex) : null; internal Transform CurrentAnchor => SpectatingEnemies ? anchor : null; private void Awake() { if ((Object)(object)Instance != (Object)null) { Object.Destroy((Object)(object)((Component)this).gameObject); } Instance = this; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); HideControls = Plugin.Configuration.Bind("Config", "Hide Controls", false, "Hides the controls toolip on the right hand side."); RenderView.Init(); Plugin.Configuration.SaveOnConfigSet = false; SpectateMenu.Register(); } private static bool CanControlCamera() { if ((Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null) { return false; } PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; return (Object)(object)localPlayerController != (Object)null && ((NetworkBehaviour)localPlayerController).IsOwner && localPlayerController.isPlayerDead && !StartOfRound.Instance.shipIsLeaving && (!((NetworkBehaviour)localPlayerController).IsServer || localPlayerController.isHostPlayerObject); } internal void ToggleLight() { Light val = CurrentLight(); if ((Object)(object)val != (Object)null) { ((Behaviour)val).enabled = !((Behaviour)val).enabled; } } private Light CurrentLight() { if ((Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null) { return null; } if (Mode == SpectateMode.Ghost) { PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; return ((Object)(object)localPlayerController == (Object)null) ? null : localPlayerController.helmetLight; } Camera spectateCamera = StartOfRound.Instance.spectateCamera; return ((Object)(object)spectateCamera == (Object)null) ? null : ((Component)spectateCamera).GetComponent(); } private void ReadScroll(PlayerControllerB player) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || player.playerActions == null || IsMenuOpen()) { lastScroll = 0f; return; } MovementActions movement = player.playerActions.Movement; float value = ((MovementActions)(ref movement)).SwitchItem.ReadValue(); int num = Sign(value); int num2 = Sign(lastScroll); lastScroll = value; if (num != 0 && num != num2) { if (Mode == SpectateMode.FreeCam) { FreeCamSpeed = Mathf.Clamp(FreeCamSpeed + (float)num, 1f, 40f); } else if (Mode == SpectateMode.Ghost) { GhostBody.FlySpeed = Mathf.Clamp(GhostBody.FlySpeed + (float)num, 1f, 40f); } else if (SpectatingEnemies) { ZoomLevel = Mathf.Clamp(ZoomLevel - (float)num * 0.1f, 1f, 10f); } } } private static int Sign(float value) { if (value > 0.3f) { return 1; } return (value < -0.3f) ? (-1) : 0; } internal static void SaveConfig() { if (Plugin.Configuration != null) { Plugin.Configuration.Save(); } } private Vector3 Viewpoint() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance == (Object)null) ? null : GameNetworkManager.Instance.localPlayerController); if (Mode == SpectateMode.Ghost && (Object)(object)val != (Object)null && (Object)(object)val.gameplayCamera != (Object)null) { return ((Component)val.gameplayCamera).transform.position; } Camera val2 = (((Object)(object)StartOfRound.Instance == (Object)null) ? null : StartOfRound.Instance.spectateCamera); if ((Object)(object)val2 != (Object)null) { return ((Component)val2).transform.position; } return ((Object)(object)val == (Object)null) ? Vector3.zero : ((Component)val).transform.position; } internal void SetFreeCamPosition(Vector3 point) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) camPosition = point; } private void ReadHotkeys() { if (IsMenuOpen()) { return; } Keyboard current = Keyboard.current; if (current != null) { if (((ButtonControl)current.fKey).wasPressedThisFrame) { ToggleLight(); } if (Mode == SpectateMode.Ghost && ((ButtonControl)current.nKey).wasPressedThisFrame) { GhostBody.SetNoClip(!GhostBody.NoClip); Dock.Toast(GhostBody.NoClip ? "No clip on" : "No clip off"); } } } private void LateUpdate() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) if (CanControlCamera()) { ReadScroll(GameNetworkManager.Instance.localPlayerController); ReadHotkeys(); RenderView.Tick(Viewpoint()); } else { RenderView.Restore(); Doorways.Forget(); } if (Mode == SpectateMode.Ghost) { if (!StillDead()) { SetMode(SpectateMode.Spectate); return; } GhostBody.LateTick(); Doorways.Tick(); return; } if (Mode == SpectateMode.FreeCam) { UpdateFreeCam(); if (Mode == SpectateMode.FreeCam) { Doorways.Tick(); } return; } Doorways.Forget(); if (!SpectatingEnemies) { return; } if (anchorName.Length > 0) { if ((Object)(object)anchor == (Object)null) { ClearAnchor(); SpectatingEnemies = false; Plugin.displaySpectatorTip.Invoke(HUDManager.Instance, new object[1] { "That body is gone" }); } else { ParkCamera(anchor.position, anchorName); } return; } if (SpectatorList == null || SpectatorList.Length == 0) { SpectatingEnemies = false; return; } Spectatable obj = SpectatorList.ElementAtOrDefault(SpectatedEnemyIndex); if ((Object)(object)obj == (Object)null || (Object)(object)obj.enemyInstance == (Object)null || obj.enemyInstance.isEnemyDead) { GetNextValidSpectatable(); return; } Vector3? spectatePosition = GetSpectatePosition(obj); if (!spectatePosition.HasValue) { GetNextValidSpectatable(); return; } if (obj.enemyName == "Enemy") { TryFixName(ref obj); } string label; if (obj.type == SpectatableType.Masked && obj.maskedName != string.Empty) { label = obj.maskedName; } else if (obj.type == SpectatableType.GhostGirl) { DressGirlAI component = ((Component)obj).gameObject.GetComponent(); ((EnemyAI)component).EnableEnemyMesh(true, true, true); PlayerControllerB targetPlayer = ((EnemyAI)component).targetPlayer; label = (((Object)(object)targetPlayer != (Object)null) ? (obj.maskedName + "\n(Targeting: " + targetPlayer.playerUsername + ")") : (obj.maskedName + "\n(No Target)")); } else { label = obj.enemyName; } ParkCamera(spectatePosition.Value, label); } private static bool StillDead() { PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance == (Object)null) ? null : GameNetworkManager.Instance.localPlayerController); return (Object)(object)val != (Object)null && (Object)(object)StartOfRound.Instance != (Object)null && val.isPlayerDead && !StartOfRound.Instance.shipIsLeaving; } private void ParkCamera(Vector3 point, string label) { //IL_0034: 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_00a4: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if (!((Object)(object)localPlayerController == (Object)null) && !((Object)(object)localPlayerController.spectateCameraPivot == (Object)null)) { localPlayerController.spectateCameraPivot.position = point; if ((Object)(object)HUDManager.Instance != (Object)null) { ((TMP_Text)HUDManager.Instance.spectatingPlayerText).text = $"(Spectating: {label}) [{ZoomLevel:F1}x]"; } Plugin.raycastSpectate.Invoke(localPlayerController, Array.Empty()); ((Component)((Component)localPlayerController.spectateCameraPivot).GetComponentInChildren()).transform.localPosition = Vector3.back * (ZoomLevel + 0.5f); } } private Vector3? GetSpectatePosition(Spectatable obj) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) EnemyAI val = (((Object)(object)obj == (Object)null) ? null : obj.enemyInstance); if ((Object)(object)val == (Object)null) { return null; } return ((Object)(object)val.eye == (Object)null) ? ((Component)val).transform.position : val.eye.position; } private void TryFixName(ref Spectatable obj) { MaskedPlayerEnemy val = default(MaskedPlayerEnemy); EnemyAI val2 = default(EnemyAI); if (((Component)obj).gameObject.TryGetComponent(ref val)) { obj.enemyName = (((Object)(object)val.mimickingPlayer != (Object)null) ? val.mimickingPlayer.playerUsername : ((EnemyAI)val).enemyType.enemyName); } else if (((Component)obj).gameObject.TryGetComponent(ref val2)) { obj.enemyName = val2.enemyType.enemyName; } } internal bool SpectateTarget(Spectatable target) { if ((Object)(object)target == (Object)null || (Object)(object)GameNetworkManager.Instance == (Object)null) { return false; } PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if ((Object)(object)localPlayerController == (Object)null) { return false; } RebuildSpectatorList(); int num = Array.IndexOf(SpectatorList, target); if (num < 0) { return false; } LeaveDrivenModes(); ClearAnchor(); SpectatedEnemyIndex = num; SpectatingEnemies = true; localPlayerController.spectatedPlayerScript = null; return true; } internal bool AnchorOn(Transform body, string label) { if ((Object)(object)body == (Object)null || (Object)(object)GameNetworkManager.Instance == (Object)null) { return false; } PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if ((Object)(object)localPlayerController == (Object)null) { return false; } LeaveDrivenModes(); anchor = body; anchorName = label; SpectatedEnemyIndex = -1; SpectatingEnemies = true; localPlayerController.spectatedPlayerScript = null; return true; } private void ClearAnchor() { anchor = null; anchorName = string.Empty; } private void LeaveDrivenModes() { if (Mode == SpectateMode.Ghost) { GhostBody.Exit(); } Mode = SpectateMode.Spectate; } internal bool SetMode(SpectateMode mode) { //IL_008d: 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_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) if (Mode == mode || (Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null) { return false; } PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if ((Object)(object)localPlayerController == (Object)null) { return false; } SpectateMode mode2 = Mode; if (mode2 == SpectateMode.Ghost) { GhostBody.Exit(); } Mode = mode; ClearAnchor(); SpectatingEnemies = false; if (mode == SpectateMode.Spectate) { PlayerControllerB val = NearestLivingPlayer(camPosition); if ((Object)(object)val != (Object)null) { SpectatePlayer(val); } else { localPlayerController.spectatedPlayerScript = null; } return true; } Camera spectateCamera = StartOfRound.Instance.spectateCamera; if (mode2 == SpectateMode.Spectate && (Object)(object)spectateCamera != (Object)null) { camPosition = ((Component)spectateCamera).transform.position; Vector3 eulerAngles = ((Component)spectateCamera).transform.eulerAngles; camYaw = eulerAngles.y; camPitch = ((eulerAngles.x > 180f) ? (eulerAngles.x - 360f) : eulerAngles.x); } localPlayerController.spectatedPlayerScript = null; if (mode == SpectateMode.Ghost && !GhostBody.Enter(camPosition)) { Mode = mode2; return false; } return true; } internal bool WarpCamera(Vector3 point) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (Mode == SpectateMode.Ghost) { return GhostBody.Warp(point); } if (Mode != SpectateMode.FreeCam) { return false; } Quaternion val = Quaternion.Euler(camPitch, camYaw, 0f); camPosition = point - val * Vector3.forward * 4f; return true; } internal Vector3? PositionOf(Spectatable target) { return ((Object)(object)target == (Object)null) ? ((Vector3?)null) : GetSpectatePosition(target); } private static PlayerControllerB NearestLivingPlayer(Vector3 from) { //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_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || instance.allPlayerScripts == null) { return null; } PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance == (Object)null) ? null : GameNetworkManager.Instance.localPlayerController); PlayerControllerB result = null; float num = float.MaxValue; PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts; foreach (PlayerControllerB val2 in allPlayerScripts) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)val) && !val2.isPlayerDead && val2.isPlayerControlled) { Vector3 val3 = ((Component)val2).transform.position - from; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = val2; } } } return result; } private void UpdateFreeCam() { //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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_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_00fc: 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_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014e: 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_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) if (!StillDead()) { Mode = SpectateMode.Spectate; return; } PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; Camera spectateCamera = StartOfRound.Instance.spectateCamera; if ((Object)(object)spectateCamera == (Object)null) { return; } if (!IsMenuOpen() && localPlayerController.playerActions != null) { MovementActions movement = localPlayerController.playerActions.Movement; Vector2 val = ((MovementActions)(ref movement)).Look.ReadValue() * 0.008f * (float)IngamePlayerSettings.Instance.settings.lookSensitivity; camYaw += val.x; camPitch = Mathf.Clamp(camPitch - val.y, -89f, 89f); Quaternion val2 = Quaternion.Euler(camPitch, camYaw, 0f); movement = localPlayerController.playerActions.Movement; Vector2 val3 = ((MovementActions)(ref movement)).Move.ReadValue(); float freeCamSpeed = FreeCamSpeed; movement = localPlayerController.playerActions.Movement; float num = freeCamSpeed * (((MovementActions)(ref movement)).Sprint.IsPressed() ? 3f : 1f) * Time.deltaTime; camPosition += val2 * new Vector3(val3.x, 0f, val3.y) * num; movement = localPlayerController.playerActions.Movement; if (((MovementActions)(ref movement)).Jump.IsPressed()) { camPosition += Vector3.up * num; } movement = localPlayerController.playerActions.Movement; if (((MovementActions)(ref movement)).Crouch.IsPressed()) { camPosition -= Vector3.up * num; } } ((Component)spectateCamera).transform.SetPositionAndRotation(camPosition, Quaternion.Euler(camPitch, camYaw, 0f)); if ((Object)(object)localPlayerController.spectateCameraPivot != (Object)null) { localPlayerController.spectateCameraPivot.position = camPosition; } } internal bool SpectatePlayer(PlayerControllerB target) { if ((Object)(object)target == (Object)null || (Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null) { return false; } PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if ((Object)(object)localPlayerController == (Object)null || (Object)(object)target == (Object)(object)localPlayerController) { return false; } LeaveDrivenModes(); ClearAnchor(); SpectatingEnemies = false; localPlayerController.spectatedPlayerScript = target; StartOfRound.Instance.SetPlayerSafeInShip(); localPlayerController.SetSpectatedPlayerEffects(false); if ((Object)(object)HUDManager.Instance != (Object)null) { ((TMP_Text)HUDManager.Instance.spectatingPlayerText).text = "(Spectating: " + target.playerUsername + ")"; } return true; } internal void ResetState() { GhostBody.Exit(); RenderView.Restore(); Doorways.Forget(); SpectatedEnemyIndex = -1; SpectatingEnemies = false; Mode = SpectateMode.Spectate; ClearAnchor(); Hide(); } private void RebuildSpectatorList() { SpectatorList = (from x in Object.FindObjectsByType((FindObjectsSortMode)0) where (Object)(object)x != (Object)null && (Object)(object)x.enemyInstance != (Object)null && !x.enemyInstance.isEnemyDead select x).ToArray(); } private void GetNextValidSpectatable() { RebuildSpectatorList(); if (SpectatorList.Length == 0) { SpectatingEnemies = false; SpectatedEnemyIndex = -1; Plugin.displaySpectatorTip.Invoke(HUDManager.Instance, new object[1] { "No enemies to spectate" }); return; } int num = SpectatedEnemyIndex + 1; if (num < 0 || num >= SpectatorList.Length) { num = 0; } SpectatedEnemyIndex = num; } public void Toggle() { if (SpectateMenu.Instance != null) { SpectateMenu.Instance.Toggle(); } } public void Hide() { if (SpectateMenu.Instance != null) { SpectateMenu.Instance.Hide(); } } public bool IsMenuOpen() { return SpectateMenu.Instance != null && SpectateMenu.Instance.IsOpen; } private void OnGUI() { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) if (HideControls == null || !CanControlCamera() || IsMenuOpen()) { return; } OverlayStyles.EnsureBuilt(); Doorways.DrawMarkers(); DrawDoorPrompt(); if (!HideControls.Value) { string text = Hint(); if (text.Length != 0) { GUIContent val = new GUIContent(text); Vector2 val2 = OverlayStyles.Label.CalcSize(val); float num = Mathf.Max(val2.x, 150f) + 20f; float num2 = OverlayStyles.Label.CalcHeight(val, num - 20f) + 16f; Rect val3 = default(Rect); ((Rect)(ref val3))..ctor((float)Screen.width - num - 24f, ((float)Screen.height - num2) / 2f, num, num2); OverlayStyles.DrawBox(val3, OverlayStyles.Background, OverlayStyles.Border); OverlayStyles.Fill(new Rect(((Rect)(ref val3)).x, ((Rect)(ref val3)).y, 2f, ((Rect)(ref val3)).height), OverlayStyles.Primary); GUI.Label(new Rect(((Rect)(ref val3)).x + 12f, ((Rect)(ref val3)).y + 8f, ((Rect)(ref val3)).width - 20f, ((Rect)(ref val3)).height - 16f), val, OverlayStyles.Label); } } } private void DrawDoorPrompt() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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_00d8: Unknown result type (might be due to invalid IL or missing references) EntranceTeleport aimed = Doorways.Aimed; if (!((Object)(object)aimed == (Object)null)) { string text = "Press [" + InteractKeyName() + "] to " + (aimed.isEntranceToBuilding ? "enter" : "leave"); GUIContent val = new GUIContent(text); Vector2 val2 = OverlayStyles.Label.CalcSize(val); Rect val3 = default(Rect); ((Rect)(ref val3))..ctor(((float)Screen.width - val2.x - 24f) / 2f, (float)Screen.height / 2f + 48f, val2.x + 24f, val2.y + 12f); OverlayStyles.DrawBox(val3, OverlayStyles.Background, OverlayStyles.Border); GUI.Label(new Rect(((Rect)(ref val3)).x + 12f, ((Rect)(ref val3)).y + 6f, val2.x, val2.y), val, OverlayStyles.Label); } } private static string InteractKeyName() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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) PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance == (Object)null) ? null : GameNetworkManager.Instance.localPlayerController); if (!((Object)(object)val == (Object)null) && val.playerActions != null) { MovementActions movement = val.playerActions.Movement; if (((MovementActions)(ref movement)).Interact.bindings.Count != 0) { movement = val.playerActions.Movement; InputBinding val2 = ((MovementActions)(ref movement)).Interact.bindings[0]; return InputControlPath.ToHumanReadableString(((InputBinding)(ref val2)).effectivePath, (HumanReadableStringOptions)2, (InputControl)null); } } return "E"; } private string Hint() { string text = Dock.ToggleKeyName(); return Mode switch { SpectateMode.FreeCam => "FREE CAM\n\nMenu : [" + text + "]\nFly : [Move keys]\nUp / Down : [Jump / Crouch]\nFaster : [Sprint]\nSpeed : [Scroll]\nFlashlight : [F]\nDoorways : [" + InteractKeyName() + "] at one", SpectateMode.Ghost => "GHOST\n\nMenu : [" + text + "]\nFly / Land : [Double jump]\nUp / Down : [Jump / Crouch]\nFaster : [Sprint]\nSpeed : [Scroll]\nFlashlight : [F]\nNo clip : [N] (" + (GhostBody.NoClip ? "on" : "off") + ")\nDoorways : [" + InteractKeyName() + "] at one", _ => SpectatingEnemies ? ("SPECTATE\n\nMenu : [" + text + "]\nZoom : [Scroll]") : ("SPECTATE\n\nMenu : [" + text + "]"), }; } } public class SpectateEnemiesAPI { public static bool IsLoaded => (Object)(object)SpectateEnemies.Instance != (Object)null; public static bool IsSpectatingEnemies => SpectateEnemies.Instance.SpectatingEnemies; public static GameObject CurrentEnemySpectating() { if (IsSpectatingEnemies && SpectateEnemies.Instance.SpectatedEnemyIndex > -1) { return ((Component)SpectateEnemies.Instance.SpectatorList[SpectateEnemies.Instance.SpectatedEnemyIndex]).gameObject; } return null; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "SpectateEnemy"; public const string PLUGIN_NAME = "SpectateEnemy"; public const string PLUGIN_VERSION = "2.8.0"; } } namespace SpectateEnemy.UI { internal sealed class SpectateMenu { private struct TargetRow { public string Name; public string Kind; public string Detail; public string Where; public float Distance; public bool Dead; public PlayerControllerB Player; public Spectatable Target; public Transform Body; public Vector3 Point; } private OverlayPanel _panel; private OverlayWindow _mode; private OverlayWindow _render; private OverlayWindow _players; private OverlayWindow _enemies; private bool _savePending; private readonly List _rows = new List(); private readonly OverlayColumns _playerColumns = new OverlayColumns(new string[4] { "PLAYER", "HEALTH", "WHERE", "DIST" }); private readonly OverlayColumns _enemyColumns = new OverlayColumns(new string[4] { "ENEMY", "TYPE", "WHERE", "DIST" }); private float _nextRefresh; private string _playerSearch = string.Empty; private string _enemySearch = string.Empty; private TargetRow _picked; private bool _hasPick; private static float RowHeight => OverlayStyles.RowHeight; private static float ModeRowHeight => OverlayStyles.RowHeight + 8f; internal static SpectateMenu Instance { get; private set; } internal bool IsOpen => Dock.IsOpen; private bool IsFronted => Dock.IsOpen && Dock.ActivePanel == _panel; private static float ToggleWidth(string on, string off) { return Mathf.Max(62f, Mathf.Max(OverlayStyles.ButtonWidth(on, (GUIStyle)null), OverlayStyles.ButtonWidth(off, (GUIStyle)null))); } internal static void Register() { if (Instance == null) { Instance = new SpectateMenu(); Instance.Build(); } } private void Build() { //IL_007b: 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_015a: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) _panel = Dock.Register("SPECTATE"); _panel.Order = 20; _panel.Unavailable = () => CanSpectate() ? null : "Only available once dead"; _mode = _panel.AddWindow("MODE", (Action)DrawModeWindow, "mode", new Rect(60f, 90f, 540f, 250f)); _mode.Open = true; _mode.Subtitle = () => ModeName(SpectateEnemies.Instance.Mode).ToLowerInvariant(); _render = _panel.AddWindow("RENDER", (Action)DrawRenderWindow, "eye", new Rect(620f, 450f, 460f, 200f)); _render.Subtitle = RenderView.Summary; _players = _panel.AddWindow("PLAYERS", (Action)DrawPlayersWindow, "players", new Rect(60f, 296f, 540f, 300f)); _players.Open = true; _players.Subtitle = () => $"{Count(players: true)} on the crew"; _enemies = _panel.AddWindow("ENEMIES", (Action)DrawEnemiesWindow, "enemies", new Rect(620f, 90f, 540f, 340f)); _enemies.Subtitle = () => $"{Count(players: false)} out there"; Debug.Log((object)("[SpectateEnemies]: Registered the spectate panel with Overlay (open it with " + Dock.ToggleKeyName() + ").")); } private static string ModeName(SpectateMode mode) { return mode switch { SpectateMode.FreeCam => "FREE CAM", SpectateMode.Ghost => "GHOST", _ => "SPECTATE", }; } internal void Show() { if (Dock.Show(_panel)) { _nextRefresh = 0f; } } internal void Hide() { Dock.Close(); } internal void Toggle() { if (IsFronted) { Hide(); } else { Show(); } } private static bool CanSpectate() { if ((Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null) { return false; } PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; return (Object)(object)localPlayerController != (Object)null && ((NetworkBehaviour)localPlayerController).IsOwner && localPlayerController.isPlayerDead && !StartOfRound.Instance.shipIsLeaving && (!((NetworkBehaviour)localPlayerController).IsServer || localPlayerController.isHostPlayerObject); } private static void Toast(string message) { Dock.Toast(message); } private void RefreshIfDue() { if (!(Time.unscaledTime < _nextRefresh)) { _nextRefresh = Time.unscaledTime + 0.5f; RefreshTargets(); } } private void RefreshTargets() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0146: 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_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_033a: Unknown result type (might be due to invalid IL or missing references) //IL_036f: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) _rows.Clear(); _playerColumns.Reset(); _enemyColumns.Reset(); StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return; } PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance == (Object)null) ? null : GameNetworkManager.Instance.localPlayerController); Vector3 val2 = From(val); if (instance.allPlayerScripts != null) { PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts; foreach (PlayerControllerB val3 in allPlayerScripts) { if (!((Object)(object)val3 == (Object)null) && (val3.isPlayerControlled || val3.isPlayerDead)) { bool isPlayerDead = val3.isPlayerDead; Transform val4 = BodyOf(val3); string name = (((Object)(object)val3 == (Object)(object)val) ? (val3.playerUsername + " (you)") : val3.playerUsername); Vector3 val5 = ((isPlayerDead && (Object)(object)val4 != (Object)null) ? val4.position : (((Object)(object)val3.lowerSpine != (Object)null) ? (val3.lowerSpine.position + Vector3.up * 0.7f) : (((Component)val3).transform.position + Vector3.up * 1.5f))); _rows.Add(new TargetRow { Name = name, Kind = (isPlayerDead ? "BODY" : "PLAYER"), Detail = ((!isPlayerDead) ? $"{Mathf.Max(0, val3.health)} HP" : (((Object)(object)val4 == (Object)null) ? "NO BODY" : "DEAD")), Where = (val3.isInsideFactory ? "INSIDE" : "OUTSIDE"), Distance = Vector3.Distance(val2, val5), Dead = isPlayerDead, Player = val3, Body = val4, Point = val5 }); } } } Spectatable[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (Spectatable spectatable in array) { if (!((Object)(object)spectatable == (Object)null) && !((Object)(object)spectatable.enemyInstance == (Object)null)) { EnemyAI enemyInstance = spectatable.enemyInstance; bool isEnemyDead = enemyInstance.isEnemyDead; Vector3 val6 = (Vector3)(isEnemyDead ? ((Component)enemyInstance).transform.position : (((??)SpectateEnemies.Instance.PositionOf(spectatable)) ?? ((Component)enemyInstance).transform.position)); _rows.Add(new TargetRow { Name = DisplayName(spectatable), Kind = (isEnemyDead ? "CORPSE" : KindOf(spectatable.type)), Detail = (isEnemyDead ? "DEAD" : KindOf(spectatable.type)), Where = (enemyInstance.isOutside ? "OUTSIDE" : "INSIDE"), Distance = Vector3.Distance(val2, val6), Dead = isEnemyDead, Target = spectatable, Body = (isEnemyDead ? ((Component)enemyInstance).transform : null), Point = val6 }); } } _rows.Sort((TargetRow a, TargetRow b) => (a.Dead != b.Dead) ? (a.Dead ? 1 : (-1)) : a.Distance.CompareTo(b.Distance)); } private static Vector3 From(PlayerControllerB local) { //IL_000d: 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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)local == (Object)null) { return Vector3.zero; } if (GhostBody.Active) { return ((Component)local).transform.position; } return ((Object)(object)local.spectateCameraPivot != (Object)null) ? local.spectateCameraPivot.position : ((Component)local).transform.position; } private static Transform BodyOf(PlayerControllerB player) { if (!player.isPlayerDead || (Object)(object)player.deadBody == (Object)null || !((Component)player.deadBody).gameObject.activeSelf) { return null; } return (player.deadBody.bodyParts != null && player.deadBody.bodyParts.Length != 0 && (Object)(object)player.deadBody.bodyParts[0] != (Object)null) ? ((Component)player.deadBody.bodyParts[0]).transform : ((Component)player.deadBody).transform; } private static string KindOf(SpectatableType type) { return type switch { SpectatableType.Masked => "MASKED", SpectatableType.GhostGirl => "GHOST", _ => "ENEMY", }; } private static string DisplayName(Spectatable target) { if (target.type == SpectatableType.Masked && !string.IsNullOrEmpty(target.maskedName)) { return target.maskedName; } if (!string.IsNullOrEmpty(target.enemyName) && target.enemyName != "Enemy") { return target.enemyName; } return ((Object)(object)target.enemyInstance != (Object)null && (Object)(object)target.enemyInstance.enemyType != (Object)null) ? target.enemyInstance.enemyType.enemyName : "Enemy"; } private void Select(TargetRow row) { //IL_009a: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) SpectateEnemies instance = SpectateEnemies.Instance; if ((Object)(object)row.Player == (Object)null && (Object)(object)row.Target == (Object)null) { Toast("That target is gone"); RefreshTargets(); return; } if (row.Dead && (Object)(object)row.Body == (Object)null) { Toast("There is no body left of " + row.Name); RefreshTargets(); return; } Vector3 point = (((Object)(object)row.Body != (Object)null) ? row.Body.position : row.Point); if (instance.Mode != SpectateMode.Spectate) { if (instance.WarpCamera(point)) { Toast(((instance.Mode == SpectateMode.Ghost) ? "Walked to " : "Flew to ") + row.Name); Hide(); } else { Toast("Could not move to " + row.Name); RefreshTargets(); } return; } if (row.Dead) { if (instance.AnchorOn(row.Body, row.Name)) { Toast("Watching the body of " + row.Name); Hide(); return; } } else if ((Object)(object)row.Player != (Object)null) { if (instance.SpectatePlayer(row.Player)) { Toast("Spectating " + row.Name); Hide(); return; } } else if (instance.SpectateTarget(row.Target)) { Toast("Spectating " + row.Name); Hide(); return; } Toast("Could not spectate " + row.Name); RefreshTargets(); } private void DrawModeWindow(Rect content) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_03c4: Unknown result type (might be due to invalid IL or missing references) SpectateEnemies instance = SpectateEnemies.Instance; float y = ((Rect)(ref content)).y; y = DrawModeRow(content, y, SpectateMode.Spectate, "Watch a player, an enemy or a body. Picking a live target locks onto it."); y = DrawModeRow(content, y, SpectateMode.FreeCam, $"Fly through everything, {instance.FreeCamSpeed:F0} m/s. Picking a target flies you to it."); y = DrawModeRow(content, y, SpectateMode.Ghost, GhostBody.Flying ? "Flying. Jump and crouch for up and down, double jump to land." : "Walk about as if alive: your body, scan, no stamina. Double jump to fly."); y += 6f; OverlayStyles.Fill(new Rect(((Rect)(ref content)).x, y, ((Rect)(ref content)).width, 1f), new Color(1f, 1f, 1f, 0.12f)); y += 7f; float num = ToggleWidth("ON", "OFF"); Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref content)).x, y, ((Rect)(ref content)).width, RowHeight); GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y, Mathf.Max(0f, ((Rect)(ref val)).width - num - 8f), ((Rect)(ref val)).height), (instance.Mode == SpectateMode.Ghost) ? "Helmet light" : "Spectator flashlight", OverlayStyles.Label); bool lightOn = instance.LightOn; if (OverlayStyles.Press(new Rect(((Rect)(ref val)).xMax - num, ((Rect)(ref val)).y, num, RowHeight), lightOn ? "ON" : "OFF", lightOn ? OverlayStyles.ButtonActive : OverlayStyles.Button)) { instance.ToggleLight(); } y += RowHeight + 2f; if (instance.Mode == SpectateMode.Ghost) { float num2 = ToggleWidth("ON", "OFF"); Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(((Rect)(ref content)).x, y, ((Rect)(ref content)).width, RowHeight); GUI.Label(new Rect(((Rect)(ref val2)).x, ((Rect)(ref val2)).y, Mathf.Max(0f, ((Rect)(ref val2)).width - num2 - 8f), ((Rect)(ref val2)).height), "Walk through walls [N]", OverlayStyles.Label); bool noClip = GhostBody.NoClip; if (OverlayStyles.Press(new Rect(((Rect)(ref val2)).xMax - num2, ((Rect)(ref val2)).y, num2, RowHeight), noClip ? "ON" : "OFF", noClip ? OverlayStyles.ButtonActive : OverlayStyles.Button)) { GhostBody.SetNoClip(!noClip); } y += RowHeight + 2f; } y = DrawVoteRow(content, y); float num3 = ToggleWidth("HIDDEN", "SHOWN"); Rect val3 = default(Rect); ((Rect)(ref val3))..ctor(((Rect)(ref content)).x, y, ((Rect)(ref content)).width, RowHeight); GUI.Label(new Rect(((Rect)(ref val3)).x, ((Rect)(ref val3)).y, Mathf.Max(0f, ((Rect)(ref val3)).width - num3 - 8f), ((Rect)(ref val3)).height), "Controls hint on the HUD", OverlayStyles.Label); bool value = instance.HideControls.Value; if (OverlayStyles.Press(new Rect(((Rect)(ref val3)).xMax - num3, ((Rect)(ref val3)).y, num3, RowHeight), value ? "HIDDEN" : "SHOWN", value ? OverlayStyles.ButtonActive : OverlayStyles.Button)) { instance.HideControls.Value = !value; _savePending = true; } y += RowHeight + 4f; float num4 = OverlayStyles.TextHeight("Overlay's key is the only one that opens this. While dead: [F] for the light, [N] for no clip in ghost mode, and your interact key at a highlighted doorway.", ((Rect)(ref content)).width - 20f, OverlayStyles.LabelMuted); _mode.FitContentHeight(y - ((Rect)(ref content)).y + num4); OverlayStyles.Paragraph(new Rect(((Rect)(ref content)).x, Mathf.Max(y, ((Rect)(ref content)).yMax - num4), ((Rect)(ref content)).width - 20f, num4), "Overlay's key is the only one that opens this. While dead: [F] for the light, [N] for no clip in ghost mode, and your interact key at a highlighted doorway.", OverlayStyles.LabelMuted); SaveWhenSettled(); } private static float DrawVoteRow(Rect content, float y) { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref content)).x, y, ((Rect)(ref content)).width, RowHeight); TimeOfDay instance = TimeOfDay.Instance; StartOfRound instance2 = StartOfRound.Instance; if (!((Object)(object)instance != (Object)null) || !((Object)(object)instance2 != (Object)null) || instance2.shipIsLeaving || !((Object)(object)instance2.currentLevel != (Object)null) || !instance2.currentLevel.planetHasTime || instance.shipLeavingAlertCalled) { GUI.Label(val, "Ship cannot be voted off this planet", OverlayStyles.LabelMuted); return y + RowHeight + 2f; } bool votedShipToLeaveEarlyThisRound = instance.votedShipToLeaveEarlyThisRound; float num = ToggleWidth("VOTED", "VOTE"); GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y, Mathf.Max(0f, ((Rect)(ref val)).width - num - 8f), ((Rect)(ref val)).height), $"Tell the autopilot to leave early ({instance.votesForShipToLeaveEarly} voted)", votedShipToLeaveEarlyThisRound ? OverlayStyles.LabelMuted : OverlayStyles.Label); if (OverlayStyles.Press(new Rect(((Rect)(ref val)).xMax - num, ((Rect)(ref val)).y, num, RowHeight), votedShipToLeaveEarlyThisRound ? "VOTED" : "VOTE", votedShipToLeaveEarlyThisRound ? OverlayStyles.ButtonActive : OverlayStyles.Button) && !votedShipToLeaveEarlyThisRound) { instance.VoteShipToLeaveEarly(); Toast("Voted for the ship to leave early"); } return y + RowHeight + 2f; } private float DrawModeRow(Rect content, float y, SpectateMode mode, string description) { //IL_0075: 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_0161: Unknown result type (might be due to invalid IL or missing references) SpectateEnemies instance = SpectateEnemies.Instance; bool flag = instance.Mode == mode; float num = Mathf.Max(96f, OverlayStyles.ButtonWidth(ModeName(mode), (GUIStyle)null)); float num2 = Mathf.Max(ModeRowHeight, OverlayStyles.TextHeight(description, Mathf.Max(40f, ((Rect)(ref content)).width - num - 13f), OverlayStyles.Label) + 6f); Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref content)).x, y, ((Rect)(ref content)).width, num2); GUI.Label(val, GUIContent.none, flag ? OverlayStyles.RowHover : OverlayStyles.Row); if (OverlayStyles.Press(new Rect(((Rect)(ref val)).x + 3f, ((Rect)(ref val)).y + 3f, num, ModeRowHeight - 6f), ModeName(mode), flag ? OverlayStyles.ButtonActive : OverlayStyles.Button)) { if (instance.SetMode(mode)) { Toast(ModeName(mode) + " mode"); } else if (!flag) { Toast("Could not switch to " + ModeName(mode)); } } OverlayStyles.Paragraph(new Rect(((Rect)(ref val)).x + num + 9f, ((Rect)(ref val)).y + 3f, Mathf.Max(40f, ((Rect)(ref val)).width - num - 13f), 0f), description, flag ? OverlayStyles.Label : OverlayStyles.LabelMuted); return y + ((Rect)(ref val)).height + 2f; } private void DrawRenderWindow(Rect content) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) OverlayLayout val = _render.Begin(content); ((OverlayNode)val).Paragraph("What you see while you are dead. Kept between deaths.", OverlayStyles.LabelMuted); ((OverlayNode)val).Rule(); bool flag = RenderView.Brightness.Value > 0.01f; float num = ((OverlayBox)val).Slider("Brightness", "spectate.brightness", RenderView.Brightness.Value, 0f, 5f, "0.##", flag ? OverlayStyles.LabelStrong : OverlayStyles.Label); if (!Mathf.Approximately(num, RenderView.Brightness.Value)) { RenderView.Brightness.Value = num; _savePending = true; } bool flag2 = !RenderView.FogOff.Value; if (((OverlayBox)val).Toggle("Volumetric fog", flag2, "SHOWN", "HIDDEN", flag2 ? OverlayStyles.Label : OverlayStyles.LabelStrong)) { RenderView.FogOff.Value = flag2; _savePending = true; } ((OverlayNode)val).Rule(); ((OverlayNode)val).Paragraph("0 brightness is the game's own lighting; 1 is about what the night vision gives you inside. The light follows whatever you are looking out of, so it works outside as well.", OverlayStyles.LabelMuted); SaveWhenSettled(); } private void SaveWhenSettled() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 if (_savePending && (int)Event.current.type == 7) { Mouse current = Mouse.current; if (current == null || !current.leftButton.isPressed) { _savePending = false; SpectateEnemies.SaveConfig(); } } } private void DrawPlayersWindow(Rect content) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) DrawList(content, _players, players: true, ref _playerSearch); } private void DrawEnemiesWindow(Rect content) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) DrawList(content, _enemies, players: false, ref _enemySearch); } private void DrawList(Rect content, OverlayWindow window, bool players, ref string search) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0531: Unknown result type (might be due to invalid IL or missing references) //IL_04f4: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_0450: Unknown result type (might be due to invalid IL or missing references) //IL_0466: Unknown result type (might be due to invalid IL or missing references) //IL_047c: Unknown result type (might be due to invalid IL or missing references) RefreshIfDue(); float num = OverlayStyles.ButtonWidth("CLEAR", (GUIStyle)null); float num2 = OverlayStyles.ButtonWidth("REFRESH", (GUIStyle)null); window.FitContentWidth(120f + num + num2 + 12f); Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref content)).x, ((Rect)(ref content)).y, ((Rect)(ref content)).width, RowHeight); search = GUI.TextField(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y, Mathf.Max(40f, ((Rect)(ref val)).width - num - num2 - 12f), RowHeight), search ?? string.Empty, OverlayStyles.Field); if (OverlayStyles.Press(new Rect(((Rect)(ref val)).xMax - num - num2 - 6f, ((Rect)(ref val)).y, num, RowHeight), "CLEAR", OverlayStyles.Button)) { search = string.Empty; GUIUtility.keyboardControl = 0; } if (OverlayStyles.Press(new Rect(((Rect)(ref val)).xMax - num2, ((Rect)(ref val)).y, num2, RowHeight), "REFRESH", OverlayStyles.Button)) { RefreshTargets(); } OverlayColumns val2 = (players ? _playerColumns : _enemyColumns); val2.Fit(window, 14f); float num3 = RowHeight + 6f; Rect val3 = default(Rect); ((Rect)(ref val3))..ctor(((Rect)(ref content)).x, ((Rect)(ref content)).y + num3, ((Rect)(ref content)).width, RowHeight); val2.DrawHeaders(val3); OverlayStyles.Fill(new Rect(((Rect)(ref content)).x, ((Rect)(ref content)).y + num3 + RowHeight, ((Rect)(ref content)).width, 1f), new Color(1f, 1f, 1f, 0.12f)); List list = Filtered(players, search); string text = Footer(players); float num4 = OverlayStyles.TextHeight(text, ((Rect)(ref content)).width - 20f, OverlayStyles.LabelMuted); Rect val4 = default(Rect); ((Rect)(ref val4))..ctor(((Rect)(ref content)).x, ((Rect)(ref content)).y + num3 + RowHeight + 5f, ((Rect)(ref content)).width, Mathf.Max(RowHeight, ((Rect)(ref content)).height - num3 - RowHeight - 5f - num4)); Rect val5 = default(Rect); ((Rect)(ref val5))..ctor(0f, 0f, ((Rect)(ref val4)).width - 14f, (float)list.Count * RowHeight); window.Scroll = GUI.BeginScrollView(val4, window.Scroll, val5); Spectatable currentTarget = SpectateEnemies.Instance.CurrentTarget; Transform currentAnchor = SpectateEnemies.Instance.CurrentAnchor; PlayerControllerB val6 = WatchedPlayer(); Rect val7 = default(Rect); for (int i = 0; i < list.Count; i++) { TargetRow picked = list[i]; ((Rect)(ref val7))..ctor(0f, (float)i * RowHeight, ((Rect)(ref val5)).width, RowHeight); if (!(((Rect)(ref val7)).yMax < window.Scroll.y) && !(((Rect)(ref val7)).y > window.Scroll.y + ((Rect)(ref val4)).height)) { bool flag = ((!picked.Dead) ? (((Object)(object)picked.Player != (Object)null) ? ((Object)(object)picked.Player == (Object)(object)val6) : ((Object)(object)picked.Target != (Object)null && (Object)(object)picked.Target == (Object)(object)currentTarget)) : ((Object)(object)currentAnchor != (Object)null && (Object)(object)picked.Body == (Object)(object)currentAnchor)); bool flag2 = ((Rect)(ref val7)).Contains(Event.current.mousePosition); GUIStyle val8 = ((flag2 || flag) ? OverlayStyles.RowHover : ((i % 2 == 0) ? OverlayStyles.Row : OverlayStyles.RowAlt)); GUI.Label(val7, GUIContent.none, val8); if (flag2 && (int)Event.current.type == 0 && Event.current.button == 0) { _picked = picked; _hasPick = true; Event.current.Use(); } GUIStyle val9 = (flag ? OverlayStyles.LabelAlert : (picked.Dead ? OverlayStyles.LabelMuted : OverlayStyles.Label)); val2.DrawCell(val7, 0, flag ? (picked.Name + " <") : picked.Name, val9); val2.DrawCell(val7, 1, picked.Detail, OverlayStyles.LabelMuted); val2.DrawCell(val7, 2, picked.Where, OverlayStyles.LabelMuted); val2.DrawCell(val7, 3, $"{picked.Distance:F0}m", OverlayStyles.LabelMuted); } } GUI.EndScrollView(); if (_hasPick) { _hasPick = false; Select(_picked); } if (list.Count == 0) { GUI.Label(val4, players ? " Nobody on the crew to show." : " Nothing out there right now.", OverlayStyles.LabelMuted); } OverlayStyles.Paragraph(new Rect(((Rect)(ref content)).x, ((Rect)(ref content)).yMax - num4, ((Rect)(ref content)).width - 20f, num4), text, OverlayStyles.LabelMuted); } private static string Footer(bool players) { return SpectateEnemies.Instance.Mode switch { SpectateMode.FreeCam => "Free cam: clicking a row flies you to it. Change that on the MODE window.", SpectateMode.Ghost => "Ghost: clicking a row walks you to it. Change that on the MODE window.", _ => players ? "Click somebody to watch them. Click a body to go and look at it." : "Click an enemy to watch it. Click a corpse to go and look at it.", }; } private int Count(bool players) { int num = 0; foreach (TargetRow row in _rows) { if ((Object)(object)row.Player != (Object)null == players) { num++; } } return num; } private List Filtered(bool players, string search) { string text = (string.IsNullOrEmpty(search) ? null : search.Trim()); List list = new List(); foreach (TargetRow row in _rows) { if ((Object)(object)row.Player != (Object)null == players && (text == null || row.Name.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0 || row.Kind.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0)) { list.Add(row); } } return list; } private static PlayerControllerB WatchedPlayer() { if (SpectateEnemies.Instance.SpectatingEnemies || SpectateEnemies.Instance.Mode != SpectateMode.Spectate) { return null; } PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance == (Object)null) ? null : GameNetworkManager.Instance.localPlayerController); return ((Object)(object)val == (Object)null) ? null : val.spectatedPlayerScript; } } } namespace SpectateEnemy.Patches { [HarmonyPatch(typeof(DressGirlAI), "Start")] internal class DressGirlAI_Patches { private static void Postfix(DressGirlAI __instance) { Spectatable spectatable = ((Component)__instance).gameObject.GetComponent(); if ((Object)(object)spectatable == (Object)null) { spectatable = ((Component)__instance).gameObject.AddComponent(); spectatable.enemyName = ((EnemyAI)__instance).enemyType.enemyName; spectatable.enemyInstance = (EnemyAI)(object)__instance; } spectatable.type = SpectatableType.GhostGirl; } } [HarmonyPatch(typeof(EnemyAI), "Start")] internal class EnemyAI_Patches { private static void Postfix(EnemyAI __instance) { Spectatable spectatable = ((Component)__instance).gameObject.AddComponent(); spectatable.enemyName = __instance.enemyType.enemyName; spectatable.enemyInstance = __instance; } } [HarmonyPatch(typeof(GameNetworkManager), "Disconnect")] internal class GameNetworkManager_Disconnect { private static void Postfix() { if ((Object)(object)SpectateEnemies.Instance != (Object)null) { SpectateEnemies.Instance.ResetState(); } } } [HarmonyPatch(typeof(GameNetworkManager), "OnApplicationQuit")] internal class GameNetworkManager_Quit { private static void Prefix() { if ((Object)(object)SpectateEnemies.Instance != (Object)null) { Plugin.Configuration.Save(); Debug.LogWarning((object)"[SpectateEnemies]: Config saved"); } } } [HarmonyPatch(typeof(RoundManager), "PlayAudibleNoise")] internal class RoundManager_GhostNoise { private const float SameSpot = 1.5f; private static bool Prefix(Vector3 noisePosition) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (!GhostBody.Active || (Object)(object)GameNetworkManager.Instance == (Object)null) { return true; } PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; int result; if (!((Object)(object)localPlayerController == (Object)null)) { Vector3 val = noisePosition - ((Component)localPlayerController).transform.position; result = ((((Vector3)(ref val)).sqrMagnitude > 2.25f) ? 1 : 0); } else { result = 1; } return (byte)result != 0; } } [HarmonyPatch(typeof(EnemyAICollisionDetect), "OnTriggerStay")] internal class EnemyAICollisionDetect_GhostPass { private static bool Prefix(Collider other) { if (!GhostBody.Active || (Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)other == (Object)null) { return true; } PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; return (Object)(object)localPlayerController == (Object)null || (Object)(object)((Component)other).gameObject != (Object)(object)((Component)localPlayerController).gameObject; } } [HarmonyPatch(typeof(NutcrackerEnemyAI), "CheckLineOfSightForLocalPlayer")] internal class NutcrackerEnemyAI_GhostSight { private static bool Prefix(ref bool __result) { if (!GhostBody.Active) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(HUDManager), "Update")] internal class HUDManager_Patches { private static readonly FieldRef EndGameHoldTime = AccessTools.FieldRefAccess("holdButtonToEndGameEarlyHoldTime"); private static void Postfix(HUDManager __instance) { if ((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null) { return; } PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if (!localPlayerController.isPlayerDead) { return; } if (StartOfRound.Instance.shipIsLeaving) { SpectateEnemies.Instance.Hide(); Light component = ((Component)__instance.playersManager.spectateCamera).GetComponent(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = false; } return; } SetTopLine(__instance); if (GhostBody.Active) { EndGameHoldTime.Invoke(__instance) = 0f; ((Component)__instance.holdButtonToEndGameEarlyMeter).gameObject.SetActive(false); ((TMP_Text)__instance.holdButtonToEndGameEarlyText).text = ""; } } private static void SetTopLine(HUDManager hud) { SpectateEnemies instance = SpectateEnemies.Instance; string text; if (GhostBody.Active) { text = (GhostBody.Flying ? $"(Ghost Mode - Flying) [{GhostBody.FlySpeed:F0} m/s]" : "(Ghost Mode)"); } else if (instance.Mode == SpectateMode.FreeCam) { text = $"(Free Cam) [{instance.FreeCamSpeed:F0} m/s]"; } else { if (instance.SpectatingEnemies) { return; } PlayerControllerB spectatedPlayerScript = GameNetworkManager.Instance.localPlayerController.spectatedPlayerScript; text = (((Object)(object)spectatedPlayerScript != (Object)null) ? ("(Spectating: " + spectatedPlayerScript.playerUsername + ")") : "(Nothing to watch - pick something in the spectate menu)"); } if (((TMP_Text)hud.spectatingPlayerText).text != text) { ((TMP_Text)hud.spectatingPlayerText).text = text; } } } [HarmonyPatch(typeof(HUDManager), "CanPlayerScan")] internal class HUDManager_CanPlayerScan { private static void Postfix(ref bool __result) { if (GhostBody.Active && !((Object)(object)GameNetworkManager.Instance == (Object)null)) { PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; __result = (Object)(object)localPlayerController != (Object)null && !localPlayerController.inSpecialInteractAnimation; } } } [HarmonyPatch(typeof(MaskedPlayerEnemy), "Start")] internal class MaskedPlayerEnemy_Patches { private static void Postfix(MaskedPlayerEnemy __instance) { Spectatable spectatable = ((Component)__instance).gameObject.AddComponent(); spectatable.type = SpectatableType.Masked; spectatable.enemyName = ((EnemyAI)__instance).enemyType.enemyName; if ((Object)(object)__instance.mimickingPlayer != (Object)null) { spectatable.maskedName = __instance.mimickingPlayer.playerUsername; } spectatable.enemyInstance = (EnemyAI)(object)__instance; } } [HarmonyPatch(typeof(PlayerControllerB), "ActivateItem_performed")] internal class PlayerControllerB_Use { private static bool Prefix(PlayerControllerB __instance) { if ((Object)(object)SpectateEnemies.Instance != (Object)null && SpectateEnemies.Instance.IsMenuOpen()) { return false; } return !((NetworkBehaviour)__instance).IsOwner || !__instance.isPlayerDead || (((NetworkBehaviour)__instance).IsServer && !__instance.isHostPlayerObject); } } [HarmonyPatch(typeof(PlayerControllerB), "SpectateNextPlayer")] internal class PlayerControllerB_SpectateNext { private static bool Prefix(bool getClosest) { if (!getClosest) { return false; } return !SpectateEnemies.Instance.SpectatingEnemies && SpectateEnemies.Instance.Mode == SpectateMode.Spectate; } } [HarmonyPatch(typeof(PlayerControllerB), "SetWhoToSpectate")] internal class PlayerControllerB_SetWhoToSpectate { private static bool Prefix() { return !SpectateEnemies.Instance.SpectatingEnemies && SpectateEnemies.Instance.Mode == SpectateMode.Spectate; } } [HarmonyPatch(typeof(PlayerControllerB), "Jump_performed")] internal class PlayerControllerB_Jump { private static bool Prefix() { return !GhostBody.Flying; } } [HarmonyPatch(typeof(PlayerControllerB), "Crouch_performed")] internal class PlayerControllerB_Crouch { private static bool Prefix() { return !GhostBody.Flying; } } [HarmonyPatch] internal class PlayerControllerB_GhostRpcs { private static IEnumerable TargetMethods() { MethodInfo[] methods = typeof(PlayerControllerB).GetMethods(AccessTools.all); foreach (MethodInfo method in methods) { if (!(method.DeclaringType != typeof(PlayerControllerB)) && !method.IsStatic && !method.IsAbstract && !method.ContainsGenericParameters && (method.Name.EndsWith("ServerRpc") || method.Name == "SyncCrouchingClientRpc")) { yield return method; } } } private static bool Prefix(PlayerControllerB __instance) { return !GhostBody.Active || (Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)__instance != (Object)(object)GameNetworkManager.Instance.localPlayerController; } } [HarmonyPatch(typeof(EntranceTeleport), "TeleportPlayerServerRpc")] internal class EntranceTeleport_GhostDoor { private static bool Prefix(int playerObj) { if ((Object)(object)GameNetworkManager.Instance == (Object)null) { return true; } PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if ((Object)(object)localPlayerController == (Object)null || !localPlayerController.isPlayerDead) { return true; } return playerObj != (int)localPlayerController.playerClientId; } } [HarmonyPatch(typeof(QuickMenuManager), "Start")] internal class QuickMenuManager_Patches { private static void Postfix() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown if ((Object)(object)SpectateEnemies.Instance == (Object)null) { GameObject val = new GameObject("SpectateEnemiesObject"); val.AddComponent(); } } } [HarmonyPatch(typeof(StartOfRound), "ShipLeave")] internal class StartOfRound_Patches { private static void Postfix() { if ((Object)(object)SpectateEnemies.Instance != (Object)null) { SpectateEnemies.Instance.ResetState(); } } } }