VehicleDatabase becomes VehicleCatalog, Physics becomes VehiclePhysics, and the
textures.txt and .fiz parsers move to Infrastructure. GameLibrary replaces the
GameData singleton.
Shaders: drop ApplyHdrShader and FindBundled. The Pascal starter only copied
starter/Reinhard.glsl over shaders/tonemapping.glsl when the user picked an
operator in the HDR combo (uSettings.pas ChangeHDR, its only caller being
cbHDRChange), never on an ordinary save. We ran it from SaveTo, so every save
replaced the file the game ships. That file has been tracked in the game repo
since 2020 and now defaults to AgX, so overwriting it with a 2021-vintage
Reinhard was a two-generation downgrade that also lost the NaN/Inf sanitize.
Also comments out gfx.postfx.tonemapping on save; the engine has no such key.
Executable: ResolveExecutable now validates its pick (file exists, has an
execute bit outside Windows, and the MZ/ELF header matches the running OS) and
returns the first candidate that passes instead of the first that matches by
name. .exe is no longer a Linux candidate - a Steam install with the native
binary still zipped would otherwise resolve to the Windows PE. On failure the
problem reaches the caller, and MainWindow shows it instead of swallowing the
exception, so a launch that does nothing is no longer silent. A manual pick
whose file is temporarily missing is kept in the combo rather than falling back
to auto and being overwritten on the next save.
Claude-Session: https://claude.ai/code/session_01HamVNWE9mwmz1vs2iEpNQq
Removes every // and /// comment from the 28 .cs files, -1331 lines.
Done with a lexer rather than a regex: the sources carry plenty of // inside
string literals (@"//\$decor\b", the //$o trainset directives, sb.Append("// "),
"https://wiki.eu07.pl/") and those must survive. It tracks regular, verbatim and
interpolated strings, interpolation holes and char literals. Every file was
checked by comparing the sequence of string-literal characters before and after
the strip; all 28 match. BOMs preserved, blank-line runs collapsed to one.
Claude-Session: https://claude.ai/code/session_01HamVNWE9mwmz1vs2iEpNQq
download-artifact unpacks a zip it detects, so the Windows package arrived in
dist/ as loose files (Starter.exe, the native dlls, startercfg/) and gh tried
to upload the startercfg directory as a release asset. skip-decompress leaves
the artifact as the file it was uploaded as.
The two packages are also named explicitly instead of globbing dist/*, so a
missing one fails the step rather than quietly publishing half a release.
The packages are uploaded with archive: false, and non-zipped artifacts can
only be fetched by v8 of download-artifact - v7 fetched the first one, then
failed the run with "Unable to download and extract artifact".
The file did not exist on this branch (it was cut before the workflow landed
on main), so a merge would have shown it as new. It is copied verbatim: this
branch is not in the push triggers and builds nothing on its own.
Workflow artifacts can only be downloaded by signed-in users with access to
the repository, so they are useless for handing a build to anyone else. After
the matrix publishes, a release job recreates a rolling pre-release from the
same packages; its assets are downloadable without an account:
releases/download/latest/<file> from main
releases/download/staging/<file> from staging
Each branch owns its tag, so a staging build never overwrites the main one.
The release is deleted and created again rather than edited, so the tag
follows its branch and assets from an older build do not linger. Write access
is granted to that job only, the workflow default stays read.
Both language combos decided a change was the user's by checking
IsKeyboardFocusWithin on the picked item. Selecting with the mouse leaves the
focus on the combo, not on the item, so on Windows the check failed and the
language never changed. The handlers now compare the picked code with the one
already loaded instead of guessing who caused the event: filling the combo in
selects what is loaded and stops there, a real pick differs and applies.
The settings tab listed a hard-coded Polski / English pair and wrote the
language back as "Polski" or "English", so picking Czech, Hungarian or
Russian in the top bar was overwritten on save. It is filled from lang/ now,
and writes back the selected entry.
LocalizationService gains a LanguageChanged event: the main window rebuilds
the captions that code builds once (train stats, panel headers, combo items)
from there, so a pick in either place refreshes them. Its PropertyChanged
also names the indexer "Item[]", which is what bindings listen for.
Graphics tab: the track-curve quality slider moves over from Physics, the
view angle shows a degree sign instead of the Polish "stopni", and the HDR
tone-mapping picker is gone - only Reinhard.glsl ever shipped, so
ApplyHdrShader copies that one and the starter.hdr setting is dropped.
The 146px right margin pushed the version and social icons inwards on every
window width. Padding the whole bar down by the caption height gives the OS
buttons a strip of their own and leaves the cluster where it was; the strip
drags the window, so the handler moves to the bar's border.
The vehicle database panel loses its header bar and packs the search box and
the archival filter into one line, the class combo takes a full-width line of
its own with a miniature (big in the drop-down, one line when closed) and the
bulk / texture-base actions move into the Add button's drop-down. The mini
preview sits beside the texture data and stays hidden until an entry is
picked, so the list keeps the space.
Picking a class or a vehicle now fills both combos in, and a class alone is a
valid filter (it used to leave the list empty without a category). The combos
and the list are rebuilt on the next dispatcher pass, since clearing Items
from inside the SelectionChanged that asked for it throws.
Vehicle removal becomes a per-card tool next to flip / crew, the scenery and
vehicle names move into their panel headers, and the texture randomizer
dialog sizes to its content instead of clipping its last button.
Start no longer hides behind Ctrl: a consist with no crew and no passenger
says so on the button and asks for confirmation before launching.
Scenery parsing runs on Parallel.ForEach and the reload button does it off
the UI thread. The splash window only appears when loading passes 300ms, so
a warm start goes straight to the main window. The log button moves into the
navigation row, dropping the separate caption strip; timetable and info use
the shared MonoFont family instead of a hard-coded Consolas.
Use the Starter icon for the window and the executable; the whole caption strip drags the window. Extending the client area makes Avalonia 12 add an extra full-screen toggle to the window chrome (which lives in its own host, so it is not reachable from the window's visual tree); it is hidden globally in App.axaml via its WindowDecorationProperties.ElementRole. Standard minimize / maximize / close are kept.
#16 and #12 Start is enabled only with crew/passenger (hold Ctrl to force); the chosen starting vehicle is carried through launch; loading-screen logo; help menu; runtime language picker.
#9 category minis in the class list; #10 coupler after the last car; #11 drag and drop from the browser and consist reorder; #12 fix forced headdriver (occupancy); #13 hide archival vehicles; #14 randomise order; #15 randomise orientation; #16 pick starting vehicle; #18 collapse multi-unit sets; texture randomiser and stock database.
Consist/scenery/vehicle logic (TrainsetDisplay, TexRandomizer, SceneryI18n) goes under Domain/; the loading-screen bitmap writer under Infrastructure/, instead of the flat Classes/ bucket.
build-macos.sh ships the macOS binary as eu07.exe, so IsValidBinaryFile
must accept that extension on non-Windows too. Also fix the AlwaysOn
battery default check to use a proper near-zero epsilon instead of an
overly broad <0.2 threshold that clobbered legitimate low velocities.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Cross-checked against ../maszyna: several StarterNG defaults didn't
match the simulator's actual defaults (Globals.h), and three exposed
options never mapped to a real eu07.ini key.
- Correct defaults to match the engine: VSync=false, LiveTraction=true,
VirtualShunting(ai.trainman)=true, DynamicLights=7 fallback,
CabShadowsRange=0, GfxResourceSweep=true, FeedbackMode=1,
ShadowMapResolution=2048, ReflectionsFidelity=0, Volume=50.
- Remove Post-processing (gfx.postfx.tonemapping), onboard-screen
refresh rate (pyscreenrendererpriority), and volume-during-pause
(sound.volume.paused) — none of these keys exist in the simulator.
- Only apply parsed UART feature tokens when eu07.ini actually has an
uartfeature line; otherwise fall back to the engine's own defaults
instead of all-false.
Adds save/apply named settings profiles (SettingsProfileStore), a
battery-default export option that rewrites trainset velocity on
launch, and an option to omit decorative trainsets from the exported
scenery. Also surfaces many previously-unmapped eu07.ini keys in the
Settings UI (UART/feedback port, FPS limit, shadow angle, fullscreen
windowed, ANGLE Vulkan, friction/brake sensitivity, and an Advanced
section for texture/GLES/threading tunables).