record demos as packets

This commit is contained in:
2023-05-21 00:48:03 +03:00
parent 3a59bad850
commit 280be62caa
10 changed files with 579 additions and 255 deletions

View File

@@ -550,19 +550,25 @@ namespace Game
[ConsoleCommand("playdemo")]
public static void PlayDemoCommand(string[] text)
{
string demoName;
if (text.Length < 1)
return;
string demoName = text[0];
demoName = "638201307621505588_v2";//return;
else
demoName = text[0];
if (!demoName.EndsWith(".gdem"))
demoName += ".gdem";
string demoPath = Path.Combine(AssetManager.DemoPath, demoName);
NetworkManager.PlayDemo(demoPath);
#if false
PlayerActor playerActor = Level.GetActors<PlayerActor>().First(/*x =>
x.GetScript<PlayerMovement>().PlayerId == NetworkManager.LocalPlayerClientId*/);
string demoPath = Path.Combine(AssetManager.DemoPath, demoName);
if (File.Exists(demoPath))
playerActor.GetScript<PlayerMovement>().SetInput(demoPath);
#endif
}
private static Action timeDemoUpdate = null;
@@ -575,51 +581,97 @@ namespace Game
[ConsoleCommand("timedemo")]
public static void TimeDemoCommand(string[] text)
{
string demoName;
if (text.Length < 1)
return;
string demoName = text[0];
demoName = "638201307621505588_v2";//return;
else
demoName = text[0];
if (!demoName.EndsWith(".gdem"))
demoName += ".gdem";
PlayerActor playerActor = Level.GetActors<PlayerActor>().First(/*x =>
x.GetScript<PlayerMovement>().PlayerId == NetworkManager.LocalPlayerClientId*/);
var playerMovement = playerActor.GetScript<PlayerMovement>();
string demoPath = Path.Combine(AssetManager.DemoPath, demoName);
if (File.Exists(demoPath))
playerMovement.SetInput(demoPath);
NetworkManager.PlayDemo(demoPath);
float oldPhysicsFps = Time.PhysicsFPS;
float oldFps = Time.UpdateFPS;
Time.PhysicsFPS = 0f;
Time.UpdateFPS = 0f;
Time.DrawFPS = 0f;
float accumTime = 0f;
int accumTimes = 0;
timeDemoUpdate = () =>
{
if (playerMovement)
if (!NetworkManager.IsDemoPlaying)
{
var input = playerMovement.input as PlayerInputDemo;
if (input != null)
{
if (!input.IsPlaying)
{
Console.Print($"demo ended, time: {accumTimes} frames, avg: {(accumTime/(float)accumTimes)*1000.0f}");
timeDemoUpdate = null;
return;
}
if (accumTimes == 0)
Console.Print($"timedemo started");
accumTime += Time.DeltaTime;
accumTimes++;
}
Console.Print($"timedemo ended, time: {accumTimes} frames, avg: {(accumTime/(float)accumTimes)*1000.0f}");
timeDemoUpdate = null;
Time.PhysicsFPS = oldPhysicsFps;
Time.UpdateFPS = oldFps;
Time.DrawFPS = oldFps;
return;
}
if (accumTimes == 0)
Console.Print($"timedemo started");
accumTime += Time.DeltaTime;
accumTimes++;
};
Scripting.Update -= TimeDemoOnUpdate;
Scripting.Update += TimeDemoOnUpdate;
}
[ConsoleCommand("timedemo2")]
public static void TimeDemo2Command(string[] text)
{
string demoName;
if (text.Length < 1)
demoName = "638201307621505588_v2";//return;
else
demoName = text[0];
if (!demoName.EndsWith(".gdem"))
demoName += ".gdem";
string demoPath = Path.Combine(AssetManager.DemoPath, demoName);
NetworkManager.PlayDemo(demoPath);
float oldPhysicsFps = Time.PhysicsFPS;
float oldFps = Time.UpdateFPS;
Time.PhysicsFPS = 0f;
Time.UpdateFPS = 5f;
Time.DrawFPS = 5f;
float accumTime = 0f;
int accumTimes = 0;
timeDemoUpdate = () =>
{
if (!NetworkManager.IsDemoPlaying)
{
Console.Print($"timedemo ended, time: {accumTimes} frames, avg: {(accumTime/(float)accumTimes)*1000.0f}");
timeDemoUpdate = null;
Time.PhysicsFPS = oldPhysicsFps;
Time.UpdateFPS = oldFps;
Time.DrawFPS = oldFps;
return;
}
if (accumTimes == 0)
Console.Print($"timedemo started");
accumTime += Time.DeltaTime;
accumTimes++;
};
Scripting.FixedUpdate -= TimeDemoOnUpdate;
Scripting.FixedUpdate += TimeDemoOnUpdate;
}
[ConsoleVariable("net_fakelag")]
public static string NetFakeLag
{

View File

@@ -84,6 +84,11 @@ namespace Game
Level.SceneLoaded -= OnLevelLoaded;
//Scripting.LateUpdate -= OnLateUpdatePre;
Scripting.LateFixedUpdate -= OnLateUpdatePre;
foreach (var player in Level.GetActors<PlayerActor>())
{
FlaxEngine.Object.Destroy(player);
}
}
private static PlayerFrame GetPlayerFrame(uint playerIndex, ulong playerFrameIndex)
@@ -109,8 +114,8 @@ namespace Game
try
{
NetworkManager.IsServer = NetworkManager.server != null;
NetworkManager.IsClient = NetworkManager.client != null && NetworkManager.server == null;
NetworkManager.IsLocalClient = NetworkManager.client != null && 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
@@ -213,9 +218,9 @@ namespace Game
clientWorldState.playerFrameHistory.Add(playerId, playerFrames);
}
var playerFrameHistory = clientWorldState.playerFrameHistory[playerId];
var playerFrame = playerFrameHistory[clientWorldState.frame % 120];
var playerFrame = playerFrameHistory[ClientFrame % 120];
playerFrame.frame = clientWorldState.frame;
playerFrame.frame = ClientFrame;
playerFrame.position = playerActor.Position;
}
@@ -341,7 +346,7 @@ namespace Game
new Float3(networkEvent.Message.ReadSingle(), networkEvent.Message.ReadSingle(), networkEvent.Message.ReadSingle()));
//if (NetworkManager.IsClient)
players[playerId].GetScript<PlayerMovement>().input.frame = clientWorldState.frame;
players[playerId].GetScript<PlayerMovement>().input.frame = ClientFrame;
break;
}
case GameModeMessageType.PlayerInput:
@@ -547,7 +552,7 @@ namespace Game
players.Add(playerId, null);
players[playerId] = playerActor;
PlayerInput playerInput = playerActor.GetScript<PlayerMovement>().input;
playerInput.frame = (NetworkManager.IsServer) ? serverWorldState.frame : clientWorldState.frame;
playerInput.frame = (NetworkManager.IsServer) ? serverWorldState.frame : ClientFrame;
if (NetworkManager.IsServer)
{
serverWorldState.actors.Add(playerActor);

View File

@@ -82,23 +82,25 @@ namespace Game
public static void Cleanup()
{
Scripting.Exit -= Cleanup;
Scripting.FixedUpdate -= OnDemoUpdate;
Scripting.FixedUpdate -= OnServerNetworkUpdate;
Level.ActorSpawned -= OnServerActorSpawned;
Scripting.FixedUpdate -= OnClientNetworkUpdate;
Level.ActorSpawned -= OnClientActorSpawned;
if (server != null)
{
Scripting.FixedUpdate -= OnServerUpdate;
Scripting.Exit -= Cleanup;
Level.ActorSpawned -= OnServerActorSpawned;
NetworkPeer.ShutdownPeer(server);
server = null;
}
if (client != null)
{
Scripting.FixedUpdate -= OnClientUpdate;
Scripting.Exit -= Cleanup;
Level.ActorSpawned -= OnClientActorSpawned;
NetworkPeer.ShutdownPeer(client);
client = null;
}
LocalPlayerClientId = 0;
#if FLAX_EDITOR
@@ -107,6 +109,8 @@ namespace Game
#endif
GameModeManager.Cleanup(); // FIXME
StopRecording();
initialized = false;
}
@@ -147,5 +151,7 @@ namespace Game
break;
}
}
}
}

