152 lines
4.3 KiB
C#
152 lines
4.3 KiB
C#
using FishNet;
|
|
using FishNet.Object;
|
|
using FishNet.Object.Prediction;
|
|
using FishNet.Transporting;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using static FishNet.PredictionV2.CharacterControllerPredictionV2;
|
|
|
|
namespace FishNet.PredictionV2
|
|
{
|
|
|
|
public class CharacterControllerPredictionV2 : NetworkBehaviour
|
|
{
|
|
#if !PREDICTION_1
|
|
|
|
|
|
public struct MoveData : IReplicateData
|
|
{
|
|
public uint SentTick;
|
|
public bool Jump;
|
|
public float Horizontal;
|
|
public float Vertical;
|
|
public MoveData(bool jump, float horizontal, float vertical, uint sentTick)
|
|
{
|
|
Jump = jump;
|
|
Horizontal = horizontal;
|
|
Vertical = vertical;
|
|
SentTick = sentTick;
|
|
_tick = 0;
|
|
}
|
|
|
|
private uint _tick;
|
|
public void Dispose() { }
|
|
public uint GetTick() => _tick;
|
|
public void SetTick(uint value) => _tick = value;
|
|
}
|
|
|
|
public struct ReconcileData : IReconcileData
|
|
{
|
|
public Vector3 Position;
|
|
public float VerticalVelocity;
|
|
public ReconcileData(Vector3 position, float verticalVelocity)
|
|
{
|
|
Position = position;
|
|
VerticalVelocity = verticalVelocity;
|
|
_tick = 0;
|
|
}
|
|
|
|
private uint _tick;
|
|
public void Dispose() { }
|
|
public uint GetTick() => _tick;
|
|
public void SetTick(uint value) => _tick = value;
|
|
}
|
|
|
|
[SerializeField]
|
|
private float _jumpForce = 15f;
|
|
[SerializeField]
|
|
private float _moveRate = 4f;
|
|
|
|
private CharacterController _characterController;
|
|
private bool _jump;
|
|
private float _verticalVelocity;
|
|
|
|
private void Update()
|
|
{
|
|
if (base.IsOwner)
|
|
{
|
|
if (Input.GetKeyDown(KeyCode.Space))
|
|
_jump = true;
|
|
}
|
|
}
|
|
|
|
public override void OnStartNetwork()
|
|
{
|
|
_characterController = GetComponent<CharacterController>();
|
|
base.TimeManager.OnTick += TimeManager_OnTick;
|
|
}
|
|
|
|
public override void OnStopNetwork()
|
|
{
|
|
base.TimeManager.OnTick -= TimeManager_OnTick;
|
|
}
|
|
|
|
|
|
private void TimeManager_OnTick()
|
|
{
|
|
Move(BuildMoveData());
|
|
/* The base.IsServer check is not required but does save a little
|
|
* performance by not building the reconcileData if not server. */
|
|
CreateReconcile();
|
|
}
|
|
|
|
public override void CreateReconcile()
|
|
{
|
|
if (base.IsServerStarted)
|
|
{
|
|
ReconcileData rd = new ReconcileData(transform.position, _verticalVelocity);
|
|
Reconciliation(rd);
|
|
}
|
|
}
|
|
private MoveData BuildMoveData()
|
|
{
|
|
if (!base.IsOwner)
|
|
return default;
|
|
|
|
float horizontal = Input.GetAxisRaw("Horizontal");
|
|
float vertical = Input.GetAxisRaw("Vertical");
|
|
|
|
MoveData md;
|
|
if (horizontal != 0 || vertical != 0)
|
|
md = new MoveData(_jump, horizontal, vertical, base.TimeManager.LocalTick);
|
|
else
|
|
md = new MoveData(_jump, horizontal, vertical, 0);
|
|
_jump = false;
|
|
|
|
return md;
|
|
}
|
|
|
|
|
|
[Replicate]
|
|
private void Move(MoveData md, ReplicateState state = ReplicateState.Invalid, Channel channel = Channel.Unreliable)
|
|
{
|
|
if (state == ReplicateState.CurrentFuture)
|
|
return;
|
|
|
|
if (md.Jump)
|
|
_verticalVelocity = _jumpForce;
|
|
|
|
float delta = (float)base.TimeManager.TickDelta;
|
|
_verticalVelocity += (Physics.gravity.y * delta);
|
|
if (_verticalVelocity < -20f)
|
|
_verticalVelocity = -20f;
|
|
|
|
|
|
Vector3 forces = new Vector3(md.Horizontal, _verticalVelocity, md.Vertical) * _moveRate;
|
|
_characterController.Move(forces * delta);
|
|
|
|
|
|
}
|
|
|
|
[Reconcile]
|
|
private void Reconciliation(ReconcileData rd, Channel channel = Channel.Unreliable)
|
|
{
|
|
transform.position = rd.Position;
|
|
_verticalVelocity = rd.VerticalVelocity;
|
|
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
} |