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

3103 Commits

Author SHA1 Message Date
maj00r
f718dbf95d Ask the cell itself whether its command is still pending, guard the order table
The spent command was tracked in a table flag, which is lost whenever the speed
table is rebuilt - the cell would go back to being a stop point. The memcell
already knows: StopCommandSent() drops the pending flag and keeps the text, so
the event now answers is_command_spent() and the table point follows it.

OrderNextGet() read one past the end of OrderList when the current order sat in
the last slot; it now reports Wait_for_orders there, which is what OrderNext()
wraps to anyway.
2026-09-15 22:09:02 +02:00
maj00r
1e52bb43ba Keep a shut down AI out of the engine start hack, stop standing at spent cells
A vehicle left alone in a consist was starting its engine on its own: the
Wait_for_orders hack in handle_engine() takes a live 24V battery as a human
switching the vehicle on, and every vehicle a scenery starts with has one. The
guard for that was in master, commented out. With the engine running the driver
counted as active again, so a permitting signal went on to hand it Obey_train -
measured on td.scn: Prepare_engine 12 ms after the coupler was released, with
the signal still at stop.

A command cell keeps its text once the command has been delivered, which left
the point at zero velocity and hid the rest of the table behind it. The point is
now marked as sent and stops braking for it.

Also drops the parameter CommandClaimsPrimary() no longer reads, and puts the
brake release blocks in determine_consist_state() back at their original
indentation - the scope never changed, but the diff read as if it had.
2026-09-15 21:59:50 +02:00
maj00r
829e8b0938 Use English for the comments added on this branch 2026-09-15 18:58:08 +02:00
maj00r
0a7915ef58 Keep the master standstill threshold, name the pressures
DirectionInitial() and PrepareDirection() go back to EU07_AI_NOMOVEMENT,
so a standing consist is left alone at load as it was. The thresholds the
brake charging cut-off works with get names instead of bare numbers, as
does the overcharge margin in the pipe pressure update.
2026-09-15 18:51:47 +02:00
maj00r
2531418d26 Let a command cell reach a shut down driver
A dormant driver scans, but bailed out before anything could act on the
table. Signals stay out of it - only cm_Command is dispatched, so a memory
cell put in front of a parked consist can hand it Prepare_engine.
2026-09-15 00:03:42 +02:00
maj00r
e6c2d189ff Do not start a shut down engine on a signal; address SonarCloud findings
A permitting signal no longer wakes a dormant AI: the synthetic departure
command, the shunt-signal ownership tag and the secondary scan that fed
them are gone, and cm_SetVelocity / cm_ShuntVelocity go back to plain
PutCommand with the pre-existing order mask. A secondary now only settles
its own vehicle. Claiming the lead stays for explicit orders.

The rest is SonarCloud cleanup on the branch: if-init statements, merged
and flattened conditionals, split chained assignments, ranges::any_of,
pointer-to-const parameters, std::array for the flag name table and no
more shadowed names.
2026-09-14 23:51:20 +02:00
maj00r
a1e4e8d95b Prevent overcharge by AI - count how long each vehicle is being under higher pressure 2026-09-08 19:53:06 +02:00
maj00r
ac313f1f1d Stop cutting the forward scan short at an occupied track.
The check added to TableTraceRoute() decided consist membership through
BelongsToConsist(), which falls back on TDynamicObject::is_connected() and its
Next()/Prev() walk - the same pair that mishandles reversed members. When it
failed to recognise one of our own cars the scan ended on our own consist, no
signal ever reached the speed table, and the driver stood at a clear semaphore
for good. Seen on a shunting locomotive that had just uncoupled, with ctOwner
still cleared.

The signal-permission code does not need it: OtherConsistAtSignal() looks the
route over on its own and DistanceToAnotherConsist() measures to the vehicle
rather than to the end of a track. Both stay.
2026-09-06 15:23:50 +02:00
maj00r
f4f0b2bb10 Propagate the reverser setting, not its absolute direction.
CabActivisation() sent DirAbsolute under the "Direction" command, while
DirectionForward() and DirectionBackward() send DirActive under the same name.
The receiving end (TMoverParameters::RunInternalCommand) assigns the value
straight to DirActive and derives DirAbsolute from its own CabActive, so the two
senders only agree while CabActive is 1. Activating a rear cab therefore left
every other member of the consist with the reverser set the opposite way.

