You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
4.7 KiB
C#

using UnityEngine;
using UnityEngine.InputSystem;
using Fusion;
using Fusion.Addons.SimpleKCC;
namespace Projectiles
{
public enum EInputButton
{
Fire = 0,
AltFire = 1,
Jump = 2,
Reload = 3,
}
public struct GameplayInput : INetworkInput
{
public int WeaponSlot => WeaponButton - 1;
public Vector2 MoveDirection;
public Vector2 LookRotationDelta;
public byte WeaponButton;
public NetworkButtons Buttons;
}
/// <summary>
/// PlayerInput handles accumulating player input from Unity and passes the accumulated input to Fusion.
/// </summary>
public sealed class PlayerInput : ContextBehaviour, IBeforeUpdate, IAfterTick
{
// PUBLIC METHODS
public NetworkButtons PreviousButtons => _previousButtons;
public Vector2 AccumulatedLook => _lookRotationAccumulator.AccumulatedValue;
// PRIVATE MEMBERS
[SerializeField]
private float _lookSensitivity = 3;
[Networked]
private NetworkButtons _previousButtons { get; set; }
private GameplayInput _accumulatedInput;
private Vector2Accumulator _lookRotationAccumulator = new(0.02f, true);
private PlayerAgent _agent;
// NetworkBehaviour INTERFACE
public override void Spawned()
{
// Only local player needs networked properties (previous input buttons).
// This saves network traffic by not synchronizing networked properties to other clients except local player.
ReplicateToAll(false);
ReplicateTo(Object.InputAuthority, true);
if (HasInputAuthority == false)
return;
// Register to Fusion input poll callback
var networkEvents = Runner.GetComponent<NetworkEvents>();
networkEvents.OnInput.AddListener(OnInput);
Context.GeneralInput.RequestCursorLock();
}
public override void Despawned(NetworkRunner runner, bool hasState)
{
if (runner == null)
return;
var networkEvents = runner.GetComponent<NetworkEvents>();
if (networkEvents != null)
{
networkEvents.OnInput.RemoveListener(OnInput);
}
}
// IBeforeUpdate INTERFACE
void IBeforeUpdate.BeforeUpdate()
{
// This method is called BEFORE ANY FixedUpdateNetwork() and is used to accumulate input from Keyboard/Mouse.
// Input accumulation is mandatory - this method is called multiple times before new forward FixedUpdateNetwork() - common if rendering speed is faster than Fusion simulation.
if (HasInputAuthority == false)
return;
// Input is tracked only if the cursor is locked and runner should provide input
if (Runner.ProvideInput == false || Context.GeneralInput.IsLocked == false || _agent.InputBlocked == true)
{
_accumulatedInput = default;
return;
}
var mouse = Mouse.current;
if (mouse != null)
{
var mouseDelta = mouse.delta.ReadValue();
var lookRotationDelta = new Vector2(-mouseDelta.y, mouseDelta.x);
lookRotationDelta *= _lookSensitivity / 60f;
_lookRotationAccumulator.Accumulate(lookRotationDelta);
_accumulatedInput.Buttons.Set(EInputButton.Fire, mouse.leftButton.isPressed);
_accumulatedInput.Buttons.Set(EInputButton.AltFire, mouse.rightButton.isPressed);
}
var keyboard = Keyboard.current;
if (keyboard != null)
{
var moveDirection = Vector2.zero;
if (keyboard.wKey.isPressed) { moveDirection += Vector2.up; }
if (keyboard.sKey.isPressed) { moveDirection += Vector2.down; }
if (keyboard.aKey.isPressed) { moveDirection += Vector2.left; }
if (keyboard.dKey.isPressed) { moveDirection += Vector2.right; }
_accumulatedInput.MoveDirection = moveDirection.normalized;
_accumulatedInput.Buttons.Set(EInputButton.Jump, keyboard.spaceKey.isPressed);
_accumulatedInput.Buttons.Set(EInputButton.Reload, keyboard.rKey.isPressed);
_accumulatedInput.WeaponButton = 0;
for (int i = (int)Key.Digit1; i <= (int)Key.Digit9; i++)
{
if (keyboard[(Key)i].isPressed == true)
{
_accumulatedInput.WeaponButton = (byte)(i - (int)Key.Digit1 + 1);
break;
}
}
}
}
// IAfterTick INTERFACE
void IAfterTick.AfterTick()
{
_previousButtons = GetInput<GameplayInput>().GetValueOrDefault().Buttons;
}
// MONOBEHAVIOUR
private void Awake()
{
_agent = GetComponent<PlayerAgent>();
}
// PRIVATE METHODS
private void OnInput(NetworkRunner runner, NetworkInput networkInput)
{
// Mouse movement (delta values) is aligned to engine update.
// To get perfectly smooth interpolated look, we need to align the mouse input with Fusion ticks.
_accumulatedInput.LookRotationDelta = _lookRotationAccumulator.ConsumeTickAligned(runner);
if (_agent.InputBlocked == true)
return;
// Fusion polls accumulated input. This callback can be executed multiple times in a row if there is a performance spike.
networkInput.Set(_accumulatedInput);
}
}
}