Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 36 additions & 43 deletions src/port/GameVersion/BaseGameVersion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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<uint32_t>(buf[1]) << 24) | (static_cast<uint32_t>(buf[2]) << 16) |
(static_cast<uint32_t>(buf[3]) << 8) | static_cast<uint32_t>(buf[4]);

const uint32_t crcLE = (static_cast<uint32_t>(buf[4]) << 24) | (static_cast<uint32_t>(buf[3]) << 16) |
(static_cast<uint32_t>(buf[2]) << 8) | static_cast<uint32_t>(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<uint32_t>(buf[1]) << 24) | (static_cast<uint32_t>(buf[2]) << 16) |
(static_cast<uint32_t>(buf[3]) << 8) | static_cast<uint32_t>(buf[4]);
ok = true;
}
zip_fclose(f);
}
Expand All @@ -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() {
Expand All @@ -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<uint32_t>(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<BKVersion>(rawVersion);
return true;
}
const uint32_t swapped = ByteSwap32(rawVersion);
if (IsKnownVersion(swapped)) {
out = static_cast<BKVersion>(swapped);
return true;
}
return false;
}

bool BaseGameSupportsRomhacks() {
Expand Down
3 changes: 3 additions & 0 deletions src/port/GameVersion/BaseGameVersion.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
21 changes: 20 additions & 1 deletion src/port/Localization/Language.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,14 @@ void SetActiveLanguage(const std::string& name) {

std::unordered_map<uint32_t, std::string> 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<uint32_t>(entry->source->GetGameVersion());
BKVersion packVersion = BK_VER_US_10;
const bool classified = ClassifyArchiveVersion(rawVersion, packVersion);

const std::unordered_map<uint32_t, uint32_t>* remap = nullptr;
switch (static_cast<BKVersion>(entry->source->GetGameVersion())) {
switch (packVersion) {
case BK_VER_US_11:
remap = &sV10toV11Remap;
break;
Expand All @@ -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<uint32_t, uint32_t> inverse;
if (remap != nullptr) {
for (const auto& [v10Id, targetId] : *remap) {
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion src/port/Patches/FramePacingPatches.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Loading