diff --git a/NewHorizons/Handlers/InvulnerabilityHandler.cs b/NewHorizons/Handlers/InvulnerabilityHandler.cs index 9aa0e793..e6f3777a 100644 --- a/NewHorizons/Handlers/InvulnerabilityHandler.cs +++ b/NewHorizons/Handlers/InvulnerabilityHandler.cs @@ -1,36 +1,52 @@ +using HarmonyLib; using NewHorizons.Utility.OWML; using UnityEngine; +using UnityEngine.SceneManagement; namespace NewHorizons.Handlers { + [HarmonyPatch] internal class InvulnerabilityHandler { private static float _defaultImpactDeathSpeed = -1f; + private static bool _invulnerable; public static void MakeInvulnerable(bool invulnerable) { NHLogger.Log($"Toggling immortality: {invulnerable}"); + _invulnerable = invulnerable; var deathManager = GetDeathManager(); var resources = GetPlayerResouces(); if (invulnerable) { - if (_defaultImpactDeathSpeed == -1f) - _defaultImpactDeathSpeed = deathManager._impactDeathSpeed; - - deathManager._impactDeathSpeed = Mathf.Infinity; deathManager._invincible = true; } else { - deathManager._impactDeathSpeed = _defaultImpactDeathSpeed; resources._currentHealth = 100f; deathManager._invincible = false; } } + [HarmonyPrefix] + [HarmonyPatch(typeof(DeathManager), nameof(DeathManager.KillPlayer))] + [HarmonyPatch(typeof(PlayerResources), nameof(PlayerResources.ApplyInstantDamage))] + [HarmonyPatch(typeof(PlayerImpactAudio), nameof(PlayerImpactAudio.OnImpact))] + public static bool DeathManager_KillPlayer_Prefix() + { + // Base game _invincible is still overriden by high speed impacts + // We also are avoiding playing impact related effects by just skipping these methods + return !_invulnerable; + } + private static DeathManager GetDeathManager() => GameObject.FindObjectOfType(); private static PlayerResources GetPlayerResouces() => GameObject.FindObjectOfType(); + + static InvulnerabilityHandler() + { + SceneManager.sceneUnloaded += (_) => _invulnerable = false; + } } } diff --git a/NewHorizons/Handlers/PlayerSpawnHandler.cs b/NewHorizons/Handlers/PlayerSpawnHandler.cs index 352b4eff..24b6d73c 100644 --- a/NewHorizons/Handlers/PlayerSpawnHandler.cs +++ b/NewHorizons/Handlers/PlayerSpawnHandler.cs @@ -70,6 +70,24 @@ namespace NewHorizons.Handlers // Spawn ship Delay.FireInNUpdates(SpawnShip, 30); + + // Have had bug reports (#1034, #975) where sometimes after spawning via vessel warp or ship warp you die from impact velocity after being flung + // Something weird must be happening with velocity. + // Try to correct it here after the ship is done spawning + Delay.FireInNUpdates(() => FixVelocity(shouldWarpInFromVessel, shouldWarpInFromShip), 31); + } + + private static void FixVelocity(bool shouldWarpInFromVessel, bool shouldWarpInFromShip) + { + var spawnOWRigidBody = GetDefaultSpawn().GetAttachedOWRigidbody(); + if (shouldWarpInFromVessel) spawnOWRigidBody = VesselWarpHandler.VesselSpawnPoint.GetAttachedOWRigidbody(); + if (shouldWarpInFromShip) spawnOWRigidBody = Locator.GetShipBody(); + + var spawnVelocity = spawnOWRigidBody.GetVelocity(); + var spawnAngularVelocity = spawnOWRigidBody.GetPointTangentialVelocity(Locator.GetPlayerBody().GetPosition()); + var velocity = spawnVelocity + spawnAngularVelocity; + + Locator.GetPlayerBody().SetVelocity(velocity); } public static void SpawnShip() diff --git a/NewHorizons/Handlers/VesselWarpHandler.cs b/NewHorizons/Handlers/VesselWarpHandler.cs index 5cf611e5..c5e622eb 100644 --- a/NewHorizons/Handlers/VesselWarpHandler.cs +++ b/NewHorizons/Handlers/VesselWarpHandler.cs @@ -6,6 +6,7 @@ using NewHorizons.Utility; using NewHorizons.Utility.OuterWilds; using NewHorizons.Utility.OWML; using UnityEngine; +using System.Collections; using static NewHorizons.Main; using static NewHorizons.Utility.Files.AssetBundleUtilities; @@ -56,7 +57,9 @@ namespace NewHorizons.Handlers } if (IsVesselPresentAndActive()) + { _vesselSpawnPoint = Instance.CurrentStarSystem == "SolarSystem" ? UpdateVessel() : CreateVessel(); + } else { var vesselDimension = SearchUtilities.Find("DB_VesselDimension_Body/Sector_VesselDimension"); @@ -84,7 +87,12 @@ namespace NewHorizons.Handlers if (_vesselSpawnPoint is VesselSpawnPoint vesselSpawnPoint) { NHLogger.LogVerbose("Relative warping into vessel"); - vesselSpawnPoint.WarpPlayer();//Delay.FireOnNextUpdate(vesselSpawnPoint.WarpPlayer); + vesselSpawnPoint.WarpPlayer(); + + // #1034 Vessel warp sometimes has the player get flung away into space and die + // We do what we do with regular spawns where we keep resetting their position to the right one while invincible until we're relatively certain + // that the spawning sequence is done + Delay.StartCoroutine(FixPlayerSpawning(25, vesselSpawnPoint)); } else { @@ -96,6 +104,24 @@ namespace NewHorizons.Handlers LoadDB(); } + private static IEnumerator FixPlayerSpawning(int frameInterval, VesselSpawnPoint vesselSpawn) + { + InvulnerabilityHandler.MakeInvulnerable(true); + + var frameCount = 0; + while (frameCount <= frameInterval) + { + vesselSpawn.WarpPlayer(); + frameCount++; + yield return null; // Wait for the next frame + } + + InvulnerabilityHandler.MakeInvulnerable(false); + var playerBody = SearchUtilities.Find("Player_Body").GetAttachedOWRigidbody(); + var resources = playerBody.GetComponent(); + resources._currentHealth = 100f; + } + public static void LoadDB() { if (Instance.CurrentStarSystem == "SolarSystem") diff --git a/NewHorizons/Main.cs b/NewHorizons/Main.cs index e679e79a..468793aa 100644 --- a/NewHorizons/Main.cs +++ b/NewHorizons/Main.cs @@ -601,8 +601,8 @@ namespace NewHorizons { IsSystemReady = true; - // ShipWarpController will handle the invulnerability otherwise - if (!shouldWarpInFromShip) + // ShipWarpController or VesselWarpHandler will handle the invulnerability otherwise + if (!shouldWarpInFromShip && !shouldWarpInFromVessel) { Delay.FireOnNextUpdate(() => InvulnerabilityHandler.MakeInvulnerable(false)); }