mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-17 21:29:19 +02:00
Three things stood in the way of two people sharing a cab and of a client not
being able to reach past its own vehicle.
Vehicle commands were addressed by TTrain::id(), which every peer hands out
locally from its own counter, so the same number means a different vehicle on
a different peer. Commands now travel with the session wide NetworkEntityId
and are translated back to the local cab on arrival; outside of multiplayer
the registry is empty and both directions are a no-op, so singleplayer is
untouched.
A client could send any command it liked, including setweather, queueevent or
spawntrainset. The server now validates every incoming command: a player may
work the controls of the vehicle whose crew they are on and nothing else, and
world wide commands stay with the host until dispatcher roles exist. The
source is stamped by the server, never taken from what the peer sent, and
rejections are logged once per peer/command instead of every frame. Host input
runs through the very same validation, just without the transport.
Continuous commands were tracked per command and recipient only, so with two
people in one cab the release sent by one of them cancelled the other one's
hold. command_data now carries the source peer and the active set is keyed by
{source, recipient, command}.
Also: a client asking to quit no longer replicates quitsimulation, which would
have shut down everybody else's session.
559 lines
13 KiB
C++
559 lines
13 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 <unordered_map>
|
|
#include <queue>
|
|
#include <unordered_set>
|
|
|
|
enum class user_command
|
|
{
|
|
|
|
aidriverenable = 0,
|
|
aidriverdisable,
|
|
jointcontrollerset,
|
|
mastercontrollerincrease,
|
|
mastercontrollerincreasefast,
|
|
mastercontrollerdecrease,
|
|
mastercontrollerdecreasefast,
|
|
mastercontrollerset,
|
|
dynamicbrakecontrollerincrease,
|
|
dynamicbrakecontrollerdecrease,
|
|
dynamicbrakecontrollerset,
|
|
dynamicbrakecontrollerincreasefast,
|
|
dynamicbrakecontrollerdecreasefast,
|
|
secondcontrollerincrease,
|
|
secondcontrollerincreasefast,
|
|
secondcontrollerdecrease,
|
|
secondcontrollerdecreasefast,
|
|
secondcontrollerset,
|
|
mucurrentindicatorothersourceactivate,
|
|
independentbrakeincrease,
|
|
independentbrakeincreasefast,
|
|
independentbrakedecrease,
|
|
independentbrakedecreasefast,
|
|
independentbrakeset,
|
|
independentbrakebailoff,
|
|
universalbrakebutton1,
|
|
universalbrakebutton2,
|
|
universalbrakebutton3,
|
|
trainbrakeincrease,
|
|
trainbrakedecrease,
|
|
trainbrakeset,
|
|
trainbrakecharging,
|
|
trainbrakerelease,
|
|
trainbrakefirstservice,
|
|
trainbrakeservice,
|
|
trainbrakefullservice,
|
|
trainbrakehandleoff,
|
|
trainbrakeemergency,
|
|
trainbrakebasepressureincrease,
|
|
trainbrakebasepressuredecrease,
|
|
trainbrakebasepressurereset,
|
|
trainbrakeoperationtoggle,
|
|
manualbrakeincrease,
|
|
manualbrakedecrease,
|
|
alarmchaintoggle,
|
|
alarmchainenable,
|
|
alarmchaindisable,
|
|
wheelspinbrakeactivate,
|
|
sandboxactivate,
|
|
autosandboxtoggle,
|
|
autosandboxactivate,
|
|
autosandboxdeactivate,
|
|
reverserincrease,
|
|
reverserdecrease,
|
|
reverserforwardhigh,
|
|
reverserforward,
|
|
reverserneutral,
|
|
reverserbackward,
|
|
waterpumpbreakertoggle,
|
|
waterpumpbreakerclose,
|
|
waterpumpbreakeropen,
|
|
waterpumptoggle,
|
|
waterpumpenable,
|
|
waterpumpdisable,
|
|
waterheaterbreakertoggle,
|
|
waterheaterbreakerclose,
|
|
waterheaterbreakeropen,
|
|
waterheatertoggle,
|
|
waterheaterenable,
|
|
waterheaterdisable,
|
|
watercircuitslinktoggle,
|
|
watercircuitslinkenable,
|
|
watercircuitslinkdisable,
|
|
fuelpumptoggle,
|
|
fuelpumpenable,
|
|
fuelpumpdisable,
|
|
oilpumptoggle,
|
|
oilpumpenable,
|
|
oilpumpdisable,
|
|
linebreakertoggle,
|
|
linebreakeropen,
|
|
linebreakerclose,
|
|
convertertoggle,
|
|
converterenable,
|
|
converterdisable,
|
|
convertertogglelocal,
|
|
converteroverloadrelayreset,
|
|
compressortoggle,
|
|
compressorenable,
|
|
compressordisable,
|
|
compressortogglelocal,
|
|
compressorpresetactivatenext,
|
|
compressorpresetactivateprevious,
|
|
compressorpresetactivatedefault,
|
|
motoroverloadrelaythresholdtoggle,
|
|
motoroverloadrelaythresholdsetlow,
|
|
motoroverloadrelaythresholdsethigh,
|
|
motoroverloadrelayreset,
|
|
universalrelayreset1,
|
|
universalrelayreset2,
|
|
universalrelayreset3,
|
|
notchingrelaytoggle,
|
|
epbrakecontroltoggle,
|
|
epbrakecontrolenable,
|
|
epbrakecontroldisable,
|
|
trainbrakeoperationmodeincrease,
|
|
trainbrakeoperationmodedecrease,
|
|
brakeactingspeedincrease,
|
|
brakeactingspeeddecrease,
|
|
brakeactingspeedsetcargo,
|
|
brakeactingspeedsetpassenger,
|
|
brakeactingspeedsetrapid,
|
|
brakeloadcompensationincrease,
|
|
brakeloadcompensationdecrease,
|
|
mubrakingindicatortoggle,
|
|
alerteracknowledge,
|
|
cabsignalacknowledge,
|
|
hornlowactivate,
|
|
hornhighactivate,
|
|
whistleactivate,
|
|
radiotoggle,
|
|
radioenable,
|
|
radiodisable,
|
|
radiochannelincrease,
|
|
radiochanneldecrease,
|
|
radiochannelset,
|
|
radiostopsend,
|
|
radiostopenable,
|
|
radiostopdisable,
|
|
radiostoptest,
|
|
radiocall1send,
|
|
radiocall3send,
|
|
radiovolumeincrease,
|
|
radiovolumedecrease,
|
|
radiovolumeset,
|
|
cabchangeforward,
|
|
cabchangebackward,
|
|
|
|
modernlightdimmerdecrease,
|
|
modernlightdimmerincrease,
|
|
|
|
viewturn,
|
|
movehorizontal,
|
|
movehorizontalfast,
|
|
movevertical,
|
|
moveverticalfast,
|
|
moveleft,
|
|
moveright,
|
|
moveforward,
|
|
moveback,
|
|
moveup,
|
|
movedown,
|
|
|
|
nearestcarcouplingincrease,
|
|
nearestcarcouplingdisconnect,
|
|
nearestcarcoupleradapterattach,
|
|
nearestcarcoupleradapterremove,
|
|
occupiedcarcouplingdisconnect,
|
|
occupiedcarcouplingdisconnectback,
|
|
doortoggleleft,
|
|
doortoggleright,
|
|
doorpermitleft,
|
|
doorpermitright,
|
|
doorpermitpresetactivatenext,
|
|
doorpermitpresetactivateprevious,
|
|
dooropenleft,
|
|
dooropenright,
|
|
dooropenall,
|
|
doorcloseleft,
|
|
doorcloseright,
|
|
doorcloseall,
|
|
doorsteptoggle,
|
|
doormodetoggle,
|
|
mirrorstoggle,
|
|
departureannounce,
|
|
doorlocktoggle,
|
|
pantographcompressorvalvetoggle,
|
|
pantographcompressorvalveenable,
|
|
pantographcompressorvalvedisable,
|
|
pantographcompressoractivate,
|
|
pantographtogglefront,
|
|
pantographtogglerear,
|
|
pantographraisefront,
|
|
pantographraiserear,
|
|
pantographlowerfront,
|
|
pantographlowerrear,
|
|
pantographlowerall,
|
|
pantographselectnext,
|
|
pantographselectprevious,
|
|
pantographtoggleselected,
|
|
pantographraiseselected,
|
|
pantographlowerselected,
|
|
pantographvalvesupdate,
|
|
pantographvalvesoff,
|
|
heatingtoggle,
|
|
heatingenable,
|
|
heatingdisable,
|
|
lightspresetactivatenext,
|
|
lightspresetactivateprevious,
|
|
headlighttoggleleft,
|
|
headlightenableleft,
|
|
headlightdisableleft,
|
|
headlighttoggleright,
|
|
headlightenableright,
|
|
headlightdisableright,
|
|
headlighttoggleupper,
|
|
headlightenableupper,
|
|
headlightdisableupper,
|
|
redmarkertoggleleft,
|
|
redmarkerenableleft,
|
|
redmarkerdisableleft,
|
|
redmarkertoggleright,
|
|
redmarkerenableright,
|
|
redmarkerdisableright,
|
|
headlighttogglerearleft,
|
|
headlightenablerearleft,
|
|
headlightdisablerearleft,
|
|
headlighttogglerearright,
|
|
headlightenablerearright,
|
|
headlightdisablerearright,
|
|
headlighttogglerearupper,
|
|
headlightenablerearupper,
|
|
headlightdisablerearupper,
|
|
redmarkertogglerearleft,
|
|
redmarkerenablerearleft,
|
|
redmarkerdisablerearleft,
|
|
redmarkertogglerearright,
|
|
redmarkerenablerearright,
|
|
redmarkerdisablerearright,
|
|
redmarkerstoggle,
|
|
endsignalstoggle,
|
|
headlightsdimtoggle,
|
|
headlightsdimenable,
|
|
headlightsdimdisable,
|
|
motorconnectorsopen,
|
|
motorconnectorsclose,
|
|
motordisconnect,
|
|
interiorlighttoggle,
|
|
interiorlightenable,
|
|
interiorlightdisable,
|
|
interiorlightdimtoggle,
|
|
interiorlightdimenable,
|
|
interiorlightdimdisable,
|
|
compartmentlightstoggle,
|
|
compartmentlightsenable,
|
|
compartmentlightsdisable,
|
|
instrumentlighttoggle,
|
|
instrumentlightenable,
|
|
instrumentlightdisable,
|
|
dashboardlighttoggle,
|
|
dashboardlightenable,
|
|
dashboardlightdisable,
|
|
timetablelighttoggle,
|
|
timetablelightenable,
|
|
timetablelightdisable,
|
|
|
|
generictoggle0,
|
|
generictoggle1,
|
|
generictoggle2,
|
|
generictoggle3,
|
|
generictoggle4,
|
|
generictoggle5,
|
|
generictoggle6,
|
|
generictoggle7,
|
|
generictoggle8,
|
|
generictoggle9,
|
|
generictoggle10,
|
|
generictoggle11,
|
|
generictoggle12,
|
|
generictoggle13,
|
|
generictoggle14,
|
|
generictoggle15,
|
|
generictoggle16,
|
|
generictoggle17,
|
|
generictoggle18,
|
|
generictoggle19,
|
|
generictoggle20,
|
|
generictoggle21,
|
|
generictoggle22,
|
|
generictoggle23,
|
|
generictoggle24,
|
|
generictoggle25,
|
|
generictoggle26,
|
|
generictoggle27,
|
|
generictoggle28,
|
|
generictoggle29,
|
|
|
|
batterytoggle,
|
|
batteryenable,
|
|
batterydisable,
|
|
cabactivationtoggle,
|
|
cabactivationenable,
|
|
cabactivationdisable,
|
|
motorblowerstogglefront,
|
|
motorblowerstogglerear,
|
|
motorblowersdisableall,
|
|
coolingfanstoggle,
|
|
tempomattoggle,
|
|
springbraketoggle,
|
|
springbrakeenable,
|
|
springbrakedisable,
|
|
springbrakeshutofftoggle,
|
|
springbrakeshutoffenable,
|
|
springbrakeshutoffdisable,
|
|
springbrakerelease,
|
|
distancecounteractivate,
|
|
speedcontrolincrease,
|
|
speedcontroldecrease,
|
|
speedcontrolpowerincrease,
|
|
speedcontrolpowerdecrease,
|
|
speedcontrolbutton0,
|
|
speedcontrolbutton1,
|
|
speedcontrolbutton2,
|
|
speedcontrolbutton3,
|
|
speedcontrolbutton4,
|
|
speedcontrolbutton5,
|
|
speedcontrolbutton6,
|
|
speedcontrolbutton7,
|
|
speedcontrolbutton8,
|
|
speedcontrolbutton9,
|
|
inverterenable1,
|
|
inverterenable2,
|
|
inverterenable3,
|
|
inverterenable4,
|
|
inverterenable5,
|
|
inverterenable6,
|
|
inverterenable7,
|
|
inverterenable8,
|
|
inverterenable9,
|
|
inverterenable10,
|
|
inverterenable11,
|
|
inverterenable12,
|
|
inverterdisable1,
|
|
inverterdisable2,
|
|
inverterdisable3,
|
|
inverterdisable4,
|
|
inverterdisable5,
|
|
inverterdisable6,
|
|
inverterdisable7,
|
|
inverterdisable8,
|
|
inverterdisable9,
|
|
inverterdisable10,
|
|
inverterdisable11,
|
|
inverterdisable12,
|
|
invertertoggle1,
|
|
invertertoggle2,
|
|
invertertoggle3,
|
|
invertertoggle4,
|
|
invertertoggle5,
|
|
invertertoggle6,
|
|
invertertoggle7,
|
|
invertertoggle8,
|
|
invertertoggle9,
|
|
invertertoggle10,
|
|
invertertoggle11,
|
|
invertertoggle12,
|
|
globalradiostop,
|
|
timejump,
|
|
timejumplarge,
|
|
timejumpsmall,
|
|
setdatetime,
|
|
setweather,
|
|
settemperature,
|
|
vehiclemoveforwards,
|
|
vehiclemovebackwards,
|
|
vehicleboost,
|
|
debugtoggle,
|
|
focuspauseset,
|
|
pausetoggle,
|
|
entervehicle,
|
|
resetconsist,
|
|
fillcompressor,
|
|
consistreleaser,
|
|
queueevent,
|
|
setlight,
|
|
insertmodel,
|
|
deletemodel,
|
|
dynamicmove,
|
|
consistteleport,
|
|
pullalarmchain,
|
|
sendaicommand,
|
|
spawntrainset,
|
|
destroytrainset,
|
|
quitsimulation,
|
|
wiperswitchincrease,
|
|
wiperswitchdecrease,
|
|
lightsset,
|
|
none = -1
|
|
};
|
|
|
|
enum class command_target {
|
|
|
|
userinterface,
|
|
/*
|
|
// NOTE: there's no need for consist- and unit-specific commands at this point, but it's a possibility.
|
|
// since command targets are mutually exclusive these don't reduce ranges for individual vehicles etc
|
|
consist = 0x4000,
|
|
unit = 0x8000,
|
|
*/
|
|
// values are combined with object id. 0xffff objects of each type should be quite enough ("for everyone")
|
|
vehicle = 0x10000,
|
|
signal = 0x20000,
|
|
entity = 0x40000,
|
|
simulation = 0x80000
|
|
};
|
|
|
|
enum class command_mode {
|
|
oneoff,
|
|
continuous
|
|
};
|
|
|
|
struct command_description {
|
|
std::string name;
|
|
command_target target;
|
|
command_mode mode;
|
|
};
|
|
|
|
struct command_data {
|
|
|
|
user_command command;
|
|
int action; // press, repeat or release
|
|
double param1;
|
|
double param2;
|
|
double time_delta;
|
|
|
|
bool freefly;
|
|
glm::vec3 location;
|
|
|
|
std::string payload;
|
|
|
|
// network::PeerId of the participant the command came from. kept as a plain integer
|
|
// so that this header stays independent of the network layer. it matters wherever two
|
|
// people work the same vehicle: a continuous command held by one of them must not be
|
|
// cancelled by the other one letting go of the same key
|
|
uint32_t source { 0 };
|
|
};
|
|
|
|
// command_queues: collects and holds commands from input sources, for processing by their intended recipients
|
|
// NOTE: this won't scale well.
|
|
// TODO: turn it into a dispatcher and build individual command sequences into the items, where they can be examined without lookups
|
|
|
|
class command_queue {
|
|
|
|
public:
|
|
// types
|
|
typedef std::deque<command_data> commanddata_sequence;
|
|
typedef std::unordered_map<uint32_t, commanddata_sequence> commands_map;
|
|
// methods
|
|
// posts specified command for specified recipient into m_intercept_queue
|
|
void
|
|
push( command_data const &Command, uint32_t const Recipient );
|
|
// retrieves oldest posted command for specified recipient, if any. returns: true on retrieval, false if there's nothing to retrieve
|
|
bool
|
|
pop( command_data &Command, uint32_t const Recipient );
|
|
// generates active continuous commands
|
|
void
|
|
update();
|
|
// checks if given command must be scheduled on server
|
|
bool
|
|
is_network_target(const uint32_t Recipient);
|
|
|
|
// pops commands from intercept queue
|
|
commands_map pop_intercept_queue();
|
|
|
|
// pushes commands into main queue
|
|
void push_commands(const commands_map &commands);
|
|
|
|
private:
|
|
// members
|
|
// contains command ready to execution
|
|
commands_map m_commands;
|
|
|
|
// contains intercepted commands to be read by application layer
|
|
commands_map m_intercept_queue;
|
|
|
|
void push_direct( command_data const &Command, uint32_t const Recipient );
|
|
|
|
// a continuous command is held per source, not just per recipient: with two people in
|
|
// one cab, the release sent by one of them may only cancel their own hold
|
|
struct continuous_key {
|
|
uint32_t source;
|
|
uint32_t recipient;
|
|
user_command command;
|
|
|
|
bool operator==( continuous_key const &Other ) const {
|
|
return source == Other.source
|
|
&& recipient == Other.recipient
|
|
&& command == Other.command; }
|
|
};
|
|
|
|
struct continuous_key_hash {
|
|
std::size_t operator() ( continuous_key const &Key ) const {
|
|
std::size_t hash = (std::size_t)Key.source * 2654435761u;
|
|
hash ^= (std::size_t)Key.recipient + 0x9e3779b9 + ( hash << 6 ) + ( hash >> 2 );
|
|
hash ^= (std::size_t)Key.command + 0x9e3779b9 + ( hash << 6 ) + ( hash >> 2 );
|
|
return hash; }
|
|
};
|
|
|
|
// currently pressed continuous commands
|
|
std::unordered_set<continuous_key, continuous_key_hash> m_active_continuous;
|
|
};
|
|
|
|
template<typename A, typename B>
|
|
void add_to_dequemap(std::unordered_map<A, std::deque<B>> &lhs, const std::unordered_map<A, std::deque<B>> &rhs) {
|
|
for (auto const &kv : rhs) {
|
|
auto lookup = lhs.emplace(kv.first, std::deque<B>());
|
|
for (B const &data : kv.second)
|
|
lookup.first->second.emplace_back(data);
|
|
}
|
|
}
|
|
|
|
// NOTE: simulation should be a (light) wrapper rather than namespace so we could potentially instance it,
|
|
// but realistically it's not like we're going to run more than one simulation at a time
|
|
namespace simulation {
|
|
|
|
typedef std::vector<command_description> commanddescription_sequence;
|
|
|
|
extern command_queue Commands;
|
|
// TODO: add name to command map, and wrap these two into helper object
|
|
extern commanddescription_sequence Commands_descriptions;
|
|
|
|
extern std::unordered_map<std::string, user_command> commandMap;
|
|
}
|
|
|
|
// command_relay: composite class component, passes specified command to appropriate command stack
|
|
|
|
class command_relay {
|
|
|
|
public:
|
|
// methods
|
|
// posts specified command for the specified recipient
|
|
void
|
|
post(user_command const Command, double const Param1, double const Param2,
|
|
int const Action, uint16_t Recipient, glm::vec3 Position = glm::vec3(0.0f) , const std::string *Payload = nullptr) const;
|
|
private:
|
|
// types
|
|
// members
|
|
};
|
|
|
|
//---------------------------------------------------------------------------
|