From c72979a2d63fa8a5351b2f4b745574d1ce3b3bce Mon Sep 17 00:00:00 2001 From: Jeod <47716344+JeodC@users.noreply.github.com> Date: Sun, 2 Aug 2026 12:18:18 -0400 Subject: [PATCH] Fix language pack redirects not working --- src/port/GameVersion/BaseGameVersion.cpp | 79 +++++++++++------------- src/port/GameVersion/BaseGameVersion.h | 3 + src/port/Localization/Language.cpp | 21 ++++++- src/port/Patches/FramePacingPatches.cpp | 3 +- 4 files changed, 61 insertions(+), 45 deletions(-) diff --git a/src/port/GameVersion/BaseGameVersion.cpp b/src/port/GameVersion/BaseGameVersion.cpp index 52b16fb37..717bbb0fd 100644 --- a/src/port/GameVersion/BaseGameVersion.cpp +++ b/src/port/GameVersion/BaseGameVersion.cpp @@ -12,6 +12,22 @@ namespace Lighthouse { namespace { +bool IsKnownVersion(uint32_t crc) { + switch (crc) { + case BK_VER_US_10: + case BK_VER_US_11: + case BK_VER_PAL: + case BK_VER_JP: + return true; + default: + return false; + } +} + +uint32_t ByteSwap32(uint32_t v) { + return (v >> 24) | ((v >> 8) & 0x0000FF00u) | ((v << 8) & 0x00FF0000u) | (v << 24); +} + bool ReadStampedCrc(const std::string& archivePath, uint32_t& outCrc) { int err = 0; zip_t* z = zip_open(archivePath.c_str(), ZIP_RDONLY, &err); @@ -24,31 +40,9 @@ bool ReadStampedCrc(const std::string& archivePath, uint32_t& outCrc) { if (zip_file_t* f = zip_fopen_index(z, idx, 0)) { uint8_t buf[5] = {}; if (zip_fread(f, buf, sizeof(buf)) == sizeof(buf)) { - const uint32_t crcBE = (static_cast(buf[1]) << 24) | (static_cast(buf[2]) << 16) | - (static_cast(buf[3]) << 8) | static_cast(buf[4]); - - const uint32_t crcLE = (static_cast(buf[4]) << 24) | (static_cast(buf[3]) << 16) | - (static_cast(buf[2]) << 8) | static_cast(buf[1]); - - auto isKnownVersion = [](uint32_t crc) { - switch (crc) { - case BK_VER_US_10: - case BK_VER_US_11: - case BK_VER_PAL: - case BK_VER_JP: - return true; - default: - return false; - } - }; - - if (isKnownVersion(crcBE)) { - outCrc = crcBE; - ok = true; - } else if (isKnownVersion(crcLE)) { - outCrc = crcLE; - ok = true; - } + outCrc = (static_cast(buf[1]) << 24) | (static_cast(buf[2]) << 16) | + (static_cast(buf[3]) << 8) | static_cast(buf[4]); + ok = true; } zip_fclose(f); } @@ -58,21 +52,6 @@ bool ReadStampedCrc(const std::string& archivePath, uint32_t& outCrc) { return ok; } -BKVersion ClassifyCrc(uint32_t crc) { - switch (crc) { - case BK_VER_US_11: - return BK_VER_US_11; - case BK_VER_PAL: - return BK_VER_PAL; - case BK_VER_JP: - return BK_VER_JP; - case BK_VER_US_10: - default: - // Vanilla v1.0, a v1.0-based romhack, or an unknown dump. - return BK_VER_US_10; - } -} - } // namespace BKVersion GetBaseVersion() { @@ -88,13 +67,27 @@ BKVersion GetBaseVersion() { } uint32_t crc = 0; - if (ReadStampedCrc(basePath, crc)) { - sVersion = ClassifyCrc(crc); + BKVersion version = BK_VER_US_10; + if (ReadStampedCrc(basePath, crc) && ClassifyArchiveVersion(crc, version)) { + sVersion = version; sResolved = true; SPDLOG_INFO("[BaseGameVersion] base bk.o2r CRC 0x{:08X} -> BKVersion 0x{:08X}", crc, static_cast(sVersion)); } - return sVersion; + return sVersion; // unstamped or unrecognised: stay on the v1.0 default and retry +} + +bool ClassifyArchiveVersion(uint32_t rawVersion, BKVersion& out) { + if (IsKnownVersion(rawVersion)) { + out = static_cast(rawVersion); + return true; + } + const uint32_t swapped = ByteSwap32(rawVersion); + if (IsKnownVersion(swapped)) { + out = static_cast(swapped); + return true; + } + return false; } bool BaseGameSupportsRomhacks() { diff --git a/src/port/GameVersion/BaseGameVersion.h b/src/port/GameVersion/BaseGameVersion.h index 4d463b806..916293690 100644 --- a/src/port/GameVersion/BaseGameVersion.h +++ b/src/port/GameVersion/BaseGameVersion.h @@ -9,6 +9,9 @@ namespace Lighthouse { // The ROM CRC that Torch inserts into the o2r version file BKVersion GetBaseVersion(); +// Classify a version stamp taken from an archive +bool ClassifyArchiveVersion(uint32_t rawVersion, BKVersion& out); + // Romhacks are generally only supported by US 1.0 bool BaseGameSupportsRomhacks(); diff --git a/src/port/Localization/Language.cpp b/src/port/Localization/Language.cpp index 78bfea80c..c066c854f 100644 --- a/src/port/Localization/Language.cpp +++ b/src/port/Localization/Language.cpp @@ -221,8 +221,14 @@ void SetActiveLanguage(const std::string& name) { std::unordered_map dialogOverride; if (entry->source != nullptr) { + // The pack's assets are numbered for the ROM it was extracted from, so they have + // to be translated into the base's v1.0 id space before they can override anything. + const uint32_t rawVersion = static_cast(entry->source->GetGameVersion()); + BKVersion packVersion = BK_VER_US_10; + const bool classified = ClassifyArchiveVersion(rawVersion, packVersion); + const std::unordered_map* remap = nullptr; - switch (static_cast(entry->source->GetGameVersion())) { + switch (packVersion) { case BK_VER_US_11: remap = &sV10toV11Remap; break; @@ -232,9 +238,20 @@ void SetActiveLanguage(const std::string& name) { case BK_VER_JP: remap = &sV10toJPRemap; break; + case BK_VER_US_10: default: break; // pack ids already match v1.0 } + + // Without a recognised stamp there is no way to know which id space the pack is in. + // Installing its assets under their own ids would drop them onto whatever v1.0 asset + // happens to share the number, so leave the language alone instead. + if (!classified) { + SPDLOG_ERROR("[Lang] '{}': pack version stamp {:#010x} matches no known ROM; refusing to apply it " + "(its asset ids cannot be translated to the base game's).", + name, rawVersion); + return; + } std::unordered_map inverse; if (remap != nullptr) { for (const auto& [v10Id, targetId] : *remap) { @@ -263,6 +280,8 @@ void SetActiveLanguage(const std::string& name) { } else if (auto it = inverse.find(packId); it != inverse.end()) { v10Id = it->second; } else { + // Nothing to translate: the asset has no v1.0 counterpart (the JP-only + // font and friends, which the port asks for by their pack id). v10Id = packId; } dialogOverride[v10Id] = path; diff --git a/src/port/Patches/FramePacingPatches.cpp b/src/port/Patches/FramePacingPatches.cpp index 5ff05d6ee..db0b55c3c 100644 --- a/src/port/Patches/FramePacingPatches.cpp +++ b/src/port/Patches/FramePacingPatches.cpp @@ -20,13 +20,14 @@ enum map_e gsworld_getMap(void); // Demo Display Pacing static int sDemoViCount = 0; +static constexpr int kMaxDemoViCount = 0xF; int port_getDemoViCount(void) { return sDemoViCount; } void port_setDemoViCount(int viCount) { - sDemoViCount = viCount; + sDemoViCount = (viCount > kMaxDemoViCount) ? kMaxDemoViCount : viCount; } int port_getDemoDisplayViCount(int rawViCount) {