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

729 Commits

Author SHA1 Message Date
jerrrrycho
b400255dae Test/physics unit tests (#213)
* build: doctest 2.4.11 in ref/

Single header test framework (MIT), vendored like the other libraries in
ref/ so the tests need nothing extra installed on the CI runners.

* refactor(physics): read vehicle definitions from text as well as files

TMoverParameters::LoadFIZ(path) opens the file and hands the parser over
to LoadFIZ_Parse(), which holds what LoadFIZ() did with it before. The
new LoadFIZ_Text() reads the same format from a string, so a definition
can be made up in memory, e.g. by a unit test. No change in behaviour for
files.

* build: the simulation core as a library the game links

The vehicle physics (McZapkie), the vehicle definition parser and the
helpers they use build as eu07_core, a static library the game links,
so the unit tests to come can link the very same objects instead of
compiling their own copy with their own settings.

The game's build settings (include dirs, definitions, compile options,
libraries) move from the executable to eu07_settings, an interface
target the library links publicly, so the game, the library and later
the tests all build with the same ones. What only the executable needs
stays with it: /MAP, /LARGEADDRESSAWARE, output dirs, the precompiled
header, runtime DLL copying, the crash reporter and the experimental
renderer. No change in what the game builds or links.

* test: unit tests of the simulation core, run as part of the build

eu07_unit_tests: C++ tests (doctest) of the simulation, which set up the
conditions, run the code and check the outcome. No game data, no window.

- the code under test is the core library (eu07_core), the very objects
  the game links, built with the game's settings; engine_stubs.cpp stands
  in for the logs, settings and scenery layers the library reaches for.
  python gets linked with the settings but isn't needed to run the tests
- test vehicles are JSON definitions in tests/unit/data, with the sections
  and keys of the game's vehicle definitions (tables as "rows", _keys are
  comments), changed by the tests where needed and loaded from memory by
  the game's own loader; an unknown section is an error rather than
  silently skipped
- test::vehicle creates the mover the way TDynamicObject::Init() does and
  steps it the way the simulation loop does, on a straight track of given
  friction and gradient, optionally holding the brake pipe pressure the
  way a coupled locomotive would
- the random numbers of the simulation are reseeded before every test
  case, so a test gives the same result alone (IDE) or among the others
- building the game runs the tests at the end, once the game is linked,
  and prints a one line summary ("Unit tests: 11/11 passed (80 checks)").
  A failure prints the full report and fails the build, in CI and locally
  alike, and removes the game binary so the next build reruns them. A
  change of the tests alone relinks the game so they run (Ninja and
  Makefile generators). -DWITH_TESTS=OFF leaves them out
- first tests: definitions reach the vehicle, KE service application and
  release, deeper reduction brakes harder, every implemented distributor
  valve charges/applies/releases, service braking stops a moving wagon

* test: stub basic_node::radius_() for GCC and Clang

The Linux build failed to link the unit tests: undefined reference to
scene::basic_node::radius_() from basic_node's vtable in engine_stubs.o.
basic_node has no key function for the Itanium C++ ABI (tooltip() is
declared plain but defined inline in the header), so GCC and Clang emit
its vtable in every unit using scenenode.h, and the vtable needs
radius_(), defined in scenenode.cpp, which the tests don't link. MSVC
emits vtables differently, so the Windows build linked.

* test: test vehicle definitions load with GCC and Clang

All the tests reading a definition failed on Linux with "unknown vehicle
definition section 0": the parsed definition was brace-initialised
(auto const json{parse(...)}), which GCC and Clang take for the
initializer list constructor of nlohmann::json, making an array holding
the definition, while MSVC copies it. Initialise it with =, and require
the definition to be a JSON object.


* test: SonarCloud issues of the unit tests

- test::definition_error for unusable test vehicle definitions instead of
  std::runtime_error (S112)
- the rows of a table section written by a function of their own, less
  nesting in definition::text() (S134)
- std::less<> for the section table (S6045)
- comments in the empty methods of the reseeding listener and stub (S1186)
- NOSONAR where the engine's headers fix the stubs: the extern globals
  and the member function signatures (S5421, S5817, S1238)
- NOSONAR on LoadFIZ_Parse(): the cognitive complexity is the former body
  of LoadFIZ(), moved as it was (S3776)
