From 65159b9546484286e99061a36cafe1a3e29c056d Mon Sep 17 00:00:00 2001 From: Hirek193 Date: Sun, 6 Sep 2026 19:58:28 +0000 Subject: [PATCH] multiplayer: the session imposes the settings that decide the physics server_hello.config had been a TODO carrying a zero, and every peer ran with whatever its own eu07.ini happened to say - including a vehicle physics thread count, which makes the order vehicles are stepped in depend on how threads get scheduled. - the handshake now carries a bitfield of the settings that change how the physics comes out (full physics, realistic control) and a joining peer takes them on, saying in the log what changed - a multiplayer session runs the vehicle physics on one thread on every peer, host included Settings that only affect what a player sees or how comfortable the controls feel stay with the player; only what alters the outcome belongs in here. --- application/application.cpp | 3 +++ network/message.h | 1 + network/network.cpp | 4 ++-- network/session.cpp | 37 +++++++++++++++++++++++++++++++++++++ network/session.h | 15 +++++++++++++++ 5 files changed, 58 insertions(+), 2 deletions(-) diff --git a/application/application.cpp b/application/application.cpp index b9d89ac0..ddc2c4a9 100644 --- a/application/application.cpp +++ b/application/application.cpp @@ -1578,6 +1578,9 @@ bool eu07_application::init_network() // create network manager m_network.emplace(); + // settings a session cannot run without, whichever side we are on + network::enforce_session_settings(); + // the host takes part in the session like any other peer, with an identity of its // own, so that crew and permission handling needs no special case for it if (!Global.network_client) diff --git a/network/message.h b/network/message.h index 6a28db8b..315218f4 100644 --- a/network/message.h +++ b/network/message.h @@ -69,6 +69,7 @@ struct server_hello : public message uint32_t seed; int64_t timestamp; + // settings the server imposes on the whole session, see network/session.h int64_t config; std::string scenario; // build identification of the server, informational only diff --git a/network/network.cpp b/network/network.cpp index 0ef5de18..e6bcbf7a 100644 --- a/network/network.cpp +++ b/network/network.cpp @@ -168,7 +168,7 @@ void network::server::handle_message(std::shared_ptr conn, const mes server_hello reply; reply.seed = Global.random_seed; reply.timestamp = Global.starting_timestamp; - reply.config = 0; // TODO: pass bitfield with state of relevant setting switches + reply.config = pack_session_config(); reply.scenario = Global.SceneryFile; reply.app_version = Global.asVersion; reply.session_token = cmd.session_token; @@ -433,7 +433,7 @@ void network::client::handle_message(std::shared_ptr conn, const mes Global.random_seed = cmd.seed; Global.random_engine.seed(Global.random_seed); Global.starting_timestamp = cmd.timestamp; - // TODO: configure simulation settings according to received cmd.config + apply_session_config(cmd.config); Global.SceneryFile = cmd.scenario; Global.ready_to_load = true; diff --git a/network/session.cpp b/network/session.cpp index 80118fca..98e89d85 100644 --- a/network/session.cpp +++ b/network/session.cpp @@ -184,6 +184,43 @@ bool crew_registry::leave(PeerId Peer, NetworkEntityId Id) return true; } +int64_t pack_session_config() +{ + int64_t config{0}; + + if (Global.FullPhysics) + config |= CONFIG_FULLPHYSICS; + if (Global.RealisticControlMode) + config |= CONFIG_REALISTICCONTROL; + + return config; +} + +void apply_session_config(int64_t Config) +{ + bool const fullphysics{(Config & CONFIG_FULLPHYSICS) != 0}; + bool const realisticcontrol{(Config & CONFIG_REALISTICCONTROL) != 0}; + + if (Global.FullPhysics != fullphysics) + WriteLog(std::string("net: the session runs with full physics ") + (fullphysics ? "on" : "off"), logtype::net); + if (Global.RealisticControlMode != realisticcontrol) + WriteLog(std::string("net: the session runs with realistic control ") + (realisticcontrol ? "on" : "off"), logtype::net); + + Global.FullPhysics = fullphysics; + Global.RealisticControlMode = realisticcontrol; +} + +void enforce_session_settings() +{ + if (Global.trainThreads != 0) + { + // the order vehicles are stepped in must not depend on how threads happen to be + // scheduled; a session cannot afford that kind of drift + WriteLog("net: multiplayer session, running the vehicle physics on one thread", logtype::net); + Global.trainThreads = 0; + } +} + PeerId resolve_peer_identity(uint64_t &Token) { static std::unordered_map known; diff --git a/network/session.h b/network/session.h index 51058c14..6b5ebee8 100644 --- a/network/session.h +++ b/network/session.h @@ -102,6 +102,21 @@ extern crew_registry Crews; // how long a disconnected peer keeps its place in the crew constexpr double RECONNECT_GRACE_SECONDS = 60.0; +// settings the server imposes on everybody, carried in the handshake. only things that +// change how the physics comes out belong here - looks and comfort stay with the player +enum session_config_flags : int64_t +{ + CONFIG_FULLPHYSICS = 1 << 0, + CONFIG_REALISTICCONTROL = 1 << 1 +}; + +// packs the settings this machine is running, for the server to hand out +int64_t pack_session_config(); +// takes on the settings the server handed us +void apply_session_config(int64_t Config); +// settings a session needs regardless of who set what, applied on every peer +void enforce_session_settings(); + // resolves the identity of a connecting peer. an unknown or empty token means somebody // new and gets a fresh peer id together with a token of their own; a token this server // handed out before brings back the peer id that went with it, and with it the seat in