17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-17 20:19:20 +02:00
Commit Graph

21 Commits

Author SHA1 Message Date
1bfa1644c9 multiplayer: a cab belongs to the peer it is on, and the first one aboard drives
Joining a crew did nothing. The cab was being built by a replicated entervehicle
that the authority posted only when it had no cab of its own - which is exactly
the case that never happens for the second person to board. The host claims a
vehicle, the server builds a cab, and from then on every further claim finds one
already standing over there, posts nothing, and the joining peer waits forever
for a command that is not coming.

A cab is not a shared object. Each participant has their own, with their own
camera and their own view of it, and nothing about it needs to travel. So it is
built locally by whoever needs one: the driver mode does it for the player when
their claim is granted, and the authority does it for itself, because it needs a
cab to address the AI handover commands to. That also stops a cab being created
on every peer for every claimed vehicle, which is what the entervehicle
broadcast was doing.

Who runs a shared train is no longer decided by car numbering. It is whoever
boarded first, and it stays with them: every crew member is stamped with a
session-wide counter when they sit down, and the smallest stamp on the whole
consist owns the physics. Coupling, uncoupling and renumbering do not move it,
and neither does somebody else joining - each handover is a stutter in the ride
of the person who has been driving, and they are the one who would notice it.
The stamps travel with CREW_UPDATE and in the snapshot, because a client works
out ownership for itself and has to arrive at the same answer.

Chat: the key that opens it is now read before imgui gets a look at the input.
Any window holding the keyboard - the lobby, most likely, which is precisely
where a client sits - would swallow it, so on that side the panel could not be
opened at all. The exception is text actually being typed, which is the chat box
itself; escape closes that. A client also logs what it says, so if a line goes
missing it is clear which half of the trip lost it.

Protocol version 6, snapshot version 7.
2026-09-07 16:00:41 +00:00
0112d81b77 multiplayer: names instead of peer numbers, a chat, and the exe as a dedicated server
Three things that turn out to be one thing: a session with people in it needs
to be able to say who they are, and a machine that only referees one should not
have to open a window to do it.

Names. A peer id is what the protocol addresses; "player 4" is no use to anybody
reading a lobby. CLIENT_HELLO carries a requested nickname now, and the server
decides what it actually is: trimmed of control characters and runs of spaces,
capped at 24, and made unique - two people called Marcin are two people and the
lobby has to say which is which. The result goes out as PEER_ROSTER whenever
somebody joins or leaves, and to a joining peer just before its snapshot, so the
crew section resolves to names rather than numbers. The name comes from
multiplayer.nickname in the ini or --nick on the command line, falling back to
the account name and, failing that, to the old numbering. The host is a peer
like any other here too, and registers its own name at startup.

Chat, on the key left of 1. Going up a line carries only its text: who said it
is decided by the connection it arrived on, never by the field in the packet,
which is what stops anybody putting words in anybody's mouth. The server tidies
and caps it, says it, and passes it on - a client waits to hear itself back, so
that everybody sees the conversation in the same order. While the box has the
keyboard imgui swallows the input before the driver mode sees it, so typing "d"
types "d" instead of opening the doors of whatever you are driving; that also
means the key that opened the panel cannot close it, hence escape.

And --nogui. No glfw, no window, no imgui, the null renderer, sound off, log to
the console it was started from, and nobody in a cab - the scenario is left to
its own drivers and this process is a referee rather than a participant. Every
window-dependent path is guarded on an empty window list rather than on a flag
scattered through the code, and the loop is paced at fifty steps a second
because nothing is waiting on a swapchain to slow it down. Chat lines go to the
log, which is what a machine with no window has instead of a chat panel.

    eu07.exe -s scenario.scn --host 0.0.0.0:7420 --nogui --nick Dispatcher
2026-09-07 13:54:34 +00:00
5a5bb15fa5 multiplayer: hold the authority's readings between updates, and hear the brakes
Two complaints, one cause underneath them.

The brake and squeal sounds came out in shreds as a train got going. Both are
shaped from UnitBrakeForce and Vel, and both of those are results of a physics
step. An update arrives ten times a second; in the twenty-odd frames between
them the local physics carries on computing its own speed and its own brake
force for a train it has no business simulating, they fall away, and the next
update snaps them back. rsBrake pitches on Vel and rsPisk gains on the brake
force ratio, so what the ear got was that sawtooth.