- a comment Sonar took for code reworded (S125)
2026-10-15 17:56:41 +02:00
combolek
3ed864812f Fix line endings (#211)
There where some extra CRs introduced in a recent commit.
2026-10-11 20:42:09 +02:00
jerrrrycho
6263fe539b Fix/sonar maintainability rebased (#209)
* refactor(sonar): use override instead of redundant virtual (cpp:S3471)

* refactor(sonar): remove empty statements, one declaration per statement (cpp:S1116, cpp:S1659)

* refactor(sonar): drop redundant lambda return types (cpp:S3574)

* refactor(sonar): prefer using over typedef (cpp:S5416)

* refactor(sonar): use =default for trivial special members (cpp:S3490)

* refactor(sonar): use nullptr literal (cpp:S4962)

* refactor(sonar): remove redundant access specifiers (cpp:S3539)

* refactor(sonar): remove redundant casts (cpp:S1905)

* refactor(sonar): use std::scoped_lock instead of std::lock_guard (cpp:S5997)

* refactor(sonar): construct elements in place with emplace_back (cpp:S6003)

* refactor(sonar): make narrowing conversions explicit (cpp:S5276)

* refactor(sonar): mark unused parameters (cpp:S1172)

Unused names are commented out; parameters used only on some platforms
are marked [[maybe_unused]].

* refactor(sonar): declare non-mutating member functions const (cpp:S5817)

Virtual functions are left untouched so overrides keep matching.

* refactor(sonar): merge collapsible nested if statements (cpp:S1066)

Comments that preceded the inner if are kept above the merged statement.

* refactor(sonar): scope single-use variables in if init-statements (cpp:S6004)

* fix(sonar): give polymorphic base classes virtual destructors (cpp:S1235)

* refactor(sonar): use try_emplace for map insertion (cpp:S6030)

* refactor(sonar): use auto where the type is spelled out on the right (cpp:S5827)

* refactor(sonar): remove redundant parentheses (cpp:S1110)

* refactor(sonar): document intentionally empty functions (cpp:S1186)

* refactor(sonar): remove dead stores (cpp:S1854)

Side effects (e.g. LISTLINE++) are kept.

* refactor(sonar): remove unused variables, captures and private fields (cpp:S1481, cpp:S1068)

* refactor(sonar): use structured bindings for pair access (cpp:S6005)

* refactor(sonar): use range-based loops and ranges algorithms (cpp:S5566)

* refactor(sonar): split chained assignments (cpp:S1121)

* refactor(sonar): add default cases to switch statements (cpp:S3562)

* refactor(sonar): use std::size for array lengths (cpp:S7127)

* refactor(sonar): use std::ranges algorithms and std::erase(_if) (cpp:S6197)

* refactor(sonar): access static members through the class (cpp:S2209)

* refactor(sonar): add braces around nested if-else (cpp:S5261)

* refactor(sonar): avoid side effects inside typeid operands (cpp:S5279)

* refactor(sonar): drop top-level const from by-value return types (cpp:S5951)

* refactor(sonar): declare variables separately from their type definitions (cpp:S3646)

* refactor(sonar): declare loop counters in the for statement (cpp:S5955)

* refactor(sonar): rely on class template argument deduction (cpp:S6012)

* refactor(sonar): inherit base constructors instead of forwarding them (cpp:S5952)

* refactor(sonar): rename locals that shadow outer declarations (cpp:S1117)

Only local variables and definition parameters are renamed; shadowing
struct fields and enumerators in headers are left for a separate change.

* refactor(sonar): reduce enum qualification with using enum (cpp:S6177)

Applied only where no unqualified name in the block could be captured by
the introduced enumerators.

* refactor(sonar): mark converting constructors explicit (cpp:S1709)

sound_source and the gl::object conversion operators stay implicit; they
are relied upon by copy-list-initialisation and GL calls.

* refactor(sonar): initialise members in initialiser lists or declarations (cpp:S3230)

* refactor(sonar): make read-only local references and pointers const (cpp:S5350)

* refactor(sonar): take read-only pointer and reference parameters as const (cpp:S995)

TTrain command handlers keep their signature, it is fixed by the handler table.

* refactor(sonar): pass expensive-to-copy parameters by const reference (cpp:S1238)

Signatures declared in files touched by PR 206 (Driver.h, EU07.cpp) and
virtual overrides are left unchanged.

* refactor(sonar): use transparent comparators for string-keyed maps (cpp:S6045)

std::unordered_map instances and map types exposed in headers used by
other modules are left as they are.

* fix(sonar): do not use UI text as a printf format string (cpp:S5281)

Text lines containing '%' would otherwise be interpreted as format
specifiers by ImGui::TextColored.

* refactor(sonar): use std::bind_front for callbacks (cpp:S5995)

* refactor(sonar): drop const_cast on string literals passed to the Python C API (cpp:S859)

* refactor(sonar): take read-only string parameters as std::string_view (cpp:S6009)

The Windows messaging helpers keep std::string, they need c_str().

* refactor(sonar): make read-only global tables const (cpp:S5421)

Mutable global state (flags, timers, singletons) is left as is.

* refactor(sonar): replace single-case switch statements with if (cpp:S1301)

* refactor(sonar): format UUIDs and log timestamps with std::format (cpp:S6494, cpp:S5945)

* refactor(sonar): use std::array for local fixed-size arrays (cpp:S5945)

Arrays that are class members or part of headers are left unchanged.

* fix(sonar): test the bearing damage bit, not bit 0 (cpp:S872)

'DamageFlag & dtrain_bearing > 0' parsed as 'DamageFlag & (dtrain_bearing > 0)',
i.e. DamageFlag & 1, so bearing friction reacted to the wrong damage flag.

* refactor(sonar): assorted small fixes

- empty() instead of size() comparisons (cpp:S1155)
- member initialisers in declaration order (cpp:S3229)
- no redundant c_str() when a std::string is accepted (cpp:S7121)
- contains() on associative containers (cpp:S6171)
- const reference instead of a copying range-for (cpp:S6032)
- starts_with() for prefix checks (cpp:S6178)
- no std::move on temporaries (cpp:S5274)
- has_value() on std::optional (cpp:S7172)
- bool literals for bool members (cpp:S5820)
- inline only on the definition (cpp:S3548)
- explicit base access specifier (cpp:S5965)
- explicit element access instead of dereferencing an array (cpp:S7116)
- rely on the C++20 rewritten operator!= (cpp:S6186)

* refactor(sonar): more small fixes

- std::format instead of iostream manipulators in to_string/to_hex_str (cpp:S6495);
  output verified identical, negative hex values keep the unsigned form
- remove an empty compound statement (cpp:S108)
- drop an always-false unsigned < 0 branch (cpp:S1768)
- explicit lambda capture (cpp:S3608)
- std::make_unique (cpp:S5950)

* chore: strip stray carriage returns left in TTrain constructor comments

* fix: keep quantize() in its own value type

The S5276 change cast the result of the generic quantize<Type_>() to
unsigned int, which truncated float/double callers (shadow angle slider,
editor rotation snapping, AI speed control steps) and broke negative values.

* fix(sonar): use integer loop counters in segment sampling (cpp:S2193)

* refactor(sonar): clean up issues reported on PR 209

- remove locals left unused after the dead-store cleanup (cpp:S1481, cpp:S1854)
- unnamed unused parameter (cpp:S1172)
- single-use declarations moved into if init-statements (cpp:S6004)
- auto for casted initialisers (cpp:S5827)
- const references and pointers where nothing is modified (cpp:S5350)
- rename structured bindings shadowed by inner declarations (cpp:S1117)
2026-10-11 13:22:33 +02:00
jerrrrycho
79bd0c8e91 fix(sonar): addressing reliability/security issues (#202) 2026-10-04 20:00:13 +02:00
jerrrrycho
76a39af8c2 fix: bound MotorParam and MPTRelay indices (#196) 2026-10-01 20:21:01 +02:00
jerrrrycho
06078ddab9 fix: other sonar sast fixes (#193) 2026-10-01 13:30:25 +02:00
jerrrrycho
f05b58b0e9 Revert "fix: yet other sonar sast fixes"
This reverts commit 403a6d1f9f.
2026-10-01 08:01:23 +02:00
jerrrrycho
403a6d1f9f fix: yet other sonar sast fixes 2026-10-01 07:58:28 +02:00
pwarszawski
96be688d13 Send the reverser position, not the absolute direction, when activating a cab
CabActivisation() passed DirAbsolute (DirActive * CabActive) as the value of the
"Direction" command, which every receiving vehicle stores as its own DirActive.
Every other sender passes DirActive. With the cab at the rear end (CabActive = -1)
the two have opposite signs, so the other units got their reverser flipped
against the controlling one.

It shows whenever a rear cab is activated after the reverser has been set:
- the AI takes over an occupied cab (TakeControl() calls CabActivisation(true)),
  e.g. an EN57 inserted with reardriver and a starting velocity: the motor car
  drives the train backwards;
- a vehicle without automatic cab activation (SA134) driven by the AI from the
  start: the cab is activated by a driver hint after the reverser is set, and
  the two units pull against each other.

Fixes #169.
2026-09-30 15:00:12 +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
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
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
combolek
19441b5e91 Convert Przekladniki to std::array 2026-07-28 09:28:10 -07:00
combolek
12c583f418 Fix some SonarQube warnings 2026-07-28 08:54:33 -07:00
combolek
00bb44a789 state_manager: Optimize computation of pressure flow for Oerlikon ESt valves
TNESt3::GetPF() is a *major* hotspot in simulation state update. The leading cause is the use of typeid (RTTI) which is implemented in the C++ runtime essentially as a string compare. This change eliminates the use of typeid and instead caches statically typed pointers for the few TPrzekladnik subclass objects that need their parameters adjusted in TNESt3::GetPF(). As a bonus some virtual methods on TPrzekladnik can now be removed. Overall this change reduces the TNESt3::GetPF() contribution from about 25% to 16%.
2026-07-26 21:19:38 -07:00
maj00r
03bfbb1345 fix: restore min>max tolerance lost in clamp->std::clamp migration
The dumb3d->glm / utilities-simplification refactor replaced the old custom
clamp() (which tolerated Lo>Hi, returning the upper bound) with std::clamp,
where inverted bounds are undefined behaviour. Only a few sites were patched
afterwards, by hand, with std::minmax plumbing (incl. a stray `static` inside
a per-axle loop). Others silently produced wrong results in the AI braking /
acceleration path.

Add a safe_clamp() helper (normalizes inverted bounds) and use it ONLY where
Lo<=Hi cannot be proven at compile time (config min/max pairs, sign-dependent
expressions, container underflow). Sites with constant bounds or [0, x>=0]
keep std::clamp. Remove the manual std::minmax workarounds and rewrite the
damaged-track jolt code value-first.
2026-07-02 00:37:52 +02:00
jerrrrycho
d85096f64d reformat: remove redundant parentheses 2026-06-30 21:19:46 +02:00
jerrrrycho
bf147dd155 refactor: replace null with nullptr 2026-06-29 02:48:25 +02:00
docentYT
e06ae37f47 replace new clamps with std::clamp and to_string with std::string 2026-05-05 23:40:59 +02:00
docentYT
5367cb9940 Merge remote-tracking branch 'upstream/master' into utilities-simplification 2026-05-05 23:08:43 +02:00
cb4b6b9a4f Separate electrodynamic and localbrake levers 2026-05-03 21:51:16 +02:00
docentYT
13c7317f6e Do not allow implicit cast for inline std::string to_string(bool Value) and change to_string to std::string for non boolean values 2026-05-03 15:49:29 +02:00
docentYT
59347af5a0 Replace some std::min and std::max combinations with std::clamp 2026-05-02 19:38:14 +02:00
docentYT
ca699d117f Remove not needed includes 2026-05-02 14:40:31 +02:00
docentYT
3628eb0fc3 Replace interpolate with std::lerp and glm::mix 2026-05-02 01:31:38 +02:00
docentYT
d1f16411a1 Replace clamp with std::clamp 2026-05-01 22:14:29 +02:00
docentYT
ec1dfae953 Replace starts_with and ends_with with string class methods 2026-05-01 17:31:11 +02:00
docentYT
337e750ed1 Replace Max0R and Min0R with std::max and std::min 2026-04-30 23:47:32 +02:00
7acc34df3e Merge pull request #97 from docentYT/migrate-from-dumb3d-to-glm
Migrate from dumb3d to glm
2026-04-28 19:46:46 +02:00
docentYT
d5d1825e38 Remove dumb3d 2026-04-27 23:03:47 +02:00
129924315d Cleanup hamulce.cpp/h with Mover.cpp/h 2026-04-27 18:21:55 +02:00
dcfd34908a Revert "Add power smoothing for inverter based vehicles"
This reverts commit 40bbbc6210.
For some reason it broke SA13x controllers lol
2026-04-17 20:08:04 +02:00
593e4bcf36 Merge branch 'master' into master 2026-04-14 21:01:04 +02:00
ae056f2bbd Merge pull request #79 from xingzihai/engine-overheat
feat: add EngineMaxTemperature support for diesel locomotive overheat detection
2026-04-14 20:49:37 +02:00
jakubg1
0d010e8c6a Simplify derailing logic, derail reason enum
- The `TMoverParameters::derail()` function has been renamed to `::Derail()`, with a capital D.
- All derail events now use that function.
  - Simplified and unified the logic behind different derail types.
  - The `dtrack_freerail` track type is now slightly increasing the chance of derailing on a tight curve, as it was the intention.
- A new `DerailReason` enum has been created which holds all derail types.
- The `DerailReason` field in the `TMoverParameters` class has been removed.
  - This was a transient field which is not necessary anymore.
  - The logging functionality as such has been moved from `DynObj.cpp` to `Mover.cpp`.
2026-04-04 02:05:49 +02:00
xingzihai
754fc50ca8 feat: add EngineMaxTemperature support for diesel locomotive overheat detection
Add engine temperature monitoring to diesel locomotive heat management system:
- Add engine field to heat_data struct (fluid_circuit_t type)
- Add EngineMaxTemperature config extraction in .fiz files
- Add engine overheat detection logic (is_hot check)
- Include engine.is_hot in PT status check

Implements issue #77: Oil, water and engine overheat lamps for diesel locomotives
2026-04-01 23:28:28 +00:00
Agent
68fa78a582 feat(overheat): Add overheat indicator lamps for oil, water, water_aux, and engine
- Add engine_max_temp and engine_is_hot fields to heat_data structure
- Add EngineMaxTemperature field extraction from .fiz files
- Add engine overheat check comparing Ts with engine_max_temp
- Add four new overheat lamp indicators:
  - i-oil_overheat
  - i-water_overheat
  - i-wateraux_overheat
  - i-engine_overheat
- Add lamp update logic to turn on/off based on is_hot flags
- Add lamp initialization in clear_cab_controls()

This implements issue #77 - overheat lamps for diesel engines.

The lamps will turn on when:
- Oil temperature exceeds OilMaxTemperature
- Water temperature exceeds WaterMaxTemperature
- Auxiliary water temperature exceeds WaterAuxMaxTemperature
- Engine temperature exceeds EngineMaxTemperature

Each check includes 8-degree hysteresis to prevent rapid on/off cycling.
2026-04-01 23:26:39 +00: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
40bbbc6210 Add power smoothing for inverter based vehicles 2026-02-08 13:04:49 +01:00
7b8fa3f226 Set wiper default pos = 0 in case not defined 2025-09-30 21:08:22 +02:00
a7c2fa22f1 Add wiperList Default parameter (for default position) 2025-09-30 21:03:38 +02:00
b969a55533 Fix lightsset command so bot wont affect it 2025-09-19 01:58:40 +02:00
Ryba04
33ad7b718f Merge branch 'master' into master 2025-09-13 19:46:26 +02:00
072165aae3 Resolve conflicts for merge 2025-09-04 20:27:45 +02:00
jakubg1
dc8de9aa07 Separate FFList from DEList, add FFEDList (ffBrakeList)
Added a new optional section to .fiz files: `ffBrakeList`. It is used instead of `ffList` whenever the vehicle has its ED braking engaged.

Example (dynamic/pkp/elf_v1/inverter_kp.fiz):
```
ffList: Size=3
0	2.0
33.7	2.08
34.0	2.12
130.4	8.10
endff

ffBrakeList: Size=4
0	2.0
33.7	2.08
34.8	2.08
34.8	2.17
130.4	8.10
endff
```
2025-09-04 04:36:26 +02:00
6e2835bdeb Remove starts with statement 2025-08-21 20:25:18 +02:00
be8218949c More linux specific blocks 2025-08-21 20:22:26 +02:00
c0437946c7 Prevent multiple battery switches in hold conditions 2025-07-23 12:29:04 +02:00
13f7551b5f Modern dimmer overhaul
Now it supports custom positions
2025-07-15 16:06:42 +02:00