using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using FlaxEngine; namespace Game; [StructLayout(LayoutKind.Sequential)] public struct PlayerInputState2 : IEquatable { public ulong Frame; public Float2 ViewDelta; public float MoveForward; public float MoveRight; public bool Attack; public bool Jump; /*public override bool Equals([NotNullWhen(true)] object obj) { if (obj is not PlayerInputState2 other) return false; return Frame == other.Frame && ViewDelta == other.ViewDelta && MoveForward == other.MoveForward && MoveRight == other.MoveRight && Attack == other.Attack && Jump == other.Jump; }*/ public bool Equals(PlayerInputState2 other) { return Frame == other.Frame && ViewDelta == other.ViewDelta && MoveForward == other.MoveForward && MoveRight == other.MoveRight && Attack == other.Attack && Jump == other.Jump; } public static bool operator ==(PlayerInputState2 left, PlayerInputState2 right) => left.Equals(right); public static bool operator !=(PlayerInputState2 left, PlayerInputState2 right) => !left.Equals(right); } public interface IPlayerInput { /// /// Sets the frame number for current frame. /// /// The frame number void SetFrame(ulong frame); /// /// Updates the current state, gathering the latest input. /// void UpdateState(); /// /// Gets the current input state of the current frame. /// PlayerInputState2 GetState(); /// /// Resets the input state for a new frame. /// void ResetState(); } public class PlayerInput2 : IPlayerInput { /// /// The state currently being recorded, may get modified during multiple in-flight frames. /// private PlayerInputState2 _recordState; [ConsoleVariable("sensitivity")] private static float _sensitivity { get; set; } = 1.0f; private ulong _frame; public void SetFrame(ulong frame) { if (_frame != frame) ResetState(); _frame = frame; } public void UpdateState() { // Axis values should be either accumulated (view delta) // or taken with the peak values (axis direction), // binary values should be OR'ed so triggered action is not lost if button debounces mid-frame. //float sensitivity = 1.0f / 8.0f; //sensitivity = 1.0f; float turnSpeed = 100.0f; _recordState.ViewDelta += new Float2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y")) * _sensitivity; _recordState.ViewDelta += new Float2(Input.GetAxisRaw("LookRight"), Input.GetAxisRaw("LookUp")) * Time.DeltaTime * turnSpeed; _recordState.MoveForward = MathF.MaxMagnitude(_recordState.MoveForward, Input.GetAxis("Vertical")); _recordState.MoveRight = MathF.MaxMagnitude(_recordState.MoveRight, Input.GetAxis("Horizontal")); _recordState.Attack |= Input.GetAction("Attack"); _recordState.Jump |= Input.GetAction("Jump"); _recordState.Frame = _frame; if (Input.GetKeyDown(KeyboardKeys.F)) Thread.Sleep(20); } public PlayerInputState2 GetState() => _recordState; public void ResetState() => _recordState = new PlayerInputState2(); } public class PlayerInputNetwork2 : IPlayerInput { private uint _playerId; private World _world; private ulong _frame; private PlayerInputState2 _state; public PlayerInputNetwork2(uint playerId, World world) { _playerId = playerId; _world = world; } public void SetFrame(ulong frame) => _frame = frame; public void UpdateState() { _world.GetPlayerInputState(_playerId, _frame, out _state); } public PlayerInputState2 GetState() => _state; public void ResetState() { _state = new PlayerInputState2(); } } public class PlayerInputNone : IPlayerInput { public static PlayerInputNone Instance { get; } = new PlayerInputNone(); private PlayerInputNone() { } public PlayerInputState2 GetState() => default; public void ResetState() { } public void SetFrame(ulong frame) { } public void UpdateState() { } }