diff --git a/NewHorizons/Builder/General/AstroObjectBuilder.cs b/NewHorizons/Builder/General/AstroObjectBuilder.cs index f51ab71f..a5f024da 100644 --- a/NewHorizons/Builder/General/AstroObjectBuilder.cs +++ b/NewHorizons/Builder/General/AstroObjectBuilder.cs @@ -48,8 +48,9 @@ namespace NewHorizons.Builder.General alignment._localAlignmentAxis = alignmentAxis; // Static bodies won't update rotation with physics for some reason - // Have to set it next tick else it flings the player into deep space on spawn (#171) - if (!config.Orbit.isStatic) Delay.FireOnNextUpdate(() => alignment._usePhysicsToRotate = true); + // Have to set it in 2 ticks else it flings the player into deep space on spawn (#171) + // Pushed to 3 frames after system is ready, bc spawning takes 2 frames, this is hurting my brain too much to try to improve the numbers idc + if (!config.Orbit.isStatic) Delay.RunWhen(() => Main.IsSystemReady, () => Delay.FireInNUpdates(() => alignment._usePhysicsToRotate = true, 3)); } if (config.Base.centerOfSolarSystem) diff --git a/NewHorizons/Builder/General/SpawnPointBuilder.cs b/NewHorizons/Builder/General/SpawnPointBuilder.cs index 2fdd64e9..a4a12f74 100644 --- a/NewHorizons/Builder/General/SpawnPointBuilder.cs +++ b/NewHorizons/Builder/General/SpawnPointBuilder.cs @@ -30,6 +30,8 @@ namespace NewHorizons.Builder.General // #601 we need to actually set the right trigger volumes here playerSpawn._triggerVolumes = new OWTriggerVolume[0]; + // This was a stupid hack to stop players getting stuck in the ground and now we have to keep it forever + spawnGO.transform.position += 4f * spawnGO.transform.up; spawnGO.SetActive(true); } diff --git a/NewHorizons/Handlers/PlayerSpawnHandler.cs b/NewHorizons/Handlers/PlayerSpawnHandler.cs new file mode 100644 index 00000000..3b85de45 --- /dev/null +++ b/NewHorizons/Handlers/PlayerSpawnHandler.cs @@ -0,0 +1,128 @@ +using NewHorizons.Utility; +using NewHorizons.Utility.OWML; +using System; +using UnityEngine; + +namespace NewHorizons.Handlers +{ + public static class PlayerSpawnHandler + { + private static bool _wasInvincible; + private static bool _wasDeathManagerInvincible; + private static float _impactDeathSpeed; + + public static void SetUpPlayerSpawn() + { + var spawnPoint = Main.SystemDict[Main.Instance.CurrentStarSystem].SpawnPoint; + if (spawnPoint != null) + { + SearchUtilities.Find("Player_Body").GetComponent().SetBodyToMatch(spawnPoint.GetAttachedOWRigidbody()); + GetPlayerSpawner().SetInitialSpawnPoint(spawnPoint); + } + else + { + NHLogger.Log($"No NH spawn point for {Main.Instance.CurrentStarSystem}"); + } + } + + public static void OnSystemReady(bool shouldWarpInFromShip, bool shouldWarpInFromVessel) + { + if (shouldWarpInFromShip) + { + Main.Instance.ShipWarpController.WarpIn(Main.Instance.WearingSuit); + } + else if (shouldWarpInFromVessel) + { + VesselWarpHandler.TeleportToVessel(); + } + else if (UsingCustomSpawn()) + { + var player = SearchUtilities.Find("Player_Body"); + var playerBody = player.GetAttachedOWRigidbody(); + var spawn = GetDefaultSpawn(); + + // Player dies during the teleport sometimes so we prevent that + var resources = player.GetComponent(); + var deathManager = Locator.GetDeathManager(); + + _wasInvincible = resources._invincible; + _wasDeathManagerInvincible = deathManager._invincible; + _impactDeathSpeed = deathManager._impactDeathSpeed; + + resources._invincible = true; + deathManager._invincible = true; + deathManager._impactDeathSpeed = float.MaxValue; + + Delay.FireOnNextUpdate(() => + { + var matchInitialMotion = playerBody.GetComponent(); + + playerBody.WarpToPositionRotation(spawn.transform.position, spawn.transform.rotation); + + if (matchInitialMotion != null) + { + // Idk why but these just don't work? + UnityEngine.Object.Destroy(matchInitialMotion); + Delay.FireOnNextUpdate(FixVelocity); + } + else + { + FixVelocity(); + } + }); + } + } + + private static void FixVelocity() + { + var player = SearchUtilities.Find("Player_Body"); + var playerBody = player.GetAttachedOWRigidbody(); + var spawn = GetDefaultSpawn(); + + playerBody.WarpToPositionRotation(spawn.transform.position, spawn.transform.rotation); + + // Player dies during the teleport sometimes so we prevent that + var resources = player.GetComponent(); + var deathManager = Locator.GetDeathManager(); + + var spawnVelocity = spawn._attachedBody.GetVelocity(); + var spawnAngularVelocity = spawn._attachedBody.GetPointTangentialVelocity(playerBody.transform.position); + var velocity = spawnVelocity + spawnAngularVelocity; + + playerBody.SetVelocity(velocity); + NHLogger.LogVerbose($"Player spawn velocity {velocity} Player velocity {playerBody.GetVelocity()} spawn body {spawnVelocity} spawn angular vel {spawnAngularVelocity}"); + + resources._currentHealth = 100f; + + resources._invincible = _wasInvincible; + deathManager._invincible = _wasDeathManagerInvincible; + deathManager._impactDeathSpeed = _impactDeathSpeed; + } + + private static Vector3 CalculateMatchVelocity(OWRigidbody owRigidbody, OWRigidbody bodyToMatch, bool ignoreAngularVelocity) + { + var vector = Vector3.zero; + owRigidbody.UpdateCenterOfMass(); + vector += bodyToMatch.GetVelocity(); + if (!ignoreAngularVelocity) + { + var worldCenterOfMass = owRigidbody.GetWorldCenterOfMass(); + var worldCenterOfMass2 = bodyToMatch.GetWorldCenterOfMass(); + var initAngularVelocity = bodyToMatch.GetAngularVelocity(); + vector += OWPhysics.PointTangentialVelocity(worldCenterOfMass, worldCenterOfMass2, initAngularVelocity); + } + + var aoPrimary = bodyToMatch.GetComponent()?._primaryBody?.GetAttachedOWRigidbody(); + // Stock sun has its primary as itself for some reason + if (aoPrimary != null && aoPrimary != bodyToMatch) + { + vector += CalculateMatchVelocity(bodyToMatch, aoPrimary, true); + } + return vector; + } + + public static bool UsingCustomSpawn() => Main.SystemDict[Main.Instance.CurrentStarSystem].SpawnPoint != null; + public static PlayerSpawner GetPlayerSpawner() => GameObject.FindObjectOfType(); + public static SpawnPoint GetDefaultSpawn() => Main.SystemDict[Main.Instance.CurrentStarSystem].SpawnPoint ?? GetPlayerSpawner().GetSpawnPoint(SpawnLocation.TimberHearth); + } +} diff --git a/NewHorizons/Main.cs b/NewHorizons/Main.cs index 5dbc822a..41ed8644 100644 --- a/NewHorizons/Main.cs +++ b/NewHorizons/Main.cs @@ -75,7 +75,7 @@ namespace NewHorizons private string _defaultStarSystem = "SolarSystem"; internal string _currentStarSystem = "SolarSystem"; private bool _firstLoad = true; - private ShipWarpController _shipWarpController; + public ShipWarpController ShipWarpController { get; private set; } // API events public class StarSystemEvent : UnityEvent { } @@ -418,18 +418,21 @@ namespace NewHorizons StarChartHandler.Init(SystemDict.Values.ToArray()); + // Fix spawn point + PlayerSpawnHandler.SetUpPlayerSpawn(); + if (isSolarSystem) { // Warp drive HasWarpDrive = StarChartHandler.CanWarp(); - if (_shipWarpController == null) + if (ShipWarpController == null) { - _shipWarpController = SearchUtilities.Find("Ship_Body").AddComponent(); - _shipWarpController.Init(); + ShipWarpController = SearchUtilities.Find("Ship_Body").AddComponent(); + ShipWarpController.Init(); } if (HasWarpDrive == true) EnableWarpDrive(); - var shouldWarpInFromShip = IsWarpingFromShip && _shipWarpController != null; + var shouldWarpInFromShip = IsWarpingFromShip && ShipWarpController != null; var shouldWarpInFromVessel = IsWarpingFromVessel && VesselWarpHandler.VesselSpawnPoint != null; Delay.RunWhen(() => IsSystemReady, () => OnSystemReady(shouldWarpInFromShip, shouldWarpInFromVessel)); @@ -443,7 +446,6 @@ namespace NewHorizons // Fix the map satellite SearchUtilities.Find("HearthianMapSatellite_Body", false).AddComponent(); - // Sector changes (so that projection pools actually turn off proxies and cull groups on these moons) //Fix attlerock vanilla sector components (they were set to timber hearth's sector) @@ -565,26 +567,7 @@ namespace NewHorizons Locator.GetPlayerBody().gameObject.AddComponent(); Locator.GetPlayerBody().gameObject.AddComponent(); - if (shouldWarpInFromShip) - { - _shipWarpController.WarpIn(WearingSuit); - } - else if (shouldWarpInFromVessel) - { - VesselWarpHandler.TeleportToVessel(); - } - else - { - var spawnPoint = SystemDict[CurrentStarSystem].SpawnPoint; - if (spawnPoint != null) - { - Delay.FireOnNextUpdate(() => GameObject.FindObjectOfType().DebugWarp(spawnPoint)); - } - else - { - NHLogger.Log($"No NH spawn point for {CurrentStarSystem}"); - } - } + PlayerSpawnHandler.OnSystemReady(shouldWarpInFromShip, shouldWarpInFromVessel); VesselCoordinatePromptHandler.RegisterPrompts(SystemDict.Where(system => system.Value.Config.Vessel?.coords != null).Select(x => x.Value).ToList()); } @@ -836,7 +819,7 @@ namespace NewHorizons OnChangeStarSystem?.Invoke(newStarSystem); NHLogger.Log($"Warping to {newStarSystem}"); - if (warp && _shipWarpController) _shipWarpController.WarpOut(); + if (warp && ShipWarpController) ShipWarpController.WarpOut(); IsChangingStarSystem = true; WearingSuit = PlayerState.IsWearingSuit(); @@ -884,5 +867,7 @@ namespace NewHorizons } } #endregion Change star system + + } }