_asdf
This commit is contained in:
@@ -145,11 +145,18 @@ public class ConsoleInputTextBox : ConsoleTextBoxBase
|
||||
|
||||
public override void OnLostFocus()
|
||||
{
|
||||
// Prevent caret location getting reset back to beginning
|
||||
// Prevent caret location getting reset back to beginning,
|
||||
// and submitting the value when focus is lost.
|
||||
bool oldEditing = _isEditing;
|
||||
_isEditing = false;
|
||||
base.OnLostFocus();
|
||||
_isEditing = oldEditing;
|
||||
try
|
||||
{
|
||||
base.OnLostFocus();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isEditing = oldEditing;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
|
||||
54
Source/Game/GameMode/Messages/AcceptConnectionMessage.cs
Normal file
54
Source/Game/GameMode/Messages/AcceptConnectionMessage.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FlaxEngine.Networking;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace Game;
|
||||
|
||||
public struct AcceptConnectionMessage
|
||||
{
|
||||
public struct PlayerInfo
|
||||
{
|
||||
public uint PlayerId;
|
||||
public Float3 PlayerPosition;
|
||||
}
|
||||
public ulong Frame;
|
||||
public float GameTime;
|
||||
public PlayerInfo[] Players;
|
||||
|
||||
public static AcceptConnectionMessage Read(ref NetworkMessage networkMessage)
|
||||
{
|
||||
AcceptConnectionMessage packet = new AcceptConnectionMessage();
|
||||
packet.Frame = networkMessage.ReadUInt64();
|
||||
packet.GameTime = networkMessage.ReadSingle();
|
||||
int numActors = (int)networkMessage.ReadUInt32();
|
||||
|
||||
packet.Players = new PlayerInfo[numActors];
|
||||
for (int i = 0; i < numActors; i++)
|
||||
{
|
||||
packet.Players[i].PlayerId = networkMessage.ReadUInt32();
|
||||
packet.Players[i].PlayerPosition.X = networkMessage.ReadSingle();
|
||||
packet.Players[i].PlayerPosition.Y = networkMessage.ReadSingle();
|
||||
packet.Players[i].PlayerPosition.Z = networkMessage.ReadSingle();
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
public void Write(ref NetworkMessage networkMessage)
|
||||
{
|
||||
networkMessage.WriteByte((byte)GameModeMessageType2.AcceptConnection);
|
||||
networkMessage.WriteUInt64(Frame);
|
||||
networkMessage.WriteSingle(GameTime);
|
||||
networkMessage.WriteUInt32((uint)Players.Length);
|
||||
foreach (PlayerInfo player in Players)
|
||||
{
|
||||
networkMessage.WriteUInt32(player.PlayerId);
|
||||
networkMessage.WriteSingle(player.PlayerPosition.X);
|
||||
networkMessage.WriteSingle(player.PlayerPosition.Y);
|
||||
networkMessage.WriteSingle(player.PlayerPosition.Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FlaxEngine.Networking;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace Game;
|
||||
|
||||
public struct WelcomePlayerMessage
|
||||
{
|
||||
public struct PlayerInfo
|
||||
{
|
||||
public uint playerId;
|
||||
public Float3 playerPosition;
|
||||
}
|
||||
public ulong frame;
|
||||
public float time;
|
||||
public PlayerInfo[] players;
|
||||
|
||||
public static WelcomePlayerMessage Read(ref NetworkMessage networkMessage)
|
||||
{
|
||||
WelcomePlayerMessage packet = new WelcomePlayerMessage();
|
||||
packet.frame = networkMessage.ReadUInt64();
|
||||
packet.time = networkMessage.ReadSingle();
|
||||
int numActors = (int)networkMessage.ReadUInt32();
|
||||
|
||||
packet.players = new PlayerInfo[numActors];
|
||||
for (int i = 0; i < numActors; i++)
|
||||
{
|
||||
packet.players[i].playerId = networkMessage.ReadUInt32();
|
||||
packet.players[i].playerPosition.X = networkMessage.ReadSingle();
|
||||
packet.players[i].playerPosition.Y = networkMessage.ReadSingle();
|
||||
packet.players[i].playerPosition.Z = networkMessage.ReadSingle();
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
public void Write(ref NetworkMessage networkMessage)
|
||||
{
|
||||
networkMessage.WriteByte((byte)GameModeMessageType.WelcomePlayer);
|
||||
networkMessage.WriteUInt64(frame);
|
||||
networkMessage.WriteSingle(time);
|
||||
networkMessage.WriteUInt32((uint)players.Length);
|
||||
foreach (PlayerInfo player in players)
|
||||
{
|
||||
networkMessage.WriteUInt32(player.playerId);
|
||||
networkMessage.WriteSingle(player.playerPosition.X);
|
||||
networkMessage.WriteSingle(player.playerPosition.Y);
|
||||
networkMessage.WriteSingle(player.playerPosition.Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,8 @@ public enum NetworkMessageType : byte
|
||||
public static partial class NetworkManager
|
||||
{
|
||||
public delegate bool OnMessageDecl(ref NetworkEvent networkEvent);
|
||||
public delegate bool OnClientConnectingDecl(NetworkConnection sender);
|
||||
public delegate void OnClientConnectedDecl(NetworkConnection sender);
|
||||
|
||||
private static bool initialized;
|
||||
|
||||
@@ -45,28 +47,76 @@ public static partial class NetworkManager
|
||||
private static readonly ushort MaximumClients = 32;
|
||||
|
||||
private static List<OnMessageDecl> OnClientMessageDelegates = new(3);
|
||||
private static List<OnClientConnectingDecl> OnClientConnectingDelegates = new(3);
|
||||
private static List<OnClientConnectedDecl> OnClientConnectedDelegates = new(3);
|
||||
private static List<OnMessageDecl> OnServerMessageDelegates = new(3);
|
||||
private static List<OnClientConnectingDecl> OnServerConnectingDelegates = new(3);
|
||||
private static List<OnClientConnectedDecl> OnServerConnectedDelegates = new(3);
|
||||
|
||||
public static void RegisterClientMessageCallback(OnMessageDecl deleg)
|
||||
public static void RegisterClientCallbacks(OnMessageDecl onMessage, OnClientConnectingDecl onClientConnecting, OnClientConnectedDecl onClientConnected)
|
||||
{
|
||||
Assert.IsTrue(!OnClientMessageDelegates.Contains(deleg));
|
||||
OnClientMessageDelegates.Add(deleg);
|
||||
Assert.IsTrue(!OnClientMessageDelegates.Contains(onMessage));
|
||||
OnClientMessageDelegates.Add(onMessage);
|
||||
|
||||
if (onClientConnecting != null)
|
||||
{
|
||||
Assert.IsTrue(!OnClientConnectingDelegates.Contains(onClientConnecting));
|
||||
OnClientConnectingDelegates.Add(onClientConnecting);
|
||||
}
|
||||
if (onClientConnected != null)
|
||||
{
|
||||
Assert.IsTrue(!OnClientConnectedDelegates.Contains(onClientConnected));
|
||||
OnClientConnectedDelegates.Add(onClientConnected);
|
||||
}
|
||||
}
|
||||
public static void UnregisterClientMessageCallback(OnMessageDecl deleg)
|
||||
public static void UnregisterClientCallbacks(OnMessageDecl onMessage, OnClientConnectingDecl onClientConnecting, OnClientConnectedDecl onClientConnected)
|
||||
{
|
||||
Assert.IsTrue(OnClientMessageDelegates.Contains(deleg));
|
||||
OnClientMessageDelegates.Remove(deleg);
|
||||
Assert.IsTrue(OnClientMessageDelegates.Contains(onMessage));
|
||||
OnClientMessageDelegates.Remove(onMessage);
|
||||
|
||||
if (onClientConnecting != null)
|
||||
{
|
||||
Assert.IsTrue(OnClientConnectingDelegates.Contains(onClientConnecting));
|
||||
OnClientConnectingDelegates.Remove(onClientConnecting);
|
||||
}
|
||||
if (onClientConnected != null)
|
||||
{
|
||||
Assert.IsTrue(OnClientConnectedDelegates.Contains(onClientConnected));
|
||||
OnClientConnectedDelegates.Remove(onClientConnected);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RegisterServerMessageCallback(OnMessageDecl deleg)
|
||||
public static void RegisterServerCallbacks(OnMessageDecl onMessage, OnClientConnectingDecl onClientConnecting, OnClientConnectedDecl onClientConnected)
|
||||
{
|
||||
Assert.IsTrue(!OnServerMessageDelegates.Contains(deleg));
|
||||
OnServerMessageDelegates.Add(deleg);
|
||||
Assert.IsTrue(!OnServerMessageDelegates.Contains(onMessage));
|
||||
OnServerMessageDelegates.Add(onMessage);
|
||||
|
||||
if (onClientConnecting != null)
|
||||
{
|
||||
Assert.IsTrue(!OnServerConnectingDelegates.Contains(onClientConnecting));
|
||||
OnServerConnectingDelegates.Add(onClientConnecting);
|
||||
}
|
||||
if (onClientConnected != null)
|
||||
{
|
||||
Assert.IsTrue(!OnServerConnectedDelegates.Contains(onClientConnected));
|
||||
OnServerConnectedDelegates.Add(onClientConnected);
|
||||
}
|
||||
}
|
||||
public static void UnregisterServerMessageCallback(OnMessageDecl deleg)
|
||||
public static void UnregisterServerCallbacks(OnMessageDecl onMessage, OnClientConnectingDecl onClientConnecting, OnClientConnectedDecl onClientConnected)
|
||||
{
|
||||
Assert.IsTrue(OnServerMessageDelegates.Contains(deleg));
|
||||
OnServerMessageDelegates.Remove(deleg);
|
||||
Assert.IsTrue(OnServerMessageDelegates.Contains(onMessage));
|
||||
OnServerMessageDelegates.Remove(onMessage);
|
||||
|
||||
if (onClientConnecting != null)
|
||||
{
|
||||
Assert.IsTrue(OnServerConnectingDelegates.Contains(onClientConnecting));
|
||||
OnServerConnectingDelegates.Remove(onClientConnecting);
|
||||
}
|
||||
if (onClientConnected != null)
|
||||
{
|
||||
Assert.IsTrue(OnServerConnectedDelegates.Contains(onClientConnected));
|
||||
OnServerConnectedDelegates.Remove(onClientConnected);
|
||||
}
|
||||
}
|
||||
|
||||
public static string DebugLastHandledMessage = "";
|
||||
@@ -129,22 +179,14 @@ public static partial class NetworkManager
|
||||
client = null;
|
||||
}
|
||||
|
||||
LocalPlayerClientId = 0;
|
||||
//LocalPlayerClientId = 0;
|
||||
|
||||
#if FLAX_EDITOR
|
||||
Editor.Instance.PlayModeEnd -= Cleanup;
|
||||
//GameModeManager.Cleanup(); // FIXME
|
||||
#endif
|
||||
if (clientWorldStateManager != null)
|
||||
{
|
||||
clientWorldStateManager.Cleanup();
|
||||
clientWorldStateManager = null;
|
||||
}
|
||||
if (serverWorldStateManager != null)
|
||||
{
|
||||
serverWorldStateManager.Cleanup();
|
||||
serverWorldStateManager = null;
|
||||
}
|
||||
World.CleanupClient();
|
||||
World.CleanupServer();
|
||||
|
||||
StopRecording();
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ public static partial class NetworkManager
|
||||
|
||||
public static INetworkDriver ClientNetworkDriver { get; set; }
|
||||
|
||||
public static WorldStateManager clientWorldStateManager = null;
|
||||
//public static WorldStateManager clientWorldStateManager = null;
|
||||
|
||||
public static bool ConnectServer(string serverAddress = "localhost", bool listenServer = false)
|
||||
{
|
||||
@@ -50,7 +50,7 @@ public static partial class NetworkManager
|
||||
}
|
||||
Debug.Log("Connected...");
|
||||
|
||||
if (!listenServer)
|
||||
/*if (!listenServer)
|
||||
{
|
||||
//WorldStateManager.Init();
|
||||
clientWorldStateManager = new WorldStateManager(isClient: true);
|
||||
@@ -58,7 +58,8 @@ public static partial class NetworkManager
|
||||
else
|
||||
{
|
||||
clientWorldStateManager = new WorldStateManager(isLocalClient: true);
|
||||
}
|
||||
}*/
|
||||
World.InitClient();
|
||||
|
||||
Scripting.FixedUpdate += OnClientNetworkUpdate;
|
||||
if (!listenServer)
|
||||
@@ -106,20 +107,20 @@ public static partial class NetworkManager
|
||||
{
|
||||
case NetworkEventType.Connected:
|
||||
{
|
||||
LocalPlayerClientId = networkEvent.Sender.ConnectionId;
|
||||
Console.Print("Connected to server, ConnectionId: " + networkEvent.Sender.ConnectionId);
|
||||
foreach (var func in OnClientConnectedDelegates)
|
||||
func(networkEvent.Sender);
|
||||
break;
|
||||
}
|
||||
case NetworkEventType.Disconnected:
|
||||
{
|
||||
Console.Print("Disconnected from server, timeout.");
|
||||
LocalPlayerClientId = 0;
|
||||
//LocalPlayerClientId = 0;
|
||||
break;
|
||||
}
|
||||
case NetworkEventType.Timeout:
|
||||
{
|
||||
Console.Print("Disconnected from server, connection closed.");
|
||||
LocalPlayerClientId = 0;
|
||||
//LocalPlayerClientId = 0;
|
||||
break;
|
||||
}
|
||||
case NetworkEventType.Message:
|
||||
|
||||
@@ -38,7 +38,8 @@ public static unsafe partial class NetworkManager
|
||||
{
|
||||
{
|
||||
Cleanup();
|
||||
clientWorldStateManager = new WorldStateManager(isServer: true);
|
||||
//clientWorldStateManager = new WorldStateManager(isServer: true);
|
||||
World.InitServer();
|
||||
}
|
||||
|
||||
if (!ReadDemo(demoName))
|
||||
|
||||
@@ -18,7 +18,7 @@ public static partial class NetworkManager
|
||||
|
||||
public static INetworkDriver ServerNetworkDriver { get; set; }
|
||||
|
||||
public static WorldStateManager serverWorldStateManager = null;
|
||||
//public static WorldStateManager serverWorldStateManager = null;
|
||||
|
||||
public static bool StartServer(bool listenServer = true)
|
||||
{
|
||||
@@ -82,8 +82,9 @@ public static partial class NetworkManager
|
||||
foreach (Type type in NetworkedTypes)
|
||||
Console.Print("tracking networked type: " + type.Name);
|
||||
#endif
|
||||
serverWorldStateManager = new WorldStateManager(isServer: true);
|
||||
//serverWorldStateManager = new WorldStateManager(isServer: true);
|
||||
//WorldStateManager.Init();
|
||||
World.InitServer();
|
||||
|
||||
if (listenServer)
|
||||
return ConnectServer(listenServer: true);
|
||||
@@ -139,13 +140,21 @@ public static partial class NetworkManager
|
||||
try
|
||||
{
|
||||
//IsServer = true;
|
||||
if (serverWorldStateManager.OnClientConnecting(networkEvent.Sender))
|
||||
bool handled = false;
|
||||
foreach (var func in OnServerConnectingDelegates)
|
||||
{
|
||||
handled = func(networkEvent.Sender);
|
||||
if (handled)
|
||||
break;
|
||||
}
|
||||
if (handled)
|
||||
{
|
||||
ConnectedClients.Add(networkEvent.Sender);
|
||||
Console.Print(
|
||||
$"Client({networkEvent.Sender.ConnectionId}) connected. Total clients: {ConnectedClients.Count}");
|
||||
|
||||
serverWorldStateManager.OnClientConnected(networkEvent.Sender);
|
||||
foreach (var func in OnServerConnectedDelegates)
|
||||
func(networkEvent.Sender);
|
||||
}
|
||||
else
|
||||
Console.Print($"Client({networkEvent.Sender.ConnectionId}) connection refused");
|
||||
|
||||
549
Source/Game/GameMode/World.cs
Normal file
549
Source/Game/GameMode/World.cs
Normal file
@@ -0,0 +1,549 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Assertions;
|
||||
using FlaxEngine.Json;
|
||||
using FlaxEngine.Networking;
|
||||
|
||||
namespace Game;
|
||||
|
||||
public enum GameModeMessageType2 : byte
|
||||
{
|
||||
AcceptConnection, // AcceptConnectionMessage
|
||||
SpawnPlayer,
|
||||
PlayerInput,
|
||||
PlayerPosition, // world update
|
||||
PlayerSnapshot, // send world state delta to client since last client's acknowledged frame
|
||||
|
||||
LastMessageType = 128,
|
||||
}
|
||||
|
||||
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; }
|
||||
public ulong ServerFrame { get; protected set; } // Last received frame from server
|
||||
public float GameTime { get; protected set; } // The join time
|
||||
public float GetFrameTime(ulong frame) => GameTime + (frame * (1.0f / Time.PhysicsFPS));
|
||||
|
||||
protected Scene _scene;
|
||||
protected Actor _worldSpawn;
|
||||
protected Dictionary<uint, ClientInfo> _clients = new();
|
||||
|
||||
public static void InitClient()
|
||||
{
|
||||
WorldStore.ClientWorld = new ClientWorld();
|
||||
WorldStore.ClientWorld.Init();
|
||||
}
|
||||
public static void InitServer()
|
||||
{
|
||||
WorldStore.ServerWorld = new ServerWorld();
|
||||
WorldStore.ServerWorld.Init();
|
||||
}
|
||||
public static void CleanupClient()
|
||||
{
|
||||
WorldStore.ClientWorld?.Cleanup();
|
||||
WorldStore.ClientWorld = null;
|
||||
}
|
||||
public static void CleanupServer()
|
||||
{
|
||||
WorldStore.ServerWorld?.Cleanup();
|
||||
WorldStore.ServerWorld = null;
|
||||
}
|
||||
|
||||
virtual protected void Init()
|
||||
{
|
||||
}
|
||||
|
||||
virtual protected void Cleanup()
|
||||
{
|
||||
//Level.SceneLoaded -= OnLevelLoaded;
|
||||
//Scripting.LateUpdate -= OnLateUpdatePre;
|
||||
Scripting.LateFixedUpdate -= OnLateUpdate;
|
||||
|
||||
if (_scene)
|
||||
{
|
||||
foreach (var player in _scene.GetChildren<PlayerActor>())
|
||||
{
|
||||
FlaxEngine.Object.Destroy(player);
|
||||
}
|
||||
if (Level.UnloadScene(_scene))
|
||||
throw new Exception("Failed to unload scene");
|
||||
_scene = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void CreateScene(string sceneNamePrefix, string sceneGuid)
|
||||
{
|
||||
string physicsSceneName = $"{sceneNamePrefix}PhysicsScene";
|
||||
PhysicsScene localPhysicsScene = Physics.FindOrCreateScene(physicsSceneName);
|
||||
|
||||
Guid guid = JsonSerializer.ParseID(sceneGuid);
|
||||
string guidStr = JsonSerializer.GetStringID(guid);
|
||||
string sceneData = $@"
|
||||
{{
|
||||
""ID"": ""{guidStr}"",
|
||||
""TypeName"": ""FlaxEngine.SceneAsset"",
|
||||
""EngineBuild"": 65046,
|
||||
""Data"": [
|
||||
{{
|
||||
""ID"": ""{guidStr}"",
|
||||
""TypeName"": ""FlaxEngine.Scene"",
|
||||
""LightmapSettings"": {{
|
||||
""IndirectLightingIntensity"": 1.0,
|
||||
""GlobalObjectsScale"": 1.0,
|
||||
""ChartsPadding"": 3,
|
||||
""AtlasSize"": 1024,
|
||||
""BounceCount"": 1,
|
||||
""CompressLightmaps"": true,
|
||||
""UseGeometryWithNoMaterials"": true,
|
||||
""Quality"": 10
|
||||
}}
|
||||
}}
|
||||
]
|
||||
}}";
|
||||
|
||||
{
|
||||
var onSceneLoaded = (Scene loadedScene, Guid id) =>
|
||||
{
|
||||
if (guid == id)
|
||||
{
|
||||
loadedScene.PhysicsScene = localPhysicsScene;
|
||||
//scene = loadedScene;
|
||||
}
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
Level.SceneLoaded += onSceneLoaded;
|
||||
//Level.LoadScene(new SceneReference(guid));
|
||||
_scene = Level.LoadSceneFromBytes(Encoding.ASCII.GetBytes(sceneData));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Level.SceneLoaded -= onSceneLoaded;
|
||||
}
|
||||
}
|
||||
Assert.IsTrue(_scene);
|
||||
|
||||
_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";
|
||||
importer.LoadCollidersOnly = sceneNamePrefix != "Client"; // FIXME
|
||||
importer.Parent = _scene;
|
||||
|
||||
//importer.Enabled = true;
|
||||
_worldSpawn = _scene.FindActor("WorldSpawn");// ?? Level.FindActor("WorldSpawn");
|
||||
Assert.IsTrue(_worldSpawn);
|
||||
}
|
||||
|
||||
public void OnLateUpdate()
|
||||
{
|
||||
Frame++;
|
||||
}
|
||||
|
||||
protected void OnClientConnected(NetworkConnection connection)
|
||||
{
|
||||
uint playerId = connection.ConnectionId;
|
||||
_clients.Add(playerId, new ClientInfo() { Connection = connection });
|
||||
}
|
||||
|
||||
virtual protected PlayerActor SpawnPlayer(uint playerId, Float3 position, Vector3 eulerAngles)
|
||||
{
|
||||
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);
|
||||
|
||||
_clients[playerId].PlayerActor = playerActor;
|
||||
IPlayerInput playerInput = playerActor.GetScript<PlayerMovement>().Input;
|
||||
playerInput.SetFrame(Frame);
|
||||
/*if (IsServer)
|
||||
{
|
||||
serverWorldState.actors.Add(playerActor);
|
||||
if (!playerLastReceivedFrames.ContainsKey(playerId))
|
||||
playerLastReceivedFrames.Add(playerId, 0);
|
||||
}*/
|
||||
|
||||
return playerActor;
|
||||
}
|
||||
|
||||
protected T SpawnActor<T>(Prefab prefab) where T : Actor
|
||||
{
|
||||
T actor = PrefabManager.SpawnPrefab(prefab, _scene).As<T>();
|
||||
actor.PhysicsScene = _scene.PhysicsScene;
|
||||
return actor;
|
||||
}
|
||||
|
||||
virtual public bool IsLocalPlayer(uint playerId) => false;
|
||||
|
||||
public PlayerFrame GetPlayerFrame(uint playerId, ulong frame)
|
||||
{
|
||||
ClientInfo player = _clients[playerId];
|
||||
PlayerFrame playerFrame = player.FrameHistory[frame % 120];
|
||||
if (playerFrame.frame != frame)
|
||||
return null;
|
||||
|
||||
return playerFrame;
|
||||
}
|
||||
|
||||
public bool HasPlayerFrame(uint playerId, ulong frame) => GetPlayerFrame(playerId, frame) != null;
|
||||
|
||||
public bool GetPlayerInputState(uint playerId, ulong frame, out PlayerInputState2 inputState)
|
||||
{
|
||||
PlayerFrame playerFrame = GetPlayerFrame(playerId, frame);
|
||||
inputState = playerFrame?.inputState ?? default;
|
||||
return playerFrame != null;
|
||||
}
|
||||
}
|
||||
|
||||
file class ServerWorld : World
|
||||
{
|
||||
protected override void Init()
|
||||
{
|
||||
NetworkManager.RegisterServerCallbacks(OnMessage, OnClientConnecting, OnClientConnected);
|
||||
GameTime = Time.GameTime;
|
||||
|
||||
CreateScene("Server", "59dd37cc444d5d7015759389c6153c4c");
|
||||
|
||||
base.Init();
|
||||
}
|
||||
|
||||
protected override void Cleanup()
|
||||
{
|
||||
NetworkManager.UnregisterServerCallbacks(OnMessage, OnClientConnecting, OnClientConnected);
|
||||
base.Cleanup();
|
||||
}
|
||||
|
||||
public bool OnMessage(ref NetworkEvent networkEvent)
|
||||
{
|
||||
byte messageTypeByte = networkEvent.Message.ReadByte();
|
||||
if (!Enum.IsDefined(typeof(GameModeMessageType2), messageTypeByte))
|
||||
{
|
||||
//Console.PrintError($"GameModeManager: Unsupported message type received from client: {messageTypeByte}");
|
||||
return false;
|
||||
}
|
||||
|
||||
GameModeMessageType2 messageType = (GameModeMessageType2)messageTypeByte;
|
||||
NetworkManager.DebugLastHandledMessage = messageType.ToString();
|
||||
|
||||
//Console.Print($"GameModeManager: {messageType}");
|
||||
switch (messageType)
|
||||
{
|
||||
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;
|
||||
case GameModeMessageType2.PlayerPosition:
|
||||
{
|
||||
//uint playerId = networkEvent.Sender.ConnectionId;
|
||||
PlayerInputState2 inputState; //?
|
||||
PlayerActorState actorState;
|
||||
|
||||
ulong receivedFrame = 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 = 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();
|
||||
|
||||
ServerFrame = receivedFrame;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool OnClientConnecting(NetworkConnection connection)
|
||||
{
|
||||
AcceptConnectionMessage message = new AcceptConnectionMessage();
|
||||
message.Frame = Frame;
|
||||
message.GameTime = GameTime;
|
||||
message.Players = new AcceptConnectionMessage.PlayerInfo[_clients.Count];
|
||||
|
||||
int playerIndex = 0;
|
||||
foreach (var player in _clients.Values)
|
||||
{
|
||||
ref AcceptConnectionMessage.PlayerInfo playerInfo = ref message.Players[playerIndex];
|
||||
playerInfo.PlayerId = player.PlayerActor.GetScript<PlayerMovement>().PlayerId;
|
||||
playerInfo.PlayerPosition = player.PlayerActor.Position;
|
||||
playerIndex++;
|
||||
}
|
||||
NetworkMessage networkMessage = NetworkManager.ServerBeginSendMessage();
|
||||
message.Write(ref networkMessage);
|
||||
NetworkManager.ServerEndSendMessage(ref networkMessage, connection);
|
||||
return true;
|
||||
}
|
||||
|
||||
public new void OnClientConnected(NetworkConnection connection)
|
||||
{
|
||||
base.OnClientConnected(connection);
|
||||
uint playerId = connection.ConnectionId;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
SpawnPlayer(playerId, position, eulerAngles);
|
||||
{
|
||||
NetworkMessage message = NetworkManager.ServerBeginSendMessage();
|
||||
message.WriteByte((byte)GameModeMessageType.SpawnPlayer);
|
||||
message.WriteUInt32(playerId);
|
||||
message.WriteUInt64(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file class ClientWorld : World
|
||||
{
|
||||
private uint _localPlayerId;
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
NetworkManager.RegisterClientCallbacks(OnMessage, null, OnClientConnected);
|
||||
|
||||
CreateScene("Client", "c095f9ac4989a46afd7fe3821f086e2e");
|
||||
|
||||
base.Init();
|
||||
}
|
||||
|
||||
protected override void Cleanup()
|
||||
{
|
||||
NetworkManager.UnregisterClientCallbacks(OnMessage, null, OnClientConnected);
|
||||
base.Cleanup();
|
||||
}
|
||||
|
||||
public bool OnMessage(ref NetworkEvent networkEvent)
|
||||
{
|
||||
byte messageTypeByte = networkEvent.Message.ReadByte();
|
||||
if (!Enum.IsDefined(typeof(GameModeMessageType2), messageTypeByte))
|
||||
{
|
||||
//Console.PrintError($"GameModeManager: Unsupported message type received from client: {messageTypeByte}");
|
||||
return false;
|
||||
}
|
||||
|
||||
GameModeMessageType2 messageType = (GameModeMessageType2)messageTypeByte;
|
||||
NetworkManager.DebugLastHandledMessage = messageType.ToString();
|
||||
|
||||
//Console.Print($"GameModeManager: {messageType}");
|
||||
switch (messageType)
|
||||
{
|
||||
case GameModeMessageType2.AcceptConnection:
|
||||
{
|
||||
// Setup some initial state for newly connected client
|
||||
AcceptConnectionMessage welcomePlayer = AcceptConnectionMessage.Read(ref networkEvent.Message);
|
||||
ServerFrame = welcomePlayer.Frame;
|
||||
Frame += welcomePlayer.Frame;
|
||||
|
||||
GameTime = welcomePlayer.GameTime;
|
||||
foreach (var playerInfo in welcomePlayer.Players)
|
||||
{
|
||||
_clients.Add(playerInfo.PlayerId, new ClientInfo());
|
||||
SpawnPlayer(playerInfo.PlayerId, playerInfo.PlayerPosition, new Float3(0));
|
||||
}
|
||||
|
||||
Console.Print("received welcome: frame " + ServerFrame);
|
||||
}
|
||||
break;
|
||||
case GameModeMessageType2.SpawnPlayer:
|
||||
{
|
||||
uint playerId = networkEvent.Message.ReadUInt32();
|
||||
ulong playerFrameIndex = networkEvent.Message.ReadUInt64();
|
||||
Float3 position = new Float3(networkEvent.Message.ReadSingle(), networkEvent.Message.ReadSingle(), networkEvent.Message.ReadSingle());
|
||||
Vector3 eulerAngles = new Float3(networkEvent.Message.ReadSingle(), networkEvent.Message.ReadSingle(), networkEvent.Message.ReadSingle());
|
||||
|
||||
/*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, position, eulerAngles);
|
||||
|
||||
//if (NetworkManager.IsClient)
|
||||
//players[playerId].GetScript<PlayerMovement>().Input.SetFrame(ClientFrame);
|
||||
}
|
||||
break;
|
||||
#if false
|
||||
case GameModeMessageType2.PlayerPosition:
|
||||
{
|
||||
//uint playerId = networkEvent.Sender.ConnectionId;
|
||||
PlayerInputState2 inputState; //?
|
||||
PlayerActorState actorState;
|
||||
|
||||
ulong receivedFrame = 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 = 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();
|
||||
|
||||
ServerFrame = receivedFrame;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool IsLocalPlayer(uint playerId) => playerId == _localPlayerId;
|
||||
|
||||
public new void OnClientConnected(NetworkConnection connection)
|
||||
{
|
||||
base.OnClientConnected(connection);
|
||||
_localPlayerId = connection.ConnectionId;
|
||||
Console.Print($"ClientWorld: Connected, playerId: {_localPlayerId}");
|
||||
}
|
||||
|
||||
protected override PlayerActor SpawnPlayer(uint playerId, Float3 position, Vector3 eulerAngles)
|
||||
{
|
||||
var playerActor = base.SpawnPlayer(playerId, position, eulerAngles);
|
||||
if (playerId == _localPlayerId)
|
||||
playerActor.Input = new PlayerInput2();
|
||||
else
|
||||
playerActor.Input = new PlayerInputNetwork2(playerId, this);
|
||||
return playerActor;
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorldExtensions
|
||||
{
|
||||
public static World GetWorld(this Script script) => IsServerScene(script.Scene) ? WorldStore.ServerWorld : WorldStore.ClientWorld;
|
||||
|
||||
public static World GetWorld(this Actor actor) => IsServerScene(actor.Scene) ? WorldStore.ServerWorld : WorldStore.ClientWorld;
|
||||
|
||||
private static bool IsServerScene(Scene scene) => scene.Name == "ServerScene";
|
||||
}
|
||||
|
||||
file static class WorldStore
|
||||
{
|
||||
public static ServerWorld ServerWorld;
|
||||
public static ClientWorld ClientWorld;
|
||||
}
|
||||
|
||||
/*file class WorldPlugin : GamePlugin
|
||||
{
|
||||
public WorldPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
|
||||
WorldStore.ClientWorld = new World(isServer: false);
|
||||
}
|
||||
|
||||
public override void Deinitialize()
|
||||
{
|
||||
WorldStore.ServerWorld = null;
|
||||
WorldStore.ClientWorld = null;
|
||||
}
|
||||
}*/
|
||||
@@ -14,7 +14,7 @@ namespace Game;
|
||||
|
||||
public enum GameModeMessageType : byte
|
||||
{
|
||||
WelcomePlayer, // WelcomePlayerMessage
|
||||
AcceptConnection, // WelcomePlayerMessage
|
||||
SpawnPlayer,
|
||||
PlayerInput,
|
||||
PlayerPosition, // world update
|
||||
@@ -97,10 +97,10 @@ public class WorldStateManager
|
||||
clientWorldState = new WorldState();
|
||||
gameMode = new GameMode();
|
||||
|
||||
if (IsServer)
|
||||
NetworkManager.RegisterServerMessageCallback(OnMessage);
|
||||
/*if (IsServer)
|
||||
NetworkManager.RegisterServerCallbacks(OnMessage);
|
||||
else
|
||||
NetworkManager.RegisterClientMessageCallback(OnMessage);
|
||||
NetworkManager.RegisterClientCallbacks(OnMessage);*/
|
||||
|
||||
Debug.Log($"WorldStateManager Init is server: {IsServer}");
|
||||
Debug.Log($"WorldStateManager Init is local client: {IsLocalClient}");
|
||||
@@ -173,10 +173,10 @@ public class WorldStateManager
|
||||
|
||||
public void Cleanup()
|
||||
{
|
||||
if (IsServer)
|
||||
NetworkManager.UnregisterServerMessageCallback(OnMessage);
|
||||
/*if (IsServer)
|
||||
NetworkManager.UnregisterServerCallbacks(OnMessage);
|
||||
else
|
||||
NetworkManager.UnregisterClientMessageCallback(OnMessage);
|
||||
NetworkManager.UnregisterClientCallbacks(OnMessage);*/
|
||||
|
||||
Level.SceneLoaded -= OnLevelLoaded;
|
||||
//Scripting.LateUpdate -= OnLateUpdatePre;
|
||||
@@ -454,26 +454,26 @@ public class WorldStateManager
|
||||
//Console.Print($"GameModeManager: {messageType}");
|
||||
switch (messageType)
|
||||
{
|
||||
case GameModeMessageType.WelcomePlayer:
|
||||
case GameModeMessageType.AcceptConnection:
|
||||
{
|
||||
welcomed = true;
|
||||
if (IsClient || IsLocalClient)
|
||||
{
|
||||
WelcomePlayerMessage welcomePlayer = WelcomePlayerMessage.Read(ref networkEvent.Message);
|
||||
AcceptConnectionMessage welcomePlayer = AcceptConnectionMessage.Read(ref networkEvent.Message);
|
||||
if (!IsLocalClient)
|
||||
serverWorldState.frame = welcomePlayer.frame;
|
||||
serverWorldState.frame = welcomePlayer.Frame;
|
||||
//lastReceivedServerFrame = welcomePlayer.frame;
|
||||
clientWorldState.frame += welcomePlayer.frame;
|
||||
clientWorldState.frame += welcomePlayer.Frame;
|
||||
|
||||
ClientTime = welcomePlayer.time;
|
||||
foreach (var playerInfo in welcomePlayer.players)
|
||||
ClientTime = welcomePlayer.GameTime;
|
||||
foreach (var playerInfo in welcomePlayer.Players)
|
||||
{
|
||||
SpawnPlayer(playerInfo.playerId, playerInfo.playerPosition, new Float3(0));
|
||||
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);
|
||||
clientWorldState.playerFrameHistory.Add(playerInfo.PlayerId, playerFrames);
|
||||
}
|
||||
|
||||
Console.Print("received welcome: frame " + serverWorldState.frame);
|
||||
@@ -614,17 +614,17 @@ public class WorldStateManager
|
||||
//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];
|
||||
AcceptConnectionMessage welcomeMessage = new AcceptConnectionMessage();
|
||||
welcomeMessage.Frame = serverWorldState.frame;
|
||||
welcomeMessage.GameTime = ServerTime;
|
||||
welcomeMessage.Players = new AcceptConnectionMessage.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;
|
||||
ref AcceptConnectionMessage.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()
|
||||
{
|
||||
|
||||
@@ -43,7 +43,12 @@ public class PlayerActor : RigidBody//, INetworkSerializable
|
||||
public MeshCollider meshCollider;
|
||||
|
||||
//[NetworkReplicated]
|
||||
public uint PlayerId = uint.MaxValue;
|
||||
public uint PlayerId { get; private set; } = uint.MaxValue;
|
||||
|
||||
public IPlayerInput Input { get; set; } = PlayerInputNone.Instance;
|
||||
|
||||
private World _world;
|
||||
private World World => _world ??= this.GetWorld();
|
||||
|
||||
/*public PlayerActor()
|
||||
{
|
||||
@@ -103,9 +108,9 @@ public class PlayerActor : RigidBody//, INetworkSerializable
|
||||
IsActive = true;
|
||||
|
||||
PlayerId = playerId;
|
||||
playerMovement.SetInput(playerId);
|
||||
//playerMovement.SetInput(playerId);
|
||||
bool isServerScene = Scene.Name == "ServerScene";
|
||||
if (playerId == NetworkManager.LocalPlayerClientId && !isServerScene)
|
||||
if (World.IsLocalPlayer(PlayerId))
|
||||
{
|
||||
FindActor("CameraHolder").IsActive = true;
|
||||
//FindActor("ViewModelHolder").IsActive = true;
|
||||
|
||||
@@ -84,21 +84,21 @@ public class PlayerInput2 : IPlayerInput
|
||||
public class PlayerInputNetwork2 : IPlayerInput
|
||||
{
|
||||
private uint _playerId;
|
||||
private WorldStateManager _worldStateManager;
|
||||
private World _world;
|
||||
private ulong _frame;
|
||||
private PlayerInputState2 _state;
|
||||
|
||||
public PlayerInputNetwork2(uint playerId, WorldStateManager worldStateManager)
|
||||
public PlayerInputNetwork2(uint playerId, World world)
|
||||
{
|
||||
_playerId = playerId;
|
||||
_worldStateManager = worldStateManager;
|
||||
_world = world;
|
||||
}
|
||||
|
||||
public void SetFrame(ulong frame) => _frame = frame;
|
||||
|
||||
public void UpdateState()
|
||||
{
|
||||
_worldStateManager.GetPlayerInputState(_playerId, _frame, out _state);
|
||||
_world.GetPlayerInputState(_playerId, _frame, out _state);
|
||||
}
|
||||
|
||||
public PlayerInputState2 GetState() => _state;
|
||||
@@ -107,4 +107,15 @@ public class PlayerInputNetwork2 : IPlayerInput
|
||||
{
|
||||
_state = new PlayerInputState2();
|
||||
}
|
||||
}
|
||||
|
||||
public class PlayerInputNone : IPlayerInput
|
||||
{
|
||||
public static PlayerInputNone Instance { get; } = new PlayerInputNone();
|
||||
private PlayerInputNone() { }
|
||||
|
||||
public PlayerInputState2 GetState() => default;
|
||||
public void ResetState() { }
|
||||
public void SetFrame(ulong frame) { }
|
||||
public void UpdateState() { }
|
||||
}
|
||||
@@ -107,7 +107,10 @@ public class PlayerMovement : Script
|
||||
private readonly bool demoDeltasVerify = true;
|
||||
|
||||
|
||||
private WorldStateManager worldStateManager;
|
||||
//private WorldStateManager worldStateManager;
|
||||
|
||||
private World _world;
|
||||
private World World => _world ??= this.GetWorld();
|
||||
|
||||
private bool predicting = false;
|
||||
|
||||
@@ -115,8 +118,8 @@ public class PlayerMovement : Script
|
||||
//public int currentInputFrame;
|
||||
//private int currentInputFrame2;
|
||||
|
||||
|
||||
public IPlayerInput Input;
|
||||
[NoSerialize, HideInEditor]
|
||||
public IPlayerInput Input => playerActor?.Input ?? PlayerInputNone.Instance;
|
||||
|
||||
//private bool physicsInteractions = false;
|
||||
|
||||
@@ -136,7 +139,7 @@ public class PlayerMovement : Script
|
||||
public Float3 viewAngles;
|
||||
private Float3 viewAnglesLastFrame;
|
||||
|
||||
public uint PlayerId = 0;
|
||||
public uint PlayerId => playerActor ? playerActor.PlayerId : 0;
|
||||
|
||||
[ReadOnly]
|
||||
public float CurrentVelocity
|
||||
@@ -161,7 +164,6 @@ public class PlayerMovement : Script
|
||||
{
|
||||
base.OnAwake();
|
||||
|
||||
Console.Print("player awake, playerid: " + PlayerId);
|
||||
rootActor = Actor.GetChild("RootActor");
|
||||
rigidBody = Actor.As<RigidBody>();
|
||||
playerActor = Actor.As<PlayerActor>();
|
||||
@@ -176,36 +178,6 @@ public class PlayerMovement : Script
|
||||
//rigidBody.TriggerExit += OnTriggerExit;
|
||||
}
|
||||
|
||||
public void SetInput(uint playerId)
|
||||
{
|
||||
//if (playerId == 0)
|
||||
// input = new PlayerInput();
|
||||
Assert.IsTrue(playerId != uint.MaxValue);
|
||||
|
||||
PlayerId = playerId;
|
||||
bool isServerScene = Scene.Name == "ServerScene";
|
||||
if (isServerScene)
|
||||
worldStateManager = NetworkManager.serverWorldStateManager;
|
||||
else
|
||||
worldStateManager = NetworkManager.clientWorldStateManager;
|
||||
|
||||
if (PlayerId == NetworkManager.LocalPlayerClientId && !isServerScene)//if (NetworkReplicator.GetObjectRole(this.Parent) == NetworkObjectRole.OwnedAuthoritative)// if (playerId == NetworkManager.LocalPlayerClientId)
|
||||
{
|
||||
Console.Print("local player?: " + playerId.ToString());
|
||||
//string demoPath = System.IO.Path.Combine(AssetManager.DemoPath, $"{DateTimeOffset.Now.UtcTicks}.gdem");
|
||||
//input = new PlayerInputLocal(playerActor, demoPath); // TODO: support recording
|
||||
Input = new PlayerInput2();//new PlayerInputLocal(playerActor);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Print("network player: " + playerId.ToString());
|
||||
Input = new PlayerInputNetwork2(playerId, worldStateManager);
|
||||
|
||||
}
|
||||
Assert.IsTrue(worldStateManager != null);
|
||||
}
|
||||
|
||||
#if false
|
||||
public void SetInput(string demoFile)
|
||||
{
|
||||
@@ -286,7 +258,7 @@ public class PlayerMovement : Script
|
||||
//if (Input is PlayerInputDemo /*&& currentInputFrame2 >= currentInputFrame*/)
|
||||
// return;
|
||||
|
||||
Input.SetFrame(worldStateManager.Frame);
|
||||
Input.SetFrame(World.Frame);
|
||||
Input.UpdateState();
|
||||
|
||||
/*if (input.frame > 0)
|
||||
@@ -345,7 +317,107 @@ public class PlayerMovement : Script
|
||||
|
||||
//Input.OnFixedUpdate();
|
||||
PlayerInputState2 inputState = Input.GetState();
|
||||
bool predict = World.IsClient;
|
||||
if (predict)
|
||||
{
|
||||
// Get the latest frame we have predicted
|
||||
ulong lastFrame = World.ServerFrame;
|
||||
for (; lastFrame < World.Frame; lastFrame++)
|
||||
{
|
||||
if (!World.HasPlayerFrame(PlayerId, lastFrame))
|
||||
//if (!Input.GetState(currentFrame, out var pastInputState, out var pastActorState))
|
||||
{
|
||||
//Console.Print($"not predicting");
|
||||
predict = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (predict)
|
||||
{
|
||||
var oldAngles = viewAngles;
|
||||
var oldPos = movementState.position;
|
||||
var oldVel = movementState.currentVelocity;
|
||||
|
||||
ulong currentFrame = World.ServerFrame;
|
||||
if (currentFrame == World.ServerFrame)
|
||||
{
|
||||
// Reset all state to latest confirmed state from server
|
||||
var frameInfo = World.GetPlayerFrame(PlayerId, currentFrame);
|
||||
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);
|
||||
//cameraHolder.Orientation = Quaternion.Euler(pastActorState.viewAngles.Y, pastActorState.viewAngles.X, pastActorState.viewAngles.Z);
|
||||
//ApplyInputToCamera(pastInputState, true);
|
||||
|
||||
//if (pastActorState.viewAngles != new Float3(90f, 0f, 0f))
|
||||
// Console.Print($"moved server frame: {currentFrame}, {pastActorState.viewAngles}");
|
||||
|
||||
currentFrame++;
|
||||
//rootActor.Orientation = pastActorState.orientation;
|
||||
//viewAngles = pastActorState.viewAngles;
|
||||
//viewAngles = new Float3(pastActorState.viewAngles.Y, pastActorState.viewAngles.X, pastActorState.viewAngles.Z);
|
||||
}
|
||||
|
||||
// Predict the frames since last received frame from server up to latest client frame
|
||||
predicting = true;
|
||||
for (; currentFrame < lastFrame; currentFrame++)
|
||||
{
|
||||
var frameInfo = World.GetPlayerFrame(PlayerId, currentFrame);
|
||||
if (frameInfo == null)
|
||||
{
|
||||
Console.Print($"unexpected predict failure: {currentFrame}");
|
||||
break;
|
||||
}
|
||||
|
||||
ApplyInputToCamera(frameInfo.inputState, true);
|
||||
SimulatePlayerMovement(frameInfo.inputState, frameInfo.frame);
|
||||
}
|
||||
predicting = false;
|
||||
|
||||
var posDelta = (movementState.position - oldPos);
|
||||
var velDelta = (movementState.currentVelocity - oldVel);
|
||||
if (posDelta.Length > 0.001)
|
||||
Console.Print($"mispredicted final position");
|
||||
if (velDelta.Length > 0.001)
|
||||
Console.Print($"mispredicted final velocity");
|
||||
|
||||
// Run simulation for the upcoming frame
|
||||
//if (input is not PlayerInputNetwork)
|
||||
{
|
||||
/*if ((movementState.position - oldPos).Length > 0.001)
|
||||
Console.Print($"mispredicted final position");
|
||||
if ((currentVelocity - oldVel).Length > 0.001)
|
||||
Console.Print($"mispredicted final velocity");*/
|
||||
|
||||
ApplyInputToCamera(inputState, true);
|
||||
|
||||
// Ensure orientation is always up-to-date after predicting
|
||||
//rootActor.Orientation = Quaternion.Euler(0, viewAngles.X, 0);
|
||||
cameraHolder.Orientation = Quaternion.Euler(viewAngles.Y, viewAngles.X, viewAngles.Z);
|
||||
|
||||
SimulatePlayerMovement(inputState, World.Frame); // MAYBE?
|
||||
}
|
||||
|
||||
var viewDelta = (viewAngles - oldAngles);
|
||||
if (viewDelta.Length > 0.001)
|
||||
Console.Print($"mispredicted final viewangles: {viewAngles} <- {oldAngles}");
|
||||
}
|
||||
}
|
||||
|
||||
if (!predict)
|
||||
{
|
||||
SetCameraEulerAngles(viewAnglesLastFrame, true);
|
||||
ApplyInputToCamera(inputState, true);
|
||||
SimulatePlayerMovement(inputState, World.Frame); // MAYBE?
|
||||
}
|
||||
|
||||
viewAnglesLastFrame = viewAngles;
|
||||
|
||||
#if false
|
||||
if (false && Input is PlayerInputNetwork2)
|
||||
{
|
||||
#if false
|
||||
@@ -456,12 +528,13 @@ public class PlayerMovement : Script
|
||||
|
||||
//viewAngles = viewAnglesLastFrame;
|
||||
bool canpredict = true;
|
||||
if (true /*&& Input.Predict*/ /*&& !NetworkManager.IsDemoPlaying*/ && worldStateManager.ClientFrame > 0 && worldStateManager.ServerFrame > 0)
|
||||
if (true /*&& Input.Predict*/ /*&& !NetworkManager.IsDemoPlaying*/ && World.Frame > 0 && World.ServerFrame > 0)
|
||||
{
|
||||
ulong currentFrame = worldStateManager.ServerFrame;
|
||||
for (; currentFrame < worldStateManager.ClientFrame; currentFrame++)
|
||||
// Get the latest frame we have predicted
|
||||
ulong currentFrame = World.ServerFrame;
|
||||
for (; currentFrame < World.Frame; currentFrame++)
|
||||
{
|
||||
if (!worldStateManager.HasPlayerFrame(PlayerId, currentFrame))
|
||||
if (!World.HasPlayerFrame(PlayerId, currentFrame))
|
||||
//if (!Input.GetState(currentFrame, out var pastInputState, out var pastActorState))
|
||||
{
|
||||
//Console.Print($"not predicting");
|
||||
@@ -471,22 +544,19 @@ public class PlayerMovement : Script
|
||||
}
|
||||
|
||||
ulong lastFrame = currentFrame;
|
||||
|
||||
|
||||
if (canpredict)
|
||||
{
|
||||
var oldAngles = viewAngles;
|
||||
var oldPos = movementState.position;
|
||||
var oldVel = movementState.currentVelocity;
|
||||
|
||||
|
||||
|
||||
// Predict the frames since last received frame from server up to latest client frame
|
||||
predicting = true;
|
||||
currentFrame = worldStateManager.ServerFrame;
|
||||
currentFrame = World.ServerFrame;
|
||||
for (; currentFrame < lastFrame; currentFrame++)
|
||||
{
|
||||
//if (!Input.GetState(currentFrame, out var pastInputState, out var pastActorState))
|
||||
var frameInfo = worldStateManager.GetPlayerFrame(PlayerId, currentFrame);
|
||||
var frameInfo = World.GetPlayerFrame(PlayerId, currentFrame);
|
||||
if (frameInfo == null)
|
||||
{
|
||||
Console.Print($"unexpected predict failure: {currentFrame}");
|
||||
@@ -496,7 +566,7 @@ public class PlayerMovement : Script
|
||||
//if (currentFrame == inputState.frame)
|
||||
// movementState.jumped = movementState.jumped;
|
||||
|
||||
if (currentFrame == worldStateManager.ServerFrame)
|
||||
if (currentFrame == World.ServerFrame)
|
||||
{
|
||||
movementState.position = frameInfo.movementState.position;
|
||||
movementState.currentVelocity = frameInfo.movementState.currentVelocity;
|
||||
@@ -563,7 +633,7 @@ public class PlayerMovement : Script
|
||||
//rootActor.Orientation = Quaternion.Euler(0, viewAngles.X, 0);
|
||||
cameraHolder.Orientation = Quaternion.Euler(viewAngles.Y, viewAngles.X, viewAngles.Z);
|
||||
|
||||
SimulatePlayerMovement(inputState, worldStateManager.Frame); // MAYBE?
|
||||
SimulatePlayerMovement(inputState, World.Frame); // MAYBE?
|
||||
}
|
||||
|
||||
var viewDelta = (viewAngles - oldAngles);
|
||||
@@ -585,7 +655,7 @@ public class PlayerMovement : Script
|
||||
{
|
||||
SetCameraEulerAngles(viewAnglesLastFrame, true);
|
||||
ApplyInputToCamera(inputState, true);
|
||||
SimulatePlayerMovement(inputState, worldStateManager.Frame); // MAYBE?
|
||||
SimulatePlayerMovement(inputState, World.Frame); // MAYBE?
|
||||
}
|
||||
|
||||
if (movementState.position.Length < 0.1)
|
||||
@@ -625,7 +695,7 @@ public class PlayerMovement : Script
|
||||
});*/
|
||||
|
||||
//Console.Print($"recording frame {input.frame}, client: {GameModeManager.ClientFrame}, server: {GameModeManager.ServerFrame}");
|
||||
worldStateManager.RecordPlayerInput(PlayerId, worldStateManager.Frame, inputState, movementState); // MAYBE?
|
||||
World.RecordPlayerInput(PlayerId, World.Frame, inputState, movementState); // MAYBE?
|
||||
Input.ResetState();
|
||||
}
|
||||
|
||||
@@ -649,6 +719,7 @@ public class PlayerMovement : Script
|
||||
currentVelocity = pastActorState2.velocity;
|
||||
SetCameraEulerAngles(pastActorState2.viewAngles, true);
|
||||
}*/
|
||||
#endif
|
||||
}
|
||||
|
||||
public void ApplyInputToCamera(PlayerInputState2 inputState, bool wrapAround = true)
|
||||
@@ -925,10 +996,10 @@ public class PlayerMovement : Script
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (worldStateManager.IsClient)
|
||||
else if (World.IsClient)
|
||||
{
|
||||
var serverBbox = boxCollider.OrientedBox.GetBoundingBox();
|
||||
var frameInfo = worldStateManager.GetPlayerFrame(PlayerId, worldStateManager.ServerFrame);
|
||||
var frameInfo = World.GetPlayerFrame(PlayerId, World.ServerFrame);
|
||||
if (frameInfo != null)
|
||||
serverBbox.Center = frameInfo.movementState.position;
|
||||
|
||||
@@ -1178,7 +1249,7 @@ public class PlayerMovement : Script
|
||||
|
||||
public void SimulatePlayerMovement(PlayerInputState2 inputState, ulong frame)
|
||||
{
|
||||
simulationTime = worldStateManager.ClientTime + (frame * (1.0f / Time.PhysicsFPS));
|
||||
simulationTime = World.GetFrameTime(frame);
|
||||
|
||||
Vector3 inputDirection =
|
||||
new Float3(inputState.MoveRight, 0.0f, inputState.MoveForward);
|
||||
|
||||
Reference in New Issue
Block a user