1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
#pragma once
#if defined(WITH_MULTIPLAYER) || defined(DOXYGEN_GENERATING_OUTPUT)
#include "ConnectionResult.h"
#include "Peer.h"
#include "Reason.h"
#include "ServerDiscovery.h"
#include "../../nCine/Threading/Thread.h"
#include "../../nCine/Threading/ThreadSync.h"
#include <Base/IDisposable.h>
#include <Containers/Function.h>
#include <Containers/SmallVector.h>
#include <Containers/StringView.h>
#include <IO/MemoryStream.h>
#include <Threading/Spinlock.h>
struct _ENetHost;
using namespace Death::Containers;
using namespace Death::IO;
using namespace Death::Threading;
using namespace nCine;
namespace Jazz2::Multiplayer
{
class INetworkHandler;
/** @brief Network packet channel */
enum class NetworkChannel : std::uint8_t
{
Main, /**< Main */
UnreliableUpdates, /**< Unreliable updates */
Count /**< Count of supported channels */
};
/** @brief State of network connection */
enum class NetworkState
{
None, /**< Disconnected */
Listening, /**< Listening as server */
Connecting, /**< Connecting to server as client */
Connected /**< Connected to server as client */
};
/**
@brief All connected peers tag type
*/
struct AllPeersT {
#ifndef DOXYGEN_GENERATING_OUTPUT
struct Init {};
// Explicit constructor to avoid ambiguous calls when using {}
constexpr explicit AllPeersT(Init) {}
#endif
};
/**
@brief Local peer tag type
*/
struct LocalPeerT {
#ifndef DOXYGEN_GENERATING_OUTPUT
struct Init {};
// Explicit constructor to avoid ambiguous calls when using {}
constexpr explicit LocalPeerT(Init) {}
#endif
};
/**
@brief All connected peers tag
Use in @ref NetworkManagerBase::SendTo() to send to all connected peers or the remote server peer.
*/
constexpr AllPeersT AllPeers{AllPeersT::Init{}};
/**
@brief Local peer tag
*/
constexpr LocalPeerT LocalPeer{LocalPeerT::Init{}};
/**
@brief Allows to create generic network clients and servers
*/
class NetworkManagerBase : public Death::IDisposable
{
friend class ServerDiscovery;
public:
/** @{ @name Constants */
/** @brief Maximum connected peer count */
static constexpr std::uint32_t MaxPeerCount = 128;
/** @} */
NetworkManagerBase();
~NetworkManagerBase();
NetworkManagerBase(const NetworkManagerBase&) = delete;
NetworkManagerBase& operator=(const NetworkManagerBase&) = delete;
/** @brief Creates a client connection to a remote server */
virtual void CreateClient(INetworkHandler* handler, StringView endpoints, std::uint16_t defaultPort, std::uint32_t clientData);
/** @brief Creates a server that accepts incoming connections */
virtual bool CreateServer(INetworkHandler* handler, std::uint16_t port);
/** @brief Disposes all active connections */
virtual void Dispose();
/** @brief Returns state of network connection */
NetworkState GetState() const;
/** @brief Returns mean round trip time to the server, in milliseconds */
std::uint32_t GetRoundTripTimeMs() const;
/** @brief Returns all IPv4 and IPv6 addresses along with ports of the server */
Array<String> GetServerEndpoints() const;
/** @brief Returns port of the server */
std::uint16_t GetServerPort() const;
/** @brief Sends a packet to a given peer */
void SendTo(const Peer& peer, NetworkChannel channel, std::uint8_t packetType, ArrayView<const std::uint8_t> data);
/** @brief Sends a packet to all connected peers that match a given predicate */
void SendTo(Function<bool(const Peer&)>&& predicate, NetworkChannel channel, std::uint8_t packetType, ArrayView<const std::uint8_t> data);
/** @brief Sends a packet to all connected peers or the remote server peer */
void SendTo(AllPeersT, NetworkChannel channel, std::uint8_t packetType, ArrayView<const std::uint8_t> data);
/** @brief Kicks a given peer from the server */
void Kick(const Peer& peer, Reason reason);
/** @brief Converts the specified IPv4 endpoint to the string representation */
static String AddressToString(const struct in_addr& address, std::uint16_t port = 0);
#if ENET_IPV6
/** @brief Converts the specified IPv6 endpoint to the string representation */
static String AddressToString(const struct in6_addr& address, std::uint16_t scopeId, std::uint16_t port = 0);
#endif
/** @brief Converts the specified ENet address to the string representation */
static String AddressToString(const ENetAddress& address, bool includePort = false);
/** @brief Converts the endpoint of the specified peer to the string representation */
static String AddressToString(const Peer& peer);
/** @brief Returns `true` if the specified string representation of the address is valid */
static bool IsAddressValid(StringView address);
/** @brief Returns `true` if the specified string representation of the domain name is valid */
static bool IsDomainValid(StringView domain);
/** @brief Attempts to split the specified endpoint into address and port */
static bool TrySplitAddressAndPort(StringView input, StringView& address, std::uint16_t& port);
/** @brief Converts the specified reason to the string representation */
static const char* ReasonToString(Reason reason);
protected:
/** @brief Called when a peer connects to the local server or the local client connects to a server */
virtual ConnectionResult OnPeerConnected(const Peer& peer, std::uint32_t clientData);
/** @brief Called when a peer disconnects from the local server or the local client disconnects from a server */
virtual void OnPeerDisconnected(const Peer& peer, Reason reason);
private:
static constexpr std::uint32_t ProcessingIntervalMs = 4;
_ENetHost* _host;
Thread _thread;
NetworkState _state;
std::uint32_t _clientData;
SmallVector<_ENetPeer*, 1> _peers;
INetworkHandler* _handler;
SmallVector<ENetAddress, 0> _desiredEndpoints;
Spinlock _lock;
static void InitializeBackend();
static void ReleaseBackend();
static void OnClientThread(void* param);
static void OnServerThread(void* param);
};
}
#endif
|