View File

@@ -49,79 +49,96 @@ namespace Game
return false;
}
Scripting.FixedUpdate += OnClientUpdate;
Scripting.FixedUpdate += OnClientNetworkUpdate;
if (!listenServer)
{
Scripting.Exit += Cleanup;
Level.ActorSpawned += OnClientActorSpawned;
//Level.ActorSpawned += OnClientActorSpawned;
}
string demoPath = System.IO.Path.Combine(AssetManager.DemoPath, $"{DateTimeOffset.Now.UtcTicks}_v2.gdem");
RecordDemo(demoPath);
return true;
}
private static void OnClientUpdate()
private static void OnClientNetworkUpdate()
{
using Utilities.ScopeProfiler _ = Utilities.ProfileScope("NetworkManager_OnClientUpdate");
using var _ = Utilities.ProfileScope("NetworkManager_OnClientNetworkUpdate");
while (client.PopEvent(out NetworkEvent networkEvent))
switch (networkEvent.EventType)
{
RecordMessage(ref networkEvent);
try
{
case NetworkEventType.Connected:
{
LocalPlayerClientId = networkEvent.Sender.ConnectionId;
Console.Print("Connected to server, ConnectionId: " + networkEvent.Sender.ConnectionId);
break;
}
case NetworkEventType.Disconnected:
{
Console.Print("Disconnected from server, timeout.");
LocalPlayerClientId = 0;
break;
}
case NetworkEventType.Timeout:
{
Console.Print("Disconnected from server, connection closed.");
LocalPlayerClientId = 0;
break;
}
case NetworkEventType.Message:
{
try
{
IsLocalClient = server != null;
IsClient = true;
OnNetworkMessage(ref networkEvent);
if (networkEvent.Message.Position > 0 &&
networkEvent.Message.Position < networkEvent.Message.Length)
{
string err =
$"Network message was not fully read: {networkEvent.Message.Position} / {networkEvent.Message.Length}.";
networkEvent.Message.Position = 0;
byte[] messageBytes = new byte[networkEvent.Message.Length];
unsafe
{
fixed (byte* messageBytePtr = &messageBytes[0])
networkEvent.Message.ReadBytes(messageBytePtr, (int)networkEvent.Message.Length);
}
string messageBytesStr = string.Join(", ",
messageBytes.Select(x => "0x" + ((int)x).ToString("X2")));
Console.PrintError(err + $"Message dump: {messageBytesStr}");
}
}
finally
{
IsLocalClient = false;
IsClient = false;
client.RecycleMessage(networkEvent.Message);
}
break;
}
default:
throw new ArgumentOutOfRangeException();
IsLocalClient = server != null;
IsClient = true;
OnClientReadMessage(ref networkEvent);
}
finally
{
IsLocalClient = false;
IsClient = false;
if (networkEvent.EventType == NetworkEventType.Message)
client.RecycleMessage(networkEvent.Message);
}
}
}
private static void OnClientReadMessage(ref NetworkEvent networkEvent)
{
using var _ = Utilities.ProfileScope("NetworkManager_OnClientReadMessage");
switch (networkEvent.EventType)
{
case NetworkEventType.Connected:
{
LocalPlayerClientId = networkEvent.Sender.ConnectionId;
Console.Print("Connected to server, ConnectionId: " + networkEvent.Sender.ConnectionId);
break;
}
case NetworkEventType.Disconnected:
{
Console.Print("Disconnected from server, timeout.");
LocalPlayerClientId = 0;
break;
}
case NetworkEventType.Timeout:
{
Console.Print("Disconnected from server, connection closed.");
LocalPlayerClientId = 0;
break;
}
case NetworkEventType.Message:
{
OnNetworkMessage(ref networkEvent);
if (networkEvent.Message.Position > 0 &&
networkEvent.Message.Position < networkEvent.Message.Length)
{
string err =
$"Network message was not fully read: {networkEvent.Message.Position} / {networkEvent.Message.Length}.\n";
networkEvent.Message.Position = 0;
byte[] messageBytes = new byte[networkEvent.Message.Length];
unsafe
{
fixed (byte* messageBytePtr = &messageBytes[0])
networkEvent.Message.ReadBytes(messageBytePtr, (int)networkEvent.Message.Length);
}
//string messageBytesStr = string.Join(", ", messageBytes.Select(x => "0x" + ((int)x).ToString("X2")));
string messageBytesStr = string.Join("", messageBytes.Select(x => ((int)x).ToString("X2")));
Console.PrintError(err + $"Message dump: {messageBytesStr}");
}
break;
}
default:
throw new ArgumentOutOfRangeException();
}
}
private static void OnClientActorSpawned(Actor actor)

