From 14ce748c5c56e04135c9504b7c6c32cd9eb8af3d Mon Sep 17 00:00:00 2001 From: AeonLucid Date: Sat, 15 Jan 2022 04:34:25 +0100 Subject: [PATCH] Added more ticking functions --- .../Core/Names/UnrealConstants.cs | 2 +- .../Net/Channels/Actor/UActorChannel.cs | 11 ++++ .../Net/Channels/Control/UControlChannel.cs | 12 ++++ src/Prospect.Unreal/Net/Channels/UChannel.cs | 14 ++++- .../Net/Channels/Voice/UVoiceChannel.cs | 10 ++++ .../Net/FReceiveThreadRunnable.cs | 4 +- src/Prospect.Unreal/Net/PacketHandler.cs | 5 ++ .../Net/StatelessConnectHandlerComponent.cs | 2 - src/Prospect.Unreal/Net/UIpConnection.cs | 8 --- src/Prospect.Unreal/Net/UNetConnection.cs | 49 ++++++++++++++- src/Prospect.Unreal/Net/UNetDriver.cs | 59 +++++++++++++++++++ src/Prospect.Unreal/Runtime/UWorld.cs | 5 +- 12 files changed, 163 insertions(+), 18 deletions(-) diff --git a/src/Prospect.Unreal/Core/Names/UnrealConstants.cs b/src/Prospect.Unreal/Core/Names/UnrealConstants.cs index 430d038..a3bb93c 100644 --- a/src/Prospect.Unreal/Core/Names/UnrealConstants.cs +++ b/src/Prospect.Unreal/Core/Names/UnrealConstants.cs @@ -1,6 +1,6 @@ namespace Prospect.Unreal.Core.Names; -public class UnrealConstants +public static class UnrealConstants { public const int IndexNone = -1; } \ No newline at end of file diff --git a/src/Prospect.Unreal/Net/Channels/Actor/UActorChannel.cs b/src/Prospect.Unreal/Net/Channels/Actor/UActorChannel.cs index 575ea79..88af3c6 100644 --- a/src/Prospect.Unreal/Net/Channels/Actor/UActorChannel.cs +++ b/src/Prospect.Unreal/Net/Channels/Actor/UActorChannel.cs @@ -14,6 +14,17 @@ public class UActorChannel : UChannel // QueuedCloseReason = EChannelCloseReason::Destroyed; } + public override void Tick() + { + base.Tick(); + // TODO: ProcessQueuedBunches + } + + public override bool CanStopTicking() + { + return base.CanStopTicking() /* PendingGuidResolves / QueuedBunches */; + } + protected override void ReceivedBunch(FInBunch bunch) { throw new NotImplementedException(); diff --git a/src/Prospect.Unreal/Net/Channels/Control/UControlChannel.cs b/src/Prospect.Unreal/Net/Channels/Control/UControlChannel.cs index 40b6deb..db9ee88 100644 --- a/src/Prospect.Unreal/Net/Channels/Control/UControlChannel.cs +++ b/src/Prospect.Unreal/Net/Channels/Control/UControlChannel.cs @@ -15,6 +15,18 @@ public class UControlChannel : UChannel ChName = EName.Control; } + public override void Tick() + { + base.Tick(); + + // TODO: Resend packets that weren't [Ack]nowledged + } + + public override bool CanStopTicking() + { + return false; + } + protected override void ReceivedBunch(FInBunch bunch) { // if (Connection != null && bNeedsEndianInspection && !CheckEndianess(bunch)) diff --git a/src/Prospect.Unreal/Net/Channels/UChannel.cs b/src/Prospect.Unreal/Net/Channels/UChannel.cs index e7636d7..a592915 100644 --- a/src/Prospect.Unreal/Net/Channels/UChannel.cs +++ b/src/Prospect.Unreal/Net/Channels/UChannel.cs @@ -144,6 +144,16 @@ public abstract class UChannel SentClosingBunch = false; } + public virtual void Tick() + { + // TODO: Dormancy + } + + public virtual bool CanStopTicking() + { + return !bPendingDormancy; + } + public void ReceivedRawBunch(FInBunch bunch, out bool bOutSkipAck) { bOutSkipAck = false; @@ -151,12 +161,12 @@ public abstract class UChannel // Immediately consume the NetGUID portion of this bunch, regardless if it is partial or reliable. // NOTE - For replays, we do this even earlier, to try and load this as soon as possible, in case there is an issue creating the channel // If a replay fails to create a channel, we want to salvage as much as possible - if (bunch.bHasPackageMapExports && !Connection.IsInternalAck()) + if (bunch.bHasPackageMapExports && !Connection!.IsInternalAck()) { throw new NotImplementedException(); } - if (Connection.IsInternalAck() && Broken) + if (Connection!.IsInternalAck() && Broken) { return; } diff --git a/src/Prospect.Unreal/Net/Channels/Voice/UVoiceChannel.cs b/src/Prospect.Unreal/Net/Channels/Voice/UVoiceChannel.cs index 6ed7395..22b1d4e 100644 --- a/src/Prospect.Unreal/Net/Channels/Voice/UVoiceChannel.cs +++ b/src/Prospect.Unreal/Net/Channels/Voice/UVoiceChannel.cs @@ -11,6 +11,16 @@ public class UVoiceChannel : UChannel ChName = EName.Voice; } + public override void Tick() + { + // TODO: Tick + } + + public override bool CanStopTicking() + { + return false; + } + protected override void ReceivedBunch(FInBunch bunch) { throw new NotImplementedException(); diff --git a/src/Prospect.Unreal/Net/FReceiveThreadRunnable.cs b/src/Prospect.Unreal/Net/FReceiveThreadRunnable.cs index 96800c4..ebeb124 100644 --- a/src/Prospect.Unreal/Net/FReceiveThreadRunnable.cs +++ b/src/Prospect.Unreal/Net/FReceiveThreadRunnable.cs @@ -47,6 +47,8 @@ public class FReceiveThreadRunnable : IAsyncDisposable private async Task ReceiveAsync() { + Logger.Information("Started listening on {ServerIp}", _driver.ServerIp); + try { while (!_cancellation.IsCancellationRequested) @@ -76,7 +78,7 @@ public class FReceiveThreadRunnable : IAsyncDisposable } } - Logger.Debug("Stopped FReceiveThreadRunnable"); + Logger.Information("Stopped listening"); } public async ValueTask DisposeAsync() diff --git a/src/Prospect.Unreal/Net/PacketHandler.cs b/src/Prospect.Unreal/Net/PacketHandler.cs index 94d0f6b..bc7b190 100644 --- a/src/Prospect.Unreal/Net/PacketHandler.cs +++ b/src/Prospect.Unreal/Net/PacketHandler.cs @@ -326,6 +326,11 @@ public class PacketHandler SetState(HandlerState.Initialized); } + public bool IsFullyInitialized() + { + return _state == HandlerState.Initialized; + } + private void ReplaceIncomingPacket(FBitReader replacementPacket) { if (replacementPacket.GetPosBits() == 0 || replacementPacket.GetBitsLeft() == 0) diff --git a/src/Prospect.Unreal/Net/StatelessConnectHandlerComponent.cs b/src/Prospect.Unreal/Net/StatelessConnectHandlerComponent.cs index 3dcc533..162c348 100644 --- a/src/Prospect.Unreal/Net/StatelessConnectHandlerComponent.cs +++ b/src/Prospect.Unreal/Net/StatelessConnectHandlerComponent.cs @@ -132,8 +132,6 @@ public class StatelessConnectHandlerComponent : HandlerComponent public override void Initialize() { - Logger.Debug("Initializing"); - if (Handler.Mode == HandlerMode.Server) { Initialized(); diff --git a/src/Prospect.Unreal/Net/UIpConnection.cs b/src/Prospect.Unreal/Net/UIpConnection.cs index 16f2175..adeb57d 100644 --- a/src/Prospect.Unreal/Net/UIpConnection.cs +++ b/src/Prospect.Unreal/Net/UIpConnection.cs @@ -60,9 +60,6 @@ public class UIpConnection : UNetConnection var dataToSend = data; - // 243 - // 244 - // Process any packet modifiers if (Handler != null && !Handler.GetRawSend()) { @@ -106,11 +103,6 @@ public class UIpConnection : UNetConnection throw new NotImplementedException(); } - public override void Tick(float deltaSeconds) - { - throw new NotImplementedException(); - } - public override void CleanUp() { throw new NotImplementedException(); diff --git a/src/Prospect.Unreal/Net/UNetConnection.cs b/src/Prospect.Unreal/Net/UNetConnection.cs index 95468e1..c6b9fb0 100644 --- a/src/Prospect.Unreal/Net/UNetConnection.cs +++ b/src/Prospect.Unreal/Net/UNetConnection.cs @@ -43,7 +43,7 @@ public abstract class UNetConnection : UPlayer /// optimization over ticking and calling virtual functions on the potentially hundreds of /// OpenChannels every frame. /// - private HashSet _channelsToTick; + private List _channelsToTick; /// /// Online platform ID of remote player on this connection. Only valid on client connections (server side). @@ -89,7 +89,7 @@ public abstract class UNetConnection : UPlayer public UNetConnection() { - _channelsToTick = new HashSet(); + _channelsToTick = new List(); _playerOnlinePlatformName = EName.None; _packetOrderCache = null; _packetOrderCacheStartIdx = 0; @@ -381,7 +381,50 @@ public abstract class UNetConnection : UPlayer public abstract void LowLevelSend(byte[] data, int countBits, FOutPacketTraits traits); public abstract string LowLevelGetRemoteAddress(bool bAppendPort = false); public abstract string LowLevelDescribe(); - public abstract void Tick(float deltaSeconds); + + public virtual void Tick(float deltaSeconds) + { + if (_channelsToTick.Count > OpenChannels.Count) + { + Logger.Warning("More ticking channels ({Ticking}) than open channels ({Open}) for net connection!", _channelsToTick.Count, OpenChannels.Count); + } + + for (var i = _channelsToTick.Count - 1; i >= 0; i--) + { + _channelsToTick[i].Tick(); + + if (_channelsToTick[i].CanStopTicking()) + { + _channelsToTick.RemoveAt(i); + } + } + + // Flush + if (TimeSensitive || (Driver!.GetElapsedTime() - _lastSendTime) > Driver.KeepAliveTime) + { + var bHandlerHandshakeComplete = Handler == null || Handler.IsFullyInitialized(); + if (bHandlerHandshakeComplete) + { + FlushNet(); + } + } + + // Tick Handler + if (Handler != null) + { + Handler.Tick(deltaSeconds); + + // TODO: Low prio; send queued packets + } + + _bFlushedNetThisFrame = false; + } + + public virtual void PostTickDispatch() + { + + } + public abstract void CleanUp(); public virtual void ReceivedRawPacket(FReceivedPacketView packetView) diff --git a/src/Prospect.Unreal/Net/UNetDriver.cs b/src/Prospect.Unreal/Net/UNetDriver.cs index 6eac997..1523c37 100644 --- a/src/Prospect.Unreal/Net/UNetDriver.cs +++ b/src/Prospect.Unreal/Net/UNetDriver.cs @@ -96,9 +96,68 @@ public abstract class UNetDriver : IAsyncDisposable return true; } + /// + /// handle time update: read and process packets + /// public virtual void TickDispatch(float deltaTime) { _elapsedTime += deltaTime; + + // Delete closed connections. + for (var i = ClientConnections.Count - 1; i >= 0; i--) + { + if (ClientConnections[i].State == EConnectionState.USOCK_Closed) + { + ClientConnections[i].CleanUp(); + } + } + } + + /// + /// PostTickDispatch actions + /// + public virtual void PostTickDispatch() + { + foreach (var connection in ClientConnections) + { + /* TODO: (When UObject) if (!connection.IsPendingKill()) */ + { + connection.PostTickDispatch(); + } + } + } + + /// + /// ReplicateActors and Flush + /// + public virtual void TickFlush(float deltaTime) + { + if (IsServer() && ClientConnections.Count > 0) + { + // TODO: (When actors are implemented) ServerReplicateActors + } + + foreach (var connection in ClientConnections) + { + connection.Tick(deltaTime); + } + + if (ConnectionlessHandler != null) + { + ConnectionlessHandler.Tick(deltaTime); + + // TODO: FlushHandler + } + + // TODO: (When actors are implemented) CleanupStaleDormantReplicators + } + + /// + /// PostTick actions + /// + public virtual void PostTickFlush() + { + // ClearVoicePackets? } public virtual void LowLevelSend(IPEndPoint address, byte[] data, int countBits, FOutPacketTraits traits) diff --git a/src/Prospect.Unreal/Runtime/UWorld.cs b/src/Prospect.Unreal/Runtime/UWorld.cs index 55a9c33..b5ef4a1 100644 --- a/src/Prospect.Unreal/Runtime/UWorld.cs +++ b/src/Prospect.Unreal/Runtime/UWorld.cs @@ -33,7 +33,10 @@ public abstract partial class UWorld : FNetworkNotify, IAsyncDisposable if (NetDriver != null) { NetDriver.TickDispatch(deltaTime); - NetDriver.ConnectionlessHandler?.Tick(deltaTime); + NetDriver.PostTickDispatch(); + + NetDriver.TickFlush(deltaTime); + NetDriver.PostTickFlush(); } }