698 lines
31 KiB
C#
698 lines
31 KiB
C#
#if true
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using FlaxEngine;
|
|
using FlaxEngine.Assertions;
|
|
using FlaxEngine.Json;
|
|
using FlaxEngine.Networking;
|
|
using Console = Game.Console;
|
|
|
|
namespace Game
|
|
{
|
|
public enum GameModeMessageType : byte
|
|
{
|
|
WelcomePlayer, // WelcomePlayerMessage
|
|
SpawnPlayer,
|
|
PlayerInput,
|
|
PlayerPosition, // world update
|
|
PlayerSnapshot, // send world state delta to client since last client's acknowledged frame
|
|
|
|
LastMessageType = 128,
|
|
}
|
|
|
|
|
|
// Manages world simulation and handles network messages
|
|
public class WorldStateManager
|
|
{
|
|
private class WorldState
|
|
{
|
|
public ulong frame;
|
|
public List<PlayerActor> actors;
|
|
|
|
public Dictionary<uint, PlayerFrame[]> playerFrameHistory;
|
|
|
|
public WorldState()
|
|
{
|
|
actors = new List<PlayerActor>();
|
|
playerFrameHistory = new Dictionary<uint, PlayerFrame[]>();
|
|
}
|
|
}
|
|
|
|
private class PlayerFrame
|
|
{
|
|
public ulong frame;
|
|
public Float3 position;
|
|
}
|
|
|
|
private Dictionary<uint, PlayerActor> players;
|
|
private Dictionary<uint, NetworkConnection> playerConnections;
|
|
public Dictionary<uint, ulong> playerLastReceivedFrames;
|
|
private Dictionary<uint, ulong> playerLastFrame;
|
|
private bool welcomed = false;
|
|
|
|
private WorldState serverWorldState;
|
|
private WorldState clientWorldState;
|
|
private GameMode gameMode;
|
|
private Scene scene;
|
|
private Actor worldSpawn;
|
|
|
|
private ulong lastReceivedServerFrame = 0;
|
|
public ulong ServerFrame => /*NetworkManager.server != null ? serverWorldState.frame :*/ lastReceivedServerFrame;
|
|
public ulong ClientFrame => clientWorldState.frame;
|
|
public float ServerTime = 0f;
|
|
public float ClientTime = 0f;
|
|
|
|
public bool IsServer = false;
|
|
public bool IsClient = false;
|
|
public bool IsLocalClient = false; // Context dependant, true when message is handled by local client
|
|
|
|
public WorldStateManager(bool isServer = false, bool isClient = false, bool isLocalClient = false)
|
|
{
|
|
IsServer = isServer;
|
|
IsClient = isClient;
|
|
IsLocalClient = isLocalClient;
|
|
Assert.IsTrue(isServer || isClient || isLocalClient);
|
|
|
|
Init();
|
|
}
|
|
|
|
public void Init()
|
|
{
|
|
//welcomed = false;
|
|
//lastReceivedServerFrame = 0;
|
|
ServerTime = Time.GameTime;
|
|
//ClientTime = 0f;
|
|
|
|
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();
|
|
gameMode = new GameMode();
|
|
|
|
if (IsServer)
|
|
NetworkManager.RegisterServerMessageCallback(OnMessage);
|
|
else
|
|
NetworkManager.RegisterClientMessageCallback(OnMessage);
|
|
|
|
if (IsLocalClient)
|
|
{
|
|
PhysicsScene localPhysicsScene = Physics.FindOrCreateScene("LocalPhysicsScene");
|
|
|
|
Guid localClientSceneGuid = JsonSerializer.ParseID("c095f9ac4989a46afd7fe3821f086e2e");
|
|
|
|
var onSceneLoaded = (Scene loadedScene, Guid id) =>
|
|
{
|
|
if (localClientSceneGuid == id)
|
|
{
|
|
loadedScene.PhysicsScene = localPhysicsScene;
|
|
scene = loadedScene;
|
|
}
|
|
};
|
|
|
|
try
|
|
{
|
|
Level.SceneLoaded += onSceneLoaded;
|
|
Level.LoadScene(new SceneReference(localClientSceneGuid));
|
|
}
|
|
finally
|
|
{
|
|
Level.SceneLoaded -= onSceneLoaded;
|
|
}
|
|
}
|
|
else
|
|
scene = Level.GetScene(0);
|
|
Assert.IsTrue(scene);
|
|
|
|
Level.SceneLoaded += OnLevelLoaded;
|
|
//Scripting.LateUpdate += OnLateUpdatePre;
|
|
Scripting.LateFixedUpdate += OnLateUpdatePre;
|
|
|
|
worldSpawn = scene.FindActor("WorldSpawn") ?? Level.FindActor("WorldSpawn");
|
|
Assert.IsTrue(worldSpawn);
|
|
}
|
|
|
|
public void Cleanup()
|
|
{
|
|
if (IsServer)
|
|
NetworkManager.UnregisterServerMessageCallback(OnMessage);
|
|
else
|
|
NetworkManager.UnregisterClientMessageCallback(OnMessage);
|
|
|
|
Level.SceneLoaded -= OnLevelLoaded;
|
|
//Scripting.LateUpdate -= OnLateUpdatePre;
|
|
Scripting.LateFixedUpdate -= OnLateUpdatePre;
|
|
|
|
if (scene)
|
|
foreach (var player in scene.GetChildren<PlayerActor>())
|
|
{
|
|
FlaxEngine.Object.Destroy(player);
|
|
}
|
|
}
|
|
|
|
private PlayerFrame GetPlayerFrame(uint playerIndex, ulong playerFrameIndex)
|
|
{
|
|
WorldState worldState = NetworkManager.server != null ? serverWorldState : clientWorldState;
|
|
PlayerFrame[] playerFrames = worldState.playerFrameHistory[playerIndex];
|
|
PlayerFrame playerFrame = playerFrames[playerFrameIndex % 120];
|
|
|
|
if (playerFrame.frame != playerFrameIndex)
|
|
return null;
|
|
|
|
return playerFrame;
|
|
}
|
|
|
|
public void OnLevelLoaded(Scene scene, Guid assetGuid)
|
|
{
|
|
serverWorldState.frame = 0;
|
|
Console.Print("level loaded");
|
|
}
|
|
|
|
public void OnLateUpdatePre()
|
|
{
|
|
try
|
|
{
|
|
//NetworkManager.IsServer = NetworkManager.server != null;
|
|
//NetworkManager.IsClient = (NetworkManager.client != null || NetworkManager.IsDemoPlaying) && NetworkManager.server == null;
|
|
//NetworkManager.IsLocalClient = (NetworkManager.client != null || NetworkManager.IsDemoPlaying) && NetworkManager.server != null;
|
|
OnLateUpdate();
|
|
}
|
|
finally
|
|
{
|
|
//NetworkManager.IsServer = false;
|
|
//NetworkManager.IsClient = false;
|
|
//NetworkManager.IsLocalClient = false;
|
|
}
|
|
}
|
|
|
|
public void OnLateUpdate()
|
|
{
|
|
if (IsServer)
|
|
{
|
|
foreach (KeyValuePair<uint,PlayerActor> kv in players)
|
|
{
|
|
var playerId = kv.Key;
|
|
var playerActor = kv.Value;
|
|
|
|
var playerFrames = serverWorldState.playerFrameHistory[playerId];
|
|
var playerFrame = playerFrames[serverWorldState.frame % 120];
|
|
|
|
playerFrame.frame = serverWorldState.frame;
|
|
//playerFrame.position = playerActor.Position;
|
|
PlayerMovement playerMovement = playerActor.GetScript<PlayerMovement>();
|
|
playerMovement.input.GetState(serverWorldState.frame, out var inputState, out var actorState);
|
|
playerFrame.position = actorState.position;
|
|
}
|
|
|
|
foreach (KeyValuePair<uint, PlayerActor> kv in players)
|
|
{
|
|
var otherPlayerId = kv.Key;
|
|
foreach (KeyValuePair<uint, PlayerActor> kv2 in players)
|
|
{
|
|
//if (kv2.Key == playerId)
|
|
// continue;
|
|
|
|
var playerActor = kv2.Value;
|
|
var playerId = kv2.Key;
|
|
|
|
// TODO: relevancy checks here etc.
|
|
|
|
PlayerMovement playerMovement = playerActor.GetScript<PlayerMovement>();
|
|
//PlayerActorState actorState = playerMovement.input.GetCurrentActorState();
|
|
//PlayerInputState inputState = playerMovement.input.GetCurrentInputState();
|
|
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(playerFrame);
|
|
message.WriteUInt32(kv2.Key);
|
|
message.WriteSingle(actorState.position.X);
|
|
message.WriteSingle(actorState.position.Y);
|
|
message.WriteSingle(actorState.position.Z);
|
|
message.WriteSingle(actorState.velocity.X);
|
|
message.WriteSingle(actorState.velocity.Y);
|
|
message.WriteSingle(actorState.velocity.Z);
|
|
message.WriteSingle(actorState.orientation.X);
|
|
message.WriteSingle(actorState.orientation.Y);
|
|
message.WriteSingle(actorState.orientation.Z);
|
|
message.WriteSingle(actorState.orientation.W);
|
|
message.WriteSingle(actorState.viewAngles.X);
|
|
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);
|
|
message.WriteSingle(inputState.viewDeltaY);
|
|
message.WriteSingle(inputState.moveForward);
|
|
message.WriteSingle(inputState.moveRight);
|
|
message.WriteBoolean(inputState.attacking);
|
|
message.WriteBoolean(inputState.jumping);
|
|
|
|
NetworkManager.ServerEndSendMessage(ref message, playerConnections[otherPlayerId]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IsClient || IsLocalClient)
|
|
{
|
|
//if (!welcomed)
|
|
// return;
|
|
|
|
if (welcomed)
|
|
foreach (PlayerActor playerActor in scene.GetChildren<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[ClientFrame % 120];
|
|
|
|
playerFrame.frame = ClientFrame;
|
|
playerFrame.position = playerActor.Position;
|
|
}
|
|
|
|
clientWorldState.frame++;
|
|
|
|
/*PlayerActor playerActor = scene.GetChildren<PlayerActor>().FirstOrDefault(x =>
|
|
x.GetScript<PlayerMovement>().PlayerId == NetworkManager.LocalPlayerClientId);
|
|
|
|
if (playerActor == null)
|
|
return;*/
|
|
|
|
//var playerFrame = localPlayerFrameHistory[serverWorldState.frame % 120];
|
|
|
|
//playerFrame.frame = serverWorldState.frame;
|
|
//playerFrame.position = playerActor.Position;
|
|
|
|
/*{
|
|
NetworkMessage message = NetworkManager.ClientBeginSendMessage();
|
|
message.WriteByte((byte)GameModeMessageType.PlayerPosition);
|
|
message.WriteUInt64(worldState.frame);
|
|
message.WriteUInt32(NetworkManager.LocalPlayerClientId);
|
|
message.WriteSingle(playerActor.Position.X);
|
|
message.WriteSingle(playerActor.Position.Y);
|
|
message.WriteSingle(playerActor.Position.Z);
|
|
NetworkManager.ClientEndSendMessage(ref message);
|
|
}*/
|
|
}
|
|
else if (IsLocalClient)
|
|
{
|
|
|
|
}
|
|
|
|
serverWorldState.frame++;
|
|
|
|
/*foreach (KeyValuePair<uint,PlayerActor> kv in players)
|
|
{
|
|
var playerId = kv.Key;
|
|
var playerActor = kv.Value;
|
|
var playerConnection = playerConnections[playerId];
|
|
|
|
if (NetworkManager.IsLocalClient && playerId == NetworkManager.LocalPlayerClientId)
|
|
continue;
|
|
|
|
{
|
|
NetworkMessage message = NetworkManager.ServerBeginSendMessage();
|
|
message.WriteByte((byte)GameModeMessageType.PlayerPosition);
|
|
message.WriteUInt64(0);
|
|
message.WriteSingle(playerActor.Position.X);
|
|
message.WriteSingle(playerActor.Position.Y);
|
|
message.WriteSingle(playerActor.Position.Z);
|
|
NetworkManager.ServerEndSendMessage(ref message, playerConnections[playerId]);
|
|
}
|
|
}*/
|
|
}
|
|
|
|
public bool OnMessageServer(ref NetworkEvent networkEvent)
|
|
{
|
|
return OnMessage(ref networkEvent);
|
|
}
|
|
|
|
public bool OnMessageClient(ref NetworkEvent networkEvent)
|
|
{
|
|
return OnMessage(ref networkEvent /*NetworkMessage message, NetworkConnection sender*/);
|
|
}
|
|
|
|
public bool OnMessage(ref NetworkEvent networkEvent)
|
|
{
|
|
byte messageTypeByte = networkEvent.Message.ReadByte();
|
|
if (!Enum.IsDefined(typeof(GameModeMessageType), messageTypeByte))
|
|
{
|
|
//Console.PrintError($"GameModeManager: Unsupported message type received from client: {messageTypeByte}");
|
|
return false;
|
|
}
|
|
|
|
GameModeMessageType messageType = (GameModeMessageType)messageTypeByte;
|
|
NetworkManager.DebugLastHandledMessage = messageType.ToString();
|
|
|
|
//Console.Print($"GameModeManager: {messageType}");
|
|
switch (messageType)
|
|
{
|
|
case GameModeMessageType.WelcomePlayer:
|
|
{
|
|
welcomed = true;
|
|
if (IsClient || IsLocalClient)
|
|
{
|
|
WelcomePlayerMessage welcomePlayer = WelcomePlayerMessage.Read(ref networkEvent.Message);
|
|
if (!IsLocalClient)
|
|
serverWorldState.frame = welcomePlayer.frame;
|
|
//lastReceivedServerFrame = welcomePlayer.frame;
|
|
clientWorldState.frame += welcomePlayer.frame;
|
|
|
|
ClientTime = welcomePlayer.time;
|
|
foreach (var playerInfo in welcomePlayer.players)
|
|
{
|
|
SpawnPlayer(playerInfo.playerId, playerInfo.playerPosition, new Float3(0));
|
|
|
|
var playerFrames = new PlayerFrame[120];
|
|
for (int j = 0; j < playerFrames.Length; j++)
|
|
playerFrames[j] = new PlayerFrame();
|
|
clientWorldState.playerFrameHistory.Add(playerInfo.playerId, playerFrames);
|
|
}
|
|
|
|
Console.Print("received welcome: frame " + serverWorldState.frame);
|
|
|
|
if (!players.ContainsKey(NetworkManager.LocalPlayerClientId)) // listen server
|
|
players.Add(NetworkManager.LocalPlayerClientId, null);
|
|
//playerConnections.Add(NetworkManager.LocalPlayerClientId, connection);
|
|
}
|
|
break;
|
|
}
|
|
case GameModeMessageType.SpawnPlayer:
|
|
{
|
|
uint playerId = networkEvent.Message.ReadUInt32();
|
|
ulong playerFrameIndex = networkEvent.Message.ReadUInt64();
|
|
|
|
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);
|
|
}
|
|
|
|
SpawnPlayer(playerId,
|
|
new Float3(networkEvent.Message.ReadSingle(), networkEvent.Message.ReadSingle(), networkEvent.Message.ReadSingle()),
|
|
new Float3(networkEvent.Message.ReadSingle(), networkEvent.Message.ReadSingle(), networkEvent.Message.ReadSingle()));
|
|
|
|
//if (NetworkManager.IsClient)
|
|
players[playerId].GetScript<PlayerMovement>().input.frame = ClientFrame;
|
|
break;
|
|
}
|
|
case GameModeMessageType.PlayerInput:
|
|
{
|
|
uint playerId = networkEvent.Sender.ConnectionId;
|
|
PlayerInputState inputState = new PlayerInputState();
|
|
inputState.frame = networkEvent.Message.ReadUInt64();
|
|
inputState.viewDeltaX = networkEvent.Message.ReadSingle();
|
|
inputState.viewDeltaY = networkEvent.Message.ReadSingle();
|
|
inputState.moveForward = networkEvent.Message.ReadSingle();
|
|
inputState.moveRight = networkEvent.Message.ReadSingle();
|
|
inputState.attacking = networkEvent.Message.ReadBoolean();
|
|
inputState.jumping = networkEvent.Message.ReadBoolean();
|
|
|
|
UpdatePlayerInput(playerId, inputState);
|
|
|
|
|
|
|
|
playerLastReceivedFrames[playerId] = inputState.frame;
|
|
break;
|
|
}
|
|
case GameModeMessageType.PlayerPosition:
|
|
{
|
|
//uint playerId = networkEvent.Sender.ConnectionId;
|
|
PlayerInputState inputState = default; //?
|
|
PlayerActorState actorState;
|
|
|
|
ulong reportedFrame = networkEvent.Message.ReadUInt64();
|
|
uint reportedPlayerId = networkEvent.Message.ReadUInt32();
|
|
actorState.position.X = networkEvent.Message.ReadSingle();
|
|
actorState.position.Y = networkEvent.Message.ReadSingle();
|
|
actorState.position.Z = networkEvent.Message.ReadSingle();
|
|
actorState.velocity.X = networkEvent.Message.ReadSingle();
|
|
actorState.velocity.Y = networkEvent.Message.ReadSingle();
|
|
actorState.velocity.Z = networkEvent.Message.ReadSingle();
|
|
actorState.orientation.X = networkEvent.Message.ReadSingle();
|
|
actorState.orientation.Y = networkEvent.Message.ReadSingle();
|
|
actorState.orientation.Z = networkEvent.Message.ReadSingle();
|
|
actorState.orientation.W = networkEvent.Message.ReadSingle();
|
|
actorState.viewAngles.X = networkEvent.Message.ReadSingle();
|
|
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();
|
|
inputState.viewDeltaY = networkEvent.Message.ReadSingle();
|
|
inputState.moveForward = networkEvent.Message.ReadSingle();
|
|
inputState.moveRight = networkEvent.Message.ReadSingle();
|
|
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 (reportedPlayerId == NetworkManager.LocalPlayerClientId && reportedFrame < lastReceivedServerFrame)
|
|
{
|
|
//Console.Print($"packet wrong order, last received: {lastReceivedServerFrame}, new: {reportedFrame}");
|
|
break;
|
|
}
|
|
|
|
if (IsClient)
|
|
{
|
|
if (reportedPlayerId == NetworkManager.LocalPlayerClientId)
|
|
lastReceivedServerFrame = reportedFrame;
|
|
|
|
//Console.Print($"we drifted, corrected. client frame: {serverWorldState.frame}, server frame: {reportedFrame}");
|
|
PlayerActor playerActor = scene.GetChildren<PlayerActor>().FirstOrDefault(x =>
|
|
x.GetScript<PlayerMovement>().PlayerId == reportedPlayerId);
|
|
|
|
|
|
if (playerActor != null)
|
|
{
|
|
PlayerInput playerInput = playerActor.GetScript<PlayerMovement>().input;
|
|
|
|
if (IsLocalClient && reportedPlayerId == NetworkManager.LocalPlayerClientId)
|
|
{ }
|
|
else
|
|
playerInput.SetState(reportedFrame, inputState, actorState);
|
|
|
|
if (!IsLocalClient && playerInput is PlayerInputNetwork)
|
|
{
|
|
playerActor.Position = actorState.position;
|
|
playerActor.GetScript<PlayerMovement>().movementState.currentVelocity = actorState.velocity;
|
|
playerActor.GetScript<PlayerMovement>().movementState.lastJumped = actorState.lastJumpTime;
|
|
playerActor.GetScript<PlayerMovement>().movementState.numJumps = actorState.numJumps;
|
|
playerActor.GetScript<PlayerMovement>().movementState.jumped = actorState.jumped;
|
|
playerActor.GetScript<PlayerMovement>().SetCameraEulerAngles(actorState.viewAngles, true);
|
|
}
|
|
//playerActor.SetPosition(reportedPosition);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
Console.PrintError($"GameModeManager: Unhandled message type: {messageType}");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool OnClientConnecting(NetworkConnection connection)
|
|
{
|
|
//if (connection.ConnectionId != NetworkManager.LocalPlayerClientId)
|
|
{
|
|
Console.Print("sending welcome: frame " + serverWorldState.frame);
|
|
WelcomePlayerMessage welcomeMessage = new WelcomePlayerMessage();
|
|
welcomeMessage.frame = serverWorldState.frame;
|
|
welcomeMessage.time = ServerTime;
|
|
welcomeMessage.players = new WelcomePlayerMessage.PlayerInfo[serverWorldState.actors.Count];
|
|
|
|
for (int i = 0; i < serverWorldState.actors.Count; i++)
|
|
{
|
|
PlayerActor playerActor = serverWorldState.actors[i];
|
|
ref WelcomePlayerMessage.PlayerInfo playerInfo = ref welcomeMessage.players[i];
|
|
playerInfo.playerId = playerActor.GetScript<PlayerMovement>().PlayerId;
|
|
playerInfo.playerPosition = playerActor.Position;
|
|
|
|
playerActor.GetScript<PlayerMovement>().input.SetState(serverWorldState.frame, new PlayerInputState(), new PlayerActorState()
|
|
{
|
|
position = playerActor.Position,
|
|
velocity = playerActor.GetScript<PlayerMovement>().movementState.currentVelocity,
|
|
orientation = playerActor.GetScript<PlayerMovement>().rootActor.Orientation,
|
|
viewAngles = playerActor.GetScript<PlayerMovement>().viewAngles,
|
|
lastJumpTime = playerActor.GetScript<PlayerMovement>().movementState.lastJumped,
|
|
numJumps = playerActor.GetScript<PlayerMovement>().movementState.numJumps,
|
|
jumped = playerActor.GetScript<PlayerMovement>().movementState.jumped,
|
|
//onGround = playerActor.GetScript<PlayerMovement>().movementState.onGround,
|
|
});
|
|
}
|
|
NetworkMessage message = NetworkManager.ServerBeginSendMessage();
|
|
welcomeMessage.Write(ref message);
|
|
NetworkManager.ServerEndSendMessage(ref message, connection);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public bool OnClientConnected(NetworkConnection connection)
|
|
{
|
|
uint playerId = connection.ConnectionId;
|
|
if (NetworkManager.LocalPlayerClientId == 0)
|
|
NetworkManager.LocalPlayerClientId = playerId;
|
|
|
|
var spawns = worldSpawn.GetChildren<Actor>().Where(x => x.Name.StartsWith("PlayerSpawn_")).ToArray();
|
|
Console.Print($"found {spawns.Length} spawns");
|
|
|
|
var randomSpawn = spawns.First();
|
|
|
|
|
|
Float3 position = randomSpawn.Position + new Float3(0f, 4.1f, 0f);
|
|
Float3 eulerAngles = randomSpawn.Orientation.EulerAngles;
|
|
|
|
players.Add(playerId, null);
|
|
playerConnections.Add(playerId, connection);
|
|
var playerFrames = new PlayerFrame[120];
|
|
for (int i = 0; i < playerFrames.Length; i++)
|
|
playerFrames[i] = new PlayerFrame();
|
|
serverWorldState.playerFrameHistory.Add(playerId, playerFrames);
|
|
|
|
|
|
SpawnPlayer(playerId, position, eulerAngles);
|
|
{
|
|
NetworkMessage message = NetworkManager.ServerBeginSendMessage();
|
|
message.WriteByte((byte)GameModeMessageType.SpawnPlayer);
|
|
message.WriteUInt32(playerId);
|
|
message.WriteUInt64(serverWorldState.frame);
|
|
message.WriteSingle(position.X);
|
|
message.WriteSingle(position.Y);
|
|
message.WriteSingle(position.Z);
|
|
message.WriteSingle(eulerAngles.X);
|
|
message.WriteSingle(eulerAngles.Y);
|
|
message.WriteSingle(eulerAngles.Z);
|
|
NetworkManager.ServerEndSendMessage(ref message, connection);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void SpawnPlayer(uint playerId, Float3 position, Vector3 eulerAngles)
|
|
{
|
|
if (IsServer && !playerLastFrame.ContainsKey(playerId))
|
|
playerLastFrame.Add(playerId, serverWorldState.frame);
|
|
|
|
//if (IsLocalClient && playerId == NetworkManager.LocalPlayerClientId)
|
|
// return; // Handled by listenserver
|
|
|
|
//spawned = true;
|
|
|
|
string prefabPath = Path.Combine(AssetManager.ContentPath, "Common");
|
|
var playerPrefab = Content.Load<Prefab>(Path.Combine(prefabPath, "PlayerPrefab.prefab"));
|
|
if (playerPrefab == null)
|
|
Console.PrintError("GameModeManager: Failed to find PlayerPrefab");
|
|
|
|
PlayerActor playerActor = SpawnActor<PlayerActor>(playerPrefab);
|
|
playerActor.Initialize(playerId, position, eulerAngles);
|
|
//playerActor.Teleport(position, eulerAngles);
|
|
|
|
if (!players.ContainsKey(playerId))
|
|
players.Add(playerId, null);
|
|
players[playerId] = playerActor;
|
|
PlayerInput playerInput = playerActor.GetScript<PlayerMovement>().input;
|
|
playerInput.frame = IsServer ? serverWorldState.frame : ClientFrame;
|
|
if (IsServer)
|
|
{
|
|
serverWorldState.actors.Add(playerActor);
|
|
if (!playerLastReceivedFrames.ContainsKey(playerId))
|
|
playerLastReceivedFrames.Add(playerId, 0);
|
|
}
|
|
}
|
|
|
|
private T SpawnActor<T>(Prefab prefab) where T : Actor
|
|
{
|
|
T actor = PrefabManager.SpawnPrefab(prefab, scene).As<T>();
|
|
actor.PhysicsScene = scene.PhysicsScene;
|
|
return actor;
|
|
}
|
|
|
|
private 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.movementState.currentVelocity,
|
|
orientation = playerMovement.rootActor.Orientation,
|
|
viewAngles = playerMovement.viewAngles,
|
|
lastJumpTime = playerMovement.movementState.lastJumped,
|
|
numJumps = playerMovement.movementState.numJumps,
|
|
jumped = playerMovement.movementState.jumped,
|
|
//onGround = playerMovement.movementState.onGround,
|
|
});
|
|
|
|
simframs++;
|
|
prevInputState = lastInputState;
|
|
}
|
|
|
|
if (playerActor.Position.Length < 1.0f)
|
|
simframs = simframs;
|
|
|
|
playerLastFrame[playerId] = inputState.frame;//frame;
|
|
|
|
if (simframs > 1)
|
|
Console.Print($"simulated {simframs} frames");
|
|
}
|
|
}
|
|
}
|
|
#endif |