diff --git a/QSB/OrbSync/Events/OrbUserEvent.cs b/QSB/OrbSync/Events/OrbUserEvent.cs index 540f8372..f9d98a54 100644 --- a/QSB/OrbSync/Events/OrbUserEvent.cs +++ b/QSB/OrbSync/Events/OrbUserEvent.cs @@ -78,6 +78,7 @@ namespace QSB.OrbSync.Events DebugLog.ToConsole($"Error - Orb identity is null. (ID {message.ObjectId})", MessageType.Error); return; } + DebugLog.DebugWrite($"Orb {message.ObjectId} to owner {message.FromId}"); if (orbIdentity.ClientAuthorityOwner != null && orbIdentity.ClientAuthorityOwner != fromPlayer) { orbIdentity.RemoveClientAuthority(orbIdentity.ClientAuthorityOwner); @@ -103,6 +104,7 @@ namespace QSB.OrbSync.Events DebugLog.ToConsole($"Error - No NomaiOrbTransformSync has AttachedOrb with objectId {message.ObjectId}!"); return; } + DebugLog.DebugWrite($"Orb {message.ObjectId} to owner {message.FromId}"); var orb = QSBWorldSync.OrbSyncList .First(x => x.AttachedOrb == QSBWorldSync.OldOrbList[message.ObjectId]); orb.enabled = true; diff --git a/QSB/OrbSync/TransformSync/NomaiOrbTransformSync.cs b/QSB/OrbSync/TransformSync/NomaiOrbTransformSync.cs index fce6c87d..50cd1964 100644 --- a/QSB/OrbSync/TransformSync/NomaiOrbTransformSync.cs +++ b/QSB/OrbSync/TransformSync/NomaiOrbTransformSync.cs @@ -43,7 +43,6 @@ namespace QSB.OrbSync.TransformSync protected void Init() { - DebugLog.DebugWrite($"Init"); OrbTransform = AttachedOrb.transform; _orbParent = AttachedOrb.GetAttachedOWRigidbody().GetOrigParent(); _isInitialized = true; @@ -82,5 +81,16 @@ namespace QSB.OrbSync.TransformSync OrbTransform.rotation = transform.rotation; } } + + private void OnRenderObject() + { + if (!QSBCore.HasWokenUp || !QSBCore.DebugMode || !QSBCore.ShowLinesInDebug) + { + return; + } + + Popcron.Gizmos.Cube(OrbTransform.position, OrbTransform.rotation, Vector3.one / 2, Color.blue); + Popcron.Gizmos.Cube(_orbParent.TransformPoint(transform.position), transform.rotation, Vector3.one / 2, Color.red); + } } } \ No newline at end of file diff --git a/QSB/Player/TransformSync/PlayerCameraSync.cs b/QSB/Player/TransformSync/PlayerCameraSync.cs index 99cfdaf3..820b316f 100644 --- a/QSB/Player/TransformSync/PlayerCameraSync.cs +++ b/QSB/Player/TransformSync/PlayerCameraSync.cs @@ -6,7 +6,7 @@ using UnityEngine; namespace QSB.Player.TransformSync { - public class PlayerCameraSync : QSBNetworkTransform + public class PlayerCameraSync : SectoredTransformSync { protected override GameObject InitLocalTransform() { diff --git a/QSB/Player/TransformSync/PlayerTransformSync.cs b/QSB/Player/TransformSync/PlayerTransformSync.cs index f3ea3ab7..8c38bbec 100644 --- a/QSB/Player/TransformSync/PlayerTransformSync.cs +++ b/QSB/Player/TransformSync/PlayerTransformSync.cs @@ -5,7 +5,7 @@ using UnityEngine; namespace QSB.Player.TransformSync { - public class PlayerTransformSync : QSBNetworkTransform + public class PlayerTransformSync : SectoredTransformSync { public static PlayerTransformSync LocalInstance { get; private set; } diff --git a/QSB/ProbeSync/TransformSync/PlayerProbeSync.cs b/QSB/ProbeSync/TransformSync/PlayerProbeSync.cs index 281c4d02..4bcfa82d 100644 --- a/QSB/ProbeSync/TransformSync/PlayerProbeSync.cs +++ b/QSB/ProbeSync/TransformSync/PlayerProbeSync.cs @@ -7,14 +7,17 @@ using UnityEngine; namespace QSB.ProbeSync.TransformSync { - public class PlayerProbeSync : QSBNetworkTransform + public class PlayerProbeSync : SectoredTransformSync { public static PlayerProbeSync LocalInstance { get; private set; } protected override float DistanceLeeway => 10f; public override void OnStartAuthority() - => LocalInstance = this; + { + DebugLog.DebugWrite($"OnStartAuthority probe"); + LocalInstance = this; + } private Transform GetProbe() => Locator.GetProbe().transform.Find("CameraPivot").Find("Geometry"); diff --git a/QSB/QSB.csproj b/QSB/QSB.csproj index 09b91421..9e66b02b 100644 --- a/QSB/QSB.csproj +++ b/QSB/QSB.csproj @@ -237,9 +237,11 @@ + + diff --git a/QSB/QSBCore.cs b/QSB/QSBCore.cs index 1ea1a765..a3aaeb85 100644 --- a/QSB/QSBCore.cs +++ b/QSB/QSBCore.cs @@ -149,9 +149,13 @@ namespace QSB } var offset3 = 10f; - GUI.Label(new Rect(420, offset3, 400f, 20f), $"Current sector : {PlayerTransformSync.LocalInstance.ReferenceSector.Name}"); + var playerSector = PlayerTransformSync.LocalInstance.ReferenceSector; + var playerText = playerSector == null ? "NULL" : playerSector.Name; + GUI.Label(new Rect(420, offset3, 400f, 20f), $"Current sector : {playerText}"); offset3 += _debugLineSpacing; - GUI.Label(new Rect(420, offset3, 400f, 20f), $"Probe sector : {PlayerProbeSync.LocalInstance.ReferenceSector.Name}"); + var probeSector = PlayerProbeSync.LocalInstance.ReferenceSector; + var probeText = probeSector == null ? "NULL" : probeSector.Name; + GUI.Label(new Rect(420, offset3, 400f, 20f), $"Probe sector : {probeText}"); offset3 += _debugLineSpacing; var offset2 = 10f; diff --git a/QSB/RoastingSync/TransformSync/RoastingStickTransformSync.cs b/QSB/RoastingSync/TransformSync/RoastingStickTransformSync.cs index 2b1d9957..0c755538 100644 --- a/QSB/RoastingSync/TransformSync/RoastingStickTransformSync.cs +++ b/QSB/RoastingSync/TransformSync/RoastingStickTransformSync.cs @@ -7,7 +7,7 @@ using UnityEngine; namespace QSB.RoastingSync.TransformSync { - internal class RoastingStickTransformSync : QSBNetworkTransform + internal class RoastingStickTransformSync : SectoredTransformSync { private Transform _stickTip; private Transform _networkStickTip => gameObject.transform.GetChild(0); diff --git a/QSB/SectorSync/QSBSectorManager.cs b/QSB/SectorSync/QSBSectorManager.cs index 2c57866b..d85851bb 100644 --- a/QSB/SectorSync/QSBSectorManager.cs +++ b/QSB/SectorSync/QSBSectorManager.cs @@ -20,7 +20,7 @@ namespace QSB.SectorSync public void Invoke() { - foreach (var sync in QSBNetworkTransform.NetworkTransformList) + foreach (var sync in SectoredTransformSync.SectoredNetworkTransformList) { if (sync.AttachedObject == null) { @@ -64,7 +64,7 @@ namespace QSB.SectorSync IsReady = QSBWorldSync.GetWorldObjects().Any(); } - private void CheckTransformSyncSector(QSBNetworkTransform transformSync) + private void CheckTransformSyncSector(SectoredTransformSync transformSync) { var attachedObject = transformSync.AttachedObject; var closestSector = transformSync.SectorSync.GetClosestSector(attachedObject.transform); diff --git a/QSB/ShipSync/TransformSync/ShipTransformSync.cs b/QSB/ShipSync/TransformSync/ShipTransformSync.cs index 4494835a..f82e5c48 100644 --- a/QSB/ShipSync/TransformSync/ShipTransformSync.cs +++ b/QSB/ShipSync/TransformSync/ShipTransformSync.cs @@ -4,7 +4,7 @@ using UnityEngine; namespace QSB.ShipSync.TransformSync { - public class ShipTransformSync : QSBNetworkTransform + public class ShipTransformSync : SectoredTransformSync { protected override float DistanceLeeway => 20f; diff --git a/QSB/TransformSync/BaseTransformSync.cs b/QSB/TransformSync/BaseTransformSync.cs new file mode 100644 index 00000000..ac5984c3 --- /dev/null +++ b/QSB/TransformSync/BaseTransformSync.cs @@ -0,0 +1,218 @@ +using OWML.Common; +using QSB.Player; +using QSB.Player.TransformSync; +using QSB.Utility; +using QuantumUNET.Components; +using QuantumUNET.Transport; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace QSB.TransformSync +{ + public abstract class BaseTransformSync : QNetworkTransform + { + public uint AttachedNetId => NetIdentity?.NetId.Value ?? uint.MaxValue; + public uint PlayerId => NetIdentity.RootIdentity?.NetId.Value ?? NetIdentity.NetId.Value; + public PlayerInfo Player => QSBPlayerManager.GetPlayer(PlayerId); + + public Transform ReferenceTransform { get; set; } + public GameObject AttachedObject { get; set; } + + public abstract bool IsReady { get; } + + protected abstract GameObject InitLocalTransform(); + protected abstract GameObject InitRemoteTransform(); + + private bool _isInitialized; + private const float SmoothTime = 0.1f; + protected virtual float DistanceLeeway { get; } = 5f; + private float _previousDistance; + private Vector3 _positionSmoothVelocity; + private Quaternion _rotationSmoothVelocity; + protected IntermediaryTransform _intermediaryTransform; + + public virtual void Start() + { + var lowestBound = Resources.FindObjectsOfTypeAll() + .Where(x => x.NetId.Value <= NetId.Value).OrderBy(x => x.NetId.Value).Last(); + NetIdentity.SetRootIdentity(lowestBound.NetIdentity); + + DontDestroyOnLoad(gameObject); + _intermediaryTransform = new IntermediaryTransform(transform); + QSBSceneManager.OnSceneLoaded += OnSceneLoaded; + } + + protected virtual void OnDestroy() + { + if (!HasAuthority && AttachedObject != null) + { + Destroy(AttachedObject); + } + QSBSceneManager.OnSceneLoaded -= OnSceneLoaded; + } + + private void OnSceneLoaded(OWScene scene, bool isInUniverse) => + _isInitialized = false; + + protected virtual void Init() + { + AttachedObject = HasAuthority ? InitLocalTransform() : InitRemoteTransform(); + _isInitialized = true; + } + + public override void SerializeTransform(QNetworkWriter writer) + { + if (_intermediaryTransform == null) + { + _intermediaryTransform = new IntermediaryTransform(transform); + } + + var worldPos = _intermediaryTransform.GetPosition(); + var worldRot = _intermediaryTransform.GetRotation(); + writer.Write(worldPos); + SerializeRotation(writer, worldRot); + _prevPosition = worldPos; + _prevRotation = worldRot; + } + + public override void DeserializeTransform(QNetworkReader reader) + { + if (!QSBCore.HasWokenUp) + { + reader.ReadVector3(); + DeserializeRotation(reader); + return; + } + + var pos = reader.ReadVector3(); + var rot = DeserializeRotation(reader); + + if (HasAuthority) + { + return; + } + + _intermediaryTransform.SetPosition(pos); + _intermediaryTransform.SetRotation(rot); + + if (_intermediaryTransform.GetPosition() == Vector3.zero) + { + DebugLog.ToConsole($"Warning - {PlayerId}.{GetType().Name} at (0,0,0)! - Given position was {pos}", MessageType.Warning); + } + } + + public override void Update() + { + if (!_isInitialized && IsReady) + { + Init(); + } + else if (_isInitialized && !IsReady) + { + _isInitialized = false; + return; + } + + if (!_isInitialized) + { + return; + } + + if (AttachedObject == null) + { + DebugLog.ToConsole($"Warning - AttachedObject {Player.PlayerId}.{GetType().Name} is null.", MessageType.Warning); + return; + } + + UpdateTransform(); + + base.Update(); + } + + protected virtual void UpdateTransform() + { + if (HasAuthority) + { + _intermediaryTransform.EncodePosition(AttachedObject.transform.position); + _intermediaryTransform.EncodeRotation(AttachedObject.transform.rotation); + } + else + { + var targetPos = _intermediaryTransform.GetTargetPosition(); + var targetRot = _intermediaryTransform.GetTargetRotation(); + AttachedObject.transform.localPosition = SmartSmoothDamp(AttachedObject.transform.localPosition, targetPos); + AttachedObject.transform.localRotation = QuaternionHelper.SmoothDamp(AttachedObject.transform.localRotation, targetRot, ref _rotationSmoothVelocity, SmoothTime); + } + } + + public override bool HasMoved() + { + var displacementMagnitude = (_intermediaryTransform.GetPosition() - _prevPosition).magnitude; + return displacementMagnitude > 1E-03f + || Quaternion.Angle(_intermediaryTransform.GetRotation(), _prevRotation) > 1E-03f; + } + + public void SetReferenceTransform(Transform transform) + { + if (ReferenceTransform == transform) + { + return; + } + ReferenceTransform = transform; + _intermediaryTransform.SetReferenceTransform(transform); + if (AttachedObject == null) + { + DebugLog.ToConsole($"Warning - AttachedObject was null for {PlayerId}.{GetType().Name} when trying to set reference transform to {transform.name}. Waiting until not null...", MessageType.Warning); + QSBCore.UnityEvents.RunWhen( + () => AttachedObject != null, + () => ReparentAttachedObject(transform)); + return; + } + if (!HasAuthority) + { + ReparentAttachedObject(transform); + } + } + + private void ReparentAttachedObject(Transform sectorTransform) + { + if (AttachedObject.transform.parent != null && AttachedObject.transform.parent.GetComponent() == null) + { + DebugLog.ToConsole($" - ERROR - Trying to reparent attachedObject which wasnt attached to sector!", MessageType.Error); + return; + } + AttachedObject.transform.SetParent(sectorTransform, true); + AttachedObject.transform.localScale = GetType() == typeof(PlayerTransformSync) + ? Vector3.one / 10 + : Vector3.one; + } + + private Vector3 SmartSmoothDamp(Vector3 currentPosition, Vector3 targetPosition) + { + var distance = Vector3.Distance(currentPosition, targetPosition); + if (distance > _previousDistance + DistanceLeeway) + { + _previousDistance = distance; + return targetPosition; + } + _previousDistance = distance; + return Vector3.SmoothDamp(currentPosition, targetPosition, ref _positionSmoothVelocity, SmoothTime); + } + + private void OnRenderObject() + { + if (!QSBCore.HasWokenUp || !QSBCore.DebugMode || !QSBCore.ShowLinesInDebug || !IsReady) + { + return; + } + + Popcron.Gizmos.Cube(_intermediaryTransform.GetTargetPosition(), _intermediaryTransform.GetTargetRotation(), Vector3.one / 2, Color.red); + var color = HasMoved() ? Color.green : Color.yellow; + Popcron.Gizmos.Cube(AttachedObject.transform.position, AttachedObject.transform.rotation, Vector3.one / 2, color); + Popcron.Gizmos.Line(AttachedObject.transform.position, ReferenceTransform.position, Color.cyan); + } + } +} diff --git a/QSB/TransformSync/IntermediaryTransform.cs b/QSB/TransformSync/IntermediaryTransform.cs index 26249222..5b069c2a 100644 --- a/QSB/TransformSync/IntermediaryTransform.cs +++ b/QSB/TransformSync/IntermediaryTransform.cs @@ -3,10 +3,10 @@ using UnityEngine; namespace QSB.TransformSync { - internal class IntermediaryTransform + public class IntermediaryTransform { private Transform _attachedTransform; - private QSBSector _referenceSector; + private Transform _referenceTransform; public IntermediaryTransform(Transform transform) => _attachedTransform = transform; /// @@ -34,25 +34,25 @@ namespace QSB.TransformSync => _attachedTransform.rotation = worldRot; /// - /// Sets the reference sector - what sector this transform is syncing to. + /// Sets the reference transform - what transform this transform is syncing to. /// /// The new reference sector. - public void SetReferenceSector(QSBSector sector) - => _referenceSector = sector; + public void SetReferenceTransform(Transform transform) + => _referenceTransform = transform; /// /// Sets the position of the INVISIBLE transform to be correct, according to the reference sector and the position of the VISIBLE transform. /// /// The world position of the VISIBLE transform. public void EncodePosition(Vector3 worldPosition) - => SetPosition(_referenceSector.Transform.InverseTransformPoint(worldPosition)); + => SetPosition(_referenceTransform.InverseTransformPoint(worldPosition)); /// /// Sets the rotation of the INVISIBLE transform to be correct, according to the reference sector and the rotation of the VISIBLE transform. /// /// The world rotation of the VISIBLE transform. public void EncodeRotation(Quaternion worldRotation) - => SetRotation(_referenceSector.Transform.InverseTransformRotation(worldRotation)); + => SetRotation(_referenceTransform.InverseTransformRotation(worldRotation)); /// /// Gets what the VISIBLE transform's position should be, from the reference sector and the position of the INVISIBLE transform. diff --git a/QSB/TransformSync/QSBNetworkTransform.cs b/QSB/TransformSync/QSBNetworkTransform.cs index a81718a5..19f46894 100644 --- a/QSB/TransformSync/QSBNetworkTransform.cs +++ b/QSB/TransformSync/QSBNetworkTransform.cs @@ -12,6 +12,7 @@ using UnityEngine; namespace QSB.TransformSync { + /* public abstract class QSBNetworkTransform : QNetworkTransform { public uint AttachedNetId => NetIdentity?.NetId.Value ?? uint.MaxValue; @@ -246,4 +247,5 @@ namespace QSB.TransformSync Popcron.Gizmos.Line(AttachedObject.transform.position, ReferenceSector.Transform.position, Color.cyan); } } + */ } diff --git a/QSB/TransformSync/SectoredTransformSync.cs b/QSB/TransformSync/SectoredTransformSync.cs new file mode 100644 index 00000000..a3b3daa8 --- /dev/null +++ b/QSB/TransformSync/SectoredTransformSync.cs @@ -0,0 +1,87 @@ +using QSB.SectorSync.WorldObjects; +using QSB.Utility; +using QSB.WorldSync; +using QuantumUNET.Transport; +using System.Collections.Generic; + +namespace QSB.TransformSync +{ + public abstract class SectoredTransformSync : BaseTransformSync + { + public QSBSector ReferenceSector { get; set; } + public SectorSync.SectorSync SectorSync { get; private set; } + public static List SectoredNetworkTransformList = new List(); + + public override void Start() + { + DebugLog.DebugWrite($"Start of {GetType().Name}"); + SectorSync = gameObject.AddComponent(); + SectoredNetworkTransformList.Add(this); + base.Start(); + } + + protected override void OnDestroy() + { + DebugLog.DebugWrite($"OnDestroy of {GetType().Name}"); + base.OnDestroy(); + SectoredNetworkTransformList.Remove(this); + if (SectorSync != null) + { + Destroy(SectorSync); + } + } + + protected override void Init() + { + DebugLog.DebugWrite($"Init of {GetType().Name}"); + base.Init(); + SetReferenceTransform(SectorSync.GetClosestSector(AttachedObject.transform).Transform); + } + + public override void SerializeTransform(QNetworkWriter writer) + { + if (_intermediaryTransform == null) + { + _intermediaryTransform = new IntermediaryTransform(transform); + } + if (ReferenceSector != null) + { + writer.Write(ReferenceSector.ObjectId); + } + else + { + writer.Write(-1); + } + base.SerializeTransform(writer); + } + + public override void DeserializeTransform(QNetworkReader reader) + { + if (!QSBCore.HasWokenUp) + { + reader.ReadInt32(); + reader.ReadVector3(); + DeserializeRotation(reader); + return; + } + + var sectorId = reader.ReadInt32(); + var sector = sectorId == -1 + ? null + : QSBWorldSync.GetWorldFromId(sectorId); + + if (sector != ReferenceSector) + { + SetReferenceSector(sector); + } + + base.DeserializeTransform(reader); + } + + public void SetReferenceSector(QSBSector sector) + { + ReferenceSector = sector; + SetReferenceTransform(sector.Transform); + } + } +}