netcode good condition
This commit is contained in:
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user