diff --git a/NewHorizons/Builder/Body/StarBuilder.cs b/NewHorizons/Builder/Body/StarBuilder.cs index 3b5abd0d..53379f40 100644 --- a/NewHorizons/Builder/Body/StarBuilder.cs +++ b/NewHorizons/Builder/Body/StarBuilder.cs @@ -58,7 +58,7 @@ namespace NewHorizons.Builder.Body if (_flareMaterial == null) { _flareMaterial = new Material(_starSolarFlareEmitter.GetComponentInChildren().GetComponent().sharedMaterial).DontDestroyOnLoad(); - _flareMaterial.color = Color.white; + _flareMaterial.SetColor(Shader.PropertyToID("_Color"), Color.white); } } @@ -353,9 +353,13 @@ namespace NewHorizons.Builder.Body var flareTint = starModule.tint.ToColor(); var emitter = solarFlareEmitter.GetComponent(); emitter.tint = flareTint; + var material = new Material(_flareMaterial); - foreach (var controller in solarFlareEmitter.GetComponentsInChildren()) + // Since the star isn't awake yet the controllers haven't been made + foreach (var prefab in new GameObject[] { emitter.domePrefab, emitter.loopPrefab, emitter.streamerPrefab }) { + var controller = prefab.GetComponent(); + // controller._meshRenderer doesn't exist yet since Awake hasn't been called controller.GetComponent().sharedMaterial = material; controller._color = Color.white; controller._tint = flareTint; diff --git a/NewHorizons/Builder/General/AstroObjectBuilder.cs b/NewHorizons/Builder/General/AstroObjectBuilder.cs index f51ab71f..aec97f75 100644 --- a/NewHorizons/Builder/General/AstroObjectBuilder.cs +++ b/NewHorizons/Builder/General/AstroObjectBuilder.cs @@ -7,9 +7,10 @@ namespace NewHorizons.Builder.General { public static class AstroObjectBuilder { - public static NHAstroObject Make(GameObject body, AstroObject primaryBody, PlanetConfig config) + public static NHAstroObject Make(GameObject body, AstroObject primaryBody, PlanetConfig config, bool isVanilla) { NHAstroObject astroObject = body.AddComponent(); + astroObject.isVanilla = isVanilla; astroObject.HideDisplayName = !config.Base.hasMapMarker; astroObject.invulnerableToSun = config.Base.invulnerableToSun; @@ -48,8 +49,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 bac09f22..a4a12f74 100644 --- a/NewHorizons/Builder/General/SpawnPointBuilder.cs +++ b/NewHorizons/Builder/General/SpawnPointBuilder.cs @@ -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(); + 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._isShipSpawn = true; - spawnPoint._triggerVolumes = new OWTriggerVolume[0]; + var shipSpawn = spawnGO.AddComponent(); + 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().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(); - 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}]"); diff --git a/NewHorizons/Builder/Props/Audio/SignalBuilder.cs b/NewHorizons/Builder/Props/Audio/SignalBuilder.cs index 2fb84fd5..a5e74626 100644 --- a/NewHorizons/Builder/Props/Audio/SignalBuilder.cs +++ b/NewHorizons/Builder/Props/Audio/SignalBuilder.cs @@ -1,14 +1,13 @@ -using NewHorizons.External.Modules; +using HarmonyLib; +using NewHorizons.External.Modules.Props.Audio; using NewHorizons.Utility; -using NewHorizons.Utility.Files; using NewHorizons.Utility.OWML; -using NewHorizons.Utility.OuterWilds; using OWML.Common; using OWML.Utils; using System.Collections.Generic; -using UnityEngine; -using NewHorizons.External.Modules.Props.Audio; using System.Linq; +using UnityEngine; +using UnityEngine.SceneManagement; namespace NewHorizons.Builder.Props.Audio { @@ -20,8 +19,8 @@ namespace NewHorizons.Builder.Props.Audio public static int NumberOfFrequencies; - private static List _qmSignals; - private static List _cloakedSignals; + private static HashSet _qmSignals; + private static HashSet _cloakedSignals; public static bool Initialized; @@ -36,22 +35,46 @@ namespace NewHorizons.Builder.Props.Audio }; NumberOfFrequencies = EnumUtils.GetValues().Length; - _qmSignals = new List() { SearchUtilities.Find("QuantumMoon_Body/Signal_Quantum").GetComponent() }; - _cloakedSignals = new List(); + _qmSignals = new (){ SearchUtilities.Find("QuantumMoon_Body/Signal_Quantum").GetComponent() }; + _cloakedSignals = new(); Initialized = true; + + SceneManager.sceneUnloaded += OnSceneUnloaded; + Main.Instance.OnStarSystemLoaded.AddListener(OnStarSystemLoaded); } - public static bool IsCloaked(this AudioSignal signal) + private static HashSet _frequenciesInUse = new(); + + private static void OnSceneUnloaded(Scene _) { - return _cloakedSignals.Contains(signal); + _frequenciesInUse.Clear(); } - public static bool IsOnQuantumMoon(this AudioSignal signal) + private static void OnStarSystemLoaded(string starSystem) { - return _qmSignals.Contains(signal); + // If its the base game solar system or eye we get all the main frequencies + if (starSystem == "SolarSystem" || starSystem == "EyeOfTheUniverse") + { + _frequenciesInUse.Add(SignalFrequency.Quantum); + _frequenciesInUse.Add(SignalFrequency.EscapePod); + _frequenciesInUse.Add(SignalFrequency.Radio); + _frequenciesInUse.Add(SignalFrequency.HideAndSeek); + } + + // Always show the traveler frequency. The signalscope defaults to this on spawn, and is the only frequency known by default + // We don't want a scenario where the player knows no frequencies + _frequenciesInUse.Add(SignalFrequency.Traveler); + + NHLogger.LogVerbose($"Frequencies in use in {starSystem}: {_frequenciesInUse.Join(x => x.ToString())}"); } + public static bool IsFrequencyInUse(SignalFrequency freq) => _frequenciesInUse.Contains(freq); + + public static bool IsCloaked(this AudioSignal signal) => _cloakedSignals.Contains(signal); + + public static bool IsOnQuantumMoon(this AudioSignal signal) => _qmSignals.Contains(signal); + public static SignalFrequency AddFrequency(string str) { if (_customFrequencyNames == null) Init(); @@ -153,6 +176,8 @@ namespace NewHorizons.Builder.Props.Audio if (planetGO.GetComponent()?.GetAstroObjectName() == AstroObject.Name.QuantumMoon) _qmSignals.Add(audioSignal); if (info.insideCloak) _cloakedSignals.Add(audioSignal); + _frequenciesInUse.Add(frequency); + return signalGO; } diff --git a/NewHorizons/Builder/Props/DialogueBuilder.cs b/NewHorizons/Builder/Props/DialogueBuilder.cs index 9e2da10c..8016f80d 100644 --- a/NewHorizons/Builder/Props/DialogueBuilder.cs +++ b/NewHorizons/Builder/Props/DialogueBuilder.cs @@ -147,6 +147,7 @@ namespace NewHorizons.Builder.Props var controller = character.GetComponent(); var traveler = character.GetComponent(); var travelerEye = character.GetComponent(); + var hearthianRecorder = character.GetComponent(); var lookOnlyWhenTalking = info.lookAtRadius <= 0; @@ -196,6 +197,34 @@ namespace NewHorizons.Builder.Props dialogue.OnEndConversation += nomaiController.StopWatchingPlayer; } } + else if (hearthianRecorder != null) + { + Delay.FireOnNextUpdate(() => + { + // #520 + if (hearthianRecorder._characterDialogueTree != null) + { + hearthianRecorder._characterDialogueTree.OnStartConversation -= hearthianRecorder.OnPlayRecorder; + hearthianRecorder._characterDialogueTree.OnEndConversation -= hearthianRecorder.OnStopRecorder; + } + + // Recorder props have their own dialogue on them already + // Make sure to delete it when we're trying to connect new dialogue to it + var existingDialogue = hearthianRecorder.GetComponent(); + if (existingDialogue != dialogue && existingDialogue != null) + { + // Can't delete the existing dialogue because its a required component but we can make it unable to select at least + GameObject.Destroy(hearthianRecorder.GetComponent()); + GameObject.Destroy(hearthianRecorder.GetComponent()); + GameObject.Destroy(existingDialogue._interactVolume); + existingDialogue.enabled = false; + } + + hearthianRecorder._characterDialogueTree = dialogue; + hearthianRecorder._characterDialogueTree.OnStartConversation += hearthianRecorder.OnPlayRecorder; + hearthianRecorder._characterDialogueTree.OnEndConversation += hearthianRecorder.OnStopRecorder; + }); + } else { // If they have nothing else just put the face player when talking thing on them diff --git a/NewHorizons/Builder/Props/WarpPadBuilder.cs b/NewHorizons/Builder/Props/WarpPadBuilder.cs index 07aa3e90..41bf6ed6 100644 --- a/NewHorizons/Builder/Props/WarpPadBuilder.cs +++ b/NewHorizons/Builder/Props/WarpPadBuilder.cs @@ -1,4 +1,5 @@ using NewHorizons.Builder.Props.TranslatorText; +using NewHorizons.Components; using NewHorizons.External.Modules.Props; using NewHorizons.External.Modules.WarpPad; using NewHorizons.Utility; @@ -137,6 +138,9 @@ namespace NewHorizons.Builder.Props transmitter.GetComponent().enabled = true; + // Prevents the transmitter from sending you straight back if you use the return function of the receiver #563 + transmitterObject.AddComponent(); + transmitterObject.SetActive(true); } diff --git a/NewHorizons/Components/NomaiWarpTransmitterCooldown.cs b/NewHorizons/Components/NomaiWarpTransmitterCooldown.cs new file mode 100644 index 00000000..f057b062 --- /dev/null +++ b/NewHorizons/Components/NomaiWarpTransmitterCooldown.cs @@ -0,0 +1,45 @@ +using UnityEngine; + +namespace NewHorizons.Components +{ + public class NomaiWarpTransmitterCooldown : MonoBehaviour + { + private NomaiWarpTransmitter _transmitter; + private NomaiWarpReceiver _receiver; + + private float _reenabledTime = 0f; + private bool _cooldownActive; + + public void Start() + { + _transmitter = GetComponent(); + _transmitter.OnReceiveWarpedBody += _transmitter_OnReceiveWarpedBody; + } + + public void OnDestroy() + { + if (_transmitter != null) + { + _transmitter.OnReceiveWarpedBody -= _transmitter_OnReceiveWarpedBody; + } + } + + private void _transmitter_OnReceiveWarpedBody(OWRigidbody warpedBody, NomaiWarpPlatform startPlatform, NomaiWarpPlatform targetPlatform) + { + _cooldownActive = true; + + _reenabledTime = Time.time + 5f; + _receiver = _transmitter._targetReceiver; + _transmitter._targetReceiver = null; + } + + public void FixedUpdate() + { + if (_cooldownActive && Time.time > _reenabledTime) + { + _cooldownActive = false; + _transmitter._targetReceiver = _receiver; + } + } + } +} diff --git a/NewHorizons/Components/Orbital/NHAstroObject.cs b/NewHorizons/Components/Orbital/NHAstroObject.cs index 2087bf8c..ed51060c 100644 --- a/NewHorizons/Components/Orbital/NHAstroObject.cs +++ b/NewHorizons/Components/Orbital/NHAstroObject.cs @@ -12,6 +12,7 @@ namespace NewHorizons.Components.Orbital public bool HideDisplayName { get; set; } public bool IsDimension { get; set; } public bool invulnerableToSun; + public bool isVanilla; public void SetOrbitalParametersFromConfig(OrbitModule orbit) { diff --git a/NewHorizons/Components/Ship/ShipWarpController.cs b/NewHorizons/Components/Ship/ShipWarpController.cs index 3d951631..8917ddb0 100644 --- a/NewHorizons/Components/Ship/ShipWarpController.cs +++ b/NewHorizons/Components/Ship/ShipWarpController.cs @@ -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(); + NHLogger.LogVerbose("Debug warping into ship"); playerSpawner.DebugWarp(playerSpawner.GetSpawnPoint(SpawnLocation.Ship)); } diff --git a/NewHorizons/Components/SizeControllers/StarEvolutionController.cs b/NewHorizons/Components/SizeControllers/StarEvolutionController.cs index c55b44fd..5550daa4 100644 --- a/NewHorizons/Components/SizeControllers/StarEvolutionController.cs +++ b/NewHorizons/Components/SizeControllers/StarEvolutionController.cs @@ -252,7 +252,10 @@ namespace NewHorizons.Components.SizeControllers _surface._materials[0].SetFloat(ColorTime, 0); } - if (_flareEmitter != null) _flareEmitter._tint = _currentColour; + if (_flareEmitter != null) + { + _flareEmitter.tint = _currentColour; + } } private void UpdateCollapse() diff --git a/NewHorizons/External/Configs/AddonConfig.cs b/NewHorizons/External/Configs/AddonConfig.cs index a43f3910..54d8cf0e 100644 --- a/NewHorizons/External/Configs/AddonConfig.cs +++ b/NewHorizons/External/Configs/AddonConfig.cs @@ -26,5 +26,10 @@ namespace NewHorizons.External.Configs /// A pop-up message for the first time a user runs the add-on /// public string popupMessage; + + /// + /// If popupMessage is set, should it repeat every time the game starts or only once + /// + public bool repeatPopup; } } diff --git a/NewHorizons/External/Modules/Props/Dialogue/DialogueInfo.cs b/NewHorizons/External/Modules/Props/Dialogue/DialogueInfo.cs index 0cf3c823..06207150 100644 --- a/NewHorizons/External/Modules/Props/Dialogue/DialogueInfo.cs +++ b/NewHorizons/External/Modules/Props/Dialogue/DialogueInfo.cs @@ -22,7 +22,10 @@ namespace NewHorizons.External.Modules.Props.Dialogue /// /// If this dialogue is meant for a character, this is the relative path from the planet to that character's - /// CharacterAnimController, TravelerController, TravelerEyeController (eye of the universe), FacePlayerWhenTalking, or SolanumAnimController. + /// CharacterAnimController, TravelerController, TravelerEyeController (eye of the universe), FacePlayerWhenTalking, + /// HearthianRecorderEffects or SolanumAnimController. + /// + /// If it's a Recorder this will also delete the existing dialogue already attached to that prop. /// /// If none of those components are present it will add a FacePlayerWhenTalking component. /// diff --git a/NewHorizons/External/Modules/VariableSize/VariableSizeModule.cs b/NewHorizons/External/Modules/VariableSize/VariableSizeModule.cs index cb1649ee..6e046b42 100644 --- a/NewHorizons/External/Modules/VariableSize/VariableSizeModule.cs +++ b/NewHorizons/External/Modules/VariableSize/VariableSizeModule.cs @@ -6,7 +6,7 @@ namespace NewHorizons.External.Modules.VariableSize public class VariableSizeModule { /// - /// Scale this object over time + /// Scale this object over time. Time value is in minutes. /// public TimeValuePair[] curve; } diff --git a/NewHorizons/Handlers/PlanetCreationHandler.cs b/NewHorizons/Handlers/PlanetCreationHandler.cs index 8d0eceee..3ef2c324 100644 --- a/NewHorizons/Handlers/PlanetCreationHandler.cs +++ b/NewHorizons/Handlers/PlanetCreationHandler.cs @@ -343,7 +343,7 @@ namespace NewHorizons.Handlers body.Config.Base.hasMapMarker = false; var owRigidBody = RigidBodyBuilder.Make(go, body.Config); - var ao = AstroObjectBuilder.Make(go, null, body.Config); + var ao = AstroObjectBuilder.Make(go, null, body.Config, false); var sector = SectorBuilder.Make(go, owRigidBody, 2000f); ao._rootSector = sector; @@ -409,7 +409,7 @@ namespace NewHorizons.Handlers } var owRigidBody = RigidBodyBuilder.Make(go, body.Config); - var ao = AstroObjectBuilder.Make(go, primaryBody, body.Config); + var ao = AstroObjectBuilder.Make(go, primaryBody, body.Config, false); var sphereOfInfluence = GetSphereOfInfluence(body); @@ -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; } @@ -702,7 +705,7 @@ namespace NewHorizons.Handlers } // Just destroy the existing AO after copying everything over - var newAO = AstroObjectBuilder.Make(go, primary, body.Config); + var newAO = AstroObjectBuilder.Make(go, primary, body.Config, true); newAO._gravityVolume = ao._gravityVolume; newAO._moon = ao._moon; newAO._name = ao._name; 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/Handlers/VesselWarpHandler.cs b/NewHorizons/Handlers/VesselWarpHandler.cs index 9cc279ce..07277776 100644 --- a/NewHorizons/Handlers/VesselWarpHandler.cs +++ b/NewHorizons/Handlers/VesselWarpHandler.cs @@ -62,6 +62,7 @@ namespace NewHorizons.Handlers public static void TeleportToVessel() { var playerSpawner = Object.FindObjectOfType(); + NHLogger.LogVerbose("Debug warping into vessel"); playerSpawner.DebugWarp(_vesselSpawnPoint); Builder.General.SpawnPointBuilder.SuitUp(); diff --git a/NewHorizons/Main.cs b/NewHorizons/Main.cs index 1b431a0e..6ef0e65f 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) @@ -564,11 +566,8 @@ namespace NewHorizons Locator.GetPlayerBody().gameObject.AddComponent(); Locator.GetPlayerBody().gameObject.AddComponent(); Locator.GetPlayerBody().gameObject.AddComponent(); - // 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().DebugWarp(SystemDict[_currentStarSystem].SpawnPoint); + PlayerSpawnHandler.OnSystemReady(shouldWarpInFromShip, shouldWarpInFromVessel); VesselCoordinatePromptHandler.RegisterPrompts(SystemDict.Where(system => system.Value.Config.Vessel?.coords != null).Select(x => x.Value).ToList()); } @@ -701,7 +700,7 @@ namespace NewHorizons } if (!string.IsNullOrEmpty(addonConfig.popupMessage)) { - MenuHandler.RegisterOneTimePopup(mod, TranslationHandler.GetTranslation(addonConfig.popupMessage, TranslationHandler.TextType.UI)); + MenuHandler.RegisterOneTimePopup(mod, TranslationHandler.GetTranslation(addonConfig.popupMessage, TranslationHandler.TextType.UI), addonConfig.repeatPopup); } } @@ -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 + + } } diff --git a/NewHorizons/OtherMods/MenuFramework/MenuHandler.cs b/NewHorizons/OtherMods/MenuFramework/MenuHandler.cs index 4181c2d5..101a0789 100644 --- a/NewHorizons/OtherMods/MenuFramework/MenuHandler.cs +++ b/NewHorizons/OtherMods/MenuFramework/MenuHandler.cs @@ -13,7 +13,7 @@ namespace NewHorizons.OtherMods.MenuFramework { private static IMenuAPI _menuApi; - private static List<(IModBehaviour mod, string message)> _registeredPopups = new(); + private static List<(IModBehaviour mod, string message, bool repeat)> _registeredPopups = new(); private static List _failedFiles = new(); public static void Init() @@ -38,9 +38,9 @@ namespace NewHorizons.OtherMods.MenuFramework _menuApi.RegisterStartupPopup(warning); } - foreach(var (mod, message) in _registeredPopups) + foreach(var (mod, message, repeat) in _registeredPopups) { - if (!NewHorizonsData.HasReadOneTimePopup(mod.ModHelper.Manifest.UniqueName)) + if (repeat || !NewHorizonsData.HasReadOneTimePopup(mod.ModHelper.Manifest.UniqueName)) { _menuApi.RegisterStartupPopup(TranslationHandler.GetTranslation(message, TranslationHandler.TextType.UI)); NewHorizonsData.ReadOneTimePopup(mod.ModHelper.Manifest.UniqueName); @@ -64,6 +64,6 @@ namespace NewHorizons.OtherMods.MenuFramework public static void RegisterFailedConfig(string filename) => _failedFiles.Add(filename); - public static void RegisterOneTimePopup(IModBehaviour mod, string message) => _registeredPopups.Add((mod, message)); + public static void RegisterOneTimePopup(IModBehaviour mod, string message, bool repeat) => _registeredPopups.Add((mod, message, repeat)); } } diff --git a/NewHorizons/Patches/DialoguePatches/HearthianRecorderEffectsPatches.cs b/NewHorizons/Patches/DialoguePatches/HearthianRecorderEffectsPatches.cs new file mode 100644 index 00000000..b4b28a55 --- /dev/null +++ b/NewHorizons/Patches/DialoguePatches/HearthianRecorderEffectsPatches.cs @@ -0,0 +1,24 @@ +using HarmonyLib; + +namespace NewHorizons.Patches.DialoguePatches +{ + [HarmonyPatch(typeof(HearthianRecorderEffects))] + public static class HearthianRecorderEffectsPatches + { + [HarmonyPrefix] + [HarmonyPatch(nameof(HearthianRecorderEffects.Awake))] + public static bool HearthianRecorderEffects_Awake(HearthianRecorderEffects __instance) + { + // If we're adding custom dialogue to a recorder the CharacterDialogueTree isn't going to be on the object + if (__instance.GetComponent() == null) + { + __instance.enabled = false; + return false; + } + else + { + return true; + } + } + } +} diff --git a/NewHorizons/Patches/MapPatches/ReferenceFramePatches.cs b/NewHorizons/Patches/MapPatches/ReferenceFramePatches.cs index a9efb8b1..ba8deac6 100644 --- a/NewHorizons/Patches/MapPatches/ReferenceFramePatches.cs +++ b/NewHorizons/Patches/MapPatches/ReferenceFramePatches.cs @@ -7,32 +7,19 @@ namespace NewHorizons.Patches.MapPatches [HarmonyPatch(typeof(ReferenceFrame))] public static class ReferenceFramePatches { - [HarmonyPrefix] + [HarmonyPostfix] [HarmonyPatch(nameof(ReferenceFrame.GetHUDDisplayName))] - public static bool ReferenceFrame_GetHUDDisplayName(ReferenceFrame __instance, ref string __result) + public static void ReferenceFrame_GetHUDDisplayName(ReferenceFrame __instance, ref string __result) { - var ao = __instance.GetAstroObject(); - - if (ao == null) return true; - - if (ao._name != AstroObject.Name.CustomString) + if (__instance.GetAstroObject() is NHAstroObject nhao && !nhao.isVanilla && !nhao.HideDisplayName) { - __result = AstroObject.AstroObjectNameToString(ao._name); - return false; + var customName = nhao.GetCustomName(); + + if (!string.IsNullOrWhiteSpace(customName)) + { + __result = TranslationHandler.GetTranslation(customName, TranslationHandler.TextType.UI, false); + } } - - __result = string.Empty; - - if (ao is NHAstroObject nhao && nhao.HideDisplayName) return false; - - var customName = ao.GetCustomName(); - - if (!string.IsNullOrWhiteSpace(customName)) - { - __result = TranslationHandler.GetTranslation(customName, TranslationHandler.TextType.UI, false); - } - - return false; } } } diff --git a/NewHorizons/Patches/PlayerPatches/PlayerSpawnerPatches.cs b/NewHorizons/Patches/PlayerPatches/PlayerSpawnerPatches.cs index f3017482..70099cce 100644 --- a/NewHorizons/Patches/PlayerPatches/PlayerSpawnerPatches.cs +++ b/NewHorizons/Patches/PlayerPatches/PlayerSpawnerPatches.cs @@ -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; } } diff --git a/NewHorizons/Patches/SignalPatches/SignalscopePatches.cs b/NewHorizons/Patches/SignalPatches/SignalscopePatches.cs index a348152e..12c54db5 100644 --- a/NewHorizons/Patches/SignalPatches/SignalscopePatches.cs +++ b/NewHorizons/Patches/SignalPatches/SignalscopePatches.cs @@ -21,9 +21,11 @@ namespace NewHorizons.Patches.SignalPatches __instance._frequencyFilterIndex += increment; __instance._frequencyFilterIndex = __instance._frequencyFilterIndex >= count ? 0 : __instance._frequencyFilterIndex; __instance._frequencyFilterIndex = __instance._frequencyFilterIndex < 0 ? count - 1 : __instance._frequencyFilterIndex; - SignalFrequency signalFrequency = AudioSignal.IndexToFrequency(__instance._frequencyFilterIndex); + var signalFrequency = AudioSignal.IndexToFrequency(__instance._frequencyFilterIndex); - if (!PlayerData.KnowsFrequency(signalFrequency) && (!__instance._isUnknownFreqNearby || __instance._unknownFrequency != signalFrequency)) + // Skip over this frequency + var isUnknown = !PlayerData.KnowsFrequency(signalFrequency) && !(__instance._isUnknownFreqNearby && __instance._unknownFrequency == signalFrequency); + if (isUnknown || !SignalBuilder.IsFrequencyInUse(signalFrequency)) { __instance.SwitchFrequencyFilter(increment); } diff --git a/NewHorizons/Schemas/addon_manifest_schema.json b/NewHorizons/Schemas/addon_manifest_schema.json index 8d3c0da7..aada816a 100644 --- a/NewHorizons/Schemas/addon_manifest_schema.json +++ b/NewHorizons/Schemas/addon_manifest_schema.json @@ -23,6 +23,10 @@ "type": "string", "description": "A pop-up message for the first time a user runs the add-on" }, + "repeatPopup": { + "type": "boolean", + "description": "If popupMessage is set, should it repeat every time the game starts or only once" + }, "$schema": { "type": "string", "description": "The schema to validate with" diff --git a/NewHorizons/Schemas/body_schema.json b/NewHorizons/Schemas/body_schema.json index c63a8f12..3f72f361 100644 --- a/NewHorizons/Schemas/body_schema.json +++ b/NewHorizons/Schemas/body_schema.json @@ -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" } @@ -1323,7 +1323,7 @@ }, "pathToAnimController": { "type": "string", - "description": "If this dialogue is meant for a character, this is the relative path from the planet to that character's\nCharacterAnimController, TravelerController, TravelerEyeController (eye of the universe), FacePlayerWhenTalking, or SolanumAnimController.\n\nIf none of those components are present it will add a FacePlayerWhenTalking component." + "description": "If this dialogue is meant for a character, this is the relative path from the planet to that character's\nCharacterAnimController, TravelerController, TravelerEyeController (eye of the universe), FacePlayerWhenTalking, \nHearthianRecorderEffects or SolanumAnimController.\n\nIf it's a Recorder this will also delete the existing dialogue already attached to that prop.\n\nIf none of those components are present it will add a FacePlayerWhenTalking component." }, "radius": { "type": "number", @@ -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" } diff --git a/NewHorizons/manifest.json b/NewHorizons/manifest.json index bf0c1c3c..56abd496 100644 --- a/NewHorizons/manifest.json +++ b/NewHorizons/manifest.json @@ -4,7 +4,7 @@ "author": "xen, Bwc9876, clay, MegaPiggy, John, Trifid, Hawkbar, Book", "name": "New Horizons", "uniqueName": "xen.NewHorizons", - "version": "1.12.0", + "version": "1.12.1", "owmlVersion": "2.9.0", "dependencies": [ "JohnCorby.VanillaFix", "_nebula.MenuFramework", "xen.CommonCameraUtility", "dgarro.CustomShipLogModes" ], "conflicts": [ "Raicuparta.QuantumSpaceBuddies", "PacificEngine.OW_CommonResources" ],