mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-17 10:59:20 +02:00
multiplayer: replicate the machinery you hear, not only the machinery you set
A bystander heard nothing of somebody else's converter, compressors, brake air or relays. Two different reasons for that, and they need two different answers. The devices whose sound runs for as long as they do - the converter, the main compressor, the pantograph compressor, the releaser - are outputs of a physics that a peer only half runs for a vehicle it does not own. Their running flags travel now, alongside the permits that were already going. The clicks and hisses are a harder case: MoverParameters::SoundFlag is raised and wiped inside a single frame, so sampling it when an update happens to be put together would catch almost none of them. They are collected as the vehicle finishes with them, just before it clears the field, and the accumulation rides along with the next update. On arrival they are added to whatever the receiving peer's own physics produced, and its sound handling plays them once and wipes the lot, exactly as it does for its own.
This commit is contained in:
@@ -77,6 +77,9 @@ TTrack *track_by_id(uint32_t const Id)
|
||||
return (Id < g_trackindex.size() ? g_trackindex[Id] : nullptr);
|
||||
}
|
||||
|
||||
// one-shot sound events seen since the last update went out, per vehicle
|
||||
std::unordered_map<std::string, int> g_soundevents;
|
||||
|
||||
std::unordered_map<std::string, uint64_t> g_lastvehicles;
|
||||
std::unordered_map<std::string, uint64_t> g_lastmemcells;
|
||||
std::unordered_map<std::string, int> g_lastswitches;
|
||||
@@ -210,6 +213,14 @@ struct vehicle_state
|
||||
// what the vehicle is heard and seen doing. a peer that is not in this cab has no
|
||||
// TTrain for it, so the commands that set these never reach it - only the result does
|
||||
int32_t warningsignal{0};
|
||||
// devices whose sound runs for as long as they do, and the one-shot events - relays
|
||||
// clicking, air hissing - that happen too fast for an update to catch by sampling
|
||||
bool converterrunning{false};
|
||||
bool compressorrunning{false};
|
||||
bool pantcompressorrunning{false};
|
||||
bool compressorlock{false};
|
||||
bool releaser{false};
|
||||
int32_t soundevents{0};
|
||||
int32_t emergencywarningsignal{0};
|
||||
bool alarmchain{false};
|
||||
double wheelrevolutions{0.0};
|
||||
@@ -256,6 +267,12 @@ void serialize_vehicle(std::ostream &Stream, vehicle_state const &State)
|
||||
}
|
||||
sn_utils::ls_int32(Stream, State.lights[0]);
|
||||
sn_utils::ls_int32(Stream, State.lights[1]);
|
||||
sn_utils::s_bool(Stream, State.converterrunning);
|
||||
sn_utils::s_bool(Stream, State.compressorrunning);
|
||||
sn_utils::s_bool(Stream, State.pantcompressorrunning);
|
||||
sn_utils::s_bool(Stream, State.compressorlock);
|
||||
sn_utils::s_bool(Stream, State.releaser);
|
||||
sn_utils::ls_int32(Stream, State.soundevents);
|
||||
sn_utils::ls_int32(Stream, State.warningsignal);
|
||||
sn_utils::ls_int32(Stream, State.emergencywarningsignal);
|
||||
sn_utils::s_bool(Stream, State.alarmchain);
|
||||
@@ -307,6 +324,12 @@ vehicle_state deserialize_vehicle(std::istream &Stream)
|
||||
}
|
||||
state.lights[0] = sn_utils::ld_int32(Stream);
|
||||
state.lights[1] = sn_utils::ld_int32(Stream);
|
||||
state.converterrunning = sn_utils::d_bool(Stream);
|
||||
state.compressorrunning = sn_utils::d_bool(Stream);
|
||||
state.pantcompressorrunning = sn_utils::d_bool(Stream);
|
||||
state.compressorlock = sn_utils::d_bool(Stream);
|
||||
state.releaser = sn_utils::d_bool(Stream);
|
||||
state.soundevents = sn_utils::ld_int32(Stream);
|
||||
state.warningsignal = sn_utils::ld_int32(Stream);
|
||||
state.emergencywarningsignal = sn_utils::ld_int32(Stream);
|
||||
state.alarmchain = sn_utils::d_bool(Stream);
|
||||
@@ -362,6 +385,15 @@ vehicle_state read_from(TDynamicObject const &Vehicle)
|
||||
}
|
||||
state.lights[0] = mover.iLights[0];
|
||||
state.lights[1] = mover.iLights[1];
|
||||
state.converterrunning = mover.ConverterFlag;
|
||||
state.compressorrunning = mover.CompressorFlag;
|
||||
state.pantcompressorrunning = mover.PantCompFlag;
|
||||
state.compressorlock = mover.CompressorGovernorLock;
|
||||
state.releaser = (mover.Hamulec != nullptr && mover.Hamulec->Releaser());
|
||||
|
||||
auto const events = g_soundevents.find(Vehicle.name());
|
||||
state.soundevents = (events != g_soundevents.end() ? events->second : 0);
|
||||
|
||||
state.warningsignal = mover.WarningSignal;
|
||||
state.emergencywarningsignal = mover.EmergencyBrakeWarningSignal;
|
||||
state.alarmchain = mover.AlarmChainFlag;
|
||||
@@ -427,6 +459,18 @@ void apply_controls(TDynamicObject &Vehicle, vehicle_state const &State)
|
||||
|
||||
// the horn, the wheels and the engine note. these are set from a cab this peer does
|
||||
// not have, so nothing but the result of them ever reaches it
|
||||
mover.ConverterFlag = State.converterrunning;
|
||||
mover.CompressorFlag = State.compressorrunning;
|
||||
mover.PantCompFlag = State.pantcompressorrunning;
|
||||
mover.CompressorGovernorLock = State.compressorlock;
|
||||
|
||||
if (mover.Hamulec != nullptr && mover.Hamulec->Releaser() != State.releaser)
|
||||
mover.Hamulec->Releaser(State.releaser ? 1 : 0);
|
||||
|
||||
// the one-shot events are added to whatever this peer's own physics produced; the
|
||||
// vehicle's sound handling plays them once and wipes the lot, as it always does
|
||||
mover.SoundFlag |= State.soundevents;
|
||||
|
||||
mover.WarningSignal = State.warningsignal;
|
||||
mover.EmergencyBrakeWarningSignal = State.emergencywarningsignal;
|
||||
mover.AlarmChainFlag = State.alarmchain;
|
||||
@@ -532,6 +576,9 @@ std::string write_vehicles(bool const Full, bool const OwnedOnly)
|
||||
|
||||
entries.write(record.data(), record.size());
|
||||
++count;
|
||||
|
||||
// the one-shot events have been handed over; they must not go out twice
|
||||
g_soundevents.erase(state.name);
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
@@ -827,8 +874,17 @@ void read_switches(std::istream &Stream)
|
||||
|
||||
} // namespace
|
||||
|
||||
void network::note_sound_events(std::string const &Vehicle, int const Events)
|
||||
{
|
||||
if (Events == 0)
|
||||
return;
|
||||
|
||||
g_soundevents[Vehicle] |= Events;
|
||||
}
|
||||
|
||||
void network::reset_snapshot_history()
|
||||
{
|
||||
g_soundevents.clear();
|
||||
g_lastvehicles.clear();
|
||||
g_lastmemcells.clear();
|
||||
g_lastswitches.clear();
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace network
|
||||
{
|
||||
|
||||
// layout of the snapshot container. a reader refuses a blob it does not understand
|
||||
constexpr uint32_t SNAPSHOT_VERSION = 3;
|
||||
constexpr uint32_t SNAPSHOT_VERSION = 4;
|
||||
|
||||
// the sections a snapshot is built from. a reader skips over any id it does not know,
|
||||
// which is what makes the format extensible: a peer built before a section existed can
|
||||
@@ -72,4 +72,9 @@ snapshot_result apply_snapshot(std::string const &Blob, snapshot_mode Mode, Peer
|
||||
// forgets what was last sent, so that the next delta comes out complete
|
||||
void reset_snapshot_history();
|
||||
|
||||
// remembers the one-shot sound events a vehicle produced. they are set and cleared inside
|
||||
// a single frame, so by the time an update is put together they would be long gone; this
|
||||
// is called from the vehicle's own sound handling, just before it wipes them
|
||||
void note_sound_events(std::string const &Vehicle, int Events);
|
||||
|
||||
} // namespace network
|
||||
|
||||
@@ -23,6 +23,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "utilities/Globals.h"
|
||||
#include "utilities/Timer.h"
|
||||
#include "utilities/Logs.h"
|
||||
#include "network/entities.h"
|
||||
#include "network/snapshot.h"
|
||||
#include "utilities/glmHelpers.h"
|
||||
#include "Console.h"
|
||||
#include "world/Traction.h"
|
||||
@@ -5116,6 +5118,12 @@ void TDynamicObject::RenderSounds() {
|
||||
coupler.sounds = 0;
|
||||
}
|
||||
|
||||
if( true == network::is_multiplayer() ) {
|
||||
// relays clicking and air hissing are set and cleared inside a single frame, so
|
||||
// they have to be picked up here to have any chance of reaching the other peers
|
||||
network::note_sound_events( name(), MoverParameters->SoundFlag );
|
||||
}
|
||||
|
||||
MoverParameters->SoundFlag = 0;
|
||||
// McZapkie! - koniec obslugi dzwiekow z mover.pas
|
||||
|
||||
|
||||
Reference in New Issue
Block a user