diff --git a/NewHorizons/Builder/Props/GravityCannonBuilder.cs b/NewHorizons/Builder/Props/GravityCannonBuilder.cs index 44b1f075..65953652 100644 --- a/NewHorizons/Builder/Props/GravityCannonBuilder.cs +++ b/NewHorizons/Builder/Props/GravityCannonBuilder.cs @@ -1,5 +1,4 @@ using NewHorizons.Builder.Props.TranslatorText; -using NewHorizons.Components.Orbital; using NewHorizons.External.Modules; using NewHorizons.External.Modules.Props; using NewHorizons.External.Modules.Props.Shuttle; @@ -18,7 +17,6 @@ namespace NewHorizons.Builder.Props { private static GameObject _interfacePrefab; private static GameObject _detailedPlatformPrefab, _platformPrefab; - private static GameObject _orbPrefab; internal static void InitPrefab() { @@ -59,21 +57,13 @@ namespace NewHorizons.Builder.Props GameObject.DestroyImmediate(_platformPrefab.FindChild("Structure_NOM_GravityCannon_Crystals")); GameObject.DestroyImmediate(_platformPrefab.FindChild("Structure_NOM_GravityCannon_Geo")); } - - if (_orbPrefab == null) - { - _orbPrefab = SearchUtilities.Find("Prefab_NOM_InterfaceOrb") - .InstantiateInactive() - .Rename("Prefab_NOM_InterfaceOrb") - .DontDestroyOnLoad(); - } } public static GameObject Make(GameObject planetGO, Sector sector, GravityCannonInfo info, IModBehaviour mod) { InitPrefab(); - if (_interfacePrefab == null || planetGO == null || sector == null || _detailedPlatformPrefab == null || _platformPrefab == null || _orbPrefab == null) return null; + if (_interfacePrefab == null || planetGO == null || sector == null || _detailedPlatformPrefab == null || _platformPrefab == null) return null; var detailInfo = new DetailInfo(info.controls) { keepLoaded = true }; var gravityCannonObject = DetailBuilder.Make(planetGO, sector, _interfacePrefab, detailInfo); @@ -102,56 +92,11 @@ namespace NewHorizons.Builder.Props gravityCannonController._nomaiComputer = null; } - CreateOrb(planetGO, gravityCannonController); - gravityCannonObject.SetActive(true); return gravityCannonObject; } - private static void CreateOrb(GameObject planetGO, GravityCannonController gravityCannonController) - { - var orb = _orbPrefab.InstantiateInactive().Rename(_orbPrefab.name); - orb.transform.parent = gravityCannonController.transform; - orb.transform.localPosition = new Vector3(0f, 0.9673f, 0f); - orb.transform.localScale = Vector3.one; - orb.SetActive(true); - - var planetBody = planetGO.GetComponent(); - var orbBody = orb.GetComponent(); - - var nomaiInterfaceOrb = orb.GetComponent(); - nomaiInterfaceOrb._orbBody = orbBody; - nomaiInterfaceOrb._slotRoot = gravityCannonController.gameObject; - orbBody._origParent = planetGO.transform; - orbBody._origParentBody = planetBody; - nomaiInterfaceOrb._slots = nomaiInterfaceOrb._slotRoot.GetComponentsInChildren(); - nomaiInterfaceOrb.SetParentBody(planetBody); - nomaiInterfaceOrb._safetyRails = new OWRail[0]; - nomaiInterfaceOrb.RemoveAllLocks(); - - var spawnVelocity = planetBody.GetVelocity(); - var spawnAngularVelocity = planetBody.GetPointTangentialVelocity(orbBody.transform.position); - var velocity = spawnVelocity + spawnAngularVelocity; - - orbBody._lastVelocity = velocity; - orbBody._currentVelocity = velocity; - - // detect planet gravity - // somehow Intervention has GetAttachedOWRigidbody as null sometimes, idk why - var gravityVolume = planetGO.GetAttachedOWRigidbody()?.GetAttachedGravityVolume(); - orb.GetComponent()._detectableFields = gravityVolume ? new ForceVolume[] { gravityVolume } : new ForceVolume[0]; - - Delay.RunWhenAndInNUpdates(() => - { - foreach (var component in orb.GetComponents()) - { - component.enabled = true; - } - nomaiInterfaceOrb.RemoveAllLocks(); - }, () => Main.IsSystemReady, 10); - } - private static NomaiComputer CreateComputer(GameObject planetGO, Sector sector, GeneralPropInfo computerInfo, NomaiShuttleController.ShuttleID id) { // Load the position info from the GeneralPropInfo diff --git a/NewHorizons/Builder/Props/ShuttleBuilder.cs b/NewHorizons/Builder/Props/ShuttleBuilder.cs index f855990d..2bf556db 100644 --- a/NewHorizons/Builder/Props/ShuttleBuilder.cs +++ b/NewHorizons/Builder/Props/ShuttleBuilder.cs @@ -11,7 +11,6 @@ namespace NewHorizons.Builder.Props public static class ShuttleBuilder { private static GameObject _prefab; - private static GameObject _orbPrefab; private static GameObject _bodyPrefab; public static Dictionary Shuttles { get; } = new(); @@ -52,9 +51,9 @@ 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(); + + var orb = shuttleController._orb.gameObject; + nhShuttleController._orb = orb.GetComponent(); nhShuttleController._orb._sector = nhShuttleController._interiorSector; nhShuttleController._orb._slotRoot = slots; nhShuttleController._orb._safetyRails = slots.GetComponentsInChildren(); @@ -87,7 +86,7 @@ namespace NewHorizons.Builder.Props shuttleController._cannon = Locator.GetGravityCannon(id); GameObject slots = shuttleObject.FindChild("Sector_NomaiShuttleInterior/Interactibles_NomaiShuttleInterior/ControlPanel/Slots"); - GameObject orbObject = _orbPrefab.InstantiateInactive().Rename("InterfaceOrbSmall"); + GameObject orbObject = shuttleController._orb.gameObject; orbObject.transform.SetParent(slots.transform, false); orbObject.transform.localPosition = new Vector3(-0.0153f, -0.2386f, 0.0205f); shuttleController._orb = orbObject.GetComponent(); diff --git a/NewHorizons/Patches/RigidbodyPatches.cs b/NewHorizons/Patches/RigidbodyPatches.cs new file mode 100644 index 00000000..c0e8d3e3 --- /dev/null +++ b/NewHorizons/Patches/RigidbodyPatches.cs @@ -0,0 +1,193 @@ +using HarmonyLib; +using NewHorizons.Utility; +using System.Collections.Generic; +using UnityEngine; + +namespace NewHorizons.Patches; + +/// +/// From QSB +/// +/// By delaying rigidbody stuff here we make copying objects with orbs work properly +/// Should also improve rafts +/// +[HarmonyPatch(typeof(OWRigidbody))] +public static class OWRigidbodyPatches +{ + private static readonly Dictionary _setParentQueue = new(); + + [HarmonyPrefix] + [HarmonyPatch(nameof(OWRigidbody.Awake))] + private static bool Awake(OWRigidbody __instance) + { + __instance._transform = __instance.transform; + + if (!__instance._scaleRoot) + { + __instance._scaleRoot = __instance._transform; + } + + CenterOfTheUniverse.TrackRigidbody(__instance); + __instance._offsetApplier = __instance.gameObject.GetAddComponent(); + __instance._offsetApplier.Init(__instance); + if (__instance._simulateInSector) + { + __instance._simulateInSector.OnSectorOccupantsUpdated += __instance.OnSectorOccupantsUpdated; + } + + __instance._origParent = __instance._transform.parent; + __instance._origParentBody = __instance._origParent ? __instance._origParent.GetAttachedOWRigidbody() : null; + if (__instance._transform.parent) + { + _setParentQueue[__instance] = null; + } + + __instance._rigidbody = __instance.GetRequiredComponent(); + __instance._rigidbody.interpolation = RigidbodyInterpolation.None; + if (!__instance._autoGenerateCenterOfMass) + { + __instance._rigidbody.centerOfMass = __instance._centerOfMass; + } + + if (__instance.IsSimulatedKinematic()) + { + __instance.EnableKinematicSimulation(); + } + + __instance._origCenterOfMass = __instance.RunningKinematicSimulation() ? __instance._kinematicRigidbody.centerOfMass : __instance._rigidbody.centerOfMass; + __instance._referenceFrame = new ReferenceFrame(__instance); + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(nameof(OWRigidbody.Start))] + private static void Start(OWRigidbody __instance) + { + if (_setParentQueue.TryGetValue(__instance, out var parent)) + { + __instance._transform.parent = parent; + _setParentQueue.Remove(__instance); + } + } + + [HarmonyPrefix] + [HarmonyPatch(nameof(OWRigidbody.OnDestroy))] + private static void OnDestroy(OWRigidbody __instance) + { + _setParentQueue.Remove(__instance); + } + + [HarmonyPrefix] + [HarmonyPatch(nameof(OWRigidbody.Suspend), typeof(Transform), typeof(OWRigidbody))] + private static bool Suspend(OWRigidbody __instance, Transform suspensionParent, OWRigidbody suspensionBody) + { + if (!__instance._suspended || __instance._unsuspendNextUpdate) + { + __instance._suspensionBody = suspensionBody; + var direction = __instance.GetVelocity() - suspensionBody.GetPointVelocity(__instance._transform.position); + __instance._cachedRelativeVelocity = suspensionBody.transform.InverseTransformDirection(direction); + __instance._cachedAngularVelocity = __instance.RunningKinematicSimulation() ? __instance._kinematicRigidbody.angularVelocity : __instance._rigidbody.angularVelocity; + __instance.enabled = false; + __instance._offsetApplier.enabled = false; + if (__instance.RunningKinematicSimulation()) + { + __instance._kinematicRigidbody.enabled = false; + } + else + { + __instance.MakeKinematic(); + } + + if (_setParentQueue.ContainsKey(__instance)) + { + _setParentQueue[__instance] = suspensionParent; + } + else + { + __instance._transform.parent = suspensionParent; + } + + __instance._suspended = true; + __instance._unsuspendNextUpdate = false; + if (!Physics.autoSyncTransforms) + { + Physics.SyncTransforms(); + } + + if (__instance._childColliders == null) + { + __instance._childColliders = __instance.GetComponentsInChildren(); + foreach (var childCollider in __instance._childColliders) + { + childCollider.gameObject.GetAddComponent().ListenForParentBodySuspension(); + } + } + + __instance.RaiseEvent(nameof(__instance.OnSuspendOWRigidbody), __instance); + } + + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(nameof(OWRigidbody.ChangeSuspensionBody))] + private static bool ChangeSuspensionBody(OWRigidbody __instance, OWRigidbody newSuspensionBody) + { + if (__instance._suspended) + { + __instance._cachedRelativeVelocity = Vector3.zero; + __instance._suspensionBody = newSuspensionBody; + if (_setParentQueue.ContainsKey(__instance)) + { + _setParentQueue[__instance] = newSuspensionBody.transform; + } + else + { + __instance._transform.parent = newSuspensionBody.transform; + } + } + + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(nameof(OWRigidbody.UnsuspendImmediate))] + private static bool UnsuspendImmediate(OWRigidbody __instance, bool restoreCachedVelocity) + { + if (__instance._suspended) + { + if (__instance.RunningKinematicSimulation()) + { + __instance._kinematicRigidbody.enabled = true; + } + else + { + __instance.MakeNonKinematic(); + } + + __instance.enabled = true; + if (_setParentQueue.ContainsKey(__instance)) + { + _setParentQueue[__instance] = null; + } + else + { + __instance._transform.parent = null; + } + + if (!Physics.autoSyncTransforms) + { + Physics.SyncTransforms(); + } + + var cachedVelocity = restoreCachedVelocity ? __instance._suspensionBody.transform.TransformDirection(__instance._cachedRelativeVelocity) : Vector3.zero; + __instance.SetVelocity(__instance._suspensionBody.GetPointVelocity(__instance._transform.position) + cachedVelocity); + __instance.SetAngularVelocity(restoreCachedVelocity ? __instance._cachedAngularVelocity : Vector3.zero); + __instance._suspended = false; + __instance._suspensionBody = null; + __instance.RaiseEvent(nameof(__instance.OnUnsuspendOWRigidbody), __instance); + } + + return false; + } +} diff --git a/NewHorizons/Utility/NewHorizonExtensions.cs b/NewHorizons/Utility/NewHorizonExtensions.cs index b292b06b..dd907c45 100644 --- a/NewHorizons/Utility/NewHorizonExtensions.cs +++ b/NewHorizons/Utility/NewHorizonExtensions.cs @@ -305,5 +305,39 @@ namespace NewHorizons.Utility } return curve; } + + // From QSB + public static void RaiseEvent(this T instance, string eventName, params object[] args) + { + const BindingFlags flags = BindingFlags.Instance + | BindingFlags.Static + | BindingFlags.Public + | BindingFlags.NonPublic + | BindingFlags.DeclaredOnly; + if (typeof(T) + .GetField(eventName, flags)? + .GetValue(instance) is not MulticastDelegate multiDelegate) + { + return; + } + + multiDelegate.SafeInvoke(args); + } + + // From QSB + public static void SafeInvoke(this MulticastDelegate multicast, params object[] args) + { + foreach (var del in multicast.GetInvocationList()) + { + try + { + del.DynamicInvoke(args); + } + catch (TargetInvocationException ex) + { + NHLogger.LogError($"Error invoking delegate! {ex.InnerException}"); + } + } + } } } diff --git a/NewHorizons/manifest.json b/NewHorizons/manifest.json index 52c18523..847b5dde 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.17.3", + "version": "1.17.4", "owmlVersion": "2.9.8", "dependencies": [ "JohnCorby.VanillaFix", "_nebula.MenuFramework", "xen.CommonCameraUtility", "dgarro.CustomShipLogModes" ], "conflicts": [ "Raicuparta.QuantumSpaceBuddies", "PacificEngine.OW_CommonResources" ],