diff --git a/include/protocol.hpp b/include/protocol.hpp index 97dce18..4f4b116 100644 --- a/include/protocol.hpp +++ b/include/protocol.hpp @@ -6,12 +6,30 @@ #include #include #include +#include #include #include #include "spdlog/spdlog.h" -namespace commons::protocol { +namespace commons { + +static constexpr size_t screen_size = 30; + +namespace protocol { +struct vec2; +struct pixel; +} // namespace protocol + +class render_interface { + public: + virtual ~render_interface() = default; + virtual void update_pixel(commons::protocol::vec2 position, + commons::protocol::pixel pixel) = 0; + virtual void draw() = 0; +}; + +namespace protocol { enum class Type { DRAW_RECTANGLE = 0, @@ -42,6 +60,7 @@ class generic_message_base } virtual void handle_message() = 0; + virtual void handle_message(render_interface* renderer){}; virtual void create_message() { spdlog::debug("create_message is not implemented yet"); } @@ -87,6 +106,34 @@ struct vec3 { int x, y, z; }; +enum class background_color { + BLACK = 40, + RED, + GREEN, + YELlOW, + BLUE, + MAGENTA, + CYAN, + WHITE, +}; + +enum class foreground_color { + BLACK = 30, + RED, + GREEN, + YELlOW, + BLUE, + MAGENTA, + CYAN, + WHITE, +}; + +struct pixel { + char value = '#'; + foreground_color color_fg = foreground_color::GREEN; + background_color color_bg = background_color::BLACK; +}; + class draw_rectangle : public generic_message { public: virtual ~draw_rectangle() { spdlog::debug("draw_rect dtor"); } @@ -118,10 +165,48 @@ class draw_pixel : public generic_message { std::this_thread::sleep_for(std::chrono::seconds(1)); } + virtual void handle_message(render_interface* renderer) override { + renderer->update_pixel(position, pixel_); + } + vec2 position; + pixel pixel_; vec3 color; }; class Serializer {}; -} // namespace commons::protocol +} // namespace protocol + +class cli_renderer : public render_interface { + public: + cli_renderer(size_t screen_size) + : screen{screen_size, std::vector{screen_size}} {} + + virtual ~cli_renderer() = default; + + virtual void update_pixel(commons::protocol::vec2 position, + commons::protocol::pixel pixel) override { + screen[position.y][position.x] = pixel; + draw(); + } + + virtual void draw() override { + std::stringstream str; + for (const auto& row : screen) { + for (const auto& pixel : row) { + str << "\033[" << static_cast(pixel.color_fg) << ";" + << static_cast(pixel.color_bg) << "m" << pixel.value; + } + str << "\033[30;40m\n"; + } + + str << "\033[30;40m\n"; + std::cout << str.str() << '\n'; + } + + private: + std::vector> screen; +}; + +} // namespace commons diff --git a/include/server.hpp b/include/server.hpp index 2704dff..c68829d 100644 --- a/include/server.hpp +++ b/include/server.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "protocol.hpp" #include "spdlog/spdlog.h" @@ -25,7 +26,8 @@ class fake_thread_pool { class server { public: server(boost::asio::io_context& io_context, short port) - : socket_(io_context, udp::endpoint(udp::v4(), port)) { + : socket_(io_context, udp::endpoint(udp::v4(), port)), + renderer(std::make_unique(commons::screen_size)) { do_receive(); } @@ -38,8 +40,8 @@ class server { std::shared_ptr msg_obj = deserialize(data_.data(), bytes_recvd); - fake_thread_pool::add_task([msg_obj = std::move(msg_obj)]() { - msg_obj->handle_message(); + fake_thread_pool::add_task([this, msg_obj = std::move(msg_obj)]() { + msg_obj->handle_message(renderer.get()); }); // do_send(bytes_recvd); @@ -64,6 +66,8 @@ class server { udp::endpoint sender_endpoint_; enum { max_length = 1024 }; std::array data_; + + std::unique_ptr renderer; }; } // namespace commons diff --git a/src/main.cpp b/src/main.cpp index 0f61d98..e876f86 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,5 @@ #include +#include #include "client.hpp" #include "protocol.hpp" @@ -13,20 +14,8 @@ void init_spdlog() { auto run_client(boost::asio::io_context& context) { spdlog::info("Running client..."); - auto s = std::make_unique( + auto s = std::make_shared( context, boost::asio::ip::make_address("0.0.0.0"), 9000, 0); - - for (int i = 0; i < 100; ++i) { - auto msg = std::make_shared(); - msg->color = commons::protocol::vec3{i, i, i}; - - // used as lifetime expansion so that msg doesnt go out of scope till it - // actually was sent - s->send(msg->serialize(), - std::bind(&commons::protocol::generic_message_base::handle_sent, - msg, std::placeholders::_1)); - } - return s; } @@ -41,9 +30,42 @@ int main(int argc, char* argv[]) { try { boost::asio::io_context io_context; std::unique_ptr server = nullptr; - std::unique_ptr client = nullptr; + std::shared_ptr client = nullptr; + std::thread t; if (argc == 1) { client = run_client(io_context); + + t = std::thread([client]() { + std::random_device dev; + std::mt19937 rng(dev()); + while (true) { + std::uniform_int_distribution pos( + 0, commons::screen_size - 1); + std::uniform_int_distribution color(30, + 37); + + auto msg = std::make_shared(); + msg->pixel_.value = '@'; + msg->pixel_.color_fg = + static_cast(color(rng)); + msg->pixel_.color_bg = + static_cast(color(rng) + 10); + msg->position = commons::protocol::vec2{pos(rng), pos(rng)}; + + spdlog::debug("sending fg {}, bg {}, posx {}, posy {}", + static_cast(msg->pixel_.color_fg), + static_cast(msg->pixel_.color_bg), msg->position.x, + msg->position.y); + // used as lifetime expansion so that msg doesnt go out of scope + // till it actually was sent + client->send( + msg->serialize(), + std::bind(&commons::protocol::generic_message_base::handle_sent, + msg, std::placeholders::_1)); + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + spdlog::info("send new"); + } + }); } if (argc == 2) { @@ -60,6 +82,8 @@ int main(int argc, char* argv[]) { context.join(); } + t.join(); + } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; }