mirror of
https://github.com/BeamMP/BeamMP-Launcher.git
synced 2025-07-04 00:47:23 +00:00
fix not reading continuously and other async bugs
This commit is contained in:
parent
29b4fa9b81
commit
4e304f798e
@ -5,6 +5,7 @@
|
||||
#include "Identity.h"
|
||||
#include "Launcher.h"
|
||||
|
||||
#include <boost/asio/socket_base.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
@ -51,23 +52,27 @@ ClientNetwork::~ClientNetwork() {
|
||||
spdlog::debug("Client network destroyed");
|
||||
}
|
||||
|
||||
void ClientNetwork::start_read() {
|
||||
client_tcp_read([this](auto&& packet) {
|
||||
handle_packet(packet);
|
||||
start_read();
|
||||
});
|
||||
}
|
||||
|
||||
void ClientNetwork::handle_connection() {
|
||||
// immediately send launcher info (first step of client identification)
|
||||
m_client_state = bmp::ClientState::ClientIdentification;
|
||||
|
||||
bmp::ClientPacket info_packet {};
|
||||
info_packet.purpose = bmp::ClientPurpose::LauncherInfo;
|
||||
info_packet.raw_data = json_to_vec(
|
||||
client_tcp_write(bmp::ClientPacket {
|
||||
.purpose = bmp::ClientPurpose::LauncherInfo,
|
||||
.raw_data = json_to_vec(
|
||||
{
|
||||
{ "implementation", "Official BeamMP Launcher" },
|
||||
{ "version", { PRJ_VERSION_MAJOR, PRJ_VERSION_MINOR, PRJ_VERSION_PATCH } },
|
||||
{ "mod_cache_path", "/idk sorry/" }, // TODO: mod_cache_path in LauncherInfo
|
||||
});
|
||||
client_tcp_write(info_packet);
|
||||
}) });
|
||||
|
||||
client_tcp_read([this](auto&& packet) {
|
||||
handle_packet(packet);
|
||||
});
|
||||
start_read();
|
||||
|
||||
// packet read and respond loop
|
||||
/*
|
||||
@ -159,10 +164,9 @@ void ClientNetwork::handle_client_identification(bmp::ClientPacket& packet) {
|
||||
}
|
||||
|
||||
void ClientNetwork::start_login() {
|
||||
bmp::ClientPacket state_change {
|
||||
client_tcp_write(bmp::ClientPacket {
|
||||
.purpose = bmp::ClientPurpose::StateChangeLogin,
|
||||
};
|
||||
client_tcp_write(state_change);
|
||||
});
|
||||
|
||||
m_client_state = bmp::ClientState::Login;
|
||||
|
||||
@ -172,7 +176,7 @@ void ClientNetwork::start_login() {
|
||||
// we just send the login result and continue to the next state.
|
||||
if (login.has_value()) {
|
||||
*m_identity = login.value();
|
||||
bmp::ClientPacket login_result {
|
||||
client_tcp_write(bmp::ClientPacket {
|
||||
.purpose = bmp::ClientPurpose::LoginResult,
|
||||
.raw_data = json_to_vec({
|
||||
{ "success", true },
|
||||
@ -180,7 +184,7 @@ void ClientNetwork::start_login() {
|
||||
{ "username", m_identity->Username },
|
||||
{ "role", m_identity->Role },
|
||||
}),
|
||||
};
|
||||
});
|
||||
// move on to quick join right away
|
||||
start_quick_join();
|
||||
return; // done
|
||||
@ -193,22 +197,25 @@ void ClientNetwork::start_login() {
|
||||
|
||||
// first packet in login
|
||||
// TODO: send LoginResult if already logged in.
|
||||
bmp::ClientPacket ask_for_creds {
|
||||
client_tcp_write(bmp::ClientPacket {
|
||||
.purpose = bmp::ClientPurpose::AskForCredentials,
|
||||
};
|
||||
client_tcp_write(ask_for_creds);
|
||||
});
|
||||
// wait for response, so return
|
||||
}
|
||||
|
||||
void ClientNetwork::disconnect(const std::string& reason) {
|
||||
spdlog::debug("Disconnecting game: {}", reason);
|
||||
bmp::ClientPacket error {
|
||||
client_tcp_write(bmp::ClientPacket {
|
||||
.purpose = bmp::ClientPurpose::Error,
|
||||
.raw_data = json_to_vec({ "message", reason })
|
||||
};
|
||||
client_tcp_write(error);
|
||||
m_game_socket.close();
|
||||
.raw_data = json_to_vec({ "message", reason }) },
|
||||
[this](auto ec) {
|
||||
// ignore any error and just shut down
|
||||
// we pass `ec` to both of these and ignore their errors as well
|
||||
// because we dont care if they fail
|
||||
m_game_socket.shutdown(boost::asio::socket_base::shutdown_both, ec);
|
||||
m_game_socket.close(ec);
|
||||
start_accept();
|
||||
});
|
||||
}
|
||||
|
||||
void ClientNetwork::handle_login(bmp::ClientPacket& packet) {
|
||||
@ -223,22 +230,21 @@ void ClientNetwork::handle_login(bmp::ClientPacket& packet) {
|
||||
// login!
|
||||
auto result = ident::login(username, password, remember);
|
||||
if (result.has_error()) {
|
||||
bmp::ClientPacket login_fail {
|
||||
;
|
||||
client_tcp_write(bmp::ClientPacket {
|
||||
.purpose = bmp::ClientPurpose::LoginResult,
|
||||
.raw_data = json_to_vec({
|
||||
{ "success", false },
|
||||
{ "message", result.error() },
|
||||
}),
|
||||
};
|
||||
client_tcp_write(login_fail);
|
||||
bmp::ClientPacket retry {
|
||||
});
|
||||
client_tcp_write(bmp::ClientPacket {
|
||||
.purpose = bmp::ClientPurpose::AskForCredentials,
|
||||
};
|
||||
client_tcp_write(retry);
|
||||
});
|
||||
return;
|
||||
}
|
||||
*m_identity = result.value();
|
||||
bmp::ClientPacket login_result {
|
||||
client_tcp_write(bmp::ClientPacket {
|
||||
.purpose = bmp::ClientPurpose::LoginResult,
|
||||
.raw_data = json_to_vec({
|
||||
{ "success", true },
|
||||
@ -246,8 +252,7 @@ void ClientNetwork::handle_login(bmp::ClientPacket& packet) {
|
||||
{ "username", m_identity->Username },
|
||||
{ "role", m_identity->Role },
|
||||
}),
|
||||
};
|
||||
client_tcp_write(login_result);
|
||||
});
|
||||
|
||||
start_quick_join();
|
||||
} catch (const std::exception& e) {
|
||||
@ -274,18 +279,16 @@ void ClientNetwork::handle_browsing(bmp::ClientPacket& packet) {
|
||||
case bmp::ClientPurpose::ServerListRequest: {
|
||||
auto list = load_server_list();
|
||||
if (list.has_value()) {
|
||||
bmp::ClientPacket response {
|
||||
client_tcp_write(bmp::ClientPacket {
|
||||
.purpose = bmp::ClientPurpose::ServerListResponse,
|
||||
.raw_data = list.value(),
|
||||
};
|
||||
client_tcp_write(response);
|
||||
});
|
||||
} else {
|
||||
spdlog::error("Failed to load server list: {}", list.error());
|
||||
bmp::ClientPacket err {
|
||||
client_tcp_write(bmp::ClientPacket {
|
||||
.purpose = bmp::ClientPurpose::Error,
|
||||
.raw_data = json_to_vec({ "message", list.error() }),
|
||||
};
|
||||
client_tcp_write(err);
|
||||
});
|
||||
}
|
||||
} break;
|
||||
case bmp::ClientPurpose::Logout: {
|
||||
@ -369,6 +372,11 @@ void ClientNetwork::client_tcp_read(std::function<void(bmp::ClientPacket&&)> han
|
||||
m_tmp_packet.raw_data.resize(hdr.data_size);
|
||||
m_tmp_packet.purpose = hdr.purpose;
|
||||
m_tmp_packet.flags = hdr.flags;
|
||||
spdlog::debug("Got header: purpose: 0x{:x}, flags: 0x{:x}, pid: {}, vid: {}, size: {}",
|
||||
uint16_t(m_tmp_packet.purpose),
|
||||
uint8_t(m_tmp_packet.flags),
|
||||
m_tmp_packet.pid, m_tmp_packet.vid,
|
||||
m_tmp_packet.get_readable_data().size());
|
||||
boost::asio::async_read(m_game_socket, buffer(m_tmp_packet.raw_data),
|
||||
bind_executor(m_strand, [handler, this](auto ec, auto) {
|
||||
if (ec) {
|
||||
@ -382,21 +390,29 @@ void ClientNetwork::client_tcp_read(std::function<void(bmp::ClientPacket&&)> han
|
||||
}));
|
||||
}
|
||||
|
||||
void ClientNetwork::client_tcp_write(bmp::ClientPacket& packet) {
|
||||
void ClientNetwork::client_tcp_write(bmp::ClientPacket&& packet, std::function<void(boost::system::error_code)> handler) {
|
||||
auto header = packet.finalize();
|
||||
// copy packet
|
||||
auto owned_packet = std::make_shared<bmp::ClientPacket>(std::move(packet));
|
||||
// serialize header
|
||||
auto data = std::make_shared<std::vector<uint8_t>>(bmp::ClientHeader::SERIALIZED_SIZE + packet.raw_data.size());
|
||||
auto offset = header.serialize_to(*data);
|
||||
// copy packet data (yes i know ugh) to the `data` in order to send it in one go
|
||||
std::copy(packet.raw_data.begin(), packet.raw_data.end(), data->begin() + long(offset));
|
||||
boost::asio::async_write(m_game_socket, buffer(*data),
|
||||
[this, packet, data](auto ec, auto) {
|
||||
if (ec) {
|
||||
spdlog::error("Failed to write a packet: {}", ec.message());
|
||||
disconnect("Failed to send data to game");
|
||||
auto header_data = std::make_shared<std::vector<uint8_t>>(bmp::ClientHeader::SERIALIZED_SIZE);
|
||||
header.serialize_to(*header_data);
|
||||
std::array<const_buffer, 2> buffers = {
|
||||
buffer(*header_data),
|
||||
buffer(owned_packet->raw_data)
|
||||
};
|
||||
boost::asio::async_write(m_game_socket, buffers,
|
||||
[this, header_data, owned_packet, handler](auto ec, auto size) {
|
||||
spdlog::debug("Wrote {} bytes for 0x{:x}", size, int(owned_packet->purpose));
|
||||
if (handler) {
|
||||
handler(ec);
|
||||
} else {
|
||||
// ok! sent all data
|
||||
spdlog::debug("Sent packet: 0x{:x}", int(packet.purpose));
|
||||
if (ec) {
|
||||
disconnect(fmt::format("Failed to send packet to game: {}", ec.message()));
|
||||
} else {
|
||||
// ok!
|
||||
spdlog::debug("Sent packet of type 0x{:x}", int(owned_packet->purpose));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -409,10 +425,9 @@ nlohmann::json ClientNetwork::vec_to_json(const std::vector<uint8_t>& vec) {
|
||||
return json::parse(std::string(vec.begin(), vec.end()));
|
||||
}
|
||||
void ClientNetwork::start_quick_join() {
|
||||
bmp::ClientPacket change_to_quickjoin {
|
||||
client_tcp_write(bmp::ClientPacket {
|
||||
.purpose = bmp::ClientPurpose::StateChangeQuickJoin,
|
||||
};
|
||||
client_tcp_write(change_to_quickjoin);
|
||||
});
|
||||
m_client_state = bmp::ClientState::QuickJoin;
|
||||
|
||||
// TODO: Implement DoJoin, etc
|
||||
@ -421,10 +436,9 @@ void ClientNetwork::start_quick_join() {
|
||||
}
|
||||
|
||||
void ClientNetwork::start_browsing() {
|
||||
bmp::ClientPacket change_to_browsing {
|
||||
client_tcp_write(bmp::ClientPacket {
|
||||
.purpose = bmp::ClientPurpose::StateChangeBrowsing,
|
||||
};
|
||||
client_tcp_write(change_to_browsing);
|
||||
});
|
||||
m_client_state = bmp::ClientState::Browsing;
|
||||
}
|
||||
|
||||
|
@ -26,9 +26,11 @@ private:
|
||||
void start_accept();
|
||||
void handle_accept(boost::system::error_code ec);
|
||||
|
||||
void start_read();
|
||||
|
||||
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, std::function<void(boost::system::error_code)> handler = nullptr);
|
||||
|
||||
void handle_packet(bmp::ClientPacket& packet);
|
||||
void handle_client_identification(bmp::ClientPacket& packet);
|
||||
|
Loading…
x
Reference in New Issue
Block a user