diff --git a/Source/Engine/Networking/Drivers/ENetDriver.h b/Source/Engine/Networking/Drivers/ENetDriver.h index 86e4635e0..b3096e716 100644 --- a/Source/Engine/Networking/Drivers/ENetDriver.h +++ b/Source/Engine/Networking/Drivers/ENetDriver.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #pragma once @@ -10,6 +10,9 @@ #include "Engine/Core/Collections/Dictionary.h" #include "Engine/Scripting/ScriptingType.h" +/// +/// Low-level network transport interface implementation based on ENet library. +/// API_CLASS(Namespace="FlaxEngine.Networking", Sealed) class FLAXENGINE_API ENetDriver : public INetworkDriver { DECLARE_SCRIPTING_TYPE_MINIMAL(ENetDriver); diff --git a/Source/Engine/Networking/INetworkDriver.h b/Source/Engine/Networking/INetworkDriver.h index bcdf65079..810f4e046 100644 --- a/Source/Engine/Networking/INetworkDriver.h +++ b/Source/Engine/Networking/INetworkDriver.h @@ -1,26 +1,98 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Scripting/ScriptingType.h" #include "Types.h" +/// +/// Basic interface for the low-level network transport/driver. +/// API_INTERFACE(Namespace="FlaxEngine.Networking") class FLAXENGINE_API INetworkDriver { DECLARE_SCRIPTING_TYPE_MINIMAL(INetworkDriver); public: + /// + /// Initializes the instance of this network driver using given configuration. + /// + /// The peer that this driver has been assigned to. + /// The network config to use to configure this driver. virtual void Initialize(NetworkPeer* host, const NetworkConfig& config) = 0; + + /// + /// Disposes this driver making it no longer usable. + /// Reserved for resource deallocation etc. + /// virtual void Dispose() = 0; + /// + /// Starts listening for incoming connections. + /// Once this is called, this driver becomes a server. + /// + /// True when succeeded. virtual bool Listen() = 0; + + /// + /// Starts connection handshake with the end point specified in the structure. + /// Once this is called, this driver becomes a client. + /// + /// True when succeeded. virtual bool Connect() = 0; + + /// + /// Disconnects from the server. + /// + /// Can be used only by the client! virtual void Disconnect() = 0; + + /// + /// Disconnects given connection from the server. + /// + /// Can be used only by the server! virtual void Disconnect(const NetworkConnection& connection) = 0; + /// + /// Tries to pop an network event from the queue. + /// + /// The pointer to event structure. + /// True when succeeded and the event can be processed. virtual bool PopEvent(NetworkEvent* eventPtr) = 0; + /// + /// Sends given message over specified channel to the server. + /// + /// The channel to send the message over. + /// The message. + /// Can be used only by the client! + /// + /// Do not recycle the message after calling this. + /// This function automatically recycles the message. virtual void SendMessage(NetworkChannelType channelType, const NetworkMessage& message) = 0; + + /// + /// Sends given message over specified channel to the given client connection (target). + /// + /// The channel to send the message over. + /// The message. + /// The client connection to send the message to. + /// Can be used only by the server! + /// + /// Do not recycle the message after calling this. + /// This function automatically recycles the message. + /// virtual void SendMessage(NetworkChannelType channelType, const NetworkMessage& message, NetworkConnection target) = 0; + + /// + /// Sends given message over specified channel to the given client connection (target). + /// + /// The channel to send the message over. + /// The message. + /// The connections list to send the message to. + /// Can be used only by the server! + /// + /// Do not recycle the message after calling this. + /// This function automatically recycles the message. + /// virtual void SendMessage(NetworkChannelType channelType, const NetworkMessage& message, Array targets) = 0; // TODO: Stats API diff --git a/Source/Engine/Networking/NetworkChannelType.h b/Source/Engine/Networking/NetworkChannelType.h index e2af9c34e..e5fbc8d9b 100644 --- a/Source/Engine/Networking/NetworkChannelType.h +++ b/Source/Engine/Networking/NetworkChannelType.h @@ -1,16 +1,40 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Scripting/ScriptingType.h" +/// +/// The low-level network channel type for message sending. +/// API_ENUM(Namespace="FlaxEngine.Networking") enum class NetworkChannelType { + /// + /// Invalid channel type. + /// None = 0, - + + /// + /// Unreliable channel type. + /// Messages can be lost or arrive out-of-order. + /// Unreliable, + + /// + /// Unreliable-ordered channel type. + /// Messages can be lost but always arrive in order. + /// UnreliableOrdered, - + + /// + /// Reliable channel type. + /// Messages won't be lost but may arrive out-of-order. + /// Reliable, + + /// + /// Reliable-ordered channel type. + /// Messages won't be lost and always arrive in order. + /// ReliableOrdered }; diff --git a/Source/Engine/Networking/NetworkConfig.h b/Source/Engine/Networking/NetworkConfig.h index 2330847a3..2a6db2fc1 100644 --- a/Source/Engine/Networking/NetworkConfig.h +++ b/Source/Engine/Networking/NetworkConfig.h @@ -1,32 +1,51 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Platform/Network.h" -API_ENUM(Namespace="FlaxEngine.Networking") enum class NetworkTransportType +/// +/// Network driver implementations enum. +/// +API_ENUM(Namespace="FlaxEngine.Networking") enum class NetworkDriverType { + /// + /// Invalid network driver implementation. + /// Undefined = 0, - + + /// + /// ENet library based network driver implementation. + /// ENet }; +/// +/// Low-level network configuration structure. Provides settings for the network driver and all internal components. +/// API_STRUCT(Namespace="FlaxEngine.Networking") struct FLAXENGINE_API NetworkConfig { DECLARE_SCRIPTING_TYPE_MINIMAL(NetworkConfig); public: + /// + /// The network driver that will be used to create the peer. + /// To allow two peers to connect, they must use the same host. + /// API_FIELD() NetworkTransportType NetworkDriverType = NetworkTransportType::ENet; // TODO: Expose INetworkDriver as a ref not enum, when C++/C# interfaces are done. public: + /// + /// The upper limit on how many peers can join when we're listening. + /// API_FIELD() uint16 ConnectionsLimit = 32; /// /// Address used to connect to or listen at. - /// Set it to "any" when you want to listen at all available addresses. /// + /// Set it to "any" when you want to listen at all available addresses. /// Only IPv4 is supported. API_FIELD() String Address = String("127.0.0.1"); @@ -37,9 +56,20 @@ public: API_FIELD() uint16 Port = 7777; + /// + /// The size of a message buffer in bytes. + /// Should be lower than the MTU (maximal transmission unit) - typically 1500 bytes. + /// API_FIELD() - uint16 MessageSize = 1500; // MTU + uint16 MessageSize = 1500; + /// + /// The amount of pooled messages that can be used at once (receiving and sending!). + /// + /// + /// Creating more messages than this limit will result in a crash! + /// This should be tweaked manually to fit the needs (adjusting this value will increase/decrease memory usage)! + /// API_FIELD() - uint16 MessagePoolSize = 2048; // (RX and TX) + uint16 MessagePoolSize = 2048; }; diff --git a/Source/Engine/Networking/NetworkConnection.h b/Source/Engine/Networking/NetworkConnection.h index fe6489dd0..a93cb4ac3 100644 --- a/Source/Engine/Networking/NetworkConnection.h +++ b/Source/Engine/Networking/NetworkConnection.h @@ -1,13 +1,20 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Scripting/ScriptingType.h" +/// +/// Network connection structure - used to identify connected peers when we're listening. +/// API_STRUCT(Namespace="FlaxEngine.Networking") struct FLAXENGINE_API NetworkConnection { DECLARE_SCRIPTING_TYPE_MINIMAL(NetworkConnection); public: - API_FIELD(); + /// + /// The identifier of the connection. + /// + /// Used by network driver implementations. + API_FIELD() uint32 ConnectionId; }; diff --git a/Source/Engine/Networking/NetworkEvent.h b/Source/Engine/Networking/NetworkEvent.h index 83caee479..d61bd9ae9 100644 --- a/Source/Engine/Networking/NetworkEvent.h +++ b/Source/Engine/Networking/NetworkEvent.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #pragma once @@ -6,26 +6,60 @@ #include "NetworkMessage.h" #include "Engine/Scripting/ScriptingType.h" +/// +/// Network event type enum contains all possible events that can be returned by PopEvent function. +/// API_ENUM(Namespace="FlaxEngine.Networking") enum class NetworkEventType { + /// + /// Invalid network event type. + /// Undefined = 0, + /// + /// Event "connected" - client connected to our server or we've connected to the server. + /// Connected, + + /// + /// Event "disconnected" - client disconnected from our server or we've been kicked from the server. + /// Disconnected, + + /// + /// Event "disconnected" - client got a timeout from our server or we've list the connection to the server. + /// Timeout, + + /// + /// Event "message" - message received from some client or the server. + /// Message }; +/// +/// Network event structure that wraps all data needed to identify and process it. +/// API_STRUCT(Namespace="FlaxEngine.Networking") struct FLAXENGINE_API NetworkEvent { DECLARE_SCRIPTING_TYPE_MINIMAL(NetworkEvent); public: + /// + /// The type of the received event. + /// API_FIELD(); NetworkEventType EventType; - + + /// + /// The message when this event is an "message" event - not valid in any other cases. + /// API_FIELD(); NetworkMessage Message; + /// + /// The connected of the client that has sent message, connected, disconnected or got a timeout. + /// + /// Only valid when event has been received on server-peer. API_FIELD(); NetworkConnection Sender; }; diff --git a/Source/Engine/Networking/NetworkManager.h b/Source/Engine/Networking/NetworkManager.h index 68ac7494e..114dc4182 100644 --- a/Source/Engine/Networking/NetworkManager.h +++ b/Source/Engine/Networking/NetworkManager.h @@ -1,17 +1,30 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Scripting/ScriptingType.h" #include "Types.h" +/// +/// Low-level network service. Provides network peer management functionality. +/// API_CLASS(Namespace="FlaxEngine.Networking", Static) class FLAXENGINE_API NetworkManager { DECLARE_SCRIPTING_TYPE_NO_SPAWN(NetworkManager); public: - + /// + /// Creates new peer using given configuration. + /// + /// The configuration to create and setup new peer. + /// The peer. + /// Peer should be destroyed using once it is no longer in use. API_FUNCTION() static NetworkPeer* CreatePeer(const NetworkConfig& config); + + /// + /// Shutdowns and destroys given peer. + /// + /// The peer to destroy. API_FUNCTION() static void ShutdownPeer(NetworkPeer* peer); diff --git a/Source/Engine/Networking/NetworkMessage.cpp b/Source/Engine/Networking/NetworkMessage.cpp index bf92b0237..0ec7b5702 100644 --- a/Source/Engine/Networking/NetworkMessage.cpp +++ b/Source/Engine/Networking/NetworkMessage.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #include "NetworkMessage.h" @@ -15,3 +15,8 @@ void NetworkMessage::ReadBytes(uint8* bytes, const int numBytes) Platform::MemoryCopy(bytes, Buffer + Position, numBytes); Position += numBytes; } + +bool NetworkMessage::IsValid() const +{ + return Buffer != nullptr && BufferSize > 0; +} diff --git a/Source/Engine/Networking/NetworkMessage.cs b/Source/Engine/Networking/NetworkMessage.cs index b721ae7fa..42b0fb09e 100644 --- a/Source/Engine/Networking/NetworkMessage.cs +++ b/Source/Engine/Networking/NetworkMessage.cs @@ -12,11 +12,11 @@ namespace FlaxEngine.Networking /// Writes raw bytes into the message. /// /// The bytes that will be written. - /// The amount of bytes to write from the pointer. + /// The amount of bytes to write from the bytes pointer. public void WriteBytes(byte* bytes, int length) { Assert.IsTrue(Position + length <= BufferSize, $"Could not write data of length {length} into message with id={MessageId}! Current write position={Position}"); - Utils.MemoryCopy(new IntPtr(bytes), new IntPtr(Buffer + Position), length); + Utils.MemoryCopy(new IntPtr(bytes), new IntPtr(Buffer + Position), (ulong)length); Position += (uint)length; Length = Position; } @@ -26,13 +26,13 @@ namespace FlaxEngine.Networking /// /// /// The buffer pointer that will be used to store the bytes. - /// Should be of the same length as or longer. + /// Should be of the same length as length or longer. /// - /// The minimal amount of bytes that the contains. + /// The minimal amount of bytes that the buffer contains. public void ReadBytes(byte* buffer, int length) { Assert.IsTrue(Position + length <= Length, $"Could not read data of length {length} from message with id={MessageId} and size of {Length}B! Current read position={Position}"); - Utils.MemoryCopy(new IntPtr(Buffer + Position), new IntPtr(buffer), length); + Utils.MemoryCopy(new IntPtr(Buffer + Position), new IntPtr(buffer), (ulong)length); Position += (uint)length; } @@ -40,7 +40,7 @@ namespace FlaxEngine.Networking /// Writes raw bytes into the message. /// /// The bytes that will be written. - /// The amount of bytes to write from the array. + /// The amount of bytes to write from the bytes array. public void WriteBytes(byte[] bytes, int length) { fixed (byte* bytesPtr = bytes) @@ -54,9 +54,9 @@ namespace FlaxEngine.Networking /// /// /// The buffer that will be used to store the bytes. - /// Should be of the same length as or longer. + /// Should be of the same length as length or longer. /// - /// The minimal amount of bytes that the contains. + /// The minimal amount of bytes that the buffer contains. public void ReadBytes(byte[] buffer, int length) { fixed (byte* bufferPtr = buffer) diff --git a/Source/Engine/Networking/NetworkMessage.h b/Source/Engine/Networking/NetworkMessage.h index 5562b617f..3acdbfa17 100644 --- a/Source/Engine/Networking/NetworkMessage.h +++ b/Source/Engine/Networking/NetworkMessage.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #pragma once @@ -9,28 +9,52 @@ #include "Engine/Core/Types/String.h" #include "Engine/Scripting/ScriptingType.h" +/// +/// Network message structure. Provides raw data writing and reading to the message buffer. +/// API_STRUCT(Namespace="FlaxEngine.Networking") struct FLAXENGINE_API NetworkMessage { DECLARE_SCRIPTING_TYPE_MINIMAL(NetworkMessage); public: + /// + /// The raw message buffer. + /// API_FIELD() uint8* Buffer = nullptr; - + + /// + /// The unique, internal message identifier. + /// API_FIELD() uint32 MessageId = 0; - + + /// + /// The size in bytes of the buffer that this message has. + /// API_FIELD() uint32 BufferSize = 0; - + + /// + /// The length in bytes of this message. + /// API_FIELD() uint32 Length = 0; - + + /// + /// The position in bytes in buffer where the next read/write will occur. + /// API_FIELD() uint32 Position = 0; public: + /// + /// Initializes default values of the structure. + /// NetworkMessage() = default; - + + /// + /// Initializes values of the structure. + /// NetworkMessage(uint8* buffer, uint32 messageId, uint32 bufferSize, uint32 length, uint32 position) : Buffer(buffer), MessageId(messageId), BufferSize(bufferSize), Length(length), Position(position) { } @@ -38,7 +62,21 @@ public: ~NetworkMessage() = default; public: + /// + /// Writes raw bytes into the message. + /// + /// The bytes that will be written. + /// The amount of bytes to write from the bytes pointer. FORCE_INLINE void WriteBytes(uint8* bytes, int numBytes); + + /// + /// Reads raw bytes from the message into the given byte array. + /// + /// + /// The buffer pointer that will be used to store the bytes. + /// Should be of the same length as length or longer. + /// + /// The minimal amount of bytes that the buffer contains. FORCE_INLINE void ReadBytes(uint8* bytes, int numBytes); #define DECL_READWRITE(type, name) \ @@ -59,17 +97,26 @@ public: DECL_READWRITE(bool, Boolean) public: + /// + /// Writes data of type into the message. + /// FORCE_INLINE void WriteVector2(const Vector2& value) { WriteSingle(value.X); WriteSingle(value.Y); } + /// + /// Reads and returns data of type from the message. + /// FORCE_INLINE Vector2 ReadVector2() { return Vector2(ReadSingle(), ReadSingle()); } + /// + /// Writes data of type into the message. + /// FORCE_INLINE void WriteVector3(const Vector3& value) { WriteSingle(value.X); @@ -77,11 +124,17 @@ public: WriteSingle(value.Z); } + /// + /// Reads and returns data of type from the message. + /// FORCE_INLINE Vector3 ReadVector3() { return Vector3(ReadSingle(), ReadSingle(), ReadSingle()); } - + + /// + /// Writes data of type into the message. + /// FORCE_INLINE void WriteVector4(const Vector4& value) { WriteSingle(value.X); @@ -90,11 +143,17 @@ public: WriteSingle(value.W); } + /// + /// Reads and returns data of type from the message. + /// FORCE_INLINE Vector4 ReadVector4() { return Vector4(ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle()); } + /// + /// Writes data of type into the message. + /// FORCE_INLINE void WriteQuaternion(const Quaternion& value) { WriteSingle(value.X); @@ -103,6 +162,9 @@ public: WriteSingle(value.W); } + /// + /// Reads and returns data of type from the message. + /// FORCE_INLINE Quaternion ReadQuaternion() { return Quaternion(ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle()); @@ -125,8 +187,8 @@ public: } public: - bool IsValid() const - { - return Buffer != nullptr && BufferSize > 0; - } + /// + /// Returns true if the message is valid for reading or writing. + /// + bool IsValid() const; }; diff --git a/Source/Engine/Networking/NetworkPeer.cpp b/Source/Engine/Networking/NetworkPeer.cpp index e8a5935ef..461fd64c6 100644 --- a/Source/Engine/Networking/NetworkPeer.cpp +++ b/Source/Engine/Networking/NetworkPeer.cpp @@ -1,9 +1,8 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #include "NetworkPeer.h" #include "NetworkEvent.h" - #include "Drivers/ENetDriver.h" #include "Engine/Core/Log.h" diff --git a/Source/Engine/Networking/NetworkPeer.h b/Source/Engine/Networking/NetworkPeer.h index fee6fc251..d66aaf5a1 100644 --- a/Source/Engine/Networking/NetworkPeer.h +++ b/Source/Engine/Networking/NetworkPeer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #pragma once @@ -9,7 +9,10 @@ #include "Engine/Core/Collections/Array.h" -API_CLASS(sealed, NoSpawn, Namespace="FlaxEngine.Networking") class FLAXENGINE_API NetworkPeer final : public PersistentScriptingObject +/// +/// Low-level network peer class. Provides server-client communication functions, message processing and sending. +/// +API_CLASS(sealed, NoSpawn, Namespace = "FlaxEngine.Networking") class FLAXENGINE_API NetworkPeer final : public PersistentScriptingObject { DECLARE_SCRIPTING_TYPE_NO_SPAWN(NetworkHost); friend class NetworkManager; @@ -22,6 +25,9 @@ public: Array MessagePool; public: + /// + /// Initializes a new instance of the class. + /// NetworkPeer() : PersistentScriptingObject(SpawnParams(Guid::New(), TypeInitializer)) { } @@ -35,39 +41,112 @@ private: void DisposeMessageBuffers(); public: + /// + /// Starts listening for incoming connections. + /// Once this is called, this peer becomes a server. + /// + /// True when succeeded. API_FUNCTION() bool Listen(); - + + /// + /// Starts connection handshake with the end point specified in the structure. + /// Once this is called, this peer becomes a client. + /// + /// True when succeeded. API_FUNCTION() bool Connect(); - + + /// + /// Disconnects from the server. + /// + /// Can be used only by the client! API_FUNCTION() void Disconnect(); - + + /// + /// Disconnects given connection from the server. + /// + /// Can be used only by the server! API_FUNCTION() void Disconnect(const NetworkConnection& connection); - + + /// + /// Tries to pop an network event from the queue. + /// + /// The reference to event structure. + /// True when succeeded and the event can be processed. API_FUNCTION() bool PopEvent(API_PARAM(out) NetworkEvent& eventRef); + /// + /// Acquires new message from the pool. + /// Cannot acquire more messages than the limit specified in the structure. + /// + /// The acquired message. + /// Make sure to recycle the message to this peer once it is no longer needed! API_FUNCTION() NetworkMessage CreateMessage(); - + + /// + /// Returns given message to the pool. + /// + /// Make sure that this message belongs to the peer and has not been recycled already (debug build checks for this)! API_FUNCTION() void RecycleMessage(const NetworkMessage& message); + /// + /// Acquires new message from the pool and setups it for sending. + /// + /// The acquired message. API_FUNCTION() NetworkMessage BeginSendMessage(); - + + /// + /// Aborts given message send. This effectively deinitializes the message and returns it to the pool. + /// + /// The message. API_FUNCTION() void AbortSendMessage(const NetworkMessage& message); - + + /// + /// Sends given message over specified channel to the server. + /// + /// The channel to send the message over. + /// The message. + /// Can be used only by the client! + /// + /// Do not recycle the message after calling this. + /// This function automatically recycles the message. + /// API_FUNCTION() bool EndSendMessage(NetworkChannelType channelType, const NetworkMessage& message); - + + /// + /// Sends given message over specified channel to the given client connection (target). + /// + /// The channel to send the message over. + /// The message. + /// The client connection to send the message to. + /// Can be used only by the server! + /// + /// Do not recycle the message after calling this. + /// This function automatically recycles the message. + /// API_FUNCTION() bool EndSendMessage(NetworkChannelType channelType, const NetworkMessage& message, const NetworkConnection& target); - + + /// + /// Sends given message over specified channel to the given client connection (target). + /// + /// The channel to send the message over. + /// The message. + /// The connections list to send the message to. + /// Can be used only by the server! + /// + /// Do not recycle the message after calling this. + /// This function automatically recycles the message. + /// API_FUNCTION() bool EndSendMessage(NetworkChannelType channelType, const NetworkMessage& message, Array targets);