2021-04-21 11:02:17 +01:00
using OWML.Common ;
using QSB.Player ;
using QSB.Player.TransformSync ;
using QSB.Utility ;
using QuantumUNET.Components ;
using QuantumUNET.Transport ;
using System.Linq ;
using UnityEngine ;
2021-05-02 13:59:39 +01:00
namespace QSB.Syncs.TransformSync
2021-04-21 11:02:17 +01:00
{
2021-05-15 11:25:47 +01:00
public abstract class UnparentedBaseTransformSync : QNetworkTransform , ISync < GameObject >
2021-04-21 11:02:17 +01:00
{
2021-05-19 11:44:27 +01:00
public uint AttachedNetId
{
get
{
if ( NetIdentity = = null )
{
DebugLog . ToConsole ( $"Error - Trying to get AttachedNetId with null NetIdentity! Type:{GetType().Name} GrandType:{GetType().GetType().Name}" , MessageType . Error ) ;
return uint . MaxValue ;
}
return NetIdentity . NetId . Value ;
}
}
public uint PlayerId
{
get
{
if ( NetIdentity = = null )
{
DebugLog . ToConsole ( $"Error - Trying to get PlayerId with null NetIdentity! Type:{GetType().Name} GrandType:{GetType().GetType().Name}" , MessageType . Error ) ;
return uint . MaxValue ;
}
return NetIdentity . RootIdentity ! = null
? NetIdentity . RootIdentity . NetId . Value
: AttachedNetId ;
}
}
2021-04-21 11:02:17 +01:00
public PlayerInfo Player = > QSBPlayerManager . GetPlayer ( PlayerId ) ;
2021-04-28 10:02:16 +01:00
public Transform ReferenceTransform { get ; set ; }
2021-04-21 11:02:17 +01:00
public GameObject AttachedObject { get ; set ; }
public abstract bool IsReady { get ; }
2021-04-28 10:02:16 +01:00
public abstract bool UseInterpolation { get ; }
2021-04-21 11:02:17 +01:00
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-28 10:02:16 +01:00
protected IntermediaryTransform _intermediaryTransform ;
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 ) ;
DontDestroyOnLoad ( gameObject ) ;
2021-04-27 22:09:57 +01:00
_intermediaryTransform = new IntermediaryTransform ( transform ) ;
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 )
{
2021-05-19 11:17:37 +01:00
Destroy ( AttachedObject . gameObject ) ;
2021-04-22 20:42:38 +01:00
}
QSBSceneManager . OnSceneLoaded - = OnSceneLoaded ;
}
2021-04-29 23:57:55 +01:00
protected void OnSceneLoaded ( OWScene scene , bool isInUniverse ) = >
2021-04-22 20:42:38 +01:00
_isInitialized = false ;
2021-04-28 10:02:16 +01:00
protected virtual void Init ( )
2021-04-21 11:02:17 +01:00
{
AttachedObject = HasAuthority ? InitLocalTransform ( ) : InitRemoteTransform ( ) ;
_isInitialized = true ;
}
public override void SerializeTransform ( QNetworkWriter writer )
{
2021-04-27 22:09:57 +01:00
if ( _intermediaryTransform = = null )
{
_intermediaryTransform = new IntermediaryTransform ( transform ) ;
}
2021-04-21 11:02:17 +01:00
2021-04-27 22:09:57 +01:00
var worldPos = _intermediaryTransform . GetPosition ( ) ;
var worldRot = _intermediaryTransform . GetRotation ( ) ;
writer . Write ( worldPos ) ;
SerializeRotation ( writer , worldRot ) ;
_prevPosition = worldPos ;
_prevRotation = worldRot ;
2021-04-21 11:02:17 +01:00
}
public override void DeserializeTransform ( QNetworkReader reader )
{
2021-05-08 16:57:01 +01:00
if ( ! QSBCore . WorldObjectsReady )
2021-04-21 11:02:17 +01:00
{
reader . ReadVector3 ( ) ;
DeserializeRotation ( reader ) ;
return ;
}
2021-04-26 14:30:21 +01:00
var pos = reader . ReadVector3 ( ) ;
var rot = DeserializeRotation ( reader ) ;
2021-04-21 11:02:17 +01:00
if ( HasAuthority )
{
return ;
}
2021-04-28 13:37:51 +01:00
if ( _intermediaryTransform = = null )
{
_intermediaryTransform = new IntermediaryTransform ( transform ) ;
}
2021-04-27 22:09:57 +01:00
_intermediaryTransform . SetPosition ( pos ) ;
_intermediaryTransform . SetRotation ( rot ) ;
2021-04-21 11:02:17 +01:00
2021-04-27 22:09:57 +01:00
if ( _intermediaryTransform . GetPosition ( ) = = Vector3 . zero )
2021-04-21 11:02:17 +01:00
{
2021-04-28 10:02:16 +01:00
DebugLog . ToConsole ( $"Warning - {PlayerId}.{GetType().Name} at (0,0,0)! - Given position was {pos}" , MessageType . Warning ) ;
2021-04-21 11:02:17 +01:00
}
}
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 ;
}
2021-05-19 11:43:39 +01:00
if ( ReferenceTransform = = null )
{
return ;
}
2021-04-21 11:02:17 +01:00
UpdateTransform ( ) ;
base . Update ( ) ;
}
protected virtual void UpdateTransform ( )
{
if ( HasAuthority )
{
2021-04-27 22:09:57 +01:00
_intermediaryTransform . EncodePosition ( AttachedObject . transform . position ) ;
_intermediaryTransform . EncodeRotation ( AttachedObject . transform . rotation ) ;
2021-04-28 10:02:16 +01:00
return ;
2021-04-21 11:02:17 +01:00
}
2021-04-28 10:02:16 +01:00
var targetPos = _intermediaryTransform . GetTargetPosition_Unparented ( ) ;
var targetRot = _intermediaryTransform . GetTargetRotation_Unparented ( ) ;
if ( targetPos ! = Vector3 . zero & & _intermediaryTransform . GetTargetPosition_ParentedToReference ( ) ! = Vector3 . zero )
{
if ( UseInterpolation )
{
AttachedObject . transform . position = SmartSmoothDamp ( AttachedObject . transform . position , targetPos ) ;
AttachedObject . transform . rotation = QuaternionHelper . SmoothDamp ( AttachedObject . transform . rotation , targetRot , ref _rotationSmoothVelocity , SmoothTime ) ;
}
else
{
AttachedObject . transform . position = targetPos ;
AttachedObject . transform . rotation = targetRot ;
}
2021-04-21 11:02:17 +01:00
}
}
2021-04-21 11:28:45 +01:00
public override bool HasMoved ( )
{
2021-04-27 22:09:57 +01:00
var displacementMagnitude = ( _intermediaryTransform . GetPosition ( ) - _prevPosition ) . magnitude ;
2021-04-23 16:55:57 +01:00
return displacementMagnitude > 1E-03f
2021-04-27 22:09:57 +01:00
| | Quaternion . Angle ( _intermediaryTransform . GetRotation ( ) , _prevRotation ) > 1E-03f ;
2021-04-21 11:28:45 +01:00
}
2021-04-28 10:02:16 +01:00
public void SetReferenceTransform ( Transform transform )
2021-04-23 16:55:57 +01:00
{
2021-04-28 10:02:16 +01:00
if ( ReferenceTransform = = transform )
2021-04-26 14:30:21 +01:00
{
return ;
}
2021-04-28 10:02:16 +01:00
ReferenceTransform = transform ;
_intermediaryTransform . SetReferenceTransform ( transform ) ;
2021-04-21 11:28:45 +01:00
}
2021-05-26 20:42:47 +01:00
// TODO : remove .Distance
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 )
{
2021-05-26 20:42:47 +01:00
DebugLog . DebugWrite ( $"Warning - {AttachedObject.name} moved too far!" , MessageType . Warning ) ;
2021-04-21 11:28:45 +01:00
_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 ( )
{
2021-05-19 11:43:39 +01:00
if ( ! QSBCore . WorldObjectsReady
| | ! QSBCore . DebugMode
| | ! QSBCore . ShowLinesInDebug
| | ! IsReady
| | ReferenceTransform = = null )
2021-04-21 11:02:17 +01:00
{
return ;
}
2021-05-10 20:26:44 +01:00
Popcron . Gizmos . Cube ( _intermediaryTransform . GetTargetPosition_Unparented ( ) , _intermediaryTransform . GetTargetRotation_Unparented ( ) , Vector3 . one / 2 , Color . red ) ;
Popcron . Gizmos . Line ( _intermediaryTransform . GetTargetPosition_Unparented ( ) , AttachedObject . transform . position , Color . red ) ;
2021-04-23 16:55:57 +01:00
var color = HasMoved ( ) ? Color . green : Color . yellow ;
Popcron . Gizmos . Cube ( AttachedObject . transform . position , AttachedObject . transform . rotation , Vector3 . one / 2 , color ) ;
2021-04-28 10:02:16 +01:00
Popcron . Gizmos . Line ( AttachedObject . transform . position , ReferenceTransform . position , Color . cyan ) ;
2021-04-21 11:02:17 +01:00
}
}
}