View File

@@ -0,0 +1,278 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using FlaxEngine;
using FlaxEngine.Networking;
using Console = Game.Console;
using Object = FlaxEngine.Object;
namespace Game
{
public static unsafe partial class NetworkManager
{
public const byte DemoVer = 2;
private struct DemoNetworkEventHeader
{
public NetworkEventType EventType;
public uint SenderId;
public uint MessageId;
public uint Length;
}
private static List<NetworkEvent> buffer;
private static IEnumerator<NetworkEvent> bufferEnumerable;
private static GZipStream demoStream; // record
private static FileStream demoFileStream;
public static bool IsRecording => demoStream != null;
private static long flushedFrames = 0;
public static bool IsDemoPlaying => bufferEnumerable != null;
public static bool PlayDemo(string demoName)
{
{
Cleanup();
GameModeManager.Init();
}
if (!ReadDemo(demoName))
{
Console.Print("Failed to read demo.");
return false;
}
/*if (client == null)
{
Console.Print("Failed to create NetworkPeer.");
return false;
}
if (!client.Connect())
{
Console.Print("Failed to connect to the server.");
return false;
}*/
Scripting.FixedUpdate += OnDemoUpdate;
//if (!listenServer)
{
Scripting.Exit += Cleanup;
//Level.ActorSpawned += OnClientActorSpawned;
}
return true;
}
public static void RecordDemo(string demoPath)
{
if (IsRecording)
StopRecording();
buffer = new List<NetworkEvent>();
var demoFolder = Directory.GetParent(demoPath);
if (!demoFolder.Exists)
Directory.CreateDirectory(demoFolder.FullName);
demoFileStream = File.Open(demoPath, FileMode.Create, FileAccess.Write);
demoStream = new GZipStream(demoFileStream, CompressionMode.Compress);
demoStream.WriteByte(DemoVer);
}
private static void RecordMessage(ref NetworkEvent networkEvent)
{
if (!IsRecording)
return;
NetworkEvent recordedEvent = networkEvent;
recordedEvent.Message.Buffer = (byte*)NativeMemory.Alloc(recordedEvent.Message.Length);
recordedEvent.Sender.ConnectionId = networkEvent.Sender.ConnectionId;
NativeMemory.Copy(networkEvent.Message.Buffer, recordedEvent.Message.Buffer, recordedEvent.Message.Length);
buffer.Add(recordedEvent);
}
public static void FlushDemo()
{
if (!IsRecording)
return;
Stopwatch sw = Stopwatch.StartNew();
Span<byte> bytes = stackalloc byte[Unsafe.SizeOf<DemoNetworkEventHeader>()];
foreach (ref NetworkEvent networkEvent in CollectionsMarshal.AsSpan(buffer))
{
DemoNetworkEventHeader header = new DemoNetworkEventHeader()
{
EventType = networkEvent.EventType,
SenderId = networkEvent.Sender.ConnectionId,
Length = networkEvent.Message.Length,
MessageId = networkEvent.Message.MessageId,
};
MemoryMarshal.Write(bytes, ref header);
demoStream.Write(bytes);
Span<byte> messageBytes = new Span<byte>(networkEvent.Message.Buffer, (int)networkEvent.Message.Length);
demoStream.Write(messageBytes);
// TODO: free networkEvent buffer
}
sw.Stop();
flushedFrames += buffer.Count;
buffer.Clear();
FlaxEngine.Debug.Write(LogType.Info, $"Wrote demo in {sw.Elapsed.TotalMilliseconds}ms, frames: {flushedFrames}");
}
public static void StopRecording()
{
if (!IsRecording)
return;
FlushDemo();
demoStream.Close();
demoStream = null;
demoFileStream.Close();
demoFileStream = null;
}
private static unsafe bool ReadDemo(string demoPath)
{
if (!File.Exists(demoPath))
return false;
buffer = new List<NetworkEvent>();
Stopwatch sw = Stopwatch.StartNew();
using FileStream fileStream = File.OpenRead(demoPath);
using GZipStream stream = new GZipStream(fileStream, CompressionMode.Decompress);
int ver = stream.ReadByte();
if (ver != DemoVer)
{
Console.Print($"Demo version mismatch, expected {DemoVer}, got {ver}");
stream.Close();
return false;
}
int headerSize = Unsafe.SizeOf<DemoNetworkEventHeader>();
Span<byte> headerBuffer = stackalloc byte[headerSize];
while (true)
{
{
int bytesLeftInBuffer = headerSize;
do
{
int readBytes = stream.Read(headerBuffer.Slice(headerSize - bytesLeftInBuffer, bytesLeftInBuffer));
if (readBytes == 0)
break;
bytesLeftInBuffer -= readBytes;
} while (bytesLeftInBuffer > 0);
if (bytesLeftInBuffer > 0)
break; // EOF;
}
DemoNetworkEventHeader header = MemoryMarshal.Read<DemoNetworkEventHeader>(headerBuffer);
//buffer.Add(new NetworkEvent());
//ref NetworkEvent networkEvent = ref buffer[buffer.Length]; // collectionmarshal
NetworkEvent networkEvent = new NetworkEvent();
networkEvent.EventType = header.EventType;
networkEvent.Message.Position = 0;
networkEvent.Message.MessageId = header.MessageId;
networkEvent.Message.Length = networkEvent.Message.BufferSize = header.Length;
networkEvent.Sender.ConnectionId = header.SenderId;
if (header.Length > 0)
{
networkEvent.Message.Buffer = (byte*)NativeMemory.Alloc(header.Length);
Span<byte> messageBufferSpan = new Span<byte>(networkEvent.Message.Buffer, (int)networkEvent.Message.BufferSize);
{
int bytesLeftInBuffer = (int)header.Length;
do
{
int readBytes = stream.Read(messageBufferSpan.Slice((int)header.Length - bytesLeftInBuffer, bytesLeftInBuffer));
if (readBytes == 0)
break;
bytesLeftInBuffer -= readBytes;
} while (bytesLeftInBuffer > 0);
if (bytesLeftInBuffer > 0)
break; // EOF;
}
}
buffer.Add(networkEvent);
}
sw.Stop();
bufferEnumerable = buffer.GetEnumerator();
Console.Print($"Demo parse time {sw.Elapsed.TotalMilliseconds}ms, frames: {buffer.Count} ");
DemoEndFrame(); // advances to first frame
return true;
}
private static void DemoEndFrame()
{
// TODO: check if the current state frame matches the current frame number before advancing
/*asdf++;
if (asdf < 8)
return;*/
if (bufferEnumerable == null || !bufferEnumerable.MoveNext())
{
if (buffer.Any())
{
bufferEnumerable.Dispose();
bufferEnumerable = null;
buffer.Clear();
Console.Print("Demo ended");
}
return;
}
//var actorState = currentState.actor;
//currentState.input = bufferEnumerable.Current;
//frame++;
//currentState.actor = actorState;
}
private static void OnDemoUpdate()
{
if (!IsDemoPlaying)
return;
using Utilities.ScopeProfiler _ = Utilities.ProfileScope("NetworkManager_OnDemoUpdate");
NetworkEvent demoEvent = bufferEnumerable.Current; // ref?
// TODO: change/randomize Sender.ConnectionId?
try
{
IsLocalClient = server != null;
IsClient = true;
OnClientReadMessage(ref demoEvent);
}
finally
{
IsLocalClient = false;
IsClient = false;
//TODO: recycle event?
}
DemoEndFrame();
}
}
}

