#include "libs/enet/include/enet.h" #include "network/Client.h" #include "network/ENet.h" 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}; int index = static_cast(mode); enet_peer_send( connection, index, enet_packet_create(p.buffer, 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, 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; }