mirror of
https://github.com/Outer-Wilds-New-Horizons/new-horizons.git
synced 2025-12-11 20:15:44 +01:00
Take some rigidbody patches from QSB (#758)
## Bug fixes - Fixes orbs on copied details and rafts not being rotated with planets
This commit is contained in:
commit
e067810780
@ -1,5 +1,4 @@
|
|||||||
using NewHorizons.Builder.Props.TranslatorText;
|
using NewHorizons.Builder.Props.TranslatorText;
|
||||||
using NewHorizons.Components.Orbital;
|
|
||||||
using NewHorizons.External.Modules;
|
using NewHorizons.External.Modules;
|
||||||
using NewHorizons.External.Modules.Props;
|
using NewHorizons.External.Modules.Props;
|
||||||
using NewHorizons.External.Modules.Props.Shuttle;
|
using NewHorizons.External.Modules.Props.Shuttle;
|
||||||
@ -18,7 +17,6 @@ namespace NewHorizons.Builder.Props
|
|||||||
{
|
{
|
||||||
private static GameObject _interfacePrefab;
|
private static GameObject _interfacePrefab;
|
||||||
private static GameObject _detailedPlatformPrefab, _platformPrefab;
|
private static GameObject _detailedPlatformPrefab, _platformPrefab;
|
||||||
private static GameObject _orbPrefab;
|
|
||||||
|
|
||||||
internal static void InitPrefab()
|
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_Crystals"));
|
||||||
GameObject.DestroyImmediate(_platformPrefab.FindChild("Structure_NOM_GravityCannon_Geo"));
|
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)
|
public static GameObject Make(GameObject planetGO, Sector sector, GravityCannonInfo info, IModBehaviour mod)
|
||||||
{
|
{
|
||||||
InitPrefab();
|
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 detailInfo = new DetailInfo(info.controls) { keepLoaded = true };
|
||||||
var gravityCannonObject = DetailBuilder.Make(planetGO, sector, _interfacePrefab, detailInfo);
|
var gravityCannonObject = DetailBuilder.Make(planetGO, sector, _interfacePrefab, detailInfo);
|
||||||
@ -102,56 +92,11 @@ namespace NewHorizons.Builder.Props
|
|||||||
gravityCannonController._nomaiComputer = null;
|
gravityCannonController._nomaiComputer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateOrb(planetGO, gravityCannonController);
|
|
||||||
|
|
||||||
gravityCannonObject.SetActive(true);
|
gravityCannonObject.SetActive(true);
|
||||||
|
|
||||||
return gravityCannonObject;
|
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<OWRigidbody>();
|
|
||||||
var orbBody = orb.GetComponent<OWRigidbody>();
|
|
||||||
|
|
||||||
var nomaiInterfaceOrb = orb.GetComponent<NomaiInterfaceOrb>();
|
|
||||||
nomaiInterfaceOrb._orbBody = orbBody;
|
|
||||||
nomaiInterfaceOrb._slotRoot = gravityCannonController.gameObject;
|
|
||||||
orbBody._origParent = planetGO.transform;
|
|
||||||
orbBody._origParentBody = planetBody;
|
|
||||||
nomaiInterfaceOrb._slots = nomaiInterfaceOrb._slotRoot.GetComponentsInChildren<NomaiInterfaceSlot>();
|
|
||||||
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<ConstantForceDetector>()._detectableFields = gravityVolume ? new ForceVolume[] { gravityVolume } : new ForceVolume[0];
|
|
||||||
|
|
||||||
Delay.RunWhenAndInNUpdates(() =>
|
|
||||||
{
|
|
||||||
foreach (var component in orb.GetComponents<MonoBehaviour>())
|
|
||||||
{
|
|
||||||
component.enabled = true;
|
|
||||||
}
|
|
||||||
nomaiInterfaceOrb.RemoveAllLocks();
|
|
||||||
}, () => Main.IsSystemReady, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static NomaiComputer CreateComputer(GameObject planetGO, Sector sector, GeneralPropInfo computerInfo, NomaiShuttleController.ShuttleID id)
|
private static NomaiComputer CreateComputer(GameObject planetGO, Sector sector, GeneralPropInfo computerInfo, NomaiShuttleController.ShuttleID id)
|
||||||
{
|
{
|
||||||
// Load the position info from the GeneralPropInfo
|
// Load the position info from the GeneralPropInfo
|
||||||
|
|||||||
@ -11,7 +11,6 @@ namespace NewHorizons.Builder.Props
|
|||||||
public static class ShuttleBuilder
|
public static class ShuttleBuilder
|
||||||
{
|
{
|
||||||
private static GameObject _prefab;
|
private static GameObject _prefab;
|
||||||
private static GameObject _orbPrefab;
|
|
||||||
private static GameObject _bodyPrefab;
|
private static GameObject _bodyPrefab;
|
||||||
|
|
||||||
public static Dictionary<NomaiShuttleController.ShuttleID, NomaiShuttleController> Shuttles { get; } = new();
|
public static Dictionary<NomaiShuttleController.ShuttleID, NomaiShuttleController> Shuttles { get; } = new();
|
||||||
@ -52,9 +51,9 @@ namespace NewHorizons.Builder.Props
|
|||||||
neutralSlot._attractive = true;
|
neutralSlot._attractive = true;
|
||||||
neutralSlot._muteAudio = true;
|
neutralSlot._muteAudio = true;
|
||||||
nhShuttleController._neutralSlot = neutralSlot;
|
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();
|
var orb = shuttleController._orb.gameObject;
|
||||||
nhShuttleController._orb = _orbPrefab.GetComponent<NomaiInterfaceOrb>();
|
nhShuttleController._orb = orb.GetComponent<NomaiInterfaceOrb>();
|
||||||
nhShuttleController._orb._sector = nhShuttleController._interiorSector;
|
nhShuttleController._orb._sector = nhShuttleController._interiorSector;
|
||||||
nhShuttleController._orb._slotRoot = slots;
|
nhShuttleController._orb._slotRoot = slots;
|
||||||
nhShuttleController._orb._safetyRails = slots.GetComponentsInChildren<OWRail>();
|
nhShuttleController._orb._safetyRails = slots.GetComponentsInChildren<OWRail>();
|
||||||
@ -87,7 +86,7 @@ namespace NewHorizons.Builder.Props
|
|||||||
shuttleController._cannon = Locator.GetGravityCannon(id);
|
shuttleController._cannon = Locator.GetGravityCannon(id);
|
||||||
|
|
||||||
GameObject slots = shuttleObject.FindChild("Sector_NomaiShuttleInterior/Interactibles_NomaiShuttleInterior/ControlPanel/Slots");
|
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.SetParent(slots.transform, false);
|
||||||
orbObject.transform.localPosition = new Vector3(-0.0153f, -0.2386f, 0.0205f);
|
orbObject.transform.localPosition = new Vector3(-0.0153f, -0.2386f, 0.0205f);
|
||||||
shuttleController._orb = orbObject.GetComponent<NomaiInterfaceOrb>();
|
shuttleController._orb = orbObject.GetComponent<NomaiInterfaceOrb>();
|
||||||
|
|||||||
193
NewHorizons/Patches/RigidbodyPatches.cs
Normal file
193
NewHorizons/Patches/RigidbodyPatches.cs
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using NewHorizons.Utility;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NewHorizons.Patches;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// From QSB
|
||||||
|
///
|
||||||
|
/// By delaying rigidbody stuff here we make copying objects with orbs work properly
|
||||||
|
/// Should also improve rafts
|
||||||
|
/// </summary>
|
||||||
|
[HarmonyPatch(typeof(OWRigidbody))]
|
||||||
|
public static class OWRigidbodyPatches
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<OWRigidbody, Transform> _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<CenterOfTheUniverseOffsetApplier>();
|
||||||
|
__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<Rigidbody>();
|
||||||
|
__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<Collider>();
|
||||||
|
foreach (var childCollider in __instance._childColliders)
|
||||||
|
{
|
||||||
|
childCollider.gameObject.GetAddComponent<OWCollider>().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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -305,5 +305,39 @@ namespace NewHorizons.Utility
|
|||||||
}
|
}
|
||||||
return curve;
|
return curve;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From QSB
|
||||||
|
public static void RaiseEvent<T>(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}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"author": "xen, Bwc9876, clay, MegaPiggy, John, Trifid, Hawkbar, Book",
|
"author": "xen, Bwc9876, clay, MegaPiggy, John, Trifid, Hawkbar, Book",
|
||||||
"name": "New Horizons",
|
"name": "New Horizons",
|
||||||
"uniqueName": "xen.NewHorizons",
|
"uniqueName": "xen.NewHorizons",
|
||||||
"version": "1.17.3",
|
"version": "1.17.4",
|
||||||
"owmlVersion": "2.9.8",
|
"owmlVersion": "2.9.8",
|
||||||
"dependencies": [ "JohnCorby.VanillaFix", "_nebula.MenuFramework", "xen.CommonCameraUtility", "dgarro.CustomShipLogModes" ],
|
"dependencies": [ "JohnCorby.VanillaFix", "_nebula.MenuFramework", "xen.CommonCameraUtility", "dgarro.CustomShipLogModes" ],
|
||||||
"conflicts": [ "Raicuparta.QuantumSpaceBuddies", "PacificEngine.OW_CommonResources" ],
|
"conflicts": [ "Raicuparta.QuantumSpaceBuddies", "PacificEngine.OW_CommonResources" ],
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user