View File

@@ -44,7 +44,7 @@ namespace Game
return false;
}
Scripting.FixedUpdate += OnServerUpdate;
Scripting.FixedUpdate += OnServerNetworkUpdate;
Scripting.Exit += Cleanup;
Level.ActorSpawned += OnServerActorSpawned;
@@ -116,84 +116,91 @@ namespace Game
client.EndSendMessage(channelType, message);
}
private static void OnServerUpdate()
private static void OnServerNetworkUpdate()
{
using Utilities.ScopeProfiler _ = Utilities.ProfileScope("NetworkManager_OnServerUpdate");
using var _ = Utilities.ProfileScope("NetworkManager_OnServerNetworkUpdate");
while (server.PopEvent(out NetworkEvent networkEvent))
switch (networkEvent.EventType)
OnServerReadMessage(ref networkEvent);
}
private static void OnServerReadMessage(ref NetworkEvent networkEvent)
{
using var _ = Utilities.ProfileScope("NetworkManager_OnServerReadMessage");
switch (networkEvent.EventType)
{
case NetworkEventType.Connected:
{
case NetworkEventType.Connected:
Console.Print($"Client({networkEvent.Sender.ConnectionId}) is trying to connect");
try
{
Console.Print($"Client({networkEvent.Sender.ConnectionId}) is trying to connect");
try
IsServer = true;
if (GameModeManager.OnClientConnecting(networkEvent.Sender))
{
IsServer = true;
if (GameModeManager.OnClientConnecting(networkEvent.Sender))
{
ConnectedClients.Add(networkEvent.Sender);
Console.Print(
$"Client({networkEvent.Sender.ConnectionId}) connected. Total clients: {ConnectedClients.Count}");
ConnectedClients.Add(networkEvent.Sender);
Console.Print(
$"Client({networkEvent.Sender.ConnectionId}) connected. Total clients: {ConnectedClients.Count}");
GameModeManager.OnClientConnected(networkEvent.Sender);
}
else
Console.Print($"Client({networkEvent.Sender.ConnectionId}) connection refused");
GameModeManager.OnClientConnected(networkEvent.Sender);
}
finally
{
IsServer = false;
}
break;
else
Console.Print($"Client({networkEvent.Sender.ConnectionId}) connection refused");
}
case NetworkEventType.Disconnected:
case NetworkEventType.Timeout:
finally
{
Console.Print($"Client({networkEvent.Sender.ConnectionId}) disconnected!");
ConnectedClients.Remove(networkEvent.Sender);
Console.Print("Connected clients: " + ConnectedClients.Count);
break;
IsServer = false;
}
case NetworkEventType.Message:
{
try
{
IsServer = true;
OnNetworkMessage(ref networkEvent);
if (networkEvent.Message.Position > 0 &&
networkEvent.Message.Position < networkEvent.Message.Length)
{
string err =
$"Network message was not fully read: {networkEvent.Message.Position} / {networkEvent.Message.Length}.";
networkEvent.Message.Position = 0;
byte[] messageBytes = new byte[networkEvent.Message.Length];
unsafe
{
fixed (byte* messageBytePtr = &messageBytes[0])
networkEvent.Message.ReadBytes(messageBytePtr, (int)networkEvent.Message.Length);
}
string messageBytesStr = string.Join(", ",
messageBytes.Select(x => "0x" + ((int)x).ToString("X2")));
Console.PrintError(err + $"Message dump: {messageBytesStr}");
}
}
finally
{
IsServer = false;
server.RecycleMessage(networkEvent.Message);
}
break;
}
default:
throw new ArgumentOutOfRangeException();
break;
}
case NetworkEventType.Disconnected:
case NetworkEventType.Timeout:
{
Console.Print($"Client({networkEvent.Sender.ConnectionId}) disconnected!");
ConnectedClients.Remove(networkEvent.Sender);
Console.Print("Connected clients: " + ConnectedClients.Count);
break;
}
case NetworkEventType.Message:
{
try
{
IsServer = true;
OnNetworkMessage(ref networkEvent);
if (networkEvent.Message.Position > 0 &&
networkEvent.Message.Position < networkEvent.Message.Length)
{
string err =
$"Network message was not fully read: {networkEvent.Message.Position} / {networkEvent.Message.Length}.";
networkEvent.Message.Position = 0;
byte[] messageBytes = new byte[networkEvent.Message.Length];
unsafe
{
fixed (byte* messageBytePtr = &messageBytes[0])
networkEvent.Message.ReadBytes(messageBytePtr, (int)networkEvent.Message.Length);
}
string messageBytesStr = string.Join(", ",
messageBytes.Select(x => "0x" + ((int)x).ToString("X2")));
Console.PrintError(err + $"Message dump: {messageBytesStr}");
}
}
finally
{
IsServer = false;
server.RecycleMessage(networkEvent.Message);
}
break;
}
default:
throw new ArgumentOutOfRangeException();
}
}
private static void OnServerActorSpawned(Actor actor)