So the physics outputs of somebody else's train are now put back after every
local step, not only on the frame an update lands: speed, brake force, wheel
and engine revolutions, engine power, wheelslip, sand, and the running flags of
the converter and the compressors, which the local physics kept switching off
because the conditions it evaluates are not the ones the owner is evaluating.

The relays are the same problem wearing a different hat. MainCtrlActualPos - the
notch the resistors are actually on, as opposed to the one the handle is at -
was being stepped by the local automatic notching, off its own guesses, so the
clicks either fired at the wrong moment or never fired at all. It travels now,
together with ScndCtrlActualPos and StLinFlag, which stops the local notching
inventing anything, and every relay heard here is one that operated over there.

The brake unit keeps a sound bitfield of its own, and that is where the
accelerator and the cylinder venting live. Reading it clears it, so watching it
had to be done without consuming it: TBrake grows PeekSoundFlag(), and only the
flags that have just come up count as an event - the vehicle only clears them
when it has an accelerator sound to play, so a bit that stays lit is one event,
not one per frame. RaiseSoundFlag() hands them to the far end.

Snapshot version 5.
2026-09-07 09:24:47 +00:00
a0537356bb multiplayer: correct a train by sliding it, not by putting it down again
Reversing on the host turned the whole set around on the client, and the
locomotive ended up looking like something derailed making its way across the
scenery. Both come from the same place: a routine correction was calling
place_on_track(), which sets the axles from scratch and works from the
vehicle's own idea of which way it faces. That is right for a peer joining with
nothing to go on, and wrong for a train that is already running - the placement
reorients it.

A correction now slides the vehicle along the track it is already on, by the
difference between the two bogie offsets, which is the same operation the
physics performs on every step. When the two sides disagree about which piece
of track the vehicle is on, it is left alone until they agree; guessing there
is what put a locomotive beside the rails. place_on_track() is kept for the one
case it suits, a peer joining the session.

Also:

- taking a seat works with the game paused. The whole thing sat inside the
  "has any time passed" branch, so with the world stopped the lobby button
  changed the roster and nothing else happened
- the debug panel gets a Network section, shown only in a session: role, peer,
  tick, bytes and messages each way with a running rate, two charts of kB/s so
  the cost of a session can be read off, how far the worst vehicle is out of
  place, and whether the state digest agrees. The separate "network" overlay
  window is gone - everything it said lives there now, together with the lobby
  and refusal messages that had nowhere to be seen
2026-09-07 07:49:47 +00:00
a72c3292ad multiplayer: fix the black screen - a cab and is_ready waiting on each other
The renderer draws nothing at all while simulation::is_ready is false, and that
flag only goes up once the local player's cab is built.

The previous commit made walking into a cab a crew request, so the cab of a
claimed vehicle is created by Crews::reconcile() rather than by the command
itself. reconcile() runs from the network housekeeping, which was gated on
simulation::is_ready - so a host started with -v had its entervehicle turned
into a claim, and then the cab waited for is_ready while is_ready waited for
the cab. Black screen on both ends, since a client whose server never gets
going has nothing to show either.

- the housekeeping now waits for Global.simulation_loaded, which says the world
  exists, instead of simulation::is_ready, which says the player has a cab
- in a session, a player with no cab counts as ready: they are an observer in
  the lobby, not a game still loading, and the world has to be drawn for them
- entervehicle is only taken as a crew request when the session actually lists
  that vehicle; anything else stays an ordinary command, so a scenario that
  starts its host in something the roster does not cover still works
2026-09-06 22:54:48 +00:00
3f62fd5927 multiplayer stage 3: crew model, claim handshake and AI handover
A vehicle is not owned by one player: two people share a cab, so the session
needs a crew relation rather than an owner field. The server keeps it and is
the only one allowed to change it.

- network/session: vehicle_crew { entity_id, crew, ai_before_claim } and a
  crew_registry holding the roster. the host goes through exactly the same
  path as a remote peer (claim -> crew -> grant), only without transport
- CLAIM_VEHICLE / CLAIM_GRANTED / CLAIM_DENIED / LEAVE_VEHICLE / CREW_UPDATE;
  the server validates the vehicle exists, is present in the scenario and has
  room in the crew, and answers a refusal with a reason the lobby shows
- the cab of a claimed vehicle is created by the authority posting the
  ordinary replicated entervehicle, so every peer builds it and the vehicle is
  never moved. the claiming peer only walks in once the cab appears locally
- AI transitions follow the crew size: 0 -> 1 remembers whether an AI was
  really driving and takes the vehicle over, 1 -> 2 and 2 -> 1 change nothing,
  1 -> 0 hands the vehicle back but only if there was an AI driver to begin
  with. driver mode no longer fires aidriverdisable of its own in multiplayer
