1
0
Fork 0
Univerxel/src/core/net/Server.hpp

163 lines
6.2 KiB
C++

#pragma once
#include "data.hpp"
#include "PacketView.hpp"
namespace net {
class Server {
public:
Server(const connection& ct, int connections) {
if(connections > 0) {
auto addr = [&] {
if (auto addr = ct.toAddress())
return addr.value();
FATAL("Invalid ip address format");
}();
host = enet_host_create(&addr, connections, CHANNEL_COUNT, 0, 0);
if(host == nullptr) {
FATAL("Network server creation failed");
}
LOG_I("Listening on " << ct);
} else {
host = nullptr;
LOG_D("Local only server");
}
}
~Server() {
enet_host_destroy(host);
}
template<typename C, typename D, typename R>
void pull(C onConnect, D onDisconnect, R onData, int delay = 10, int count = 10) {
if (host == nullptr)
return;
ENetEvent event;
for(int i = 0; i < count && enet_host_service(host, &event, delay) > 0; i++) {
switch(event.type) {
case ENET_EVENT_TYPE_CONNECT:
onConnect(event.peer, event.data);
break;
case ENET_EVENT_TYPE_DISCONNECT:
onDisconnect(event.peer, (disconnect_reason)event.data);
break;
case ENET_EVENT_TYPE_RECEIVE: {
onData(event.peer, event.packet, (channel_type)event.channelID);
enet_packet_destroy(event.packet);
break;
}
case ENET_EVENT_TYPE_NONE:
break;
}
}
#if TRACY_ENABLE
TracyPlot("SrvNetUpData", (int64_t)host->totalSentData);
host->totalSentData = 0;
TracyPlot("SrvNetUpPackets", (int64_t)host->totalSentPackets);
host->totalSentPackets = 0;
TracyPlot("SrvNetDownData", (int64_t)host->totalReceivedData);
host->totalReceivedData = 0;
TracyPlot("SrvNetDownPackets", (int64_t)host->totalReceivedPackets);
host->totalReceivedPackets = 0;
int64_t throttling = 0;
int64_t peerCount = 0;
iterPeers([&](peer_t *peer) {
throttling += ENET_PEER_PACKET_THROTTLE_SCALE - peer->packetThrottle;
peerCount++;
});
TracyPlot("SrvPeersCount", peerCount);
TracyPlot("SrvPeersThrottling", peerCount > 0 ? throttling * 100 / ENET_PEER_PACKET_THROTTLE_SCALE / peerCount : 0);
#endif
}
void disconnect(peer_t *peer, disconnect_reason reason) const {
enet_peer_disconnect(peer, (enet_uint32)reason);
}
template<typename D>
static D* GetPeerData(peer_t* peer) { return (D*)peer->data; }
template<typename Call>
void iterPeers(Call call) {
for (auto currentPeer = host->peers;
currentPeer < &host->peers[host->peerCount];
++currentPeer)
{
if (currentPeer->state == ENET_PEER_STATE_CONNECTED)
call(currentPeer);
}
}
/// Send to single peer
/// Expect salt_t at peer->data
bool sendTo(peer_t* peer, server_packet_type type, const void *data, size_t size, channel_type channel, std::optional<enet_uint32> flags = {}) {
const auto salt = GetPeerData<salt_t>(peer);
if(salt == NULL) {
LOG_W("Contacting " << peer->address << " before handshake");
return false;
}
return send(peer, makePacket(type, data, size, flags.value_or(channel == channel_type::RELIABLE ? ENET_PACKET_FLAG_RELIABLE : 0), *salt).get(), channel);
}
template<typename D>
bool sendTo(peer_t* peer, server_packet_type type, const D& data, channel_type channel, std::optional<enet_uint32> flags = {}) {
static_assert(!std::is_pointer<D>::value);
return sendTo(peer, type, &data, sizeof(data), channel, flags);
}
/// Send unsalt to single peer
bool send(peer_t* peer, packet_t* packet, channel_type channel) {
return enet_peer_send(peer, (enet_uint8)channel, packet) == 0;
}
bool send(peer_t* peer, server_packet_type type, const void *data, size_t size, channel_type channel, std::optional<enet_uint32> flags = {}) {
return send(peer, makePacket(type, data, size, flags.value_or(channel == channel_type::RELIABLE ? ENET_PACKET_FLAG_RELIABLE : 0)).get(), channel);
}
template<typename D>
bool send(peer_t* peer, server_packet_type type, const D& data, channel_type channel, std::optional<enet_uint32> flags = {}) {
static_assert(!std::is_pointer<D>::value);
return send(peer, type, &data, sizeof(data), channel, flags);
}
/// Send to all connected peers
void broadcast(packet_t* packet, channel_type channel) {
if (host != nullptr)
enet_host_broadcast(host, (enet_uint8)channel, packet);
}
void broadcast(server_packet_type type, const void *data, size_t size, channel_type channel, std::optional<enet_uint32> flags = {}) {
broadcast(makePacket(type, data, size, flags.value_or(channel == channel_type::RELIABLE ? ENET_PACKET_FLAG_RELIABLE : 0)).get(), channel);
}
template<typename D>
void broadcast(server_packet_type type, const D& data, channel_type channel, std::optional<enet_uint32> flags = {}) {
static_assert(!std::is_pointer<D>::value);
broadcast(type, &data, sizeof(data), channel, flags);
}
static PacketWriter makePacket(server_packet_type type, const void* data, size_t size, enet_uint32 flags) {
assert(type >= server_packet_type::BROADCASTED);
auto packet = PacketWriter(sizeof(server_packet_type) + size, flags);
packet.write(type);
if (data != nullptr)
packet.write(data, size);
return packet;
}
static PacketWriter makePacket(server_packet_type type, const void* data, size_t size, enet_uint32 flags, salt_t salt) {
assert(type < server_packet_type::BROADCASTED);
auto packet = PacketWriter(sizeof(server_packet_type) + sizeof(salt_t) + size, flags);
packet.write(type);
packet.write(salt);
if (data != nullptr)
packet.write(data, size);
return packet;
}
private:
ENetHost *host;
};
}