2021-04-28 00:22:08 +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-28 00:22:08 +01:00
{
2021-04-28 10:02:16 +01:00
/ *
2021-05-15 11:25:47 +01:00
* Rewrite number : 5
2021-04-28 10:02:16 +01:00
* God has cursed me for my hubris , and my work is never finished .
* /
2021-05-15 11:25:47 +01:00
public abstract class BaseTransformSync : QNetworkTransform , ISync < Transform >
2021-04-28 00:22:08 +01:00
{
2021-05-19 11:36:08 +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-28 00:22:08 +01:00
public PlayerInfo Player = > QSBPlayerManager . GetPlayer ( PlayerId ) ;
public Transform ReferenceTransform { get ; set ; }
2021-05-15 11:25:47 +01:00
public Transform AttachedObject { get ; set ; }
2021-04-28 00:22:08 +01:00
public abstract bool IsReady { get ; }
2021-04-28 10:02:16 +01:00
public abstract bool UseInterpolation { get ; }
2021-04-28 00:22:08 +01:00
2021-05-15 11:25:47 +01:00
protected abstract Transform InitLocalTransform ( ) ;
protected abstract Transform InitRemoteTransform ( ) ;
2021-04-28 00:22:08 +01:00
2021-05-02 08:54:00 +01:00
protected bool _isInitialized ;
2021-04-28 00:22:08 +01:00
private const float SmoothTime = 0.1f ;
protected virtual float DistanceLeeway { get ; } = 5f ;
private float _previousDistance ;
private Vector3 _positionSmoothVelocity ;
private Quaternion _rotationSmoothVelocity ;
2021-05-08 00:10:30 +01:00
private string _logName = > $"{PlayerId}.{GetType().Name}" ;
2021-04-28 00:22:08 +01:00
protected IntermediaryTransform _intermediaryTransform ;
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 ) ;
_intermediaryTransform = new IntermediaryTransform ( transform ) ;
QSBSceneManager . OnSceneLoaded + = OnSceneLoaded ;
}
protected virtual void OnDestroy ( )
{
if ( ! HasAuthority & & AttachedObject ! = null )
{
2021-05-19 11:17:37 +01:00
Destroy ( AttachedObject . gameObject ) ;
2021-04-28 00:22:08 +01:00
}
QSBSceneManager . OnSceneLoaded - = OnSceneLoaded ;
}
2021-05-08 00:10:30 +01:00
private void OnSceneLoaded ( OWScene scene , bool isInUniverse )
= > _isInitialized = false ;
2021-04-28 00:22:08 +01:00
protected virtual void Init ( )
{
2021-05-08 00:10:30 +01:00
if ( ! QSBSceneManager . IsInUniverse )
{
DebugLog . ToConsole ( $"Error - {_logName} is being init-ed when not in the universe!" , MessageType . Error ) ;
}
2021-05-02 09:09:37 +01:00
if ( ! HasAuthority & & AttachedObject ! = null )
2021-05-02 08:54:00 +01:00
{
2021-05-19 11:17:37 +01:00
Destroy ( AttachedObject . gameObject ) ;
2021-05-02 08:54:00 +01:00
}
2021-04-28 00:22:08 +01:00
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 )
{
2021-05-08 16:57:01 +01:00
if ( ! QSBCore . WorldObjectsReady )
2021-04-28 00:22:08 +01:00
{
reader . ReadVector3 ( ) ;
DeserializeRotation ( reader ) ;
return ;
}
var pos = reader . ReadVector3 ( ) ;
var rot = DeserializeRotation ( reader ) ;
if ( HasAuthority )
{
return ;
}
2021-04-28 13:37:51 +01:00
if ( _intermediaryTransform = = null )
{
_intermediaryTransform = new IntermediaryTransform ( transform ) ;
}
2021-04-28 00:22:08 +01:00
_intermediaryTransform . SetPosition ( pos ) ;
_intermediaryTransform . SetRotation ( rot ) ;
if ( _intermediaryTransform . GetPosition ( ) = = Vector3 . zero )
{
2021-05-08 00:10:30 +01:00
DebugLog . ToConsole ( $"Warning - {_logName} at (0,0,0)! - Given position was {pos}" , MessageType . Warning ) ;
2021-04-28 00:22:08 +01:00
}
}
public override void Update ( )
{
if ( ! _isInitialized & & IsReady )
{
Init ( ) ;
}
else if ( _isInitialized & & ! IsReady )
{
_isInitialized = false ;
return ;
}
if ( ! _isInitialized )
{
return ;
}
if ( AttachedObject = = null )
{
2021-05-08 00:10:30 +01:00
DebugLog . ToConsole ( $"Warning - AttachedObject {_logName} is null." , MessageType . Warning ) ;
return ;
}
2021-05-15 11:25:47 +01:00
if ( ! AttachedObject . gameObject . activeInHierarchy )
2021-05-08 00:10:30 +01:00
{
2021-04-28 00:22:08 +01:00
return ;
}
2021-05-19 11:43:39 +01:00
if ( ReferenceTransform = = null )
{
return ;
}
2021-04-28 00:22:08 +01:00
UpdateTransform ( ) ;
base . Update ( ) ;
}
protected virtual void UpdateTransform ( )
{
if ( HasAuthority )
{
_intermediaryTransform . EncodePosition ( AttachedObject . transform . position ) ;
_intermediaryTransform . EncodeRotation ( AttachedObject . transform . rotation ) ;
2021-04-28 10:02:16 +01:00
return ;
2021-04-28 00:22:08 +01:00
}
2021-04-28 10:02:16 +01:00
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 ;
}
2021-04-28 00:22:08 +01:00
}
}
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 )
{
2021-05-19 12:12:13 +01:00
DebugLog . ToConsole ( $"Warning - AttachedObject was null for {_logName} when trying to set reference transform to {transform?.name}. Waiting until not null..." , MessageType . Warning ) ;
2021-04-28 00:22:08 +01:00
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 < Sector > ( ) = = null )
{
2021-04-28 10:02:16 +01:00
DebugLog . ToConsole ( $"Warning - Trying to reparent AttachedObject {AttachedObject.name} which wasnt attached to sector!" , MessageType . Warning ) ;
2021-04-28 00:22:08 +01:00
}
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 ( )
{
2021-05-19 11:43:39 +01:00
if ( ! QSBCore . WorldObjectsReady
| | ! QSBCore . DebugMode
| | ! QSBCore . ShowLinesInDebug
| | ! IsReady
| | ReferenceTransform = = null )
2021-05-10 20:26:44 +01:00
{
return ;
}
2021-04-28 10:02:16 +01:00
Popcron . Gizmos . Cube ( _intermediaryTransform . GetTargetPosition_Unparented ( ) , _intermediaryTransform . GetTargetRotation_Unparented ( ) , Vector3 . one / 2 , Color . red ) ;
2021-05-10 20:26:44 +01:00
Popcron . Gizmos . Line ( _intermediaryTransform . GetTargetPosition_Unparented ( ) , AttachedObject . transform . position , Color . red ) ;
2021-04-28 00:22:08 +01:00
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 ) ;
}
}
}