mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-18 03:19:19 +02:00
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.
120 lines
3.4 KiB
C++
120 lines
3.4 KiB
C++
/*
|
|
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);
|
|
}
|