diff --git a/Source/Engine/Networking/INetworkDriver.h b/Source/Engine/Networking/INetworkDriver.h new file mode 100644 index 000000000..c40bb15d5 --- /dev/null +++ b/Source/Engine/Networking/INetworkDriver.h @@ -0,0 +1,13 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +API_INTERFACE() class FLAXENGINE_API INetworkDriver +{ +public: + virtual void Initialize(const NetworkConfig& config) = 0; + virtual void Dispose() = 0; + + virtual void Listen() = 0; + virtual void SendMessage(const NetworkMessage* message, void* targets) = 0; // TODO +}; diff --git a/Source/Engine/Networking/NetworkChannelType.h b/Source/Engine/Networking/NetworkChannelType.h new file mode 100644 index 000000000..57ace04ab --- /dev/null +++ b/Source/Engine/Networking/NetworkChannelType.h @@ -0,0 +1,18 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Scripting/ScriptingType.h" + +API_ENUM() enum class NetworkChannelType +{ + None = 0, + + Unreliable, + UnreliableOrdered, + UnreliableFragmented, + + Reliable, + ReliableOrdered, + ReliableFragmented +}; diff --git a/Source/Engine/Networking/NetworkConfig.h b/Source/Engine/Networking/NetworkConfig.h new file mode 100644 index 000000000..b0fa3c5ae --- /dev/null +++ b/Source/Engine/Networking/NetworkConfig.h @@ -0,0 +1,15 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +API_STRUCT() struct FLAXENGINE_API NetworkConfig +{ +public: + INetworkDriver* NetworkDriver = nullptr; + +public: + uint16 ConnectionsLimit = 32; + uint16 Port = 7777; + uint16 MessageSize = 1500; // MTU + uint16 MessagePoolSize = 2048; // (RX and TX) +}; diff --git a/Source/Engine/Networking/NetworkConnection.cpp b/Source/Engine/Networking/NetworkConnection.cpp new file mode 100644 index 000000000..dab6ffd3f --- /dev/null +++ b/Source/Engine/Networking/NetworkConnection.cpp @@ -0,0 +1,4 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#include "NetworkConnection.h" + diff --git a/Source/Engine/Networking/NetworkConnection.h b/Source/Engine/Networking/NetworkConnection.h new file mode 100644 index 000000000..8feac0914 --- /dev/null +++ b/Source/Engine/Networking/NetworkConnection.h @@ -0,0 +1,11 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Scripting/ScriptingType.h" + +API_STRUCT() struct FLAXENGINE_API NetworkConnection +{ +public: + uint32 ConnectionId; +}; diff --git a/Source/Engine/Networking/NetworkEvent.h b/Source/Engine/Networking/NetworkEvent.h new file mode 100644 index 000000000..cd3debba8 --- /dev/null +++ b/Source/Engine/Networking/NetworkEvent.h @@ -0,0 +1,25 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Scripting/ScriptingType.h" + +API_ENUM() enum class NetworkEventType +{ + Undefined = 0, + + ConnectionRequest, + Connected, + Disconnected, + Message, + Error +}; + +API_STRUCT() struct FLAXENGINE_API NetworkEvent +{ +public: + API_FIELD(); + NetworkEventType EventType; + + // TODO +}; diff --git a/Source/Engine/Networking/NetworkManager.cpp b/Source/Engine/Networking/NetworkManager.cpp new file mode 100644 index 000000000..6a18bf749 --- /dev/null +++ b/Source/Engine/Networking/NetworkManager.cpp @@ -0,0 +1,135 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#include "NetworkManager.h" + +#include "NetworkMessage.h" +#include "NetworkConfig.h" +#include "INetworkDriver.h" + +#include "Engine/Core/Core.h" +#include "Engine/Core/Collections/Array.h" +#include "Engine/Core/Math/Math.h" +#include "Engine/Platform/CPUInfo.h" + +namespace +{ + NetworkConfig Config; + INetworkDriver* NetworkDriver = nullptr; + + uint8* MessageBuffer = nullptr; + Array MessagePool; +} + +bool NetworkManager::Initialize(const NetworkConfig& config) +{ + Config = config; + + ASSERT(NetworkDriver == nullptr); + ASSERT(Config.NetworkDriver); + ASSERT(Config.ConnectionsLimit > 0); + ASSERT(Config.MessageSize > 32); // TODO: Adjust this, not sure what the lowest limit should be. + ASSERT(Config.MessagePoolSize > 128); + + // Setup messages + CreateMessageBuffers(); + MessagePool.Clear(); + MessagePool.Resize(Config.MessagePoolSize); + + // Warmup message pool + for(uint32 messageId = Config.MessagePoolSize; messageId > 0; messageId --) + MessagePool.Push(messageId); + + // Setup network driver + NetworkDriver = Config.NetworkDriver; + NetworkDriver->Initialize(Config); + + return false; +} + +void NetworkManager::Shutdown() +{ + SAFE_DISPOSE(NetworkDriver); + DisposeMessageBuffers(); +} + +bool NetworkManager::Listen() +{ + // TODO + return false; +} + +void NetworkManager::Connect() +{ + // TODO +} + +void NetworkManager::Disconnect() +{ + // TODO +} + +NetworkMessage NetworkManager::BeginSendMessage() +{ + return CreateMessage(); +} + +void NetworkManager::AbortSendMessage(const NetworkMessage& message) +{ + ASSERT(message.IsValid()); + RecycleMessage(message); +} + +bool NetworkManager::EndSendMessage(NetworkChannelType channelType, const NetworkMessage& message, Array targets) +{ + ASSERT(message.IsValid()); + + // TODO: Send message + + RecycleMessage(message); + return false; +} + +NetworkMessage NetworkManager::CreateMessage() +{ + ASSERT(MessagePool.Count() > 0); + + const uint32 messageId = MessagePool.Pop(); + uint8* messageBuffer = GetMessageBuffer(messageId); + + return NetworkMessage { messageBuffer, Config.MessageSize, 0, 0 }; +} + +void NetworkManager::RecycleMessage(const NetworkMessage& message) +{ + ASSERT(message.IsValid()); +} + +void NetworkManager::CreateMessageBuffers() +{ + ASSERT(MessageBuffer == nullptr); + + const uint32 pageSize = Platform::GetCPUInfo().PageSize; + + // Calculate total size in bytes + const uint64 totalSize = static_cast(Config.MessagePoolSize) * Config.MessageSize; + + // Calculate the amount of pages that we need + const uint32 numPages = totalSize > pageSize ? Math::CeilToInt(totalSize / static_cast(pageSize)) : 1; + + MessageBuffer = static_cast(Platform::AllocatePages(numPages, pageSize)); + Platform::MemorySet(MessageBuffer, 0, numPages * pageSize); +} + +void NetworkManager::DisposeMessageBuffers() +{ + ASSERT(MessageBuffer != nullptr); + + Platform::FreePages(MessageBuffer); + MessageBuffer = nullptr; +} + +uint8* NetworkManager::GetMessageBuffer(const uint32 messageId) +{ + // Calculate and return the buffer slice using previously calculated slice. + return MessageBuffer + Config.MessageSize * messageId; +} diff --git a/Source/Engine/Networking/NetworkManager.h b/Source/Engine/Networking/NetworkManager.h new file mode 100644 index 000000000..fec6610ef --- /dev/null +++ b/Source/Engine/Networking/NetworkManager.h @@ -0,0 +1,34 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Scripting/ScriptingType.h" +#include "Types.h" + +API_CLASS(Static) class FLAXENGINE_API NetworkManager +{ +DECLARE_SCRIPTING_TYPE_NO_SPAWN(NetworkManager); +public: + + API_FUNCTION() static bool Initialize(const NetworkConfig& config); + API_FUNCTION() static void Shutdown(); + + API_FUNCTION() static bool Listen(); + API_FUNCTION() static void Connect(); + API_FUNCTION() static void Disconnect(); + + API_FUNCTION() static bool PopEvent(NetworkEvent* event); + + API_FUNCTION() static NetworkMessage BeginSendMessage(); + API_FUNCTION() static void AbortSendMessage(const NetworkMessage& message); + API_FUNCTION() static bool EndSendMessage(NetworkChannelType channelType, const NetworkMessage& message, Array targets); + +private: + + static NetworkMessage CreateMessage(); + static void RecycleMessage(const NetworkMessage& message); + + static void CreateMessageBuffers(); + static void DisposeMessageBuffers(); + static uint8* GetMessageBuffer(uint32 messageId); +}; diff --git a/Source/Engine/Networking/NetworkMessage.cpp b/Source/Engine/Networking/NetworkMessage.cpp new file mode 100644 index 000000000..19bfbbfda --- /dev/null +++ b/Source/Engine/Networking/NetworkMessage.cpp @@ -0,0 +1,29 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#include "NetworkMessage.h" + +void NetworkMessage::WriteBytes(uint8* bytes, const int numBytes) +{ + ASSERT(Position + numBytes < BufferSize); + Platform::MemoryCopy(Buffer + Position, bytes, numBytes); + Position += numBytes; +} + +void NetworkMessage::ReadBytes(uint8* bytes, const int numBytes) +{ + ASSERT(Position + numBytes < BufferSize); + Platform::MemoryCopy(bytes, Buffer + Position, numBytes); + Position += numBytes; +} + +void NetworkMessage::WriteUInt32(uint32 value) +{ + WriteBytes(reinterpret_cast(&value), sizeof(uint32)); +} + +uint32 NetworkMessage::ReadUInt32() +{ + uint32 value = 0; + ReadBytes(reinterpret_cast(&value), sizeof(uint32)); + return value; +} diff --git a/Source/Engine/Networking/NetworkMessage.h b/Source/Engine/Networking/NetworkMessage.h new file mode 100644 index 000000000..cd55e9cbe --- /dev/null +++ b/Source/Engine/Networking/NetworkMessage.h @@ -0,0 +1,35 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Scripting/ScriptingType.h" + +API_STRUCT() struct FLAXENGINE_API NetworkMessage +{ +public: + API_FIELD() + uint8* Buffer; + + API_FIELD() + uint32 BufferSize; + + API_FIELD() + uint32 Length; + + API_FIELD() + uint32 Position; + +public: + API_FUNCTION() void WriteBytes(uint8* bytes, int numBytes); + API_FUNCTION() void ReadBytes(uint8* bytes, int numBytes); + +public: + API_FUNCTION() void WriteUInt32(uint32 value); // TODO: Macro the shit out of this + API_FUNCTION() uint32 ReadUInt32(); + +public: + API_FUNCTION() bool IsValid() const + { + return Buffer != nullptr && BufferSize > 0; + } +}; diff --git a/Source/Engine/Networking/Types.h b/Source/Engine/Networking/Types.h new file mode 100644 index 000000000..ad4922868 --- /dev/null +++ b/Source/Engine/Networking/Types.h @@ -0,0 +1,12 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +enum class NetworkChannelType; + +class INetworkDriver; + +struct NetworkEvent; +struct NetworkConnection; +struct NetworkMessage; +struct NetworkConfig;