netcode good condition

This commit is contained in:
2023-04-19 21:38:28 +03:00
parent 3b4d50e75e
commit 353db087a6
8 changed files with 403 additions and 79 deletions

View File

@@ -45,6 +45,8 @@ namespace Game
private static Dictionary<uint, PlayerActor> players;
private static Dictionary<uint, NetworkConnection> playerConnections;
public static Dictionary<uint, ulong> playerLastReceivedFrames;
private static Dictionary<uint, ulong> playerLastFrame;
private static bool welcomed = false;
private static WorldState serverWorldState;
@@ -65,6 +67,8 @@ namespace Game
players = new Dictionary<uint, PlayerActor>();
playerConnections = new Dictionary<uint, NetworkConnection>();
playerLastReceivedFrames = new Dictionary<uint, ulong>();
playerLastFrame = new Dictionary<uint, ulong>();
serverWorldState = new WorldState();
clientWorldState = new WorldState();
@@ -138,24 +142,28 @@ namespace Game
foreach (KeyValuePair<uint, PlayerActor> kv in players)
{
var playerId = kv.Key;
var otherPlayerId = kv.Key;
foreach (KeyValuePair<uint, PlayerActor> kv2 in players)
{
//if (kv2.Key == playerId)
// continue;
var otherPlayerActor = kv2.Value;
var playerActor = kv2.Value;
var playerId = kv2.Key;
// TODO: relevancy checks here etc.
PlayerMovement playerMovement = otherPlayerActor.GetScript<PlayerMovement>();
PlayerMovement playerMovement = playerActor.GetScript<PlayerMovement>();
//PlayerActorState actorState = playerMovement.input.GetCurrentActorState();
//PlayerInputState inputState = playerMovement.input.GetCurrentInputState();
playerMovement.input.GetState(serverWorldState.frame, out var inputState, out var actorState);
var playerFrame = playerLastFrame[playerId];
if (!playerMovement.input.GetState(playerFrame, out var inputState, out var actorState))
Console.Print("send input failure to client");
{
NetworkMessage message = NetworkManager.ServerBeginSendMessage();
message.WriteByte((byte)GameModeMessageType.PlayerPosition);
message.WriteUInt64(serverWorldState.frame);
message.WriteUInt64(playerFrame);
message.WriteUInt32(kv2.Key);
message.WriteSingle(actorState.position.X);
message.WriteSingle(actorState.position.Y);
@@ -171,6 +179,8 @@ namespace Game
message.WriteSingle(actorState.viewAngles.Y);
message.WriteSingle(actorState.viewAngles.Z);
message.WriteSingle(actorState.lastJumpTime);
message.WriteInt32(actorState.numJumps);
message.WriteBoolean(actorState.jumped);
//inputState.frame
message.WriteSingle(inputState.viewDeltaX);
@@ -180,7 +190,7 @@ namespace Game
message.WriteBoolean(inputState.attacking);
message.WriteBoolean(inputState.jumping);
NetworkManager.ServerEndSendMessage(ref message, playerConnections[playerId]);
NetworkManager.ServerEndSendMessage(ref message, playerConnections[otherPlayerId]);
}
}
}
@@ -195,6 +205,13 @@ namespace Game
foreach (PlayerActor playerActor in Level.GetActors<PlayerActor>())
{
var playerId = playerActor.PlayerId;
if (!clientWorldState.playerFrameHistory.ContainsKey(playerId))
{
var playerFrames = new PlayerFrame[120];
for (int j = 0; j < playerFrames.Length; j++)
playerFrames[j] = new PlayerFrame();
clientWorldState.playerFrameHistory.Add(playerId, playerFrames);
}
var playerFrameHistory = clientWorldState.playerFrameHistory[playerId];
var playerFrame = playerFrameHistory[clientWorldState.frame % 120];
@@ -274,6 +291,11 @@ namespace Game
if (NetworkManager.IsClient || NetworkManager.IsLocalClient)
{
var serverFrame = networkEvent.Message.ReadUInt64();
if (!NetworkManager.IsLocalClient)
serverWorldState.frame = serverFrame;
//lastReceivedServerFrame = serverFrame;
clientWorldState.frame += serverFrame;
ClientTime = networkEvent.Message.ReadSingle();
int numActors = (int)networkEvent.Message.ReadUInt32();
for (int i = 0; i < numActors; i++)
@@ -294,11 +316,6 @@ namespace Game
Console.Print("received welcome: frame " + serverWorldState.frame);
if (!NetworkManager.IsLocalClient)
serverWorldState.frame = serverFrame;
//lastReceivedServerFrame = serverFrame;
clientWorldState.frame += serverFrame;
if (!players.ContainsKey(NetworkManager.LocalPlayerClientId)) // listen server
players.Add(NetworkManager.LocalPlayerClientId, null);
//playerConnections.Add(NetworkManager.LocalPlayerClientId, connection);
@@ -340,11 +357,15 @@ namespace Game
inputState.jumping = networkEvent.Message.ReadBoolean();
UpdatePlayerInput(playerId, inputState);
playerLastReceivedFrames[playerId] = inputState.frame;
break;
}
case GameModeMessageType.PlayerPosition:
{
uint playerId = networkEvent.Sender.ConnectionId;
//uint playerId = networkEvent.Sender.ConnectionId;
PlayerInputState inputState = default; //?
PlayerActorState actorState;
@@ -364,6 +385,8 @@ namespace Game
actorState.viewAngles.Y = networkEvent.Message.ReadSingle();
actorState.viewAngles.Z = networkEvent.Message.ReadSingle();
actorState.lastJumpTime = networkEvent.Message.ReadSingle();
actorState.numJumps = networkEvent.Message.ReadInt32();
actorState.jumped = networkEvent.Message.ReadBoolean();
inputState.frame = reportedFrame;
inputState.viewDeltaX = networkEvent.Message.ReadSingle();
@@ -373,16 +396,21 @@ namespace Game
inputState.attacking = networkEvent.Message.ReadBoolean();
inputState.jumping = networkEvent.Message.ReadBoolean();
//if (actorState.viewAngles != new Float3(90f, 0f, 0f))
// Console.Print($"{reportedFrame} has viewangles: {actorState.viewAngles}");
//Assert.IsTrue(reportedFrame >= lastReceivedServerFrame);
if (reportedFrame < lastReceivedServerFrame)
if (reportedPlayerId == NetworkManager.LocalPlayerClientId && reportedFrame < lastReceivedServerFrame)
{
//Console.Print($"packet wrong order, received {lastReceivedServerFrame}, new {reportedFrame}");
Console.Print($"packet wrong order, received {lastReceivedServerFrame}, new {reportedFrame}");
break;
}
if (NetworkManager.IsClient)
{
lastReceivedServerFrame = reportedFrame;
if (reportedPlayerId == NetworkManager.LocalPlayerClientId)
lastReceivedServerFrame = reportedFrame;
//Console.Print($"we drifted, corrected. client frame: {serverWorldState.frame}, server frame: {reportedFrame}");
PlayerActor playerActor = Level.GetActors<PlayerActor>().FirstOrDefault(x =>
x.GetScript<PlayerMovement>().PlayerId == reportedPlayerId);
@@ -392,9 +420,19 @@ namespace Game
{
PlayerInput playerInput = playerActor.GetScript<PlayerMovement>().input;
playerInput.SetState(reportedFrame, inputState, actorState);
{
if (NetworkManager.IsLocalClient && reportedPlayerId == NetworkManager.LocalPlayerClientId)
{ }
else
playerInput.SetState(reportedFrame, inputState, actorState);
if (!NetworkManager.IsLocalClient && playerInput is PlayerInputNetwork)
{
playerActor.Position = actorState.position;
playerActor.GetScript<PlayerMovement>().currentVelocity = actorState.velocity;
playerActor.GetScript<PlayerMovement>().lastJumped = actorState.lastJumpTime;
playerActor.GetScript<PlayerMovement>().numJumps = actorState.numJumps;
playerActor.GetScript<PlayerMovement>().jumped = actorState.jumped;
playerActor.GetScript<PlayerMovement>().SetCameraEulerAngles(actorState.viewAngles, true);
}
//playerActor.SetPosition(reportedPosition);
}
@@ -426,8 +464,20 @@ namespace Game
message.WriteSingle(playerActor.Position.X);
message.WriteSingle(playerActor.Position.Y);
message.WriteSingle(playerActor.Position.Z);
playerActor.GetScript<PlayerMovement>().input.SetState(serverWorldState.frame, new PlayerInputState(), new PlayerActorState()
{
position = playerActor.Position,
velocity = playerActor.GetScript<PlayerMovement>().currentVelocity,
orientation = playerActor.GetScript<PlayerMovement>().rootActor.Orientation,
viewAngles = playerActor.GetScript<PlayerMovement>().viewAngles,
lastJumpTime = playerActor.GetScript<PlayerMovement>().lastJumped,
numJumps = playerActor.GetScript<PlayerMovement>().numJumps,
jumped = playerActor.GetScript<PlayerMovement>().jumped,
});
}
NetworkManager.ServerEndSendMessage(ref message, connection);
}
return true;
}
@@ -475,7 +525,10 @@ namespace Game
private static void SpawnPlayer(uint playerId, Float3 position, Vector3 eulerAngles)
{
if (NetworkManager.IsLocalClient)
if (NetworkManager.IsServer && !playerLastFrame.ContainsKey(playerId))
playerLastFrame.Add(playerId, serverWorldState.frame);
if (NetworkManager.IsLocalClient && playerId == NetworkManager.LocalPlayerClientId)
return; // Handled by listenserver
//spawned = true;
@@ -495,13 +548,71 @@ namespace Game
PlayerInput playerInput = playerActor.GetScript<PlayerMovement>().input;
playerInput.frame = (NetworkManager.IsServer) ? serverWorldState.frame : clientWorldState.frame;
if (NetworkManager.IsServer)
{
serverWorldState.actors.Add(playerActor);
if (!playerLastReceivedFrames.ContainsKey(playerId))
playerLastReceivedFrames.Add(playerId, 0);
}
}
private static void UpdatePlayerInput(uint playerId, PlayerInputState inputState)
{
if (playerId == NetworkManager.LocalPlayerClientId)
{
playerLastFrame[playerId] = inputState.frame;
return;
}
PlayerActor playerActor = players[playerId];
PlayerMovement playerMovement = playerActor.GetScript<PlayerMovement>();
playerActor.UpdateNetworkInput(inputState);
ulong startFrame = playerLastFrame[playerId];
if (startFrame >= inputState.frame)
return; // dropped frame, ignore
// simulate at least one or more frame when receiving input frames from player. missing frames use inputs from previous frames
var simframs = 0;
ulong frame = startFrame+1;
PlayerInputState prevInputState;
playerMovement.input.GetState(frame - 1, out prevInputState, out var _);
for (; frame <= inputState.frame; frame++)
{
if (!playerMovement.input.GetState(frame, out var lastInputState, out var lastActorState))
{
// dropped frame, use previous input
lastInputState = prevInputState;
lastInputState.frame = frame;
}
playerMovement.ApplyInputToCamera(lastInputState, true);
playerMovement.SimulatePlayerMovement(lastInputState);
playerMovement.input.SetState(frame, lastInputState, new PlayerActorState()
{
position = playerActor.Position,
velocity = playerMovement.currentVelocity,
orientation = playerMovement.rootActor.Orientation,
viewAngles = playerMovement.viewAngles,
lastJumpTime = playerMovement.lastJumped,
numJumps = playerMovement.numJumps,
jumped = playerMovement.jumped,
});
simframs++;
prevInputState = lastInputState;
}
if (playerActor.Position.Length < 1.0f)
simframs = simframs;
playerLastFrame[playerId] = inputState.frame;//frame;
if (simframs > 1)
Console.Print($"simulated {simframs} frames");
}
}
}

View File

@@ -96,6 +96,12 @@ namespace Game
server.EndSendMessage(channelType, message, connection);
}
public static void ServerEndSendMessage(ref NetworkMessage message, NetworkConnection[] connections, NetworkChannelType channelType = NetworkChannelType.Reliable)
{
server.EndSendMessage(channelType, message, connections);
}
public static NetworkMessage ClientBeginSendMessage()
{
NetworkMessage message = client.BeginSendMessage();