#ifndef SERVER_H #define SERVER_H #include "network/ENet.h" #include "network/Packet.h" #include "utils/HashMap.h" #include "utils/StringBuffer.h" #include "utils/Types.h" struct Server final { typedef enet_uint16 Port; typedef StringBuffer<256> Error; class Client final { ENetPeer* peer; int id; friend HashMap; Client(ENetPeer* peer, int id); Client(const Client&) = delete; Client(Client&& other); Client& operator=(const Client&) = delete; Client& operator=(Client&& other); public: ~Client(); int getId() const; }; private: ENetHost* server; Error error; HashMap clients; int idCounter; public: Server(Port port, int maxClients); Server(const Server&) = delete; Server(Server&&) = delete; ~Server(); Server& operator=(const Server&) = delete; Server& operator=(Server&&) = delete; bool hasError() const; const Error& getError() const; template void consumeEvents(T& consumer) { ENetEvent e; while(!hasError() && enet_host_service(server, &e, 0) > 0) { switch(e.type) { case ENET_EVENT_TYPE_CONNECT: onConnect(e, consumer); break; case ENET_EVENT_TYPE_RECEIVE: onPackage(e, consumer); enet_packet_destroy(e.packet); break; case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: case ENET_EVENT_TYPE_DISCONNECT: onDisconnect(e, consumer); break; case ENET_EVENT_TYPE_NONE: return; } } } private: template void onConnect(ENetEvent& e, T& consumer) { int id = idCounter++; if(clients.tryEmplace(id, e.peer, id)) { error.clear().append("id is connected twice"); return; } static_assert(sizeof(e.peer->data) >= sizeof(id), "private data not big enough for id"); memcpy(&(e.peer->data), &id, sizeof(id)); Client* client = clients.search(id); if(client != nullptr) { consumer.onConnection(*client); } else { error.clear().append("cannot find added client"); } } template void onPackage(ENetEvent& e, T& consumer) { if(e.peer->data == nullptr) { error.clear().append("client without data sent package"); return; } int id = -1; memcpy(&id, &(e.peer->data), sizeof(id)); Client* client = clients.search(id); if(client != nullptr) { InPacket in(e.packet); consumer.onPackage(*client, in); } else { error.clear().append("client with invalid id sent package"); } } template void onDisconnect(ENetEvent& e, T& consumer) { if(e.peer->data == nullptr) { error.clear().append("client without data disconnected"); return; } int id = -1; memcpy(&id, &(e.peer->data), sizeof(id)); Client* client = clients.search(id); if(client != nullptr) { consumer.onDisconnect(*client); clients.remove(id); } else { error.clear().append("client has invalid id"); } } }; #endif