diff --git a/QSB/OrbSync/TransformSync/NomaiOrbTransformSync.cs b/QSB/OrbSync/TransformSync/NomaiOrbTransformSync.cs index bee4e965..dc9cdfc2 100644 --- a/QSB/OrbSync/TransformSync/NomaiOrbTransformSync.cs +++ b/QSB/OrbSync/TransformSync/NomaiOrbTransformSync.cs @@ -1,4 +1,4 @@ -using QSB.Syncs.TransformSync; +using QSB.Syncs.Unsectored.Transforms; using QSB.Utility; using QSB.WorldSync; using System.Collections.Generic; @@ -6,7 +6,7 @@ using UnityEngine; namespace QSB.OrbSync.TransformSync { - internal class NomaiOrbTransformSync : UnparentedBaseTransformSync + internal class NomaiOrbTransformSync : UnsectoredTransformSync { public static List OrbTransformSyncs = new List(); diff --git a/QSB/Player/TransformSync/PlayerTransformSync.cs b/QSB/Player/TransformSync/PlayerTransformSync.cs index f3b89a91..d748cc99 100644 --- a/QSB/Player/TransformSync/PlayerTransformSync.cs +++ b/QSB/Player/TransformSync/PlayerTransformSync.cs @@ -4,7 +4,7 @@ using QSB.Events; using QSB.Instruments; using QSB.RoastingSync; using QSB.SectorSync; -using QSB.Syncs.TransformSync; +using QSB.Syncs.Sectored.Transforms; using QSB.Tools; using QSB.Utility; using QSB.WorldSync; diff --git a/QSB/ProbeSync/TransformSync/PlayerProbeSync.cs b/QSB/ProbeSync/TransformSync/PlayerProbeSync.cs index e51cfa35..dbc7dba6 100644 --- a/QSB/ProbeSync/TransformSync/PlayerProbeSync.cs +++ b/QSB/ProbeSync/TransformSync/PlayerProbeSync.cs @@ -1,7 +1,7 @@ using OWML.Common; using OWML.Utils; using QSB.SectorSync; -using QSB.Syncs.TransformSync; +using QSB.Syncs.Sectored.Transforms; using QSB.Tools; using QSB.Tools.ProbeLauncherTool; using QSB.Utility; diff --git a/QSB/QSB.csproj b/QSB/QSB.csproj index ac1b7919..088c2d87 100644 --- a/QSB/QSB.csproj +++ b/QSB/QSB.csproj @@ -278,9 +278,13 @@ - - + + + + + + @@ -308,10 +312,7 @@ - - - diff --git a/QSB/SectorSync/QSBSectorManager.cs b/QSB/SectorSync/QSBSectorManager.cs index fc94c8a5..534f83fd 100644 --- a/QSB/SectorSync/QSBSectorManager.cs +++ b/QSB/SectorSync/QSBSectorManager.cs @@ -1,6 +1,7 @@ using OWML.Common; using QSB.SectorSync.WorldObjects; using QSB.Syncs; +using QSB.Syncs.Sectored; using QSB.Utility; using QSB.WorldSync; using System.Collections.Generic; @@ -18,8 +19,7 @@ namespace QSB.SectorSync private void OnEnable() => RepeatingManager.Repeatings.Add(this); private void OnDisable() => RepeatingManager.Repeatings.Remove(this); - public List SectoredTransformSyncs = new List(); - public List SectoredRigidbodySyncs = new List(); + public List SectoredSyncs = new List(); public void Invoke() { @@ -28,7 +28,7 @@ namespace QSB.SectorSync return; } - foreach (var sync in SectoredTransformSyncs) + foreach (var sync in SectoredSyncs) { if (sync.AttachedObject == null) { @@ -39,22 +39,7 @@ namespace QSB.SectorSync && sync.AttachedObject.gameObject.activeInHierarchy && sync.IsReady) { - CheckTransformSyncSector(sync as ISectoredSync); - } - } - - foreach (var sync in SectoredRigidbodySyncs) - { - if (sync.AttachedObject == null) - { - continue; - } - - if (sync.HasAuthority - && sync.AttachedObject.gameObject.activeInHierarchy - && sync.IsReady) - { - CheckTransformSyncSector(sync as ISectoredSync); + CheckTransformSyncSector(sync); } } } @@ -89,10 +74,9 @@ namespace QSB.SectorSync IsReady = QSBWorldSync.GetWorldObjects().Any(); } - private void CheckTransformSyncSector(ISectoredSync transformSync) - where T : Component + private void CheckTransformSyncSector(BaseSectoredSync transformSync) { - var attachedObject = (transformSync as SyncBase).AttachedObject; + var attachedObject = transformSync.AttachedObject; var closestSector = transformSync.SectorSync.GetClosestSector(attachedObject.transform); if (closestSector == default(QSBSector)) { diff --git a/QSB/ShipSync/TransformSync/ShipTransformSync.cs b/QSB/ShipSync/TransformSync/ShipTransformSync.cs index a76937ed..4b6f68fd 100644 --- a/QSB/ShipSync/TransformSync/ShipTransformSync.cs +++ b/QSB/ShipSync/TransformSync/ShipTransformSync.cs @@ -1,6 +1,6 @@ using QSB.Player; using QSB.SectorSync; -using QSB.Syncs.RigidbodySync; +using QSB.Syncs.Sectored.Rigidbodies; using QSB.Utility; using QSB.WorldSync; using UnityEngine; @@ -20,9 +20,6 @@ namespace QSB.ShipSync.TransformSync LocalInstance = this; } - protected override Component InitLocalTransform() => throw new System.NotImplementedException(); - protected override Component InitRemoteTransform() => throw new System.NotImplementedException(); - protected override OWRigidbody GetRigidbody() { QSBCore.UnityEvents.RunWhen(() => WorldObjectManager.AllReady, () => SectorSync.Init(Locator.GetShipDetector().GetComponent(), this)); diff --git a/QSB/Syncs/Sectored/BaseSectoredSync.cs b/QSB/Syncs/Sectored/BaseSectoredSync.cs new file mode 100644 index 00000000..bd03e8eb --- /dev/null +++ b/QSB/Syncs/Sectored/BaseSectoredSync.cs @@ -0,0 +1,226 @@ +using QSB.SectorSync.WorldObjects; +using QSB.SectorSync; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using QSB.Player.TransformSync; +using UnityEngine; +using OWML.Common; +using QSB.Utility; +using QSB.Player; +using QSB.WorldSync; +using QuantumUNET.Transport; + +namespace QSB.Syncs.Sectored +{ + public abstract class BaseSectoredSync : SyncBase + { + public override bool IgnoreDisabledAttachedObject => false; + public override bool IgnoreNullReferenceTransform => true; + + public QSBSector ReferenceSector { get; set; } + public SectorSync.SectorSync SectorSync { get; private set; } + public abstract TargetType Type { get; } + + private int _sectorIdWaitingSlot = int.MinValue; + + public override void Start() + { + SectorSync = gameObject.AddComponent(); + QSBSectorManager.Instance.SectoredSyncs.Add(this); + base.Start(); + } + + protected override void OnDestroy() + { + base.OnDestroy(); + QSBSectorManager.Instance.SectoredSyncs.Remove(this); + if (SectorSync != null) + { + Destroy(SectorSync); + } + } + + protected override void Init() + { + base.Init(); + if (!QSBSectorManager.Instance.IsReady) + { + return; + } + + if (!HasAuthority) + { + return; + } + + QSBCore.UnityEvents.RunWhen(() => SectorSync.IsReady, InitSector); + } + + private void InitSector() + { + DebugLog.DebugWrite($"[BaseSectoredSync] {_logName} InitSector"); + var closestSector = SectorSync.GetClosestSector(AttachedObject.transform); + if (closestSector != null) + { + SetReferenceSector(closestSector); + } + else + { + DebugLog.ToConsole($"Warning - {_logName}'s initial sector was null.", OWML.Common.MessageType.Warning); + } + } + + public override void Update() + { + if (_sectorIdWaitingSlot == int.MinValue) + { + base.Update(); + return; + } + + if (!WorldObjectManager.AllReady) + { + base.Update(); + return; + } + + var sector = _sectorIdWaitingSlot == -1 + ? null + : QSBWorldSync.GetWorldFromId(_sectorIdWaitingSlot); + + if (sector != ReferenceSector) + { + if (sector == null) + { + DebugLog.ToConsole($"Error - {PlayerId}.{GetType().Name} got sector of ID -1.", OWML.Common.MessageType.Error); + base.Update(); + return; + } + + SetReferenceSector(sector); + } + + _sectorIdWaitingSlot = int.MinValue; + + base.Update(); + } + + public override void SerializeTransform(QNetworkWriter writer, bool initialState) + { + if (_intermediaryTransform == null) + { + _intermediaryTransform = new IntermediaryTransform(transform); + } + + if (!QSBPlayerManager.PlayerExists(PlayerId)) + { + writer.Write(-1); + } + else if (!Player.PlayerStates.IsReady) + { + writer.Write(-1); + } + else if (ReferenceSector != null) + { + writer.Write(ReferenceSector.ObjectId); + } + else + { + if (_isInitialized) + { + DebugLog.ToConsole($"Warning - ReferenceSector of {PlayerId}.{GetType().Name} is null.", OWML.Common.MessageType.Warning); + } + + writer.Write(-1); + } + } + + public override void DeserializeTransform(QNetworkReader reader, bool initialState) + { + int sectorId; + if (!QSBCore.WorldObjectsReady) + { + sectorId = reader.ReadInt32(); + DebugLog.DebugWrite($" - {_logName} ReadInt32 {sectorId}"); + if (initialState && sectorId != -1) + { + DebugLog.DebugWrite($"{_logName} set waiting sector id:{sectorId}"); + _sectorIdWaitingSlot = sectorId; + } + return; + } + + sectorId = reader.ReadInt32(); + DebugLog.DebugWrite($" - {_logName} ReadInt32 {sectorId}"); + var sector = sectorId == -1 + ? null + : QSBWorldSync.GetWorldFromId(sectorId); + + if (sector != ReferenceSector) + { + if (sector == null) + { + DebugLog.ToConsole($"Error - {PlayerId}.{GetType().Name} got sector of ID -1.", OWML.Common.MessageType.Error); + return; + } + + SetReferenceSector(sector); + } + } + + protected override bool UpdateTransform() + { + var referenceNull = ReferenceTransform == null || ReferenceSector == null || _intermediaryTransform.GetReferenceTransform() == null; + var sectorManagerReady = QSBSectorManager.Instance.IsReady; + + if (!sectorManagerReady) + { + if (referenceNull && HasAuthority) + { + DebugLog.ToConsole($"Warning - Reference was null, but sector manager wasn't ready. " + + $"Transform:{ReferenceTransform == null}, Sector:{ReferenceSector == null}, Intermediary:{_intermediaryTransform.GetReferenceTransform() == null}", + OWML.Common.MessageType.Warning); + } + + DebugLog.DebugWrite($"[BaseSectoredSync] {_logName} : Sector Manager not ready."); + return false; + } + + if (!HasAuthority) + { + DebugLog.DebugWrite($"[BaseSectoredSync] {_logName} : Does not have authority."); + return false; + } + + if (referenceNull) + { + var closestSector = SectorSync.GetClosestSector(AttachedObject.transform); + if (closestSector != null) + { + SetReferenceTransform(closestSector.Transform); + } + else + { + if (SectorSync.IsReady) + { + DebugLog.ToConsole($"Error - No closest sector found to {PlayerId}.{GetType().Name}!", OWML.Common.MessageType.Error); + } + + DebugLog.DebugWrite($"[BaseSectoredSync] {_logName} : No sector found."); + return false; + } + } + + return true; + } + + public void SetReferenceSector(QSBSector sector) + { + DebugLog.DebugWrite($"[BaseSectoredSync] {_logName} SetReferenceSector {sector.Name}"); + ReferenceSector = sector; + SetReferenceTransform(sector?.Transform); + } + } +} diff --git a/QSB/Syncs/Sectored/Transforms/SectoredTransformSync.cs b/QSB/Syncs/Sectored/Transforms/SectoredTransformSync.cs new file mode 100644 index 00000000..0addacea --- /dev/null +++ b/QSB/Syncs/Sectored/Transforms/SectoredTransformSync.cs @@ -0,0 +1,100 @@ +using OWML.Common; +using QSB.Utility; +using QuantumUNET.Transport; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace QSB.Syncs.Sectored.Transforms +{ + public abstract class SectoredTransformSync : BaseSectoredSync + { + public override bool ShouldReparentAttachedObject => true; + + protected abstract Component InitLocalTransform(); + protected abstract Component InitRemoteTransform(); + + protected override Component SetAttachedObject() + => HasAuthority ? InitLocalTransform() : InitRemoteTransform(); + + public override void SerializeTransform(QNetworkWriter writer, bool initialState) + { + base.SerializeTransform(writer, initialState); + + var worldPos = _intermediaryTransform.GetPosition(); + var worldRot = _intermediaryTransform.GetRotation(); + writer.Write(worldPos); + SerializeRotation(writer, worldRot); + _prevPosition = worldPos; + _prevRotation = worldRot; + } + + public override void DeserializeTransform(QNetworkReader reader, bool initialState) + { + base.DeserializeTransform(reader, initialState); + + if (!QSBCore.WorldObjectsReady) + { + reader.ReadVector3(); + DeserializeRotation(reader); + return; + } + + var pos = reader.ReadVector3(); + var rot = DeserializeRotation(reader); + + if (HasAuthority) + { + return; + } + + if (_intermediaryTransform == null) + { + _intermediaryTransform = new IntermediaryTransform(transform); + } + + _intermediaryTransform.SetPosition(pos); + _intermediaryTransform.SetRotation(rot); + + if (_intermediaryTransform.GetPosition() == Vector3.zero) + { + DebugLog.ToConsole($"Warning - {_logName} at (0,0,0)! - Given position was {pos}", MessageType.Warning); + } + } + + protected override bool UpdateTransform() + { + if (!base.UpdateTransform()) + { + return false; + } + + if (HasAuthority) + { + _intermediaryTransform.EncodePosition(AttachedObject.transform.position); + _intermediaryTransform.EncodeRotation(AttachedObject.transform.rotation); + return true; + } + + var targetPos = _intermediaryTransform.GetTargetPosition_ParentedToReference(); + var targetRot = _intermediaryTransform.GetTargetRotation_ParentedToReference(); + if (targetPos != Vector3.zero && _intermediaryTransform.GetTargetPosition_Unparented() != Vector3.zero) + { + if (UseInterpolation) + { + AttachedObject.transform.localPosition = SmartSmoothDamp(AttachedObject.transform.localPosition, targetPos); + AttachedObject.transform.localRotation = QuaternionHelper.SmoothDamp(AttachedObject.transform.localRotation, targetRot, ref _rotationSmoothVelocity, SmoothTime); + } + else + { + AttachedObject.transform.localPosition = targetPos; + AttachedObject.transform.localRotation = targetRot; + } + } + + return true; + } + } +} diff --git a/QSB/Syncs/Unsectored/Transforms/UnsectoredTransformSync.cs b/QSB/Syncs/Unsectored/Transforms/UnsectoredTransformSync.cs new file mode 100644 index 00000000..94454dd6 --- /dev/null +++ b/QSB/Syncs/Unsectored/Transforms/UnsectoredTransformSync.cs @@ -0,0 +1,89 @@ +using OWML.Common; +using QSB.Utility; +using QuantumUNET.Transport; +using UnityEngine; + +namespace QSB.Syncs.Unsectored.Transforms +{ + public abstract class UnsectoredTransformSync : BaseUnsectoredSync + { + protected abstract Component InitLocalTransform(); + protected abstract Component InitRemoteTransform(); + + protected override Component SetAttachedObject() + => HasAuthority ? InitLocalTransform() : InitRemoteTransform(); + + public override void SerializeTransform(QNetworkWriter writer, bool initialState) + { + base.SerializeTransform(writer, initialState); + + var worldPos = _intermediaryTransform.GetPosition(); + var worldRot = _intermediaryTransform.GetRotation(); + writer.Write(worldPos); + SerializeRotation(writer, worldRot); + _prevPosition = worldPos; + _prevRotation = worldRot; + } + + public override void DeserializeTransform(QNetworkReader reader, bool initialState) + { + base.DeserializeTransform(reader, initialState); + + if (!QSBCore.WorldObjectsReady) + { + reader.ReadVector3(); + DeserializeRotation(reader); + return; + } + + var pos = reader.ReadVector3(); + var rot = DeserializeRotation(reader); + + if (HasAuthority) + { + return; + } + + if (_intermediaryTransform == null) + { + _intermediaryTransform = new IntermediaryTransform(transform); + } + + _intermediaryTransform.SetPosition(pos); + _intermediaryTransform.SetRotation(rot); + + if (_intermediaryTransform.GetPosition() == Vector3.zero) + { + DebugLog.ToConsole($"Warning - {_logName} at (0,0,0)! - Given position was {pos}", MessageType.Warning); + } + } + + protected override bool UpdateTransform() + { + if (HasAuthority) + { + _intermediaryTransform.EncodePosition(AttachedObject.transform.position); + _intermediaryTransform.EncodeRotation(AttachedObject.transform.rotation); + return true; + } + + var targetPos = _intermediaryTransform.GetTargetPosition_ParentedToReference(); + var targetRot = _intermediaryTransform.GetTargetRotation_ParentedToReference(); + if (targetPos != Vector3.zero && _intermediaryTransform.GetTargetPosition_Unparented() != Vector3.zero) + { + if (UseInterpolation) + { + AttachedObject.transform.localPosition = SmartSmoothDamp(AttachedObject.transform.localPosition, targetPos); + AttachedObject.transform.localRotation = QuaternionHelper.SmoothDamp(AttachedObject.transform.localRotation, targetRot, ref _rotationSmoothVelocity, SmoothTime); + } + else + { + AttachedObject.transform.localPosition = targetPos; + AttachedObject.transform.localRotation = targetRot; + } + } + + return true; + } + } +}