netcode progress, improved handling of missing frames
This commit is contained in:
@@ -6,8 +6,8 @@
|
||||
"UseVSync": false,
|
||||
"AAQuality": 3,
|
||||
"SSRQuality": 3,
|
||||
"SSAOQuality": 0,
|
||||
"VolumetricFogQuality": 3,
|
||||
"SSAOQuality": 3,
|
||||
"VolumetricFogQuality": 0,
|
||||
"ShadowsQuality": 3,
|
||||
"ShadowMapsQuality": 3,
|
||||
"AllowCSMBlending": true,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"ID": "8ec53dba4c238bfbea1d62922e612a4d",
|
||||
"TypeName": "FlaxEditor.Content.Settings.InputSettings",
|
||||
"EngineBuild": 6335,
|
||||
"EngineBuild": 6705,
|
||||
"Data": {
|
||||
"ActionMappings": [
|
||||
{
|
||||
@@ -84,6 +84,8 @@
|
||||
"Gamepad": 0,
|
||||
"PositiveButton": 0,
|
||||
"NegativeButton": 0,
|
||||
"GamepadPositiveButton": 0,
|
||||
"GamepadNegativeButton": 0,
|
||||
"DeadZone": 0.0,
|
||||
"Sensitivity": 0.11,
|
||||
"Gravity": 1.0,
|
||||
@@ -96,6 +98,8 @@
|
||||
"Gamepad": 0,
|
||||
"PositiveButton": 0,
|
||||
"NegativeButton": 0,
|
||||
"GamepadPositiveButton": 0,
|
||||
"GamepadNegativeButton": 0,
|
||||
"DeadZone": 0.0,
|
||||
"Sensitivity": 0.11,
|
||||
"Gravity": 1.0,
|
||||
@@ -108,9 +112,11 @@
|
||||
"Gamepad": 0,
|
||||
"PositiveButton": 68,
|
||||
"NegativeButton": 65,
|
||||
"GamepadPositiveButton": 0,
|
||||
"GamepadNegativeButton": 0,
|
||||
"DeadZone": 0.01,
|
||||
"Sensitivity": 5.0,
|
||||
"Gravity": 5.0,
|
||||
"Sensitivity": 0.0,
|
||||
"Gravity": 0.0,
|
||||
"Scale": 1.0,
|
||||
"Snap": true
|
||||
},
|
||||
@@ -120,9 +126,11 @@
|
||||
"Gamepad": 0,
|
||||
"PositiveButton": 87,
|
||||
"NegativeButton": 83,
|
||||
"GamepadPositiveButton": 0,
|
||||
"GamepadNegativeButton": 0,
|
||||
"DeadZone": 0.01,
|
||||
"Sensitivity": 5.0,
|
||||
"Gravity": 5.0,
|
||||
"Sensitivity": 0.0,
|
||||
"Gravity": 0.0,
|
||||
"Scale": 1.0,
|
||||
"Snap": true
|
||||
},
|
||||
@@ -132,6 +140,8 @@
|
||||
"Gamepad": 0,
|
||||
"PositiveButton": 39,
|
||||
"NegativeButton": 37,
|
||||
"GamepadPositiveButton": 0,
|
||||
"GamepadNegativeButton": 0,
|
||||
"DeadZone": 0.0,
|
||||
"Sensitivity": 1.0,
|
||||
"Gravity": 800.0,
|
||||
@@ -144,6 +154,8 @@
|
||||
"Gamepad": 0,
|
||||
"PositiveButton": 38,
|
||||
"NegativeButton": 40,
|
||||
"GamepadPositiveButton": 0,
|
||||
"GamepadNegativeButton": 0,
|
||||
"DeadZone": 0.0,
|
||||
"Sensitivity": 1.0,
|
||||
"Gravity": 800.0,
|
||||
@@ -156,6 +168,8 @@
|
||||
"Gamepad": 0,
|
||||
"PositiveButton": 0,
|
||||
"NegativeButton": 0,
|
||||
"GamepadPositiveButton": 0,
|
||||
"GamepadNegativeButton": 0,
|
||||
"DeadZone": 0.19,
|
||||
"Sensitivity": 1.0,
|
||||
"Gravity": 1.0,
|
||||
@@ -168,6 +182,8 @@
|
||||
"Gamepad": 0,
|
||||
"PositiveButton": 0,
|
||||
"NegativeButton": 0,
|
||||
"GamepadPositiveButton": 0,
|
||||
"GamepadNegativeButton": 0,
|
||||
"DeadZone": 0.19,
|
||||
"Sensitivity": 1.0,
|
||||
"Gravity": 1.0,
|
||||
@@ -180,6 +196,8 @@
|
||||
"Gamepad": 0,
|
||||
"PositiveButton": 0,
|
||||
"NegativeButton": 0,
|
||||
"GamepadPositiveButton": 0,
|
||||
"GamepadNegativeButton": 0,
|
||||
"DeadZone": 0.19,
|
||||
"Sensitivity": 1.0,
|
||||
"Gravity": 1.0,
|
||||
@@ -192,6 +210,8 @@
|
||||
"Gamepad": 0,
|
||||
"PositiveButton": 0,
|
||||
"NegativeButton": 0,
|
||||
"GamepadPositiveButton": 0,
|
||||
"GamepadNegativeButton": 0,
|
||||
"DeadZone": 0.19,
|
||||
"Sensitivity": 1.0,
|
||||
"Gravity": 1.0,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"ID": "4bd8a4cc460399b5f1975fbe0a668e3f",
|
||||
"TypeName": "FlaxEditor.Content.Settings.PhysicsSettings",
|
||||
"EngineBuild": 6510,
|
||||
"EngineBuild": 6705,
|
||||
"Data": {
|
||||
"DefaultGravity": {
|
||||
"X": 0.0,
|
||||
@@ -13,6 +13,7 @@
|
||||
"RestitutionCombineMode": 0,
|
||||
"DisableCCD": false,
|
||||
"BroadPhaseType": 3,
|
||||
"EnableEnhancedDeterminism": false,
|
||||
"SolverType": 0,
|
||||
"MaxDeltaTime": 0.1,
|
||||
"EnableSubstepping": false,
|
||||
|
||||
@@ -137,7 +137,7 @@ public class CameraRender : PostProcessEffect
|
||||
private bool lastRescale = false;
|
||||
public override void OnUpdate()
|
||||
{
|
||||
#if FLAX_EDITOR
|
||||
/*#if FLAX_EDITOR
|
||||
if (Input.GetKeyDown(KeyboardKeys.F7))
|
||||
{
|
||||
PhysicsSettings physicsSettings = GameSettings.Load<PhysicsSettings>();
|
||||
@@ -145,7 +145,7 @@ public class CameraRender : PostProcessEffect
|
||||
GameSettings.Save(physicsSettings);
|
||||
//GameSettings.Apply();
|
||||
}
|
||||
#endif
|
||||
#endif*/
|
||||
|
||||
if (lastEnabled != camera.IsActive)
|
||||
{
|
||||
|
||||
@@ -24,14 +24,17 @@ public static partial class NetworkManager
|
||||
|
||||
//var driver = Object.New(typeof(ENetDriver));
|
||||
//ClientNetworkDriver = null;
|
||||
NetworkLagDriver driver = Object.New<NetworkLagDriver>();
|
||||
driver.Lag = 0f;
|
||||
|
||||
//INetworkDriver driver = Object.New<ENetDriver>();
|
||||
INetworkDriver driver = Object.New<NetworkLagDriver>();
|
||||
if (driver is NetworkLagDriver networkLagDriver)
|
||||
networkLagDriver.Lag = 50.0f;
|
||||
ClientNetworkDriver = driver;
|
||||
|
||||
|
||||
client = NetworkPeer.CreatePeer(new NetworkConfig
|
||||
{
|
||||
NetworkDriver = driver,
|
||||
NetworkDriver = (Object)driver,
|
||||
ConnectionsLimit = MaximumClients,
|
||||
MessagePoolSize = 2048,
|
||||
MessageSize = MTU,
|
||||
|
||||
@@ -22,14 +22,15 @@ public static partial class NetworkManager
|
||||
|
||||
public static bool StartServer(bool listenServer = true)
|
||||
{
|
||||
Time.Synchronize();
|
||||
Cleanup();
|
||||
ConnectedClients = new List<NetworkConnection>(MaximumClients);
|
||||
|
||||
|
||||
//INetworkDriver driver = Object.New<ENetDriver>();
|
||||
NetworkLagDriver driver = Object.New<NetworkLagDriver>();
|
||||
INetworkDriver driver = Object.New<ENetDriver>();
|
||||
//NetworkLagDriver driver = Object.New<NetworkLagDriver>();
|
||||
if (driver is NetworkLagDriver networkLagDriver)
|
||||
networkLagDriver.Lag = 200f;
|
||||
networkLagDriver.Lag = 50.0f;//200f;
|
||||
|
||||
ServerNetworkDriver = driver;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ public enum GameModeMessageType2 : byte
|
||||
|
||||
public class PlayerFrame
|
||||
{
|
||||
public ulong frame;
|
||||
public ulong frame => inputState.Frame;
|
||||
public Float3 position;
|
||||
public PlayerInputState2 inputState;
|
||||
public PlayerMovementState movementState;
|
||||
@@ -40,7 +40,7 @@ public interface IClientInfo
|
||||
public class World
|
||||
{
|
||||
public bool IsServer => this is ServerWorld;
|
||||
public bool IsClient => !IsServer;
|
||||
public bool IsClient => this is ClientWorld;
|
||||
public ulong Frame { get; protected set; }
|
||||
public ulong ServerFrame { get; protected set; } // Last received frame from server
|
||||
public float GameTime { get; protected set; } // The join time
|
||||
@@ -102,17 +102,17 @@ public class World
|
||||
|
||||
void OnUpdate()
|
||||
{
|
||||
Console.Print("server Update");
|
||||
//Console.Print("server Update");
|
||||
}
|
||||
|
||||
void OnUpdateLate()
|
||||
{
|
||||
Console.Print("server LateUpdate");
|
||||
//Console.Print("server LateUpdate");
|
||||
}
|
||||
|
||||
void OnFixedUpdate()
|
||||
{
|
||||
Console.Print("server FixedUpdate");
|
||||
//Console.Print("server FixedUpdate");
|
||||
}
|
||||
|
||||
protected void CreateScene(string sceneNamePrefix, string sceneGuid)
|
||||
@@ -224,14 +224,17 @@ public class World
|
||||
|
||||
virtual public bool IsLocalPlayer(uint playerId) => false;
|
||||
|
||||
virtual public ulong GetLastProcessedFrame(uint playerId) => 0;
|
||||
|
||||
virtual public ulong GetLastReceivedFrame(uint playerId) => 0;
|
||||
|
||||
public PlayerFrame GetPlayerFrame(uint playerId, ulong frame)
|
||||
{
|
||||
IClientInfo player = GetClient(playerId);
|
||||
PlayerFrame playerFrame = player.FrameHistory[frame % 120];
|
||||
if (playerFrame.frame != frame)
|
||||
return null;
|
||||
|
||||
return playerFrame;
|
||||
if (playerFrame.inputState.Frame == frame || playerFrame.movementState.frame == frame)
|
||||
return playerFrame;
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool HasPlayerFrame(uint playerId, ulong frame) => GetPlayerFrame(playerId, frame) != null;
|
||||
@@ -248,8 +251,9 @@ public class World
|
||||
IClientInfo player = GetClient(playerId);
|
||||
|
||||
PlayerFrame playerFrame = player.FrameHistory[frame % 120];
|
||||
if (playerFrame.frame == frame)
|
||||
/*if (playerFrame.frame == frame)
|
||||
{
|
||||
var old = playerFrame.inputState with { Frame = inputState.Frame };
|
||||
playerFrame.inputState = inputState with
|
||||
{
|
||||
ViewDelta = playerFrame.inputState.ViewDelta + inputState.ViewDelta,
|
||||
@@ -258,11 +262,23 @@ public class World
|
||||
Attack = playerFrame.inputState.Attack || inputState.Attack,
|
||||
Jump = playerFrame.inputState.Jump || inputState.Jump,
|
||||
};
|
||||
|
||||
if (old != playerFrame.inputState)
|
||||
old = old;
|
||||
}
|
||||
else
|
||||
else*/
|
||||
playerFrame.inputState = inputState;
|
||||
playerFrame.inputState.Frame = frame;
|
||||
//playerFrame.movementState = movementState;
|
||||
//playerFrame.frame = frame;
|
||||
}
|
||||
|
||||
virtual public void UpdatePlayerState(uint playerId, ulong frame, PlayerMovementState movementState)
|
||||
{
|
||||
IClientInfo player = GetClient(playerId);
|
||||
PlayerFrame playerFrame = player.FrameHistory[frame % 120];
|
||||
playerFrame.movementState = movementState;
|
||||
playerFrame.frame = frame;
|
||||
playerFrame.movementState.frame = frame;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,12 +291,17 @@ file class ServerWorld : World
|
||||
public PlayerFrame[] FrameHistory { get; set; } = new PlayerFrame[120];
|
||||
public ulong LastReceivedFrame = 0;
|
||||
public ulong LastSentDeltaFrame = 0; // TODO: Accumulate deltas since this frame
|
||||
public ulong LastProcessedFrame = 0; // In case player is lagged behind, these frames should be caught up during next simulation
|
||||
public int SendRate = 0; // How many updates the client wants to receive per second
|
||||
|
||||
public ClientInfo()
|
||||
{
|
||||
for (int i = 0; i < FrameHistory.Length; i++)
|
||||
{
|
||||
FrameHistory[i] = new PlayerFrame();
|
||||
FrameHistory[i].inputState.Frame = ulong.MaxValue;
|
||||
FrameHistory[i].movementState.frame = ulong.MaxValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,8 +327,14 @@ file class ServerWorld : World
|
||||
|
||||
protected override void OnLateUpdate()
|
||||
{
|
||||
Console.Print("server LateFixedUpdate");
|
||||
//Console.Print("server LateFixedUpdate");
|
||||
base.OnLateUpdate();
|
||||
|
||||
foreach (var client in _clients.Values)
|
||||
{
|
||||
// We assume all the scripts have processed the frames during this cycle
|
||||
client.LastProcessedFrame = client.LastReceivedFrame;
|
||||
}
|
||||
}
|
||||
|
||||
public bool OnMessage(ref NetworkEvent networkEvent)
|
||||
@@ -369,9 +396,10 @@ file class ServerWorld : World
|
||||
{
|
||||
PlayerInputState2 inputState; //?
|
||||
|
||||
ulong receivedFrame = networkEvent.Message.ReadUInt64();
|
||||
uint reportedPlayerId = networkEvent.Message.ReadUInt32();
|
||||
inputState.Frame = receivedFrame;
|
||||
ulong receivedFrame = inputState.Frame = networkEvent.Message.ReadUInt64();
|
||||
uint playerId = networkEvent.Message.ReadUInt32();
|
||||
float time = networkEvent.Message.ReadSingle();
|
||||
float delay = Time.TimeSinceStartup - time;
|
||||
inputState.ViewDelta.X = networkEvent.Message.ReadSingle();
|
||||
inputState.ViewDelta.Y = networkEvent.Message.ReadSingle();
|
||||
inputState.MoveForward = networkEvent.Message.ReadSingle();
|
||||
@@ -379,22 +407,42 @@ file class ServerWorld : World
|
||||
inputState.Attack = networkEvent.Message.ReadBoolean();
|
||||
inputState.Jump = networkEvent.Message.ReadBoolean();
|
||||
|
||||
Console.Print($"server receive client frame {receivedFrame}, current server frame {Frame}");
|
||||
//Console.Print("recv: " + receivedFrame.ToString());
|
||||
|
||||
ClientInfo player = GetClient(playerId) as ClientInfo;
|
||||
if (receivedFrame <= player.LastReceivedFrame)
|
||||
{
|
||||
if (receivedFrame < player.LastProcessedFrame)
|
||||
{
|
||||
Console.PrintWarning($"Dropping late frame from client: {receivedFrame}, last processed: {player.LastProcessedFrame}");
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Console.PrintWarning($"Out-of-order frame received from client: {receivedFrame}, latest: {player.LastReceivedFrame}");
|
||||
}
|
||||
}
|
||||
player.LastReceivedFrame = Math.Max(receivedFrame, player.LastReceivedFrame);
|
||||
//if (player.LastProcessedFrame == 0)
|
||||
// player.LastProcessedFrame = receivedFrame - 1;
|
||||
|
||||
//Console.Print($"server receive client frame {receivedFrame}, current server frame {Frame}");
|
||||
var asdf = receivedFrame;
|
||||
receivedFrame = Frame;
|
||||
//receivedFrame = Frame; // TODO: receive all frames from players, simulate all unprocessed frames in next simulation cycle?
|
||||
|
||||
if (inputState.MoveForward != 0)
|
||||
receivedFrame = receivedFrame;
|
||||
|
||||
|
||||
//Console.Print($"delay: {delay * 1000}ms");
|
||||
|
||||
// Sanity check
|
||||
if (GetPlayerInputState(reportedPlayerId, receivedFrame, out var prevInputState))
|
||||
if (GetPlayerInputState(playerId, receivedFrame, out var prevInputState))
|
||||
{
|
||||
Console.PrintWarning($"Duplicate frame received from client: {asdf}");
|
||||
Console.PrintWarning($"Duplicate frame received from client: {asdf}, delay: {delay*1000}ms");
|
||||
//break;
|
||||
}
|
||||
|
||||
PlayerMovementState movementState = default;
|
||||
UpdatePlayerInputState(reportedPlayerId, receivedFrame, inputState, movementState);
|
||||
UpdatePlayerInputState(playerId, receivedFrame, inputState, default);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -454,12 +502,24 @@ file class ServerWorld : World
|
||||
}
|
||||
}
|
||||
|
||||
public override ulong GetLastProcessedFrame(uint playerId)
|
||||
{
|
||||
ClientInfo player = GetClient(playerId) as ClientInfo;
|
||||
return player.LastProcessedFrame;
|
||||
}
|
||||
|
||||
public override ulong GetLastReceivedFrame(uint playerId)
|
||||
{
|
||||
ClientInfo player = GetClient(playerId) as ClientInfo;
|
||||
return player.LastReceivedFrame;
|
||||
}
|
||||
|
||||
public override void UpdatePlayerInputState(uint playerId, ulong frame, PlayerInputState2 inputState, PlayerMovementState movementState)
|
||||
{
|
||||
base.UpdatePlayerInputState(playerId, frame, inputState, movementState);
|
||||
|
||||
ClientInfo player = GetClient(playerId) as ClientInfo;
|
||||
player.LastReceivedFrame = frame; // Dropped frames should be ignored?
|
||||
//ClientInfo player = GetClient(playerId) as ClientInfo;
|
||||
//player.LastReceivedFrame = frame; // Dropped frames should be ignored?
|
||||
}
|
||||
|
||||
protected override PlayerActor SpawnPlayer(uint playerId, Float3 position, Vector3 eulerAngles)
|
||||
@@ -526,7 +586,7 @@ file class ClientWorld : World
|
||||
public bool Jump;*/
|
||||
|
||||
|
||||
Console.Print($"client send {Frame}");
|
||||
//Console.Print($"client send {Frame}");
|
||||
UpdatePlayerInputState(player.PlayerId, Frame, inputState, movementState);
|
||||
//Console.Print($"cframe: {Frame}");
|
||||
|
||||
@@ -534,12 +594,15 @@ file class ClientWorld : World
|
||||
message.WriteByte((byte)GameModeMessageType2.PlayerInput);
|
||||
message.WriteUInt64(Frame);
|
||||
message.WriteUInt32(player.PlayerId);
|
||||
message.WriteSingle(Time.TimeSinceStartup);
|
||||
message.WriteVector2(inputState.ViewDelta);
|
||||
message.WriteSingle(inputState.MoveForward);
|
||||
message.WriteSingle(inputState.MoveRight);
|
||||
message.WriteBoolean(inputState.Attack);
|
||||
message.WriteBoolean(inputState.Jump);
|
||||
NetworkManager.ClientEndSendMessage(ref message);
|
||||
|
||||
//Console.Print("send: " + Frame.ToString());
|
||||
}
|
||||
base.OnLateUpdate();
|
||||
}
|
||||
@@ -644,6 +707,18 @@ file class ClientWorld : World
|
||||
|
||||
public override bool IsLocalPlayer(uint playerId) => playerId == _localPlayerId;
|
||||
|
||||
public override ulong GetLastProcessedFrame(uint playerId)
|
||||
{
|
||||
//ClientInfo player = GetClient(playerId) as ClientInfo;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override ulong GetLastReceivedFrame(uint playerId)
|
||||
{
|
||||
//ClientInfo player = GetClient(playerId) as ClientInfo;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void OnClientConnected(NetworkConnection connection)
|
||||
{
|
||||
uint playerId = connection.ConnectionId;
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
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
|
||||
public struct PlayerInputState2 : IEquatable<PlayerInputState2>
|
||||
{
|
||||
public ulong Frame;
|
||||
public Float2 ViewDelta;
|
||||
@@ -17,6 +19,22 @@ public struct PlayerInputState2
|
||||
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
|
||||
@@ -80,6 +98,9 @@ public class PlayerInput2 : IPlayerInput
|
||||
_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;
|
||||
|
||||
@@ -74,6 +74,7 @@ public struct PlayerMovementState
|
||||
public int numJumps;
|
||||
public bool jumped;
|
||||
public bool onGround;
|
||||
public ulong frame;
|
||||
|
||||
|
||||
public PlayerMovementState()
|
||||
@@ -250,9 +251,20 @@ public class PlayerMovement : Script
|
||||
viewAnglesLastFrame = viewAngles;
|
||||
}
|
||||
|
||||
private static int framedropped = 0;
|
||||
public override void OnUpdate()
|
||||
{
|
||||
Console.Print("playerMovement OnUpdate");
|
||||
if (World.IsServer && Mathf.Abs(Time.DeltaTime - (1.0f / Time.UpdateFPS)) > (1.0f / Time.UpdateFPS) * 0.999f)
|
||||
{
|
||||
Console.Print($"drop: {Time.DeltaTime*1000.0f}ms");
|
||||
framedropped = 3;
|
||||
}
|
||||
else if (World.IsServer && framedropped > 0)
|
||||
{
|
||||
Console.Print("dropping...");
|
||||
framedropped--;
|
||||
}
|
||||
//Console.Print($"{(World.IsClient ? "[cl] " : "[sv] ") + World.Frame.ToString()} playerMovement OnUpdate");
|
||||
//input.OnUpdate();
|
||||
|
||||
|
||||
@@ -315,7 +327,7 @@ public class PlayerMovement : Script
|
||||
|
||||
public override void OnFixedUpdate()
|
||||
{
|
||||
Console.Print("playerMovement OnFixedUpdate");
|
||||
//Console.Print($"{(World.IsClient ? "[cl] " : "[sv] ") + World.Frame.ToString()} playerMovement OnFixedUpdate");
|
||||
float timeDeltaDiff = Time.DeltaTime - 1.0f / Time.PhysicsFPS;
|
||||
if (Time.PhysicsFPS > 0 && Math.Abs(timeDeltaDiff) > 0.0001f)
|
||||
Console.Print("Time.DeltaTime is not stable: " + timeDeltaDiff);
|
||||
@@ -413,13 +425,93 @@ public class PlayerMovement : Script
|
||||
}
|
||||
}
|
||||
|
||||
if (!predict)
|
||||
if (World.IsServer)
|
||||
{
|
||||
ulong currentFrame = World.GetLastProcessedFrame(PlayerId);
|
||||
{
|
||||
// Rewind to last confirmed state
|
||||
var frameInfo = World.GetPlayerFrame(PlayerId, currentFrame);
|
||||
if (frameInfo != null && frameInfo.movementState.frame == currentFrame)
|
||||
{
|
||||
// Reset all state to latest confirmed state from server
|
||||
movementState.position = frameInfo.movementState.position;
|
||||
movementState.currentVelocity = frameInfo.movementState.currentVelocity;
|
||||
movementState.lastJumped = frameInfo.movementState.lastJumped;
|
||||
movementState.numJumps = frameInfo.movementState.numJumps;
|
||||
movementState.jumped = frameInfo.movementState.jumped;
|
||||
Actor.Position = movementState.position;
|
||||
SetCameraEulerAngles(frameInfo.movementState.viewAngles, true);
|
||||
//ApplyInputToCamera(frameInfo.inputState, true);
|
||||
}
|
||||
else if (frameInfo == null)
|
||||
{
|
||||
// First frame, update the known state
|
||||
movementState.viewAngles = viewAngles;
|
||||
World.UpdatePlayerState(PlayerId, currentFrame, movementState);
|
||||
}
|
||||
currentFrame++;
|
||||
}
|
||||
|
||||
//Console.Print("before:" + viewAngles.ToString());
|
||||
|
||||
ulong lastFrame = World.GetLastReceivedFrame(PlayerId);
|
||||
PlayerFrame lastFrameInfo = null;
|
||||
for (; currentFrame < lastFrame+1; currentFrame++)
|
||||
{
|
||||
var frameInfo = World.GetPlayerFrame(PlayerId, currentFrame);
|
||||
if (frameInfo == null || frameInfo.inputState.Frame != currentFrame)
|
||||
//if (!Input.GetState(currentFrame, out var pastInputState, out var pastActorState))
|
||||
{
|
||||
Console.Print($"frame {currentFrame} missing");
|
||||
frameInfo = lastFrameInfo; // Use last known input
|
||||
|
||||
if (frameInfo == null)
|
||||
{
|
||||
// FIXME
|
||||
frameInfo = new PlayerFrame()
|
||||
{
|
||||
inputState =
|
||||
{
|
||||
Frame = currentFrame,
|
||||
},
|
||||
movementState = movementState,
|
||||
};
|
||||
frameInfo.movementState.frame = currentFrame;
|
||||
}
|
||||
//continue;
|
||||
//Console.Print($"not predicting");
|
||||
//predict = false;
|
||||
//break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Input.SetFrame(currentFrame);
|
||||
Input.UpdateState();
|
||||
|
||||
ApplyInputToCamera(frameInfo.inputState, true);
|
||||
lastFrameInfo = frameInfo;
|
||||
}
|
||||
SimulatePlayerMovement(frameInfo.inputState, currentFrame);
|
||||
movementState.viewAngles = viewAngles;
|
||||
|
||||
//Console.Print("tick: " + viewAngles.ToString());
|
||||
|
||||
//if (frameInfo.movementState.frame != currentFrame)
|
||||
World.UpdatePlayerState(PlayerId, currentFrame, movementState);
|
||||
//else
|
||||
// currentFrame = currentFrame;
|
||||
}
|
||||
}
|
||||
else if (!predict)
|
||||
{
|
||||
SetCameraEulerAngles(viewAnglesLastFrame, true);
|
||||
ApplyInputToCamera(inputState, true);
|
||||
SimulatePlayerMovement(inputState, World.Frame); // MAYBE?
|
||||
}
|
||||
|
||||
//if (!movementState.currentVelocity.IsZero)
|
||||
// Console.Print($"{(World.IsClient ? "client" : "server")} {World.Frame} vel: {movementState.currentVelocity}, pos: {movementState.position}");
|
||||
|
||||
viewAnglesLastFrame = viewAngles;
|
||||
|
||||
#if false
|
||||
|
||||
Reference in New Issue
Block a user