mirror of
https://github.com/BeamMP/BeamMP-Launcher.git
synced 2025-07-04 00:47:23 +00:00
switch to make ClientNetwork async
This commit is contained in:
parent
b9be3990c7
commit
c6e07cd26b
@ -2,8 +2,8 @@
|
|||||||
#include "ClientPacket.h"
|
#include "ClientPacket.h"
|
||||||
#include "ClientTransport.h"
|
#include "ClientTransport.h"
|
||||||
#include "Http.h"
|
#include "Http.h"
|
||||||
#include "Launcher.h"
|
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
|
#include "Launcher.h"
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
@ -28,8 +28,8 @@ void ClientNetwork::run() {
|
|||||||
ec.message());
|
ec.message());
|
||||||
}
|
}
|
||||||
|
|
||||||
ip::tcp::acceptor acceptor(m_io, listen_ep);
|
m_acceptor = ip::tcp::acceptor(m_io, listen_ep);
|
||||||
acceptor.listen(ip::tcp::socket::max_listen_connections, ec);
|
m_acceptor.listen(ip::tcp::socket::max_listen_connections, ec);
|
||||||
if (ec) {
|
if (ec) {
|
||||||
spdlog::error("listen() failed, which is needed for the launcher to operate. "
|
spdlog::error("listen() failed, which is needed for the launcher to operate. "
|
||||||
"Shutting down. spdlog::error: {}",
|
"Shutting down. spdlog::error: {}",
|
||||||
@ -37,22 +37,8 @@ void ClientNetwork::run() {
|
|||||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||||
std::exit(1);
|
std::exit(1);
|
||||||
}
|
}
|
||||||
do {
|
start_accept();
|
||||||
try {
|
m_io.run();
|
||||||
spdlog::info("Waiting for the game to connect");
|
|
||||||
ip::tcp::endpoint game_ep;
|
|
||||||
auto game = acceptor.accept(game_ep, ec);
|
|
||||||
if (ec) {
|
|
||||||
spdlog::error("Failed to accept: {}", ec.message());
|
|
||||||
}
|
|
||||||
spdlog::info("Game connected!");
|
|
||||||
spdlog::debug("Game: [{}]:{}", game_ep.address().to_string(), game_ep.port());
|
|
||||||
handle_connection(std::move(game));
|
|
||||||
spdlog::warn("Game disconnected!");
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
spdlog::error("Fatal error in core network: {}", e.what());
|
|
||||||
}
|
|
||||||
} while (!*m_shutdown);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientNetwork::ClientNetwork(Launcher& launcher, uint16_t port)
|
ClientNetwork::ClientNetwork(Launcher& launcher, uint16_t port)
|
||||||
@ -65,8 +51,7 @@ ClientNetwork::~ClientNetwork() {
|
|||||||
spdlog::debug("Client network destroyed");
|
spdlog::debug("Client network destroyed");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientNetwork::handle_connection(ip::tcp::socket&& socket) {
|
void ClientNetwork::handle_connection() {
|
||||||
m_game_socket = std::move(socket);
|
|
||||||
// immediately send launcher info (first step of client identification)
|
// immediately send launcher info (first step of client identification)
|
||||||
m_client_state = bmp::ClientState::ClientIdentification;
|
m_client_state = bmp::ClientState::ClientIdentification;
|
||||||
|
|
||||||
@ -80,18 +65,21 @@ void ClientNetwork::handle_connection(ip::tcp::socket&& socket) {
|
|||||||
});
|
});
|
||||||
client_tcp_write(info_packet);
|
client_tcp_write(info_packet);
|
||||||
|
|
||||||
|
client_tcp_read([this](auto&& packet) {
|
||||||
|
handle_packet(packet);
|
||||||
|
});
|
||||||
|
|
||||||
// packet read and respond loop
|
// packet read and respond loop
|
||||||
while (!*m_shutdown) {
|
/*
|
||||||
try {
|
try {
|
||||||
auto packet = client_tcp_read();
|
auto packet = client_tcp_read();
|
||||||
handle_packet(packet);
|
handle_packet(packet);
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
spdlog::error("Unhandled exception in connection handler, connection closing.");
|
spdlog::error("Unhandled exception in connection handler, connection closing.");
|
||||||
spdlog::debug("Exception: {}", e.what());
|
spdlog::debug("Exception: {}", e.what());
|
||||||
m_game_socket.close();
|
m_game_socket.close();
|
||||||
break;
|
break;
|
||||||
}
|
}*/
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientNetwork::handle_packet(bmp::ClientPacket& packet) {
|
void ClientNetwork::handle_packet(bmp::ClientPacket& packet) {
|
||||||
@ -213,12 +201,14 @@ void ClientNetwork::start_login() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ClientNetwork::disconnect(const std::string& reason) {
|
void ClientNetwork::disconnect(const std::string& reason) {
|
||||||
|
spdlog::debug("Disconnecting game: {}", reason);
|
||||||
bmp::ClientPacket error {
|
bmp::ClientPacket error {
|
||||||
.purpose = bmp::ClientPurpose::Error,
|
.purpose = bmp::ClientPurpose::Error,
|
||||||
.raw_data = json_to_vec({ "message", reason })
|
.raw_data = json_to_vec({ "message", reason })
|
||||||
};
|
};
|
||||||
client_tcp_write(error);
|
client_tcp_write(error);
|
||||||
m_game_socket.close();
|
m_game_socket.close();
|
||||||
|
start_accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientNetwork::handle_login(bmp::ClientPacket& packet) {
|
void ClientNetwork::handle_login(bmp::ClientPacket& packet) {
|
||||||
@ -366,30 +356,50 @@ void ClientNetwork::handle_server_leaving(bmp::ClientPacket& packet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bmp::ClientPacket ClientNetwork::client_tcp_read() {
|
void ClientNetwork::client_tcp_read(std::function<void(bmp::ClientPacket&&)> handler) {
|
||||||
bmp::ClientPacket packet {};
|
m_tmp_header_buffer.resize(bmp::ClientHeader::SERIALIZED_SIZE);
|
||||||
std::vector<uint8_t> header_buffer(bmp::ClientHeader::SERIALIZED_SIZE);
|
boost::asio::async_read(m_game_socket, buffer(m_tmp_header_buffer),
|
||||||
read(m_game_socket, buffer(header_buffer));
|
bind_executor(m_strand, [this, handler](auto ec, auto) {
|
||||||
bmp::ClientHeader hdr {};
|
if (ec) {
|
||||||
hdr.deserialize_from(header_buffer);
|
disconnect(fmt::format("Failed to read from game: {}", ec.message()));
|
||||||
// vector eaten up by now, recv again
|
} else {
|
||||||
packet.raw_data.resize(hdr.data_size);
|
bmp::ClientHeader hdr {};
|
||||||
read(m_game_socket, buffer(packet.raw_data));
|
hdr.deserialize_from(m_tmp_header_buffer);
|
||||||
packet.purpose = hdr.purpose;
|
// vector eaten up by now, recv again
|
||||||
packet.flags = hdr.flags;
|
m_tmp_packet.raw_data.resize(hdr.data_size);
|
||||||
return packet;
|
m_tmp_packet.purpose = hdr.purpose;
|
||||||
|
m_tmp_packet.flags = hdr.flags;
|
||||||
|
boost::asio::async_read(m_game_socket, buffer(m_tmp_packet.raw_data),
|
||||||
|
bind_executor(m_strand, [handler, this](auto ec, auto) {
|
||||||
|
if (ec) {
|
||||||
|
disconnect(fmt::format("Failed to read from game: {}", ec.message()));
|
||||||
|
} else {
|
||||||
|
// ok!
|
||||||
|
handler(std::move(m_tmp_packet));
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientNetwork::client_tcp_write(bmp::ClientPacket& packet) {
|
void ClientNetwork::client_tcp_write(bmp::ClientPacket& packet) {
|
||||||
// finalize the packet (compress etc) and produce header
|
|
||||||
auto header = packet.finalize();
|
auto header = packet.finalize();
|
||||||
// serialize header
|
// serialize header
|
||||||
std::vector<uint8_t> header_data(bmp::ClientHeader::SERIALIZED_SIZE);
|
std::vector<uint8_t> data(bmp::ClientHeader::SERIALIZED_SIZE + packet.raw_data.size());
|
||||||
header.serialize_to(header_data);
|
auto offset = header.serialize_to(data);
|
||||||
// write header and packet data
|
// copy packet data (yes i know ugh) to the `data` in order to send it in one go
|
||||||
write(m_game_socket, buffer(header_data));
|
std::copy(packet.raw_data.begin(), packet.raw_data.end(), data.begin() + long(offset));
|
||||||
write(m_game_socket, buffer(packet.raw_data));
|
boost::asio::async_write(m_game_socket, buffer(data),
|
||||||
|
[this](auto ec, auto) {
|
||||||
|
if (ec) {
|
||||||
|
spdlog::error("Failed to write a packet: {}", ec.message());
|
||||||
|
disconnect("Failed to send data to game");
|
||||||
|
} else {
|
||||||
|
// ok! sent all data
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> ClientNetwork::json_to_vec(const nlohmann::json& value) {
|
std::vector<uint8_t> ClientNetwork::json_to_vec(const nlohmann::json& value) {
|
||||||
auto str = value.dump();
|
auto str = value.dump();
|
||||||
return std::vector<uint8_t>(str.begin(), str.end());
|
return std::vector<uint8_t>(str.begin(), str.end());
|
||||||
@ -429,3 +439,73 @@ Result<nlohmann::json, std::string> ClientNetwork::load_server_list() noexcept {
|
|||||||
return outcome::failure(fmt::format("Failed to fetch server list from backend: {}", e.what()));
|
return outcome::failure(fmt::format("Failed to fetch server list from backend: {}", e.what()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void ClientNetwork::handle_server_packet(bmp::Packet&& packet) {
|
||||||
|
post(m_io, [packet, this] {
|
||||||
|
spdlog::info("HELLO WORLD: {}", m_listen_port);
|
||||||
|
switch (packet.purpose) {
|
||||||
|
case bmp::Invalid:
|
||||||
|
break;
|
||||||
|
case bmp::ProtocolVersion:
|
||||||
|
case bmp::ProtocolVersionOk:
|
||||||
|
case bmp::ProtocolVersionBad:
|
||||||
|
case bmp::ClientInfo:
|
||||||
|
case bmp::ServerInfo:
|
||||||
|
case bmp::PlayerPublicKey:
|
||||||
|
case bmp::AuthOk:
|
||||||
|
case bmp::AuthFailed:
|
||||||
|
case bmp::PlayerRejected:
|
||||||
|
case bmp::StartUDP:
|
||||||
|
case bmp::ModsInfo:
|
||||||
|
case bmp::MapInfo:
|
||||||
|
case bmp::ModRequest:
|
||||||
|
case bmp::ModResponse:
|
||||||
|
case bmp::ModRequestInvalid:
|
||||||
|
case bmp::ModsSyncDone:
|
||||||
|
case bmp::PlayersVehiclesInfo:
|
||||||
|
case bmp::SessionReady:
|
||||||
|
case bmp::Ping:
|
||||||
|
case bmp::VehicleSpawn:
|
||||||
|
case bmp::VehicleDelete:
|
||||||
|
case bmp::VehicleReset:
|
||||||
|
case bmp::VehicleEdited:
|
||||||
|
case bmp::VehicleCouplerChanged:
|
||||||
|
case bmp::SpectatorSwitched:
|
||||||
|
case bmp::ApplyInput:
|
||||||
|
case bmp::ApplyElectrics:
|
||||||
|
case bmp::ApplyNodes:
|
||||||
|
case bmp::ApplyBreakgroups:
|
||||||
|
case bmp::ApplyPowertrain:
|
||||||
|
case bmp::ApplyPosition:
|
||||||
|
case bmp::ChatMessage:
|
||||||
|
case bmp::Event:
|
||||||
|
case bmp::PlayerJoined:
|
||||||
|
case bmp::PlayerLeft:
|
||||||
|
case bmp::PlayerPingUpdate:
|
||||||
|
case bmp::Notification:
|
||||||
|
case bmp::Kicked:
|
||||||
|
case bmp::StateChangeIdentification:
|
||||||
|
case bmp::StateChangeAuthentication:
|
||||||
|
case bmp::StateChangeModDownload:
|
||||||
|
case bmp::StateChangeSessionSetup:
|
||||||
|
case bmp::StateChangePlaying:
|
||||||
|
case bmp::StateChangeLeaving:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientNetwork::start_accept() {
|
||||||
|
m_acceptor.async_accept(m_game_socket, [this](const auto& ec) { handle_accept(ec); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientNetwork::handle_accept(boost::system::error_code ec) {
|
||||||
|
if (ec) {
|
||||||
|
spdlog::error("Failed accepting game connection: {}", ec.message());
|
||||||
|
} else {
|
||||||
|
spdlog::info("Game connected!");
|
||||||
|
auto game_ep = m_game_socket.remote_endpoint();
|
||||||
|
spdlog::debug("Game: [{}]:{}", game_ep.address().to_string(), game_ep.port());
|
||||||
|
handle_connection();
|
||||||
|
}
|
||||||
|
// TODO: We should probably accept() again somewhere once the game disconnected
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "ClientPacket.h"
|
#include "ClientPacket.h"
|
||||||
#include "ClientState.h"
|
#include "ClientState.h"
|
||||||
#include "Launcher.h"
|
#include "Launcher.h"
|
||||||
|
#include "Packet.h"
|
||||||
#include "Sync.h"
|
#include "Sync.h"
|
||||||
#include "Version.h"
|
#include "Version.h"
|
||||||
|
|
||||||
@ -19,11 +20,14 @@ public:
|
|||||||
|
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
|
void handle_server_packet(bmp::Packet&& packet);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handle_connection(ip::tcp::socket&& socket);
|
void start_accept();
|
||||||
bmp::ClientPacket client_tcp_read();
|
void handle_accept(boost::system::error_code ec);
|
||||||
|
|
||||||
|
void handle_connection();
|
||||||
|
void client_tcp_read(std::function<void(bmp::ClientPacket&&)> handler);
|
||||||
void client_tcp_write(bmp::ClientPacket& packet);
|
void client_tcp_write(bmp::ClientPacket& packet);
|
||||||
|
|
||||||
void handle_packet(bmp::ClientPacket& packet);
|
void handle_packet(bmp::ClientPacket& packet);
|
||||||
@ -56,5 +60,12 @@ private:
|
|||||||
Sync<bool> m_shutdown { false };
|
Sync<bool> m_shutdown { false };
|
||||||
bmp::ClientState m_client_state;
|
bmp::ClientState m_client_state;
|
||||||
|
|
||||||
|
ip::tcp::acceptor m_acceptor { m_io };
|
||||||
|
boost::asio::strand<ip::tcp::socket::executor_type> m_strand { m_game_socket.get_executor() };
|
||||||
|
|
||||||
|
// temporary packet and header buffer for async reads
|
||||||
|
bmp::ClientPacket m_tmp_packet {};
|
||||||
|
std::vector<uint8_t> m_tmp_header_buffer {};
|
||||||
|
|
||||||
Launcher& launcher;
|
Launcher& launcher;
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
#include "ServerNetwork.h"
|
#include "ServerNetwork.h"
|
||||||
#include "ClientInfo.h"
|
#include "ClientInfo.h"
|
||||||
|
#include "ClientPacket.h"
|
||||||
|
#include "ClientTransport.h"
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
#include "ImplementationInfo.h"
|
#include "ImplementationInfo.h"
|
||||||
#include "Launcher.h"
|
#include "Launcher.h"
|
||||||
|
#include "Packet.h"
|
||||||
#include "ProtocolVersion.h"
|
#include "ProtocolVersion.h"
|
||||||
#include "ServerInfo.h"
|
#include "ServerInfo.h"
|
||||||
#include "Transport.h"
|
#include "Transport.h"
|
||||||
|
#include "ClientNetwork.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
@ -19,6 +23,7 @@ ServerNetwork::ServerNetwork(Launcher& launcher, const ip::tcp::endpoint& ep)
|
|||||||
if (ec) {
|
if (ec) {
|
||||||
throw std::runtime_error(ec.message());
|
throw std::runtime_error(ec.message());
|
||||||
}
|
}
|
||||||
|
launcher.client_network->handle_server_packet(bmp::Packet {});
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerNetwork::~ServerNetwork() {
|
ServerNetwork::~ServerNetwork() {
|
||||||
|
@ -89,6 +89,8 @@ int main(int argc, char** argv) {
|
|||||||
launcher.start_game();
|
launcher.start_game();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
launcher.client_network->handle_server_packet(bmp::Packet {});
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user