diff --git a/src/Prospect.Server.Game/Program.cs b/src/Prospect.Server.Game/Program.cs index eb15b0c..a0a93c4 100644 --- a/src/Prospect.Server.Game/Program.cs +++ b/src/Prospect.Server.Game/Program.cs @@ -1,4 +1,4 @@ -using Prospect.Unreal.Net; +using Prospect.Unreal.Core; using Serilog; namespace Prospect.Server.Game; @@ -10,9 +10,9 @@ internal static class Program private static readonly ILogger Logger = Log.ForContext(typeof(Program)); private static readonly PeriodicTimer Tick = new PeriodicTimer(TimeSpan.FromSeconds(TickRate)); - public static async Task Main(string[] args) + public static async Task Main() { - Console.CancelKeyPress += (s, e) => + Console.CancelKeyPress += (_, e) => { Tick.Dispose(); e.Cancel = true; @@ -25,23 +25,19 @@ internal static class Program .CreateLogger(); Logger.Information("Starting Prospect.Server.Game"); - - await using (var driver = new UIpNetDriver()) + + var worldUrl = new FUrl { - driver.Init(); + Map = "/Game/ThirdPersonCPP/Maps/ThirdPersonExampleMap" + }; + + await using (var world = new ProspectWorld(worldUrl)) + { + world.Listen(); - // Tick all components. while (await Tick.WaitForNextTickAsync()) { - var deltaTime = TickRate; - - driver.TickDispatch(deltaTime); - // driver.PostTickDispatch(); - - if (driver.ConnectionlessHandler != null) - { - driver.ConnectionlessHandler.Tick(deltaTime); - } + world.Tick(TickRate); } } diff --git a/src/Prospect.Server.Game/ProspectWorld.cs b/src/Prospect.Server.Game/ProspectWorld.cs new file mode 100644 index 0000000..2ff5b31 --- /dev/null +++ b/src/Prospect.Server.Game/ProspectWorld.cs @@ -0,0 +1,11 @@ +using Prospect.Unreal.Core; +using Prospect.Unreal.Runtime; + +namespace Prospect.Server.Game; + +public class ProspectWorld : UWorld +{ + public ProspectWorld(FUrl url) : base(url) + { + } +} \ No newline at end of file diff --git a/src/Prospect.Unreal/Core/FURL.cs b/src/Prospect.Unreal/Core/FURL.cs deleted file mode 100644 index d8384e0..0000000 --- a/src/Prospect.Unreal/Core/FURL.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Prospect.Unreal.Core; - -public class FURL -{ - -} \ No newline at end of file diff --git a/src/Prospect.Unreal/Core/FUrl.cs b/src/Prospect.Unreal/Core/FUrl.cs new file mode 100644 index 0000000..132b0d8 --- /dev/null +++ b/src/Prospect.Unreal/Core/FUrl.cs @@ -0,0 +1,14 @@ +using System.Net; + +namespace Prospect.Unreal.Core; + +public class FUrl +{ + public string Protocol { get; init; } = "unreal"; + public IPAddress Host { get; init; } = IPAddress.Any; + public int Port { get; init; } = 7777; + public string Map { get; init; } = "GearStart"; + public string RedirectUrl { get; init; } = string.Empty; + public List Options { get; init; } = new List(); + public string Portal { get; init; } = string.Empty; +} \ No newline at end of file diff --git a/src/Prospect.Unreal/Exceptions/UnrealNetException.cs b/src/Prospect.Unreal/Exceptions/UnrealNetException.cs new file mode 100644 index 0000000..3b79db8 --- /dev/null +++ b/src/Prospect.Unreal/Exceptions/UnrealNetException.cs @@ -0,0 +1,22 @@ +using System.Runtime.Serialization; + +namespace Prospect.Unreal.Exceptions; + +public class UnrealNetException : UnrealException +{ + public UnrealNetException() + { + } + + protected UnrealNetException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + + public UnrealNetException(string? message) : base(message) + { + } + + public UnrealNetException(string? message, Exception? innerException) : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/src/Prospect.Unreal/Net/UIpConnection.cs b/src/Prospect.Unreal/Net/UIpConnection.cs index 666773b..5a9006a 100644 --- a/src/Prospect.Unreal/Net/UIpConnection.cs +++ b/src/Prospect.Unreal/Net/UIpConnection.cs @@ -6,17 +6,17 @@ namespace Prospect.Unreal.Net; public class UIpConnection : UNetConnection { - public override void InitBase(UNetDriver inDriver, UdpClient inSocket, FURL inURL, EConnectionState inState, int inMaxPacket = 0, int inPacketOverhead = 0) + public override void InitBase(UNetDriver inDriver, UdpClient inSocket, FUrl inURL, EConnectionState inState, int inMaxPacket = 0, int inPacketOverhead = 0) { throw new NotImplementedException(); } - public override void InitRemoteConnection(UNetDriver inDriver, UdpClient inSocket, FURL inURL, IPEndPoint inRemoteAddr, EConnectionState inState, int inMaxPacket = 0, int inPacketOverhead = 0) + public override void InitRemoteConnection(UNetDriver inDriver, UdpClient inSocket, FUrl inURL, IPEndPoint inRemoteAddr, EConnectionState inState, int inMaxPacket = 0, int inPacketOverhead = 0) { throw new NotImplementedException(); } - public override void InitLocalConnection(UNetDriver inDriver, UdpClient inSocket, FURL inURL, EConnectionState inState, + public override void InitLocalConnection(UNetDriver inDriver, UdpClient inSocket, FUrl inURL, EConnectionState inState, int inMaxPacket = 0, int inPacketOverhead = 0) { throw new NotImplementedException(); diff --git a/src/Prospect.Unreal/Net/UIpNetDriver.cs b/src/Prospect.Unreal/Net/UIpNetDriver.cs index f6c2aaa..257fcde 100644 --- a/src/Prospect.Unreal/Net/UIpNetDriver.cs +++ b/src/Prospect.Unreal/Net/UIpNetDriver.cs @@ -11,9 +11,9 @@ public class UIpNetDriver : UNetDriver private bool _isDisposed; - public UIpNetDriver() + public UIpNetDriver(IPAddress host, int port) { - ServerIp = new IPEndPoint(IPAddress.Any, 7777); + ServerIp = new IPEndPoint(host, port); Socket = new UdpClient(ServerIp); ReceiveThread = new FReceiveThreadRunnable(this); } @@ -22,7 +22,7 @@ public class UIpNetDriver : UNetDriver public UdpClient Socket { get; } public FReceiveThreadRunnable ReceiveThread { get; } - public bool Init() + public override bool Init() { // Initialize connectionless packet handler. InitConnectionlessHandler(); @@ -119,8 +119,7 @@ public class UIpNetDriver : UNetDriver returnVal.InitSequence(clientSequence, serverSequence); } - // TODO: World url - returnVal.InitRemoteConnection(this, Socket, null, address, EConnectionState.USOCK_Open); + returnVal.InitRemoteConnection(this, Socket, World != null ? World.Url : new FUrl(), address, EConnectionState.USOCK_Open); // if (returnVal.Handler) } diff --git a/src/Prospect.Unreal/Net/UNetConnection.cs b/src/Prospect.Unreal/Net/UNetConnection.cs index 54d4672..e679d6d 100644 --- a/src/Prospect.Unreal/Net/UNetConnection.cs +++ b/src/Prospect.Unreal/Net/UNetConnection.cs @@ -9,9 +9,9 @@ public abstract class UNetConnection public const int ReliableBuffer = 256; public const int MaxPacketId = 16384; - public abstract void InitBase(UNetDriver inDriver, UdpClient inSocket, FURL inURL, EConnectionState inState, int inMaxPacket = 0, int inPacketOverhead = 0); - public abstract void InitRemoteConnection(UNetDriver inDriver, UdpClient inSocket, FURL inURL, IPEndPoint inRemoteAddr, EConnectionState inState, int inMaxPacket = 0, int inPacketOverhead = 0); - public abstract void InitLocalConnection(UNetDriver inDriver, UdpClient inSocket, FURL inURL, EConnectionState inState, int inMaxPacket = 0, int inPacketOverhead = 0); + public abstract void InitBase(UNetDriver inDriver, UdpClient inSocket, FUrl inURL, EConnectionState inState, int inMaxPacket = 0, int inPacketOverhead = 0); + public abstract void InitRemoteConnection(UNetDriver inDriver, UdpClient inSocket, FUrl inURL, IPEndPoint inRemoteAddr, EConnectionState inState, int inMaxPacket = 0, int inPacketOverhead = 0); + public abstract void InitLocalConnection(UNetDriver inDriver, UdpClient inSocket, FUrl inURL, EConnectionState inState, int inMaxPacket = 0, int inPacketOverhead = 0); public abstract void LowLevelSend(byte[] data, int countBits, FOutPacketTraits traits); public abstract string LowLevelGetRemoteAddress(bool bAppendPort = false); public abstract string LowLevelDescribe(); diff --git a/src/Prospect.Unreal/Net/UNetDriver.cs b/src/Prospect.Unreal/Net/UNetDriver.cs index 1140d95..fffdae6 100644 --- a/src/Prospect.Unreal/Net/UNetDriver.cs +++ b/src/Prospect.Unreal/Net/UNetDriver.cs @@ -1,5 +1,6 @@ using System.Collections.Concurrent; using System.Net; +using Prospect.Unreal.Runtime; namespace Prospect.Unreal.Net; @@ -12,6 +13,11 @@ public abstract class UNetDriver : IAsyncDisposable MappedClientConnections = new ConcurrentDictionary(); } + /// + /// World this net driver is associated with + /// + public UWorld? World { get; private set; } + /// /// Map of to . /// @@ -37,6 +43,11 @@ public abstract class UNetDriver : IAsyncDisposable ConnectionlessHandler.InitializeComponents(); } + + public virtual bool Init() + { + throw new NotImplementedException(); + } public virtual void TickDispatch(float deltaTime) { @@ -49,7 +60,22 @@ public abstract class UNetDriver : IAsyncDisposable } public abstract bool IsNetResourceValid(); + + public void SetWorld(UWorld? inWorld) + { + if (World != null) + { + World = null; + } + if (inWorld != null) + { + World = inWorld; + + // TODO: AddInitialObjects? + } + } + public double GetElapsedTime() { return _elapsedTime; diff --git a/src/Prospect.Unreal/Runtime/UWorld.cs b/src/Prospect.Unreal/Runtime/UWorld.cs new file mode 100644 index 0000000..e494903 --- /dev/null +++ b/src/Prospect.Unreal/Runtime/UWorld.cs @@ -0,0 +1,56 @@ +using Prospect.Unreal.Core; +using Prospect.Unreal.Net; +using Serilog; + +namespace Prospect.Unreal.Runtime; + +public abstract class UWorld : IAsyncDisposable +{ + private static readonly ILogger Logger = Log.ForContext(); + + public UWorld(FUrl url) + { + Url = url; + } + + public FUrl Url { get; } + public UNetDriver? NetDriver { get; private set; } + + public void Tick(float deltaTime) + { + if (NetDriver != null) + { + NetDriver.TickDispatch(deltaTime); + NetDriver.ConnectionlessHandler?.Tick(deltaTime); + } + } + + public bool Listen() + { + if (NetDriver != null) + { + Logger.Error("NetDriver already exists"); + return false; + } + + NetDriver = new UIpNetDriver(Url.Host, Url.Port); + NetDriver.SetWorld(this); + + if (!NetDriver.Init()) + { + Logger.Error("Failed to listen"); + NetDriver = null; + return false; + } + + return true; + } + + public async ValueTask DisposeAsync() + { + if (NetDriver != null) + { + await NetDriver.DisposeAsync(); + } + } +} \ No newline at end of file