View File

@@ -1286,7 +1286,7 @@ namespace Game
LightWithShadow light;
Float3? lightTargetPosition = null;
int preset = 3;
if (entity.properties.TryGetValue("target", out string targetName))
{
@@ -1353,6 +1353,7 @@ namespace Game
light.ShadowsDistance = 500f;
light.ShadowsDepthBias = 0.027f;//0.005f;
int preset = 3;
if (preset == 0) // most accurate?, huge radius and low performance
{
light.Brightness = lightamm / 93f;
@@ -1394,16 +1395,9 @@ namespace Game
}
else //if (preset == 3)
{
if (pointLight != null)
{
pointLight.Radius = radamm * LightRadiusMultiplier;
pointLight.FallOffExponent = FallOffExponent;
}
if (spotLight != null)
{
spotLight.Radius = radamm * LightRadiusMultiplier;
spotLight.FallOffExponent = FallOffExponent;
}
bool inverse = false;
float finalRadius = radamm * LightRadiusMultiplier;
light.Brightness = (lightamm / 128f) * BrightnessMultiplier;
@@ -1427,6 +1421,25 @@ namespace Game
// huge aliasing with spot lights for some reason?
light.ShadowsDepthBias = 0.7f;
}
if (inverse)
{
light.Brightness *= 20000f;
finalRadius *= 0.7f;
}
if (pointLight != null)
{
pointLight.UseInverseSquaredFalloff = inverse;
pointLight.Radius = finalRadius;
pointLight.FallOffExponent = FallOffExponent;
}
if (spotLight != null)
{
spotLight.UseInverseSquaredFalloff = inverse;
spotLight.Radius = finalRadius;
spotLight.FallOffExponent = FallOffExponent;
}
}
lightIndex++;

