#include #include #include #include #include #include #include #include #include #include #define _USE_MATH_DEFINES #include #include "../src/network/ClientState.h" #include #include // Вспомогательный split std::vector split(const std::string& s, char delimiter) { std::vector tokens; std::string token; std::istringstream tokenStream(s); while (std::getline(tokenStream, token, delimiter)) { tokens.push_back(token); } return tokens; } namespace beast = boost::beast; namespace http = beast::http; namespace websocket = beast::websocket; namespace net = boost::asio; using tcp = net::ip::tcp; class Session; struct ServerBox { Eigen::Vector3f position; Eigen::Matrix3f rotation; float collisionRadius = 2.0f; }; std::vector g_serverBoxes; std::mutex g_boxes_mutex; std::vector> g_sessions; std::mutex g_sessions_mutex; class Session : public std::enable_shared_from_this { websocket::stream ws_; beast::flat_buffer buffer_; int id_; bool is_writing_ = false; ClientStateInterval timedClientStates; void process_message(const std::string& msg) { auto now_server = std::chrono::system_clock::now(); auto parts = split(msg, ':'); if (parts.size() < 16) { throw std::runtime_error("Unknown message type received, too small"); } uint64_t clientTimestamp = std::stoull(parts[1]); ClientState receivedState; receivedState.id = id_; std::chrono::system_clock::time_point uptime_timepoint{ std::chrono::duration_cast(std::chrono::milliseconds(clientTimestamp)) }; receivedState.lastUpdateServerTime = uptime_timepoint; if (parts[0] == "UPD") { receivedState.handle_full_sync(parts, 2); retranslateMessage(msg); } else { throw std::runtime_error("Unknown message type received: " + parts[0]); } timedClientStates.add_state(receivedState); } void retranslateMessage(const std::string& msg) { std::string event_msg = "EVENT:" + std::to_string(id_) + ":" + msg; std::lock_guard lock(g_sessions_mutex); for (auto& session : g_sessions) { if (session->get_id() != id_) { // Не шлем отправителю session->send_message(event_msg); } } } void sendBoxesToClient() { std::lock_guard lock(g_boxes_mutex); std::string boxMsg = "BOXES:"; for (const auto& box : g_serverBoxes) { Eigen::Quaternionf q(box.rotation); boxMsg += std::to_string(box.position.x()) + ":" + std::to_string(box.position.y()) + ":" + std::to_string(box.position.z()) + ":" + std::to_string(q.w()) + ":" + std::to_string(q.x()) + ":" + std::to_string(q.y()) + ":" + std::to_string(q.z()) + "|"; } if (!boxMsg.empty() && boxMsg.back() == '|') { boxMsg.pop_back(); } send_message(boxMsg); } void send_message(std::string msg) { auto ss = std::make_shared(std::move(msg)); if (is_writing_) { ws_.async_write(net::buffer(*ss), [self = shared_from_this(), ss](beast::error_code ec, std::size_t) { if (ec) { std::cerr << "Write error: " << ec.message() << std::endl; } }); } else { is_writing_ = true; ws_.async_write(net::buffer(*ss), [self = shared_from_this(), ss](beast::error_code ec, std::size_t) { self->is_writing_ = false; if (ec) { std::cerr << "Write error: " << ec.message() << std::endl; } }); } } public: explicit Session(tcp::socket&& socket, int id) : ws_(std::move(socket)), id_(id) { } void init() { sendBoxesToClient(); auto timer = std::make_shared(ws_.get_executor()); timer->expires_after(std::chrono::milliseconds(100)); timer->async_wait([self = shared_from_this(), timer](const boost::system::error_code& ec) { if (!ec) { self->send_message("ID:" + std::to_string(self->id_)); self->do_read(); } }); } void run() { { std::lock_guard lock(g_sessions_mutex); g_sessions.push_back(shared_from_this()); } ws_.async_accept([self = shared_from_this()](beast::error_code ec) { if (ec) return; std::cout << "Client " << self->id_ << " connected\n"; self->init(); // self->send_message("ID:" + std::to_string(self->id_)); // 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 get_id() const { return id_; } private: void do_read() { ws_.async_read(buffer_, [self = shared_from_this()](beast::error_code ec, std::size_t) { if (ec) { std::lock_guard lock(g_sessions_mutex); g_sessions.erase(std::remove_if(g_sessions.begin(), g_sessions.end(), [self](const std::shared_ptr& session) { return session.get() == self.get(); }), g_sessions.end()); return; } std::string msg = beast::buffers_to_string(self->buffer_.data()); self->process_message(msg); self->buffer_.consume(self->buffer_.size()); self->do_read(); }); } }; void update_world(net::steady_timer& timer, net::io_context& ioc) { // TODO: Renew game state timer.expires_after(std::chrono::milliseconds(50)); timer.async_wait([&](const boost::system::error_code& ec) { if (!ec) update_world(timer, ioc); }); } std::vector generateServerBoxes(int count) { std::vector boxes; std::random_device rd; std::mt19937 gen(rd()); const float MIN_COORD = -100.0f; const float MAX_COORD = 100.0f; const float MIN_DISTANCE = 3.0f; const float MIN_DISTANCE_SQUARED = MIN_DISTANCE * MIN_DISTANCE; const int MAX_ATTEMPTS = 1000; std::uniform_real_distribution<> posDistrib(MIN_COORD, MAX_COORD); std::uniform_real_distribution<> angleDistrib(0.0, M_PI * 2.0); for (int i = 0; i < count; i++) { bool accepted = false; int attempts = 0; while (!accepted && attempts < MAX_ATTEMPTS) { ServerBox box; box.position = Eigen::Vector3f( (float)posDistrib(gen), (float)posDistrib(gen), (float)posDistrib(gen) ); accepted = true; for (const auto& existingBox : boxes) { Eigen::Vector3f diff = box.position - existingBox.position; if (diff.squaredNorm() < MIN_DISTANCE_SQUARED) { accepted = false; break; } } if (accepted) { float randomAngle = (float)angleDistrib(gen); Eigen::Vector3f axis = Eigen::Vector3f::Random().normalized(); box.rotation = Eigen::AngleAxisf(randomAngle, axis).toRotationMatrix(); boxes.push_back(box); } attempts++; } } return boxes; } int main() { try { { std::lock_guard lock(g_boxes_mutex); g_serverBoxes = generateServerBoxes(50); std::cout << "Generated " << g_serverBoxes.size() << " boxes on server\n"; } 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); }); }; net::steady_timer timer(ioc); update_world(timer, ioc); do_accept(do_accept); ioc.run(); } catch (std::exception const& e) { std::cerr << "Error: " << e.what() << std::endl; } return 0; }