|
|
|
|
@@ -22,29 +22,23 @@ public enum GameModeMessageType2 : byte
|
|
|
|
|
LastMessageType = 128,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class PlayerFrame
|
|
|
|
|
{
|
|
|
|
|
public ulong frame;
|
|
|
|
|
public Float3 position;
|
|
|
|
|
public PlayerInputState2 inputState;
|
|
|
|
|
public PlayerMovementState movementState;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public interface IClientInfo
|
|
|
|
|
{
|
|
|
|
|
public NetworkConnection Connection { get; set; }
|
|
|
|
|
public PlayerActor PlayerActor { get; set; }
|
|
|
|
|
public PlayerFrame[] FrameHistory { get; set; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class World
|
|
|
|
|
{
|
|
|
|
|
protected class ClientInfo
|
|
|
|
|
{
|
|
|
|
|
public NetworkConnection Connection;
|
|
|
|
|
public PlayerActor PlayerActor;
|
|
|
|
|
public PlayerFrame[] FrameHistory = new PlayerFrame[120];
|
|
|
|
|
|
|
|
|
|
public ClientInfo()
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < FrameHistory.Length; i++)
|
|
|
|
|
FrameHistory[i] = new PlayerFrame();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class PlayerFrame
|
|
|
|
|
{
|
|
|
|
|
public ulong frame;
|
|
|
|
|
public Float3 position;
|
|
|
|
|
public PlayerInputState2 inputState;
|
|
|
|
|
public PlayerMovementState movementState;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsServer => this is ServerWorld;
|
|
|
|
|
public bool IsClient => !IsServer;
|
|
|
|
|
public ulong Frame { get; protected set; }
|
|
|
|
|
@@ -54,7 +48,6 @@ public class World
|
|
|
|
|
|
|
|
|
|
protected Scene _scene;
|
|
|
|
|
protected Actor _worldSpawn;
|
|
|
|
|
protected Dictionary<uint, ClientInfo> _clients = new();
|
|
|
|
|
|
|
|
|
|
public static void InitClient()
|
|
|
|
|
{
|
|
|
|
|
@@ -65,6 +58,9 @@ public class World
|
|
|
|
|
{
|
|
|
|
|
WorldStore.ServerWorld = new ServerWorld();
|
|
|
|
|
WorldStore.ServerWorld.Init();
|
|
|
|
|
Scripting.Update += WorldStore.ServerWorld.OnUpdate;
|
|
|
|
|
Scripting.LateUpdate += WorldStore.ServerWorld.OnUpdateLate;
|
|
|
|
|
Scripting.FixedUpdate += WorldStore.ServerWorld.OnFixedUpdate;
|
|
|
|
|
}
|
|
|
|
|
public static void CleanupClient()
|
|
|
|
|
{
|
|
|
|
|
@@ -79,12 +75,17 @@ public class World
|
|
|
|
|
|
|
|
|
|
virtual protected void Init()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
Scripting.LateFixedUpdate += OnLateUpdate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual protected void Cleanup()
|
|
|
|
|
{
|
|
|
|
|
//Level.SceneLoaded -= OnLevelLoaded;
|
|
|
|
|
//Scripting.LateUpdate -= OnLateUpdatePre;
|
|
|
|
|
Scripting.Update -= OnUpdate;
|
|
|
|
|
Scripting.LateUpdate -= OnUpdateLate;
|
|
|
|
|
Scripting.FixedUpdate -= OnFixedUpdate;
|
|
|
|
|
Scripting.LateFixedUpdate -= OnLateUpdate;
|
|
|
|
|
|
|
|
|
|
if (_scene)
|
|
|
|
|
@@ -99,6 +100,21 @@ public class World
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnUpdate()
|
|
|
|
|
{
|
|
|
|
|
Console.Print("server Update");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnUpdateLate()
|
|
|
|
|
{
|
|
|
|
|
Console.Print("server LateUpdate");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnFixedUpdate()
|
|
|
|
|
{
|
|
|
|
|
Console.Print("server FixedUpdate");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void CreateScene(string sceneNamePrefix, string sceneGuid)
|
|
|
|
|
{
|
|
|
|
|
string physicsSceneName = $"{sceneNamePrefix}PhysicsScene";
|
|
|
|
|
@@ -155,7 +171,7 @@ public class World
|
|
|
|
|
_scene.Name = $"{sceneNamePrefix}Scene";
|
|
|
|
|
|
|
|
|
|
//Level.SceneLoaded += OnLevelLoaded;
|
|
|
|
|
Scripting.LateFixedUpdate += OnLateUpdate;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var importer = FlaxEngine.Object.New<Q3MapImporter>();
|
|
|
|
|
importer.mapPath = @"C:\dev\GoakeFlax\Assets\Maps\aerowalk.map";
|
|
|
|
|
@@ -167,16 +183,12 @@ public class World
|
|
|
|
|
Assert.IsTrue(_worldSpawn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void OnLateUpdate()
|
|
|
|
|
virtual protected void OnLateUpdate()
|
|
|
|
|
{
|
|
|
|
|
Frame++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void OnClientConnected(NetworkConnection connection)
|
|
|
|
|
{
|
|
|
|
|
uint playerId = connection.ConnectionId;
|
|
|
|
|
_clients.Add(playerId, new ClientInfo() { Connection = connection });
|
|
|
|
|
}
|
|
|
|
|
virtual protected IClientInfo GetClient(uint playerId) => null;
|
|
|
|
|
|
|
|
|
|
virtual protected PlayerActor SpawnPlayer(uint playerId, Float3 position, Vector3 eulerAngles)
|
|
|
|
|
{
|
|
|
|
|
@@ -189,7 +201,8 @@ public class World
|
|
|
|
|
playerActor.Initialize(playerId, position, eulerAngles);
|
|
|
|
|
//playerActor.Teleport(position, eulerAngles);
|
|
|
|
|
|
|
|
|
|
_clients[playerId].PlayerActor = playerActor;
|
|
|
|
|
IClientInfo player = GetClient(playerId);
|
|
|
|
|
player.PlayerActor = playerActor;
|
|
|
|
|
IPlayerInput playerInput = playerActor.GetScript<PlayerMovement>().Input;
|
|
|
|
|
playerInput.SetFrame(Frame);
|
|
|
|
|
/*if (IsServer)
|
|
|
|
|
@@ -213,7 +226,7 @@ public class World
|
|
|
|
|
|
|
|
|
|
public PlayerFrame GetPlayerFrame(uint playerId, ulong frame)
|
|
|
|
|
{
|
|
|
|
|
ClientInfo player = _clients[playerId];
|
|
|
|
|
IClientInfo player = GetClient(playerId);
|
|
|
|
|
PlayerFrame playerFrame = player.FrameHistory[frame % 120];
|
|
|
|
|
if (playerFrame.frame != frame)
|
|
|
|
|
return null;
|
|
|
|
|
@@ -229,10 +242,52 @@ public class World
|
|
|
|
|
inputState = playerFrame?.inputState ?? default;
|
|
|
|
|
return playerFrame != null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual public void UpdatePlayerInputState(uint playerId, ulong frame, PlayerInputState2 inputState, PlayerMovementState movementState)
|
|
|
|
|
{
|
|
|
|
|
IClientInfo player = GetClient(playerId);
|
|
|
|
|
|
|
|
|
|
PlayerFrame playerFrame = player.FrameHistory[frame % 120];
|
|
|
|
|
if (playerFrame.frame == frame)
|
|
|
|
|
{
|
|
|
|
|
playerFrame.inputState = inputState with
|
|
|
|
|
{
|
|
|
|
|
ViewDelta = playerFrame.inputState.ViewDelta + inputState.ViewDelta,
|
|
|
|
|
MoveForward = MathF.MaxMagnitude(playerFrame.inputState.MoveForward, inputState.MoveForward),
|
|
|
|
|
MoveRight = MathF.MaxMagnitude(playerFrame.inputState.MoveRight, inputState.MoveRight),
|
|
|
|
|
Attack = playerFrame.inputState.Attack || inputState.Attack,
|
|
|
|
|
Jump = playerFrame.inputState.Jump || inputState.Jump,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
playerFrame.inputState = inputState;
|
|
|
|
|
playerFrame.movementState = movementState;
|
|
|
|
|
playerFrame.frame = frame;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file class ServerWorld : World
|
|
|
|
|
{
|
|
|
|
|
protected class ClientInfo : IClientInfo
|
|
|
|
|
{
|
|
|
|
|
public NetworkConnection Connection { get; set; }
|
|
|
|
|
public PlayerActor PlayerActor { get; set; }
|
|
|
|
|
public PlayerFrame[] FrameHistory { get; set; } = new PlayerFrame[120];
|
|
|
|
|
public ulong LastReceivedFrame = 0;
|
|
|
|
|
public ulong LastSentDeltaFrame = 0; // TODO: Accumulate deltas since this frame
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected Dictionary<uint, ClientInfo> _clients = new();
|
|
|
|
|
|
|
|
|
|
protected override IClientInfo GetClient(uint playerId) => _clients[playerId];
|
|
|
|
|
|
|
|
|
|
protected override void Init()
|
|
|
|
|
{
|
|
|
|
|
NetworkManager.RegisterServerCallbacks(OnMessage, OnClientConnecting, OnClientConnected);
|
|
|
|
|
@@ -249,6 +304,12 @@ file class ServerWorld : World
|
|
|
|
|
base.Cleanup();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void OnLateUpdate()
|
|
|
|
|
{
|
|
|
|
|
Console.Print("server LateFixedUpdate");
|
|
|
|
|
base.OnLateUpdate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool OnMessage(ref NetworkEvent networkEvent)
|
|
|
|
|
{
|
|
|
|
|
byte messageTypeByte = networkEvent.Message.ReadByte();
|
|
|
|
|
@@ -266,23 +327,9 @@ file class ServerWorld : World
|
|
|
|
|
{
|
|
|
|
|
case GameModeMessageType2.AcceptConnection: // Client
|
|
|
|
|
{
|
|
|
|
|
AcceptConnectionMessage message = AcceptConnectionMessage.Read(ref networkEvent.Message);
|
|
|
|
|
Frame += message.Frame;
|
|
|
|
|
GameTime = message.GameTime;
|
|
|
|
|
ServerFrame = message.Frame;
|
|
|
|
|
|
|
|
|
|
/*foreach (var player in message.Players)
|
|
|
|
|
{
|
|
|
|
|
SpawnPlayer(player.PlayerId, player.PlayerPosition, new Float3(0));
|
|
|
|
|
|
|
|
|
|
var playerFrames = new PlayerFrame[120];
|
|
|
|
|
for (int j = 0; j < playerFrames.Length; j++)
|
|
|
|
|
playerFrames[j] = new PlayerFrame();
|
|
|
|
|
clientWorldState.playerFrameHistory.Add(player.PlayerId, playerFrames);
|
|
|
|
|
}*/
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case GameModeMessageType2.PlayerPosition:
|
|
|
|
|
case GameModeMessageType2.PlayerPosition: // FIXME: Should be the delta frame
|
|
|
|
|
{
|
|
|
|
|
//uint playerId = networkEvent.Sender.ConnectionId;
|
|
|
|
|
PlayerInputState2 inputState; //?
|
|
|
|
|
@@ -316,8 +363,40 @@ file class ServerWorld : World
|
|
|
|
|
inputState.Jump = networkEvent.Message.ReadBoolean();
|
|
|
|
|
|
|
|
|
|
ServerFrame = receivedFrame;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case GameModeMessageType2.PlayerInput:
|
|
|
|
|
{
|
|
|
|
|
PlayerInputState2 inputState; //?
|
|
|
|
|
|
|
|
|
|
ulong receivedFrame = networkEvent.Message.ReadUInt64();
|
|
|
|
|
uint reportedPlayerId = networkEvent.Message.ReadUInt32();
|
|
|
|
|
inputState.Frame = receivedFrame;
|
|
|
|
|
inputState.ViewDelta.X = networkEvent.Message.ReadSingle();
|
|
|
|
|
inputState.ViewDelta.Y = networkEvent.Message.ReadSingle();
|
|
|
|
|
inputState.MoveForward = networkEvent.Message.ReadSingle();
|
|
|
|
|
inputState.MoveRight = networkEvent.Message.ReadSingle();
|
|
|
|
|
inputState.Attack = networkEvent.Message.ReadBoolean();
|
|
|
|
|
inputState.Jump = networkEvent.Message.ReadBoolean();
|
|
|
|
|
|
|
|
|
|
Console.Print($"server receive client frame {receivedFrame}, current server frame {Frame}");
|
|
|
|
|
var asdf = receivedFrame;
|
|
|
|
|
receivedFrame = Frame;
|
|
|
|
|
|
|
|
|
|
if (inputState.MoveForward != 0)
|
|
|
|
|
receivedFrame = receivedFrame;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Sanity check
|
|
|
|
|
if (GetPlayerInputState(reportedPlayerId, receivedFrame, out var prevInputState))
|
|
|
|
|
{
|
|
|
|
|
Console.PrintWarning($"Duplicate frame received from client: {asdf}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PlayerMovementState movementState = default;
|
|
|
|
|
UpdatePlayerInputState(reportedPlayerId, receivedFrame, inputState, movementState);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
@@ -346,11 +425,10 @@ file class ServerWorld : World
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public new void OnClientConnected(NetworkConnection connection)
|
|
|
|
|
public void OnClientConnected(NetworkConnection connection)
|
|
|
|
|
{
|
|
|
|
|
base.OnClientConnected(connection);
|
|
|
|
|
uint playerId = connection.ConnectionId;
|
|
|
|
|
|
|
|
|
|
_clients.Add(playerId, new ClientInfo() { Connection = connection });
|
|
|
|
|
|
|
|
|
|
var spawns = _worldSpawn.GetChildren<Actor>().Where(x => x.Name.StartsWith("PlayerSpawn_")).ToArray();
|
|
|
|
|
Console.Print($"found {spawns.Length} spawns");
|
|
|
|
|
@@ -375,12 +453,44 @@ file class ServerWorld : World
|
|
|
|
|
NetworkManager.ServerEndSendMessage(ref message, connection);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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?
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override PlayerActor SpawnPlayer(uint playerId, Float3 position, Vector3 eulerAngles)
|
|
|
|
|
{
|
|
|
|
|
var playerActor = base.SpawnPlayer(playerId, position, eulerAngles);
|
|
|
|
|
playerActor.Input = new PlayerInputNetwork2(playerId, this);
|
|
|
|
|
return playerActor;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file class ClientWorld : World
|
|
|
|
|
{
|
|
|
|
|
protected class ClientInfo : IClientInfo
|
|
|
|
|
{
|
|
|
|
|
public NetworkConnection Connection { get; set; }
|
|
|
|
|
public PlayerActor PlayerActor { get; set; }
|
|
|
|
|
public PlayerFrame[] FrameHistory { get; set; } = new PlayerFrame[120];
|
|
|
|
|
|
|
|
|
|
public ClientInfo()
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < FrameHistory.Length; i++)
|
|
|
|
|
FrameHistory[i] = new PlayerFrame();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private uint _localPlayerId;
|
|
|
|
|
|
|
|
|
|
protected Dictionary<uint, ClientInfo> _clients = new();
|
|
|
|
|
|
|
|
|
|
protected override IClientInfo GetClient(uint playerId) => _clients[playerId];
|
|
|
|
|
|
|
|
|
|
protected override void Init()
|
|
|
|
|
{
|
|
|
|
|
NetworkManager.RegisterClientCallbacks(OnMessage, null, OnClientConnected);
|
|
|
|
|
@@ -396,6 +506,44 @@ file class ClientWorld : World
|
|
|
|
|
base.Cleanup();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override protected void OnLateUpdate()
|
|
|
|
|
{
|
|
|
|
|
foreach (var player in _scene.GetChildren<PlayerActor>())
|
|
|
|
|
{
|
|
|
|
|
if (player.PlayerId != _localPlayerId)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
ClientInfo playerClient = GetClient(player.PlayerId) as ClientInfo;
|
|
|
|
|
PlayerInputState2 inputState = player.Input.GetState();
|
|
|
|
|
PlayerMovementState movementState = player.GetScript<PlayerMovement>().movementState;
|
|
|
|
|
|
|
|
|
|
if (inputState.Frame == 0)
|
|
|
|
|
inputState = inputState;
|
|
|
|
|
/*public Float2 ViewDelta;
|
|
|
|
|
public float MoveForward;
|
|
|
|
|
public float MoveRight;
|
|
|
|
|
public bool Attack;
|
|
|
|
|
public bool Jump;*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Console.Print($"client send {Frame}");
|
|
|
|
|
UpdatePlayerInputState(player.PlayerId, Frame, inputState, movementState);
|
|
|
|
|
//Console.Print($"cframe: {Frame}");
|
|
|
|
|
|
|
|
|
|
NetworkMessage message = NetworkManager.ClientBeginSendMessage();
|
|
|
|
|
message.WriteByte((byte)GameModeMessageType2.PlayerInput);
|
|
|
|
|
message.WriteUInt64(Frame);
|
|
|
|
|
message.WriteUInt32(player.PlayerId);
|
|
|
|
|
message.WriteVector2(inputState.ViewDelta);
|
|
|
|
|
message.WriteSingle(inputState.MoveForward);
|
|
|
|
|
message.WriteSingle(inputState.MoveRight);
|
|
|
|
|
message.WriteBoolean(inputState.Attack);
|
|
|
|
|
message.WriteBoolean(inputState.Jump);
|
|
|
|
|
NetworkManager.ClientEndSendMessage(ref message);
|
|
|
|
|
}
|
|
|
|
|
base.OnLateUpdate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool OnMessage(ref NetworkEvent networkEvent)
|
|
|
|
|
{
|
|
|
|
|
byte messageTypeByte = networkEvent.Message.ReadByte();
|
|
|
|
|
@@ -426,8 +574,8 @@ file class ClientWorld : World
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Console.Print("received welcome: frame " + ServerFrame);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case GameModeMessageType2.SpawnPlayer:
|
|
|
|
|
{
|
|
|
|
|
uint playerId = networkEvent.Message.ReadUInt32();
|
|
|
|
|
@@ -447,8 +595,8 @@ file class ClientWorld : World
|
|
|
|
|
|
|
|
|
|
//if (NetworkManager.IsClient)
|
|
|
|
|
//players[playerId].GetScript<PlayerMovement>().Input.SetFrame(ClientFrame);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
#if false
|
|
|
|
|
case GameModeMessageType2.PlayerPosition:
|
|
|
|
|
{
|
|
|
|
|
@@ -484,8 +632,8 @@ file class ClientWorld : World
|
|
|
|
|
inputState.Jump = networkEvent.Message.ReadBoolean();
|
|
|
|
|
|
|
|
|
|
ServerFrame = receivedFrame;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
@@ -496,10 +644,12 @@ file class ClientWorld : World
|
|
|
|
|
|
|
|
|
|
public override bool IsLocalPlayer(uint playerId) => playerId == _localPlayerId;
|
|
|
|
|
|
|
|
|
|
public new void OnClientConnected(NetworkConnection connection)
|
|
|
|
|
public void OnClientConnected(NetworkConnection connection)
|
|
|
|
|
{
|
|
|
|
|
base.OnClientConnected(connection);
|
|
|
|
|
_localPlayerId = connection.ConnectionId;
|
|
|
|
|
uint playerId = connection.ConnectionId;
|
|
|
|
|
_clients.Add(playerId, new ClientInfo() { Connection = connection });
|
|
|
|
|
|
|
|
|
|
_localPlayerId = playerId;
|
|
|
|
|
Console.Print($"ClientWorld: Connected, playerId: {_localPlayerId}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|