From df21ec104fac7f024e090a806598b0ff7f5cef43 Mon Sep 17 00:00:00 2001 From: maj00r Date: Fri, 4 Sep 2026 22:24:54 +0200 Subject: [PATCH] Cut the comments from the refactored code Three survive: why AppServices is hand-wired, the cp1250 registration trap, and the IsDieselEngine note carried over from Physics.cs. --- StarterNG/Application/Abstractions/IClock.cs | 5 -- .../Abstractions/IDiagnosticsLog.cs | 6 --- .../Application/Abstractions/IEnvironment.cs | 6 --- .../Application/Abstractions/IFileSystem.cs | 22 --------- .../Application/Abstractions/IGamePaths.cs | 14 ------ .../Abstractions/ILocalizedStrings.cs | 10 ---- .../Abstractions/IMiniTextureIndex.cs | 7 --- .../Abstractions/IPhysicsRepository.cs | 9 ---- .../Abstractions/IProcessLauncher.cs | 20 -------- .../Application/Abstractions/IRandomSource.cs | 7 --- .../Abstractions/ISceneryRepository.cs | 10 ---- .../Abstractions/ISceneryTranslations.cs | 13 ----- .../Abstractions/IVehicleRepository.cs | 9 ---- StarterNG/Application/AppServices.cs | 35 ++------------ StarterNG/Application/AppState.cs | 10 ---- StarterNG/Application/GameLibrary.cs | 18 ------- StarterNG/Application/MissingVehicleLog.cs | 9 ---- StarterNG/Application/SettingsStore.cs | 33 ------------- StarterNG/Application/StartSimulation.cs | 38 --------------- StarterNG/Controls/DetailRows.cs | 23 --------- StarterNG/Controls/SettingRow.cs | 20 -------- StarterNG/Controls/SettingsSection.cs | 5 -- StarterNG/Domain/Sceneries/Scenery.cs | 48 ------------------- StarterNG/Domain/Sceneries/SceneryWeather.cs | 24 ---------- .../Domain/Sceneries/SceneryWeatherWriter.cs | 17 ------- .../Domain/Settings/SimulatorSettings.cs | 45 ----------------- StarterNG/Domain/Vehicles/LoadWeightsTable.cs | 11 ----- StarterNG/Domain/Vehicles/VehicleCatalog.cs | 30 ------------ StarterNG/Domain/Vehicles/VehiclePhysics.cs | 14 ------ StarterNG/Domain/Vehicles/VehicleTexture.cs | 23 --------- .../Adapters/FileDiagnosticsLog.cs | 16 ------- .../Infrastructure/Adapters/GamePaths.cs | 5 -- .../Infrastructure/Adapters/LegacyText.cs | 6 --- .../Adapters/PhysicalFileSystem.cs | 4 -- .../Infrastructure/Adapters/SystemClock.cs | 1 - .../Adapters/SystemEnvironment.cs | 1 - .../Adapters/SystemProcessLauncher.cs | 4 -- .../Adapters/SystemRandomSource.cs | 1 - StarterNG/Infrastructure/Diagnostics.cs | 13 ----- StarterNG/Infrastructure/InstallationCheck.cs | 8 ---- .../Sceneries/SceneryImageLocator.cs | 10 ---- .../Infrastructure/Sceneries/SceneryParser.cs | 25 ---------- .../Sceneries/SceneryRepository.cs | 10 ---- .../Sceneries/SceneryTranslations.cs | 14 ------ .../Sceneries/TimetableLocator.cs | 9 ---- .../Settings/ExecutableLocator.cs | 22 --------- .../Infrastructure/Settings/SettingsPaths.cs | 6 --- .../Settings/SettingsSerializer.cs | 17 ------- StarterNG/Infrastructure/Shortcuts.cs | 14 ------ StarterNG/Infrastructure/TextMatch.cs | 8 ---- .../Vehicles/FizPhysicsRepository.cs | 23 --------- .../Vehicles/LoadWeightsRepository.cs | 11 ----- .../Vehicles/MiniTextureIndex.cs | 9 ---- .../Vehicles/MissingAssetScanner.cs | 8 ---- .../Vehicles/TexturesTxtParser.cs | 26 ---------- .../Vehicles/TexturesTxtVehicleRepository.cs | 15 ------ StarterNG/Presentation/Scenarios/FogScale.cs | 12 ----- .../Presentation/Scenarios/SceneryTree.cs | 21 -------- .../Presentation/Scenarios/SeasonDates.cs | 14 ------ StarterNG/Views/ShortcutsWindow.cs | 4 -- 60 files changed, 3 insertions(+), 875 deletions(-) diff --git a/StarterNG/Application/Abstractions/IClock.cs b/StarterNG/Application/Abstractions/IClock.cs index b3fa40d..97f0c2c 100644 --- a/StarterNG/Application/Abstractions/IClock.cs +++ b/StarterNG/Application/Abstractions/IClock.cs @@ -2,11 +2,6 @@ namespace StarterNG.Application.Abstractions; using System; -/// -/// Port over the system clock. Scenery weather defaults, timetable rendering and -/// log timestamps all depend on "now"; routing them through a clock keeps those -/// rules deterministic under test. -/// public interface IClock { DateTime Now { get; } diff --git a/StarterNG/Application/Abstractions/IDiagnosticsLog.cs b/StarterNG/Application/Abstractions/IDiagnosticsLog.cs index aa049b4..a5a0765 100644 --- a/StarterNG/Application/Abstractions/IDiagnosticsLog.cs +++ b/StarterNG/Application/Abstractions/IDiagnosticsLog.cs @@ -3,11 +3,6 @@ using System.Collections.Generic; namespace StarterNG.Application.Abstractions; -/// -/// Port over the starter's error log. Domain and application code depends on -/// this interface only; the file-backed implementation and the message box that -/// surfaces faults to the user live in Infrastructure and Presentation. -/// public interface IDiagnosticsLog { void Log(string message); @@ -16,7 +11,6 @@ public interface IDiagnosticsLog void Log(IEnumerable messages); - /// Everything logged so far, newline separated. string Text { get; } void Clear(); diff --git a/StarterNG/Application/Abstractions/IEnvironment.cs b/StarterNG/Application/Abstractions/IEnvironment.cs index aad2b85..bc614ab 100644 --- a/StarterNG/Application/Abstractions/IEnvironment.cs +++ b/StarterNG/Application/Abstractions/IEnvironment.cs @@ -1,9 +1,5 @@ namespace StarterNG.Application.Abstractions; -/// -/// The bits of the host machine the starter has to ask about: which operating -/// system it is on, and where that system keeps per-user configuration. -/// public interface IEnvironment { bool IsWindows { get; } @@ -12,9 +8,7 @@ public interface IEnvironment bool IsMacOS { get; } - /// An environment variable, or null when it is not set. string? GetVariable(string name); - /// The folder the starter's own executable lives in. string BaseDirectory { get; } } diff --git a/StarterNG/Application/Abstractions/IFileSystem.cs b/StarterNG/Application/Abstractions/IFileSystem.cs index fe381c5..93c1083 100644 --- a/StarterNG/Application/Abstractions/IFileSystem.cs +++ b/StarterNG/Application/Abstractions/IFileSystem.cs @@ -5,18 +5,6 @@ using System.Text; namespace StarterNG.Application.Abstractions; -/// -/// Port over the file system. Everything that reads or writes the MaSzyna -/// installation goes through this interface instead of and -/// , so parsers and use cases can be exercised against an -/// in-memory installation in tests. -/// -/// -/// Kept deliberately narrow: only the operations the application actually -/// performs are exposed. Paths are passed through verbatim to the adapter, which -/// resolves them relative to the process working directory just like the -/// framework methods it replaces. -/// public interface IFileSystem { bool FileExists(string path); @@ -45,23 +33,13 @@ public interface IFileSystem void CopyFile(string sourcePath, string destinationPath, bool overwrite); - /// Top-level files, empty when the directory does not exist. IReadOnlyList GetFiles(string path, string searchPattern = "*"); - /// Top-level directories, empty when the directory does not exist. IReadOnlyList GetDirectories(string path); - /// - /// Files matching the pattern anywhere below the path. Empty when the - /// directory does not exist. - /// IReadOnlyList GetFilesRecursive(string path, string searchPattern); DateTime GetLastWriteTimeUtc(string path); - /// - /// Whether the file carries an execute bit. Always true on Windows, where - /// executability is a property of the file's contents rather than its mode. - /// bool IsExecutable(string path); } diff --git a/StarterNG/Application/Abstractions/IGamePaths.cs b/StarterNG/Application/Abstractions/IGamePaths.cs index 464cf37..314647c 100644 --- a/StarterNG/Application/Abstractions/IGamePaths.cs +++ b/StarterNG/Application/Abstractions/IGamePaths.cs @@ -1,34 +1,20 @@ namespace StarterNG.Application.Abstractions; -/// -/// The layout of a MaSzyna installation. Replaces the -/// Directory.GetCurrentDirectory() calls and hard-coded "scenery/", -/// "dynamic", "textures/mini/" literals that were previously spread across -/// parsers, views and the loader. -/// public interface IGamePaths { - /// Installation root: the folder holding eu07.exe. string Root { get; } - /// Scenery definitions (*.scn). string Scenery { get; } - /// Rolling stock: dynamic/<maker>/<vehicle>/textures.txt. string Dynamic { get; } - /// Vehicle thumbnails used by the depot and the consist strip. string MiniTextures { get; } - /// Simulator data files (load_weights.txt and friends). string Data { get; } - /// Starter-owned configuration: presets, profiles, key bindings. string StarterConfig { get; } - /// The starter's own error log (starter/bledy.txt). string DiagnosticsLog { get; } - /// Resolves a path relative to . string FromRoot(params string[] segments); } diff --git a/StarterNG/Application/Abstractions/ILocalizedStrings.cs b/StarterNG/Application/Abstractions/ILocalizedStrings.cs index f72ce5b..826d732 100644 --- a/StarterNG/Application/Abstractions/ILocalizedStrings.cs +++ b/StarterNG/Application/Abstractions/ILocalizedStrings.cs @@ -1,19 +1,9 @@ namespace StarterNG.Application.Abstractions; -/// -/// Port over the translation table. Anything that needs a user-facing string -/// takes this, rather than reaching for the concrete localization service or a -/// static on App. -/// public interface ILocalizedStrings { - /// - /// Translation for a key. Missing keys return the key itself (and are logged - /// once), so an untranslated screen stays usable. - /// string this[string key] { get; } - /// Lookup for a key that may legitimately be absent; "" when missing. string Opt(string key); string CurrentLanguage { get; } diff --git a/StarterNG/Application/Abstractions/IMiniTextureIndex.cs b/StarterNG/Application/Abstractions/IMiniTextureIndex.cs index d876765..1edadd4 100644 --- a/StarterNG/Application/Abstractions/IMiniTextureIndex.cs +++ b/StarterNG/Application/Abstractions/IMiniTextureIndex.cs @@ -1,19 +1,12 @@ namespace StarterNG.Application.Abstractions; -/// -/// The thumbnails in textures/mini, looked up by name. Backed by one directory -/// scan; a name with no bitmap falls back to the generic "other" thumbnail. -/// public interface IMiniTextureIndex { - /// Builds the index up front, off the UI thread. void Preload(); bool Has(string? miniName); - /// Bitmap for the name, the fallback thumbnail, or null when neither exists. string? PathFor(string? miniName); - /// The generic thumbnail shown for unknown stock. string? FallbackPath { get; } } diff --git a/StarterNG/Application/Abstractions/IPhysicsRepository.cs b/StarterNG/Application/Abstractions/IPhysicsRepository.cs index 44e9a63..d479167 100644 --- a/StarterNG/Application/Abstractions/IPhysicsRepository.cs +++ b/StarterNG/Application/Abstractions/IPhysicsRepository.cs @@ -2,20 +2,11 @@ using StarterNG.Domain.Vehicles; namespace StarterNG.Application.Abstractions; -/// -/// Looks up the .fiz physics of a vehicle type by model name. -/// public interface IPhysicsRepository { - /// Indexes the installation's .fiz files up front, off the UI thread. void Preload(); - /// How many vehicle types were indexed; zero means a broken installation. int IndexedCount { get; } - /// - /// Physics for a model name (with or without extension), or null when the - /// installation has no .fiz for it. - /// VehiclePhysics? For(string? dataFolder, string? model); } diff --git a/StarterNG/Application/Abstractions/IProcessLauncher.cs b/StarterNG/Application/Abstractions/IProcessLauncher.cs index 7029f36..a8ecab1 100644 --- a/StarterNG/Application/Abstractions/IProcessLauncher.cs +++ b/StarterNG/Application/Abstractions/IProcessLauncher.cs @@ -4,12 +4,6 @@ using System.Threading.Tasks; namespace StarterNG.Application.Abstractions; -/// -/// A process the starter has launched or adopted. Exposes only what the starter -/// needs — whether the simulator is still up, and a way to await its exit — so -/// the presentation layer never handles -/// directly. -/// public interface IProcessHandle { bool HasExited { get; } @@ -17,26 +11,12 @@ public interface IProcessHandle Task WaitForExitAsync(CancellationToken cancellationToken = default); } -/// -/// Port over process creation: starting the simulator, opening a file, folder or -/// URL in the desktop shell, and adopting an already running simulator. -/// public interface IProcessLauncher { - /// - /// Starts an executable with the given arguments. Returns null when the - /// process could not be created; then carries the - /// reason for display. - /// IProcessHandle? Start(string executablePath, IReadOnlyList arguments, string? workingDirectory, out string? error); - /// - /// Hands a path or URL to the desktop shell (explorer, xdg-open, ...). - /// Returns false and logs when the shell refused it. - /// bool OpenInShell(string pathOrUrl); - /// The first running process with that name, or null. IProcessHandle? FindRunning(string processName); } diff --git a/StarterNG/Application/Abstractions/IRandomSource.cs b/StarterNG/Application/Abstractions/IRandomSource.cs index f5f57b2..b4403a2 100644 --- a/StarterNG/Application/Abstractions/IRandomSource.cs +++ b/StarterNG/Application/Abstractions/IRandomSource.cs @@ -1,15 +1,8 @@ namespace StarterNG.Application.Abstractions; -/// -/// Port over randomness. Scenery weather deliberately varies between runs (fog -/// distance, overcast presets, texture randomiser); routing it through a port -/// keeps those rules assertable instead of flaky. -/// public interface IRandomSource { - /// Inclusive lower bound, exclusive upper bound. int Next(int minInclusive, int maxExclusive); - /// Uniform value in [0, 1). double NextDouble(); } diff --git a/StarterNG/Application/Abstractions/ISceneryRepository.cs b/StarterNG/Application/Abstractions/ISceneryRepository.cs index f923fc7..031b05b 100644 --- a/StarterNG/Application/Abstractions/ISceneryRepository.cs +++ b/StarterNG/Application/Abstractions/ISceneryRepository.cs @@ -4,21 +4,11 @@ using StarterNG.Domain.Sceneries; namespace StarterNG.Application.Abstractions; -/// How far a scenery sweep has got, for the splash screen. public readonly record struct SceneryLoadProgress(int Loaded, int Total, string FileName); -/// -/// Reads the scenarios of an installation. The only route from a .scn on disk to -/// a ; nothing else constructs one from a path. -/// public interface ISceneryRepository { - /// - /// Every scenario in the installation, in no particular order. Files that - /// fail to parse are logged and skipped rather than failing the load. - /// IReadOnlyList LoadAll(IProgress? progress = null); - /// Reloads a single scenario; null when it is gone or unreadable. Scenery? Load(string path); } diff --git a/StarterNG/Application/Abstractions/ISceneryTranslations.cs b/StarterNG/Application/Abstractions/ISceneryTranslations.cs index 4ffdc17..de599ce 100644 --- a/StarterNG/Application/Abstractions/ISceneryTranslations.cs +++ b/StarterNG/Application/Abstractions/ISceneryTranslations.cs @@ -2,22 +2,9 @@ using StarterNG.Domain.Sceneries; namespace StarterNG.Application.Abstractions; -/// -/// The translations a scenery ships alongside itself, in scenery/i18n/*.json. -/// -/// -/// Scenery text may be an "@key" reference rather than literal prose, resolved -/// against the currently loaded scenery's table. The table is per scenery, so -/// replaces it rather than adding to it. -/// public interface ISceneryTranslations { - /// Loads the tables for one scenery, English first then the user's language. void LoadFor(Scenery scenery, string langCode); - /// - /// Resolves an "@key" reference against the loaded table. Text that is not a - /// reference, or a key with no translation, comes back unchanged. - /// string Translate(string? text); } diff --git a/StarterNG/Application/Abstractions/IVehicleRepository.cs b/StarterNG/Application/Abstractions/IVehicleRepository.cs index d32247b..5e285f2 100644 --- a/StarterNG/Application/Abstractions/IVehicleRepository.cs +++ b/StarterNG/Application/Abstractions/IVehicleRepository.cs @@ -2,16 +2,7 @@ using StarterNG.Domain.Vehicles; namespace StarterNG.Application.Abstractions; -/// -/// Reads the installation's rolling stock. The only route from the dynamic/ -/// folder to a . -/// public interface IVehicleRepository { - /// - /// Fills the catalogue from every textures.txt under dynamic/. Returns the - /// number of liveries read, which the caller uses to spot an installation - /// with no rolling stock at all. - /// int Load(VehicleCatalog catalog); } diff --git a/StarterNG/Application/AppServices.cs b/StarterNG/Application/AppServices.cs index d12d0f9..e223746 100644 --- a/StarterNG/Application/AppServices.cs +++ b/StarterNG/Application/AppServices.cs @@ -9,22 +9,9 @@ using StarterNG.Services; namespace StarterNG.Application; -/// -/// The composition root: the single place where concrete adapters are chosen and -/// wired to the ports the rest of the application depends on. -/// -/// -/// Hand-written on purpose. The starter publishes with PublishAot and -/// PublishTrimmed, which rules out reflection-based containers; the object -/// graph is small enough that explicit construction is also the clearest -/// documentation of what depends on what. -/// -/// is a service locator and is used in exactly one kind of -/// place — the entry point and the view constructors Avalonia creates for us, -/// which cannot take arguments. Everything below that boundary receives its -/// dependencies through its constructor; new code must not reach for -/// . -/// +// Skladany recznie: PublishAot i PublishTrimmed wykluczaja kontener oparty na +// refleksji. Current jest service locatorem i wolno go czytac tylko z entry +// pointu i z konstruktorow widokow, ktorych Avalonia nie potrafi parametryzowac. public sealed class AppServices { private static AppServices? _current; @@ -61,16 +48,10 @@ public sealed class AppServices StartSimulation = new StartSimulation(State, SettingsStore, files, Processes, Random, log); } - /// - /// The graph built by the entry point. Throws when read before - /// , which would mean a static initializer somewhere - /// ran ahead of the composition root. - /// public static AppServices Current => _current ?? throw new InvalidOperationException( "AppServices.Current read before Initialize(); the composition root must be built first."); - /// Builds the production graph. Called once, from the entry point. public static AppServices Initialize(IGamePaths? paths = null, IFileSystem? files = null, IClock? clock = null, IEnvironment? environment = null) { @@ -114,16 +95,12 @@ public sealed class AppServices public LoadWeightsRepository LoadWeights { get; } - /// Everything read out of the installation: rolling stock and scenarios. public GameLibrary Library { get; } - /// What the user currently has selected. public AppState State { get; } - /// The settings the starter runs with, and their load/save lifecycle. public SettingsStore SettingsStore { get; } - /// Shorthand for the settings themselves. public SimulatorSettings Settings => SettingsStore.Settings; public ExecutableLocator Executables { get; } @@ -132,13 +109,7 @@ public sealed class AppServices public MissingVehicleLog MissingVehicleLog { get; } - /// Starts the simulator on the current selection. public StartSimulation StartSimulation { get; } - /// - /// Exposed as the concrete service rather than - /// because the XAML binds to it as a change-notifying source; code should take - /// the port. - /// public LocalizationService Localization { get; } } diff --git a/StarterNG/Application/AppState.cs b/StarterNG/Application/AppState.cs index 105e6c7..78ab716 100644 --- a/StarterNG/Application/AppState.cs +++ b/StarterNG/Application/AppState.cs @@ -5,18 +5,8 @@ using StarterNG.Classes; namespace StarterNG.Application; -/// -/// What the user currently has selected: which scenario, which consist in it and -/// which vehicle they will start in. -/// -/// -/// Session state rather than domain state, which is why it lives in the -/// application layer. Built by the composition root instead of being an ambient -/// singleton; screens observe to stay in step. -/// public sealed class AppState { - /// Raised whenever any of the selections changes. public event Action? Changed; private Scenery? _currentScenery; diff --git a/StarterNG/Application/GameLibrary.cs b/StarterNG/Application/GameLibrary.cs index 8783c09..1f94b67 100644 --- a/StarterNG/Application/GameLibrary.cs +++ b/StarterNG/Application/GameLibrary.cs @@ -7,7 +7,6 @@ using StarterNG.Domain.Vehicles; namespace StarterNG.Application; -/// Which part of the installation the loader is working through. public enum LoadPhase { Vehicles, @@ -15,19 +14,8 @@ public enum LoadPhase Done } -/// How far the load has got, for the splash screen. public readonly record struct LoadStatus(double Fraction, LoadPhase Phase, string? Detail); -/// -/// Everything the starter reads out of the installation once: the rolling stock -/// catalogue and the list of scenarios. -/// -/// -/// Was the GameData singleton, which also owned directory enumeration and -/// parallel parsing. It is now an ordinary object built by the composition root, -/// delegating to the repositories; the loading policy (what is read, in what -/// order, what counts as progress) is all that is left here. -/// public sealed class GameLibrary { private readonly IVehicleRepository _vehicles; @@ -53,11 +41,6 @@ public sealed class GameLibrary public bool Loaded { get; private set; } - /// - /// Reads the whole installation. Vehicles first, because the scenery list - /// resolves consists against them; the thumbnail and physics indexes are - /// built alongside since they are independent directory scans. - /// public void Load(IProgress? progress = null) { if (Loaded) @@ -78,7 +61,6 @@ public sealed class GameLibrary Loaded = true; } - /// Re-reads the scenery folder, picking up files added since startup. public void ReloadSceneries(IProgress? progress = null) { var reloaded = _sceneries.LoadAll(progress); diff --git a/StarterNG/Application/MissingVehicleLog.cs b/StarterNG/Application/MissingVehicleLog.cs index fa4de6c..5d3ff7e 100644 --- a/StarterNG/Application/MissingVehicleLog.cs +++ b/StarterNG/Application/MissingVehicleLog.cs @@ -5,15 +5,6 @@ using StarterNG.Infrastructure.Vehicles; namespace StarterNG.Application; -/// -/// Writes the "vehicle files that are not there" report into the diagnostics -/// log, when the user has asked for it. -/// -/// -/// Was a method on the settings object, which had no business scanning the -/// installation. The setting decides whether it runs; the scan itself belongs to -/// the vehicle side. -/// public sealed class MissingVehicleLog { private readonly SimulatorSettings _settings; diff --git a/StarterNG/Application/SettingsStore.cs b/StarterNG/Application/SettingsStore.cs index bdd40c9..bb56352 100644 --- a/StarterNG/Application/SettingsStore.cs +++ b/StarterNG/Application/SettingsStore.cs @@ -9,24 +9,11 @@ using StarterNG.Infrastructure.Adapters; namespace StarterNG.Application; -/// -/// A screen that holds settings the user is editing and can be asked to write -/// them back into the model before a save. -/// -/// -/// Replaces the mutable Action? CaptureFromUi the settings model used to -/// expose: the dependency now points the right way, from the store to an -/// interface the view implements. -/// public interface ISettingsCapture { void CaptureInto(SimulatorSettings settings); } -/// -/// Owns the settings the starter runs with: where they were read from, when to -/// write them back, and which executable they point at. -/// public sealed class SettingsStore { private readonly IFileSystem _files; @@ -54,25 +41,14 @@ public sealed class SettingsStore _encoding = LegacyText.CodePage1250; } - /// The settings the application is running with. public SimulatorSettings Settings { get; } = new(); - /// The file the current settings were read from. public string LoadedFrom { get; private set; } = string.Empty; - /// The file a save will write to. public string SavePath => _savePath; - /// - /// Registers the screen that holds pending edits, so a save can collect them - /// first. Called by the settings view when it is created. - /// public void RegisterCapture(ISettingsCapture capture) => _capture = capture; - /// - /// Reads the user's settings, falling back to the copy shipped with the - /// installation on a first run. - /// public void Load() { _savePath = _paths.UserConfigPath(); @@ -91,7 +67,6 @@ public sealed class SettingsStore } catch (Exception ex) { - // An unreadable ini means defaults, not a failed start. _log.Log($"reading {path}", ex); _config = new ConfigFile(); } @@ -100,7 +75,6 @@ public sealed class SettingsStore TouchConfigAge(); } - /// Collects pending edits from the settings screen, then saves. public void CaptureAndSave() { _capture?.CaptureInto(Settings); @@ -134,7 +108,6 @@ public sealed class SettingsStore } } - /// Records the ini's timestamp, so an outside edit can be noticed. public void TouchConfigAge() { string path = string.IsNullOrEmpty(_savePath) ? _paths.UserConfigPath() : _savePath; @@ -148,10 +121,6 @@ public sealed class SettingsStore } } - /// - /// True when something else has written the ini since we last touched it - - /// the simulator itself, usually, which the starter must not clobber. - /// public bool IsConfigNewerOnDisk() { string path = string.IsNullOrEmpty(_savePath) ? _paths.UserConfigPath() : _savePath; @@ -160,7 +129,6 @@ public sealed class SettingsStore if (!_files.FileExists(path) || _configAgeUtc == DateTime.MinValue) return false; - // A second of slack: writing our own file must not count as an edit. return _files.GetLastWriteTimeUtc(path) > _configAgeUtc + TimeSpan.FromSeconds(1); } catch (Exception) @@ -172,5 +140,4 @@ public sealed class SettingsStore public string ResolveExecutable() => _executables.Resolve(Settings, out _); public string ResolveExecutable(out ExeProblem problem) => _executables.Resolve(Settings, out problem); - } diff --git a/StarterNG/Application/StartSimulation.cs b/StarterNG/Application/StartSimulation.cs index a6b75dd..fcfe53c 100644 --- a/StarterNG/Application/StartSimulation.cs +++ b/StarterNG/Application/StartSimulation.cs @@ -10,28 +10,19 @@ using StarterNG.Infrastructure.Adapters; namespace StarterNG.Application; -/// Why a start attempt ended the way it did. public enum SimulationStartOutcome { Started, - /// Nothing is selected to run. NothingSelected, - /// The scenario could not be written for the simulator to read. ExportFailed, - /// The executable is missing, not executable, or built for another platform. ExecutableProblem, - /// The executable is fine but the process would not start. LaunchFailed } -/// -/// What happened, and what the caller needs in order to say so or to watch the -/// simulator it just started. -/// public readonly record struct SimulationStartResult( SimulationStartOutcome Outcome, IProcessHandle? Process = null, @@ -39,25 +30,10 @@ public readonly record struct SimulationStartResult( ExeProblem Problem = ExeProblem.None, string? Detail = null); -/// -/// Starts the simulator on the scenario and consist the user has selected. -/// -/// -/// This was the middle of a 100-line click handler that also drove dialogs and -/// the loading screen. The sequence itself - settle the consist's starting -/// state, write the scenario the simulator will read, save the settings, launch - -/// is application logic and belongs away from the window; what is left in the -/// view is asking the user things and showing what came back. -/// public sealed class StartSimulation { - /// - /// A scenario the starter has rewritten is saved beside the original under a - /// '$' name, which the simulator loads and the scenery list ignores. - /// private const char ExportPrefix = '$'; - /// Battery voltage stood in for by a token velocity, as the format demands. private const float BatteryOnVelocity = 0.1f; private readonly AppState _state; @@ -78,10 +54,6 @@ public sealed class StartSimulation _log = log; } - /// - /// The vehicle the player would start in, or null when the consist has no one - /// aboard - which is what the caller warns about before committing. - /// public static string? StartableVehicle(Trainset? trainset, string? preferred) { if (trainset is null || trainset.Vehicles.Count == 0) @@ -101,8 +73,6 @@ public sealed class StartSimulation return trainset.Vehicles.FirstOrDefault(CanStart)?.Name; } - /// Start as a free camera rather than in a vehicle. - /// Write the settings before launching. public SimulationStartResult Execute(bool freeFly, bool saveSettings) { var scenery = _state.CurrentScenery; @@ -116,8 +86,6 @@ public sealed class StartSimulation ?? StartableVehicle(trainset, _state.StartingVehicleName); _state.StartingVehicleName = vehicle; - // The export always rewrites the weather block, so a run reflects what the - // weather tab shows even when the user never touched it. scenery.Weather.Dirty = true; string exportName = ExportPrefix + Path.GetFileName(scenery.Path); @@ -155,11 +123,6 @@ public sealed class StartSimulation return new SimulationStartResult(SimulationStartOutcome.Started, process, executable); } - /// - /// Applies the user's battery preference to the consist. The scenery format - /// carries the battery state in the trainset's velocity field, so "always on" - /// means a token non-zero value when the consist is standing still. - /// private void ApplyBatteryDefault(Trainset trainset) { if (trainset.Vehicles.Count == 0) @@ -174,5 +137,4 @@ public sealed class StartSimulation _ => trainset.OriginalVelocity }; } - } diff --git a/StarterNG/Controls/DetailRows.cs b/StarterNG/Controls/DetailRows.cs index 4d325e7..706a895 100644 --- a/StarterNG/Controls/DetailRows.cs +++ b/StarterNG/Controls/DetailRows.cs @@ -2,28 +2,10 @@ using Avalonia.Controls; namespace StarterNG.Controls; -/// -/// The read-only label/value lines the depot's detail tabs are built from. -/// -/// -/// Shared so every tab reads the same way: label in the left column, value in -/// the right, aligned down the panel. Previously each tab built its own rows, -/// and the texture tab glued "label: value" into a single line, which lined up -/// with nothing. -/// public static class DetailRows { - /// Shown in place of a reading a vehicle does not have. public const string NoValue = "–"; - /// - /// The one row shape every detail tab uses. The label column negotiates its - /// width through the shared-size group on the host panel, so all rows in a - /// panel line up without anyone naming a pixel count - see the Compact styles - /// in Settings.axaml. Omitting makes it a - /// read-only line; omitting indents a bare widget to - /// the control column. - /// public static SettingRow Row(string? label = null, Control? content = null, string? value = null, string? description = null, string? tip = null) @@ -43,11 +25,6 @@ public static class DetailRows return row; } - /// - /// A read-only label/value line. The dash keeps the row from collapsing when a - /// vehicle has no reading for the field; the full value is on the tooltip, so - /// a trimmed one is still legible. - /// public static SettingRow Reading(string label, string? value) { bool empty = string.IsNullOrWhiteSpace(value); diff --git a/StarterNG/Controls/SettingRow.cs b/StarterNG/Controls/SettingRow.cs index 3135314..bee10d4 100644 --- a/StarterNG/Controls/SettingRow.cs +++ b/StarterNG/Controls/SettingRow.cs @@ -3,13 +3,6 @@ using Avalonia.Controls; namespace StarterNG.Controls; -/// -/// One line of the settings panel: label on the left, the control itself in the -/// middle, a value read-out on the right, and underneath the eu07.ini key this -/// row writes plus an optional description. -/// Replaces the hand-rolled StackPanel/DockPanel pattern that used to be repeated -/// for every setting. -/// public class SettingRow : ContentControl { public static readonly StyledProperty LabelProperty = @@ -18,12 +11,6 @@ public class SettingRow : ContentControl public static readonly StyledProperty DescriptionProperty = AvaloniaProperty.Register(nameof(Description)); - /// - /// The eu07.ini key this row reads and writes, shown verbatim so a user can - /// match what they see here against the file, the wiki or a forum post. Rows - /// that are starter-only preferences carry their "starter.*" key just the - /// same; rows that write no key at all leave this empty. - /// public static readonly StyledProperty ConfigKeyProperty = AvaloniaProperty.Register(nameof(ConfigKey)); @@ -71,19 +58,12 @@ public class SettingRow : ContentControl UpdatePseudoClasses(); } - /// - /// Drives the template: an empty label lets the control span the label column, - /// an empty description or value collapses that part of the row entirely. - /// private void UpdatePseudoClasses() { PseudoClasses.Set(":no-label", string.IsNullOrEmpty(Label)); PseudoClasses.Set(":no-description", string.IsNullOrEmpty(Description)); PseudoClasses.Set(":no-key", string.IsNullOrEmpty(ConfigKey)); PseudoClasses.Set(":no-value", string.IsNullOrEmpty(ValueText)); - // A read-only row is a label and a reading with no widget between them. The - // reading then takes the middle column too, so a long path ellipsises instead - // of demanding its full width from an Auto column and getting cut off. PseudoClasses.Set(":no-content", Content is null); } } diff --git a/StarterNG/Controls/SettingsSection.cs b/StarterNG/Controls/SettingsSection.cs index cf5fa23..7cb092d 100644 --- a/StarterNG/Controls/SettingsSection.cs +++ b/StarterNG/Controls/SettingsSection.cs @@ -3,11 +3,6 @@ using Avalonia.Controls.Primitives; namespace StarterNG.Controls; -/// -/// A group of s under a flat title with an accent rule. -/// holds an optional master switch shown on the right of the -/// title line; the section content gates itself off it. -/// public class SettingsSection : HeaderedContentControl { public static readonly StyledProperty ToggleProperty = diff --git a/StarterNG/Domain/Sceneries/Scenery.cs b/StarterNG/Domain/Sceneries/Scenery.cs index df9a079..243ab2f 100644 --- a/StarterNG/Domain/Sceneries/Scenery.cs +++ b/StarterNG/Domain/Sceneries/Scenery.cs @@ -9,43 +9,22 @@ using StarterNG.Domain; namespace StarterNG.Domain.Sceneries; -/// A file the scenery offers to open alongside it (map, manual, ...). public sealed class SceneryAttachment { public string FilePath = ""; public string Label = ""; } -/// -/// An include the scenery marks as optional, so the user can decide -/// whether it ends up in the exported scenario. -/// public sealed class SceneryInclude { public string FilePath = ""; public string Desc = ""; - /// 1 = on by default, 2 = only when no companion timetable exists. public int Kind; public bool Selected; } -/// -/// A scenario the user can start: its consists, loose vehicles, optional -/// includes and weather, plus the ability to render all of that back into a .scn -/// the simulator can load. -/// -/// -/// The aggregate is pure: it never reads or writes files. Parsing lives in -/// Infrastructure.Sceneries.SceneryParser and loading in -/// SceneryRepository, which is what lets the export rules be tested from -/// a string rather than an installation. -/// -/// is the .scn text with every trainset replaced by a -/// {{index}} placeholder and the optional includes stripped, so -/// only has to substitute rather than re-parse. -/// public sealed class Scenery { public Scenery(string path, string template) @@ -54,13 +33,10 @@ public sealed class Scenery Template = template; } - /// Path of the .scn this was parsed from; the aggregate's identity. public string Path { get; } - /// The .scn body with trainset placeholders, used for export. public string Template { get; } - /// True when a companion .sbt timetable sits next to the .scn. public bool HasCompanionTimetable { get; set; } public string? Group { get; set; } @@ -71,7 +47,6 @@ public sealed class Scenery public string? ImageName { get; set; } - /// Scenery kept for historical interest; hidden unless asked for. public bool Archival { get; set; } public List Trainsets { get; } = new(); @@ -80,38 +55,21 @@ public sealed class Scenery public List Includes { get; } = new(); - /// Vehicles placed directly as nodes rather than inside a trainset. public List LooseVehicles { get; } = new(); - /// - /// Names of every loose vehicle, including those whose node failed to parse - /// and therefore has no . - /// public List LooseVehicleNames { get; } = new(); - /// Parse problems worth showing on the scenario's fault list. public List Faults { get; } = new(); public SceneryWeather Weather { get; } = new(); public string DisplayName => System.IO.Path.GetFileNameWithoutExtension(Path); - /// - /// The description with any "@key" references resolved against the scenery's - /// own translation files. - /// public string LocalizedDescription(ISceneryTranslations translations) => string.IsNullOrEmpty(Description) ? "" : string.Join("\n", Description.Split('\n').Select(translations.Translate)); - /// - /// Renders the scenario the simulator should load: the original file with the - /// user's consists, weather and optional includes applied. - /// - /// - /// Drops AI trainsets the user marked irrelevant, which shortens loading. - /// public string BuildExportContent(bool skipDecorTrainsets, IRandomSource random) { string result = Template; @@ -154,8 +112,6 @@ public sealed class Scenery var sb = new StringBuilder(); foreach (var include in Includes) { - // Kind 2 is the scenery's own timetable stand-in: it is only wanted - // when the user has not supplied a companion .sbt. if (include.Kind == 2) { if (!HasCompanionTimetable) @@ -172,10 +128,6 @@ public sealed class Scenery return InsertBeforeFirstInit(text, sb.ToString(), fallbackAtEnd: false); } - /// - /// Places generated content ahead of FirstInit, which the simulator - /// treats as the end of the definition section. - /// private static string InsertBeforeFirstInit(string text, string addition, bool fallbackAtEnd) { var firstInit = Regex.Match(text, @"\bFirstInit\b", RegexOptions.IgnoreCase); diff --git a/StarterNG/Domain/Sceneries/SceneryWeather.cs b/StarterNG/Domain/Sceneries/SceneryWeather.cs index 36f7054..ebe9b78 100644 --- a/StarterNG/Domain/Sceneries/SceneryWeather.cs +++ b/StarterNG/Domain/Sceneries/SceneryWeather.cs @@ -3,22 +3,11 @@ using StarterNG.Application.Abstractions; namespace StarterNG.Domain.Sceneries; -/// -/// The weather and time-of-day a scenery starts with: what the .scn file -/// declared, what the user has changed it to, and whether that differs. -/// -/// -/// Split out of Scenery so the "is this still the authored weather?" -/// rule lives next to the values it compares, instead of being spread over the -/// aggregate and the weather tab. The aggregate owns one of these; the parser -/// fills it and calls once. -/// public sealed class SceneryWeather { public const int FogMin = 10; public const int FogMax = 10000; - /// Overcast values the "random" option picks between. private static readonly double[] OvercastPresets = { -1.5, 0, 0.3, 0.7, 1, 1.1, 1.5 }; private string _authoredTime = "10:30"; @@ -33,7 +22,6 @@ public sealed class SceneryWeather public string ScenarioTimeOverride { get; set; } = "10:30"; - /// Day of the year driving the sun position (movelight). public int Day { get; set; } public double Temperature { get; set; } = 15; @@ -44,16 +32,12 @@ public sealed class SceneryWeather public double Overcast { get; set; } - /// When set, each export draws a fresh overcast from the presets. public bool OvercastRandom { get; set; } - /// True when the .scn actually declared weather, rather than us defaulting it. public bool IsAuthored { get; set; } - /// Set once the user has touched the weather, so export rewrites the config block. public bool Dirty { get; set; } - /// Takes the current values as the baseline "what the file said". public void AcceptAsAuthored() { _authoredTime = Time; @@ -65,7 +49,6 @@ public sealed class SceneryWeather _authoredOvercastRandom = OvercastRandom; } - /// True when the user's weather differs from what the .scn declared. public bool Changed => Day != _authoredDay || ScenarioTimeOverride != _authoredTimeOverride || @@ -74,11 +57,6 @@ public sealed class SceneryWeather OvercastRandom != _authoredOvercastRandom || (!OvercastRandom && Math.Abs(Overcast - _authoredOvercast) > 0.001); - /// - /// Puts back the authored weather. Stays : the export must - /// still rewrite the config block, because the file on disk may already carry - /// an edit from an earlier run. - /// public void Restore() { Time = _authoredTime; @@ -91,7 +69,6 @@ public sealed class SceneryWeather Dirty = true; } - /// Clamps a parsed fog range and picks the distance to run with. public void SetFogRange(int start, int end, IRandomSource random) { FogStart = Math.Clamp(start, FogMin, FogMax); @@ -99,7 +76,6 @@ public sealed class SceneryWeather FogEnd = end > FogStart ? random.Next(FogStart, end + 1) : end; } - /// The overcast to export, drawing a preset when randomisation is on. public double EffectiveOvercast(IRandomSource random) => OvercastRandom ? OvercastPresets[random.Next(0, OvercastPresets.Length)] : Overcast; } diff --git a/StarterNG/Domain/Sceneries/SceneryWeatherWriter.cs b/StarterNG/Domain/Sceneries/SceneryWeatherWriter.cs index 2b9d069..bf4270d 100644 --- a/StarterNG/Domain/Sceneries/SceneryWeatherWriter.cs +++ b/StarterNG/Domain/Sceneries/SceneryWeatherWriter.cs @@ -6,17 +6,8 @@ using StarterNG.Application.Abstractions; namespace StarterNG.Domain.Sceneries; -/// -/// Renders a back into the .scn dialect: strips the -/// blocks the starter owns and prepends freshly written ones. -/// -/// -/// A pure text transformation, kept out of the aggregate because it is entirely -/// about the file format rather than about the scenario. -/// public static class SceneryWeatherWriter { - /// Config lines the starter writes itself and must not carry over. private static readonly Regex ManagedConfigLine = new( @"^\s*(movelight|scenario\.weather\.temperature|scenario\.time\.override)\b", RegexOptions.IgnoreCase | RegexOptions.Compiled); @@ -51,14 +42,10 @@ public static class SceneryWeatherWriter } catch { - // A scenery we cannot rewrite is still worth starting unmodified. return text; } } - /// - /// The simulator's parser expects an unpadded hour ("7:30", not "07:30"). - /// private static string DelphiHourMinute(string hhmm) { int colon = hhmm.IndexOf(':'); @@ -70,10 +57,6 @@ public static class SceneryWeatherWriter : "0" + hhmm[colon..]; } - /// - /// Config entries the scenery author wrote that are none of the starter's - /// business, preserved verbatim across a rewrite. - /// private static string CarriedConfigLines(string text) { var block = Regex.Match(text, @"(?is)\bconfig\b(.*?)\bendconfig\b"); diff --git a/StarterNG/Domain/Settings/SimulatorSettings.cs b/StarterNG/Domain/Settings/SimulatorSettings.cs index f326691..2ba822b 100644 --- a/StarterNG/Domain/Settings/SimulatorSettings.cs +++ b/StarterNG/Domain/Settings/SimulatorSettings.cs @@ -2,43 +2,16 @@ using System; namespace StarterNG.Domain.Settings; -/// How the simulator should treat the battery switch when a run starts. public enum BatteryDefault { Default = 0, AlwaysOff = 1, AlwaysOn = 2 } -/// What is wrong with the executable the starter would launch. public enum ExeProblem { None, NotFound, NotExecutable, WrongPlatform } -/// -/// Everything the starter writes into eu07.ini, plus the handful of preferences -/// it keeps for itself. -/// -/// -/// Plain state with sensible defaults, and nothing else: reading and writing the -/// ini is Infrastructure.Settings.SettingsSerializer, locating the file -/// and the executable is the rest of that folder, and the load/save lifecycle is -/// Application.SettingsStore. Splitting those out is what makes it -/// possible to test the ini mapping without a disk. -/// public sealed class SimulatorSettings { - /// - /// False until the ini names a language, which is how the first run knows to - /// follow the operating system instead. - /// public bool LanguageWasSet { get; internal set; } - /// - /// Display name of the starter's language, as the picker shows it ("Polski", - /// "English", "中文"). Resolved from at startup. - /// public string Language = "English"; - /// - /// The language's code, as its startercfg/lang/*.xml declares it and as - /// eu07.ini stores it. This is what the simulator reads, so it has to carry - /// whatever language the user actually picked rather than being folded into - /// one of two known ones. - /// public string LanguageCode = ""; public bool Fullscreen; public bool PauseWhenInactive = true; @@ -118,10 +91,6 @@ public sealed class SimulatorSettings public bool SkipPipeline; public int PythonScreenUpdateRate = 200; public bool DebugLogVisible; - /// - /// Debug log bits beyond the two the UI exposes, carried through a round trip - /// so a hand-configured log level is not silently narrowed. - /// internal int DebugLogExtraBits { get; set; } public bool CompressTextures = true; @@ -146,11 +115,6 @@ public sealed class SimulatorSettings public bool HideArchivalVehicles = true; public string LastScenery = ""; - /// - /// Starter's own window state, the way the old one kept WindowMaximized in - /// starter.ini. Only the maximised flag is remembered - a normal window - /// always opens at its design size, centred on the screen. - /// public bool WindowMaximized; public static readonly string[] RenderEngines = @@ -158,16 +122,7 @@ public sealed class SimulatorSettings public static readonly int[] AnisotropySteps = { 1, 2, 4, 8, 16 }; - /// - /// Vertical mouse scale as the ini stored it. The UI only exposes one - /// sensitivity, so the authored vertical magnitude is carried through a - /// round trip rather than being overwritten. - /// internal double MouseScaleYMagnitude { get; set; } = 0.2; - /// - /// Shadow tuning values beyond the two the UI edits, carried through a round - /// trip unchanged. - /// internal string[] ShadowTuneExtra { get; set; } = { "400", "300" }; } diff --git a/StarterNG/Domain/Vehicles/LoadWeightsTable.cs b/StarterNG/Domain/Vehicles/LoadWeightsTable.cs index 52d8501..2422545 100644 --- a/StarterNG/Domain/Vehicles/LoadWeightsTable.cs +++ b/StarterNG/Domain/Vehicles/LoadWeightsTable.cs @@ -4,18 +4,8 @@ using StarterNG.Classes; namespace StarterNG.Domain.Vehicles; -/// -/// How heavy a tonne of each cargo type is, as declared by -/// data/load_weights.txt, used to turn a load into a mass. -/// -/// -/// Was a static class that also read the file. The table is now a value the -/// repository builds; an unknown cargo weighs , which -/// is what the simulator assumes. -/// public sealed class LoadWeightsTable { - /// Weight assumed for a cargo the file does not mention. public const int DefaultWeight = 1000; private readonly Dictionary _weights; @@ -24,7 +14,6 @@ public sealed class LoadWeightsTable { _weights = new Dictionary(StringComparer.OrdinalIgnoreCase) { - // The pantograph state is carried as a pseudo load and weighs nothing. [Dynamic.PantState] = 0 }; diff --git a/StarterNG/Domain/Vehicles/VehicleCatalog.cs b/StarterNG/Domain/Vehicles/VehicleCatalog.cs index 96bf7c4..095837e 100644 --- a/StarterNG/Domain/Vehicles/VehicleCatalog.cs +++ b/StarterNG/Domain/Vehicles/VehicleCatalog.cs @@ -6,17 +6,6 @@ using StarterNG.Application.Abstractions; namespace StarterNG.Domain.Vehicles; -/// -/// Every livery the installation offers, indexed for the lookups the depot and -/// the consist editor make: by uuid, by skin file, and by the set a vehicle -/// belongs to. -/// -/// -/// Was VehicleCatalog, which also owned file enumeration, textures.txt -/// parsing, a static thumbnail dictionary and a missing-asset scan. Those moved -/// to Infrastructure; what is left is the model and its resolution rules, filled -/// by a repository through . -/// public sealed class VehicleCatalog { private readonly IMiniTextureIndex _minis; @@ -26,7 +15,6 @@ public sealed class VehicleCatalog _minis = minis; } - /// Every livery worth offering (wrecks excluded). public List Textures { get; } = new(); public Dictionary GroupsById { get; } = new(); @@ -37,7 +25,6 @@ public sealed class VehicleCatalog public Dictionary TextureByUuid { get; } = new(); - /// Liveries by skin file name without extension, lower cased. public Dictionary TextureBySkin { get; } = new(); public void BeginLoad() @@ -50,7 +37,6 @@ public sealed class VehicleCatalog TextureBySkin.Clear(); } - /// Adds one vehicle folder's liveries to the catalogue. public void Ingest(VehicleEntry entry) { foreach (var group in entry.Groups) @@ -74,14 +60,12 @@ public sealed class VehicleCatalog Sets.AddRange(entry.Sets); } - /// Builds the indexes that depend on the catalogue being complete. public void EndLoad() { BuildSetIndex(); ResolveGroupInheritance(); } - /// The vehicles of the fixed set this livery leads or belongs to. public List? ResolveSet(VehicleTexture texture) { if (string.IsNullOrEmpty(texture.Uuid)) @@ -97,10 +81,6 @@ public sealed class VehicleCatalog return cars.Count > 0 ? cars : null; } - /// - /// True when the livery is a non-leading member of a set, and so is added - /// along with its leader rather than on its own. - /// public bool IsSetFollower(VehicleTexture texture) { if (string.IsNullOrEmpty(texture.Uuid)) @@ -113,10 +93,6 @@ public sealed class VehicleCatalog return lead is not null && !string.Equals(lead, texture.Uuid, StringComparison.OrdinalIgnoreCase); } - /// - /// The thumbnail to draw for a livery: its own if we have that bitmap, - /// otherwise the one its group declares. - /// public string? ResolveMiniName(VehicleTexture texture) { if (_minis.Has(texture.TextureMini)) @@ -141,7 +117,6 @@ public sealed class VehicleCatalog return TextureBySkin.TryGetValue(key, out var texture) ? texture : null; } - /// Heading shown above a group in the depot browser. public string GroupHeader(string? groupId) { if (string.IsNullOrEmpty(groupId) || !GroupsById.TryGetValue(groupId, out var group)) @@ -164,10 +139,6 @@ public sealed class VehicleCatalog } } - /// - /// Copies thumbnail, category and archived status down from each group onto - /// its liveries, so the browser can sort and filter without walking back up. - /// private void ResolveGroupInheritance() { foreach (var texture in Textures) @@ -182,7 +153,6 @@ public sealed class VehicleCatalog string? category = group?.Category; - // "*" means "categorise by the first letter of the thumbnail name". if (category == "*") { string source = !string.IsNullOrEmpty(mini) ? mini : texture.TextureMini ?? ""; diff --git a/StarterNG/Domain/Vehicles/VehiclePhysics.cs b/StarterNG/Domain/Vehicles/VehiclePhysics.cs index 22c62bd..742bed8 100644 --- a/StarterNG/Domain/Vehicles/VehiclePhysics.cs +++ b/StarterNG/Domain/Vehicles/VehiclePhysics.cs @@ -2,24 +2,12 @@ using System; namespace StarterNG.Domain.Vehicles; -/// -/// The physical properties of a vehicle type, as declared by its .fiz file: -/// what it weighs, how fast it goes, what it can carry and what it couples to. -/// -/// -/// Was Classes.Physics, which also owned the .fiz index, the parser and a -/// static cache. Those are now Infrastructure.Vehicles.FizPhysicsRepository; -/// this is the value the rest of the application reasons about. -/// public sealed class VehiclePhysics { - /// Tare mass in kilograms. public double Mass { get; set; } - /// Design speed in km/h. public double VMax { get; set; } - /// Length over buffers in metres. public double Length { get; set; } public string LoadAccepted { get; set; } = ""; @@ -28,10 +16,8 @@ public sealed class VehiclePhysics public int MaxLoad { get; set; } - /// Coupling capabilities of the front end. public int AllowedFlagA { get; set; } = 3; - /// Coupling capabilities of the rear end. public int AllowedFlagB { get; set; } = 3; public string ControlTypeA { get; set; } = ""; diff --git a/StarterNG/Domain/Vehicles/VehicleTexture.cs b/StarterNG/Domain/Vehicles/VehicleTexture.cs index 2c4131c..820b08a 100644 --- a/StarterNG/Domain/Vehicles/VehicleTexture.cs +++ b/StarterNG/Domain/Vehicles/VehicleTexture.cs @@ -2,10 +2,6 @@ using System.Collections.Generic; namespace StarterNG.Domain.Vehicles; -/// -/// One vehicle folder's contribution to the catalogue: the liveries it defines, -/// the groups they belong to and any fixed sets they form. -/// public sealed class VehicleEntry { public string? Uuid { get; set; } @@ -14,21 +10,15 @@ public sealed class VehicleEntry public List Sets { get; } = new(); } -/// -/// A family of liveries sharing a thumbnail and a category letter, as declared -/// by one textures.txt block. -/// public sealed class VehicleGroup { public string Id { get; set; } = ""; public string? Category { get; set; } public string? Mini { get; set; } - /// Withdrawn stock, hidden from the depot unless asked for. public bool Archived { get; set; } } -/// A single livery: one skin file on one model. public sealed class VehicleTexture { public string? Uuid { get; set; } @@ -39,7 +29,6 @@ public sealed class VehicleTexture public string? MiniRef { get; set; } public string? TextureMini { get; set; } - /// Wreck liveries exist in the files but are not offered in the depot. public bool Wreck { get; set; } public List Aliases { get; } = new(); @@ -47,17 +36,13 @@ public sealed class VehicleTexture public string FullPath => Directory + Skinfile; - /// Thumbnail name after group inheritance; filled by the catalogue. public string ResolvedClass { get; internal set; } = ""; - /// Category letter after group inheritance; filled by the catalogue. public string? ResolvedCategory { get; internal set; } - /// Whether the owning group is archived; filled by the catalogue. public bool ResolvedArchived { get; internal set; } } -/// An alternative model this same skin can be worn by. public sealed class VehicleAlias { public string? Model { get; set; } @@ -66,10 +51,6 @@ public sealed class VehicleAlias public string? TextureMini { get; set; } } -/// -/// The comma separated description a livery carries after "//": who made it, for -/// which operator and depot, and when it was last revised. -/// public sealed class VehicleMeta { public string? Raw { get; set; } @@ -84,10 +65,6 @@ public sealed class VehicleMeta public List Extra { get; } = new(); } -/// -/// Vehicles that belong together and are added to a consist as a unit, such as a -/// multiple unit or a fixed rake. -/// public sealed class VehicleSet { public string? Uuid { get; set; } diff --git a/StarterNG/Infrastructure/Adapters/FileDiagnosticsLog.cs b/StarterNG/Infrastructure/Adapters/FileDiagnosticsLog.cs index f8b1c18..e1c8e5c 100644 --- a/StarterNG/Infrastructure/Adapters/FileDiagnosticsLog.cs +++ b/StarterNG/Infrastructure/Adapters/FileDiagnosticsLog.cs @@ -6,17 +6,6 @@ using StarterNG.Application.Abstractions; namespace StarterNG.Infrastructure.Adapters; -/// -/// that mirrors every line into starter/bledy.txt. -/// Writing is best-effort: a read-only or full installation directory degrades to -/// an in-memory log rather than taking the starter down, and a single retry is -/// made at time. -/// -/// -/// Instance state replaces the previous static Diagnostics accumulator, so -/// tests can assert on what a use case logged without touching disk (pair it with -/// an in-memory ). -/// public sealed class FileDiagnosticsLog : IDiagnosticsLog { private readonly IFileSystem _files; @@ -75,7 +64,6 @@ public sealed class FileDiagnosticsLog : IDiagnosticsLog } catch { - // A log we cannot delete is not worth failing a user action over. } } } @@ -100,8 +88,6 @@ public sealed class FileDiagnosticsLog : IDiagnosticsLog if (!_writerFailed && _writer is not null) return; - // The streaming writer never came up (or died mid-session): fall back - // to one bulk write so the session is not lost entirely. try { _files.CreateDirectory(Path.GetDirectoryName(_logPath)!); @@ -109,7 +95,6 @@ public sealed class FileDiagnosticsLog : IDiagnosticsLog } catch { - // Nothing left to try; the in-memory log still backs the UI. } } } @@ -143,7 +128,6 @@ public sealed class FileDiagnosticsLog : IDiagnosticsLog } catch { - // Disposing a broken writer is allowed to fail. } _writer = null; } diff --git a/StarterNG/Infrastructure/Adapters/GamePaths.cs b/StarterNG/Infrastructure/Adapters/GamePaths.cs index fe5d38e..3dd5c67 100644 --- a/StarterNG/Infrastructure/Adapters/GamePaths.cs +++ b/StarterNG/Infrastructure/Adapters/GamePaths.cs @@ -3,10 +3,6 @@ using StarterNG.Application.Abstractions; namespace StarterNG.Infrastructure.Adapters; -/// -/// The stock MaSzyna layout, rooted at the process working directory (the -/// starter ships inside the installation folder, next to eu07.exe). -/// public sealed class GamePaths : IGamePaths { public GamePaths(string root) @@ -14,7 +10,6 @@ public sealed class GamePaths : IGamePaths Root = root; } - /// The installation the starter was launched from. public static GamePaths ForCurrentDirectory() => new(Directory.GetCurrentDirectory()); public string Root { get; } diff --git a/StarterNG/Infrastructure/Adapters/LegacyText.cs b/StarterNG/Infrastructure/Adapters/LegacyText.cs index aa48b34..991b023 100644 --- a/StarterNG/Infrastructure/Adapters/LegacyText.cs +++ b/StarterNG/Infrastructure/Adapters/LegacyText.cs @@ -17,14 +17,8 @@ namespace StarterNG.Infrastructure.Adapters; /// public static class LegacyText { - /// The .scn / .fiz / .ini code page, or Latin-1 if it is unavailable. public static Encoding CodePage1250 { get; } = Resolve(); - /// - /// True when the code page could not be loaded and text is being read as - /// Latin-1 instead. Polish characters will be wrong; the startup check - /// reports it rather than leaving it to be discovered on screen. - /// public static bool IsFallback { get; private set; } private static Encoding Resolve() diff --git a/StarterNG/Infrastructure/Adapters/PhysicalFileSystem.cs b/StarterNG/Infrastructure/Adapters/PhysicalFileSystem.cs index 2a3c295..3c3effe 100644 --- a/StarterNG/Infrastructure/Adapters/PhysicalFileSystem.cs +++ b/StarterNG/Infrastructure/Adapters/PhysicalFileSystem.cs @@ -6,10 +6,6 @@ using StarterNG.Application.Abstractions; namespace StarterNG.Infrastructure.Adapters; -/// -/// backed by the real disk. The only place in the -/// application allowed to touch and . -/// public sealed class PhysicalFileSystem : IFileSystem { public bool FileExists(string path) => File.Exists(path); diff --git a/StarterNG/Infrastructure/Adapters/SystemClock.cs b/StarterNG/Infrastructure/Adapters/SystemClock.cs index 6f3e514..225e73b 100644 --- a/StarterNG/Infrastructure/Adapters/SystemClock.cs +++ b/StarterNG/Infrastructure/Adapters/SystemClock.cs @@ -3,7 +3,6 @@ using StarterNG.Application.Abstractions; namespace StarterNG.Infrastructure.Adapters; -/// backed by the machine clock. public sealed class SystemClock : IClock { public DateTime Now => DateTime.Now; diff --git a/StarterNG/Infrastructure/Adapters/SystemEnvironment.cs b/StarterNG/Infrastructure/Adapters/SystemEnvironment.cs index e4b4f7e..24e9ded 100644 --- a/StarterNG/Infrastructure/Adapters/SystemEnvironment.cs +++ b/StarterNG/Infrastructure/Adapters/SystemEnvironment.cs @@ -3,7 +3,6 @@ using StarterNG.Application.Abstractions; namespace StarterNG.Infrastructure.Adapters; -/// backed by the running process. public sealed class SystemEnvironment : IEnvironment { public bool IsWindows => OperatingSystem.IsWindows(); diff --git a/StarterNG/Infrastructure/Adapters/SystemProcessLauncher.cs b/StarterNG/Infrastructure/Adapters/SystemProcessLauncher.cs index ae99789..c72eae0 100644 --- a/StarterNG/Infrastructure/Adapters/SystemProcessLauncher.cs +++ b/StarterNG/Infrastructure/Adapters/SystemProcessLauncher.cs @@ -8,10 +8,6 @@ using StarterNG.Application.Abstractions; namespace StarterNG.Infrastructure.Adapters; -/// -/// backed by . The only place -/// in the application that starts an operating-system process. -/// public sealed class SystemProcessLauncher : IProcessLauncher { private readonly IDiagnosticsLog _log; diff --git a/StarterNG/Infrastructure/Adapters/SystemRandomSource.cs b/StarterNG/Infrastructure/Adapters/SystemRandomSource.cs index debbfb8..b5300dd 100644 --- a/StarterNG/Infrastructure/Adapters/SystemRandomSource.cs +++ b/StarterNG/Infrastructure/Adapters/SystemRandomSource.cs @@ -3,7 +3,6 @@ using StarterNG.Application.Abstractions; namespace StarterNG.Infrastructure.Adapters; -/// backed by . public sealed class SystemRandomSource : IRandomSource { public int Next(int minInclusive, int maxExclusive) => Random.Shared.Next(minInclusive, maxExclusive); diff --git a/StarterNG/Infrastructure/Diagnostics.cs b/StarterNG/Infrastructure/Diagnostics.cs index e5bbc61..2696797 100644 --- a/StarterNG/Infrastructure/Diagnostics.cs +++ b/StarterNG/Infrastructure/Diagnostics.cs @@ -9,16 +9,6 @@ using StarterNG.Views; namespace StarterNG.Infrastructure; -/// -/// Compatibility facade over -/// plus the fault dialog. -/// -/// -/// The log itself now lives in Infrastructure.Adapters.FileDiagnosticsLog -/// and is reached through the composition root. This static shim keeps the -/// existing call sites compiling while they are migrated to constructor-injected -/// logging; new code should take IDiagnosticsLog instead. -/// public static class Diagnostics { private static Application.Abstractions.IDiagnosticsLog Log_ => AppServices.Current.Log; @@ -63,9 +53,6 @@ public static class Diagnostics Dispatcher.UIThread.Post(() => _ = ReportAsync(message, title)); } - /// - /// Sanity check of the installation the starter was launched from. - /// public static List CheckInstallation() => new InstallationCheck( AppServices.Current.Paths, diff --git a/StarterNG/Infrastructure/InstallationCheck.cs b/StarterNG/Infrastructure/InstallationCheck.cs index e6d1824..0c0bb0c 100644 --- a/StarterNG/Infrastructure/InstallationCheck.cs +++ b/StarterNG/Infrastructure/InstallationCheck.cs @@ -7,14 +7,6 @@ using StarterNG.Domain.Settings; namespace StarterNG.Infrastructure; -/// -/// Verifies that the folder the starter runs from actually looks like a MaSzyna -/// installation, and reports what is missing in the user's language. -/// -/// -/// Depends only on ports, so a broken installation can be described in a test by -/// handing it an empty in-memory file system. -/// public sealed class InstallationCheck { private static readonly string[] RequiredFolders = { "dynamic", "sounds", "models", "scenery", "textures" }; diff --git a/StarterNG/Infrastructure/Sceneries/SceneryImageLocator.cs b/StarterNG/Infrastructure/Sceneries/SceneryImageLocator.cs index 42b95a5..dba90fe 100644 --- a/StarterNG/Infrastructure/Sceneries/SceneryImageLocator.cs +++ b/StarterNG/Infrastructure/Sceneries/SceneryImageLocator.cs @@ -5,15 +5,6 @@ using StarterNG.Domain.Sceneries; namespace StarterNG.Infrastructure.Sceneries; -/// -/// Finds the preview image a scenery names, which authors place in any of -/// several conventional spots relative to the .scn. -/// -/// -/// Was a lazy property on the aggregate; moved out because it is a lookup on -/// disk. Results are cached per scenery path, which is what the lazy field -/// bought us before. -/// public sealed class SceneryImageLocator { private readonly IFileSystem _files; @@ -24,7 +15,6 @@ public sealed class SceneryImageLocator _files = files; } - /// The image file for this scenery, or null when there is none. public string? Resolve(Scenery scenery) { lock (_cache) diff --git a/StarterNG/Infrastructure/Sceneries/SceneryParser.cs b/StarterNG/Infrastructure/Sceneries/SceneryParser.cs index 7897255..788062a 100644 --- a/StarterNG/Infrastructure/Sceneries/SceneryParser.cs +++ b/StarterNG/Infrastructure/Sceneries/SceneryParser.cs @@ -10,15 +10,6 @@ using StarterNG.Domain.Sceneries; namespace StarterNG.Infrastructure.Sceneries; -/// -/// Turns the text of a .scn file into a . -/// -/// -/// All knowledge of the .scn dialect lives here, so the aggregate stays free of -/// regular expressions and the parser can be exercised on a string. Anything -/// malformed is recorded as a fault rather than thrown: a scenery with one bad -/// consist is still worth listing. -/// public sealed class SceneryParser { private readonly IClock _clock; @@ -32,8 +23,6 @@ public sealed class SceneryParser public Scenery Parse(string path, string content) { - // Directives, attachments and weather are read from the file as written; - // the placeholder rewriting below only shapes the export template. string original = content; var faults = new List(); @@ -42,8 +31,6 @@ public sealed class SceneryParser var includes = new List(); content = StripOptionalIncludes(content, includes); - // Trainsets are lifted out first so the placeholders survive the loose - // vehicle sweep below, which would otherwise match nodes inside them. var trainsetEntries = new List(); content = Regex.Replace(content, @"trainset\b[\s\S]*?\bendtrainset\b", match => @@ -98,7 +85,6 @@ public sealed class SceneryParser string[] parts = rest.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries); - // A leading one- or two-character token is a legacy ordering hint. if (parts.Length >= 3 && parts[0].Length <= 2) attachments.Add(new SceneryAttachment { @@ -122,10 +108,6 @@ public sealed class SceneryParser return attachments; } - /// - /// Removes the includes the scenery marked $optional from the text and - /// records them, so the user can pick which ones the export puts back. - /// private static string StripOptionalIncludes(string content, List includes) { if (content.IndexOf("$optional", StringComparison.OrdinalIgnoreCase) < 0) @@ -160,10 +142,6 @@ public sealed class SceneryParser RegexOptions.IgnoreCase); } - /// - /// Lifts node ... dynamic ... enddynamic entries that sit outside any - /// trainset, so the depot can show and reorder them like a consist. - /// private static string ExtractLooseVehicles(string content, List vehicles, List names, List faults) { @@ -176,7 +154,6 @@ public sealed class SceneryParser { string name = m.Groups[3].Value; - // A placeholder means the node belongs to a trainset already lifted out. if (name.StartsWith("{{", StringComparison.Ordinal)) return m.Value; @@ -214,7 +191,6 @@ public sealed class SceneryParser } catch { - // Leave the node in the template so the export stays faithful. faults.Add($"# loose dynamic parse fault: {name}"); names.Add(name); return m.Value; @@ -239,7 +215,6 @@ public sealed class SceneryParser } else if (!time.Success) { - // Nothing authored: start the scenario at the player's wall clock. var now = _clock.Now; weather.ScenarioTimeOverride = $"{now.Hour:D2}:{now.Minute:D2}"; } diff --git a/StarterNG/Infrastructure/Sceneries/SceneryRepository.cs b/StarterNG/Infrastructure/Sceneries/SceneryRepository.cs index e8308a2..5da5dee 100644 --- a/StarterNG/Infrastructure/Sceneries/SceneryRepository.cs +++ b/StarterNG/Infrastructure/Sceneries/SceneryRepository.cs @@ -12,17 +12,8 @@ using StarterNG.Infrastructure.Adapters; namespace StarterNG.Infrastructure.Sceneries; -/// -/// Loads scenarios from the installation's scenery folder. -/// -/// -/// Sceneries are code page 1250 text, and a large installation holds hundreds of -/// them, so the sweep is parallel; each file that throws is logged and dropped -/// rather than taking the whole load down. -/// public sealed class SceneryRepository : ISceneryRepository { - /// Files starting with '$' are authoring scratch, not scenarios. private const char ExcludedPrefix = '$'; private readonly IFileSystem _files; @@ -83,5 +74,4 @@ public sealed class SceneryRepository : ISceneryRepository private IEnumerable SceneryFiles() => _files.GetFiles(_paths.Scenery, "*.scn") .Where(path => Path.GetFileName(path).FirstOrDefault() != ExcludedPrefix); - } diff --git a/StarterNG/Infrastructure/Sceneries/SceneryTranslations.cs b/StarterNG/Infrastructure/Sceneries/SceneryTranslations.cs index 593e425..efcc73d 100644 --- a/StarterNG/Infrastructure/Sceneries/SceneryTranslations.cs +++ b/StarterNG/Infrastructure/Sceneries/SceneryTranslations.cs @@ -7,18 +7,8 @@ using StarterNG.Domain.Sceneries; namespace StarterNG.Infrastructure.Sceneries; -/// -/// reading the JSON files a scenery may ship -/// in its i18n folder. -/// -/// -/// English is loaded first and the user's language layered over it, so a partial -/// translation falls back per key rather than per file. Nested objects are -/// flattened to dotted keys, which is how the scenery text references them. -/// public sealed class SceneryTranslations : ISceneryTranslations { - /// Marks a scenery string as a key rather than literal text. private const char ReferencePrefix = '@'; private const string BaseLanguage = "en"; @@ -99,10 +89,6 @@ public sealed class SceneryTranslations : ISceneryTranslations } } - /// - /// Sceneries name their files by two-letter code; the starter's language - /// setting may carry a display name instead. - /// private static string NormalizeLanguage(string language) { string lower = language.Trim().ToLowerInvariant(); diff --git a/StarterNG/Infrastructure/Sceneries/TimetableLocator.cs b/StarterNG/Infrastructure/Sceneries/TimetableLocator.cs index 0fe1dcc..75496d4 100644 --- a/StarterNG/Infrastructure/Sceneries/TimetableLocator.cs +++ b/StarterNG/Infrastructure/Sceneries/TimetableLocator.cs @@ -6,15 +6,6 @@ using StarterNG.Domain.Sceneries; namespace StarterNG.Infrastructure.Sceneries; -/// -/// Finds the timetable file a consist names. -/// -/// -/// Timetables live in the shared timetables/ folder, next to the scenery, or in -/// scenario/ depending on the installation's vintage, and the name may or may -/// not carry its .txt extension. "none" is the format's way of saying a consist -/// runs without one. -/// public sealed class TimetableLocator { private const string NoTimetable = "none"; diff --git a/StarterNG/Infrastructure/Settings/ExecutableLocator.cs b/StarterNG/Infrastructure/Settings/ExecutableLocator.cs index 7521cff..2283eee 100644 --- a/StarterNG/Infrastructure/Settings/ExecutableLocator.cs +++ b/StarterNG/Infrastructure/Settings/ExecutableLocator.cs @@ -7,18 +7,8 @@ using StarterNG.Domain.Settings; namespace StarterNG.Infrastructure.Settings; -/// -/// Finds and vets the simulator executable the starter will launch. -/// -/// -/// Installations ship the binary under several names (eu07.exe, eu07, -/// eu07-vulkan, ...), and a folder shared between platforms may hold both a PE -/// and an ELF build. So a candidate is not just found by name: it is checked for -/// the execute bit and for a magic number matching the platform we are on. -/// public sealed class ExecutableLocator { - /// Extensions that are never the simulator, whatever they are named. private static readonly string[] NeverExecutable = { ".ini", ".log", ".txt", ".cfg", ".config", ".json", ".dll", ".so", ".dat", ".bak", ".csv", ".xml" @@ -37,13 +27,8 @@ public sealed class ExecutableLocator _log = log; } - /// The canonical name for the platform, used when nothing is found. public string CanonicalName => _environment.IsWindows ? "eu07.exe" : "eu07"; - /// - /// The executable to launch for these settings, along with what is wrong with - /// it. A path is always returned so the UI can show what it was looking for. - /// public string Resolve(SimulatorSettings settings, out ExeProblem problem) { if (!settings.SelectExeAutomatically && !string.IsNullOrWhiteSpace(settings.ExecutablePath)) @@ -55,7 +40,6 @@ public sealed class ExecutableLocator string? fallback = null; try { - // Prefer the canonical name, then the shortest: "eu07" over "eu07-dev". var candidates = _files.GetFiles(_paths.Root, "eu07*") .Where(IsCandidate) .OrderBy(path => string.Equals(Path.GetFileName(path), CanonicalName, @@ -87,7 +71,6 @@ public sealed class ExecutableLocator return CanonicalName; } - /// Executables the user can pick from, most recently built first. public List ListCandidates(string? directory = null) { try @@ -122,11 +105,6 @@ public sealed class ExecutableLocator } } - /// - /// Reads the file's magic number: "MZ" for a Windows binary, 0x7F "ELF" for a - /// Linux one. A file we cannot read four bytes from is given the benefit of - /// the doubt. - /// private bool MatchesPlatform(string path) { byte[] head = new byte[4]; diff --git a/StarterNG/Infrastructure/Settings/SettingsPaths.cs b/StarterNG/Infrastructure/Settings/SettingsPaths.cs index f8e62b1..d9eba18 100644 --- a/StarterNG/Infrastructure/Settings/SettingsPaths.cs +++ b/StarterNG/Infrastructure/Settings/SettingsPaths.cs @@ -3,10 +3,6 @@ using StarterNG.Application.Abstractions; namespace StarterNG.Infrastructure.Settings; -/// -/// Where the simulator's eu07.ini lives: per user on each platform, with the -/// installation's own copy as the template for a first run. -/// public sealed class SettingsPaths { private const string ConfigFileName = "eu07.ini"; @@ -21,7 +17,6 @@ public sealed class SettingsPaths _paths = paths; } - /// The user's own settings file, which is what the starter writes. public string UserConfigPath() { if (_environment.IsWindows) @@ -46,7 +41,6 @@ public sealed class SettingsPaths return Path.Combine(_environment.BaseDirectory, ConfigFileName); } - /// The ini shipped with the installation, read when the user has none. public string InstallationConfigPath() => _paths.FromRoot(ConfigFileName); public string UserConfigDirectory() => diff --git a/StarterNG/Infrastructure/Settings/SettingsSerializer.cs b/StarterNG/Infrastructure/Settings/SettingsSerializer.cs index 3ad6ccd..de02a80 100644 --- a/StarterNG/Infrastructure/Settings/SettingsSerializer.cs +++ b/StarterNG/Infrastructure/Settings/SettingsSerializer.cs @@ -8,26 +8,11 @@ using StarterNG.Domain.Settings; namespace StarterNG.Infrastructure.Settings; -/// -/// Maps onto the simulator's eu07.ini and back. -/// -/// -/// Every key the starter understands is named exactly once, here. Reads clamp -/// and default so a hand-edited ini cannot put the UI into an impossible state, -/// and writes preserve the keys the starter does not manage - which is why a -/// round trip through this class is worth testing on its own. -/// public sealed class SettingsSerializer { public void Read(SimulatorSettings s, ConfigFile c) { - s.LanguageWasSet = c.Has("lang"); - // Kept as the code the file holds. Startup hands it to the localisation - // service, which resolves it to a display name and writes that back; the - // starter must not decide here that an unrecognised code means English, - // because the same key is what tells the simulator which language to run - // in. s.LanguageCode = c.GetString("lang", ""); s.Language = s.LanguageCode; s.Fullscreen = c.GetBool("fullscreen", false); @@ -167,11 +152,9 @@ public sealed class SettingsSerializer public void Write(SimulatorSettings s, ConfigFile c) { - foreach (string key in ObsoleteKeys) c.Remove(key); - // Lower case, as the simulator expects and as the old starter wrote it. c.Set("lang", string.IsNullOrWhiteSpace(s.LanguageCode) ? "en" : s.LanguageCode.Trim().ToLowerInvariant()); diff --git a/StarterNG/Infrastructure/Shortcuts.cs b/StarterNG/Infrastructure/Shortcuts.cs index 03cabaf..2791347 100644 --- a/StarterNG/Infrastructure/Shortcuts.cs +++ b/StarterNG/Infrastructure/Shortcuts.cs @@ -7,21 +7,13 @@ namespace StarterNG.Infrastructure; public enum ShortcutScope { - /// Works anywhere in the window. Global, - /// Only while the depot page is on screen. Depot, - /// Handled by the consist strip itself, once a vehicle card has focus. Consist } -/// -/// One row of the shortcut table. is -/// for rows that only document a gesture handled elsewhere (the consist strip reads the -/// arrow keys itself, they are never dispatched from the window). -/// public sealed record Shortcut( string Id, string Display, @@ -36,12 +28,6 @@ public sealed record Shortcut( IsDispatched && Key == key && Modifiers == modifiers; } -/// -/// The single source of truth for the starter's own shortcuts: the window dispatches from -/// this table and the cheat sheet is printed from it, so the two cannot drift apart. These -/// are deliberately hardcoded - the configurable key list in Settings belongs to the -/// simulator's cab controls and mixing the two only confuses people. -/// public static class Shortcuts { public const string Start = "start"; diff --git a/StarterNG/Infrastructure/TextMatch.cs b/StarterNG/Infrastructure/TextMatch.cs index e851791..ffb0651 100644 --- a/StarterNG/Infrastructure/TextMatch.cs +++ b/StarterNG/Infrastructure/TextMatch.cs @@ -4,10 +4,6 @@ using System.Text; namespace StarterNG.Infrastructure; -/// -/// Case- and diacritic-insensitive substring matching, so that typing -/// "rozdzielczosc" in a search box still finds "Rozdzielczość". -/// public static class TextMatch { public static bool Contains(string? haystack, string? needle) @@ -20,10 +16,6 @@ public static class TextMatch return Fold(haystack).Contains(Fold(needle), StringComparison.Ordinal); } - /// - /// Lower-cases and strips combining marks, so "Ż" and "z" compare equal. - /// Polish "ł" has no decomposed form, so it is mapped by hand. - /// public static string Fold(string text) { if (string.IsNullOrEmpty(text)) diff --git a/StarterNG/Infrastructure/Vehicles/FizPhysicsRepository.cs b/StarterNG/Infrastructure/Vehicles/FizPhysicsRepository.cs index b530a59..52f52eb 100644 --- a/StarterNG/Infrastructure/Vehicles/FizPhysicsRepository.cs +++ b/StarterNG/Infrastructure/Vehicles/FizPhysicsRepository.cs @@ -11,24 +11,10 @@ using StarterNG.Infrastructure.Adapters; namespace StarterNG.Infrastructure.Vehicles; -/// -/// Reads vehicle physics from the .fiz files under dynamic/. -/// -/// -/// The format is a flat token stream of "section" headings and "key value" -/// pairs, with an include file p1 p2 end directive whose parameters are -/// substituted for (1)-style placeholders in the included file. Only the -/// handful of keys the starter shows are decoded; everything else is skipped. -/// -/// Both the name index and the parsed results are cached, because the depot asks -/// for the same model repeatedly while the user scrolls. -/// public sealed class FizPhysicsRepository : IPhysicsRepository { - /// Guard against an include cycle in hand written files. private const int MaxIncludeDepth = 6; - /// Sentinel meaning "the rear coupler was never declared". private const int UndeclaredCoupler = -1; private static readonly HashSet KnownKeys = new(StringComparer.OrdinalIgnoreCase) @@ -80,7 +66,6 @@ public sealed class FizPhysicsRepository : IPhysicsRepository { var index = Index(); - // Unpowered variants are shipped as "dumb.fiz". if (!index.TryGetValue(name, out string? path) && !index.TryGetValue(name + "dumb", out path)) return null; @@ -95,7 +80,6 @@ public sealed class FizPhysicsRepository : IPhysicsRepository _log.Log($"physics/{Path.GetFileName(path)}", ex); } - // A vehicle that only declares one coupler has the same at both ends. if (physics.AllowedFlagB == UndeclaredCoupler) { physics.AllowedFlagB = physics.AllowedFlagA; @@ -189,7 +173,6 @@ public sealed class FizPhysicsRepository : IPhysicsRepository } else { - // Anything else at this level opens a section, e.g. "Param:" or "BuffCoupl1:". section = new string(bare.Where(char.IsLetterOrDigit).ToArray()).ToLowerInvariant(); } } @@ -228,10 +211,6 @@ public sealed class FizPhysicsRepository : IPhysicsRepository private static bool Is(string key, string name) => key.Equals(name, StringComparison.OrdinalIgnoreCase); - /// - /// A negative flag means the coupling is present but disabled; the simulator - /// encodes that as its absolute value plus 128. - /// private static int ParseFlag(string value, int fallback) => int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int flag) ? flag < 0 ? -flag + 128 : flag @@ -242,7 +221,6 @@ public sealed class FizPhysicsRepository : IPhysicsRepository ? parsed : fallback; - /// Substitutes an include's "(n)" placeholder with its n-th parameter. private static string Resolve(string token, string[]? parameters) { if (parameters is null || token.Length < 3 || token[0] != '(' || token[^1] != ')') @@ -270,5 +248,4 @@ public sealed class FizPhysicsRepository : IPhysicsRepository .Split(new[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) .ToList(); } - } diff --git a/StarterNG/Infrastructure/Vehicles/LoadWeightsRepository.cs b/StarterNG/Infrastructure/Vehicles/LoadWeightsRepository.cs index 8639771..53a4f1f 100644 --- a/StarterNG/Infrastructure/Vehicles/LoadWeightsRepository.cs +++ b/StarterNG/Infrastructure/Vehicles/LoadWeightsRepository.cs @@ -9,14 +9,6 @@ using StarterNG.Infrastructure.Adapters; namespace StarterNG.Infrastructure.Vehicles; -/// -/// Reads data/load_weights.txt into a . -/// -/// -/// The file is a brace-delimited list of "name : weight" pairs with '#', ';' and -/// '//' comments. It is read once and kept, since it does not change while the -/// starter runs. -/// public sealed class LoadWeightsRepository { private const string FileName = "load_weights.txt"; @@ -79,8 +71,6 @@ public sealed class LoadWeightsRepository body.Append(line).Append(' '); } - // Colons may be written tight against their neighbours, so space them out - // before tokenising. string[] tokens = body.Replace(":", " : ").ToString() .Split(new[] { ' ', '\t', '\r' }, StringSplitOptions.RemoveEmptyEntries); @@ -100,5 +90,4 @@ public sealed class LoadWeightsRepository return weights; } - } diff --git a/StarterNG/Infrastructure/Vehicles/MiniTextureIndex.cs b/StarterNG/Infrastructure/Vehicles/MiniTextureIndex.cs index 8871522..c42293c 100644 --- a/StarterNG/Infrastructure/Vehicles/MiniTextureIndex.cs +++ b/StarterNG/Infrastructure/Vehicles/MiniTextureIndex.cs @@ -5,17 +5,8 @@ using StarterNG.Application.Abstractions; namespace StarterNG.Infrastructure.Vehicles; -/// -/// over the installation's textures/mini folder. -/// -/// -/// Replaces the static thumbnail dictionary that used to live on the vehicle -/// database: an installation-scoped lookup with its own lifetime, which is what -/// lets a test point the depot at thumbnails that only exist in memory. -/// public sealed class MiniTextureIndex : IMiniTextureIndex { - /// Thumbnail shown when a vehicle names one we do not have. private const string FallbackName = "other"; private readonly IFileSystem _files; diff --git a/StarterNG/Infrastructure/Vehicles/MissingAssetScanner.cs b/StarterNG/Infrastructure/Vehicles/MissingAssetScanner.cs index d44bdc1..d303e69 100644 --- a/StarterNG/Infrastructure/Vehicles/MissingAssetScanner.cs +++ b/StarterNG/Infrastructure/Vehicles/MissingAssetScanner.cs @@ -5,14 +5,6 @@ using StarterNG.Domain.Vehicles; namespace StarterNG.Infrastructure.Vehicles; -/// -/// Reports liveries whose skin or model file is not actually present, for the -/// optional "log missing vehicle files" diagnostic. -/// -/// -/// Both assets are looked up under several extensions because the simulator -/// accepts a texture as .mat or .bmp and a model as .t3d or .e3d. -/// public sealed class MissingAssetScanner { private static readonly string[] TextureExtensions = { ".mat", ".bmp" }; diff --git a/StarterNG/Infrastructure/Vehicles/TexturesTxtParser.cs b/StarterNG/Infrastructure/Vehicles/TexturesTxtParser.cs index d3e0591..c99a88e 100644 --- a/StarterNG/Infrastructure/Vehicles/TexturesTxtParser.cs +++ b/StarterNG/Infrastructure/Vehicles/TexturesTxtParser.cs @@ -4,30 +4,10 @@ using StarterNG.Domain.Vehicles; namespace StarterNG.Infrastructure.Vehicles; -/// -/// Reads one vehicle folder's textures.txt into a . -/// -/// -/// The format is line oriented and stateful: '$a' marks the rest of the file as -/// archived, '!=' sets the category letter, and '^n' opens a fixed set of n -/// vehicles. Everything else with an '=' is a livery. Unknown lines are skipped -/// rather than rejected, because the files are hand written. -/// -/// Pure text in, model out: the repository does the reading, so the format can -/// be tested from a string array. -/// public sealed class TexturesTxtParser { - /// Category letter meaning "derive it from the thumbnail name". private const string DeriveCategory = "*"; - /// - /// Parses the file's lines. Returns null when the folder declares no liveries. - /// - /// - /// The folder path relative to dynamic/, with a trailing slash; it forms the - /// livery ids and is what the scenery format writes as the data folder. - /// public VehicleEntry? Parse(string directory, IReadOnlyList lines) { var entry = new VehicleEntry { Uuid = "legacy:" + directory }; @@ -120,8 +100,6 @@ public sealed class TexturesTxtParser if (skin.Length == 0) return null; - // Every "=" segment is "model, thumbnail[, per-texture thumbnail]"; the - // first is the livery proper and the rest are alternative models. var specs = new List<(string Model, string Mini, string TextureMini)>(); for (int i = 1; i < parts.Length; i++) { @@ -170,10 +148,6 @@ public sealed class TexturesTxtParser return texture; } - /// - /// The trailing comment is a fixed, comma separated credit line. Underscores - /// stand in for spaces, a convention from the era the format comes from. - /// private static VehicleMeta? ParseDescription(string description) { if (string.IsNullOrWhiteSpace(description)) diff --git a/StarterNG/Infrastructure/Vehicles/TexturesTxtVehicleRepository.cs b/StarterNG/Infrastructure/Vehicles/TexturesTxtVehicleRepository.cs index d2f709c..4a9a30d 100644 --- a/StarterNG/Infrastructure/Vehicles/TexturesTxtVehicleRepository.cs +++ b/StarterNG/Infrastructure/Vehicles/TexturesTxtVehicleRepository.cs @@ -8,10 +8,6 @@ using StarterNG.Infrastructure.Adapters; namespace StarterNG.Infrastructure.Vehicles; -/// -/// Loads the catalogue from the dynamic/<maker>/<vehicle>/textures.txt -/// files an installation ships. -/// public sealed class TexturesTxtVehicleRepository : IVehicleRepository { private const string TexturesFileName = "textures.txt"; @@ -55,8 +51,6 @@ public sealed class TexturesTxtVehicleRepository : IVehicleRepository { try { - // Read as text so the code page survives: the credit lines carry - // Polish characters that ReadAllLines' default encoding would mangle. string[] lines = _files.ReadAllText(path, _encoding).Split('\n'); return _parser.Parse(RelativeDirectory(path), lines); } @@ -67,10 +61,6 @@ public sealed class TexturesTxtVehicleRepository : IVehicleRepository } } - /// - /// Rolling stock sits exactly two levels below dynamic/: a maker folder and a - /// vehicle folder. - /// private IEnumerable TexturesFiles() { foreach (string maker in _files.GetDirectories(_paths.Dynamic)) @@ -82,10 +72,6 @@ public sealed class TexturesTxtVehicleRepository : IVehicleRepository } } - /// - /// The folder as the scenery format spells it: relative to dynamic/, forward - /// slashes, trailing slash. - /// private string RelativeDirectory(string texturesPath) { string directory = Path.GetDirectoryName(texturesPath) ?? ""; @@ -98,5 +84,4 @@ public sealed class TexturesTxtVehicleRepository : IVehicleRepository return relative.Replace('\\', '/').TrimEnd('/') + "/"; } - } diff --git a/StarterNG/Presentation/Scenarios/FogScale.cs b/StarterNG/Presentation/Scenarios/FogScale.cs index b95c82c..0b76c13 100644 --- a/StarterNG/Presentation/Scenarios/FogScale.cs +++ b/StarterNG/Presentation/Scenarios/FogScale.cs @@ -4,19 +4,8 @@ using StarterNG.Domain.Sceneries; namespace StarterNG.Presentation.Scenarios; -/// -/// Converts between the weather tab's fog slider and a distance in metres. -/// -/// -/// Visibility runs from 10 m to 10 km, a range no linear slider handles well: -/// the interesting part - thick fog, where a few metres matter - would be a -/// couple of pixels wide. The slider is therefore logarithmic over its 0-1000 -/// travel, and the result snaps to a step that grows with the distance, so the -/// read-out lands on round numbers a driver would recognise. -/// public static class FogScale { - /// Travel of the slider the scale is spread over. public const double SliderRange = 1000.0; public static int ToMetres(double sliderPosition) @@ -37,7 +26,6 @@ public static class FogScale Math.Log((double)SceneryWeather.FogMax / SceneryWeather.FogMin); } - /// Metres below a kilometre, kilometres above it. public static string Format(int metres, CultureInfo culture) => metres < 1000 ? $"{metres} m" diff --git a/StarterNG/Presentation/Scenarios/SceneryTree.cs b/StarterNG/Presentation/Scenarios/SceneryTree.cs index 12569c7..507809a 100644 --- a/StarterNG/Presentation/Scenarios/SceneryTree.cs +++ b/StarterNG/Presentation/Scenarios/SceneryTree.cs @@ -6,27 +6,11 @@ using StarterNG.Domain.Sceneries; namespace StarterNG.Presentation.Scenarios; -/// -/// A node of the scenery list: either a scenario, or a group holding scenarios. -/// -/// Text to show. -/// Index into the scenery list, or -1 for a group. -/// Scenarios under a group; empty for a scenario. public sealed record SceneryTreeNode(string Label, int SceneryIndex, IReadOnlyList Children) { public bool IsGroup => SceneryIndex < 0; } -/// -/// Turns the flat scenery list into the tree the scenario picker shows: -/// scenarios that declare a group sit under it, the rest stay at the top, and -/// everything is sorted by name. -/// -/// -/// Pulled out of the view so the grouping and the archival filter can be tested -/// without a TreeView. The view's job is reduced to turning these nodes into -/// controls. -/// public sealed class SceneryTreeBuilder { private readonly ISceneryTranslations _translations; @@ -36,9 +20,6 @@ public sealed class SceneryTreeBuilder _translations = translations; } - /// The list the node indices refer to. - /// Whether scenarios marked archival are listed. - /// Language for resolving each scenery's own translations. public IReadOnlyList Build(IReadOnlyList sceneries, bool includeArchival, string langCode) { @@ -52,8 +33,6 @@ public sealed class SceneryTreeBuilder if (scenery.Archival && !includeArchival) continue; - // The group name may itself be an "@key" reference into the scenery's - // own translation files, so the table has to be loaded per scenery. _translations.LoadFor(scenery, langCode); var node = new SceneryTreeNode(scenery.DisplayName, i, Array.Empty()); diff --git a/StarterNG/Presentation/Scenarios/SeasonDates.cs b/StarterNG/Presentation/Scenarios/SeasonDates.cs index 5a938a4..959d952 100644 --- a/StarterNG/Presentation/Scenarios/SeasonDates.cs +++ b/StarterNG/Presentation/Scenarios/SeasonDates.cs @@ -3,15 +3,6 @@ using StarterNG.Application.Abstractions; namespace StarterNG.Presentation.Scenarios; -/// -/// Translates between the scenery's day-of-year (movelight) and the date the -/// weather tab shows. -/// -/// -/// Day 0 is the scenery saying "whatever today is", which the tab presents as -/// the current date; the season presets are ordinary days of the year. Leap -/// years are honoured so 366 stays selectable in one. -/// public sealed class SeasonDates { private readonly IClock _clock; @@ -21,13 +12,8 @@ public sealed class SeasonDates _clock = clock; } - /// The day-of-year a scenery means by 0: today. public int Today => _clock.Now.DayOfYear; - /// - /// The date to show for a stored day-of-year, in the current year. Day 0 and - /// out-of-range values fall back to today, clamped to the year's length. - /// public DateTimeOffset DateOf(int dayOfYear) { int year = _clock.Now.Year; diff --git a/StarterNG/Views/ShortcutsWindow.cs b/StarterNG/Views/ShortcutsWindow.cs index 421284f..d7bd5be 100644 --- a/StarterNG/Views/ShortcutsWindow.cs +++ b/StarterNG/Views/ShortcutsWindow.cs @@ -9,10 +9,6 @@ using StarterNG.Infrastructure; namespace StarterNG.Views; -/// -/// The cheat sheet, printed straight from so it can never -/// list a gesture the window does not actually dispatch. -/// public static class ShortcutsWindow { public static Window Create()