269 lines
7.3 KiB
C#
Raw Normal View History

2021-08-22 16:57:09 +01:00
using OWML.Common;
using QSB.Player;
using QSB.Utility;
2021-07-17 09:51:47 +01:00
using QSB.WorldSync;
2021-08-14 14:45:52 +01:00
using System;
using System.Linq;
using UnityEngine;
namespace QSB.Syncs
{
2022-01-14 22:39:41 -08:00
/*
2022-01-14 22:41:36 -08:00
* Rewrite number : 10
2022-01-14 22:39:41 -08:00
* God has cursed me for my hubris, and my work is never finished.
*/
public abstract class SyncBase : QSBNetworkTransform
2022-01-14 20:59:42 -08:00
{
/// <summary>
/// valid if IsPlayerObject, otherwise null
/// </summary>
public PlayerInfo Player { get; private set; }
private bool _baseIsReady
{
get
{
if (netId is uint.MaxValue or 0)
{
return false;
}
if (!WorldObjectManager.AllObjectsAdded)
{
return false;
}
if (IsPlayerObject)
{
if (!Player.IsReady && !isLocalPlayer)
{
return false;
}
}
return true;
}
}
2022-01-16 06:11:44 -08:00
protected abstract bool IsReady { get; }
protected abstract bool UseInterpolation { get; }
protected abstract bool AllowDisabledAttachedObject { get; }
protected abstract bool AllowNullReferenceTransform { get; }
protected abstract bool DestroyAttachedObject { get; }
protected abstract bool IsPlayerObject { get; }
protected virtual bool OnlyUpdateOnDeserialize => false;
2022-01-14 20:59:42 -08:00
2022-01-16 05:38:06 -08:00
public Transform AttachedTransform { get; private set; }
public Transform ReferenceTransform { get; private set; }
2022-01-14 20:59:42 -08:00
public string LogName => (IsPlayerObject ? $"{Player.PlayerId}." : string.Empty) + $"{netId}:{GetType().Name}";
protected virtual float DistanceLeeway => 5f;
2022-01-16 04:34:52 -08:00
protected virtual float AngleLeeway => 5f;
2022-01-14 20:59:42 -08:00
private float _previousDistance;
2022-01-16 04:34:52 -08:00
private float _previousAngle;
2022-01-14 20:59:42 -08:00
protected const float SmoothTime = 0.1f;
private Vector3 _positionSmoothVelocity;
private Quaternion _rotationSmoothVelocity;
2022-01-16 05:38:06 -08:00
public bool IsInitialized { get; private set; }
2022-01-14 20:59:42 -08:00
protected Vector3 SmoothPosition;
protected Quaternion SmoothRotation;
2022-01-16 04:34:52 -08:00
protected abstract Transform InitAttachedTransform();
2022-01-16 06:11:44 -08:00
// protected abstract bool GetFromAttached();
// protected abstract bool ApplyToAttached();
2022-01-14 20:59:42 -08:00
protected abstract bool UpdateTransform();
public virtual void Start()
{
if (IsPlayerObject)
{
// get player objects spawned before this object (or is this one)
// and use the closest one
Player = QSBPlayerManager.PlayerList
.Where(x => x.PlayerId <= netId)
.OrderBy(x => x.PlayerId).Last();
}
DontDestroyOnLoad(gameObject);
QSBSceneManager.OnSceneLoaded += OnSceneLoaded;
}
protected virtual void OnDestroy()
{
2022-01-16 04:34:52 -08:00
if (DestroyAttachedObject && !hasAuthority && AttachedTransform != null)
2022-01-14 20:59:42 -08:00
{
2022-01-16 04:34:52 -08:00
Destroy(AttachedTransform.gameObject);
2022-01-14 20:59:42 -08:00
}
QSBSceneManager.OnSceneLoaded -= OnSceneLoaded;
}
protected virtual void Init()
{
if (!QSBSceneManager.IsInUniverse)
{
DebugLog.ToConsole($"Error - {LogName} is being init-ed when not in the universe!", MessageType.Error);
}
2022-01-16 04:34:52 -08:00
if (DestroyAttachedObject && !hasAuthority && AttachedTransform != null)
2022-01-14 20:59:42 -08:00
{
2022-01-16 04:34:52 -08:00
Destroy(AttachedTransform.gameObject);
2022-01-14 20:59:42 -08:00
}
2022-01-16 04:34:52 -08:00
AttachedTransform = InitAttachedTransform();
IsInitialized = true;
2022-01-14 20:59:42 -08:00
}
2022-01-16 04:34:52 -08:00
protected virtual void OnSceneLoaded(OWScene oldScene, OWScene newScene, bool isInUniverse) => IsInitialized = false;
2022-01-14 20:59:42 -08:00
2022-01-16 06:11:44 -08:00
protected sealed override void Update()
2022-01-14 20:59:42 -08:00
{
2022-01-16 04:34:52 -08:00
if (!IsInitialized && IsReady && _baseIsReady)
2022-01-14 20:59:42 -08:00
{
try
{
Init();
}
catch (Exception ex)
{
DebugLog.ToConsole($"Exception when initializing {name} : {ex}", MessageType.Error);
return;
2022-01-14 20:59:42 -08:00
}
}
2022-01-16 04:34:52 -08:00
else if (IsInitialized && (!IsReady || !_baseIsReady))
2022-01-14 20:59:42 -08:00
{
2022-01-16 04:34:52 -08:00
IsInitialized = false;
2022-01-14 20:59:42 -08:00
return;
}
2022-01-16 04:34:52 -08:00
if (!IsInitialized)
2022-01-14 20:59:42 -08:00
{
return;
}
if (AttachedTransform == null)
{
DebugLog.ToConsole($"Warning - AttachedObject {LogName} is null.", MessageType.Warning);
2022-01-16 04:34:52 -08:00
IsInitialized = false;
2022-01-14 20:59:42 -08:00
return;
}
2022-01-16 04:52:48 -08:00
if (!AttachedTransform.gameObject.activeInHierarchy && !AllowDisabledAttachedObject)
2022-01-14 20:59:42 -08:00
{
return;
}
2022-01-16 04:52:48 -08:00
if (ReferenceTransform == null && !AllowNullReferenceTransform)
2022-01-14 20:59:42 -08:00
{
2022-01-16 04:34:52 -08:00
DebugLog.ToConsole($"Warning - {LogName}'s ReferenceTransform is null. AttachedObject:{AttachedTransform.name}", MessageType.Warning);
return;
2022-01-14 20:59:42 -08:00
}
2022-01-16 04:34:52 -08:00
if (ReferenceTransform != null && ReferenceTransform.position == Vector3.zero && ReferenceTransform != Locator.GetRootTransform())
2022-01-14 20:59:42 -08:00
{
2022-01-16 04:34:52 -08:00
DebugLog.ToConsole($"Warning - {LogName}'s ReferenceTransform is at (0,0,0). ReferenceTransform:{ReferenceTransform.name}, AttachedObject:{AttachedTransform.name}", MessageType.Warning);
2022-01-14 20:59:42 -08:00
}
2022-01-16 04:34:52 -08:00
if (ReferenceTransform == Locator.GetRootTransform())
2022-01-14 20:59:42 -08:00
{
return;
}
if (!hasAuthority && UseInterpolation)
{
SmoothPosition = SmartSmoothDamp(SmoothPosition, transform.position);
SmoothRotation = SmartSmoothDamp(SmoothRotation, transform.rotation);
}
UpdateTransform();
base.Update();
}
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 Quaternion SmartSmoothDamp(Quaternion currentRotation, Quaternion targetRotation)
{
2022-01-16 04:34:52 -08:00
var angle = Quaternion.Angle(currentRotation, targetRotation);
if (angle > _previousAngle + AngleLeeway)
{
_previousAngle = angle;
return targetRotation;
}
_previousAngle = angle;
2022-01-14 20:59:42 -08:00
return QuaternionHelper.SmoothDamp(currentRotation, targetRotation, ref _rotationSmoothVelocity, SmoothTime);
}
public void SetReferenceTransform(Transform referenceTransform)
{
if (ReferenceTransform == referenceTransform)
{
return;
}
ReferenceTransform = referenceTransform;
if (hasAuthority)
{
transform.position = ReferenceTransform.ToRelPos(AttachedTransform.position);
transform.rotation = ReferenceTransform.ToRelRot(AttachedTransform.rotation);
}
else if (UseInterpolation)
{
SmoothPosition = ReferenceTransform.ToRelPos(AttachedTransform.position);
SmoothRotation = ReferenceTransform.ToRelRot(AttachedTransform.rotation);
}
}
protected virtual void OnRenderObject()
{
if (!QSBCore.ShowLinesInDebug
2022-01-16 04:34:52 -08:00
|| !IsInitialized
2022-01-14 20:59:42 -08:00
|| AttachedTransform == null
|| ReferenceTransform == null)
{
return;
}
/* Red Cube = Where visible object should be
* Green cube = Where visible object is
* Magenta cube = Reference transform
* Red Line = Connection between Red Cube and Green Cube
* Cyan Line = Connection between Green cube and reference transform
*/
Popcron.Gizmos.Cube(ReferenceTransform.FromRelPos(transform.position), ReferenceTransform.FromRelRot(transform.rotation), Vector3.one / 8, Color.red);
Popcron.Gizmos.Line(ReferenceTransform.FromRelPos(transform.position), AttachedTransform.transform.position, Color.red);
Popcron.Gizmos.Cube(AttachedTransform.transform.position, AttachedTransform.transform.rotation, Vector3.one / 6, Color.green);
Popcron.Gizmos.Cube(ReferenceTransform.position, ReferenceTransform.rotation, Vector3.one / 8, Color.magenta);
Popcron.Gizmos.Line(AttachedTransform.transform.position, ReferenceTransform.position, Color.cyan);
}
private void OnGUI()
{
if (!QSBCore.ShowDebugLabels ||
Event.current.type != EventType.Repaint)
{
return;
}
if (AttachedTransform != null)
{
DebugGUI.DrawLabel(AttachedTransform.transform, LogName);
}
}
}
}