From 74a683def02065a608f0daa28cea547e808ad727 Mon Sep 17 00:00:00 2001 From: Nick Date: Thu, 5 May 2022 18:43:04 -0400 Subject: [PATCH] Rafts + patching with HarmonyLib --- NewHorizons/Builder/Body/WaterBuilder.cs | 2 +- .../Builder/Props/PlanetaryRaftController.cs | 124 ------------------ NewHorizons/Builder/Props/PropBuildManager.cs | 7 +- NewHorizons/Builder/Props/RaftBuilder.cs | 116 +++++++--------- NewHorizons/Components/NHFluidVolume.cs | 19 +++ NewHorizons/Components/NHPlanetaryRaftFix.cs | 41 ++++++ NewHorizons/Handlers/PlanetCreationHandler.cs | 2 +- NewHorizons/Main.cs | 5 + NewHorizons/NewHorizons.csproj | 1 + NewHorizons/Patches/RaftPatches.cs | 116 ++++++++++++++++ NewHorizons/Tools/Patches.cs | 2 +- 11 files changed, 235 insertions(+), 200 deletions(-) delete mode 100644 NewHorizons/Builder/Props/PlanetaryRaftController.cs create mode 100644 NewHorizons/Components/NHFluidVolume.cs create mode 100644 NewHorizons/Components/NHPlanetaryRaftFix.cs create mode 100644 NewHorizons/Patches/RaftPatches.cs diff --git a/NewHorizons/Builder/Body/WaterBuilder.cs b/NewHorizons/Builder/Body/WaterBuilder.cs index 0e8a94d0..f77306c8 100644 --- a/NewHorizons/Builder/Body/WaterBuilder.cs +++ b/NewHorizons/Builder/Body/WaterBuilder.cs @@ -70,7 +70,7 @@ namespace NewHorizons.Builder.Body var buoyancyTriggerVolume = buoyancyObject.AddComponent(); buoyancyTriggerVolume._owCollider = owCollider; - var fluidVolume = buoyancyObject.AddComponent(); + var fluidVolume = buoyancyObject.AddComponent(); fluidVolume._fluidType = FluidVolume.Type.WATER; fluidVolume._attachedBody = rb; fluidVolume._triggerVolume = buoyancyTriggerVolume; diff --git a/NewHorizons/Builder/Props/PlanetaryRaftController.cs b/NewHorizons/Builder/Props/PlanetaryRaftController.cs deleted file mode 100644 index 0da56284..00000000 --- a/NewHorizons/Builder/Props/PlanetaryRaftController.cs +++ /dev/null @@ -1,124 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using UnityEngine; -using Logger = NewHorizons.Utility.Logger; - -namespace NewHorizons.Builder.Props -{ - public class PlanetaryRaftController : MonoBehaviour - { - private LightSensor[] _lightSensors; - private float _acceleration = 5f; - private Vector3 _localAcceleration = Vector3.zero; - private OWRigidbody _raftBody; - private Sector _sector; - private GameObject parentBody; - //private GravityVolume gravityVolume; - - public float BuoyancyModifier = 5f; - - private Vector3 initialPosition; - private float targetRadius; - - private void Awake() - { - this._raftBody = base.GetComponent(); - _lightSensors = GetComponentsInChildren(); - - //gravity = (GetComponentInChildren()._activeVolumes[0] as GravityVolume); - //gravityVolume = _sector.transform.parent.GetComponentInChildren(); - - initialPosition = transform.position - _sector.transform.position; - targetRadius = initialPosition.magnitude; - parentBody = _sector.transform.parent.gameObject; - Logger.Log($"{targetRadius}"); - } - - public void OnDestroy() - { - if(_sector != null) - { - _sector.OnOccupantEnterSector += OnOccupantEnterSector; - _sector.OnOccupantExitSector += OnOccupantExitSector; - } - } - - private void FixedUpdate() - { - if (this._lightSensors[0].IsIlluminated()) - { - this._localAcceleration += Vector3.forward * this._acceleration; - } - if (this._lightSensors[1].IsIlluminated()) - { - this._localAcceleration += Vector3.right * this._acceleration; - } - if (this._lightSensors[2].IsIlluminated()) - { - this._localAcceleration -= Vector3.forward * this._acceleration; - } - if (this._lightSensors[3].IsIlluminated()) - { - this._localAcceleration -= Vector3.right * this._acceleration; - } - - /* - var currentRadius = GetRelativePosition().magnitude; - if(currentRadius != targetRadius) - { - float g = 1f; - var r = (currentRadius / targetRadius); - //if (gravityVolume != null) g = gravityVolume.CalculateGravityMagnitude(currentRadius); - _raftBody.AddAcceleration((1f - Mathf.Sqrt(r)) * GetRelativePosition().normalized * g * BuoyancyModifier); - } - */ - - /* - Vector3 vector2 = _raftBody.GetVelocity(); - var normalVector = GetRelativePosition().normalized; - float normalComponent2 = Vector3.Dot(vector2, normalVector); - vector2 -= normalComponent2 * normalVector; - _raftBody.SetVelocity(vector2); - _raftBody.SetPosition(_sector.transform.position + normalVector * targetRadius); - */ - - if (this._localAcceleration.sqrMagnitude > 0.001f) - { - this._raftBody.AddLocalAcceleration(this._localAcceleration); - } - this._localAcceleration = Vector3.zero; - - } - - private Vector3 GetRelativePosition() - { - return transform.position - parentBody.transform.position; - } - - public void SetSector(Sector sector) - { - _sector = sector; - _sector.OnOccupantEnterSector += OnOccupantEnterSector; - _sector.OnOccupantExitSector += OnOccupantExitSector; - } - - private void OnOccupantEnterSector(SectorDetector sectorDetector) - { - if (sectorDetector.GetOccupantType() == DynamicOccupant.Player) - { - _raftBody.Unsuspend(); - } - } - - private void OnOccupantExitSector(SectorDetector sectorDetector) - { - if (sectorDetector.GetOccupantType() == DynamicOccupant.Player) - { - _raftBody.Suspend(); - } - } - } -} diff --git a/NewHorizons/Builder/Props/PropBuildManager.cs b/NewHorizons/Builder/Props/PropBuildManager.cs index 69ba4ab4..c64a47f5 100644 --- a/NewHorizons/Builder/Props/PropBuildManager.cs +++ b/NewHorizons/Builder/Props/PropBuildManager.cs @@ -18,7 +18,7 @@ namespace NewHorizons.Builder.Props { public static class PropBuildManager { - public static void Make(GameObject go, Sector sector, IPlanetConfig config, IModBehaviour mod, string uniqueModName) + public static void Make(GameObject go, Sector sector, OWRigidbody planetBody, IPlanetConfig config, IModBehaviour mod, string uniqueModName) { if (config.Props.Scatter != null) { @@ -40,7 +40,10 @@ namespace NewHorizons.Builder.Props } if(config.Props.Rafts != null) { - // TODO + foreach(var raftInfo in config.Props.Rafts) + { + RaftBuilder.Make(go, sector, raftInfo, planetBody); + } } if(config.Props.Tornados != null) { diff --git a/NewHorizons/Builder/Props/RaftBuilder.cs b/NewHorizons/Builder/Props/RaftBuilder.cs index b9e06222..7e661295 100644 --- a/NewHorizons/Builder/Props/RaftBuilder.cs +++ b/NewHorizons/Builder/Props/RaftBuilder.cs @@ -1,4 +1,8 @@ using NewHorizons.Builder.General; +using NewHorizons.Components; +using NewHorizons.External; +using NewHorizons.Handlers; +using NewHorizons.Utility; using OWML.Utils; using System; using System.Collections.Generic; @@ -12,86 +16,56 @@ namespace NewHorizons.Builder.Props { public static class RaftBuilder { - public static void Make(GameObject body, Vector3 position, Sector sector, OWRigidbody OWRB, AstroObject ao) + private static GameObject _prefab; + + public static void Make(GameObject planetGO, Sector sector, PropModule.RaftInfo info, OWRigidbody planetBody) { - var originalRaft = GameObject.Find("RingWorld_Body/Sector_RingInterior/Interactibles_RingInterior/Rafts/Raft_Body"); - - GameObject raftObject = new GameObject($"{body.name}Raft"); - raftObject.SetActive(false); - - GameObject lightSensors = GameObject.Instantiate(GameObject.Find("RingWorld_Body/Sector_RingInterior/Sector_Zone2/Structures_Zone2/RaftHouse_Eye_Zone2/Interactables_RaftHouse_Eye_Zone2/Prefab_IP_RaftDock/RaftSocket/Raft_Body (7)/LightSensorRoot"), raftObject.transform); - GameObject geometry = GameObject.Instantiate(GameObject.Find("RingWorld_Body/Sector_RingInterior/Sector_Zone2/Structures_Zone2/RaftHouse_Eye_Zone2/Interactables_RaftHouse_Eye_Zone2/Prefab_IP_RaftDock/RaftSocket/Raft_Body (7)/Structure_IP_Raft"), raftObject.transform); - GameObject collidersObject = GameObject.Instantiate(GameObject.Find("RingWorld_Body/Sector_RingInterior/Sector_Zone2/Structures_Zone2/RaftHouse_Eye_Zone2/Interactables_RaftHouse_Eye_Zone2/Prefab_IP_RaftDock/RaftSocket/Raft_Body (7)/Colliders/"), raftObject.transform); + if(_prefab == null) + { + _prefab = GameObject.FindObjectOfType().gameObject.InstantiateInactive(); + _prefab.name = "Raft_Body_Prefab"; + } + GameObject raftObject = _prefab.InstantiateInactive(); + raftObject.name = "Raft_Body"; raftObject.transform.parent = sector.transform; - raftObject.transform.localPosition = position; - raftObject.transform.rotation = Quaternion.FromToRotation(raftObject.transform.TransformDirection(Vector3.up), position.normalized); + raftObject.transform.localPosition = info.position; + raftObject.transform.localRotation = Quaternion.identity; - foreach (var l in lightSensors.GetComponentsInChildren()) + sector.OnOccupantEnterSector += (sd) => OWAssetHandler.OnOccupantEnterSector(raftObject, sd, sector); + OWAssetHandler.LoadObject(raftObject); + + var raftController = raftObject.GetComponent(); + // Since awake already ran we have to unhook these events + raftController._sector.OnOccupantEnterSector -= raftController.OnOccupantEnterSector; + raftController._sector.OnOccupantExitSector -= raftController.OnOccupantExitSector; + raftController._riverFluid = null; + + raftController._sector = sector; + sector.OnOccupantEnterSector += raftController.OnOccupantEnterSector; + sector.OnOccupantExitSector += raftController.OnOccupantExitSector; + + // Detectors + var fluidDetector = raftObject.transform.Find("Detector_Raft").GetComponent(); + var waterVolume = planetGO.GetComponentInChildren(); + fluidDetector._alignmentFluid = waterVolume; + + // Light sensors + foreach(var lightSensor in raftObject.GetComponentsInChildren()) { - if (l._sector != null) l._sector.OnSectorOccupantsUpdated -= l.OnSectorOccupantsUpdated; - l._sector = sector; - l._sector.OnSectorOccupantsUpdated += l.OnSectorOccupantsUpdated; - l._lightSourceMask = LightSourceType.FLASHLIGHT; - l.SetDetectorActive(true); - l.gameObject.SetActive(true); + lightSensor._sector.OnSectorOccupantsUpdated -= lightSensor.OnSectorOccupantsUpdated; + lightSensor._sector = sector; + sector.OnSectorOccupantsUpdated += lightSensor.OnSectorOccupantsUpdated; } - var rigidBody = raftObject.AddComponent(); - rigidBody.isKinematic = true; - rigidBody.interpolation = originalRaft.GetComponent().interpolation; - rigidBody.collisionDetectionMode = originalRaft.GetComponent().collisionDetectionMode; - rigidBody.mass = originalRaft.GetComponent().mass; - rigidBody.drag = originalRaft.GetComponent().drag; - rigidBody.angularDrag = originalRaft.GetComponent().angularDrag; - - var kinematicRigidBody = raftObject.AddComponent(); - kinematicRigidBody.centerOfMass = Vector3.zero; - - var owRigidBody = raftObject.AddComponent(); - owRigidBody._kinematicSimulation = true; - owRigidBody._rigidbody = rigidBody; - owRigidBody._kinematicRigidbody = kinematicRigidBody; - kinematicRigidBody._rigidbody = rigidBody; - kinematicRigidBody._owRigidbody = owRigidBody; - - //var motion = raftObject.AddComponent(); - //motion.SetBodyToMatch(OWRB); - - foreach (var c in collidersObject.GetComponentsInChildren()) + /* + // Debug + foreach (var point in fluidDetector._localAlignmentCheckPoints) { - c.ClearParentBody(); - c._parentBody = owRigidBody; - c.ListenForParentBodySuspension(); + var sphere = AddDebugShape.AddSphere(fluidDetector.gameObject, 0.5f, Color.green); + sphere.transform.localPosition = point; } - var meshColliders = collidersObject.GetComponentsInChildren(); - foreach (var c in meshColliders) - { - var child = c.gameObject; - var newCollider = child.AddComponent(); - newCollider.sharedMesh = c.sharedMesh; - newCollider.material = c.material; - newCollider.sharedMaterial = c.sharedMaterial; - GameObject.Destroy(c); - } - - foreach (var child in raftObject.GetComponentsInChildren()) - { - StreamingManager.LoadStreamingAssets(child.assetBundle); - } - - //var detectorGO = DetectorBuilder.Make(raftObject, owRigidBody, ao, null, false, false); - //var fluidDetector = detectorGO.AddComponent(); - //Main.Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => fluidDetector._activeVolumes = new EffectVolume[] { body.GetComponentInChildren() }.ToList()); - - - var targetBodyAlignment = raftObject.AddComponent(); - targetBodyAlignment._owRigidbody = owRigidBody; - targetBodyAlignment.SetTargetBody(OWRB); - targetBodyAlignment.SetUsePhysicsToRotate(true); - - var controller = raftObject.AddComponent(); - controller.SetSector(sector); + */ raftObject.SetActive(true); } diff --git a/NewHorizons/Components/NHFluidVolume.cs b/NewHorizons/Components/NHFluidVolume.cs new file mode 100644 index 00000000..3f01a0d1 --- /dev/null +++ b/NewHorizons/Components/NHFluidVolume.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace NewHorizons.Components +{ + public class NHFluidVolume : RadialFluidVolume + { + public override float GetDepthAtPosition(Vector3 worldPosition) + { + Vector3 vector = transform.InverseTransformPoint(worldPosition); + float dist = Mathf.Sqrt(vector.x * vector.x + vector.z * vector.z + vector.y * vector.y); + return dist - _radius; + } + } +} diff --git a/NewHorizons/Components/NHPlanetaryRaftFix.cs b/NewHorizons/Components/NHPlanetaryRaftFix.cs new file mode 100644 index 00000000..4e5a9408 --- /dev/null +++ b/NewHorizons/Components/NHPlanetaryRaftFix.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using Logger = NewHorizons.Utility.Logger; + +namespace NewHorizons.Components +{ + public class NHPlanetaryRaftFix : MonoBehaviour + { + private RaftController _raftController; + private RaftFluidDetector _fluidDetector; + private FluidVolume _fluidVolume; + private RaftEffectsController _effectsController; + + public void Awake() + { + _raftController = gameObject.GetComponent(); + _fluidDetector = _raftController._fluidDetector; + _fluidVolume = _fluidDetector._alignmentFluid; + _effectsController = _raftController._effectsController; + } + + public void FixedUpdate() + { + if (_raftController._raftBody.IsSuspended()) return; + if (!_raftController._playerInEffectsRange) return; + + // Normally this part won't get called because in RaftController it checks how submerged we are in the Ringworld river + // Just copy pasted it here using the actual fluid volume instead of making an ugly patch + float num = _fluidDetector.InFluidType(FluidVolume.Type.WATER) ? _fluidVolume.GetFractionSubmerged(_fluidDetector) : 0f; + bool allowMovement = num > 0.25f && num < 1f; + Logger.Log($"AllowMovement? [{allowMovement}]"); + allowMovement = true; + _effectsController.UpdateMovementAudio(allowMovement, _raftController._lightSensors); + _effectsController.UpdateGroundedAudio(_fluidDetector); + } + } +} diff --git a/NewHorizons/Handlers/PlanetCreationHandler.cs b/NewHorizons/Handlers/PlanetCreationHandler.cs index 7fe0378a..8a362255 100644 --- a/NewHorizons/Handlers/PlanetCreationHandler.cs +++ b/NewHorizons/Handlers/PlanetCreationHandler.cs @@ -340,7 +340,7 @@ namespace NewHorizons.Handlers } if (body.Config.Props != null) - PropBuildManager.Make(go, sector, body.Config, body.Mod, body.Mod.ModHelper.Manifest.UniqueName); + PropBuildManager.Make(go, sector, rb, body.Config, body.Mod, body.Mod.ModHelper.Manifest.UniqueName); if (body.Config.Signal != null) SignalBuilder.Make(go, sector, body.Config.Signal, body.Mod); diff --git a/NewHorizons/Main.cs b/NewHorizons/Main.cs index c9342c6e..cc4191db 100644 --- a/NewHorizons/Main.cs +++ b/NewHorizons/Main.cs @@ -28,6 +28,8 @@ using NewHorizons.Builder.Atmosphere; using PacificEngine.OW_CommonResources.Geometry.Orbits; using NewHorizons.Utility.CommonResources; using UnityEngine.Events; +using HarmonyLib; +using System.Reflection; namespace NewHorizons { @@ -111,6 +113,9 @@ namespace NewHorizons BodyDict["EyeOfTheUniverse"] = new List(); // Keep this empty tho fr SystemDict["SolarSystem"] = new NewHorizonsSystem("SolarSystem", new StarSystemConfig(null), this); + // Patches + Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly()); + Tools.Patches.Apply(); Tools.WarpDrivePatches.Apply(); Tools.OWCameraFix.Apply(); diff --git a/NewHorizons/NewHorizons.csproj b/NewHorizons/NewHorizons.csproj index 97bef051..013043d0 100644 --- a/NewHorizons/NewHorizons.csproj +++ b/NewHorizons/NewHorizons.csproj @@ -16,6 +16,7 @@ none + diff --git a/NewHorizons/Patches/RaftPatches.cs b/NewHorizons/Patches/RaftPatches.cs new file mode 100644 index 00000000..3b061cd4 --- /dev/null +++ b/NewHorizons/Patches/RaftPatches.cs @@ -0,0 +1,116 @@ +using HarmonyLib; +using NewHorizons.Components; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using Logger = NewHorizons.Utility.Logger; + +namespace NewHorizons.Patches +{ + [HarmonyPatch] + public class RaftPatches : HarmonyPatch + { + [HarmonyPrefix] + [HarmonyPatch(typeof(RaftController), nameof(RaftController.FixedUpdate))] + public static bool RaftController_FixedUpdate(RaftController __instance) + { + // If it has a river fluid its a normal one and we don't do anything + if (__instance._riverFluid != null) return true; + + // Copy paste the original method + if (__instance._raftBody.IsSuspended()) + { + return false; + } + bool playerInEffectsRange = __instance._playerInEffectsRange; + __instance._playerInEffectsRange = ((Locator.GetPlayerBody().GetPosition() - __instance._raftBody.GetPosition()).sqrMagnitude < 2500f); + if (playerInEffectsRange && !__instance._playerInEffectsRange) + { + __instance._effectsController.StopAllEffects(); + } + if (__instance._dock != null || __instance._movingToTarget) + { + __instance._localAcceleration = Vector3.zero; + if (__instance._playerInEffectsRange) + { + __instance._effectsController.UpdateMovementAudio(false, __instance._lightSensors); + } + if (__instance._movingToTarget) + { + __instance.UpdateMoveToTarget(); + } + return false; + } + if (__instance._fluidDetector.InFluidType(FluidVolume.Type.WATER)) + { + if (__instance._lightSensors[0].IsIlluminated()) + { + __instance._localAcceleration += Vector3.forward * __instance._acceleration; + } + if (__instance._lightSensors[1].IsIlluminated()) + { + __instance._localAcceleration += Vector3.right * __instance._acceleration; + } + if (__instance._lightSensors[2].IsIlluminated()) + { + __instance._localAcceleration -= Vector3.forward * __instance._acceleration; + } + if (__instance._lightSensors[3].IsIlluminated()) + { + __instance._localAcceleration -= Vector3.right * __instance._acceleration; + } + } + if (__instance._localAcceleration.sqrMagnitude > 0.001f) + { + __instance._raftBody.AddLocalAcceleration(__instance._localAcceleration); + } + if (__instance._playerInEffectsRange) + { + // All this to change what fluidVolume we use on this line + float num = __instance._fluidDetector.InFluidType(FluidVolume.Type.WATER) ? __instance._fluidDetector._alignmentFluid.GetFractionSubmerged(__instance._fluidDetector) : 0f; + bool allowMovement = num > 0.25f && num < 1f; + __instance._effectsController.UpdateMovementAudio(allowMovement, __instance._lightSensors); + __instance._effectsController.UpdateGroundedAudio(__instance._fluidDetector); + } + __instance._localAcceleration = Vector3.zero; + + return false; + } + + [HarmonyReversePatch] + [HarmonyPatch(typeof(AsymmetricFluidDetector), "ManagedFixedUpdate")] + public static void AsymmetricFluidDetector_ManagedFixedUpdate(AsymmetricFluidDetector __instance) + { + // This is like doing base.FixedUpdate + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(AlignToSurfaceFluidDetector), "ManagedFixedUpdate")] + public static bool AlignToSurfaceFluidDetector_ManagedFixedUpdate(AlignToSurfaceFluidDetector __instance) + { + if (!__instance._alignmentFluid is NHFluidVolume) return true; + + // Mostly copy pasting from the AlignWithDirection class + AsymmetricFluidDetector_ManagedFixedUpdate(__instance); + + if (__instance._inAlignmentFluid) + { + // Both in world space + var currentDirection = __instance._owRigidbody.transform.up; + var alignmentDirection = (__instance.transform.position - __instance._alignmentFluid.transform.position).normalized; + var degreesToTarget = Vector3.Angle(currentDirection, alignmentDirection); + + var adjustedSlerpRate = Mathf.Clamp01(100f / degreesToTarget * Time.fixedDeltaTime); + + Vector3 a = OWPhysics.FromToAngularVelocity(currentDirection, alignmentDirection); + __instance._owRigidbody.SetAngularVelocity(Vector3.zero); + __instance._owRigidbody.AddAngularVelocityChange(a * adjustedSlerpRate); + } + + return false; + } + } +} diff --git a/NewHorizons/Tools/Patches.cs b/NewHorizons/Tools/Patches.cs index 25a653a2..78ecbac7 100644 --- a/NewHorizons/Tools/Patches.cs +++ b/NewHorizons/Tools/Patches.cs @@ -10,7 +10,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; -using Harmony; +using HarmonyLib; using NewHorizons.Utility; using OWML.Utils; using UnityEngine;