using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FirstPersonDeath.Patches; using GameNetcodeStuff; using HarmonyLib; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("FirstPersonDeath")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("FirstPersonDeath")] [assembly: AssemblyCopyright("Copyright © 2024")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("94edb759-c44e-4b9e-8486-12654b79b044")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace FirstPersonDeath { [BepInPlugin("rogan.FirstPersonDeath", "First Person Death", "1.3.7")] public class FirstPersonDeathBase : BaseUnityPlugin { private const string modGUID = "rogan.FirstPersonDeath"; private const string modName = "First Person Death"; private const string modVersion = "1.3.7"; private readonly Harmony harmony = new Harmony("rogan.FirstPersonDeath"); private static FirstPersonDeathBase Instance; internal static ManualLogSource mls; public static ConfigEntry SwapKey; public static ConfigEntry SwapTime; private void Awake() { if ((Object)(object)Instance == (Object)null) { Instance = this; } LoadConfigs(); mls = Logger.CreateLogSource("rogan.FirstPersonDeath"); mls.LogInfo((object)"FirstPersonDeath Started!"); harmony.PatchAll(typeof(FirstPersonDeathBase)); harmony.PatchAll(typeof(KeyDownPatch)); harmony.PatchAll(typeof(KillPlayerPatch)); harmony.PatchAll(typeof(HudManagerPatch)); harmony.PatchAll(typeof(MaskedPlayerPatch)); harmony.PatchAll(typeof(PlayerControllerPatch)); } private void LoadConfigs() { SwapKey = ((BaseUnityPlugin)this).Config.Bind("FirstPersonDeath", "SwapKey", "E", "Key used to toggle perspectives; Default binding may conflict with other mods"); SwapTime = ((BaseUnityPlugin)this).Config.Bind("FirstPersonDeath", "SwapTime", 4f, "How long to stay in first person; Set this to 0 to disable auto swap to spectate"); } } } namespace FirstPersonDeath.Patches { [HarmonyPatch(typeof(PlayerControllerB))] internal class KeyDownPatch { public static KeyCode SwapKeyCode = (KeyCode)Enum.Parse(typeof(KeyCode), FirstPersonDeathBase.SwapKey.Value); public static KeyboardShortcut SwapKey = new KeyboardShortcut(SwapKeyCode, Array.Empty()); public static bool SwapKeyDown = false; public static bool UsePlayerCamera = false; [HarmonyPatch("Update")] [HarmonyPostfix] private static void SwapPatch() { if (GameNetworkManager.Instance.localPlayerController.isPlayerDead) { if (((KeyboardShortcut)(ref SwapKey)).IsDown()) { if (!SwapKeyDown) { UsePlayerCamera = !UsePlayerCamera; SwapKeyDown = true; FirstPersonDeathBase.mls.LogInfo((object)$"switching to {UsePlayerCamera}"); } } else if (((KeyboardShortcut)(ref SwapKey)).IsUp()) { SwapKeyDown = false; } } else { UsePlayerCamera = true; } } } internal class KillPlayerPatch { [HarmonyPatch(typeof(PlayerControllerB), "KillPlayer")] [HarmonyTranspiler] private static IEnumerable DeathLengthPatch(IEnumerable instructions) { List list = instructions.ToList(); for (int i = 0; i < list.Count - 1; i++) { if (list[i].opcode == OpCodes.Ldc_R4 && list[i].operand.ToString() == "1.5") { list[i].operand = 0f; FirstPersonDeathBase.mls.LogInfo((object)"Patched death camera time!"); } } return list; } } internal class HudManagerPatch { [HarmonyPatch(typeof(HUDManager), "Update")] [HarmonyTranspiler] private static IEnumerable EarlyVotePatch(IEnumerable instructions) { List list = instructions.ToList(); for (int i = 0; i < list.Count - 1; i++) { if (list[i].opcode == OpCodes.Ldstr && list[i].operand.ToString() == "Tell autopilot ship to leave early : [RMB] (Hold)") { CodeInstruction obj = list[i]; CodeInstruction obj2 = list[i]; obj.operand = (obj2.operand = obj2.operand?.ToString() + "\n\n\n\n\nSwitch Camera: [" + FirstPersonDeathBase.SwapKey.Value + "]"); FirstPersonDeathBase.mls.LogInfo((object)"Patched vote leave text!"); } else if (list[i].opcode == OpCodes.Ldstr && (list[i].operand.ToString() == "Voted for ship to leave early" || list[i].operand.ToString() == "Ship leaving in one hour")) { CodeInstruction obj3 = list[i]; CodeInstruction obj4 = list[i]; obj3.operand = (obj4.operand = obj4.operand?.ToString() + "\n\n\n\n\n\nSwitch Camera: [" + FirstPersonDeathBase.SwapKey.Value + "]"); } } return list; } } [HarmonyPatch(typeof(MaskedPlayerEnemy))] internal class MaskedPlayerPatch { public static Transform MaskedTransform; [HarmonyPatch("Update")] [HarmonyPostfix] private static void GetMaskedPatch(ref PlayerControllerB ___mimickingPlayer, Transform ___headTiltTarget) { if (Object.op_Implicit((Object)(object)___mimickingPlayer) && ___mimickingPlayer.playerUsername == PlayerControllerPatch.PlayerUsername) { MaskedTransform = ___headTiltTarget; } } } [HarmonyPatch(typeof(PlayerControllerB))] internal class PlayerControllerPatch { public static PlayerControllerB RoundController; public static PlayerControllerB NetworkController; public static GameObject MeshModel; public static Rigidbody[] BodyParts; public static DeadBodyInfo[] DeadMesh; public static GameObject PivotCamera; public static GameObject CameraHolder; public static GameObject SpectateCamera; public static AudioListener AudioListener; public static int ClientId; public static string PlayerUsername; public static string SpectatedPlayer; public static PlayerControllerB[] AllPlayers; public static bool bPlayerBody = true; public static bool bPlayerUnderwater = false; public static bool bPlayerDecapitated = false; public static bool bAcknowledgedLeaving = false; public static bool bAcknowledgedUnderwater = false; public static bool bSetTimer = true; public static float Timer = 0f; public static float TimerDuration = FirstPersonDeathBase.SwapTime.Value; public static List PlayerNames = new List(); [HarmonyPatch("Update")] [HarmonyPostfix] public static void FirstPersonPatch() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 //IL_0363: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Invalid comparison between Unknown and I4 //IL_07da: Unknown result type (might be due to invalid IL or missing references) //IL_066f: Unknown result type (might be due to invalid IL or missing references) //IL_08b2: Unknown result type (might be due to invalid IL or missing references) //IL_08b8: Invalid comparison between Unknown and I4 //IL_09f2: Unknown result type (might be due to invalid IL or missing references) //IL_0aa4: Unknown result type (might be due to invalid IL or missing references) //IL_0a65: Unknown result type (might be due to invalid IL or missing references) //IL_0aff: Unknown result type (might be due to invalid IL or missing references) //IL_0ad7: Unknown result type (might be due to invalid IL or missing references) if ((!bPlayerBody && (int)NetworkController.causeOfDeath != 4) || !((Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)null) || !((Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)null)) { return; } RoundController = StartOfRound.Instance.localPlayerController; NetworkController = GameNetworkManager.Instance.localPlayerController; PivotCamera = ((Component)RoundController.spectateCameraPivot).gameObject; SpectateCamera = ((Component)StartOfRound.Instance.spectateCamera).gameObject; PlayerUsername = NetworkController.playerUsername; ClientId = (int)NetworkController.playerClientId; MeshModel = ((Component)NetworkController.thisPlayerModel).gameObject; if (!NetworkController.isPlayerDead) { if (bAcknowledgedLeaving || bAcknowledgedUnderwater) { FirstPersonDeathBase.mls.LogInfo((object)("Resetting acknowledgements for " + PlayerUsername + "...")); bAcknowledgedLeaving = false; bAcknowledgedUnderwater = false; } bPlayerUnderwater = NetworkController.isUnderwater; } if (!NetworkController.isPlayerDead) { return; } if (bSetTimer && !StartOfRound.Instance.shipIsLeaving) { Timer += Time.fixedDeltaTime / 7.75f; } if (Timer > TimerDuration && bSetTimer && !StartOfRound.Instance.shipIsLeaving && TimerDuration != 0f) { Timer = 0f; bSetTimer = false; FirstPersonDeathBase.mls.LogInfo((object)("Timer for " + PlayerUsername + " expired...")); KeyDownPatch.UsePlayerCamera = false; } if (Object.op_Implicit((Object)(object)NetworkController.spectatedPlayerScript)) { SpectatedPlayer = NetworkController.spectatedPlayerScript.playerUsername; } AllPlayers = StartOfRound.Instance.allPlayerScripts; if (SpectatedPlayer == PlayerUsername) { for (int i = 0; i < AllPlayers.Length; i++) { if (AllPlayers[i].playerUsername != PlayerUsername && !AllPlayers[i].playerUsername.Contains("Player #")) { NetworkController.spectatedPlayerScript = AllPlayers[i]; string[] array = AllPlayers[i].playerUsername.Split(new char[1] { ' ' }); foreach (string text in array) { FirstPersonDeathBase.mls.LogInfo((object)text); } } } } if (!Object.op_Implicit((Object)(object)AudioListener)) { AudioListener = Object.FindObjectOfType(); } if (!Object.op_Implicit((Object)(object)CameraHolder)) { if (DeadMesh == null) { FirstPersonDeathBase.mls.LogInfo((object)(PlayerUsername + " died!")); } if ((int)NetworkController.causeOfDeath == 4) { if (Object.op_Implicit((Object)(object)MaskedPlayerPatch.MaskedTransform)) { CameraHolder = ((Component)MaskedPlayerPatch.MaskedTransform).gameObject; } else { DeadMesh = Object.FindObjectsOfType(); DeadBodyInfo[] deadMesh = DeadMesh; foreach (DeadBodyInfo val in deadMesh) { if (val.playerObjectId != ClientId) { continue; } BodyParts = val.bodyParts; Rigidbody[] bodyParts = BodyParts; foreach (Rigidbody val2 in bodyParts) { if (((Object)val2).name == "spine.004") { FirstPersonDeathBase.mls.LogInfo((object)("Found head node of " + PlayerUsername + "...")); CameraHolder = ((Component)val2).gameObject; } } } } } else { DeadMesh = Object.FindObjectsOfType(); DeadBodyInfo[] deadMesh2 = DeadMesh; foreach (DeadBodyInfo val3 in deadMesh2) { if (val3.playerObjectId != ClientId) { continue; } BodyParts = val3.bodyParts; Rigidbody[] bodyParts2 = BodyParts; foreach (Rigidbody val4 in bodyParts2) { if (((Object)val4).name == "spine.004") { FirstPersonDeathBase.mls.LogInfo((object)("Found head node of " + PlayerUsername + "...")); CameraHolder = ((Component)val4).gameObject; } } if (!Object.op_Implicit((Object)(object)CameraHolder) && (Object)(object)val3.detachedHeadObject != (Object)null) { bPlayerDecapitated = true; CameraHolder = ((Component)val3.detachedHeadObject).gameObject; FirstPersonDeathBase.mls.LogInfo((object)(PlayerUsername + " was killed by coilhead!")); } } } } if (StartOfRound.Instance.shipIsLeaving) { if (!bAcknowledgedLeaving) { FirstPersonDeathBase.mls.LogInfo((object)"Ship is leaving; reverting to normal spectate..."); bAcknowledgedLeaving = true; } PlayerNames.Clear(); bSetTimer = true; bPlayerDecapitated = false; if (StartOfRound.Instance.allPlayersDead) { NetworkController.spectatedPlayerScript = null; ((TMP_Text)HUDManager.Instance.spectatingPlayerText).text = ""; } else { ((TMP_Text)HUDManager.Instance.spectatingPlayerText).text = "(Spectating: " + SpectatedPlayer + ")"; } HUDManager.Instance.setUnderwaterFilter = false; StartOfRound.Instance.overrideSpectateCamera = false; SpectateCamera.transform.parent = PivotCamera.transform; SpectateCamera.transform.position = PivotCamera.transform.position; return; } if (KeyDownPatch.UsePlayerCamera) { if (Object.op_Implicit((Object)(object)MaskedPlayerPatch.MaskedTransform)) { FirstPersonDeathBase.mls.LogInfo((object)"Spectating masked; disabling renderer..."); MeshRenderer[] componentsInChildren = ((Component)MaskedPlayerPatch.MaskedTransform.root).gameObject.GetComponentsInChildren(); MeshRenderer[] array2 = componentsInChildren; foreach (MeshRenderer val5 in array2) { ((Renderer)val5).enabled = false; } SkinnedMeshRenderer[] componentsInChildren2 = ((Component)MaskedPlayerPatch.MaskedTransform.root).gameObject.GetComponentsInChildren(); SkinnedMeshRenderer[] array3 = componentsInChildren2; foreach (SkinnedMeshRenderer val6 in array3) { ((Renderer)val6).enabled = false; } } if (bPlayerUnderwater) { if (!bAcknowledgedUnderwater) { FirstPersonDeathBase.mls.LogInfo((object)(PlayerUsername + " is underwater!")); bAcknowledgedUnderwater = true; } HUDManager.Instance.setUnderwaterFilter = true; } ((TMP_Text)HUDManager.Instance.spectatingPlayerText).text = ""; StartOfRound.Instance.overrideSpectateCamera = true; ((Component)AudioListener).gameObject.transform.parent = SpectateCamera.transform; ((Component)AudioListener).gameObject.transform.localPosition = new Vector3(0f, 0f, 0f); FirstPersonDeathBase.mls.LogInfo((object)(PlayerUsername + " is switching to first person camera...")); } else { PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val7 in allPlayerScripts) { if (!val7.playerUsername.Contains("Player #") && !PlayerNames.Contains(val7.playerUsername)) { FirstPersonDeathBase.mls.LogInfo((object)("Added " + val7.playerUsername + " to PlayerNames...")); PlayerNames.Add(val7.playerUsername); } } if (PlayerNames.Count == 1) { return; } if ((int)NetworkController.causeOfDeath == 4 && Object.op_Implicit((Object)(object)MaskedPlayerPatch.MaskedTransform)) { MeshRenderer[] componentsInChildren3 = ((Component)MaskedPlayerPatch.MaskedTransform.root).gameObject.GetComponentsInChildren(); MeshRenderer[] array4 = componentsInChildren3; foreach (MeshRenderer val8 in array4) { ((Renderer)val8).enabled = true; } SkinnedMeshRenderer[] componentsInChildren4 = ((Component)MaskedPlayerPatch.MaskedTransform.root).gameObject.GetComponentsInChildren(); SkinnedMeshRenderer[] array5 = componentsInChildren4; foreach (SkinnedMeshRenderer val9 in array5) { ((Renderer)val9).enabled = true; } } if (((TMP_Text)HUDManager.Instance.spectatingPlayerText).text == "") { ((TMP_Text)HUDManager.Instance.spectatingPlayerText).text = "(Spectating: " + SpectatedPlayer + ")"; } HUDManager.Instance.setUnderwaterFilter = false; StartOfRound.Instance.overrideSpectateCamera = false; ((Component)AudioListener).gameObject.transform.parent = PivotCamera.transform; ((Component)AudioListener).gameObject.transform.localPosition = new Vector3(0f, 0f, 0f); FirstPersonDeathBase.mls.LogInfo((object)(PlayerUsername + " is switching to pivot camera...")); } if (Object.op_Implicit((Object)(object)CameraHolder)) { if ((Object)(object)SpectateCamera.transform.parent != (Object)(object)CameraHolder.transform) { SpectateCamera.transform.position = CameraHolder.transform.position; } SpectateCamera.transform.parent = CameraHolder.transform; SpectateCamera.transform.localPosition = new Vector3(0f, 0f, 0.2f); if (!bPlayerDecapitated) { SpectateCamera.transform.localRotation = Quaternion.Euler(0f, 0f, 0f); } else { SpectateCamera.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); } } else { StartOfRound.Instance.overrideSpectateCamera = false; bPlayerBody = false; } } } }