- losing a connection removes that peer from every crew it was on; a vehicle
  with somebody still on board carries on untouched
- the lobby lists who is on board, offers "join crew" for a vehicle another
  player already occupies, and lets a player step off

The AI and cab handling runs as a reconciliation pass rather than as edge
triggered actions, so a request that has not taken effect yet (the cab needs a
frame to appear) is simply repeated, with a cooldown to keep it off the wire.
2026-09-06 18:08:06 +00:00
b9bd0ee33d 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.
2026-09-06 17:48:35 +00:00
eed44dc858 hardware protocol v2.1: device log, diagnostic routines, manual links
Three additions, all driven from the simulator debug panel.

DEVICE_LOG lets a controller send text lines; they reach the simulator log
and a per connection view in the panel which keeps the last 64 of them.

Diagnostic routines: a controller lists the procedures it offers, the
operator picks one from a drop down and starts it, and the controller
reports progress and the result. While a routine runs the controller can
ask the simulator to show a message box with its own text and buttons and
gets back which one was pressed, which is what a valve or gauge
calibration needs. The message box appears whether the debug panel is
open or not.

Links can now be disconnected and reconnected by hand: disconnecting
closes the serial port so the controller can be reprogrammed, and the
session is rebuilt from scratch on reconnect. Ports which appear while
the simulation runs can be picked from a refreshed list, given a baud
rate and added as a new controller, so the manager now starts even with
no uart2 entries in eu07.ini.
2026-09-06 11:29:26 +00:00
91be90548f hardware protocol v2: configuration, wiring and debug panel
Adds the WITH_HARDWARE_PROTOCOL_V2 build option and the eu07.ini entries
which configure it: uart2 declares a serial link and may be repeated for
several controllers, the remaining uart2* entries tune frame size,
heartbeat, rate limits and logging. UART v1 is untouched and both may be
active at the same time on different ports.

The driver mode starts the manager when at least one link is configured
and pumps it from the input polling loop, and the debug panel gains a
Hardware Protocol v2 section reporting link and session condition,
packet rates, round trip time, protocol and transport error counters and
whatever diagnostics the device itself reports, with switches for
protocol and frame logging.
2026-09-05 20:35:38 +00:00
Sebastian Krzyszkowiak
f8339d9bfb drivermode: Make sure to draw the first frame before pausing
Otherwise the screen stays empty when the game is launched paused.
2026-07-02 09:37:07 +02:00
jerrrrycho
d85096f64d reformat: remove redundant parentheses 2026-06-30 21:19:46 +02:00
Sebastian Krzyszkowiak
2f187b470f drivermode: Allow to (un)set picking mode by combining Alt with Shift/Ctrl
Pressing Alt toggles picking mode. This is fine for keyboard and mouse usage,
but some use cases, such as disabling picking mode when a finger is placed
on a thumbstick and enabling it back when it's lifted, require finer control.
Allow to always enable picking mode when pressing Alt with Shift, and to always
disable picking mode when pressing Alt with Ctrl.
2026-06-30 06:14:43 +02:00
docentYT
4e0b4e6ff6 Check if Train pointer is not nullptr 2026-05-11 23:48:13 +02:00
docentYT
7081dab3c2 Replace RadToDeg and DegToRad with glm::degrees and glm::radians 2026-05-02 14:51:13 +02:00
docentYT
ca699d117f Remove not needed includes 2026-05-02 14:40:31 +02:00
docentYT
ca839652bf Use the sq function to force constexpr expressions for numeric literals and enhance readability 2026-04-28 13:23:14 +02:00
docentYT
cba106e22e Use glm::length2 instead of glm::length where possible 2026-04-27 23:27:08 +02:00
docentYT
fae68642bc use glm instead of Math3D in vehicle
WARNING: Model rotation is broken
2026-04-27 13:07:38 +02:00
docentYT
bdff45b584 use glm instead of Math3D in drivermode 2026-04-26 22:40:02 +02:00
copilot-swe-agent[bot]
7e49aa8740 Rewrite #includes to use explicit subdirectory paths
Co-authored-by: Hirek193 <23196899+Hirek193@users.noreply.github.com>
2026-03-14 19:16:48 +00:00
copilot-swe-agent[bot]
0531086bb9 Reorganize source files into logical subdirectories
Co-authored-by: Hirek193 <23196899+Hirek193@users.noreply.github.com>
2026-03-14 19:01:57 +00:00