View File

@@ -90,11 +90,13 @@ namespace Game
public class PlayerInput
{
public const byte DemoVer = 1;
public const int MaxPlayerStates = 120;
public PlayerState currentState;
public ulong frame;
//public ulong oldestFrame;
private PlayerState[] states = new PlayerState[120];
private PlayerState[] states = new PlayerState[MaxPlayerStates];
public virtual bool Predict => false;
@@ -110,7 +112,7 @@ namespace Game
{
//Console.Print("recorded frame " + frame);
states[frame % 120] = currentState;
states[frame % MaxPlayerStates] = currentState;
/*ulong oldest = ulong.MaxValue;
for (int i = 0; i < 120; i++)
@@ -130,7 +132,7 @@ namespace Game
public bool GetState(ulong frame, out PlayerInputState inputState, out PlayerActorState actorState)
{
int frameIndex = (int)frame % 120;
int frameIndex = (int)frame % MaxPlayerStates;
if (states[frameIndex].input.frame != frame)
{
inputState = default;
@@ -145,7 +147,7 @@ namespace Game
public void SetState(ulong frame, PlayerInputState inputState)
{
int frameIndex = (int)frame % 120;
int frameIndex = (int)frame % MaxPlayerStates;
states[frameIndex].input = inputState;
states[frameIndex].input.frame = frame;
states[frameIndex].actor = new PlayerActorState();
@@ -153,7 +155,7 @@ namespace Game
public void SetState(ulong frame, PlayerInputState inputState, PlayerActorState actorState)
{
int frameIndex = (int)frame % 120;
int frameIndex = (int)frame % MaxPlayerStates;
states[frameIndex].input = inputState;
states[frameIndex].input.frame = frame;
states[frameIndex].actor = actorState;

View File

@@ -27,9 +27,11 @@ namespace Game
public override bool Predict => true;
public PlayerInputLocal(PlayerActor playerActor, string demoPath)
public PlayerInputLocal(PlayerActor playerActor, string demoPath = null)
{
this.playerActor = playerActor;
if (demoPath == null)
return;
var demoFolder = Directory.GetParent(demoPath);
if (!demoFolder.Exists)
Directory.CreateDirectory(demoFolder.FullName);
@@ -72,6 +74,7 @@ namespace Game
public override void OnEndFrame()
{
currentState.input.frame = frame;
if (IsRecording)
{
currentState.input.verificationPosition = currentState.actor.position;
@@ -79,7 +82,6 @@ namespace Game
currentState.input.verificationViewAngles = currentState.actor.viewAngles;
currentState.input.verificationOrientation = currentState.actor.orientation;
currentState.input.frame = frame;
buffer.Add(currentState.input);
}
@@ -111,14 +113,6 @@ namespace Game
currentState.input.viewDeltaY = 0;
}
public override void RecordCurrentActorState(PlayerActorState actorState)
{
if (!IsRecording)
return;
base.RecordCurrentActorState(actorState);
}
public void FlushDemo()
{
if (!IsRecording)

View File

@@ -135,7 +135,6 @@ namespace Game
public Float3 viewAngles;
private Float3 viewAnglesLastFrame;
[NetworkReplicated]
public uint PlayerId = 0;
[ReadOnly]
@@ -186,8 +185,9 @@ namespace Game
if (PlayerId == NetworkManager.LocalPlayerClientId)//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
//string demoPath = System.IO.Path.Combine(AssetManager.DemoPath, $"{DateTimeOffset.Now.UtcTicks}.gdem");
//input = new PlayerInputLocal(playerActor, demoPath); // TODO: support recording
input = new PlayerInputLocal(playerActor);
}
else
@@ -327,67 +327,14 @@ namespace Game
public override void OnFixedUpdate()
{
PlayerInputDemo demoInput = input as PlayerInputDemo;
if (demoInput != null)
demoInput.OnUpdate();
float timeDeltaDiff = Time.DeltaTime - 1.0f / Time.PhysicsFPS;
if (Math.Abs(timeDeltaDiff) > 0.0001f)
if (Time.PhysicsFPS > 0 && Math.Abs(timeDeltaDiff) > 0.0001f)
Console.Print("Time.DeltaTime is not stable: " + timeDeltaDiff);
input.OnFixedUpdate();
PlayerInputState inputState = input.GetCurrentInputState();
if (demoInput != null && demoInput.IsPlaying)
{
ApplyInputToCamera(inputState, true);
// Verify view angles first
if (demoDeltasVerify)
{
Float3 verifAngles = new Float3(inputState.verificationViewAngles.Y, inputState.verificationViewAngles.X, inputState.verificationViewAngles.Z);
float viewAnglesDelta = (viewAngles - verifAngles).Length;
if (viewAnglesDelta > 0.00001)
{
Console.Print($"Demo verification failed, view angles delta: {viewAnglesDelta}, viewAngles:{viewAngles}, verif:{verifAngles}");
if (demoDeltasCorrect)
SetCameraEulerAngles(verifAngles, false);
}
}
SimulatePlayerMovement(inputState);
if (demoDeltasVerify)
{
// verify
float positionDelta = (movementState.position - inputState.verificationPosition).Length;
if (positionDelta > 0.00001)
Console.Print("Demo verification failed, position delta: " + positionDelta);
float velocityDelta = (movementState.currentVelocity - inputState.verificationVelocity).Length;
if (velocityDelta > 0.00001)
Console.Print("Demo verification failed, velocity delta: " + velocityDelta);
float orientationDelta = (rootActor.Orientation - inputState.verificationOrientation).Length;
if (orientationDelta > 0.00001)
{
Console.Print("Demo verification failed, orientation delta: " + orientationDelta);
if (demoDeltasCorrect)
{
}
}
//if (currentInputFrame == 0)
/*{
//Console.Print("repos: " + inputState.verificationPosition);
movementState.position = inputState.verificationPosition;
currentVelocity = inputState.verificationVelocity;
rootActor.Orientation = inputState.verificationOrientation;
}*/
}
}
else if (input is PlayerInputNetwork)
if (input is PlayerInputNetwork)
{
#if false
bool canpredict = true;
@@ -497,7 +444,7 @@ namespace Game
//viewAngles = viewAnglesLastFrame;
bool canpredict = true;
if (true && input.Predict && GameModeManager.ClientFrame > 0 && GameModeManager.ServerFrame > 0)
if (true && input.Predict /*&& !NetworkManager.IsDemoPlaying*/ && GameModeManager.ClientFrame > 0 && GameModeManager.ServerFrame > 0)
{
ulong currentFrame = GameModeManager.ServerFrame;
for (; currentFrame < GameModeManager.ClientFrame; currentFrame++)
@@ -580,9 +527,11 @@ namespace Game
predicting = false;
if ((movementState.position - oldPos).Length > 0.001)
var posDelta = (movementState.position - oldPos);
var velDelta = (movementState.currentVelocity - oldVel);
if (posDelta.Length > 0.001)
Console.Print($"mispredicted final position");
if ((movementState.currentVelocity - oldVel).Length > 0.001)
if (velDelta.Length > 0.001)
Console.Print($"mispredicted final velocity");
@@ -602,7 +551,8 @@ namespace Game
SimulatePlayerMovement(inputState);
}
if ((viewAngles - oldAngles).Length > 0.001)
var viewDelta = (viewAngles - oldAngles);
if (viewDelta.Length > 0.001)
Console.Print($"mispredicted final viewangles: {viewAngles} <- {oldAngles}");
//if (viewAngles != new Float3(90f, 0f, 0f))