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 DeathSpectator v1.0.0
DeathSpectator.dll
Decompiled 9 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using Unity.Netcode; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.InputSystem.LowLevel; using UnityEngine.Rendering.HighDefinition; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("DeathSpectator")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("DeathSpectator")] [assembly: AssemblyTitle("DeathSpectator")] [assembly: AssemblyVersion("1.0.0.0")] [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 DeathSpectator { internal class AutoTestDriver : MonoBehaviour { private readonly List<string> errors = new List<string>(); private string shotDir; private string logFile; private PlayerControllerB me; private void Log(string s) { Plugin.Log.LogInfo((object)("[AutoTest] " + s)); try { File.AppendAllText(logFile, s + Environment.NewLine); } catch { } } private void OnEnable() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown Application.logMessageReceived += new LogCallback(OnLog); } private void OnDisable() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown Application.logMessageReceived -= new LogCallback(OnLog); } private void OnLog(string message, string stack, LogType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) if (((int)type == 4 || (int)type == 0) && ((stack ?? "").Contains("DeathSpectator") || message.Contains("DeathSpectator"))) { errors.Add(message.Split('\n')[0]); } } private void Check(bool ok, string what) { Log((ok ? "OK : " : "ÉCHEC : ") + what); if (!ok) { errors.Add("check: " + what); } } private IEnumerator Start() { shotDir = Path.Combine(Paths.ConfigPath, "DeathSpectator", "autotest"); Directory.CreateDirectory(shotDir); string[] files = Directory.GetFiles(shotDir); for (int i = 0; i < files.Length; i++) { File.Delete(files[i]); } logFile = Path.Combine(shotDir, "log.txt"); Log("Démarrage du test automatique."); yield return WaitFor(() => (Object)(object)Object.FindObjectOfType<PreInitSceneScript>() != (Object)null || (Object)(object)MainMenu() != (Object)null, 90f); PreInitSceneScript pre = Object.FindObjectOfType<PreInitSceneScript>(); if ((Object)(object)pre != (Object)null) { yield return (object)new WaitForSeconds(2f); pre.ChooseLaunchOption(false); } MenuManager menu = null; yield return WaitFor(() => (Object)(object)(menu = MainMenu()) != (Object)null, 120f); if ((Object)(object)menu == (Object)null) { Finish("menu introuvable"); yield break; } yield return (object)new WaitForSeconds(4f); GameNetworkManager.Instance.currentSaveFileName = "LCDeathSpectatorAutoTest"; menu.ClickHostButton(); yield return (object)new WaitForSeconds(1f); menu.lobbyNameInputField.text = "DeathSpectatorAutoTest"; menu.ConfirmHostButton(); yield return WaitFor(() => (Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)StartOfRound.Instance.localPlayerController != (Object)null && StartOfRound.Instance.inShipPhase && StartOfRound.Instance.fullyLoadedPlayers.Count > 0, 120f); StartOfRound sor = StartOfRound.Instance; if ((Object)(object)sor == (Object)null) { Finish("vaisseau non chargé"); yield break; } yield return (object)new WaitForSeconds(6f); StartMatchLever obj = Object.FindObjectOfType<StartMatchLever>(); obj.singlePlayerEnabled = true; obj.leverHasBeenPulled = true; obj.StartGame(); Log("Levier tiré, lune : " + sor.currentLevel.PlanetName + "."); yield return WaitFor(() => sor.shipHasLanded && RoundManager.Instance.dungeonCompletedGenerating, 240f); if (!sor.shipHasLanded) { Finish("le vaisseau n'a pas atterri"); yield break; } me = sor.localPlayerController; yield return (object)new WaitForSeconds(4f); me.TeleportPlayer(((Component)me).transform.position + ((Component)me).transform.forward * 4f, false, 0f, false, true); yield return (object)new WaitForSeconds(1f); Vector3 eye = ((Component)me.gameplayCamera).transform.position; StartOfRound obj2 = sor; obj2.livingPlayers++; me.KillPlayer(Vector3.zero, true, (CauseOfDeath)0, 0, default(Vector3), false); yield return (object)new WaitForSeconds(0.5f); Check(me.isPlayerDead, "joueur mort"); Check(!sor.allPlayersDead && !sor.overrideSpectateCamera, "partie toujours en cours (vivant fictif)"); Check(SpectatorCam.Active, "vol libre activé automatiquement à la mort"); Transform cam = ((Component)sor.spectateCamera).transform; Check(Vector3.Distance(cam.position, eye) < 0.5f, $"caméra au point de mort ({Vector3.Distance(cam.position, eye):0.00} m des yeux)"); Check((Object)(object)sor.activeCamera == (Object)(object)sor.spectateCamera, "caméra active = caméra spectateur"); Check(((Component)StartOfRound.Instance.audioListener).transform.IsChildOf(cam) || Vector3.Distance(((Component)sor.audioListener).transform.position, cam.position) < 0.1f, "le son suit la caméra"); string text = ((TMP_Text)HUDManager.Instance.spectatingPlayerText).text; Check(text.Contains("Vol libre"), "texte spectateur : " + text.Split('\n')[0]); yield return Capture("01_mort_vol_libre"); Vector3 p0 = cam.position; float speed = SpectatorCam.CurrentSpeed; yield return HoldKey((Key)37, 1f); float num = Vector3.Distance(p0, cam.position); Check(num > speed * 0.6f && num < speed * 1.5f, $"avance de {num:0.0} m en 1 s à {speed} m/s"); p0 = cam.position; yield return HoldKey((Key)1, 1f); Check(cam.position.y - p0.y > speed * 0.6f, $"monte de {cam.position.y - p0.y:0.0} m avec Espace"); p0 = cam.position; yield return HoldKeys((Key[])(object)new Key[2] { (Key)37, (Key)51 }, 0.5f); Check(Vector3.Distance(p0, cam.position) > speed * Settings.SprintMult.Value * 0.3f, $"sprint : {Vector3.Distance(p0, cam.position):0.0} m en 0,5 s"); yield return Capture("02_apres_vol"); yield return Scroll(120f); Check(SpectatorCam.CurrentSpeed > speed, $"molette vers le haut : {speed} → {SpectatorCam.CurrentSpeed:0.0} m/s"); yield return Scroll(-120f); Check(Mathf.Abs(SpectatorCam.CurrentSpeed - speed) < 0.01f, "molette vers le bas : vitesse revenue"); bool l0 = SpectatorCam.LightOn; yield return PressKey(Settings.LightKey.Value); Check(SpectatorCam.LightOn != l0, "touche lumière : bascule"); Transform val = cam.Find("DeathSpectatorLight"); Check((Object)(object)val != (Object)null && ((Behaviour)((Component)val).GetComponent<Light>()).enabled == SpectatorCam.LightOn, "lumière accrochée à la caméra et dans le bon état"); if (!SpectatorCam.LightOn) { yield return PressKey(Settings.LightKey.Value); } EntranceTeleport val2 = ((IEnumerable<EntranceTeleport>)Object.FindObjectsOfType<EntranceTeleport>()).FirstOrDefault((Func<EntranceTeleport, bool>)((EntranceTeleport e) => e.entranceId == 0 && !e.isEntranceToBuilding)); if ((Object)(object)val2 != (Object)null) { SetPose(val2.entrancePoint.position + Vector3.up * 1.5f); yield return (object)new WaitForSeconds(1.5f); LocalVolumetricFog indoorFog = RoundManager.Instance.indoorFog; Check((Object)(object)indoorFog == (Object)null || !((Component)indoorFog).gameObject.activeSelf || ((Behaviour)indoorFog).enabled, "brouillard intérieur activé dans le bâtiment"); Check(!((Behaviour)TimeOfDay.Instance.sunDirect).enabled, "soleil coupé dans le bâtiment"); yield return Capture("03_interieur_lumiere"); yield return PressKey(Settings.LightKey.Value); yield return (object)new WaitForSeconds(0.3f); yield return Capture("04_interieur_sans_lumiere"); yield return PressKey(Settings.LightKey.Value); SetPose(sor.elevatorTransform.position + Vector3.up * 8f); yield return (object)new WaitForSeconds(1.5f); Check(((Behaviour)TimeOfDay.Instance.sunDirect).enabled, "soleil rallumé dehors"); } else { Check(ok: false, "entrée intérieure introuvable"); } yield return PressKey(Settings.ModeKey.Value); Check(SpectatorCam.Active, "touche mode sans joueur vivant : reste en vol libre"); sor.ReviveDeadPlayers(); yield return (object)new WaitForSeconds(1f); Check(!me.isPlayerDead && !SpectatorCam.Active, "réanimé : vol libre terminé"); Check((Object)(object)cam.Find("DeathSpectatorLight") == (Object)null, "lumière supprimée à la réanimation"); Check((Object)(object)sor.activeCamera == (Object)(object)me.gameplayCamera, "caméra du joueur rendue"); yield return Capture("05_reanime"); yield return (object)new WaitForSeconds(1f); me.KillPlayer(Vector3.zero, true, (CauseOfDeath)0, 0, default(Vector3), false); yield return WaitFor(() => sor.overrideSpectateCamera, 5f); yield return (object)new WaitForSeconds(0.5f); Check(sor.allPlayersDead && sor.overrideSpectateCamera, "tous morts : fin de partie du jeu"); Check(!SpectatorCam.Active, "vol libre rendu au jeu pendant la fin de partie"); yield return Capture("06_fin_de_partie"); yield return WaitFor(() => sor.inShipPhase && !me.isPlayerDead, 90f); Check(!me.isPlayerDead && !SpectatorCam.Active, "de retour en orbite, vivant, sans vol libre"); Finish(null); } private static void SetPose(Vector3 p) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) SpectatorCam.SetPositionForTest(p); } private static IEnumerator HoldKey(Key key, float seconds) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected I4, but got Unknown return HoldKeys((Key[])(object)new Key[1] { (Key)(int)key }, seconds); } private static IEnumerator HoldKeys(Key[] keys, float seconds) { Keyboard kb = Keyboard.current; InputSystem.QueueStateEvent<KeyboardState>((InputDevice)(object)kb, new KeyboardState(keys), -1.0); yield return (object)new WaitForSeconds(seconds); InputSystem.QueueStateEvent<KeyboardState>((InputDevice)(object)kb, default(KeyboardState), -1.0); yield return null; yield return null; } private static IEnumerator PressKey(Key key) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) Keyboard kb = Keyboard.current; InputSystem.QueueStateEvent<KeyboardState>((InputDevice)(object)kb, new KeyboardState((Key[])(object)new Key[1] { (Key)(int)key }), -1.0); yield return null; yield return null; InputSystem.QueueStateEvent<KeyboardState>((InputDevice)(object)kb, default(KeyboardState), -1.0); yield return null; } private static IEnumerator Scroll(float y) { InputSystem.QueueStateEvent<MouseState>((InputDevice)(object)Mouse.current, new MouseState { scroll = new Vector2(0f, y) }, -1.0); yield return null; yield return null; InputSystem.QueueStateEvent<MouseState>((InputDevice)(object)Mouse.current, default(MouseState), -1.0); yield return null; } private void Finish(string fail) { if (fail != null) { Log("ÉCHEC : " + fail); } Log("===== RÉSUMÉ ====="); Log((errors.Count == 0 && fail == null) ? "Aucune erreur." : string.Format("{0} erreur(s) : {1}", errors.Count, string.Join(" | ", errors.Distinct().Take(20)))); Application.Quit(); } private IEnumerator Capture(string name) { yield return (object)new WaitForEndOfFrame(); ScreenCapture.CaptureScreenshot(Path.Combine(shotDir, name + ".png")); Log("Capture : " + name); yield return (object)new WaitForSeconds(0.4f); } private static MenuManager MainMenu() { return ((IEnumerable<MenuManager>)Object.FindObjectsOfType<MenuManager>()).FirstOrDefault((Func<MenuManager, bool>)((MenuManager m) => !m.isInitScene && (Object)(object)m.lobbyNameInputField != (Object)null)); } private static IEnumerator WaitFor(Func<bool> cond, float timeout) { float t = 0f; while (t < timeout) { bool flag = false; try { flag = cond(); } catch { } if (flag) { break; } t += 0.25f; yield return (object)new WaitForSeconds(0.25f); } } } [HarmonyPatch] internal static class Patches { [HarmonyPatch(typeof(PlayerControllerB), "KillPlayer")] [HarmonyPrefix] private static void KillPlayerPrefix(PlayerControllerB __instance) { if (((NetworkBehaviour)__instance).IsOwner && !__instance.isPlayerDead && (Object)(object)__instance == (Object)(object)GameNetworkManager.Instance?.localPlayerController) { SpectatorCam.RememberDeathPose(__instance); } } [HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")] [HarmonyPostfix] private static void LateUpdatePostfix(PlayerControllerB __instance) { if (!((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)__instance != (Object)(object)GameNetworkManager.Instance.localPlayerController)) { SpectatorCam.Tick(__instance); } } [HarmonyPatch(typeof(PlayerControllerB), "ActivateItem_performed")] [HarmonyPrefix] private static bool ActivateItemPrefix(PlayerControllerB __instance, CallbackContext context) { if (!SpectatorCam.IsLocalFlying(__instance)) { return true; } if (((CallbackContext)(ref context)).performed) { SpectatorCam.OnActivatePressed(__instance); } return false; } [HarmonyPatch(typeof(PlayerControllerB), "Interact_performed")] [HarmonyPrefix] private static bool InteractPrefix(PlayerControllerB __instance) { return !SpectatorCam.IsLocalFlying(__instance); } [HarmonyPatch(typeof(HUDManager), "SetSpectatingTextToPlayer")] [HarmonyPostfix] private static void SpectatingTextPostfix() { SpectatorCam.AfterSpectatingText(); } [HarmonyPatch(typeof(TimeOfDay), "SetInsideLightingDimness")] [HarmonyPostfix] private static void SunPostfix(TimeOfDay __instance) { SpectatorCam.FixSun(__instance); } [HarmonyPatch(typeof(StartOfRound), "UpdateOcclusionCuller")] [HarmonyPostfix] private static void OcclusionPostfix(StartOfRound __instance) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_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) if (SpectatorCam.Active && !(SpectatorCam.Position.y < -80f)) { ManualCameraRenderer mapScreen = __instance.mapScreen; if (!((Object)(object)mapScreen == (Object)null) && !((Object)(object)mapScreen.mapCamera == (Object)null)) { __instance.SetOcclusionCullerToPosition(((Component)mapScreen.mapCamera).transform.position - new Vector3(0f, 3.636f, 0f)); } } } [HarmonyPatch(typeof(StartOfRound), "OnLocalDisconnect")] [HarmonyPostfix] private static void Disconnect() { SpectatorCam.ResetAll(); } } [BepInPlugin("emeric.deathspectator", "DeathSpectator", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "emeric.deathspectator"; public const string Name = "DeathSpectator"; public const string Version = "1.0.0"; internal static Plugin Instance; internal static ManualLogSource Log; private void Awake() { //IL_0021: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Settings.Init(((BaseUnityPlugin)this).Config); new Harmony("emeric.deathspectator").PatchAll(); if (Settings.AutoTest.Value) { GameObject val = new GameObject("DeathSpectatorAutoTest") { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)val); val.AddComponent<AutoTestDriver>(); } Log.LogInfo((object)"DeathSpectator 1.0.0 chargé."); } } internal static class Settings { public const float MinSpeed = 1f; public const float MaxSpeed = 80f; public static ConfigEntry<bool> FreeOnDeath; public static ConfigEntry<float> Speed; public static ConfigEntry<float> SprintMult; public static ConfigEntry<bool> LightOnStart; public static ConfigEntry<bool> FollowWhenShipLeaves; public static ConfigEntry<bool> ShowHelp; public static ConfigEntry<Key> ModeKey; public static ConfigEntry<Key> LightKey; public static ConfigEntry<bool> AutoTest; public static void Init(ConfigFile cfg) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown FreeOnDeath = cfg.Bind<bool>("Spectateur", "VolLibreALaMort", true, "À ta mort, tu passes directement en vol libre (sinon tu suis un joueur comme dans le jeu de base, et la touche Mode passe en vol libre)."); Speed = cfg.Bind<float>("Spectateur", "Vitesse", 10f, new ConfigDescription("Vitesse de vol de départ (m/s). La molette la change en jeu.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 80f), Array.Empty<object>())); SprintMult = cfg.Bind<float>("Spectateur", "MultiplicateurSprint", 3f, new ConfigDescription("Vitesse multipliée en maintenant la touche de sprint.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>())); LightOnStart = cfg.Bind<bool>("Spectateur", "LumiereAuDepart", true, "La lumière (que toi seul vois) est allumée en passant en vol libre."); FollowWhenShipLeaves = cfg.Bind<bool>("Spectateur", "SuivreAuDecollage", true, "Quand le vaisseau décolle, repasse automatiquement en suivi d'un joueur pour partir avec lui."); ShowHelp = cfg.Bind<bool>("Spectateur", "AfficherAide", true, "Affiche les commandes en bas de l'écran en vol libre."); ModeKey = cfg.Bind<Key>("Touches", "Mode", (Key)36, "Mort : passer du vol libre au suivi d'un joueur, et inversement."); LightKey = cfg.Bind<Key>("Touches", "Lumiere", (Key)26, "Vol libre : allumer / éteindre la lumière (toi seul la vois)."); AutoTest = cfg.Bind<bool>("Test", "AutoTest", false, "Développeur : lance tout seul une partie de test."); } } internal static class SpectatorCam { private const float InsideY = -80f; private const float AimAngle = 20f; private static bool wasDead; private static Vector3 pos; private static float yaw; private static float pitch; private static float speed = 10f; private static bool lightOn; private static Light light; private static bool hasDeathPose; private static Vector3 deathPos; private static Quaternion deathRot; private static string label; private static float labelSpeed = -1f; private static bool labelLight; public static bool Active { get; private set; } public static float CurrentSpeed => speed; public static Vector3 Position => pos; public static bool LightOn => lightOn; private static PlayerControllerB Local { get { if (!((Object)(object)GameNetworkManager.Instance != (Object)null)) { return null; } return GameNetworkManager.Instance.localPlayerController; } } public static void RememberDeathPose(PlayerControllerB me) { //IL_001a: 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_002f: 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) if (!((Object)(object)me.gameplayCamera == (Object)null)) { deathPos = ((Component)me.gameplayCamera).transform.position; deathRot = ((Component)me.gameplayCamera).transform.rotation; hasDeathPose = true; } } public static void Tick(PlayerControllerB me) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) if (!me.isPlayerDead) { if (wasDead) { OnRevived(); } return; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.spectateCamera == (Object)null) { return; } if (!wasDead) { wasDead = true; speed = Mathf.Clamp(Settings.Speed.Value, 1f, 80f); lightOn = Settings.LightOnStart.Value; Plugin.Log.LogInfo((object)"Joueur local mort : mode spectateur."); if (Settings.FreeOnDeath.Value) { if (hasDeathPose) { Enter(me, deathPos, deathRot); } else { Enter(me, ((Component)instance.spectateCamera).transform.position, ((Component)instance.spectateCamera).transform.rotation); } } } if (instance.overrideSpectateCamera) { if (Active) { Exit(me, "séquence de fin de partie"); } return; } bool flag = instance.shipIsLeaving && Settings.FollowWhenShipLeaves.Value; if (Active && flag) { Plugin.Log.LogInfo((object)"Le vaisseau décolle : retour au suivi d'un joueur."); if (!FollowPlayer(me, Target(me, ((Component)instance.spectateCamera).transform))) { Exit(me, "décollage"); } } if (!InputBlocked(me)) { Keyboard current = Keyboard.current; bool flag2 = current != null && (int)Settings.ModeKey.Value != 0 && ((ButtonControl)current[Settings.ModeKey.Value]).wasPressedThisFrame; if (Active) { if (flag2) { FollowPlayer(me, Target(me, ((Component)instance.spectateCamera).transform)); } else if (current != null && (int)Settings.LightKey.Value != 0 && ((ButtonControl)current[Settings.LightKey.Value]).wasPressedThisFrame) { lightOn = !lightOn; } } else if (!flag) { if (!flag2) { MovementActions movement = me.playerActions.Movement; if (!((MovementActions)(ref movement)).Crouch.WasPressedThisFrame()) { goto IL_020b; } } Transform transform = ((Component)instance.spectateCamera).transform; Enter(me, transform.position, transform.rotation); } goto IL_020b; } goto IL_0218; IL_020b: if (Active) { Fly(me); } goto IL_0218; IL_0218: if (Active) { Apply(me, instance); } } public static void OnActivatePressed(PlayerControllerB me) { StartOfRound instance = StartOfRound.Instance; if (Active && !((Object)(object)instance == (Object)null) && !((Object)(object)instance.spectateCamera == (Object)null) && !InputBlocked(me)) { FollowPlayer(me, Target(me, ((Component)instance.spectateCamera).transform)); } } public static void ResetAll() { Active = false; wasDead = false; hasDeathPose = false; label = null; if ((Object)(object)light != (Object)null) { Object.Destroy((Object)(object)((Component)light).gameObject); } light = null; } private static void OnRevived() { Plugin.Log.LogInfo((object)"Joueur local de nouveau en vie : fin du mode spectateur."); ResetAll(); } private static void Enter(PlayerControllerB me, Vector3 position, Quaternion rotation) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) Active = true; pos = position; Vector3 eulerAngles = ((Quaternion)(ref rotation)).eulerAngles; yaw = eulerAngles.y; pitch = Mathf.Clamp(Mathf.DeltaAngle(0f, eulerAngles.x), -89f, 89f); label = null; EnsureLight(me); Plugin.Log.LogInfo((object)$"Vol libre à {pos}."); } private static void Exit(PlayerControllerB me, string why) { Active = false; if ((Object)(object)light != (Object)null) { ((Behaviour)light).enabled = false; } HUDManager instance = HUDManager.Instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.spectatingPlayerText != (Object)null) { ((TMP_Text)instance.spectatingPlayerText).text = (((Object)(object)me.spectatedPlayerScript != (Object)null) ? ("(Spectating: " + me.spectatedPlayerScript.playerUsername + ")") : ""); } Plugin.Log.LogInfo((object)("Fin du vol libre (" + why + ").")); } private static bool FollowPlayer(PlayerControllerB me, PlayerControllerB target) { if ((Object)(object)target == (Object)null) { return false; } me.spectatedPlayerScript = target; StartOfRound.Instance.SetPlayerSafeInShip(); me.SetSpectatedPlayerEffects(false); Exit(me, "suivi de " + target.playerUsername); return true; } private static PlayerControllerB Target(PlayerControllerB me, Transform cam) { //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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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) PlayerControllerB val = null; PlayerControllerB result = null; float num = 20f; float num2 = float.MaxValue; PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val2 in allPlayerScripts) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)me) && !val2.isPlayerDead && val2.isPlayerControlled) { Vector3 val3 = ((Component)val2).transform.position + Vector3.up - cam.position; float num3 = Vector3.Angle(cam.forward, val3); if (num3 < num) { num = num3; val = val2; } if (((Vector3)(ref val3)).sqrMagnitude < num2) { num2 = ((Vector3)(ref val3)).sqrMagnitude; result = val2; } } } if (!((Object)(object)val != (Object)null)) { return result; } return val; } private static bool InputBlocked(PlayerControllerB me) { if (!me.isTypingChat && !me.inTerminalMenu && !me.disableLookInput) { if ((Object)(object)me.quickMenuManager != (Object)null) { return me.quickMenuManager.isMenuOpen; } return false; } return true; } private static void Fly(PlayerControllerB me) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_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_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: 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_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) MovementActions movement = me.playerActions.Movement; Vector2 val = ((MovementActions)(ref movement)).Look.ReadValue<Vector2>() * 0.008f; IngamePlayerSettings instance = IngamePlayerSettings.Instance; if ((Object)(object)instance != (Object)null) { val *= (float)instance.settings.lookSensitivity; if (instance.flipCamera) { val.x = 0f - val.x; } if (instance.settings.invertYAxis) { val.y = 0f - val.y; } } yaw += val.x; pitch = Mathf.Clamp(pitch - val.y, -89f, 89f); Mouse current = Mouse.current; if (current != null) { float y = ((InputControl<Vector2>)(object)current.scroll).ReadValue().y; if (y > 0f) { speed = Mathf.Min(speed * 1.25f, 80f); } else if (y < 0f) { speed = Mathf.Max(speed / 1.25f, 1f); } } Vector2 val2 = ((MovementActions)(ref movement)).Move.ReadValue<Vector2>(); float num = (((MovementActions)(ref movement)).Jump.IsPressed() ? 1f : 0f) - (((MovementActions)(ref movement)).Crouch.IsPressed() ? 1f : 0f); Vector3 val3 = Quaternion.Euler(pitch, yaw, 0f) * new Vector3(val2.x, 0f, val2.y) + Vector3.up * num; if (((Vector3)(ref val3)).sqrMagnitude > 1f) { ((Vector3)(ref val3)).Normalize(); } float num2 = speed * (((MovementActions)(ref movement)).Sprint.IsPressed() ? Settings.SprintMult.Value : 1f); pos += val3 * (num2 * Time.deltaTime); } private static void Apply(PlayerControllerB me, StartOfRound sor) { //IL_000b: 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) ((Component)sor.spectateCamera).transform.SetPositionAndRotation(pos, Quaternion.Euler(pitch, yaw, 0f)); bool enabled = pos.y < -80f; RoundManager instance = RoundManager.Instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.indoorFog != (Object)null && ((Component)instance.indoorFog).gameObject.activeSelf) { ((Behaviour)instance.indoorFog).enabled = enabled; } if ((Object)(object)light == (Object)null) { EnsureLight(me); } if ((Object)(object)light != (Object)null && ((Behaviour)light).enabled != lightOn) { ((Behaviour)light).enabled = lightOn; } UpdateLabel(); } public static void FixSun(TimeOfDay tod) { if (Active && !((Object)(object)tod.sunDirect == (Object)null) && !((Object)(object)tod.sunIndirect == (Object)null) && !((Object)(object)StartOfRound.Instance == (Object)null) && !StartOfRound.Instance.allPlayersDead) { bool enabled = pos.y >= -80f; ((Behaviour)tod.sunDirect).enabled = enabled; ((Behaviour)tod.sunIndirect).enabled = enabled; } } private static void EnsureLight(PlayerControllerB me) { //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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)light != (Object)null) && !((Object)(object)me.nightVision == (Object)null) && !((Object)(object)StartOfRound.Instance == (Object)null) && !((Object)(object)StartOfRound.Instance.spectateCamera == (Object)null)) { Light nightVision = me.nightVision; GameObject val = new GameObject("DeathSpectatorLight"); val.SetActive(false); val.transform.SetParent(((Component)StartOfRound.Instance.spectateCamera).transform, false); light = val.AddComponent<Light>(); light.type = nightVision.type; light.color = nightVision.color; light.intensity = nightVision.intensity; light.range = nightVision.range; light.spotAngle = nightVision.spotAngle; light.cullingMask = nightVision.cullingMask; light.shadows = (LightShadows)0; HDAdditionalLightData val2 = val.AddComponent<HDAdditionalLightData>(); HDAdditionalLightData component = ((Component)nightVision).GetComponent<HDAdditionalLightData>(); if ((Object)(object)component != (Object)null) { component.CopyTo(val2); } val2.affectsVolumetric = false; ((Behaviour)light).enabled = false; val.SetActive(true); Plugin.Log.LogInfo((object)string.Format("Lumière spectateur créée ({0}, portée {1}, intensité {2}, HDRP {3}).", nightVision.type, nightVision.range, nightVision.intensity, ((Object)(object)component != (Object)null) ? "copié" : "par défaut")); } } private static void UpdateLabel() { //IL_0095: 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) HUDManager instance = HUDManager.Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.spectatingPlayerText == (Object)null)) { if (label == null || labelSpeed != speed || labelLight != lightOn) { labelSpeed = speed; labelLight = lightOn; label = (Settings.ShowHelp.Value ? string.Format("(Vol libre · {0:0.#} m/s)\n<size=50%>ZQSD voler · Espace/Ctrl haut/bas · Maj vite · Molette vitesse\nClic suivre · {1} mode · {2} lumière ({3})</size>", speed, Settings.ModeKey.Value, Settings.LightKey.Value, lightOn ? "on" : "off") : $"(Vol libre · {speed:0.#} m/s)"); } if (((TMP_Text)instance.spectatingPlayerText).text != label) { ((TMP_Text)instance.spectatingPlayerText).text = label; } } } public static void AfterSpectatingText() { if (Active) { label = null; UpdateLabel(); } } internal static void SetPositionForTest(Vector3 p) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) pos = p; } public static bool IsLocalFlying(PlayerControllerB p) { if (Active && (Object)(object)p != (Object)null) { return (Object)(object)p == (Object)(object)Local; } return false; } } }