StationObscurum/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObjectOwnerSmoother.cs

299 lines
11 KiB
C#

using FishNet.Utility.Extension;
using FishNet.Object;
using System.Runtime.CompilerServices;
using UnityEngine;
namespace FishNet.Component.Prediction
{
internal class PredictedObjectOwnerSmoother
{
#region Serialized.
/// <summary>
/// Transform which holds the graphical features of this object. This transform will be smoothed when desynchronizations occur.
/// </summary>
private Transform _graphicalObject;
/// <summary>
/// Sets GraphicalObject.
/// </summary>
/// <param name="value"></param>
public void SetGraphicalObject(Transform value)
{
_graphicalObject = value;
_networkBehaviour.transform.SetTransformOffsets(value, ref _graphicalInstantiatedOffsetPosition, ref _graphicalInstantiatedOffsetRotation);
}
/// <summary>
/// NetworkBehaviour which is using this object.
/// </summary>
private NetworkBehaviour _networkBehaviour;
/// <summary>
/// How far the transform must travel in a single update to cause a teleport rather than smoothing. Using 0f will teleport every update.
/// </summary>
private float _teleportThreshold = 1f;
/// <summary>
/// How far in the past to keep the graphical object when owner.
/// </summary>
private byte _interpolation = 1;
/// <summary>
/// Sets the interpolation value to use when the owner of this object.
/// </summary>
/// <param name="value"></param>
public void SetInterpolation(byte value) => _interpolation = value;
#endregion
#region Private.
/// <summary>
/// World position before transform was predicted or reset.
/// </summary>
private Vector3 _graphicalStartPosition;
/// <summary>
/// World rotation before transform was predicted or reset.
/// </summary>
private Quaternion _graphicalStartRotation;
/// <summary>
/// GraphicalObject position difference from the PredictedObject when this is initialized.
/// </summary>
private Vector3 _graphicalInstantiatedOffsetPosition;
/// <summary>
/// How quickly to move towards TargetPosition.
/// </summary>
private float _positionMoveRate = -2;
/// <summary>
/// GraphicalObject rotation difference from the PredictedObject when this is initialized.
/// </summary>
private Quaternion _graphicalInstantiatedOffsetRotation;
/// <summary>
/// How quickly to move towards TargetRotation.
/// </summary>
private float _rotationMoveRate = -2;
/// <summary>
/// True if OnPreTick was received this frame.
/// </summary>
private bool _preTickReceived;
/// <summary>
/// True to move towards position goals.
/// </summary>
private bool _smoothPosition;
/// <summary>
/// True to move towards rotation goals.
/// </summary>
private bool _smoothRotation;
#endregion
/// <summary>
/// Initializes this script for use.
/// </summary>
public void Initialize(NetworkBehaviour nb, Vector3 instantiatedOffsetPosition, Quaternion instantiatedOffsetRotation, Transform graphicalObject
, bool smoothPosition, bool smoothRotation, byte interpolation, float teleportThreshold)
{
_networkBehaviour = nb;
_graphicalInstantiatedOffsetPosition = instantiatedOffsetPosition;
_graphicalInstantiatedOffsetRotation = instantiatedOffsetRotation;
_graphicalObject = graphicalObject;
_smoothPosition = smoothPosition;
_smoothRotation = smoothRotation;
_interpolation = interpolation;
_teleportThreshold = teleportThreshold;
}
/// <summary>
/// Called every frame.
/// </summary>
public void ManualUpdate()
{
MoveToTarget();
}
/// <summary>
/// Called when the TimeManager invokes OnPreTick.
/// </summary>
public void OnPreTick()
{
if (CanSmooth())
{
_preTickReceived = true;
/* Only snap to destination if interpolation is 1.
* This ensures the graphics will be at the proper location
* before the next movement rates are calculated. */
if (_interpolation == 1)
ResetGraphicalToInstantiatedProperties(true, true);
SetGraphicalPreviousProperties();
}
}
public void OnPostTick()
{
if (CanSmooth() && _preTickReceived)
{
_preTickReceived = false;
ResetGraphicalToPreviousProperties();
SetGraphicalMoveRates();
}
}
/// <summary>
/// Returns if prediction can be used on this rigidbody.
/// </summary>
/// <returns></returns>
private bool CanSmooth()
{
if (_interpolation == 0)
return false;
//Only owner needs smoothing.
if (!_networkBehaviour.IsOwner && !_networkBehaviour.IsHost)
return false;
return true;
}
/// <summary>
/// Moves transform to target values.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void MoveToTarget()
{
//Not set, meaning movement doesnt need to happen or completed.
if (_positionMoveRate == -2f && _rotationMoveRate == -2f)
return;
Vector3 posGoal = GetGraphicalGoalPosition();
Quaternion rotGoal = GetGraphicalGoalRotation();
/* Only try to update properties if they have a valid move rate.
* Properties may have 0f move rate if they did not change. */
Transform t = _graphicalObject;
float delta = Time.deltaTime;
//Position.
if (SmoothPosition())
{
if (_positionMoveRate == -1f)
ResetGraphicalToInstantiatedProperties(true, false);
else if (_positionMoveRate > 0f)
t.position = Vector3.MoveTowards(t.position, posGoal, _positionMoveRate * delta);
}
//Rotation.
if (SmoothRotation())
{
if (_rotationMoveRate == -1f)
ResetGraphicalToInstantiatedProperties(false, true);
else if (_rotationMoveRate > 0f)
t.rotation = Quaternion.RotateTowards(t.rotation, rotGoal, _rotationMoveRate * delta);
}
if (GraphicalObjectMatches(posGoal, rotGoal))
{
_positionMoveRate = -2f;
_rotationMoveRate = -2f;
}
}
/// <summary>
/// Returns if this transform matches arguments.
/// </summary>
/// <returns></returns>
private bool GraphicalObjectMatches(Vector3 position, Quaternion rotation)
{
bool positionMatches = (!_smoothPosition || (_graphicalObject.position == position));
bool rotationMatches = (!_smoothRotation || (_graphicalObject.rotation == rotation));
return (positionMatches && rotationMatches);
}
/// <summary>
/// True to smooth position. When false the graphicalObjects property will not be updated.
/// </summary>
/// <returns></returns>
private bool SmoothPosition() => (_smoothPosition && (_networkBehaviour.IsOwner || _networkBehaviour.IsHost));
/// <summary>
/// True to smooth rotation. When false the graphicalObjects property will not be updated.
/// </summary>
/// <returns></returns>
private bool SmoothRotation() => (_smoothRotation && (_networkBehaviour.IsOwner || _networkBehaviour.IsHost));
/// <summary>
/// Sets Position and Rotation move rates to reach Target datas.
/// </summary>
private void SetGraphicalMoveRates()
{
float delta = ((float)_networkBehaviour.TimeManager.TickDelta * _interpolation);
float distance;
distance = Vector3.Distance(_graphicalObject.position, GetGraphicalGoalPosition());
//If qualifies for teleporting.
if (_teleportThreshold != -1f && distance >= _teleportThreshold)
{
_positionMoveRate = -1f;
_rotationMoveRate = -1f;
}
//Smoothing.
else
{
_positionMoveRate = (distance / delta);
distance = Quaternion.Angle(_graphicalObject.rotation, GetGraphicalGoalRotation());
if (distance > 0f)
_rotationMoveRate = (distance / delta);
}
}
/// <summary>
/// Gets a goal position for the graphical object.
/// </summary>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector3 GetGraphicalGoalPosition()
{
if (SmoothPosition())
return (_networkBehaviour.transform.position + _graphicalInstantiatedOffsetPosition);
else
return _graphicalObject.position;
}
/// <summary>
/// Gets a goal rotation for the graphical object.
/// </summary>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Quaternion GetGraphicalGoalRotation()
{
if (SmoothRotation())
return (_graphicalInstantiatedOffsetRotation * _networkBehaviour.transform.rotation);
else
return _graphicalObject.rotation;
}
/// <summary>
/// Caches the graphical object' current position and rotation.
/// </summary>
private void SetGraphicalPreviousProperties()
{
_graphicalStartPosition = _graphicalObject.position;
_graphicalStartRotation = _graphicalObject.rotation;
}
/// <summary>
/// Resets the graphical object to cached position and rotation of the transform.
/// </summary>
private void ResetGraphicalToPreviousProperties()
{
_graphicalObject.SetPositionAndRotation(_graphicalStartPosition, _graphicalStartRotation);
}
/// <summary>
/// Resets the graphical object to it's transform offsets during instantiation.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ResetGraphicalToInstantiatedProperties(bool position, bool rotation)
{
if (position)
_graphicalObject.position = GetGraphicalGoalPosition();
if (rotation)
_graphicalObject.rotation = GetGraphicalGoalRotation();
}
}
}