diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/Diagnostics/LoggingTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/Diagnostics/LoggingTests.cs index b302273f7..b45826c7c 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Test/Diagnostics/LoggingTests.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/Diagnostics/LoggingTests.cs @@ -24,6 +24,7 @@ using NUnit.Framework; using UnityEngine; using UnityEngine.TestTools; +using VisualPinball.Unity.Simulation; namespace VisualPinball.Unity.Test { @@ -153,6 +154,8 @@ public void ShouldThrottleOncePerKeyBeyondTheKeyLimit() } [TestCase(new[] { "-vpe-log-level=debug" }, "Debug")] + [TestCase(new[] { "--vpe-log-level=debug" }, "Debug")] + [TestCase(new[] { "player.exe", "--vpe-log-level", "warn" }, "Warn")] [TestCase(new[] { "player.exe", "-vpe-log-level", "trace" }, "Trace")] [TestCase(new[] { "-VPE-LOG-LEVEL=Warning" }, "Warn")] [TestCase(new[] { "-vpe-log-level" }, null)] @@ -164,6 +167,19 @@ public void ShouldParseTheLevelFromTheCommandLine(string[] args, string expected (VpeLog.ParseCommandLineLevel(args)?.Name).Should().Be(expected); } + [TestCase(new[] { "player.exe", "--simulation-trace" }, true)] + [TestCase(new[] { "player.exe", "-simulation-trace" }, true)] + [TestCase(new[] { "--no-simulation-trace" }, false)] + [TestCase(new[] { "-NO-SIMULATION-TRACE" }, false)] + [TestCase(new[] { "--simulation-trace", "--no-simulation-trace" }, false)] + [TestCase(new[] { "-no-simulation-trace", "-simulation-trace" }, true)] + [TestCase(new[] { "player.exe", "--simulation-tracex", "---simulation-trace" }, null)] + [TestCase(new string[0], null)] + public void ShouldParseTheSimulationTraceSwitch(string[] args, bool? expected) + { + SimulationTrace.ParseCommandLineOverride(args).Should().Be(expected); + } + [Test] public void ShouldKeepTheNewestLinesWithinTheBudget() { diff --git a/VisualPinball.Unity/VisualPinball.Unity/Diagnostics/SystemSpecs.cs b/VisualPinball.Unity/VisualPinball.Unity/Diagnostics/SystemSpecs.cs index 63cdaf645..74e63c772 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Diagnostics/SystemSpecs.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Diagnostics/SystemSpecs.cs @@ -91,7 +91,7 @@ internal static string CommandLine(IReadOnlyList args, bool editor) for (var i = 0; i < args.Count; i++) { var arg = args[i]; var isOption = arg.StartsWith("-"); - if (editor && !(isOption && arg.StartsWith("-vpe", StringComparison.OrdinalIgnoreCase))) { + if (editor && !(isOption && arg.TrimStart('-').StartsWith("vpe", StringComparison.OrdinalIgnoreCase))) { continue; } var equals = arg.IndexOf('='); diff --git a/VisualPinball.Unity/VisualPinball.Unity/Diagnostics/VpeLog.cs b/VisualPinball.Unity/VisualPinball.Unity/Diagnostics/VpeLog.cs index 0ab00378a..d517efd4d 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Diagnostics/VpeLog.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Diagnostics/VpeLog.cs @@ -248,7 +248,7 @@ private static void PublishSessionDiagnostics() /// Folder for session log files. Logging to a file /// starts with this call; lines logged before it are copied from the tail. An /// empty string stops logging to a file. - /// Lowest level to log. The -vpe-log-level command + /// Lowest level to log. The --vpe-log-level command /// line argument overrides it. public static void Configure(string logDirectory = null, LogLevel level = null) { @@ -489,7 +489,7 @@ public static LogLevel ParseLevel(string name) } /// - /// Reads -vpe-log-level=debug or -vpe-log-level debug. + /// Reads --vpe-log-level=debug or --vpe-log-level debug (one dash works too). /// public static LogLevel ParseCommandLineLevel(IReadOnlyList args) { @@ -498,6 +498,10 @@ public static LogLevel ParseCommandLineLevel(IReadOnlyList args) } for (var i = 0; i < args.Count; i++) { var arg = args[i]; + // --name is the documented form, -name still works + if (arg != null && arg.StartsWith("--", StringComparison.Ordinal)) { + arg = arg.Substring(1); + } if (arg == null || !arg.StartsWith(LevelArgument, StringComparison.OrdinalIgnoreCase)) { continue; } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/Engine/GamelogicPaths.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/Engine/GamelogicPaths.cs index 1e23d06f7..74345d458 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/Engine/GamelogicPaths.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/Engine/GamelogicPaths.cs @@ -58,6 +58,23 @@ public static string RomFolderOverride private static string _hostRomFolder; private static string _romFolderOverride; + /// + /// A gamelogic engine couldn't find the ROM the table needs. Raised on the main thread with + /// the ROM's name and the folder(s) that were searched, so the host can ask for the ROM + /// folder. + /// + public static event Action RomMissing; + + /// + /// Called by a gamelogic engine on the main thread when the table's ROM isn't there. + /// + /// Name of the ROM, e.g. t2_l8 + /// The ';'-separated folders it looked in, or null + public static void ReportRomMissing(string rom, string searchedFolders) + { + RomMissing?.Invoke(rom, searchedFolders); + } + /// /// The root of VPE's own data on this machine (%LOCALAPPDATA%\Visual Pinball Engine /// on Windows), shared by all VPE apps. Gamelogic engines keep their data in a sub folder. @@ -90,6 +107,7 @@ public static string NormalizeFolderList(string folders) private static void ResetPlaySession() { _romFolderOverride = null; + RomMissing = null; } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Simulation/SimulationTrace.cs b/VisualPinball.Unity/VisualPinball.Unity/Simulation/SimulationTrace.cs index 3374b68d4..a186e89bf 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Simulation/SimulationTrace.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Simulation/SimulationTrace.cs @@ -5,6 +5,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later using System; +using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; @@ -215,13 +216,23 @@ public void Dispose() private static long _beginUsec; /// - /// Command-line override for player builds: -simulation-trace records, - /// -no-simulation-trace does not. Null when neither is given. + /// Command-line override for player builds: --simulation-trace records, + /// --no-simulation-trace does not (one dash works too). Null when neither is given. /// - public static bool? CommandLineOverride() + public static bool? CommandLineOverride() => ParseCommandLineOverride(Environment.GetCommandLineArgs()); + + /// + /// for given arguments. The last switch wins. + /// + public static bool? ParseCommandLineOverride(IReadOnlyList args) { var result = (bool?)null; - foreach (var arg in Environment.GetCommandLineArgs()) { + if (args == null) { + return null; + } + foreach (var raw in args) { + // --name is the documented form, -name still works + var arg = raw.StartsWith("--", StringComparison.Ordinal) ? raw.Substring(1) : raw; if (string.Equals(arg, "-simulation-trace", StringComparison.OrdinalIgnoreCase)) { result = true; } else if (string.Equals(arg, "-no-simulation-trace", StringComparison.OrdinalIgnoreCase)) {