336 lines
10 KiB
C#
Raw Normal View History

2021-08-22 16:57:09 +01:00
using OWML.Common;
using QSB.Player;
2021-08-14 14:45:52 +01:00
using QSB.Player.TransformSync;
using QSB.Utility;
2021-07-17 09:51:47 +01:00
using QSB.WorldSync;
using QuantumUNET.Components;
2021-08-14 14:45:52 +01:00
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace QSB.Syncs
{
2021-08-14 14:45:52 +01:00
/*
* Rewrite number : 9
* God has cursed me for my hubris, and my work is never finished.
*/
2021-07-07 23:54:09 +01:00
public abstract class SyncBase : QNetworkTransform
{
private static readonly Dictionary<uint, Dictionary<Type, SyncBase>> _storedTransformSyncs = new Dictionary<uint, Dictionary<Type, SyncBase>>();
2021-08-14 14:45:52 +01:00
public static T GetPlayers<T>(PlayerInfo player)
where T : SyncBase
{
var dictOfOwnedSyncs = _storedTransformSyncs[player.PlayerId];
2021-08-14 14:45:52 +01:00
var wantedSync = dictOfOwnedSyncs[typeof(T)];
if (wantedSync == default)
{
DebugLog.ToConsole($"Error - _storedTransformSyncs does not contain type:{typeof(T)} under player {player.PlayerId}. Attempting to find manually...", MessageType.Error);
var allSyncs = QSBWorldSync.GetUnityObjects<T>();
2021-08-14 14:45:52 +01:00
wantedSync = allSyncs.First(x => x.Player == player);
if (wantedSync == default)
{
DebugLog.ToConsole($"Error - Could not find type:{typeof(T)} for player {player.PlayerId} manually!", MessageType.Error);
return default;
}
}
return (T)wantedSync;
}
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;
}
}
public PlayerInfo Player => QSBPlayerManager.GetPlayer(PlayerId);
2021-07-17 09:51:47 +01:00
private bool _baseIsReady => QSBPlayerManager.PlayerExists(PlayerId)
&& Player != null
&& Player.PlayerStates.IsReady
&& NetId.Value != uint.MaxValue
&& NetId.Value != 0U
&& WorldObjectManager.AllReady;
public abstract bool IsReady { get; }
public abstract bool UseInterpolation { get; }
2021-07-11 16:18:47 +01:00
public abstract bool IgnoreDisabledAttachedObject { get; }
public abstract bool IgnoreNullReferenceTransform { get; }
2021-08-14 14:45:52 +01:00
public abstract bool ShouldReparentAttachedObject { get; }
2021-07-07 23:54:09 +01:00
public Component AttachedObject { get; set; }
public Transform ReferenceTransform { get; set; }
2021-11-10 21:51:14 -08:00
public string LogName => $"{PlayerId}.{NetId.Value}:{GetType().Name}";
protected virtual float DistanceLeeway { get; } = 5f;
private float _previousDistance;
protected const float SmoothTime = 0.1f;
protected Vector3 _positionSmoothVelocity;
protected Quaternion _rotationSmoothVelocity;
protected IntermediaryTransform _intermediaryTransform;
protected bool _isInitialized;
2021-08-14 14:45:52 +01:00
protected abstract Component SetAttachedObject();
2021-07-11 16:18:47 +01:00
protected abstract bool UpdateTransform();
2021-08-14 14:45:52 +01:00
public virtual void Start()
{
var lowestBound = QSBWorldSync.GetUnityObjects<PlayerTransformSync>()
2021-08-14 14:45:52 +01:00
.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;
if (Player == null)
{
2021-11-10 21:51:14 -08:00
DebugLog.ToConsole($"Error - Player in start of {LogName} was null!", MessageType.Error);
2021-08-14 14:45:52 +01:00
return;
}
if (!_storedTransformSyncs.ContainsKey(PlayerId))
2021-08-14 14:45:52 +01:00
{
_storedTransformSyncs.Add(PlayerId, new Dictionary<Type, SyncBase>());
2021-08-14 14:45:52 +01:00
}
var playerDict = _storedTransformSyncs[PlayerId];
2021-08-14 14:45:52 +01:00
playerDict[GetType()] = this;
}
protected virtual void OnDestroy()
{
if (ShouldReparentAttachedObject)
{
if (!HasAuthority && AttachedObject != null)
{
Destroy(AttachedObject.gameObject);
}
}
QSBSceneManager.OnSceneLoaded -= OnSceneLoaded;
if (!QSBPlayerManager.PlayerExists(PlayerId))
{
return;
}
var playerDict = _storedTransformSyncs[PlayerId];
2021-08-14 14:45:52 +01:00
playerDict.Remove(GetType());
}
protected virtual void Init()
{
if (!QSBSceneManager.IsInUniverse)
{
2021-11-10 21:51:14 -08:00
DebugLog.ToConsole($"Error - {LogName} is being init-ed when not in the universe!", MessageType.Error);
2021-08-14 14:45:52 +01:00
}
// TODO : maybe make it's own option
if (ShouldReparentAttachedObject)
{
if (!HasAuthority && AttachedObject != null)
{
Destroy(AttachedObject.gameObject);
}
}
AttachedObject = SetAttachedObject();
_isInitialized = true;
}
2021-10-29 23:00:13 +01:00
protected virtual void OnSceneLoaded(OWScene oldScene, OWScene newScene, bool isInUniverse) => _isInitialized = false;
2021-07-07 23:04:00 +01:00
public override void Update()
{
2021-07-17 09:51:47 +01:00
if (!_isInitialized && IsReady && _baseIsReady)
2021-07-07 23:04:00 +01:00
{
try
{
Init();
}
catch (Exception ex)
{
DebugLog.ToConsole($"Exception when initializing {name} : {ex}", MessageType.Error);
enabled = false;
}
2021-07-17 09:51:47 +01:00
base.Update();
return;
2021-07-07 23:04:00 +01:00
}
2021-07-17 09:51:47 +01:00
else if (_isInitialized && (!IsReady || !_baseIsReady))
2021-07-07 23:04:00 +01:00
{
_isInitialized = false;
2021-07-11 16:18:47 +01:00
base.Update();
2021-07-07 23:04:00 +01:00
return;
}
if (!_isInitialized)
{
2021-07-11 16:18:47 +01:00
base.Update();
2021-07-07 23:04:00 +01:00
return;
}
if (AttachedObject == null)
{
2021-11-10 21:51:14 -08:00
DebugLog.ToConsole($"Warning - AttachedObject {LogName} is null.", MessageType.Warning);
2021-07-07 23:04:00 +01:00
_isInitialized = false;
2021-07-11 16:18:47 +01:00
base.Update();
2021-07-07 23:04:00 +01:00
return;
}
if (ReferenceTransform != null && ReferenceTransform.position == Vector3.zero)
{
2021-11-10 21:51:14 -08:00
DebugLog.ToConsole($"Warning - {LogName}'s ReferenceTransform is at (0,0,0). ReferenceTransform:{ReferenceTransform.name}, AttachedObject:{AttachedObject.name}", MessageType.Warning);
}
2021-07-11 16:18:47 +01:00
if (!AttachedObject.gameObject.activeInHierarchy && !IgnoreDisabledAttachedObject)
2021-07-07 23:04:00 +01:00
{
2021-07-11 16:18:47 +01:00
base.Update();
2021-07-07 23:04:00 +01:00
return;
}
2021-07-11 16:18:47 +01:00
if (ReferenceTransform == null && !IgnoreNullReferenceTransform)
2021-07-07 23:04:00 +01:00
{
2021-11-10 21:51:14 -08:00
DebugLog.ToConsole($"Warning - {LogName}'s ReferenceTransform is null. AttachedObject:{AttachedObject.name}", MessageType.Warning);
2021-07-11 16:18:47 +01:00
base.Update();
2021-07-07 23:04:00 +01:00
return;
}
2021-07-11 16:18:47 +01:00
if (ReferenceTransform != _intermediaryTransform.GetReferenceTransform())
{
2021-11-10 21:51:14 -08:00
DebugLog.ToConsole($"Warning - {LogName}'s ReferenceTransform does not match the reference transform set for the intermediary. ReferenceTransform null : {ReferenceTransform == null}, Intermediary reference null : {_intermediaryTransform.GetReferenceTransform() == null}");
2021-07-11 16:18:47 +01:00
base.Update();
return;
}
2021-10-23 21:17:49 +01:00
if (ShouldReparentAttachedObject
&& !HasAuthority
&& AttachedObject.transform.parent != ReferenceTransform)
{
2021-11-10 21:51:14 -08:00
DebugLog.ToConsole($"Warning : {LogName} : AttachedObject's parent is different to ReferenceTransform. Correcting...", MessageType.Warning);
2021-10-23 21:17:49 +01:00
ReparentAttachedObject(ReferenceTransform);
}
2021-09-13 19:21:40 +01:00
UpdateTransform();
2021-07-07 23:04:00 +01:00
base.Update();
}
2021-08-14 14:45:52 +01:00
protected Vector3 SmartSmoothDamp(Vector3 currentPosition, Vector3 targetPosition)
{
var distance = Vector3.Distance(currentPosition, targetPosition);
if (distance > _previousDistance + DistanceLeeway)
{
2021-08-19 16:32:18 +01:00
/*
DebugLog.DebugWrite($"{_logName} moved too far!" +
$"\r\n CurrentPosition:{currentPosition}," +
$"\r\n TargetPosition:{targetPosition}");
*/
2021-08-14 14:45:52 +01:00
_previousDistance = distance;
return targetPosition;
}
_previousDistance = distance;
return Vector3.SmoothDamp(currentPosition, targetPosition, ref _positionSmoothVelocity, SmoothTime);
}
public void SetReferenceTransform(Transform transform)
{
if (ReferenceTransform == transform)
{
return;
}
ReferenceTransform = transform;
_intermediaryTransform.SetReferenceTransform(transform);
if (ShouldReparentAttachedObject)
{
if (AttachedObject == null)
{
2021-11-10 21:51:14 -08: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-08-14 14:45:52 +01:00
QSBCore.UnityEvents.RunWhen(
() => AttachedObject != null,
() => ReparentAttachedObject(transform));
return;
}
if (!HasAuthority)
{
ReparentAttachedObject(transform);
}
}
if (HasAuthority)
{
_intermediaryTransform.EncodePosition(AttachedObject.transform.position);
_intermediaryTransform.EncodeRotation(AttachedObject.transform.rotation);
}
}
private void ReparentAttachedObject(Transform newParent)
{
if (AttachedObject.transform.parent != null && AttachedObject.transform.parent.GetComponent<Sector>() == null)
{
DebugLog.ToConsole($"Warning - Trying to reparent AttachedObject {AttachedObject.name} which wasnt attached to sector!", MessageType.Warning);
}
AttachedObject.transform.SetParent(newParent, true);
AttachedObject.transform.localScale = Vector3.one;
}
protected virtual void OnRenderObject()
{
if (!QSBCore.WorldObjectsReady
|| !QSBCore.DebugMode
|| !QSBCore.ShowLinesInDebug
|| !IsReady
2021-07-11 16:18:47 +01:00
|| ReferenceTransform == null
|| _intermediaryTransform.GetReferenceTransform() == null)
{
return;
}
/* Red Cube = Where visible object should be
* Green/Yellow Cube = Where visible object is
* Magenta cube = Reference transform
* Red Line = Connection between Red Cube and Green/Yellow Cube
* Cyan Line = Connection between Green/Yellow cube and reference transform
*/
2021-07-19 14:58:59 +01:00
Popcron.Gizmos.Cube(_intermediaryTransform.GetTargetPosition_Unparented(), _intermediaryTransform.GetTargetRotation_Unparented(), Vector3.one / 4, Color.red);
Popcron.Gizmos.Line(_intermediaryTransform.GetTargetPosition_Unparented(), AttachedObject.transform.position, Color.red);
var color = HasMoved() ? Color.green : Color.yellow;
2021-07-19 14:58:59 +01:00
Popcron.Gizmos.Cube(AttachedObject.transform.position, AttachedObject.transform.rotation, Vector3.one / 4, color);
Popcron.Gizmos.Cube(ReferenceTransform.position, ReferenceTransform.rotation, Vector3.one / 4, Color.magenta);
Popcron.Gizmos.Line(AttachedObject.transform.position, ReferenceTransform.position, Color.cyan);
}
}
}