fgm24/Assets/Scripts/Multiplayer/ReconciliationPlayerControl...

183 lines
5.9 KiB
Plaintext

using PlayerController;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Unity.Netcode;
using UnityEditor.Events;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.UIElements;
/// This script is for networking the player with reconciliation
public class ReconciliationPlayerControllerMiddleman : MonoBehaviour
{
#region Ugly ass code
// Convert to C# events because superiority
public void In_OnLook(CustomInput ctx) => OnIn_OnLook?.Invoke(ctx);
public void In_OnMove(CustomInput ctx) => OnIn_OnMove?.Invoke(ctx);
public void In_OnJump(CustomInput ctx) => OnIn_OnJump?.Invoke(ctx);
public void In_OnCrouch(CustomInput ctx) => OnIn_OnCrouch?.Invoke(ctx);
public void In_OnSliding(CustomInput ctx) => OnIn_OnSliding?.Invoke(ctx);
private Action<CustomInput> OnIn_OnLook;
private Action<CustomInput> OnIn_OnMove;
private Action<CustomInput> OnIn_OnJump;
private Action<CustomInput> OnIn_OnCrouch;
private Action<CustomInput> OnIn_OnSliding;
public UnityEvent<CustomInput> OnLook;
public UnityEvent<CustomInput> OnMove;
public UnityEvent<CustomInput> OnJump;
public UnityEvent<CustomInput> OnCrouch;
public UnityEvent<CustomInput> OnSliding;
#endregion
// Shared
private float timer;
private int currentTick;
private float minTimeBetweenTicks;
private uint serverTickRate;
private const int BUFFER_SIZE = 1024;
// Local
private StatePayload[] stateBuffer;
private InputPayload[] inputBuffer;
private StatePayload latestServerState;
private StatePayload lastProcessedState;
private InputGroup currentInputState;
void OnEnable()
{
PlayerController.PlayerInput blockThisScript;
if (!TryGetComponent<PlayerController.PlayerInput>(out blockThisScript))
{
Debug.LogError("Could not find playerinput component.");
return;
}
if (NetworkManager.Singleton == null)
{
Debug.Log("[Movement] No network manager found. Ignoring reconciliation.");
return;
}
serverTickRate = NetworkManager.Singleton.NetworkTickSystem.TickRate;
stateBuffer = new StatePayload[BUFFER_SIZE];
inputBuffer = new InputPayload[BUFFER_SIZE];
currentInputState = new InputGroup();
#region Ugly ass code
// Remove old hooks
blockThisScript.OnLook.RemoveAllPersistentListeners();
blockThisScript.OnMove.RemoveAllPersistentListeners();
blockThisScript.OnJump.RemoveAllPersistentListeners();
blockThisScript.OnCrouch.RemoveAllPersistentListeners();
blockThisScript.OnSliding.RemoveAllPersistentListeners();
// Rehook C# hooks (Entry)
blockThisScript.OnLook.AddListener(In_OnLook);
blockThisScript.OnMove.AddListener(In_OnMove);
blockThisScript.OnJump.AddListener(In_OnJump);
blockThisScript.OnCrouch.AddListener(In_OnCrouch);
blockThisScript.OnSliding.AddListener(In_OnSliding);
// Pass hook from hook to hook (Connect)
OnIn_OnLook += (ctx) => {currentInputState.OnLook.Input = ctx; currentInputState.OnLook.WasCalled = true;};
OnIn_OnMove += (ctx) => {currentInputState.OnMove.Input = ctx; currentInputState.OnMove.WasCalled = true;};
OnIn_OnJump += (ctx) => {currentInputState.OnJump.Input = ctx; currentInputState.OnJump.WasCalled = true;};
OnIn_OnCrouch += (ctx) => {currentInputState.OnCrouch.Input = ctx; currentInputState.OnCrouch.WasCalled = true;};
OnIn_OnSliding += (ctx) => {currentInputState.OnSliding.Input = ctx; currentInputState.OnSliding.WasCalled = true;};
#endregion
}
private void Update()
{
int tickTime = NetworkManager.Singleton.NetworkTickSystem.LocalTime.Tick;
int bufferIndex = tickTime % BUFFER_SIZE;
// Add payload to inputBuffer
InputPayload payload = new InputPayload();
payload.tick = tickTime;
payload.inputs = currentInputState;
inputBuffer[bufferIndex] = payload;
stateBuffer[bufferIndex] = ProcessMovement(payload);
}
private StatePayload ProcessMovement(InputPayload payload)
{
// Invokes movement only if something changed.
if (payload.inputs.OnLook.WasCalled)
OnLook?.Invoke(payload.inputs.OnLook.Input);
if (payload.inputs.OnMove.WasCalled)
OnMove?.Invoke(payload.inputs.OnMove.Input);
if (payload.inputs.OnJump.WasCalled)
OnJump?.Invoke(payload.inputs.OnJump.Input);
if (payload.inputs.OnCrouch.WasCalled)
OnCrouch?.Invoke(payload.inputs.OnCrouch.Input);
if (payload.inputs.OnSliding.WasCalled)
OnSliding?.Invoke(payload.inputs.OnSliding.Input);
// Resets inputs
currentInputState.OnLook.WasCalled = false;
currentInputState.OnMove.WasCalled = false;
currentInputState.OnJump.WasCalled = false;
currentInputState.OnCrouch.WasCalled = false;
currentInputState.OnSliding.WasCalled = false;
return new StatePayload()
{
tick = payload.tick,
position = transform.position
};
}
private void OnDisable()
{
// Clears subscribers from events
OnIn_OnLook = null;
OnIn_OnMove = null;
OnIn_OnJump = null;
OnIn_OnCrouch = null;
OnIn_OnSliding = null;
}
}
public struct InputPayload
{
public int tick;
public InputGroup inputs;
}
public struct StatePayload
{
public int tick;
public Vector3 position;
}
public struct InputGroup
{
public InputState OnLook;
public InputState OnMove;
public InputState OnJump;
public InputState OnCrouch;
public InputState OnSliding;
}
public struct InputState
{
public bool WasCalled;
public CustomInput Input;
}