The symptom was an EMU that stalled and then accelerated backwards after control
changed hands. It was intermittent because the reverser sweep in
sync_consist_reversers() normally repairs the members through the other two call
sites - except on an EZT, where the first DirectionBackward() at DirActive 1 is
consumed by the high-current switch and propagates nothing, leaving the state set
by CabActivisation() in place.

Seen on an EN57 driven from the rear cab: the occupied car held DirActive 1 with
CabActive -1, the motor car and the far cab held DirActive -1 with the same
CabActive, so their DirAbsolute came out inverted.
2026-09-06 14:45:12 +02:00
maj00r
e95d4a57bc Disown the vehicles before deleting their driver.
TDynamicObject::Update() reads ctOwner->Controlling() every frame, but ctOwner is
only ever refreshed by CheckVehicles() and cleared only by Dettach(). Both
TController::MoveTo() and ~TDynamicObject() delete a controller while the rest of
the consist still points at it, so the vehicles keep dereferencing freed memory
until some other driver happens to claim them.

Seen as a segfault in DynObj.cpp on ctOwner->Controlling()->MainCtrlPosNo after
changing cabs through an EN57 with an AI driver in the leading unit: ctOwner was
a live-looking pointer into a freed TController, its mvControlling long gone.

~TController() now clears ctOwner on every vehicle still pointing at it. nullptr
is what the readers already expect - they fall back on Mechanik or skip the block
- and the next CheckVehicles() re-establishes ownership.
2026-09-06 13:48:05 +02:00
maj00r
aaccd7b9b7 Keep one primary per consist and let a secondary AI claim it.
A driver without movePrimary no longer just idles. UpdateSecondary() cuts
BrakeValveActive so a secondary AI stops fighting the primary over the brake
pipe, and - as long as no driver in the consist has iEngineActive - keeps
scanning ahead of CabOccupied, so it can take movePrimary and start the engine
once a signal permits.

scan_route() orients by CabOccupied when DirActive is 0, and
ClaimConsistPrimary() clears movePrimary on every other driver in the consist,
then calls TableClear() and CheckVehicles(), so sSpeedTable is rebuilt for the
new front and ctOwner follows it.

- walk the consist with FirstFind()/Neighbour() instead of Next()/Prev(), which
  stopped at the starting vehicle and mishandled reversed members;
- ReassignConsistPrimary() picks a single driver after any coupling change,
  both from TDynamicObject::couple() and from the AI path;
- IsOccupiedByAnotherConsist() decides membership with BelongsToConsist() and
  takes a signed distance, so a consist left behind no longer cuts the scan
  short. DistanceToAnotherConsist() hands back the gap it already computes, so
  OtherConsistAtSignal() counts a foreign vehicle only while it stands closer
  than the signal itself, instead of comparing track starts;
- TSpeedPos::Set() marks an entry with spNotOurShuntSignal when a
  spShuntSemaphor was already permitting as the entry was added. A shunting
  signal does not address its permission to a particular consist, so a dormant
  driver does not wake up on a permission it did not see light up; the flag
  drops once the signal shows stop, so its own turn is never blocked. spSemaphor
  is excluded: a semaphore sets a route for us and permits us even when found
  already lit. The check reads SemPermitIndex - the entry that produced the
  permitting command - because SemNextIndex can point at an earlier signal.
  The flag is also stamped whenever the permission turns out to belong to a
  consist standing in front of us - both where TableUpdateEvent() already knows
  the signal is for the vehicle ahead, and in check_route_ahead() - so the
  addressee pulling away does not hand the still-lit signal over to whoever
  waited behind it;
- the scantable debug panel lists the flags by name (spNotOurShuntSignal shows
  as not-ours) and folds the nearest vehicle ahead into the table by its own
  distance.
