diff --git a/QSB/MeteorSync/Events/FragmentResyncEvent.cs b/QSB/MeteorSync/Events/FragmentResyncEvent.cs index 7c00ac43..1312d4d7 100644 --- a/QSB/MeteorSync/Events/FragmentResyncEvent.cs +++ b/QSB/MeteorSync/Events/FragmentResyncEvent.cs @@ -1,10 +1,15 @@ -using QSB.Events; +using System; +using QSB.Events; using QSB.MeteorSync.WorldObjects; +using QSB.Utility; using QSB.WorldSync; +using UnityEngine; +using EventType = QSB.Events.EventType; namespace QSB.MeteorSync.Events { /// called when we request a resync on client join + /// pain public class FragmentResyncEvent : QSBEvent { public override EventType Type => EventType.FragmentResync; @@ -26,6 +31,30 @@ namespace QSB.MeteorSync.Events OrigIntegrity = qsbFragment.AttachedObject._origIntegrity }; + if (msg.Integrity <= 0) + { + var detachableFragment = qsbFragment.AttachedObject.GetRequiredComponent(); + + msg.IsThruWhitehole = detachableFragment._sector._parentSector == MeteorManager.WhiteHoleVolume._whiteHoleSector; + + var refBody = GetRefBody(msg.IsThruWhitehole); + var body = detachableFragment.transform.parent.parent.GetAttachedOWRigidbody(); + if (!body.CompareTag("DetachedFragment")) + { + throw new Exception("HUGE BRUH MOMENT"); + } + + if (msg.IsThruWhitehole) + { + msg.LeashLength = body.gameObject.GetRequiredComponent()._leashLength; + } + + msg.Pos = refBody.transform.InverseTransformPoint(body.transform.position); + msg.Rot = refBody.transform.InverseTransformRotation(body.transform.rotation); + msg.Vel = GetRelativeVelocity(body, refBody); + msg.AngVel = body.GetRelativeAngularVelocity(refBody); + } + return msg; } @@ -40,6 +69,65 @@ namespace QSB.MeteorSync.Events qsbFragment.AttachedObject._integrity = msg.Integrity; qsbFragment.AttachedObject._origIntegrity = msg.OrigIntegrity; qsbFragment.AttachedObject.CallOnTakeDamage(); + + if (msg.Integrity <= 0) + { + // the detach is delay, so wait even more until that happens lol + QSBCore.UnityEvents.FireInNUpdates(() => + { + var detachableFragment = qsbFragment.AttachedObject.GetRequiredComponent(); + + var refBody = GetRefBody(msg.IsThruWhitehole); + var body = detachableFragment.transform.parent.parent.GetAttachedOWRigidbody(); + if (!body.CompareTag("DetachedFragment")) + { + throw new Exception("HUGE BRUH MOMENT"); + } + + if (msg.IsThruWhitehole) + { + detachableFragment.ChangeFragmentSector(MeteorManager.WhiteHoleVolume._whiteHoleSector, + MeteorManager.WhiteHoleVolume._whiteHoleProxyShadowSuperGroup); + body.gameObject.AddComponent().Init(MeteorManager.WhiteHoleVolume._whiteHoleBody, + msg.LeashLength); + } + + var targetPos = refBody.transform.TransformPoint(msg.Pos); + var targetRot = refBody.transform.TransformRotation(msg.Rot); + var targetVel = refBody.GetPointVelocity(targetPos) + msg.Vel; + var targetAngVel = refBody.GetAngularVelocity() + msg.AngVel; + body.MoveToPosition(targetPos); + body.MoveToRotation(targetRot); + SetVelocity(body, targetVel); + body.SetAngularVelocity(targetAngVel); + }, 20); + } } + + + private static OWRigidbody GetRefBody(bool isThruWhitehole) => + isThruWhitehole ? MeteorManager.WhiteHoleVolume._whiteHoleBody : Locator._brittleHollow._owRigidbody; + + // code yoink from transform sync lol + private static void SetVelocity(OWRigidbody rigidbody, Vector3 relativeVelocity) + { + var isRunningKinematic = rigidbody.RunningKinematicSimulation(); + var currentVelocity = rigidbody._currentVelocity; + + if (isRunningKinematic) + { + rigidbody._kinematicRigidbody.velocity = relativeVelocity + Locator.GetCenterOfTheUniverse().GetStaticFrameVelocity_Internal(); + } + else + { + rigidbody._rigidbody.velocity = relativeVelocity + Locator.GetCenterOfTheUniverse().GetStaticFrameVelocity_Internal(); + } + + rigidbody._lastVelocity = currentVelocity; + rigidbody._currentVelocity = relativeVelocity; + } + + private static Vector3 GetRelativeVelocity(OWRigidbody body, OWRigidbody refBody) + => body.GetVelocity() - refBody.GetPointVelocity(body.transform.position); } } diff --git a/QSB/MeteorSync/Events/FragmentResyncMessage.cs b/QSB/MeteorSync/Events/FragmentResyncMessage.cs index 7bb2eb2a..db6c3d96 100644 --- a/QSB/MeteorSync/Events/FragmentResyncMessage.cs +++ b/QSB/MeteorSync/Events/FragmentResyncMessage.cs @@ -1,5 +1,6 @@ using QSB.WorldSync.Events; using QuantumUNET.Transport; +using UnityEngine; namespace QSB.MeteorSync.Events { @@ -8,11 +9,31 @@ namespace QSB.MeteorSync.Events public float Integrity; public float OrigIntegrity; + public Vector3 Pos; + public Quaternion Rot; + public Vector3 Vel; + public Vector3 AngVel; + public bool IsThruWhitehole; + public float LeashLength; + public override void Deserialize(QNetworkReader reader) { base.Deserialize(reader); Integrity = reader.ReadSingle(); OrigIntegrity = reader.ReadSingle(); + if (Integrity <= 0) + { + Pos = reader.ReadVector3(); + Rot = reader.ReadQuaternion(); + Vel = reader.ReadVector3(); + AngVel = reader.ReadVector3(); + + IsThruWhitehole = reader.ReadBoolean(); + if (IsThruWhitehole) + { + LeashLength = reader.ReadSingle(); + } + } } public override void Serialize(QNetworkWriter writer) @@ -20,6 +41,19 @@ namespace QSB.MeteorSync.Events base.Serialize(writer); writer.Write(Integrity); writer.Write(OrigIntegrity); + if (Integrity <= 0) + { + writer.Write(Pos); + writer.Write(Rot); + writer.Write(Vel); + writer.Write(AngVel); + + writer.Write(IsThruWhitehole); + if (IsThruWhitehole) + { + writer.Write(LeashLength); + } + } } } } diff --git a/QSB/MeteorSync/MeteorManager.cs b/QSB/MeteorSync/MeteorManager.cs index c20d5fd6..17f5aed7 100644 --- a/QSB/MeteorSync/MeteorManager.cs +++ b/QSB/MeteorSync/MeteorManager.cs @@ -1,4 +1,5 @@ -using QSB.MeteorSync.WorldObjects; +using System.Linq; +using QSB.MeteorSync.WorldObjects; using QSB.WorldSync; namespace QSB.MeteorSync @@ -6,6 +7,7 @@ namespace QSB.MeteorSync public class MeteorManager : WorldObjectManager { public static bool Ready; + public static WhiteHoleVolume WhiteHoleVolume; protected override void RebuildWorldObjects(OWScene scene) { @@ -15,6 +17,7 @@ namespace QSB.MeteorSync QSBWorldSync.Init(); QSBWorldSync.Init(); QSBWorldSync.Init(); + WhiteHoleVolume = QSBWorldSync.GetUnityObjects().First(); Ready = true; }, 10); }