#include "core/Network.h" #define ENET_IMPLEMENTATION #include #include typedef CoreOutPacket OutPacket; void coreInitInPacket(CoreInPacket* in, const void* data, size_t n) { in->data = data; in->size = n; in->index = 0; } bool coreInPacketReadU8(CoreInPacket* in, u8* u) { return coreInPacketRead(in, u, sizeof(*u)); } bool coreInPacketReadU16(CoreInPacket* in, u16* u) { if(coreInPacketRead(in, u, sizeof(*u))) { return true; } *u = ntohs(*u); return false; } bool coreInPacketReadU32(CoreInPacket* in, u32* u) { if(coreInPacketRead(in, u, sizeof(*u))) { return true; } *u = ntohl(*u); return false; } bool coreInPacketReadI8(CoreInPacket* in, i8* i) { u8 u; if(coreInPacketReadU8(in, &u)) { return true; } *i = (i8)((i32)u - (i32)128); return false; } bool coreInPacketReadI16(CoreInPacket* in, i16* i) { u16 u; if(coreInPacketReadU16(in, &u)) { return true; } *i = (i16)((i32)u - (i32)32768); return false; } bool coreInPacketReadI32(CoreInPacket* in, i32* i) { u32 u; if(coreInPacketReadU32(in, &u)) { return true; } if(u < 2147483648) { *i = (i32)((i32)u - (i32)2147483648); } else { *i = (i32)(u - (u32)2147483648); } return false; } bool coreInPacketReadFloat(CoreInPacket* in, float* f) { u32 u; static_assert(sizeof(u) == sizeof(*f), "float and u32 size do not match"); if(coreInPacketReadU32(in, &u)) { return true; } memcpy(f, &u, sizeof(float)); return false; } size_t coreInPacketReadString(CoreInPacket* in, char* buffer, size_t n) { if(n == 0) { return 0; } u16 size; if(coreInPacketReadU16(in, &size)) { return 0; } size_t end = size; char* bufferStart = buffer; n--; while(n-- > 0 && end-- > 0) { u8 u; if(coreInPacketReadU8(in, &u)) { *bufferStart = '\0'; break; } *(buffer++) = (char)u; } while(end-- > 0 && !coreInPacketReadU8(in, &(u8){0})) {} *buffer = '\0'; return size; } bool coreInPacketRead(CoreInPacket* in, void* buffer, size_t n) { if(in->index + n > in->size) { return true; } memcpy(buffer, in->data + in->index, n); in->index += n; return false; } void coreInitOutPacket(OutPacket* out) { coreInitBuffer(&out->data); } void coreDestroyOutPacket(OutPacket* out) { coreDestroyBuffer(&out->data); } OutPacket* coreOutPacketWriteU8(OutPacket* out, u8 u) { coreAddSizedBufferData(&out->data, &u, sizeof(u)); return out; } OutPacket* coreOutPacketWriteU16(OutPacket* out, u16 u) { u = htons(u); coreAddSizedBufferData(&out->data, &u, sizeof(u)); return out; } OutPacket* coreOutPacketWriteU32(OutPacket* out, u32 u) { u = htonl(u); coreAddSizedBufferData(&out->data, &u, sizeof(u)); return out; } OutPacket* coreOutPacketWriteI8(OutPacket* out, i8 i) { if(i < 0) { return coreOutPacketWriteU8(out, (u8)((i32)i + (i32)128)); } return coreOutPacketWriteU8(out, (u8)((u32)i + (u32)128)); } OutPacket* coreOutPacketWriteI16(OutPacket* out, i16 i) { if(i < 0) { return coreOutPacketWriteU16(out, (u16)((i32)i + (i32)32768)); } return coreOutPacketWriteU16(out, (u16)((u32)i + (u32)32768)); } OutPacket* coreOutPacketWriteI32(OutPacket* out, i32 i) { if(i < 0) { return coreOutPacketWriteU32(out, (u32)(i + (i32)2147483648)); } return coreOutPacketWriteU32(out, (u32)((u32)i + (u32)2147483648)); } OutPacket* coreOutPacketWriteFloat(OutPacket* out, float f) { u32 u; static_assert(sizeof(u) == sizeof(f), "float and u32 size do not match"); memcpy(&u, &f, sizeof(float)); return coreOutPacketWriteU32(out, u); } OutPacket* coreOutPacketWriteString(OutPacket* out, const char* s, size_t n) { size_t end = n > 65535 ? 65535 : n; coreOutPacketWriteU16(out, (u16)end); for(size_t i = 0; i < end; i++) { coreOutPacketWriteU8(out, (u8)(*(s++))); } return out; } OutPacket* coreOutPacketWrite(OutPacket* out, const void* buffer, size_t n) { coreAddSizedBufferData(&out->data, buffer, n); return out; } /*static int enetCounter = 0; bool ENet::add() { if(enetCounter == 0 && enet_initialize() != 0) { return true; } enetCounter++; return false; } void ENet::remove() { if(enetCounter > 0 && --enetCounter == 0) { enet_deinitialize(); } } static_assert(sizeof(enet_uint16) == sizeof(Client::Port), "client port has wrong type"); static ENetHost* client = nullptr; static ENetPeer* connection = nullptr; static int connectTicks = 0; static int connectTimeoutTicks = 0; static int disconnectTicks = 0; static int disconnectTimeoutTicks = 0; static Client::OnConnect onConnect = []() {}; static Client::OnDisconnect onDisconnect = []() {}; static Client::OnPacket onPacket = [](InPacket&) {}; Error Client::start() { if(client != nullptr) { return {"already started"}; } else if(ENet::add()) { return {"cannot initialize enet"}; } client = enet_host_create(nullptr, 1, 2, 0, 0); if(client == nullptr) { ENet::remove(); return {"cannot create enet client host"}; } return {}; } void Client::stop() { if(connection != nullptr) { onDisconnect(); enet_peer_disconnect_now(connection, 0); connection = nullptr; } if(client != nullptr) { enet_host_destroy(client); ENet::remove(); client = nullptr; } connectTicks = 0; disconnectTicks = 0; } Error Client::connect(const char* server, Port port, int timeoutTicks) { if(client == nullptr) { return {"client not started"}; } else if(connection != nullptr) { return {"connection already exists"}; } ENetAddress address; memset(&address, 0, sizeof(ENetAddress)); enet_address_set_host(&address, server); address.port = port; connection = enet_host_connect(client, &address, 3, 0); if(connection == nullptr) { return {"cannot create connection"}; } connectTicks = 1; connectTimeoutTicks = timeoutTicks; return {}; } void Client::disconnect(int timeoutTicks) { if(connection == nullptr) { return; } connectTicks = 0; enet_peer_disconnect(connection, 0); disconnectTicks = 1; disconnectTimeoutTicks = timeoutTicks; } void Client::send(OutPacket& p, PacketSendMode mode) { if(client != nullptr && connection != nullptr && connectTicks < 0) { constexpr enet_uint32 flags[] = {ENET_PACKET_FLAG_RELIABLE, 0, ENET_PACKET_FLAG_UNSEQUENCED}; enet_uint8 index = static_cast(mode); enet_peer_send(connection, index, enet_packet_create( p.buffer, static_cast(p.buffer.getLength()), flags[index])); } } void Client::tick() { if(client == nullptr) { return; } ENetEvent e; while(enet_host_service(client, &e, 0) > 0) { switch(e.type) { case ENET_EVENT_TYPE_CONNECT: connectTicks = -1; onConnect(); break; case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: case ENET_EVENT_TYPE_DISCONNECT: disconnectTicks = 0; onDisconnect(); connection = nullptr; break; case ENET_EVENT_TYPE_NONE: return; case ENET_EVENT_TYPE_RECEIVE: InPacket in(e.packet->data, static_cast(e.packet->dataLength)); onPacket(in); enet_packet_destroy(e.packet); break; } } if(connectTicks >= 1 && ++connectTicks > connectTimeoutTicks) { connectTicks = 0; disconnect(connectTimeoutTicks); } if(disconnectTicks >= 1 && ++disconnectTicks > disconnectTimeoutTicks) { disconnectTicks = 0; onDisconnect(); if(connection != nullptr) { enet_peer_reset(connection); connection = nullptr; } } } void Client::setConnectHandler(OnConnect oc) { onConnect = oc; } void Client::setDisconnectHandler(OnDisconnect od) { onDisconnect = od; } void Client::setPacketHandler(OnPacket op) { onPacket = op; } void Client::resetHandler() { onConnect = []() {}; onDisconnect = []() {}; onPacket = [](InPacket&) {}; } bool Client::isConnecting() { return connectTicks >= 1; } bool Client::isConnected() { return connectTicks < 0; } static_assert(sizeof(enet_uint16) == sizeof(Server::Port), "client port has wrong type"); static ENetHost* server; static HashMap clients; static Server::Client idCounter = 1; static Server::OnConnect onConnect = [](Server::Client) {}; static Server::OnDisconnect onDisconnect = [](Server::Client) {}; static Server::OnPacket onPacket = [](Server::Client, InPacket&) {}; Error Server::start(Port port, int maxClients) { if(maxClients <= 0) { return {"invalid max client amount"}; } else if(server != nullptr) { return {"already started"}; } else if(ENet::add()) { return {"cannot initialize enet"}; } ENetAddress address; memset(&address, 0, sizeof(ENetAddress)); address.host = ENET_HOST_ANY; address.port = port; server = enet_host_create(&address, static_cast(maxClients), 3, 0, 0); if(server == nullptr) { ENet::remove(); return {"cannot create enet server host"}; } return {}; } void Server::stop() { if(server == nullptr) { return; } for(ENetPeer* peer : clients.values()) { enet_peer_reset(peer); } enet_host_destroy(server); server = nullptr; ENet::remove(); } static void writeId(ENetPeer* peer, Server::Client id) { static_assert(sizeof(peer->data) >= sizeof(id), "private data not big enough for id"); memcpy(&(peer->data), &id, sizeof(id)); } static Server::Client getId(ENetPeer* peer) { Server::Client id = -1; memcpy(&id, &(peer->data), sizeof(id)); return id; } static void handleConnect(ENetEvent& e) { Server::Client id = idCounter++; if(clients.tryEmplace(id, e.peer)) { LOG_WARNING("id is connected twice"); return; } writeId(e.peer, id); onConnect(id); } static void handlePacket(ENetEvent& e) { if(e.peer->data == nullptr) { LOG_WARNING("client without data sent package"); return; } Server::Client id = getId(e.peer); InPacket in(e.packet->data, static_cast(e.packet->dataLength)); onPacket(id, in); } static void handleDisconnect(ENetEvent& e) { if(e.peer->data == nullptr) { LOG_WARNING("client without data disconnected"); return; } Server::Client id = getId(e.peer); onDisconnect(id); if(clients.remove(id)) { LOG_WARNING("removed non existing client"); } } void Server::tick() { if(server == nullptr) { return; } ENetEvent e; while(enet_host_service(server, &e, 0) > 0) { switch(e.type) { case ENET_EVENT_TYPE_CONNECT: handleConnect(e); break; case ENET_EVENT_TYPE_RECEIVE: handlePacket(e); enet_packet_destroy(e.packet); break; case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: case ENET_EVENT_TYPE_DISCONNECT: handleDisconnect(e); break; case ENET_EVENT_TYPE_NONE: return; } } } static ENetPacket* fromBuffer(const Buffer& buffer, int index) { constexpr enet_uint32 flags[] = {ENET_PACKET_FLAG_RELIABLE, 0, ENET_PACKET_FLAG_UNSEQUENCED}; return enet_packet_create( buffer, static_cast(buffer.getLength()), flags[index]); } void Server::send(const OutPacket& p, PacketSendMode mode) { if(server != nullptr) { int index = static_cast(mode); enet_host_broadcast(server, static_cast(index), fromBuffer(p.buffer, index)); } } void Server::send(Server::Client client, const OutPacket& p, PacketSendMode mode) { if(server == nullptr) { return; } ENetPeer** peer = clients.search(client); if(peer != nullptr) { int index = static_cast(mode); enet_peer_send(*peer, static_cast(index), fromBuffer(p.buffer, index)); } } void Server::disconnect(Client client) { ENetPeer** peer = clients.search(client); if(peer != nullptr) { enet_peer_disconnect(*peer, 0); } } void Server::setConnectHandler(OnConnect oc) { onConnect = oc; } void Server::setDisconnectHandler(OnDisconnect od) { onDisconnect = od; } void Server::setPacketHandler(OnPacket op) { onPacket = op; } void Server::resetHandler() { onConnect = [](Server::Client) {}; onDisconnect = [](Server::Client) {}; onPacket = [](Server::Client, InPacket&) {}; }*/