2026-09-06 13:21:44 +02:00
7a469190ca Merge pull request #168 from pwarszawski/whois-owner-fallback
whois: fall back to the consist owner in the +0/+7 mode too
2026-09-05 21:08:29 +02:00
3b061a1bf1 Merge pull request #171 from pwarszawski/event-name-registration-casefold
event names: fix registration/lookup casing mismatch for non-ASCII identifiers
2026-09-05 21:07:41 +02:00
76eede79aa Merge pull request #154 from MaSzyna-EU07/uart-independent-dynamic-brake
Add independent dynamic brake support (eg. Vectron) to UART controllers
2026-09-05 20:04:34 +02:00
fadcc2d666 Merge pull request #170 from MaSzyna-EU07/fix/reflections-and-burned-colors
Fix relfections on default shader and tonemapping
2026-09-05 20:03:31 +02:00
Piotr Warszawski
2dcae05c77 event names: drop redundant locale-dependent ToLower() at registration
make_event() lowercased the event name twice: cParser::getToken() already
folds ASCII via toLowerChar() (which intentionally leaves bytes >= 0x80
alone), then ToLower() ran std::tolower() over every byte on top of that.

With a non-"C" global locale, that second pass remaps cp1250 uppercase
accented letters (e.g. 0xAF -> 0xBF). Every lookup path - TTrack::AssignEvents(),
child-event resolution in multi_event, event-launcher name resolution -
normalizes only through the parser, so a registered name containing such a
letter can no longer be found: the track logs "can't find assigned event"
and the binding is silently dropped.

Removing the extra ToLower() makes the registration key match every lookup
site (ASCII-only folding, non-ASCII bytes compared verbatim), and matches
the direction toLowerChar()'s own comment already points at for UTF-8.
2026-09-05 19:10:58 +02:00
Piotr Warszawski
1ce576c0c6 whois: log the no-activator case instead of failing silently
A whois with no triggering vehicle previously just wrote nothing to
the target cell with no trace in the log, which is a real pain to
diagnose from the scenery side (this is exactly the kind of thing that
cost real debugging time on a station script recently).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-04 22:22:25 +02:00
Piotr Warszawski
7ead4f11b4 whois: guard against a null activator
whois_event::run_() dereferenced m_activator unconditionally in every
branch (this predates this PR). getvalues_event::run_() and
putvalues_event::run_() already guard the same way elsewhere in this
file; whois_event was missing it. Single early return covers every
branch, old and new.
2026-09-04 22:09:23 +02:00
Piotr Warszawski
4f47233a89 whois: fall back to the consist owner in the +0/+7 mode too
The +8/+16/+24/+32/+40 (and the new +48) modes all pick the reporting
vehicle the same way: the activator's own Mechanik if it's the primary
driver, otherwise the consist's controlling vehicle (ctOwner) - so the
event still resolves correctly if a wagon happens to trigger it ahead
of its locomotive.

+0 (train name / stations left / stop flag) predates that pattern and
never got it: it required m_activator->Mechanik directly and silently
wrote nothing otherwise. A whois hook placed where the loco doesn't
necessarily lead (e.g. a train that reverses direction, or one being
propelled) can have a wagon trigger the event first and the memcell
stays empty, with no error - hard to diagnose from scenery side.

