18
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-15 03:39:05 +01:00
Commit Graph

67 Commits

Author SHA1 Message Date
8701c5de02 Merge branch 'master' into feat/renderers-cleanup 2026-11-10 17:09:09 +01:00
e433b43fef Script screens: led_post and resize of the Lua screens on the gpu 2026-11-10 16:22:35 +01:00
c4924f756d Lua script screens beside the WebAssembly ones 2026-11-10 15:29:25 +01:00
18c333b089 wasm display support 2026-11-10 00:57:37 +01:00
7edf23b8ff Merge pull request #270 from MaSzyna-EU07/fix/fpslimit-frame-pacing
fpslimit: pace frames in integer clock ticks, show the real frame rate (eu07/maszyna#416)
2026-11-09 12:56:40 +00:00
jerrrrycho
8fb596f218 fix(simulation): any exception ends a test run with error, other runs as on master
main() tells a test run (--test) apart before anything runs. Only a test run
catches every exception and installs a std::terminate handler, both ending the
run with the error code and a test: line; any other run keeps master's
exception handling, so on Linux an uncaught runtime_error aborts at the throw
site again.

A test run doesn't start the Discord RPC thread: it published the test
scenery as the player's presence and held the closing up to 5 s.

run.py drops a case scenery's .sbt cache after a run cut short (wall_timeout,
error, a crash, killed by run.py), which could have been writing it.

