mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-08 06:15:12 +01:00
917c472cc97c85a03bb7c79beb77578a0cdc7d51
20 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| 917c472cc9 |
Merge pull request #257 from MaSzyna-EU07/fix/vehicle-removal-smoke
fix(gfx): a vehicle taken off the tracks stops smoking (#90) |
|||
|
|
466cbbbfa1 |
Test/core unit coverage (#235)
* test: real vehicles and golden traces in the unit tests The game's own vehicles (dynamic/ of the release used for the tests) as JSON of what the game's vehicle loader reads of their .fiz files, includes expanded: test_fiz.cpp converts them on demand and checks the loader reads the same sections, values and rows as of the game's file (fiz.h). Chosen to cover every engine type, brake valve, brake handle, local brake, coupler type, door type and brake delay set the game data uses. Golden traces (golden.h) characterise the simulation, compared within a relative tolerance or exactly, re-recorded with EU07_UNIT_TESTS_UPDATE_GOLDEN=1: - the parameters of every real vehicle as loaded, - the brakes of every real vehicle through charge, service steps, release, overcharge and emergency, on every brake delay setting, - every position of every driver's and local brake handle, - every powered vehicle started up the way the AI does it, driven to full power and braked to a stop (drive.h), - the real electric units and a locomotive with wagons driven whole, as trains of coupled vehicles stepped the way the game steps them (consist.h), - scenarios of the controls (scenario.h): doors, reversing and cab change, slip and sand, emergency stops, releasers, the ep and the electrodynamic brake, heating, loading, a collision, and frames of several physics iterations. * test: commands passed between vehicles Every command RunCommand knows run on every real vehicle and recorded, commands travelling through a train with a vehicle facing backwards, a coupling without the control cable, and loading and unloading by commands. * test: every switch of the cab, sent to the next vehicle Each switch sending its state to the train, each way and to each range, with the controllers and direction among them, on every real vehicle driving another of its kind, recorded for both. * test: the switches of the cab worked on a pair under the catenary The same switches with two seconds for the vehicles to act on each, so the pantographs rise, the main switch closes and the auxiliaries start. * test: gauges of trains in multiple and the damage descriptions The ammeters and the brake force the AI expects, recorded on the electric units and locomotives in multiple driven, the damage described on the driver's panel and ammeters showing the current of controlled vehicles. * test: give load commands their place, as the game does The loading test set its commands with SetInternalCommand, which leaves TCommand::Location as it is: uninitialised in a fresh vehicle, so the distance check of Load= and UnLoad= read garbage and the test failed now and then. The game gives them through PutCommand with the place of the platform, and so do the tests now. * test: brake valves and handles no vehicle of the game data has Fitted to a wagon and to an EU07: the valve variants and handles the loader knows that no real vehicle uses, the CV1 ones and the test handle among them, and a name the loader doesn't know. * test: braking from speed with the automatic ED brake, and a draisine Trains with the EP09, the E6ACT and the EW58 braked by ep, light and full service applications from speed, and the draisine pumped from rest and rolling. Only the E6ACT brings its electrodynamic brake in here. * test: the EP09's electrodynamic brake in service braking held to a stop start_up() took a vehicle for ready once its line breaker was closed and its reservoir full, which a train made already moving is at once: the EP09's manually started converter was never switched on, so there was no 110 V and no electrodynamic brake. It now waits for the converter. The EP09 with wagons is braked from 120 km/h by light, medium, high and full service applications held to a stop: the motors brake, the air of its cylinders is let out and given back as the train slows down. The flag of the electrodynamic brake stays on at a standstill below 2.1 bar. C strings given to CAPTURE are shown as text. * test: the converter switched on before a train is ready, the EW58's ep-staged electrodynamic brake start_up() called a train ready as soon as its line breaker closed and the air was there, so the converter of a unit having it in another car than the cab (the EW58's middle car) was never switched on, and its electrodynamic brake, gated by the 110 V, never came in. The converter and the compressor now always get switched on first. The EW58 brakes electrically by the stages of the ep brake, not by the pipe alone. * test: the ET42 and the 214M railbus among the real vehicles The ET42's halves (its own series motor branch: the motors in series at the high current setting) and the 214MA, a diesel railbus with the hydraulic torque converter, the retarder and the controller of an induction motor drive, converted from the game data and recorded in every sweep of the real vehicles. * test: the wagons' hand brakes released with the train's brakes; the 754, SM31 and SU46 release_brakes() released the hand brake of the driver's vehicle only, so every wagon set up braked kept its hand brake on and got dragged along. It now releases the hand and spring brakes of the whole train, as TController::AutoRewident() does when the AI takes it over, and the traces of the trains with wagons are recorded anew. The 754, the SM31 and the SU46 join the real vehicles for the kinds of the diesel-electrics' field shunting relays the others lack (RelayType 0, 1 and 46). * test: traction on a lost and too high catenary voltage, the ET42, the diesel-electrics' shunting relays The line breaker opened by the voltage relays of a series motor locomotive and by the limits of an induction motor one. The ET42 at the high current setting, which keeps its halves' motors in series, and its switched electrodynamic brake, whose current trips the overload relay from the top speed of the low setting. The field shunting of the diesel-electrics through each kind of their relays, at full power and notched back. * test: the EW58's electrodynamic brake stages, the EU47's speed control and braking at the voltage's limit The stages of the EW58's motor brake set by the positions of its ep handle, the first one alone over 100 km/h. The EU47's second controller holding, raising and lowering the speed set, its local brake setting the flag of the electrodynamic brake without the motors braking, and its brake feeding back less current into a catenary over the drive's MaxV. * test: diesel engines too cold and too hot to start, the 214M railbus's controller and retarder The heat of the diesel engines: at -10 degrees the ones with the lowest water temperature set don't start until the heater warms them, at 88 degrees the ones with a second water circuit don't start while it cools, and the SM42 run hot at full power is kept under its highest temperature by its fans and shutters. The 214M railbus's controller from the air brake through the retarder and neutral to power, its torque converter's lock-up and its gearbox. The controller helpers of the traction tests (full power, waiting for the line contactors, and notching back) move to test::scenario. * test: couplers coupled, uncoupled, broken and colliding; loads assigned, loaded and unloaded Coupling by hand touching or apart and of the same kind or not, with the sounds of what changes; uncoupling a screw coupler pressed together, stretched, with the hoses alone or broken; the automatic couplers of electric units coupling on contact, without the control cable between two kinds; a coupler broken with its brake hose; collisions over 15 km/h derailing. The pantographs set up by the pantstate load, a load of one kind at a time up to the capacity, and the steps of loading and unloading. * test: the battery drained and charged, the pantographs' tank and pressure switch, the 214M's speed control The EU07's battery drained without the converter by the lights and the small compressor until it opens the line breaker and nothing starts, charged by the converter, and switched off. The pantographs on their own leaking tank until the pressure switch opens the line breaker, and the small compressor pumping it up and priming the switch. The 214M railbus's speed control set by its buttons, steps and power limit, braking down with the retarder, and standing by. * test: the MHZ handles' buttons, the valves at speed, every brake material, the NESt3's relays The overload and the high pressure buttons of the MHZ handles. The KE and the LSt at speed in the R and P settings, under the anti-slip request and the releaser button. Every material of the brake shoes and disks the loader takes, braking a wagon from speed, the ones no game vehicle has among them. The CV1_R and the Oerlikon valve's relays set by its name (-ED, AL2 without ESt3) fitted to a wagon. * test: the loader's lists and lines: the 218M, SA134 and 22WEc, a compressor list, Pmax by speed, skipped lines The 218M (V2NList), the SA134 (HTCList) and the Elf 22WEc (ffBrakeList) join the real vehicles for the lists the others lack. Definitions made by the tests for what no game file has: a compressor list, whose table of whole numbers reads a factor of 0.9 as 0; the compressor's limits apart for the rear cab; the highest power of an induction motor drive by the speed, extrapolated past the table; and the lines the loader skips or trims (comments, a hash anywhere, leading spaces, carriage returns). * test: what the cab and the AI call on a vehicle: gauges of the train, the split ED brake, spring brake, cut-off The engine rotation of up to three vehicles in multiple and the lamps of the overload relay and the starting resistors read through the control cable; the engine's idle speed and the ET42's second controller shown in its dynamic brake; the controller of the electrodynamic brake apart from the local brake, which no game vehicle has yet; the spring brake shut off and released, the ep brake's fuse and the handle stepped by the AI; damaged motors cut off; the cab activated by itself; a road vehicle moved across a road, for which the tests' track gets a width; and the lamps and the buzzer of the security system left unattended. * test: the EP05 and its camshaft among the real vehicles, the headlights' colour and brightness The EP05, whose camshaft closes the line breaker and the line contactors by the camshaft's own position, converted from the game data and recorded in every sweep of the real vehicles. The Headlights section, which only the 214M's own file has, in a definition made by the test. * test: what the unit tests reach of the simulation core, what's dead or left, and what they found COVERAGE.md: the blocks of Mover.cpp, hamulce.cpp, Oerlikon_ESt.cpp and friction.cpp the tests run, the code nothing in the game runs, the code only data no game vehicle has would run, what's reachable and left, and the behaviour the tests found that may deserve a look. * test: check invariants of the physics on every step of every golden trace Rules any vehicle keeps whatever a test does (no NaN, cylinders and pipes within their limits, no current with the line breaker or contactors open, no force without power, distance as the speed runs, no acceleration over 5 g), checked on every step, with no comparison to a recorded file. The traces where a test or a game vehicle breaks one are excused with the reason; the vehicles' cases are in the findings of COVERAGE.md. * test: key figures of every golden trace, per part of the run Duration, speeds, distance, time to stop, the brake pipe's lowest pressure and time to recover, the peaks of the cylinders, the motor current and the tractive force, for each part between two events, in data/golden/<name>.figures. Compared within 0.5% or the last decimal, so they hold on any compiler, and an intended change of behaviour shows in a few readable lines. Traces sampled by hand keep none. * test: keep the golden samples out of the repository, recorded on the code before a change The samples of the golden traces are 29 MB and only mean something against the code before the change they check, so they're recorded locally before it (EU07_UNIT_TESTS_UPDATE_GOLDEN=1) and compared after it, and ignored by git. The key figures and the invariants stay, and are what the CI checks. Without samples recorded a trace compares only its key figures, but with EU07_UNIT_TESTS_GOLDEN_EXACT=1, the check of a change which shouldn't alter anything, it fails, so the check can't pass by having nothing to compare. * fix: draw the noise of the control pipe pressure in one order on every compiler The order of the two Random(10) calls in 'Random(10) - Random(10)' is unspecified: GCC draws them the other way round than MSVC Release, which mirrored the control pipe pressure around 5 bar and failed 32 unit tests on the Linux CI. The draws are sequenced in the order of MSVC Release, which the golden traces were recorded with. * test: count the start-up rounds with an integer, not a double (SonarCloud S2193) * test: behaviour in CHECKs, the key figures out of the repository The key figures of the golden traces are recorded with their samples on the code before a change, and compared after it, instead of being kept: a trace without them checks the invariants and its test's CHECKs, which is what the CI runs. The scenarios of the controls state what they show in CHECKs, and the runs of every real vehicle what holds for each of them. Writing them showed scenarios which didn't do what they were named for: the cab change stopped in the engine room, the slip runs put the controller to full power at once and never got the line contactors closed, and the train stopped by the alarm chain never got its pipe charged again. They do it now; the rest went to the findings. * test: the SonarCloud findings in the unit tests std::format for the texts put together, emplace_back, const references, string_view parameters, std::array and std::vector for the C arrays, the ranges algorithms, names no longer shadowing the coupler ends, comments in the empty loops; start_up(), trace::check() and the converter of the definitions split up. BrakeForceR() is const, which it always was in effect, so the gauges test needs no const_cast. The golden traces compare bit for bit. |
||
| 3f6a10f1fe |
Merge pull request #237 from MaSzyna-EU07/feat/track-uneven
Feat/track uneven |
|||
|
|
4489dd7469 |
test(gfx): unit tests of the smoke of a vehicle taken off the tracks (#90)
The spawn count of the smoke source of a vehicle moves out of smoke_source::update() into smoke::vehicle_spawn_count() (vehicle/smoke.h), a free function on the mover state, which joins the core library so the unit tests can call it the way the source does. The rates are the same as before, the steady rate of the source still counted in before the share of the engine. Tests: tests/unit/test_smoke.cpp. A vehicle taken off the tracks spawns no smoke and drops the pending particles, with the engine starting, idling or under load; a road vehicle back from the pool puffs again; the engine adds to the steady rate; the pending count stays within the room of the source. Two of the four fail without the fix. Checked again on td.scn with the SM42 driven into a portal: the smoke source keeps puffing on the run and drops to 0 particles once the vehicle is taken off the tracks. |
||
|
|
e0cef91049 |
fix(physics): running backwards, the camshaft goes back down from the last series position (eu07/maszyna#393) (#256)
Running backwards, AutoRelayCheck() keeps the camshaft from joining the motors in more branches than BackwardsBranchesAllowed (the series connection alone, by default). It did that by returning before any move of the camshaft, so once it reached the last series position (22 of 43 in the Skoda 181 and 182, the next one joins the motors in two branches) it stayed there whatever the driver did with the master controller: with the controller back at zero the line contactors stayed closed and the motors kept pulling, until the line contactors were opened by hand. Now the limit only keeps the camshaft from going further up; it goes back down as usual. Tests: tests/unit/test_camshaft.cpp, on a locomotive made after the Skoda 181 (its RList); the test definitions take the RList and MotorParamTable0 tables. |
||
|
|
fc22645d7c |
fix(physics): articulated couplers stall freight trains (eu07/maszyna#553) (#255)
* fix(physics): articulated couplers stall freight trains (eu07/maszyna#553) Articulated wagons (T3000e, N-230, N-234) set up with CType=Articulated barely moved in a freight train and jerked. - The articulated joint took the spring force up to DmaxC = 0.05 m only, 225 kN, well short of its FmaxC of 850 kN and of what a loaded section in a freight train takes. It overstretched and the sections collided at every physics step. Dmax is now sized so the spring carries FmaxC (0.19 m stretched, 0.09 m pressed in), never below the old 0.05 m. - ComputeCollision() scaled the velocities of both vehicles by sqrt(1 - beta), so each collision braked the pair as a whole: two coupled vehicles in a sustained "collision" lost a third of their speed per step. The restitution now applies to the velocities relative to the centre of mass only, and the pair keeps its momentum. Tests: the articulated joint carries FmaxC within its travel; a jerked articulated set and a jerked screw-coupled pair keep their momentum. On the code before the fix both pairs stop dead within 3 s. * style(physics): English-only comment in ComputeCollision() The comment above the collision velocities started in Polish and went on in English. * style(physics): SonarQube findings in the #553 fix std::lerp for the collision velocities (cpp:S6179) and test locals renamed so they no longer shadow the end and coupling enumerators (cpp:S1117). |
||
|
|
09b1c2de10 |
fix(utilities): win1250_to_utf8 turns the polish letters into utf-8, not into themselves (#252)
utilities.cpp starts with a byte order mark, so the compiler reads it as utf-8. The game's targets don't get /utf-8, though: set_target_properties(... COMPILE_OPTIONS ...) in the MSVC block of CMakeLists.txt replaces the options add_compile_options gave them. So the string literals went into the program in the code page of the system, windows-1250 on a polish one, and the map of win1250_to_utf8 turned each letter into itself. What read windows-1250 through it got no utf-8: the names, descriptions and categories of the sceneries and the names of the textures in the launcher, and the descriptions of the templates in the editor. The editor writes such a description back through utf8_to_win1250, which makes a question mark of each byte that doesn't start a utf-8 sequence, so the letters it had read unchanged didn't come back. The utf-8 sequences are written as bytes now, the way utf8_to_win1250 has them, so they don't depend on the options. The options stay as they are: with /utf-8 other literals of the files with a byte order mark would change, the "±" of the table of Bezogonkow would take two bytes and move the letters after it. The unit tests check the letters and that the text given is valid utf-8. Co-authored-by: maj00r <maj00r@host> |
||
|
|
a68c535be9 |
fix(track): the cab keeps the shake a track doesn't replace, and the editor redraws all that an edit changes
The side sway from the lateral acceleration now goes off only on a track with a sideways value, and the random jolts on one with a vertical or a sideways value. Dips at the rail joints and cross level alone replace neither. On a switch it goes by the path set and what its joined tracks allow. An edit in the editor also rebuilds the other switches of a joined group with the tracks they meet, and the tracks of a rail run whose joints moved. Removing a track does the same. While dragging, the tracks further off wait until the drag ends. The clatter of a bogie's axles was right: the followers stand at the pivots and the offsets are the places of the wheel sets. The misleading name goes. Also what Sonar had left: a parameter as a span, a const method, a struct and its member apart, commented out code, and a function of the grading tool split, with the same output. |
||
|
|
d995674bee |
fix(physics): automatic couplers don't catch above the safe collision… (#217)
* fix: automatic coupler crashes, horns, compressor start delay, radio and cab lever sounds fix(cab): the line contactors lamp goes out with the pressure switch (eu07/maszyna#470) The lamp of the open line contactors, which tells the start can be made, went out at 1 bar in the brake cylinders, while the pressure switch cuts the start off only at 2 bar (or below 3.6 bar in the main pipe), so with the brakes partly applied the start could be made with the lamp out. With a pressure switch fitted the lamp now follows it; without one it goes out at 1 bar as before. The same holds for the lamp of the second unit, which used to keep its last state between 1 bar and the cut-off. The condition is TMoverParameters::LineContactorsLampLit(). Tests: tests/unit/test_line_contactors.cpp. refactor: Sonar findings of PR 217 - horn_supply::pneumatic shadowed the pneumatic enumerator of the sound flags (cpp:S1117), it's horn_supply::air; the supplies read with using enum (S6177), - CouplerForce(): the automatic coupling refused or caught without another level of nested ifs (S134), the same outcome: too fast, the coupling is locked; caught, coupled and locked; otherwise left to try again, - CompressorCheck(): the power the compressor doesn't draw yet noted without a TODO (S1135), - tests: the previous crash damage setting in an in-class initializer (S3230), the loops which stop early with break rather than in their conditions (S886), the stand-ins of test::pair in a std::vector rather than an array (S5945), units in the comments of the example without /* */ (S1103). test: the cases the changes of the branch left without a test - Cntrl.: BDelay1 to BDelay4 reach the brake delays (now through std::format), the default start types of the ground and converter overload relays of a multiple unit and of other vehicles (out of the nested conditionals), - the compressor: fed from the low voltage it waits from the low voltage coming on; the pressure switch stops it above the cut-out pressure, without one the excess air is vented (the vented fraction rewritten), - the horns: a vehicle without any air sounds as before, the threshold pressure, an electric horn on 110 V, - the positions of a cab control below zero, and a control without position sounds. refactor(cab): the kind of the train heating switch as a flag Read once with the vehicle definition, rather than compared as text in each of the switch commands. feat(cab): train heating switch springing back (MaSzyna-EU07/maszyna#85) TrainHeating=[toggle]|impulse in the Switches: section of the vehicle definition makes the train heating switch an unstable one: it goes up to switch the heating on, down to switch it off, and back to the middle once let go, instead of staying where it was put. The position of such a switch isn't set from the heating state when the cab is entered. Tests: tests/unit/test_switches.cpp. feat(sound): mirror sounds (MaSzyna-EU07/maszyna#84, eu07/maszyna#322) The sound definitions of a vehicle (.mmd) take mirroropen: and mirrorclose:, played as a mirror sets off unfolding or folding, and the locations section mirrors: <offset>... end, the offsets along the vehicle of the mirror pairs, as for the doors (negative ahead of the centre), each pair at the sides of the vehicle. As the animation, only the mirrors at the occupied cab sound. The start of a move is mirror_moves::motion in vehicle/mirrors.h. Tests: tests/unit/test_mirrors.cpp. feat(cab): joint oil and fuel pump switch (MaSzyna-EU07/maszyna#81) A cab control oilfuelpump_sw: switches both the oil and the fuel pump at once, with the new command oilfuelpumptoggle (no key by default). As a two-state switch it turns both pumps off when both are on and both on otherwise; as an impulse switch it's held to start them, like the separate pump switches. Its position follows the pumps when the cab is entered. refactor(editor): text fields filled without strncpy (MaSzyna-EU07/maszyna#112) The last three strncpy calls Sonar flags (cpp:S5816), in the road and track editors, copy the text into the ImGui field buffers with std::string::copy and terminate it right after; the text gets cut to the buffer as before. fix: automatic coupler crashes, horns, compressor start delay, radio and cab lever sounds - automatic couplers don't catch above the safe collision speed (#86): with crash damage on they couple at a closing speed of 15 km/h at most, a faster hit locks the coupling until the vehicles part and the collision runs its course. On the way: CollisionVelocity() read a head-on 10 + 10 km/h as 14.1 km/h (quaternions turn by half the angle), it's now taken from the touching ends; CollisionDetect() took the other vehicle's speed the wrong way round for vehicles facing each other. Head-on hits now derail sooner, at the intended limit, - a single horn lever can't sound both tones at once (eu07/maszyna#392), - a skid ends once the vehicle stops on locked wheels (eu07/maszyna#479), - electronic destination signs are blanked at the end of the timetable (eu07/maszyna#446), - horns need the air or the voltage to sound (eu07/maszyna#290, #76): HornType=[Pneumatic]|Electric and Horn3Type in Cntrl.; a pneumatic horn needs 0.2 MPa in the main reservoir (or the main pipe without one), an electric one the low voltage; the lever stays where it was put, - compressor start delay (#67): CompressorStartDelay [s] in Brake., counted from the compressor getting its power, after the engine starts say; none by default, - the channel and volume buttons of a radio without power do nothing (eu07/maszyna#429); the power check of the radio is TMoverParameters::RadioPowered(), - a lever moved smoothly sounds the positions it passes (#83). Sonar findings in the functions changed: nesting, nested conditionals, commented-out code, std::format, references to const. Unit tests: test::pair for two vehicles running into each other, test_couplers, test_horn, test_wheelslip, test_compressor, test_radio, test_gauge_positions. * fix: review findings of PR 217 - the pressures of the mover are in bar (MinCP=7.0 in the vehicle definitions), so the 0.2 the pneumatic horns needed was 0.2 bar; it's 2 bar now, and the tests take their pressures in bar too, - the lamps of the ground relay and of the motor overload relays follow the pressure switch as the line contactors one does, TMoverParameters::MainCircuitLampsEnabled(), so the lamps of one cab go out together, - the joint oil and fuel pump switch leaves out a pump started automatically, which ignores the switching: with one, it couldn't turn the other off, and showed off with both running (OilFuelPumpsEnabled()), - the kind of the train heating switch comes from the occupied vehicle on entering the cab too, as in the switch commands; in a multiple unit these are different vehicles, - CouplerForce() put the force taken back by the other vehicle on its far coupler when the vehicles faced each other (Couplers[1 - End] rather than the coupler it's coupled with), - the velocity difference along the coupler axis computed once, CouplerVelocityDifference(), for CouplerForce() and CollisionVelocity(), - the attachcoupler flag added without the SetFlag() call with 0, the index of the mirror moves noted as by side. Tests: the coupler force of vehicles facing each other, the joint switch with an automatic pump, the lamps of the main circuit, the horn and compressor pressures in bar. * fix: coupler force of vehicles facing each other taken back along the other vehicle's axis CForce runs along the axis of its own vehicle, so the force the other vehicle takes back on its coupler of the pair is turned around once more when the vehicles face each other (-CF * DirPatch()), as that vehicle computes it itself. Tests: the coupler forces of the pair facing each other and facing the same way. |
||
|
|
9364b03e1a |
fix(track): what Sonar reports on the unevenness
The blockers are in the EP brake of a vehicle, older than this work: its arrays made with new[] are vectors now, which also removes the deletes. - The caches of the unevenness of a track are no longer mutable: what fills them isn't const any more. - TSegment gets back to RaPositionGet in one piece, with what the path has to do with the others in one struct. - Less nesting in the group of switches and in the fields of the editor, nested conditionals written out, and the attribute is read from a string_view. A test no longer counts in floating point. No change in behaviour. |
||
|
|
2b8d7d7cf3 |
refactor(track): what goes with unevenness in one place, readable
The rules stay in TrackUneven.h with no dependence on the engine, as they can be tested. Their use on the tracks moves out of Track.cpp to TrackUneven.cpp, split into steps: the group of switches, the values of its paths, the meeting of two ends. One set of helpers for the paths of a track takes the place of the same conditions written out in several places, and the value at the ends of a switch is worked out in one place. The clatter of an axle leaves the long Update of a vehicle. The fields in the editor say themselves when they show. No change in behaviour. |
||
|
|
371de52342 |
fix(track): what the review of unevenness found in the engine
- A path of no length gave a joint with a vector across of NaN to the path joined to it, on any scenery, with unevenness or not. It now has no vector across, and so makes no joint. - Axles no longer stray along the track. It moved vehicles against each other, changing the distance their couplers go by. - The bend under an axle goes straight on past the ends of a path: the polynomial ran off on a short curved one, with a kick in the cab shake. - A track left out of its rail run, where tracks are joined one way only, no longer walks the whole run again on every call. - The clatter of an axle goes by the outer axle on its side of the vehicle, and not always by the same one, as the two can be on different tracks. - A vertex works out the amounts once, and the foot of the ballast not at all. |
||
|
|
ec2d226688 |
fix(editor): the uneven attribute is written in the layout of the entry it goes into
Its numbers go by position, and the positions differ between a plain track and a switch. A switch made in the style of a plain track wrote them in the layout of the plain one, so they were read back as other values: the up and down part as the value of the path p3-p4, and so on. The values are now one struct with pure functions to read, write and resolve them, which replaces eight fields and which the unit tests can reach. |
||
|
|
02abc7df0a |
feat(track): all of the unevenness in one attribute, with values for each path of a switch
Usage, before endtrack, in mm, 0-100, separated by semicolons with no spaces: a plain track: uneven value;up;side;cross;dip a switch: uneven p1-p2;p3-p4;up p1-p2;side p1-p2;up p3-p4;side p3-p4 uneven 18 the value alone uneven 18;;;25;6 with its own cross level and dip at the joints uneven 0;;30 sideways alone uneven 14;35 a switch, 14 on the straight path, 35 on the diverging What's left out takes the first number, the dip goes by the up and down one, and a path p3-p4 with no numbers of its own takes those of p1-p2. This replaces unevenup, unevenside, unevencross and jointdip. The fields in the editor stay, track panel, section Ride and sound. At the end they share, the paths of a switch keep to the lower value, and each comes to its own value along the way. Joined switches take the lowest of the same path, a path joined to another path the lower of the two, and a plain track comes to the value of the path it meets. See track_uneven_doc.md. |
||
|
|
3dbe8a75f8 |
feat(track): the foot of the ballast stays on the ground as designed
Rails, sleepers and the top of the ballast go with the unevenness, the slope of the ballast takes up the difference. |
||
|
|
6aed9ec5bd |
feat(track): vertical unevenness comes near its limit more often, with longer buckles too
Fewer short waves: at uneven 18 the humps over 12.6 mm on the 10 m chord go from 28 to 38 per km, with the peak still at 18 mm. Waves of 47-83 m join them. They hardly count on that chord, the body rises and falls on them. The documentation tells how far unevenness goes before a pantograph can't keep up. A wire rising fast enough trips the main breaker on a straight track too: it does at tor0290 on Baltyk, over about 46 km/h. |
||
|
|
e74bbf951f |
fix(track): the cross level of an uneven track goes by the place, not by how it was laid
Tracks laid towards each other settled to opposite sides: a step of cant of twice the value at their joint, in the geometry and under the axles. It's now a tilt of the plan, which reads the same from either track. |
||
|
|
e5266e1e6b |
feat(track): track unevenness declared in the track entry
Usage, optional attributes of a track entry, before endtrack:
uneven <mm> peak deviation of a rail on a 10 m chord, 0-100; normal and switch
unevenup <mm> up and down alone, instead of uneven; normal and switch
unevenside <mm> sideways alone, instead of uneven; normal and switch
unevencross <mm> cross level alone, instead of uneven; normal only
jointdip <mm> depth of the dip at rail joints, every sound distance; normal only,
default 0.4 of the up and down component
Values of uneven follow PLK Id-14 appendix 1: 6 mm is the limit at 160 km/h, 10 at 120,
18 at 80, 35 at 40; half of it for a track in a good state. Example:
uneven 18
unevencross 25
jointdip 6
endtrack
The same fields are in the editor, track panel, section Ride and sound. See
track_uneven_doc.md.
The unevenness is a displacement field over the plan of the scenery, with no random
numbers: one place strays the same every time, and joined tracks, the paths of a switch,
sleepermodel and axles at one place move together. Tracks meet at a joint at the lower of
their values. Joined switches take the lowest of theirs, the tracks joined to them come to
it, and a track with none of a component keeps the switch to its design in it. The clatter
comes from the dipping joints. Curve radius and grade for the physics stay as designed.
Tracks with it get geometry every 2 m on straights: 4x the vertices on Baltyk with all
tracks flagged, 0.2 ms more per frame on td.scn.
|
||
|
|
c7f9796387 |
fix(ai): release horn when human driver takes over from AI (#210)
* fix(ai): release what the AI was holding when the player takes over * fix(ai): keep the light selector lookup within its table, Sonar findings of the handover - the light selector size comes from the vehicle definition (LightsList Size) and isn't limited, while the table holds 18 positions; a bigger selector read past the table, and so did a table index other than the front or rear one. Only the positions the table holds are looked at now, and the selector stays where it is for a bad table index (cpp:S2259), - the lambdas of the handover capture what they use explicitly (cpp:S3608), - the chained assignments resetting the headlight state on the AI taking over are split (cpp:S1121). |
||
|
|
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)
|