183 lines
5.9 KiB
Plaintext
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;
|
|
} |