mirror of
https://github.com/Outer-Wilds-New-Horizons/new-horizons.git
synced 2025-12-11 20:15:44 +01:00
Custom spawn points (#617)
<!-- Some improvement that requires no action on the part of add-on creators i.e., improved star graphics --> ## Improvements - Can now change the spawn point within the base game Hearthian system (resolves #567) <!-- Be sure to reference the existing issue if it exists --> ## Bug fixes - Fixed spawning on tidally locked planets (resolves #505)
This commit is contained in:
commit
b9e324d5a2
@ -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)
|
||||
|
||||
@ -6,6 +6,7 @@ using NewHorizons.Utility.OuterWilds;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using Steamworks;
|
||||
|
||||
namespace NewHorizons.Builder.General
|
||||
{
|
||||
@ -16,25 +17,39 @@ namespace NewHorizons.Builder.General
|
||||
{
|
||||
SpawnPoint playerSpawn = null;
|
||||
|
||||
if (!Main.Instance.IsWarpingFromVessel && !Main.Instance.IsWarpingFromShip && module.playerSpawn != null)
|
||||
// Make the spawn point even if it won't be used this loop
|
||||
if (module.playerSpawn != null)
|
||||
{
|
||||
GameObject spawnGO = GeneralPropBuilder.MakeNew("PlayerSpawnPoint", planetGO, null, module.playerSpawn);
|
||||
spawnGO.SetActive(false);
|
||||
spawnGO.layer = Layer.PlayerSafetyCollider;
|
||||
|
||||
playerSpawn = spawnGO.AddComponent<SpawnPoint>();
|
||||
playerSpawn._attachedBody = owRigidBody;
|
||||
playerSpawn._spawnLocation = SpawnLocation.None;
|
||||
// #601 we need to actually set the right trigger volumes here
|
||||
playerSpawn._triggerVolumes = new OWTriggerVolume[0];
|
||||
|
||||
spawnGO.transform.position += spawnGO.transform.up * 4f;
|
||||
// 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);
|
||||
}
|
||||
|
||||
if (module.shipSpawn != null)
|
||||
{
|
||||
GameObject spawnGO = GeneralPropBuilder.MakeNew("ShipSpawnPoint", planetGO, null, module.shipSpawn);
|
||||
spawnGO.SetActive(false);
|
||||
spawnGO.layer = Layer.PlayerSafetyCollider;
|
||||
|
||||
var spawnPoint = spawnGO.AddComponent<SpawnPoint>();
|
||||
spawnPoint._isShipSpawn = true;
|
||||
spawnPoint._triggerVolumes = new OWTriggerVolume[0];
|
||||
var shipSpawn = spawnGO.AddComponent<SpawnPoint>();
|
||||
shipSpawn._isShipSpawn = true;
|
||||
shipSpawn._attachedBody = owRigidBody;
|
||||
shipSpawn._spawnLocation = SpawnLocation.None;
|
||||
|
||||
// #601 we need to actually set the right trigger volumes here
|
||||
shipSpawn._triggerVolumes = new OWTriggerVolume[0];
|
||||
|
||||
// TODO: this should happen elsewhere
|
||||
var ship = SearchUtilities.Find("Ship_Body");
|
||||
if (ship != null)
|
||||
{
|
||||
@ -48,27 +63,14 @@ namespace NewHorizons.Builder.General
|
||||
}
|
||||
|
||||
ship.GetRequiredComponent<MatchInitialMotion>().SetBodyToMatch(owRigidBody);
|
||||
|
||||
if (Main.Instance.IsWarpingFromShip)
|
||||
{
|
||||
NHLogger.LogVerbose("Overriding player spawn to be inside ship");
|
||||
GameObject playerSpawnGO = new GameObject("PlayerSpawnPoint");
|
||||
playerSpawnGO.transform.parent = ship.transform;
|
||||
playerSpawnGO.layer = Layer.PlayerSafetyCollider;
|
||||
|
||||
playerSpawnGO.transform.localPosition = new Vector3(0, 0, 0);
|
||||
|
||||
playerSpawn = playerSpawnGO.AddComponent<SpawnPoint>();
|
||||
playerSpawn._triggerVolumes = new OWTriggerVolume[0];
|
||||
playerSpawnGO.transform.localRotation = Quaternion.Euler(0, 0, 0);
|
||||
}
|
||||
}
|
||||
spawnGO.SetActive(true);
|
||||
}
|
||||
|
||||
if ((Main.Instance.IsWarpingFromVessel || (!Main.Instance.IsWarpingFromShip && (module.playerSpawn?.startWithSuit ?? false))) && !suitUpQueued)
|
||||
{
|
||||
suitUpQueued = true;
|
||||
Delay.RunWhen(() => Main.IsSystemReady, () => SuitUp());
|
||||
Delay.RunWhen(() => Main.IsSystemReady, SuitUp);
|
||||
}
|
||||
|
||||
NHLogger.Log($"Made spawnpoint on [{planetGO.name}]");
|
||||
|
||||
@ -134,7 +134,7 @@ namespace NewHorizons.Components.Ship
|
||||
{
|
||||
if (_isWarpingIn && LateInitializerManager.isDoneInitializing)
|
||||
{
|
||||
Delay.FireInNUpdates(() => StartWarpInEffect(), 1);
|
||||
Delay.FireOnNextUpdate(StartWarpInEffect);
|
||||
_isWarpingIn = false;
|
||||
}
|
||||
|
||||
@ -167,7 +167,7 @@ namespace NewHorizons.Components.Ship
|
||||
NHLogger.LogVerbose("Starting warp-in effect");
|
||||
_oneShotSource.PlayOneShot(AudioType.VesselSingularityCollapse, 1f);
|
||||
Locator.GetDeathManager()._invincible = true;
|
||||
if (Main.Instance.CurrentStarSystem.Equals("SolarSystem")) TeleportToShip();
|
||||
TeleportToShip();
|
||||
_whitehole.Create();
|
||||
_waitingToBeSeated = true;
|
||||
if (_wearingSuit && !Locator.GetPlayerController()._isWearingSuit)
|
||||
@ -179,6 +179,7 @@ namespace NewHorizons.Components.Ship
|
||||
private void TeleportToShip()
|
||||
{
|
||||
var playerSpawner = FindObjectOfType<PlayerSpawner>();
|
||||
NHLogger.LogVerbose("Debug warping into ship");
|
||||
playerSpawner.DebugWarp(playerSpawner.GetSpawnPoint(SpawnLocation.Ship));
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ namespace NewHorizons.External.Modules.VariableSize
|
||||
public class VariableSizeModule
|
||||
{
|
||||
/// <summary>
|
||||
/// Scale this object over time
|
||||
/// Scale this object over time. Time value is in minutes.
|
||||
/// </summary>
|
||||
public TimeValuePair[] curve;
|
||||
}
|
||||
|
||||
@ -456,9 +456,12 @@ namespace NewHorizons.Handlers
|
||||
// Spawning on other planets is a bit hacky so we do it last
|
||||
if (body.Config.Spawn != null)
|
||||
{
|
||||
NHLogger.LogVerbose("Making spawn point");
|
||||
NHLogger.LogVerbose($"Making spawn point on {body.Config.name}");
|
||||
var spawnPoint = SpawnPointBuilder.Make(go, body.Config.Spawn, owRigidBody);
|
||||
if (Main.SystemDict[body.Config.starSystem].SpawnPoint == null || (body.Config.Spawn.playerSpawn?.isDefault ?? false))
|
||||
var isVanillaSystem = body.Config.starSystem == "SolarSystem" || body.Config.starSystem == "EyeOfTheUniverse";
|
||||
var needsSpawnPoint = Main.SystemDict[body.Config.starSystem].SpawnPoint == null || isVanillaSystem;
|
||||
var isDefaultSpawn = body.Config.Spawn.playerSpawn?.isDefault ?? true; // Backwards compat
|
||||
if (needsSpawnPoint || isDefaultSpawn)
|
||||
{
|
||||
Main.SystemDict[body.Config.starSystem].SpawnPoint = spawnPoint;
|
||||
}
|
||||
|
||||
128
NewHorizons/Handlers/PlayerSpawnHandler.cs
Normal file
128
NewHorizons/Handlers/PlayerSpawnHandler.cs
Normal file
@ -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<MatchInitialMotion>().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<PlayerResources>();
|
||||
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<MatchInitialMotion>();
|
||||
|
||||
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<PlayerResources>();
|
||||
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<AstroObject>()?._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<PlayerSpawner>();
|
||||
public static SpawnPoint GetDefaultSpawn() => Main.SystemDict[Main.Instance.CurrentStarSystem].SpawnPoint ?? GetPlayerSpawner().GetSpawnPoint(SpawnLocation.TimberHearth);
|
||||
}
|
||||
}
|
||||
@ -62,6 +62,7 @@ namespace NewHorizons.Handlers
|
||||
public static void TeleportToVessel()
|
||||
{
|
||||
var playerSpawner = Object.FindObjectOfType<PlayerSpawner>();
|
||||
NHLogger.LogVerbose("Debug warping into vessel");
|
||||
playerSpawner.DebugWarp(_vesselSpawnPoint);
|
||||
Builder.General.SpawnPointBuilder.SuitUp();
|
||||
|
||||
|
||||
@ -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<string> { }
|
||||
@ -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>();
|
||||
_shipWarpController.Init();
|
||||
ShipWarpController = SearchUtilities.Find("Ship_Body").AddComponent<ShipWarpController>();
|
||||
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<MapSatelliteOrbitFix>();
|
||||
|
||||
|
||||
// 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)
|
||||
@ -564,11 +566,8 @@ namespace NewHorizons
|
||||
Locator.GetPlayerBody().gameObject.AddComponent<DebugRaycaster>();
|
||||
Locator.GetPlayerBody().gameObject.AddComponent<DebugPropPlacer>();
|
||||
Locator.GetPlayerBody().gameObject.AddComponent<DebugMenu>();
|
||||
// DebugArrow.CreateArrow(Locator.GetPlayerBody().gameObject); // This is for NH devs mostly. It shouldn't be active in debug mode for now. Someone should make a dev tools submenu for it though.
|
||||
|
||||
if (shouldWarpInFromShip) _shipWarpController.WarpIn(WearingSuit);
|
||||
else if (shouldWarpInFromVessel) VesselWarpHandler.TeleportToVessel();
|
||||
else FindObjectOfType<PlayerSpawner>().DebugWarp(SystemDict[_currentStarSystem].SpawnPoint);
|
||||
PlayerSpawnHandler.OnSystemReady(shouldWarpInFromShip, shouldWarpInFromVessel);
|
||||
|
||||
VesselCoordinatePromptHandler.RegisterPrompts(SystemDict.Where(system => system.Value.Config.Vessel?.coords != null).Select(x => x.Value).ToList());
|
||||
}
|
||||
@ -820,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();
|
||||
|
||||
@ -868,5 +867,7 @@ namespace NewHorizons
|
||||
}
|
||||
}
|
||||
#endregion Change star system
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,19 +11,12 @@ namespace NewHorizons.Patches.PlayerPatches
|
||||
[HarmonyPatch(nameof(PlayerSpawner.SpawnPlayer))]
|
||||
public static bool PlayerSpawner_SpawnPlayer(PlayerSpawner __instance)
|
||||
{
|
||||
if (Main.Instance.IsWarpingFromVessel || Main.Instance.DidWarpFromVessel)
|
||||
if (Main.Instance.IsWarpingFromVessel || Main.Instance.DidWarpFromVessel || Main.Instance.IsWarpingFromShip)
|
||||
{
|
||||
NHLogger.LogWarning("Abort player spawn. Vessel will handle it.");
|
||||
NHLogger.LogWarning("Abort player spawn. Vessel/Ship will handle it.");
|
||||
return false;
|
||||
}
|
||||
else if (Main.SystemDict[Main.Instance.CurrentStarSystem].SpawnPoint != null)
|
||||
{
|
||||
NHLogger.LogVerbose($"Player spawning at {Main.SystemDict[Main.Instance.CurrentStarSystem].SpawnPoint.transform.GetPath()}");
|
||||
__instance.SetInitialSpawnPoint(Main.SystemDict[Main.Instance.CurrentStarSystem].SpawnPoint);
|
||||
} else if (Main.Instance.CurrentStarSystem != "SolarSystem" && Main.Instance.CurrentStarSystem != "EyeOfTheUniverse")
|
||||
{
|
||||
NHLogger.LogWarning("No player spawn point set.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -774,7 +774,7 @@
|
||||
"properties": {
|
||||
"curve": {
|
||||
"type": "array",
|
||||
"description": "Scale this object over time",
|
||||
"description": "Scale this object over time. Time value is in minutes.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/TimeValuePair"
|
||||
}
|
||||
@ -963,7 +963,7 @@
|
||||
"properties": {
|
||||
"curve": {
|
||||
"type": "array",
|
||||
"description": "Scale this object over time",
|
||||
"description": "Scale this object over time. Time value is in minutes.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/TimeValuePair"
|
||||
}
|
||||
@ -2854,7 +2854,7 @@
|
||||
"properties": {
|
||||
"curve": {
|
||||
"type": "array",
|
||||
"description": "Scale this object over time",
|
||||
"description": "Scale this object over time. Time value is in minutes.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/TimeValuePair"
|
||||
}
|
||||
@ -3088,7 +3088,7 @@
|
||||
"properties": {
|
||||
"curve": {
|
||||
"type": "array",
|
||||
"description": "Scale this object over time",
|
||||
"description": "Scale this object over time. Time value is in minutes.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/TimeValuePair"
|
||||
}
|
||||
@ -3222,7 +3222,7 @@
|
||||
"properties": {
|
||||
"curve": {
|
||||
"type": "array",
|
||||
"description": "Scale this object over time",
|
||||
"description": "Scale this object over time. Time value is in minutes.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/TimeValuePair"
|
||||
}
|
||||
@ -4430,7 +4430,7 @@
|
||||
"properties": {
|
||||
"curve": {
|
||||
"type": "array",
|
||||
"description": "Scale this object over time",
|
||||
"description": "Scale this object over time. Time value is in minutes.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/TimeValuePair"
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user