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
|
#pragma once
#if defined(WITH_MULTIPLAYER) || defined(DOXYGEN_GENERATING_OUTPUT)
#include "MpGameMode.h"
#include "../PreferencesCache.h"
#include "../../nCine/Base/TimeStamp.h"
#include "../../nCine/Threading/Thread.h"
// <mmeapi.h> included by "enet.h" still uses `far` macro
#define far
#define ENET_FEATURE_ADDRESS_MAPPING
//#if defined(DEATH_DEBUG)
# define ENET_DEBUG
//#endif
#include "Backends/enet.h"
// Undefine it again after include
#undef far
#include <Base/TypeInfo.h>
#include <Containers/String.h>
#include <Containers/StringView.h>
using namespace Death::Containers;
using namespace nCine;
namespace Jazz2::Multiplayer
{
class NetworkManager;
/** @brief Server description */
struct ServerDescription
{
/** @brief Server endpoint in text format */
String EndpointString;
/** @brief Server unique identifier */
Uuid UniqueServerID;
/** @brief Server version */
String Version;
/** @brief Server name */
String Name;
/** @brief Multiplayer game mode */
MpGameMode GameMode;
/** @brief Server flags */
std::uint32_t Flags;
/** @brief Current number of players */
std::uint32_t CurrentPlayerCount;
/** @brief Maximum number of players */
std::uint32_t MaxPlayerCount;
/** @brief Current level name */
String LevelName;
/** @brief Whether the server is compatible with the local client */
bool IsCompatible;
// TODO: LastPingTime
//bool IsLost;
};
/**
@brief Interface to observe publicly-listed running servers
@experimental
*/
class IServerObserver
{
public:
/** @brief Called when a server is discovered */
virtual void OnServerFound(ServerDescription&& desc) = 0;
};
/**
@brief Interface to provide current status of the server
@experimental
*/
class IServerStatusProvider
{
DEATH_RUNTIME_OBJECT();
public:
/** @brief Returns display name of current level */
virtual StringView GetLevelDisplayName() const = 0;
};
/**
@brief Allows to monitor publicly-listed running servers for server listing
@experimental
*/
class ServerDiscovery
{
public:
/** @{ @name Constants */
/** @brief UDP port for server discovery broadcast */
static constexpr std::uint16_t DiscoveryPort = 7439;
/** @brief Length of server unique identifier */
static constexpr std::int32_t UniqueIdentifierLength = 16;
/** @} */
/** @brief Creates an instance to advertise a running local server */
ServerDiscovery(NetworkManager* server);
/** @brief Creates an instance to observe remote servers */
ServerDiscovery(IServerObserver* observer);
~ServerDiscovery();
/** @brief Sets status provider */
void SetStatusProvider(std::weak_ptr<IServerStatusProvider> statusProvider);
private:
ServerDiscovery(const ServerDiscovery&) = delete;
ServerDiscovery& operator=(const ServerDiscovery&) = delete;
static constexpr std::uint64_t PacketSignature = 0x2095A59FF0BFBBEF;
NetworkManager* _server;
IServerObserver* _observer;
std::weak_ptr<IServerStatusProvider> _statusProvider;
ENetSocket _socket;
Thread _thread;
TimeStamp _lastLocalRequestTime;
TimeStamp _lastOnlineRequestTime;
ENetAddress _localMulticastAddress;
bool _onlineSuccess;
static ENetSocket TryCreateLocalSocket(const char* multicastAddress, ENetAddress& parsedAddress);
void SendLocalDiscoveryRequest(ENetSocket socket, const ENetAddress& address);
void DownloadPublicServerList(IServerObserver* observer);
bool ProcessLocalDiscoveryResponses(ENetSocket socket, ServerDescription& discoveredServer, std::int32_t timeoutMs = 0);
bool ProcessLocalDiscoveryRequests(ENetSocket socket, std::int32_t timeoutMs = 0);
void SendLocalDiscoveryResponse(ENetSocket socket, NetworkManager* server);
void PublishToPublicServerList(NetworkManager* server);
void DelistFromPublicServerList(NetworkManager* server);
static void OnClientThread(void* param);
static void OnServerThread(void* param);
};
}
#endif
|