mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2025-07-01 23:35:41 +00:00
implement session sync
This commit is contained in:
parent
bde689d31a
commit
630d5f1cfa
@ -120,6 +120,8 @@ struct Vehicle {
|
||||
m_status_data = raw_packet;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t>& get_raw_status() const { return m_status_data; }
|
||||
|
||||
private:
|
||||
std::recursive_mutex m_mtx;
|
||||
|
||||
@ -163,14 +165,10 @@ public:
|
||||
|
||||
std::unordered_map<VehicleID, Vehicle::Ptr> get_vehicles_owned_by(ClientID id);
|
||||
|
||||
std::optional<Vehicle::Ptr> get_vehicle(VehicleID id) {
|
||||
auto vehicles = m_vehicles.synchronize();
|
||||
if (vehicles->contains(id)) {
|
||||
return vehicles->at(id);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
std::optional<Vehicle::Ptr> get_vehicle(VehicleID id);
|
||||
|
||||
/// Builds the SessionSetup.PlayersInfo json which contains all player info and all vehicles.
|
||||
nlohmann::json build_players_info();
|
||||
|
||||
size_t authenticated_client_count() const;
|
||||
|
||||
@ -199,11 +197,16 @@ private:
|
||||
void udp_read_main();
|
||||
void tcp_listen_main();
|
||||
|
||||
/// Handles all packets which are allowed during the Identification state.
|
||||
void handle_identification(ClientID id, const bmp::Packet& packet, std::shared_ptr<Client>& client);
|
||||
|
||||
/// Handles all packets which are allowed during the Authentication state.
|
||||
void handle_authentication(ClientID id, const bmp::Packet& packet, std::shared_ptr<Client>& client);
|
||||
|
||||
/// Handles all packets which are allowed during the ModDownload state.
|
||||
void handle_mod_download(ClientID id, const bmp::Packet& packet, std::shared_ptr<Client>& client);
|
||||
/// Handles all packets which are allowed during the SessionSetup state.
|
||||
void handle_session_setup(ClientID id, const bmp::Packet& packet, std::shared_ptr<Client>& client);
|
||||
/// Handles all packets which are allowed during the Playing state.
|
||||
void handle_playing(ClientID id, const bmp::Packet& packet, std::shared_ptr<Client>& client);
|
||||
|
||||
/// On failure, throws an exception with the error for the client.
|
||||
static void authenticate_user(const std::string& public_key, std::shared_ptr<Client>& client);
|
||||
@ -216,13 +219,7 @@ private:
|
||||
Sync<std::unordered_map<uint64_t, ClientID>> m_client_magics {};
|
||||
Sync<std::unordered_map<ip::udp::endpoint, ClientID>> m_udp_endpoints {};
|
||||
|
||||
ClientID new_client_id() {
|
||||
static Sync<ClientID> s_id { 0 };
|
||||
auto id = s_id.synchronize();
|
||||
ClientID new_id = *id;
|
||||
*id += 1;
|
||||
return new_id;
|
||||
}
|
||||
ClientID new_client_id();
|
||||
|
||||
thread_pool m_threadpool { std::thread::hardware_concurrency() };
|
||||
Sync<bool> m_shutdown { false };
|
||||
|
@ -607,13 +607,41 @@ void Network::handle_packet(ClientID id, const bmp::Packet& packet) {
|
||||
handle_mod_download(id, packet, client);
|
||||
break;
|
||||
case bmp::State::SessionSetup:
|
||||
handle_session_setup(id, packet, client);
|
||||
break;
|
||||
case bmp::State::Playing:
|
||||
handle_playing(id, packet, client);
|
||||
break;
|
||||
case bmp::State::Leaving:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Network::handle_playing(ClientID id, const bmp::Packet& packet, std::shared_ptr<Client>& client) {
|
||||
switch (packet.purpose) {
|
||||
|
||||
default:
|
||||
beammp_errorf("Got 0x{:x} in state {}. This is not allowed. Disconnecting the client", uint16_t(packet.purpose), int(client->state.get()));
|
||||
disconnect(id, "invalid purpose in current state");
|
||||
}
|
||||
}
|
||||
|
||||
void Network::handle_session_setup(ClientID id, const bmp::Packet& packet, std::shared_ptr<Client>& client) {
|
||||
switch (packet.purpose) {
|
||||
case bmp::Purpose::SessionReady: {
|
||||
beammp_infof("Client {} is synced", id);
|
||||
bmp::Packet state_change {
|
||||
.purpose = bmp::Purpose::StateChangePlaying,
|
||||
};
|
||||
client->tcp_write(state_change);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
beammp_errorf("Got 0x{:x} in state {}. This is not allowed. Disconnecting the client", uint16_t(packet.purpose), int(client->state.get()));
|
||||
disconnect(id, "invalid purpose in current state");
|
||||
}
|
||||
}
|
||||
|
||||
void Network::handle_identification(ClientID id, const bmp::Packet& packet, std::shared_ptr<Client>& client) {
|
||||
switch (packet.purpose) {
|
||||
case bmp::ProtocolVersion: {
|
||||
@ -733,6 +761,25 @@ void Network::handle_mod_download(ClientID id, const bmp::Packet& packet, std::s
|
||||
.purpose = bmp::Purpose::StateChangeSessionSetup,
|
||||
};
|
||||
client->tcp_write(state_change);
|
||||
|
||||
beammp_infof("Client {} starting session sync.", id);
|
||||
beammp_debugf("Syncing {} client(s) and {} vehicle(s) to client {}", m_clients->size(), m_vehicles->size(), id);
|
||||
// immediately start with the player+vehicle info
|
||||
bmp::Packet players_info {
|
||||
.purpose = bmp::Purpose::PlayersVehiclesInfo,
|
||||
.raw_data = {},
|
||||
};
|
||||
try {
|
||||
auto players_info_json = build_players_info();
|
||||
beammp_tracef("Players and vehicles info: {}", players_info_json.dump(4));
|
||||
auto serialized = players_info_json.dump();
|
||||
players_info.raw_data = std::vector<uint8_t>(serialized.begin(), serialized.end());
|
||||
} catch (const std::exception& e) {
|
||||
beammp_errorf("Failed to construct players and vehicles info for session setup: {}. This is not recoverable, kicking client.", e.what());
|
||||
disconnect(id, "Internal server error: Session setup failed to construct players and vehicles info object");
|
||||
return;
|
||||
}
|
||||
client->tcp_write(players_info);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -928,3 +975,50 @@ size_t Network::clients_in_state_count(bmp::State state) const {
|
||||
}
|
||||
|
||||
size_t Network::vehicle_count() const { return m_vehicles->size(); }
|
||||
nlohmann::json Network::build_players_info() {
|
||||
auto all = boost::synchronize(m_clients, m_vehicles);
|
||||
auto& clients = std::get<0>(all);
|
||||
auto& vehicles = std::get<1>(all);
|
||||
nlohmann::json info = nlohmann::json::array();
|
||||
for (const auto& [id, client] : *clients) {
|
||||
auto obj = nlohmann::json({
|
||||
{ "name", client->name.get() },
|
||||
{ "id", client->id },
|
||||
{ "role", client->role },
|
||||
});
|
||||
obj["vehicles"] = nlohmann::json::array();
|
||||
// get all vehicles owned by this client
|
||||
// cant use the helper function since that locks as well, that's not clean
|
||||
for (const auto& [vid, vehicle] : *vehicles) {
|
||||
if (vehicle->owner == id) {
|
||||
// vehicle owned by client
|
||||
auto data = vehicle->data.synchronize();
|
||||
auto status = vehicle->get_raw_status();
|
||||
obj["vehicles"] = nlohmann::json::object({
|
||||
{ "id", vid },
|
||||
{ "data", nlohmann::json::parse(data->begin(), data->end()) },
|
||||
{ "status", nlohmann::json::parse(status.begin(), status.end()) },
|
||||
});
|
||||
}
|
||||
}
|
||||
info.push_back(std::move(obj));
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
std::optional<Vehicle::Ptr> Network::get_vehicle(VehicleID id) {
|
||||
auto vehicles = m_vehicles.synchronize();
|
||||
if (vehicles->contains(id)) {
|
||||
return vehicles->at(id);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
ClientID Network::new_client_id() {
|
||||
static Sync<ClientID> s_id { 0 };
|
||||
auto id = s_id.synchronize();
|
||||
ClientID new_id = *id;
|
||||
*id += 1;
|
||||
return new_id;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user