diff --git a/Launcher/Build-Installer.ps1 b/Launcher/Build-Installer.ps1 index 03009a3..428eda8 100644 --- a/Launcher/Build-Installer.ps1 +++ b/Launcher/Build-Installer.ps1 @@ -253,7 +253,7 @@ foreach ($required in @('ToolkitFingerprint','TranslationFingerprint','NativeToo $manifest = [ordered]@{ SchemaVersion = 2 - ProductVersion = '0.2.22' + ProductVersion = '0.2.23' ExpectedGameId = $pins.GameId ExpectedDolSha256 = $pins.DolSha256 ExpectedRelSha256 = $pins.RelSha256 diff --git a/Launcher/WiiCompiled.Setup/Program.cs b/Launcher/WiiCompiled.Setup/Program.cs index c47eb82..d7c1249 100644 --- a/Launcher/WiiCompiled.Setup/Program.cs +++ b/Launcher/WiiCompiled.Setup/Program.cs @@ -121,7 +121,7 @@ internal static class PlatformChecks internal static class ProductInfo { public const string Name = "WiiCompiled"; - public const string Version = "0.2.22"; + public const string Version = "0.2.23"; /// /// The setup executable is copied into the installation under this name. It is the launcher and diff --git a/Launcher/WiiCompiled.Setup/WiiCompiled.Setup.csproj b/Launcher/WiiCompiled.Setup/WiiCompiled.Setup.csproj index a7456de..326a27c 100644 --- a/Launcher/WiiCompiled.Setup/WiiCompiled.Setup.csproj +++ b/Launcher/WiiCompiled.Setup/WiiCompiled.Setup.csproj @@ -7,7 +7,7 @@ WiiCompiled.Setup WiiCompiled.Setup app.manifest - 0.2.22 + 0.2.23 patchzy WiiCompiled Command-line installer and launcher for WiiCompiled diff --git a/runtime/src/hle/os/os_report.cpp b/runtime/src/hle/os/os_report.cpp index 78facb4..cb8e6cf 100644 --- a/runtime/src/hle/os/os_report.cpp +++ b/runtime/src/hle/os/os_report.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -103,17 +104,26 @@ static void HLE_LogOSReport(CpuContext* cpu, const char* fmt) [&state]() { return NextOsReportDouble(state); }, [](uint32_t address) { return ReadGuestStringForReport(address); }); + // nw4r warnings arrive as ": Warning:" plus a bare newline, so + // consecutive identical messages never land back to back. Blank lines are + // transparent to the repeat tracker so the pair still collapses. static thread_local std::string lastBuffer; static thread_local size_t repeated = 0; - if (buffer == lastBuffer) { + const bool blank = buffer.find_first_not_of(" \t\r\n") == std::string::npos; + if (blank) { + if (repeated != 0) { + return; + } + } else if (buffer == lastBuffer) { ++repeated; return; + } else { + if (repeated != 0) { + std::cout << "[OSReport] previous message repeated " << repeated << " time(s)" << std::endl; + repeated = 0; + } + lastBuffer = buffer; } - if (repeated != 0) { - std::cout << "[OSReport] previous message repeated " << repeated << " time(s)" << std::endl; - repeated = 0; - } - lastBuffer = buffer; std::cout << "[OSReport] " << buffer; @@ -128,9 +138,23 @@ static void HLE_LogOSReport(CpuContext* cpu, const char* fmt) // the guest caller because OS__Report is an HLE boundary. The context is // synchronized at this boundary, so capture the guest backchain at the // first warning/panic instead of attributing the later PPCHalt unwind. + // + // The dump is expensive and stdio is an unbuffered pipe, so a guest that + // warns every frame would stall the game thread on backpressure. One dump + // per distinct site, with an overall cap. if (buffer.find(" Warning:") != std::string::npos || buffer.find(" Panic:") != std::string::npos) { - SystemBridge::DumpCpuState(cpu); + constexpr size_t kMaxWarningDumps = 8; + static thread_local std::set dumpedSites; + static thread_local size_t dumpsEmitted = 0; + if (dumpsEmitted < kMaxWarningDumps && dumpedSites.insert(buffer).second) { + ++dumpsEmitted; + SystemBridge::DumpCpuState(cpu); + if (dumpsEmitted == kMaxWarningDumps) { + std::cerr << "[runtime] guest warning context dumps capped at " << kMaxWarningDumps + << "; further warnings log the message only." << std::endl; + } + } } }