183 lines
4.5 KiB
C#
183 lines
4.5 KiB
C#
|
using System;
|
||
|
using UnityEngine;
|
||
|
using Fusion;
|
||
|
using Fusion.Addons.KCC;
|
||
|
|
||
|
namespace TPSBR
|
||
|
{
|
||
|
[DefaultExecutionOrder(-10000)]
|
||
|
[RequireComponent(typeof(Rigidbody))]
|
||
|
public class Elevator : ContextTRSPBehaviour, IPlatform, IAfterClientPredictionReset, IBeforeAllTicks, IKCCProcessor, IKCCProcessorProvider
|
||
|
{
|
||
|
// PROTECTED MEMBERS
|
||
|
|
||
|
[Networked]
|
||
|
protected Vector3 _basePosition { get; private set; }
|
||
|
[Networked]
|
||
|
protected float _currentHeight { get; private set; }
|
||
|
|
||
|
// PRIVATE MEMBERS
|
||
|
|
||
|
[SerializeField]
|
||
|
private float _height = -5f;
|
||
|
[SerializeField]
|
||
|
private float _speed = 1f;
|
||
|
|
||
|
private Transform _transform;
|
||
|
private Rigidbody _rigidbody;
|
||
|
private int _lastRenderFrame;
|
||
|
private int _syncFrames = 1;
|
||
|
private int _syncOffset;
|
||
|
|
||
|
private static int _sharedOffset;
|
||
|
|
||
|
// PUBLIC METHODS
|
||
|
|
||
|
public void OverrideHeight(float height)
|
||
|
{
|
||
|
_currentHeight = height;
|
||
|
}
|
||
|
|
||
|
// NetworkBehaviour INTERFACE
|
||
|
|
||
|
public override void Spawned()
|
||
|
{
|
||
|
_lastRenderFrame = default;
|
||
|
|
||
|
if (HasStateAuthority == true)
|
||
|
{
|
||
|
_transform.GetPositionAndRotation(out Vector3 position, out Quaternion rotation);
|
||
|
|
||
|
_basePosition = position;
|
||
|
_currentHeight = _height;
|
||
|
_syncFrames = TickRate.Resolve(Runner.Config.Simulation.TickRateSelection).Server;
|
||
|
_syncOffset = _sharedOffset;
|
||
|
|
||
|
_sharedOffset++;
|
||
|
|
||
|
// Set position of NetworkTRSP (compressed).
|
||
|
State.Position = position;
|
||
|
State.Rotation = rotation;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Read initial values.
|
||
|
RestoreTransform();
|
||
|
}
|
||
|
|
||
|
Runner.SetIsSimulated(Object, true);
|
||
|
|
||
|
if (ApplicationSettings.IsStrippedBatch == true)
|
||
|
{
|
||
|
gameObject.SetActive(false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void FixedUpdateNetwork()
|
||
|
{
|
||
|
Vector3 position = CalculatePosition(Runner.Tick * Runner.DeltaTime);
|
||
|
|
||
|
_transform.position = position;
|
||
|
_rigidbody.position = position;
|
||
|
|
||
|
if (((Runner.Tick.Raw + _syncOffset) % _syncFrames) == 0 && HasStateAuthority == true)
|
||
|
{
|
||
|
// Store transform once per second to lower network sync pressure.
|
||
|
// Precise position is based on tick - calculated.
|
||
|
State.Position = position;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void Render()
|
||
|
{
|
||
|
_lastRenderFrame = Time.frameCount;
|
||
|
|
||
|
Vector3 position = CalculatePosition((Runner.Tick + Runner.LocalAlpha) * Runner.DeltaTime);
|
||
|
|
||
|
_transform.position = position;
|
||
|
_rigidbody.position = position;
|
||
|
}
|
||
|
|
||
|
// IAfterClientPredictionReset INTERFACE
|
||
|
|
||
|
void IAfterClientPredictionReset.AfterClientPredictionReset()
|
||
|
{
|
||
|
RestoreTransform();
|
||
|
}
|
||
|
|
||
|
// IBeforeAllTicks INTERFACE
|
||
|
|
||
|
void IBeforeAllTicks.BeforeAllTicks(bool resimulation, int tickCount)
|
||
|
{
|
||
|
// Skip resimulation, the state is already restored from AfterClientPredictionReset().
|
||
|
if (resimulation == true)
|
||
|
return;
|
||
|
|
||
|
// Restore state only if a render update was executed previous frame.
|
||
|
// Otherwise we continue with state from previous fixed tick or the state is already restored from AfterClientPredictionReset().
|
||
|
int previousFrame = Time.frameCount - 1;
|
||
|
if (previousFrame != _lastRenderFrame)
|
||
|
return;
|
||
|
|
||
|
RestoreTransform();
|
||
|
}
|
||
|
|
||
|
// IKCCInteractionProvider INTERFACE
|
||
|
|
||
|
bool IKCCInteractionProvider.CanStartInteraction(KCC kcc, KCCData data) => true;
|
||
|
bool IKCCInteractionProvider.CanStopInteraction (KCC kcc, KCCData data) => true;
|
||
|
|
||
|
// IKCCProcessorProvider INTERFACE
|
||
|
|
||
|
IKCCProcessor IKCCProcessorProvider.GetProcessor()
|
||
|
{
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
// MonoBehaviour INTERFACE
|
||
|
|
||
|
private void Awake()
|
||
|
{
|
||
|
_transform = transform;
|
||
|
_rigidbody = GetComponent<Rigidbody>();
|
||
|
|
||
|
if (_rigidbody == null)
|
||
|
throw new NullReferenceException($"GameObject {name} has missing Rigidbody component!");
|
||
|
|
||
|
_rigidbody.isKinematic = true;
|
||
|
_rigidbody.useGravity = false;
|
||
|
_rigidbody.interpolation = RigidbodyInterpolation.None;
|
||
|
_rigidbody.constraints = RigidbodyConstraints.FreezeAll;
|
||
|
}
|
||
|
|
||
|
// PRIVATE METHODS
|
||
|
|
||
|
private void RestoreTransform()
|
||
|
{
|
||
|
Vector3 position = CalculatePosition(Runner.Tick * Runner.DeltaTime);
|
||
|
|
||
|
_transform.SetPositionAndRotation(position, State.Rotation);
|
||
|
_rigidbody.position = position;
|
||
|
}
|
||
|
|
||
|
private Vector3 CalculatePosition(float time)
|
||
|
{
|
||
|
Vector3 position = _basePosition;
|
||
|
|
||
|
float absoluteHeight = Mathf.Abs(_currentHeight);
|
||
|
if (absoluteHeight <= 0.0f)
|
||
|
return _basePosition;
|
||
|
|
||
|
float totalDistance = _speed * time;
|
||
|
float distanceAlpha = (totalDistance % (absoluteHeight * 2.0f)) / absoluteHeight; // 0.0f - 2.0f
|
||
|
|
||
|
if (distanceAlpha > 1.0f)
|
||
|
{
|
||
|
distanceAlpha = 2.0f - distanceAlpha; // 0.0f - 1.0f
|
||
|
}
|
||
|
|
||
|
return _basePosition + Vector3.up * distanceAlpha * _currentHeight;
|
||
|
}
|
||
|
}
|
||
|
}
|