From ac463f06692b358b3bfc8adee49c58769ecca096 Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Wed, 4 Sep 2019 21:08:52 +0000 Subject: [PATCH] Implemented more networking --- flint.lua | 3 + network-client/src/client.cpp | 67 ++++++++++++++++++-- network-server/src/server.cpp | 103 ++++++++++++++++++++++++------- network-shared/include/debug.h | 13 ++++ network-shared/include/packets.h | 10 +++ 5 files changed, 170 insertions(+), 26 deletions(-) create mode 100644 network-shared/include/debug.h create mode 100644 network-shared/include/packets.h diff --git a/flint.lua b/flint.lua index 320c6b0..9965193 100644 --- a/flint.lua +++ b/flint.lua @@ -60,11 +60,14 @@ executable "server" path "network-server" dependency "network-shared" + dependency "iohelper" threads() executable "client" path "network-client" + dependency "network-shared" + run_dir "test" run_target "test" diff --git a/network-client/src/client.cpp b/network-client/src/client.cpp index bd55d8d..6ae243a 100644 --- a/network-client/src/client.cpp +++ b/network-client/src/client.cpp @@ -1,9 +1,21 @@ #include +#include #include #include +#include "ecs-serial.h" +#include "ecs_network_components.h" + +#include "iohelper/memstream.h" + +#include "packets.h" +#include "debug.h" + int main() { + ecs::Manager manager; + generated::init(); + // IPv4 int address_family = AF_INET; // UDP @@ -24,20 +36,65 @@ int main() { sockaddr* to = (sockaddr*)&server_address; int to_size = sizeof(server_address); - int8_t buffer[1024]; - buffer[0] = 'c'; + std::array buff; + // @todo Implement iomemstream + iohelper::omemstream_fixed buff_stream_out(buff); + iohelper::imemstream_fixed buff_stream_in(buff); - if (sendto(sock, buffer, 1024, 0, to, to_size) < 0) { + iohelper::write(buff_stream_out, PACKET::CONNECT); + + if (sendto(sock, buff.data(), buff.size(), 0, to, to_size) < 0) { throw std::runtime_error("Failed to connect to server"); } sockaddr_in from; socklen_t from_size = sizeof(from); - int bytes_received = recvfrom(sock, buffer, 1024, 0, (sockaddr*)&from, &from_size); + int bytes_received = recvfrom(sock, buff.data(), buff.size(), 0, (sockaddr*)&from, &from_size); if (bytes_received < 0) { throw std::runtime_error("Failed to receive data!"); } - std::cout << "Connected to server!\n"; + if (iohelper::read(buff_stream_in) == PACKET::ACK) { + std::cout << "Connected to server!\n"; + } else { + throw std::runtime_error("Unexpected server response"); + } + + while (true) { + buff_stream_in.seekg(0, std::ios::beg); + + int bytes_received = recvfrom(sock, buff.data(), buff.size(), 0, (sockaddr*)&from, &from_size); + + if (bytes_received < 0) { + throw std::runtime_error("Failed to receive data!"); + } + + PACKET type = (PACKET)iohelper::read(buff_stream_in); + switch (type) { + case PACKET::IDS: + std::cout << "Receiving ids\n"; + ecs::serial::deserialize_ids(buff_stream_in); + break; + + case PACKET::ENTITIES: { + std::cout << "Receiving entities\n"; + size_t entity_count = iohelper::read_length(buff_stream_in); + for (size_t i = 0; i < entity_count; ++i) { + ecs::serial::deserialize(buff_stream_in, manager); + } + + manager.view().for_each([](ecs::Entity* entity, Position* position) { + std::cout << entity->uuid << ' ' << position->x << ' ' << position->y << '\n'; + }); + + break; + } + + default: + std::cout << "Unknown packet type: " << (uint32_t)type << '\n'; + } + + // dump_buffer(buff); + } } diff --git a/network-server/src/server.cpp b/network-server/src/server.cpp index a257148..1f270c0 100644 --- a/network-server/src/server.cpp +++ b/network-server/src/server.cpp @@ -1,12 +1,18 @@ #include #include #include +#include #include #include "ecs-serial.h" #include "ecs_network_components.h" +#include "iohelper/memstream.h" + +#include "packets.h" +#include "debug.h" + ecs::Manager manager; void on_connect(int sock, sockaddr_in from) { @@ -20,40 +26,84 @@ void on_connect(int sock, sockaddr_in from) { std::cout << "Client connected: " << bytes[0] << '.' << bytes[1] << '.' << bytes[2] << '.' << bytes[3] << '\n'; - uint8_t buffer[1024]; - buffer[0] = 'a'; - if (sendto(sock, buffer, 1024, 0, (sockaddr*)&from, sizeof(from)) < 0) { + std::array buff; + iohelper::omemstream_fixed buff_stream(buff); + iohelper::write(buff_stream, PACKET::ACK); + + if (sendto(sock, buff.data(), buff.size(), 0, (sockaddr*)&from, sizeof(from)) < 0) { throw std::runtime_error("Failed to send ack to client"); } + // dump_buffer(buff); + // Send ids and all entities - // @todo We need to somehow write to the socket // @todo Make everything thread safe - ecs::serial::serialize_ids(std::cout); -} - -// For now we will just send the entire state every tick -void on_update() { - // Depending on the update type send it to all clients - // New component added -> send new id - // Component updated -> send updated component + buff_stream.seekp(0, std::ios::beg); + iohelper::write(buff_stream, PACKET::IDS); + ecs::serial::serialize_ids(buff_stream); + + std::cout << "Sending ids\n"; + + if (sendto(sock, buff.data(), buff.size(), 0, (sockaddr*)&from, sizeof(from)) < 0) { + throw std::runtime_error("Failed to send ids to client"); + } + + // dump_buffer(buff); + + std::cout << "Sending entities\n"; + + buff_stream.seekp(0, std::ios::beg); + iohelper::write(buff_stream, PACKET::ENTITIES); + iohelper::write_length(buff_stream, manager.view<>().size()); + for (auto [uuid, entity] : manager.view<>()) { + ecs::serial::serialize(buff_stream, entity); + } + + if (sendto(sock, buff.data(), buff.size(), 0, (sockaddr*)&from, sizeof(from)) < 0) { + throw std::runtime_error("Failed to send ids to client"); + } + + // THIS IS A TEST + std::cout << "Sending update\n"; + + manager.view().for_each([](ecs::Entity* /* entity */, Position* position) { + if (int(position->y * 10) % 2 == 0) { + position->y *= 2; + } + }); + + // @todo Figure out how to delta everything + buff_stream.seekp(0, std::ios::beg); + iohelper::write(buff_stream, PACKET::ENTITIES); + iohelper::write_length(buff_stream, manager.view<>().size()); + for (auto [uuid, entity] : manager.view<>()) { + ecs::serial::serialize(buff_stream, entity); + } + + if (sendto(sock, buff.data(), buff.size(), 0, (sockaddr*)&from, sizeof(from)) < 0) { + throw std::runtime_error("Failed to send ids to client"); + } + // dump_buffer(buff); } +// This is the loop that listens for messages from clients void listener(int sock) { - // @todo Replace true with an atomic - while (true) { - int8_t buffer[1024]; - // Wait on initial connection - sockaddr_in from; - socklen_t from_size = sizeof(from); - int bytes_received = recvfrom(sock, buffer, 1024, 0, (sockaddr*)&from, &from_size); + std::array buff; + iohelper::imemstream_fixed buff_stream(buff); + sockaddr_in from; + socklen_t from_size = sizeof(from); + + while (true) { + buff_stream.seekg(0, std::ios::beg); + + int bytes_received = recvfrom(sock, buff.data(), buff.size(), 0, (sockaddr*)&from, &from_size); if (bytes_received < 0) { throw std::runtime_error("Failed to receive data!"); } - switch (buffer[0]) { - case 'c': + switch (iohelper::read(buff_stream)) { + case PACKET::CONNECT: on_connect(sock, from); break; } @@ -63,6 +113,17 @@ void listener(int sock) { int main() { generated::init(); + for (int i = 0; i < 10; ++i) { + // We can create entities + ecs::Entity* entity = manager.create_entity(); + // Then we can add components to them + entity->add_component(0.1f*i, 0.3f*i); + } + + manager.view().for_each([](ecs::Entity* entity, Position* position) { + std::cout << entity->uuid << ' ' << position->x << ' ' << position->y << '\n'; + }); + int address_family = AF_INET; int type = SOCK_DGRAM; int protocol = 0; diff --git a/network-shared/include/debug.h b/network-shared/include/debug.h new file mode 100644 index 0000000..18eaab9 --- /dev/null +++ b/network-shared/include/debug.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + +template +void dump_buffer(std::array &buff) { + for (uint32_t b : buff) { + std::cout << b << ' '; + } + std::cout << '\n'; +} + diff --git a/network-shared/include/packets.h b/network-shared/include/packets.h new file mode 100644 index 0000000..a7175e4 --- /dev/null +++ b/network-shared/include/packets.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +enum PACKET : uint8_t { + CONNECT, + ACK, + IDS, + ENTITIES +};