mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-18 03:19:19 +02:00
multiplayer stage 2: peer identity, stable vehicle ids and a session lobby
TTrain::id() numbers cabs with a local counter, in the order each peer happens to create them, so it cannot address a vehicle across the session. Neither was there any way for a player to see what is available to drive. - network/entities: PeerId (the host is peer 1, remote peers are numbered from 2, so it is a participant rather than a special case) and NetworkEntityId, plus a registry that numbers the drivable vehicles of the loaded scenario in name order and resolves ids back to TDynamicObject - the server owns the numbering and publishes it as VEHICLE_LIST - name, crew occupancy, crew capacity, AI state, availability - on every change and at least every 120 frames, out of band so it stays out of the replay backbuffer; a client binds the received ids to its own copy of the scenario by name - SERVER_HELLO hands the joining peer its PeerId - a multiplayer lobby listing that roster, with vehicles taken by other players shown as such rather than hidden; entering one goes through the existing entervehicle command, the vehicle is never moved The lobby lives inside the driver mode instead of a mode of its own: the world has to keep running while somebody is choosing (a client stops consuming the server's frames the moment its mode is not a command processor), and the same screen is what a player needs to change vehicles later on. Crew occupancy is still derived from the presence of a cab instance; the real crew model, claim handshake and AI takeover follow in stage 3.
This commit is contained in:
119
widgets/multiplayer_lobby.cpp
Normal file
119
widgets/multiplayer_lobby.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "widgets/multiplayer_lobby.h"
|
||||
|
||||
#include "application/application.h"
|
||||
#include "network/entities.h"
|
||||
#include "simulation/simulation.h"
|
||||
#include "utilities/Globals.h"
|
||||
#include "utilities/utilities.h"
|
||||
#include "utilities/translation.h"
|
||||
#include "vehicle/Driver.h"
|
||||
#include "vehicle/DynObj.h"
|
||||
#include "vehicle/Train.h"
|
||||
|
||||
ui::multiplayer_lobby_panel::multiplayer_lobby_panel()
|
||||
: ui_panel(STR_C("Multiplayer lobby"), false)
|
||||
{
|
||||
size_min = {480, 260};
|
||||
}
|
||||
|
||||
void ui::multiplayer_lobby_panel::enter_vehicle(std::string const &Name)
|
||||
{
|
||||
TDynamicObject *vehicle = simulation::Vehicles.find(Name);
|
||||
if (vehicle == nullptr)
|
||||
return;
|
||||
|
||||
std::string payload{Name};
|
||||
// the request travels as an ordinary simulation command, so every peer builds the cab
|
||||
m_relay.post(user_command::entervehicle, 0.0, simulation::Train ? simulation::Train->id() : 0, GLFW_PRESS, 0, vehicle->GetPosition(), &payload);
|
||||
// ...and the driver mode moves our own camera in once the cab shows up locally
|
||||
Global.network_pending_vehicle = Name;
|
||||
is_open = false;
|
||||
}
|
||||
|
||||
void ui::multiplayer_lobby_panel::render_contents()
|
||||
{
|
||||
bool const host{Application.is_server()};
|
||||
bool const client{Application.is_client()};
|
||||
|
||||
if (!host && !client)
|
||||
{
|
||||
ImGui::TextUnformatted(STR_C("This is not a multiplayer session."));
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::Text("%s: %s, peer %u", STR_C("Session"), host ? (client ? "host + client" : "host") : "client", Global.network_peer_id);
|
||||
ImGui::TextUnformatted(Global.SceneryFile.c_str());
|
||||
ImGui::Separator();
|
||||
|
||||
auto const &entries = network::Entities.entries();
|
||||
if (entries.empty())
|
||||
{
|
||||
ImGui::TextUnformatted(STR_C("Waiting for the vehicle list from the server..."));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string const currentvehicle{simulation::Train != nullptr && simulation::Train->Dynamic() != nullptr ? simulation::Train->Dynamic()->name() : std::string()};
|
||||
|
||||
if (!FreeFlyModeFlag)
|
||||
{
|
||||
ImGui::TextUnformatted(STR_C("Leave the cab to change vehicles."));
|
||||
ImGui::Separator();
|
||||
}
|
||||
|
||||
ImGui::Columns(4, "mp_vehicles", false);
|
||||
ImGui::SetColumnWidth(1, 80.0f * Global.ui_scale);
|
||||
ImGui::SetColumnWidth(2, 90.0f * Global.ui_scale);
|
||||
ImGui::SetColumnWidth(3, 130.0f * Global.ui_scale);
|
||||
|
||||
ImGui::TextDisabled("%s", STR_C("Vehicle"));
|
||||
ImGui::NextColumn();
|
||||
ImGui::TextDisabled("%s", STR_C("Crew"));
|
||||
ImGui::NextColumn();
|
||||
ImGui::TextDisabled("%s", STR_C("Driver"));
|
||||
ImGui::NextColumn();
|
||||
ImGui::NextColumn();
|
||||
ImGui::Separator();
|
||||
|
||||
for (auto const &entry : entries)
|
||||
{
|
||||
ImGui::PushID(static_cast<int>(entry.id));
|
||||
|
||||
ImGui::TextUnformatted(entry.name.c_str());
|
||||
ImGui::NextColumn();
|
||||
|
||||
ImGui::Text("%u/%u", (unsigned)entry.crew_count, (unsigned)entry.crew_capacity);
|
||||
ImGui::NextColumn();
|
||||
|
||||
ImGui::TextUnformatted(entry.crew_count > 0 ? STR_C("player") : entry.ai_active ? STR_C("AI") : STR_C("free"));
|
||||
ImGui::NextColumn();
|
||||
|
||||
if (entry.name == currentvehicle)
|
||||
{
|
||||
ImGui::TextUnformatted(STR_C("you"));
|
||||
}
|
||||
else if (entry.claimable && FreeFlyModeFlag && network::Entities.resolve(entry.id) != nullptr)
|
||||
{
|
||||
if (ImGui::Button(STR_C("Enter"), ImVec2(-1, 0)))
|
||||
enter_vehicle(entry.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::TextDisabled("%s", entry.claimable ? "-" : STR_C("occupied"));
|
||||
}
|
||||
ImGui::NextColumn();
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
ImGui::Columns(1);
|
||||
}
|
||||
Reference in New Issue
Block a user