mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-19 07:19:18 +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.
99 lines
3.2 KiB
C++
99 lines
3.2 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/.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <unordered_map>
|
|
|
|
class TDynamicObject;
|
|
|
|
namespace network
|
|
{
|
|
|
|
// identifies a participant of the session. the host is a participant like any other,
|
|
// so that peer/crew/permission handling does not need a special case for it
|
|
using PeerId = uint32_t;
|
|
constexpr PeerId PEER_NONE = 0;
|
|
constexpr PeerId PEER_HOST = 1;
|
|
// remote peers are numbered from here up
|
|
constexpr PeerId PEER_FIRST_REMOTE = 2;
|
|
|
|
// identifies a vehicle for the whole session. unlike TTrain::id() this does not depend
|
|
// on the order in which a particular peer happened to create its trains
|
|
using NetworkEntityId = uint32_t;
|
|
constexpr NetworkEntityId ENTITY_NONE = 0;
|
|
|
|
// how many people may share one vehicle. the crew itself is a plain container,
|
|
// so raising this number does not call for a structural change
|
|
constexpr uint8_t CREW_CAPACITY = 2;
|
|
|
|
// authoritative description of a single drivable vehicle, as published by the server
|
|
struct vehicle_entry
|
|
{
|
|
NetworkEntityId id{ENTITY_NONE};
|
|
std::string name;
|
|
uint8_t crew_count{0};
|
|
uint8_t crew_capacity{CREW_CAPACITY};
|
|
bool ai_active{false};
|
|
bool claimable{false};
|
|
|
|
bool operator==(vehicle_entry const &Other) const
|
|
{
|
|
return id == Other.id && name == Other.name && crew_count == Other.crew_count && crew_capacity == Other.crew_capacity && ai_active == Other.ai_active &&
|
|
claimable == Other.claimable;
|
|
}
|
|
bool operator!=(vehicle_entry const &Other) const { return !(*this == Other); }
|
|
};
|
|
|
|
// maps stable network ids onto the vehicles of the loaded scenario.
|
|
// the server owns the numbering and publishes it; a client binds the received ids to
|
|
// its own copy of the scenario by vehicle name, which keeps the runtime protocol on ids
|
|
class entity_registry
|
|
{
|
|
public:
|
|
// server side: builds the numbering from the loaded scenario. vehicles are ordered by
|
|
// name so that the result does not depend on the order the scenario happened to spawn them
|
|
void build();
|
|
// client side: takes over the numbering published by the server
|
|
void adopt(std::vector<vehicle_entry> const &Entries);
|
|
// server side: refreshes the volatile part of the published entries
|
|
void refresh();
|
|
void clear();
|
|
|
|
bool empty() const { return m_entries.empty(); }
|
|
std::vector<vehicle_entry> const &entries() const { return m_entries; }
|
|
|
|
NetworkEntityId id_of(std::string const &Name) const;
|
|
NetworkEntityId id_of(TDynamicObject const *Vehicle) const;
|
|
std::string name_of(NetworkEntityId Id) const;
|
|
TDynamicObject *resolve(NetworkEntityId Id) const;
|
|
vehicle_entry const *find(NetworkEntityId Id) const;
|
|
|
|
private:
|
|
void reindex();
|
|
|
|
std::vector<vehicle_entry> m_entries;
|
|
std::unordered_map<std::string, NetworkEntityId> m_byname;
|
|
std::unordered_map<NetworkEntityId, size_t> m_byid;
|
|
};
|
|
|
|
// session wide vehicle registry. stays empty outside of multiplayer
|
|
extern entity_registry Entities;
|
|
|
|
// hands out ids for connecting peers; PEER_HOST is reserved for the local participant
|
|
PeerId allocate_peer_id();
|
|
|
|
// true for vehicles a player can take over
|
|
bool is_drivable(TDynamicObject const *Vehicle);
|
|
|
|
} // namespace network
|