2021-04-21 11:02:17 +01:00
using OWML.Common ;
using QSB.Player ;
using QSB.Player.TransformSync ;
using QSB.SectorSync.WorldObjects ;
using QSB.Utility ;
using QSB.WorldSync ;
using QuantumUNET.Components ;
using QuantumUNET.Transport ;
using System.Linq ;
using UnityEngine ;
namespace QSB.TransformSync
{
public abstract class QSBNetworkTransform : 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 QSBSector ReferenceSector { get ; set ; }
public GameObject AttachedObject { get ; set ; }
public SectorSync . SectorSync SectorSync { get ; private set ; }
public abstract bool IsReady { get ; }
protected abstract GameObject InitLocalTransform ( ) ;
protected abstract GameObject InitRemoteTransform ( ) ;
private bool _isInitialized ;
2021-04-21 11:28:45 +01:00
private const float SmoothTime = 0.1f ;
2021-04-21 16:49:30 +01:00
protected virtual float DistanceLeeway { get ; } = 5f ;
2021-04-21 11:28:45 +01:00
private float _previousDistance ;
private Vector3 _positionSmoothVelocity ;
private Quaternion _rotationSmoothVelocity ;
2021-04-21 11:02:17 +01:00
public virtual void Start ( )
{
var lowestBound = Resources . FindObjectsOfTypeAll < PlayerTransformSync > ( )
. Where ( x = > x . NetId . Value < = NetId . Value ) . OrderBy ( x = > x . NetId . Value ) . Last ( ) ;
NetIdentity . SetRootIdentity ( lowestBound . NetIdentity ) ;
SectorSync = gameObject . AddComponent < SectorSync . SectorSync > ( ) ;
DontDestroyOnLoad ( gameObject ) ;
2021-04-22 20:42:38 +01:00
QSBSceneManager . OnSceneLoaded + = OnSceneLoaded ;
2021-04-21 11:02:17 +01:00
}
2021-04-22 20:42:38 +01:00
protected virtual void OnDestroy ( )
{
if ( ! HasAuthority & & AttachedObject ! = null )
{
DebugLog . DebugWrite ( $"Destroying {AttachedObject.name}" ) ;
Destroy ( AttachedObject ) ;
}
QSBSceneManager . OnSceneLoaded - = OnSceneLoaded ;
if ( SectorSync ! = null )
{
Destroy ( SectorSync ) ;
}
}
private void OnSceneLoaded ( OWScene scene , bool isInUniverse ) = >
_isInitialized = false ;
2021-04-21 11:02:17 +01:00
protected void Init ( )
{
AttachedObject = HasAuthority ? InitLocalTransform ( ) : InitRemoteTransform ( ) ;
SetReferenceSector ( SectorSync . GetClosestSector ( AttachedObject . transform ) ) ;
_isInitialized = true ;
}
public override void SerializeTransform ( QNetworkWriter writer )
{
if ( ReferenceSector ! = null )
{
writer . Write ( ReferenceSector . ObjectId ) ;
}
else
{
writer . Write ( - 1 ) ;
}
writer . Write ( transform . localPosition ) ;
SerializeRotation ( writer , transform . localRotation ) ;
_prevPosition = transform . localPosition ;
_prevRotation = transform . localRotation ;
}
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 < QSBSector > ( sectorId ) ;
if ( sector ! = ReferenceSector )
{
SetReferenceSector ( sector ) ;
}
var localPosition = reader . ReadVector3 ( ) ;
var localRotation = DeserializeRotation ( reader ) ;
if ( HasAuthority )
{
return ;
}
transform . localPosition = localPosition ;
transform . localRotation = localRotation ;
if ( transform . position = = Vector3 . zero )
{
DebugLog . ToConsole ( $"Warning - {PlayerId}.{GetType().Name} at (0,0,0)! - Given localPosition was {localPosition} at sector {sector?.Name}" , 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 )
{
transform . position = AttachedObject . transform . position ;
transform . rotation = AttachedObject . transform . rotation ;
}
else
{
2021-04-21 11:28:45 +01:00
AttachedObject . transform . localPosition = SmartSmoothDamp ( AttachedObject . transform . localPosition , transform . localPosition ) ;
AttachedObject . transform . localRotation = QuaternionHelper . SmoothDamp ( AttachedObject . transform . localRotation , transform . localRotation , ref _rotationSmoothVelocity , SmoothTime ) ;
2021-04-21 11:02:17 +01:00
}
}
2021-04-21 11:28:45 +01:00
public override bool HasMoved ( )
{
var displacementMagnitude = ( transform . localPosition - _prevPosition ) . magnitude ;
return displacementMagnitude > 1E-05f
| | Quaternion . Angle ( transform . localRotation , _prevRotation ) > 1E-05f ;
}
2021-04-21 11:02:17 +01:00
public void SetReferenceSector ( QSBSector sector )
{
if ( ReferenceSector = = sector )
{
return ;
}
ReferenceSector = sector ;
transform . SetParent ( sector . Transform , true ) ;
2021-04-21 22:26:12 +01:00
if ( ! HasAuthority & & AttachedObject ! = null )
2021-04-21 11:28:45 +01:00
{
AttachedObject . transform . SetParent ( sector . Transform , true ) ;
2021-04-21 22:26:12 +01:00
AttachedObject . transform . localScale = GetType ( ) = = typeof ( PlayerTransformSync )
? Vector3 . one / 10
: Vector3 . one ;
2021-04-21 11:28:45 +01:00
}
}
private Vector3 SmartSmoothDamp ( Vector3 currentPosition , Vector3 targetPosition )
{
var distance = Vector3 . Distance ( currentPosition , targetPosition ) ;
if ( distance > _previousDistance + DistanceLeeway )
{
// moved too far! assume sector sync warp / actual warp
_previousDistance = distance ;
return targetPosition ;
}
_previousDistance = distance ;
return Vector3 . SmoothDamp ( currentPosition , targetPosition , ref _positionSmoothVelocity , SmoothTime ) ;
2021-04-21 11:02:17 +01:00
}
private void OnRenderObject ( )
{
if ( ! QSBCore . HasWokenUp | | ! QSBCore . DebugMode | | ! QSBCore . ShowLinesInDebug | | ! IsReady )
{
return ;
}
Popcron . Gizmos . Cube ( transform . position , transform . rotation , Vector3 . one / 2 , Color . red ) ;
Popcron . Gizmos . Cube ( AttachedObject . transform . position , AttachedObject . transform . rotation , Vector3 . one / 2 , Color . green ) ;
Popcron . Gizmos . Line ( AttachedObject . transform . position , ReferenceSector . Transform . position , Color . cyan ) ;
}
}
}