diff --git a/proj-windows/CMakeLists.txt b/proj-windows/CMakeLists.txt index 0f68441..942ab6e 100644 --- a/proj-windows/CMakeLists.txt +++ b/proj-windows/CMakeLists.txt @@ -50,6 +50,9 @@ add_executable(space-game001 ../src/UiManager.h ../src/Projectile.h ../src/Projectile.cpp + ../src/network/NetworkInterface.h + ../src/network/WebSocketClient.h + ../src/network/WebSocketClient.cpp ) # Установка проекта по умолчанию для Visual Studio @@ -71,6 +74,7 @@ target_compile_definitions(space-game001 PRIVATE WIN32_LEAN_AND_MEAN PNG_ENABLED SDL_MAIN_HANDLED + NETWORK # SIMPLIFIED ) diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt new file mode 100644 index 0000000..b119422 --- /dev/null +++ b/server/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.15) +project(SpaceGameServer) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Подключаем зависимости нашего движка +include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/ThirdParty.cmake) + +# Настройка флагов для тяжелых шаблонов Boost +if (MSVC) + add_compile_options(/bigobj) +endif() + +# Добавляем скомпилированные компоненты Boost через относительные пути +# CMake сам создаст цели boost_system и др. +add_subdirectory("${BOOST_SRC_DIR}/libs/system" boost-system-build EXCLUDE_FROM_ALL) +add_subdirectory("${BOOST_SRC_DIR}/libs/assert" boost-assert-build EXCLUDE_FROM_ALL) +add_subdirectory("${BOOST_SRC_DIR}/libs/config" boost-config-build EXCLUDE_FROM_ALL) +add_subdirectory("${BOOST_SRC_DIR}/libs/throw_exception" boost-throw_exception-build EXCLUDE_FROM_ALL) +add_subdirectory("${BOOST_SRC_DIR}/libs/variant2" boost-variant2-build EXCLUDE_FROM_ALL) +add_subdirectory("${BOOST_SRC_DIR}/libs/mp11" boost-mp11-build EXCLUDE_FROM_ALL) +add_subdirectory("${BOOST_SRC_DIR}/libs/winapi" boost-winapi-build EXCLUDE_FROM_ALL) +add_subdirectory("${BOOST_SRC_DIR}/libs/predef" boost-predef-build EXCLUDE_FROM_ALL) +# EXCLUDE_FROM_ALL гарантирует, что мы собираем только то, что линкуем + +# Исполняемый файл сервера +add_executable(Server main.cpp) + +target_include_directories(Server PRIVATE ${BOOST_SRC_DIR}) + +# Линковка +target_link_libraries(Server + PRIVATE + boost_system # Скомпилированная часть для error_code + eigen_external_lib # Если планируешь использовать математику на сервере +) + +if(WIN32) + target_link_libraries(Server PRIVATE ws2_32 mswsock) +endif() + +# Дополнительный макрос, чтобы Asio знал, что мы работаем без устаревших функций +target_compile_definitions(Server PRIVATE BOOST_ASIO_NO_DEPRECATED) \ No newline at end of file diff --git a/server/main.cpp b/server/main.cpp new file mode 100644 index 0000000..c3a3195 --- /dev/null +++ b/server/main.cpp @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast = boost::beast; +namespace http = beast::http; +namespace websocket = beast::websocket; +namespace net = boost::asio; +using tcp = net::ip::tcp; + +class Session : public std::enable_shared_from_this { + websocket::stream ws_; + beast::flat_buffer buffer_; + int id_; + +public: + explicit Session(tcp::socket&& socket, int id) + : ws_(std::move(socket)), id_(id) { + } + + void run() { + ws_.async_accept([self = shared_from_this()](beast::error_code ec) { + if (ec) return; + std::cout << "Client " << self->id_ << " connected\n"; + // ID + self->send_message("ID:" + std::to_string(self->id_)); + self->do_read(); + }); + } + +private: + void do_read() { + ws_.async_read(buffer_, [self = shared_from_this()](beast::error_code ec, std::size_t) { + if (ec) return; + std::string msg = beast::buffers_to_string(self->buffer_.data()); + + if (msg == "PING") { + self->send_message("PONG"); + } + + self->buffer_.consume(self->buffer_.size()); + self->do_read(); + }); + } + + void send_message(std::string msg) { + auto ss = std::make_shared(std::move(msg)); + ws_.async_write(net::buffer(*ss), [ss](beast::error_code, std::size_t) {}); + } +}; + +int main() { + try { + net::io_context ioc; + tcp::acceptor acceptor{ ioc, {tcp::v4(), 8080} }; + int next_id = 1000; + + std::cout << "Server started on port 8080...\n"; + + auto do_accept = [&](auto& self_fn) -> void { + acceptor.async_accept([&, self_fn](beast::error_code ec, tcp::socket socket) { + if (!ec) { + std::make_shared(std::move(socket), next_id++)->run(); + } + self_fn(self_fn); + }); + }; + + do_accept(do_accept); + ioc.run(); + } + catch (std::exception const& e) { + std::cerr << "Error: " << e.what() << std::endl; + } + return 0; +} \ No newline at end of file diff --git a/src/network/NetworkInterface.h b/src/network/NetworkInterface.h new file mode 100644 index 0000000..dca15c0 --- /dev/null +++ b/src/network/NetworkInterface.h @@ -0,0 +1,14 @@ +#pragma once +#include + +// NetworkInterface.h - +namespace ZL { + class INetworkClient { + public: + virtual ~INetworkClient() = default; + virtual void Connect(const std::string& host, uint16_t port) = 0; + virtual void Send(const std::string& message) = 0; + virtual bool IsConnected() const = 0; + virtual void Poll() = 0; // + }; +} diff --git a/src/network/WebSocketClient.cpp b/src/network/WebSocketClient.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/network/WebSocketClient.h b/src/network/WebSocketClient.h new file mode 100644 index 0000000..7add3fe --- /dev/null +++ b/src/network/WebSocketClient.h @@ -0,0 +1,29 @@ +#pragma once + +// WebSocketClient.h +#include "NetworkInterface.h" +#include + +namespace ZL { + class WebSocketClient : public INetworkClient { + private: + std::queue messageQueue; + bool connected = false; + int clientId = -1; + + public: + void Connect(const std::string& host, uint16_t port) override { + // Emscripten emscripten_websocket_new + // Desktop - boost::beast::websocket::stream + } + + void Poll() override { + // . + // ID: clientId = parseId(msg); connected = true; + // "PONG": . + } + + bool IsConnected() const override { return connected; } + int GetClientId() const { return clientId; } + }; +} \ No newline at end of file