Same owner-selection, same guard semantics (still nothing written if
neither the activator nor its consist has a controller), only the
source of the vehicle it reads from is widened.
2026-09-04 21:01:33 +02:00
6befd69968 Merge pull request #149 from combolek/getpf
state_manager: Optimize computation of pressure flow for Oerlikon ESt valves
2026-09-04 16:39:49 +02:00
maj00r
a9b561cd65 Merge pull request #162 from MaSzyna-EU07/bugfix/260825-00jor
make targetfps great again
2026-09-03 22:18:16 +02:00
jakubg1
db6296124b Merge pull request #166 from jakubg1/dev/revert_remove_instructor_panel
Revert "Remove training card window"
2026-09-02 12:37:40 +02:00
jakubg1
ba19db8715 Revert "Remove training card window"
This reverts commit 363b50c9c2.
2026-09-02 12:32:35 +02:00
jakubg1
4e35a5f45f Merge pull request #160 from jakubg1/dev/remove_instructor_panel
Remove training card window
2026-09-02 11:59:49 +02:00
jakubg1
a2f62c56ff Merge pull request #161 from jakubg1/dev/epfuse_engage_fix
Fix EP fuse auto-(dis)engaging
2026-09-02 11:59:30 +02:00
766a957527 Fix relfections on default shader and tonemapping 2026-09-01 20:41:06 +02:00
maj00r
0aceb120e2 make targetfps great again 2026-08-25 18:03:55 +02:00
jakubg1
f8cb5e4431 Fix EP fuse auto-(dis)engaging
When the Autorewident function is enabled, the EP fuse switch will no longer automatically engage or disengage if the player is controlling the train. This would happen for example when approaching a station.
2026-08-24 00:24:15 +02:00
jakubg1
363b50c9c2 Remove training card window
This was a leftover from attempts at modifying MaSzyna for professional simulators.
Interaction with this window could cause a crash.
2026-08-23 22:37:33 +02:00
jakubg1
9a0b63a97c Merge pull request #133 from dos1/launcher-panel
launcher: Open on scenery list panel
2026-08-23 21:53:12 +02:00
df9ba73a88 Merge pull request #158 from MaSzyna-EU07/migrate-to-actions
Migrate to actions
2026-08-20 23:11:27 +02:00
66302bd88e Remove appveyor and update readme 2026-08-19 14:50:28 +02:00
8024c2be7b Revert "Delete appveyor.yml"
This reverts commit 8a22553e7c.
2026-08-19 14:48:03 +02:00
3c61168783 Revert "Delete azure-pipelines.yml"
This reverts commit 67bb6e1d3c.
2026-08-19 14:47:59 +02:00
67bb6e1d3c Delete azure-pipelines.yml eu07-2026.423-prerelease 2026-08-19 14:45:49 +02:00
8a22553e7c Delete appveyor.yml eu07-2026.422-prerelease 2026-08-19 14:45:33 +02:00
6b50a6aa68 Update CI configuration for Windows and Linux builds 2026-08-19 14:23:40 +02:00
1cfe44a9d3 Add Linux Python environment setup in workflow
Added a step to prepare a Linux Python environment with a virtual environment and install Pillow.
2026-08-19 14:07:30 +02:00
fee2dcea28 Fix path for vswhere.exe in build_bin.yml 2026-08-19 13:20:53 +02:00
af08beaaa8 Change push branch filter to include all branches 2026-08-19 13:17:00 +02:00
518ac093ac Rename workflow from 'Build' to 'Build binaries' 2026-08-19 13:15:29 +02:00
9d1a8244ed Add GitHub Actions workflow for building binaries 2026-08-19 13:14:53 +02:00
4dcf0abfa1 Merge pull request #157 from MaSzyna-EU07/python-add-dynamicbrakectrlpos
Add DynamicBrakeCtrlPos to python
2026-08-19 10:32:16 +02:00
4aa4918a36 Merge pull request #155 from MaSzyna-EU07/fix/default-shader-reflections
Fix default shader reflection
2026-08-19 10:03:45 +02:00
dcd87d8c80 Merge pull request #156 from MaSzyna-EU07/fix-traxx-independent-brake
Fix "Traxx" local brake
2026-08-19 10:03:11 +02:00
Ryba04
763a76d48c Expose dynamic brake controller position to python script dictionary 2026-08-19 00:55:24 +02:00
Ryba04
7cc6a67399 Followed sonar's suggestions 2026-08-18 20:34:37 +02:00
Ryba04
7d3b9a7360 Fix "Traxx" local brake 2026-08-18 00:04:31 +02:00
3b4df9bb6d Fix default shader reflection 2026-08-17 18:51:36 +02:00
Ryba04
72f932e5d9 Add independent dynamic brake support (eg. Vectron) to UART controllers 2026-08-16 21:34:22 +02:00