Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Spectator plus v2.9.1
SpectateEnemy.dll
Decompiled 5 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using 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<EntranceTeleport>((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<PlayerControllerB, bool> CameraDisabled = AccessTools.FieldRefAccess<PlayerControllerB, bool>("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<BoxCollider>(); 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<float> Brightness; internal static ConfigEntry<bool> FogOff; private static readonly Type FogType = AccessTools.TypeByName("UnityEngine.Rendering.HighDefinition.LocalVolumetricFog"); private static readonly List<Behaviour> silenced = new List<Behaviour>(); 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<float>("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<bool>("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<GameObject>(((Component)val.nightVision).gameObject); ((Object)val2).name = "SpectateEnemiesViewLight"; val2.transform.SetParent((Transform)null, true); Object.DontDestroyOnLoad((Object)(object)val2); light = val2.GetComponent<Light>(); 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<bool> 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<bool>("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<Light>(); } 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<float>(); 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<DressGirlAI>(); ((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<object>()); ((Component)((Component)localPlayerController.spectateCameraPivot).GetComponentInChildren<Camera>()).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<MaskedPlayerEnemy>(ref val)) { obj.enemyName = (((Object)(object)val.mimickingPlayer != (Object)null) ? val.mimickingPlayer.playerUsername : ((EnemyAI)val).enemyType.enemyName); } else if (((Component)obj).gameObject.TryGetComponent<EnemyAI>(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<Vector2>() * 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<Vector2>(); 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<Spectatable>((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<TargetRow> _rows = new List<TargetRow>(); 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<Rect>)DrawModeWindow, "mode", new Rect(60f, 90f, 540f, 250f)); _mode.Open = true; _mode.Subtitle = () => ModeName(SpectateEnemies.Instance.Mode).ToLowerInvariant(); _render = _panel.AddWindow("RENDER", (Action<Rect>)DrawRenderWindow, "eye", new Rect(620f, 450f, 460f, 200f)); _render.Subtitle = RenderView.Summary; _players = _panel.AddWindow("PLAYERS", (Action<Rect>)DrawPlayersWindow, "players", new Rect(60f, 296f, 540f, 300f)); _players.Open = true; _players.Subtitle = () => $"{Count(players: true)} on the crew"; _enemies = _panel.AddWindow("ENEMIES", (Action<Rect>)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<Spectatable>((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<TargetRow> 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<TargetRow> Filtered(bool players, string search) { string text = (string.IsNullOrEmpty(search) ? null : search.Trim()); List<TargetRow> list = new List<TargetRow>(); 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<Spectatable>(); if ((Object)(object)spectatable == (Object)null) { spectatable = ((Component)__instance).gameObject.AddComponent<Spectatable>(); 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>(); 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<HUDManager, float> EndGameHoldTime = AccessTools.FieldRefAccess<HUDManager, float>("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<Light>(); 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>(); 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; } } [