The -edit branch of the test command line parser had no effect (a token that
isn't an option is ignored either way) and is gone; its test checks what can
be seen instead.
2026-11-08 19:46:16 +01:00
jerrrrycho
03a417c7b0 feat(simulation): a real time watchdog ends a test run that hangs
A test run that hung, in the loading or anywhere else, waited until whoever
started it killed it. A watchdog thread now ends a run still going test.wall_timeout
seconds of real time after the start of the simulator, loading included: it says
`test: timeout ... still running after N s of real time` and quits with the
timeout code, whatever the main thread is doing, with no dialog. A test that has
ended but whose simulator doesn't close ends with its own result.

The limit is test.wall_timeout (settings, the scenery's config block) or
--test-wall-timeout, which wins. Not given, it is test.timeout + 600 s: ten
minutes for the loading, and a simulation that runs at least as fast as real
time is never cut short. test.timeout 0 means no watchdog unless the limit is
given; test.wall_timeout 0 turns it off.

run.py passes the case's timeout as --test-wall-timeout and kills a simulator
only 30 s after it. A timeout from the watchdog counts as wall_timeout there, so
a run that hung doesn't pass a case expecting the simulation time to run out;
test_mode_wall_timeout ends while loading on a limit of 2 s.
2026-11-08 11:33:36 +01:00
jerrrrycho
14d25520f3 fix(simulation): a test's standard output carries its result only
The log was printed in colour to stdout too (debuglog bit 2), so a script reading
the verdict of a test got the whole log with it. In test mode the log goes to the
log file only and stdout has the `test: ...` line alone; the usage text of a bad
command line goes to stderr. Whether the run is a test is now known before the
log service starts.
2026-11-08 11:23:02 +01:00
jerrrrycho
1626df2bc4 fix(simulation): a scenery's config block can't turn back on what a test keeps off
The config block of a scenery is read like the settings files, after the test
mode settings were applied, so a scenery with soundenabled, multiplayer,
execonexit, feedbackmode or the like in it got them back in a test run. The test
mode settings now are applied again after each config block of the scenery;
apply_test_mode_settings() moved to simulationtest.cpp for that.
2026-11-08 11:22:37 +01:00
jerrrrycho
7f8892cda6 fix(simulation): a test doesn't read the player's own eu07.ini
The simulator reads eu07.ini from %APPDATA%/MaSzyna (~/.config/MaSzyna on Linux)
when there is one, in place of the game folder's. A test run then depended on
whose machine it ran on. With --test only the game folder's eu07.ini is read,
then the files given with -ini. The test mode options are taken from the command
line before the settings for that; --test-timeout still wins over test.timeout
of any settings file.
2026-11-08 11:21:57 +01:00
jerrrrycho
486a714f52 refactor(simulation): the rules of the test mode in a file of their own, with unit tests
The command line options of the test mode and the end conditions checked after
each frame are now plain functions in simulation/simulationtestrules.cpp, which
needs nothing of the running simulation: parse_test_command_line() and
evaluate_frame(). The file is part of the core library, so the unit tests check
them (tests/unit/test_test_mode.cpp): the --test-timeout value, values of other
options not taken for options, a pass that waits for the stop, the standstill,
the timeout. test_manager only gathers what a frame brought and acts on the
verdict. No change in behaviour.
2026-11-08 11:20:52 +01:00
jerrrrycho
93e2b85d08 fix(simulation): the test mode gives nothing to the outside and leaves the player's files alone
The test mode turned off what comes in from outside, but a few settings
of the user's eu07.ini still reached out of a test run:

- feedbackmode: 1 and 2 toggle Caps Lock / Scroll Lock by injecting key
  events into the whole system, 3 and 4 drive an LPT port or a PoKeys
  desk (and 4 reads the desk's switches);
- multiplayer: events are reported to a multiplayer server, and some
  events are held back for it;
- execonexit: a program is run with system() at the end of each run,
  which also waits for it;
- showsystemconsole: a console of the run's own pops up and stdout is
  reopened on it, so whoever started the test with a redirected output
  doesn't get the `test:` line (and a console the run was started from
  would be hidden without it);
- imgui.ini in the game folder was written by every run, and by several
  at once with run.py -j.

All of these are off in test mode. Nothing changes outside it.
2026-11-08 09:36:51 +01:00
jerrrrycho
4356e7c3fd fix(simulation): a test run that can't start ends with the error code and says why
- `--test` is looked for before the rest of the command line is read. An
  unknown option before it (e.g. `-s x.scn --test-timout 90 --test`) used
  to end the run with exit code 0, which a caller reads as a pass.
- `--test-timeout` without a value, or with one that isn't a number of
  seconds, fails the run instead of leaving the default or, through atof,
  turning the timeout off.
- These, a missing -s, a failed start and an exception caught in main()
  end the test through test_manager::conclude(), which writes the usual
  `test: error (exit code 5) ... : <reason>` line to stdout and the log.
  Before, `eu07 --test` alone exited with 5 and nothing anywhere: the
  error went to the log queue and the process ended before the log
  thread wrote it. In test mode main() now stops the log thread and
  waits for it before _Exit().

Outside the test mode nothing changes: conclude() does nothing there.
2026-11-08 09:36:28 +01:00
jerrrrycho
e8c4f3592e fix: fpslimit paced in integer clock ticks, FPS shown counts the wait (eu07/maszyna#416)
The limiter slept off the rest of each frame with sleep_for() given a float
duration. MSVC adds that to steady_clock::now() in float nanoseconds, so after
a few hours of system uptime the wake-up time is rounded to tens of ms: at
95 h uptime fpslimit 60 had no effect at all and fpslimit 30 gave ~22 fps, in
the full and the legacy renderer alike.

frame_pacer now schedules frames on a fixed cadence in steady_clock ticks and
the loop waits with sleep_until; an overshooting wait is made up in the next
frame. The FPS shown and the motion blur use the new mainloop_period stopwatch
(frame start to frame start, wait included); the targetfps/fpsaverage
draw-range controllers keep reading the work time as before.

(eu07/maszyna#416)
2026-11-07 18:47:41 +01:00
jerrrrycho
dd019d88ba feat(simulation): the test mode takes no input from outside (eu07/maszyna#541)
With --test the gamepad, mouse picking, UART, ZeroMQ and motion telemetry are
off, the hidden window gets no key, mouse, scroll or char callbacks, and the
window procedure that takes WM_COPYDATA commands from other programs isn't
installed, so nothing but the scenery drives a test run.
2026-11-07 17:38:37 +01:00
jerrrrycho
441caeed64 refactor(simulation): tidy the test mode code
The test manager is reached through simulation::test() instead of a global,
the result cell is owned by a unique_ptr until the memory table takes it, the
cell value is compared with a margin, strings are built with std::format and
the --test settings moved to apply_test_mode_settings(). The driver's signal
check is folded into UpdateSpeedPosition(), which updates a speed table entry
and reports a signal at stop the head of the train just passed. The test.*
keys are listed with the other settings at the start of the log.
2026-11-07 17:12:11 +01:00
d4120ea5db Merge branch 'master' into feat/renderers-cleanup 2026-11-07 16:44:51 +01:00
jerrrrycho
02e29f6971 feat(simulation): test mode, --test runs a scenery unattended and exits with the result (eu07/maszyna#541)
eu07 --test -s <scenery> [--test-timeout <s>] runs the scenery in ghostview with
the null renderer (models loaded, no textures), a hidden window, no sound,
network or python, and in fixed steps of 0.03 s of simulation time per frame
(three 10 ms physics steps) as fast as it can. Without -seed it uses a fixed
seed, so two runs give byte-identical physicslogs.

The scenery reports its result to the __test.result memory cell, which the
simulator always creates: value 1 passes once every vehicle has stood still for
1 s, value 0 fails at once. The run ends with exit code
  0 pass, 1 fail,
  2 a train passed a signal at stop (SetVelocity 0 0, as seen in its driver's
    speed table; SetVelocity 0 x on automatic block doesn't count),
  3 timeout (test.timeout, default 3600 s of simulation time),
  4 standstill (every vehicle still for test.standstill s, default 300, with no
    result; a pass with test.pass_on_standstill yes),
  5 error (no -s, the scenery didn't load or has no vehicles, an exception).
The test.* keys go in the scenery's config block; test.fail_if_stop_overran no
only logs a signal passed at danger. Outside the test mode a signal passed at
danger is logged.

The null renderer gets a ui backend which draws nothing, hands out the null
texture and material instead of throwing, and ends the ui frame. A GL context
is still made for the hidden window, without asking for a version, as parts
of the ui create textures with gl calls of their own. No crash dialog or
message box in test mode; the window code no longer needs a monitor.
2026-11-07 16:20:42 +01:00
jerrrrycho
798fd89dd0 test: scenario tests that run the simulator and check a vehicle's physicslog
tests/scenarios/run.py builds a test scenery from a game install's scenery
(own trainsets removed, case fragment added), runs eu07 in ghostview with
physicslog on, and checks what the vehicle did: starts, max speed, brakes,
stops. First case: EU07 on td.scn driven by AI on the td/rozklad timetable,
with the Stacja1 exit route set by an event launcher instead of shift+4.

eu07 gets a -ini <file> option: an extra settings file read after eu07.ini,
so a test run can switch to a window and turn on physicslog without touching
the user's config.

Local only: scenery and vehicle data are not in the repo.
2026-11-07 16:20:41 +01:00
maj00r
a6778c9fe2 refactor: the Sonar remarks on the small fixes taken care of
- the log stops through a flag kept in a function, not a global one
- the messages are put together with std::format
- a vehicle dropped on a trainset in the launcher goes in once the
  trainset is drawn, so the vehicles are gone through with a plain loop
  again; the drop split into a new vehicle and a moved one
- the scenario that can't be opened is caught as the runtime error it
  is, a file name outside of the code page as the system error it is
- a track of an unknown type is left out through the pointer owning it
- the keyword of a track type written out by a function of its own
- the picked node forgotten with ranges::replace_if, the empty
  Forget_Node of the base renderer told why it is empty
- FileCased takes the path it works on
2026-11-06 19:54:54 +01:00
maj00r
ed0ff36a69 fix(app): a scenario failing as it loads goes back to the launcher too, the files of other cases looked for only off Windows
A scenario failing past its opening popped the loader mode and went on to pop it again and push the driver mode with the scenery half loaded; it goes back to the launcher as one that can't be opened. FileCased() goes through the folder only where the file system tells the case apart: on Windows a missing file was looked for in its whole folder for nothing, and a name outside the code page threw from the parser. The Discord thread sleeps a quarter of a second outside the driver mode, not to hold the closing up.
2026-11-03 21:53:52 +01:00
maj00r
b34238f33f fix(app): the log written to the end of the closing, each step of it with its time; the Discord thread idle outside the driver mode
The log service stopped with applicationQuitOrder, so whatever was logged while the simulator closed was lost; it now runs until StopLogService() and writes out what came before. The closing logs each of its steps with the time since it began, to tell where a closing that hangs stops. Outside the driver mode the Discord thread spun a core in its loop, it now sleeps a second between the checks.
2026-11-03 21:45:57 +01:00
765153ad91 Merge remote-tracking branch 'origin/feat/switch-blades' into feat/renderers-cleanup 2026-10-29 23:55:04 +01:00
55372571b3 Merge branch 'master' into feat/renderers-cleanup 2026-10-29 20:42:39 +01:00
a6bdeeaa2b Add DLSS Frame Generation (gfx.framegeneration x2/x3/x4) and Reflex (gfx.reflex) to the Vulkan renderer 2026-10-25 20:52:12 +01:00
maj00r
b74a200bdf test(editor): EU07_EDITOR_SELFTEST_HIDDEN runs a selftest in a window never shown nor focused, full screen or not, for the computer in use meanwhile 2026-10-24 21:12:28 +02:00
bd589f272d feat(vulkan): vulkan 1.4 core with the user interface and the launcher, shaders split into ogl46/vk14 with SPIR-V binaries loaded first 2026-10-24 05:47:11 +02:00
68fa5dc2da feat(vulkan): gfxrenderer picks the opengl 4.6 or the vulkan 1.4 renderer (B1-B3) 2026-10-24 03:06:33 +02:00
336690ad8a perf(debug): debug.memorystats switch for the heap counting (off by default) and the places of the large heap blocks in the memory section 2026-10-23 23:10:32 +02:00
52df707f30 perf(debug): parts of the vehicle update in the debug panel: scenery animations, power grid, roads, preparation, forces, vehicle update and ai, with the counts of vehicles and physics steps; input and the start of the ui frame timed apart 2026-10-23 17:26:44 +02:00
fc714d50ec perf(debug): cpu timers of the simulation and the main loop, cpu time of the frame parts next to the gpu, renderer data of the debug panel in folding sections 2026-10-22 20:54:30 +02:00
maj00r
04af7d5758 fix(python): stop python workers before destroying windows on exit 2026-10-21 21:23:29 +02:00
12c2aaf1db chore: remove the NVRHI-based betterRenderer 2026-10-21 19:30:32 +02:00
maj00r
9696b5f795 fix: closing the simulator no longer makes a destroyed window current
The python task queue was stopped after the windows were destroyed, and
its worker, leaving, released the context of its own window, which was
gone by then: a use after free on every exit. The queue is stopped
first.
2026-10-21 08:41:59 +02:00
de9f61b307 Merge remote-tracking branch 'origin/feat/switch-blades' into feat/gl46-migration 2026-10-19 22:13:43 +02:00
maj00r
ff1710d9ea feat(editor): labels for a layman, light at the start; whole sceneries fitted to the terrain model
Labels:
- every button, field, tooltip and message of the editor reread for a beginner: short nouns for the fields with the
  sentence in the tooltip, the less used options under More settings, one glossary (field of work, template, track,
  grade), sides told from directions, degrees and per mille as signs, messages built from one format string
- plural forms through STR_P; the last entry of a po file is read too, and the Polish plural rule is in the header
- lang/editor_pl.po: the code pass entries merged, 391 entries no code uses and 3 duplicates dropped
- roads: the notes and errors naming a road translated; the build options and the layout fold the texture length,
  kerb sizes, traffic share, roundabout part, height over the ground and junction speed limit under More settings, the
  lanes start folded

Grade lines fitted to the terrain model (NMT), a line or the whole scenery at once:
- fit_ground: a robust fit on nodes 5 m apart; the ground parting from the line (a bridge, a viaduct, a wall) is gone
  past rather than followed, the bends keep off the switches as far as their curves reach, a run of bends the same way
  is one point of intersection, a curve with no room is as sharp as the room lets it be
- the ends of the line and the other paths of its switches leading into lines fitted already bound the line by what
  the tracks between can climb; ends meeting in the plan, laid apart in height by hand, are joined before the run
- apply_profile: the paths are split where split_path takes the parameter (a straight was cut in the wrong place, into
  pieces of a few centimetres the game takes for zero length), no piece shorter than the margin; the paths off the
  ends of the route are brought to its height
- Bytom: 1600 lines, grade breaks at the joints 89 -> 20; Tarnowskie Gory: 848 lines, 223 -> 3; no step over 2 cm
2026-10-19 15:27:50 +02:00
maj00r
2a3d7f2e29 feat(editor): scripted mouse and keys of a self-test are delivered between frames like real input events, so a press seen by ImGui starts a drag as it does by hand; while a script drives the input the real mouse and keyboard are ignored 2026-10-17 23:30:37 +02:00
f47172f34d Migration cleanup and renderer documentation 2026-10-15 19:05:35 +02:00
9e64244ebd Require OpenGL 4.6 core context and regenerate glad 2026-10-15 01:39:32 +02:00
0e10ce4d0b Remove OpenGL ES / ANGLE render path 2026-10-15 00:53:28 +02:00
3d3eef2e1c Remove legacy OpenGL 2.1 renderer 2026-10-15 00:06:31 +02:00
jerrrrycho
8125166690 Fix/sonar reliability security (#205)
* fix(sonar): addressing reliability/security issues

* fix(sonar): addressing reliability/security issues

* fix(sonar): addressing reliability/security issues

* fix(sonar): addressing last reliability/security issues

* fix(sonar): addressing last reliability/security issues

* fix(sonar): addressing last reliability/security issues

* refactor(sonar): imgui update

* refactor(sonar): hasChar revert
2026-10-11 15:31:45 +02:00
9935257783 Add nosonar tags 2026-10-09 18:40:31 +02:00
344034ec70 feat(ui): imgui 1.91.9b-docking in place of 1.73: local changes of the backends carried over (glad as the gl loader, srgb and gamma of the ui, gles glsl string), BufferingBar/Spinner kept, imgui_tables in cmake; cursor position, cursor enter and focus of the main window passed to the glfw backend, which works with events now; code adapted to the api: ImGuiListClipper::Begin, BeginListBox, ImTextureID as an integer, ImageButton with an id, ImGuiKey without GetKeyIndex, logarithmic sliders in place of the removed power argument; ImGuizmo with the math operators defined before imgui.h and SetNextFrameWantCaptureMouse 2026-10-08 20:38:13 +02:00
917c8f7285 Merge branch 'master' into feat/modern-editor 2026-10-08 17:44:58 +02:00
maj00r
0a3cd55e59 feat(launcher): -edit without a scenery opens the wizard of a new scenery: file name, title and centre, picked on the OpenStreetMap map of geoportal.gov.pl in PUWG 1992 or given in degrees; the scenery is written with the centre as its //$g reference and opened in the editor; a bare -edit no longer loads the scenery of eu07.ini 2026-10-06 22:19:40 +02:00
jerrrrycho
79bd0c8e91 fix(sonar): addressing reliability/security issues (#202) 2026-10-04 20:00:13 +02:00
73f2f68aa0 feat(editor): edit session (-edit) and scenery layers 2026-10-02 21:29:18 +02:00
jerrrrycho
176427f96b refactor: sonar c++20 changes (#185) 2026-09-28 21:08:15 +02:00
jerrrrycho
4137f5504a fix: sonar sast fixes - sonar.yml, nosonar, linux chmod modification 2026-09-28 21:07:53 +02:00