diff --git a/NewHorizons/Builder/General/RigidBodyBuilder.cs b/NewHorizons/Builder/General/RigidBodyBuilder.cs index 9a0d5186..5661d430 100644 --- a/NewHorizons/Builder/General/RigidBodyBuilder.cs +++ b/NewHorizons/Builder/General/RigidBodyBuilder.cs @@ -1,15 +1,17 @@ +using NewHorizons.External; +using NewHorizons.External.Configs; using NewHorizons.Utility; +using NewHorizons.Utility.OWML; using UnityEngine; namespace NewHorizons.Builder.General { public static class RigidBodyBuilder { - public static OWRigidbody Make(GameObject body, float sphereOfInfluence) + public static OWRigidbody Make(GameObject body, float sphereOfInfluence, PlanetConfig config) { body.AddComponent()._bounds.radius = sphereOfInfluence; Rigidbody rigidBody = body.AddComponent(); - rigidBody.mass = 10000; rigidBody.drag = 0f; rigidBody.angularDrag = 0f; rigidBody.useGravity = false; @@ -17,18 +19,60 @@ namespace NewHorizons.Builder.General rigidBody.interpolation = RigidbodyInterpolation.None; rigidBody.collisionDetectionMode = CollisionDetectionMode.Discrete; - KinematicRigidbody kinematicRigidBody = body.AddComponent(); - OWRigidbody owRigidBody = body.AddComponent(); - owRigidBody._kinematicSimulation = true; owRigidBody._autoGenerateCenterOfMass = true; owRigidBody.SetIsTargetable(true); owRigidBody._maintainOriginalCenterOfMass = true; owRigidBody._rigidbody = rigidBody; - owRigidBody._kinematicRigidbody = kinematicRigidBody; owRigidBody._origParent = SearchUtilities.Find("SolarSystemRoot")?.transform; - owRigidBody.EnableKinematicSimulation(); + + KinematicRigidbody kinematicRigidBody = body.AddComponent(); + owRigidBody._kinematicRigidbody = kinematicRigidBody; + owRigidBody._kinematicSimulation = true; owRigidBody.MakeKinematic(); + owRigidBody.EnableKinematicSimulation(); + rigidBody.mass = 10000; + + if (config.Base.addPhysics) + { + // hack: make all mesh colliders convex + // triggers are already convex + // prints errors for non readable meshes but whatever + foreach (var meshCollider in body.GetComponentsInChildren(true)) + meshCollider.convex = true; + + var shape = body.AddComponent(); + shape._collisionMode = Shape.CollisionMode.Detector; + shape._layerMask = (int)(Shape.Layer.Default | Shape.Layer.Gravity); + shape._radius = config.Base.surfaceSize; + + var impactSensor = body.AddComponent(); + var audioSource = body.AddComponent(); + audioSource.maxDistance = 30; + audioSource.dopplerLevel = 0; + audioSource.rolloffMode = AudioRolloffMode.Custom; + audioSource.playOnAwake = false; + audioSource.spatialBlend = 1; + + var owAudioSource = body.AddComponent(); + owAudioSource._audioSource = audioSource; + owAudioSource._track = OWAudioMixer.TrackName.Environment; + + var objectImpactAudio = body.AddComponent(); + objectImpactAudio._minPitch = 0.4f; + objectImpactAudio._maxPitch = 0.6f; + objectImpactAudio._impactSensor = impactSensor; + + // For some reason when originally testing, not doing MakeKinematic caused the body to not move relative to the player character + // It seems that turning it on and then off makes it actually work properly + owRigidBody.MakeNonKinematic(); + owRigidBody.DisableKinematicSimulation(); + + // Should make this number changeable, if anybody ever asks + // For some reason, setting this on the exact same frame as it is created doesn't work. + // I imagine something strange is happening on Awake/Start, hence the delay + Delay.FireOnNextUpdate(() => owRigidBody.SetMass(0.001f)); + } return owRigidBody; } diff --git a/NewHorizons/Builder/Orbital/OrbitlineBuilder.cs b/NewHorizons/Builder/Orbital/OrbitlineBuilder.cs index 0ede52f2..fac2bfcf 100644 --- a/NewHorizons/Builder/Orbital/OrbitlineBuilder.cs +++ b/NewHorizons/Builder/Orbital/OrbitlineBuilder.cs @@ -17,7 +17,7 @@ namespace NewHorizons.Builder.Orbital if (_dottedLineMaterial == null || _lineMaterial == null) return null; - GameObject orbitGO = new GameObject("Orbit"); + var orbitGO = new GameObject("Orbit"); orbitGO.transform.parent = planetGO.transform; orbitGO.transform.localPosition = Vector3.zero; @@ -83,6 +83,16 @@ namespace NewHorizons.Builder.Orbital Delay.FireOnNextUpdate(orbitLine.InitializeLineRenderer); + // If the planet has physics and a regular orbit line, make sure that when it's bumped into the old orbit line vanishes + if (config.Base.addPhysics && !config.Orbit.trackingOrbitLine) + { + var impactSensor = planetGO.GetComponent(); + impactSensor.OnImpact += (ImpactData _) => + { + orbitGO.SetActive(false); + }; + } + return orbitLine; } } diff --git a/NewHorizons/Builder/Props/DetailBuilder.cs b/NewHorizons/Builder/Props/DetailBuilder.cs index 6c762931..622cdd82 100644 --- a/NewHorizons/Builder/Props/DetailBuilder.cs +++ b/NewHorizons/Builder/Props/DetailBuilder.cs @@ -218,9 +218,10 @@ namespace NewHorizons.Builder.Props if (detail.hasPhysics) { var addPhysics = prop.AddComponent(); - addPhysics.Sector = sector; + addPhysics.Sector = detail.keepLoaded ? null : sector; addPhysics.Mass = detail.physicsMass; addPhysics.Radius = detail.physicsRadius; + addPhysics.SuspendUntilImpact = detail.physicsSuspendUntilImpact; } if (!string.IsNullOrEmpty(detail.activationCondition)) @@ -259,6 +260,7 @@ namespace NewHorizons.Builder.Props // Not doing else if here because idk if any of the classes below implement ISectorGroup // Null check else shuttles controls break + // parent sector is always null before Awake so this code actually never runs lol if (component is Sector s && s.GetParentSector() != null && !existingSectors.Contains(s.GetParentSector())) { s.SetParentSector(sector); diff --git a/NewHorizons/Builder/Props/ShuttleBuilder.cs b/NewHorizons/Builder/Props/ShuttleBuilder.cs index 06d8dabb..f855990d 100644 --- a/NewHorizons/Builder/Props/ShuttleBuilder.cs +++ b/NewHorizons/Builder/Props/ShuttleBuilder.cs @@ -52,6 +52,7 @@ namespace NewHorizons.Builder.Props neutralSlot._attractive = true; neutralSlot._muteAudio = true; nhShuttleController._neutralSlot = neutralSlot; + // TODO: at some point delay rigidbody parenting so we dont have to find orb via references. mainly to fix orbs on existing details and rafts not rotating with planets _orbPrefab = shuttleController._orb.gameObject?.InstantiateInactive()?.Rename("Prefab_QM_Shuttle_InterfaceOrbSmall")?.DontDestroyOnLoad(); nhShuttleController._orb = _orbPrefab.GetComponent(); nhShuttleController._orb._sector = nhShuttleController._interiorSector; diff --git a/NewHorizons/Components/AddPhysics.cs b/NewHorizons/Components/AddPhysics.cs index 6f987255..c7671a50 100644 --- a/NewHorizons/Components/AddPhysics.cs +++ b/NewHorizons/Components/AddPhysics.cs @@ -18,9 +18,16 @@ public class AddPhysics : MonoBehaviour [Tooltip("The radius that the added sphere collider will use for physics collision.\n" + "If there's already good colliders on the detail, you can make this 0.")] public float Radius = 1f; + [Tooltip("If true, this detail will stay still until it touches something.\n" + + "Good for zero-g props.")] + public bool SuspendUntilImpact; + + private OWRigidbody _body; + private ImpactSensor _impactSensor; private IEnumerator Start() { + // detectors dont detect unless we wait for some reason yield return new WaitForSeconds(.1f); var parentBody = GetComponentInParent(); @@ -37,8 +44,8 @@ public class AddPhysics : MonoBehaviour bodyGo.transform.position = transform.position; bodyGo.transform.rotation = transform.rotation; - var owRigidbody = bodyGo.AddComponent(); - owRigidbody._simulateInSector = Sector; + _body = bodyGo.AddComponent(); + _body._simulateInSector = Sector; bodyGo.layer = Layer.PhysicalDetector; bodyGo.tag = "DynamicPropDetector"; @@ -53,7 +60,7 @@ public class AddPhysics : MonoBehaviour fluidDetector._buoyancy = Locator.GetProbe().GetOWRigidbody()._attachedFluidDetector._buoyancy; fluidDetector._splashEffects = Locator.GetProbe().GetOWRigidbody()._attachedFluidDetector._splashEffects; - var impactSensor = bodyGo.AddComponent(); + _impactSensor = bodyGo.AddComponent(); var audioSource = bodyGo.AddComponent(); audioSource.maxDistance = 30; audioSource.dopplerLevel = 0; @@ -66,24 +73,73 @@ public class AddPhysics : MonoBehaviour var objectImpactAudio = bodyGo.AddComponent(); objectImpactAudio._minPitch = 0.4f; objectImpactAudio._maxPitch = 0.6f; - objectImpactAudio._impactSensor = impactSensor; + objectImpactAudio._impactSensor = _impactSensor; bodyGo.SetActive(true); transform.parent = bodyGo.transform; - owRigidbody.SetMass(Mass); - owRigidbody.SetVelocity(parentBody.GetPointVelocity(transform.position)); + _body.SetMass(Mass); + _body.SetVelocity(parentBody.GetPointVelocity(_body.GetWorldCenterOfMass())); + _body.SetAngularVelocity(parentBody.GetAngularVelocity()); // #536 - Physics objects in bramble dimensions not disabled on load // sectors wait 3 frames and then call OnSectorOccupantsUpdated // however we wait .1 real seconds which is longer // so we have to manually call this - if (owRigidbody._simulateInSector != null) - owRigidbody.OnSectorOccupantsUpdated(); + if (_body._simulateInSector) _body.OnSectorOccupantsUpdated(); + if (SuspendUntilImpact) + { + // copied from OWRigidbody.Suspend + _body._suspensionBody = parentBody; + _body.MakeKinematic(); + _body._transform.parent = parentBody.transform; + _body._suspended = true; + _body._unsuspendNextUpdate = false; + + // match velocity doesnt work so just make it not targetable + _body.SetIsTargetable(false); + + _impactSensor.OnImpact += OnImpact; + Locator.GetProbe().OnAnchorProbe += OnAnchorProbe; + } + else + { + Destroy(this); + } + } + + private void OnDestroy() + { + if (_impactSensor) _impactSensor.OnImpact -= OnImpact; + Locator.GetProbe().OnAnchorProbe -= OnAnchorProbe; + } + + private void OnImpact(ImpactData impact) + { + _body.UnsuspendImmediate(false); + _body.SetIsTargetable(true); Destroy(this); } + private void OnAnchorProbe() + { + var attachedOWRigidbody = Locator.GetProbe().GetAttachedOWRigidbody(true); + if (attachedOWRigidbody == _body) + { + OnImpact(null); + + // copied from ProbeAnchor.AnchorToObject + var _probeBody = Locator.GetProbe().GetOWRigidbody(); + var hitPoint = _probeBody.GetWorldCenterOfMass(); + if (attachedOWRigidbody.GetMass() < 100f) + { + Vector3 vector = _probeBody.GetVelocity() - attachedOWRigidbody.GetPointVelocity(_probeBody.GetPosition()); + attachedOWRigidbody.GetRigidbody().AddForceAtPosition(vector.normalized * 0.005f, hitPoint, ForceMode.Impulse); + } + } + } + private void OnDrawGizmosSelected() { Gizmos.DrawWireSphere(transform.position, Radius); diff --git a/NewHorizons/Components/Stars/SunLightEffectsController.cs b/NewHorizons/Components/Stars/SunLightEffectsController.cs index 8c3798bf..6d26808e 100644 --- a/NewHorizons/Components/Stars/SunLightEffectsController.cs +++ b/NewHorizons/Components/Stars/SunLightEffectsController.cs @@ -195,6 +195,8 @@ namespace NewHorizons.Components.Stars // Some effects use Locator.GetSunTransform so hopefully its fine to change it Locator._sunTransform = transform; + + // TODO?: maybe also turn off star controller stuff (mainly proxy light) since idk if that can handle more than 1 being on } } } diff --git a/NewHorizons/External/Modules/BaseModule.cs b/NewHorizons/External/Modules/BaseModule.cs index cfab241e..03dbb51a 100644 --- a/NewHorizons/External/Modules/BaseModule.cs +++ b/NewHorizons/External/Modules/BaseModule.cs @@ -71,6 +71,14 @@ namespace NewHorizons.External.Modules /// [DefaultValue(0)] public int gravityVolumePriority = 0; + /// + /// Apply physics to this planet when you bump into it. Will have a spherical collider the size of surfaceSize. + /// For custom colliders they have to all be convex and you can leave surface size as 0. + /// This is meant for stuff like satellites which are relatively simple and can be de-orbited. + /// If you are using an orbit line but a tracking line, it will be removed when the planet is bumped in to. + /// + public bool addPhysics; + #region Obsolete [Obsolete("IsSatellite is deprecated, please use ShowMinimap instead")] diff --git a/NewHorizons/External/Modules/Props/DetailInfo.cs b/NewHorizons/External/Modules/Props/DetailInfo.cs index a6cb6592..48b3b125 100644 --- a/NewHorizons/External/Modules/Props/DetailInfo.cs +++ b/NewHorizons/External/Modules/Props/DetailInfo.cs @@ -75,6 +75,12 @@ namespace NewHorizons.External.Modules.Props /// [DefaultValue(1f)] public float physicsRadius = 1f; + /// + /// If true, this detail will stay still until it touches something. + /// Good for zero-g props. + /// + [DefaultValue(false)] public bool physicsSuspendUntilImpact = false; + /// /// Set to true if this object's lighting should ignore the effects of sunlight /// diff --git a/NewHorizons/Handlers/PlanetCreationHandler.cs b/NewHorizons/Handlers/PlanetCreationHandler.cs index ea235665..2b014cbf 100644 --- a/NewHorizons/Handlers/PlanetCreationHandler.cs +++ b/NewHorizons/Handlers/PlanetCreationHandler.cs @@ -348,7 +348,7 @@ namespace NewHorizons.Handlers const float sphereOfInfluence = 2000f; - var owRigidBody = RigidBodyBuilder.Make(go, sphereOfInfluence); + var owRigidBody = RigidBodyBuilder.Make(go, sphereOfInfluence, body.Config); var ao = AstroObjectBuilder.Make(go, null, body.Config, false); var sector = SectorBuilder.Make(go, owRigidBody, sphereOfInfluence); @@ -423,7 +423,7 @@ namespace NewHorizons.Handlers var sphereOfInfluence = GetSphereOfInfluence(body); - var owRigidBody = RigidBodyBuilder.Make(go, sphereOfInfluence); + var owRigidBody = RigidBodyBuilder.Make(go, sphereOfInfluence, body.Config); var ao = AstroObjectBuilder.Make(go, primaryBody, body.Config, false); var sector = SectorBuilder.Make(go, owRigidBody, sphereOfInfluence * 2f); diff --git a/NewHorizons/Main.cs b/NewHorizons/Main.cs index f2d5c7e7..f2aa10b9 100644 --- a/NewHorizons/Main.cs +++ b/NewHorizons/Main.cs @@ -3,8 +3,10 @@ using NewHorizons.Builder.Atmosphere; using NewHorizons.Builder.Body; using NewHorizons.Builder.General; using NewHorizons.Builder.Props; +using NewHorizons.Builder.Props.Audio; using NewHorizons.Builder.Props.TranslatorText; using NewHorizons.Components.Fixers; +using NewHorizons.Components.Ship; using NewHorizons.Components.SizeControllers; using NewHorizons.External; using NewHorizons.External.Configs; @@ -14,9 +16,11 @@ using NewHorizons.OtherMods.MenuFramework; using NewHorizons.OtherMods.OWRichPresence; using NewHorizons.OtherMods.VoiceActing; using NewHorizons.Utility; +using NewHorizons.Utility.DebugTools; +using NewHorizons.Utility.DebugTools.Menu; using NewHorizons.Utility.Files; -using NewHorizons.Utility.OWML; using NewHorizons.Utility.OuterWilds; +using NewHorizons.Utility.OWML; using OWML.Common; using OWML.ModHelper; using OWML.Utils; @@ -29,12 +33,6 @@ using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; -using NewHorizons.Utility.DebugTools; -using NewHorizons.Utility.DebugTools.Menu; -using NewHorizons.Components.Ship; -using NewHorizons.Builder.Props.Audio; -using Epic.OnlineServices; - namespace NewHorizons { @@ -116,12 +114,12 @@ namespace NewHorizons else if (Debug) NHLogger.UpdateLogLevel(NHLogger.LogType.Log); else NHLogger.UpdateLogLevel(NHLogger.LogType.Error); + var oldDefaultSystemOverride = _defaultSystemOverride; _defaultSystemOverride = config.GetSettingsValue("Default System Override"); - - // Else it doesn't get set idk - if (currentScene == "TitleScreen" && SystemDict.ContainsKey(_defaultSystemOverride)) + if (oldDefaultSystemOverride != _defaultSystemOverride) { - _currentStarSystem = _defaultSystemOverride; + ResetCurrentStarSystem(); + NHLogger.Log($"Changed default star system override to {_defaultSystemOverride}"); } var wasUsingCustomTitleScreen = _useCustomTitleScreen; @@ -553,17 +551,7 @@ namespace NewHorizons } else { - // Reset back to original solar system after going to main menu. - // If the override is a valid system then we go there - if (SystemDict.ContainsKey(_defaultSystemOverride)) - { - _currentStarSystem = _defaultSystemOverride; - IsWarpingFromShip = true; // always do this else sometimes the spawn gets messed up - } - else - { - _currentStarSystem = _defaultStarSystem; - } + ResetCurrentStarSystem(); } } @@ -614,7 +602,7 @@ namespace NewHorizons if (starSystemName != "SolarSystem") { SetDefaultSystem(starSystemName); - _currentStarSystem = starSystemName; + _currentStarSystem = DefaultStarSystem; } } @@ -634,6 +622,8 @@ namespace NewHorizons { try { + if (mod.ModHelper.Manifest.Filename.Contains("Extinction")) return; + if (_firstLoad) { MountedAddons.Add(mod); @@ -903,15 +893,23 @@ namespace NewHorizons { if (SystemDict[_currentStarSystem].Config.respawnHere) return; - // If the override is a valid system then we go there - if (SystemDict.ContainsKey(_defaultSystemOverride)) - { - _currentStarSystem = _defaultSystemOverride; - } - else - { - _currentStarSystem = _defaultStarSystem; - } + ResetCurrentStarSystem(); + } + } + + private void ResetCurrentStarSystem() + { + if (SystemDict.ContainsKey(_defaultSystemOverride)) + { + _currentStarSystem = _defaultSystemOverride; + + // Sometimes the override will not support spawning regularly, so always warp in + IsWarpingFromShip = true; + } + else + { + _currentStarSystem = _defaultStarSystem; + IsWarpingFromShip = false; } } #endregion Change star system diff --git a/NewHorizons/Schemas/body_schema.json b/NewHorizons/Schemas/body_schema.json index 62a2069c..843e9478 100644 --- a/NewHorizons/Schemas/body_schema.json +++ b/NewHorizons/Schemas/body_schema.json @@ -573,6 +573,10 @@ "description": "Optional. You can force this planet's gravity to be felt over other gravity/zero-gravity sources by increasing this number.", "format": "int32", "default": 0 + }, + "addPhysics": { + "type": "boolean", + "description": "Apply physics to this planet when you bump into it. Will have a spherical collider the size of surfaceSize. \nFor custom colliders they have to all be convex and you can leave surface size as 0.\nThis is meant for stuff like satellites which are relatively simple and can be de-orbited.\nIf you are using an orbit line but a tracking line, it will be removed when the planet is bumped in to." } } }, @@ -1339,6 +1343,11 @@ "format": "float", "default": 1.0 }, + "physicsSuspendUntilImpact": { + "type": "boolean", + "description": "If true, this detail will stay still until it touches something.\nGood for zero-g props.", + "default": false + }, "ignoreSun": { "type": "boolean", "description": "Set to true if this object's lighting should ignore the effects of sunlight" diff --git a/NewHorizons/manifest.json b/NewHorizons/manifest.json index 56cf858b..2fb8ac31 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.14.0", + "version": "1.14.1", "owmlVersion": "2.9.3", "dependencies": [ "JohnCorby.VanillaFix", "_nebula.MenuFramework", "xen.CommonCameraUtility", "dgarro.CustomShipLogModes" ], "conflicts": [ "Raicuparta.QuantumSpaceBuddies", "PacificEngine.OW_CommonResources" ],