diff --git a/src/port/Localization/Language.cpp b/src/port/Localization/Language.cpp index 85c2a3ef6..922b71b6a 100644 --- a/src/port/Localization/Language.cpp +++ b/src/port/Localization/Language.cpp @@ -155,8 +155,8 @@ bool EntryStamp(zip_t* z, const std::string& entryPath, uint32_t& outCrc, uint64 return true; } -size_t DropUnchangedOverrides(const std::string& packArchivePath, - std::unordered_map& overrides) { +size_t DropUnchangedOverrides(const std::string& packArchivePath, std::unordered_map& overrides, + const std::unordered_map>& packFamilies) { const std::string basePath = BaseArchivePath(); if (basePath.empty() || packArchivePath.empty()) { return 0; @@ -177,11 +177,31 @@ size_t DropUnchangedOverrides(const std::string& packArchivePath, ++it; continue; } - uint32_t packCrc = 0, baseCrc = 0; - uint64_t packSize = 0, baseSize = 0; const std::string baseEntry = ResourceHelpers_GetBaseAssetPath(it->first); - if (baseEntry.empty() || !EntryStamp(packZip, it->second, packCrc, packSize) || - !EntryStamp(baseZip, baseEntry, baseCrc, baseSize) || packCrc != baseCrc || packSize != baseSize) { + if (baseEntry.empty()) { + ++it; + continue; + } + + bool unchanged = true; + auto family = packFamilies.find(it->first); + const std::vector single = { it->second }; + const std::vector& entries = family != packFamilies.end() ? family->second : single; + for (const std::string& packEntry : entries) { + if (packEntry.rfind(it->second, 0) != 0) { + unchanged = false; + break; + } + const std::string baseSibling = baseEntry + packEntry.substr(it->second.size()); + uint32_t packCrc = 0, baseCrc = 0; + uint64_t packSize = 0, baseSize = 0; + if (!EntryStamp(packZip, packEntry, packCrc, packSize) || + !EntryStamp(baseZip, baseSibling, baseCrc, baseSize) || packCrc != baseCrc || packSize != baseSize) { + unchanged = false; + break; + } + } + if (!unchanged) { ++it; continue; } @@ -316,12 +336,14 @@ void SetActiveLanguage(const std::string& name) { } std::unordered_map packMain; + std::unordered_map> packFamilies; if (auto files = entry->source->ListFiles()) { for (const auto& [hash, path] : *files) { uint32_t id = 0; if (!AssetHexFromPath(path, id)) { continue; } + packFamilies[id].push_back(path); auto it = packMain.find(id); if (it == packMain.end() || path.size() < it->second.size()) { packMain[id] = path; @@ -343,7 +365,8 @@ void SetActiveLanguage(const std::string& name) { dialogOverride[v10Id] = path; } - if (const size_t dropped = DropUnchangedOverrides(entry->source->GetPath(), dialogOverride); dropped > 0) { + if (const size_t dropped = DropUnchangedOverrides(entry->source->GetPath(), dialogOverride, packFamilies); + dropped > 0) { SPDLOG_INFO("[Lang] '{}': {} pack asset(s) are identical to the base game and were left un-repointed", name, dropped); } diff --git a/src/port/Resource/Alt/AltSprites.cpp b/src/port/Resource/Alt/AltSprites.cpp index 2206418f1..f3ca1737c 100644 --- a/src/port/Resource/Alt/AltSprites.cpp +++ b/src/port/Resource/Alt/AltSprites.cpp @@ -59,6 +59,22 @@ const char* resolveColorVariant(const char* base, int variant) { return result; } +std::unordered_map sAltPresentCache; + +bool altFilePresent(const char* path) { + auto it = sAltPresentCache.find(path); + if (it != sAltPresentCache.end()) { + return it->second; + } + bool present = false; + if (std::string(path).rfind("__OTR__", 0) == 0) { + present = Ship::Context::GetRawInstance()->GetResourceManager()->GetArchiveManager()->HasFile( + "alt/" + std::string(path + 7)); + } + sAltPresentCache.emplace(path, present); + return present; +} + const char* resolvePath(const void* chunkAddr) { const int variant = sColorVariant; sColorVariant = -1; @@ -80,7 +96,7 @@ const char* resolvePath(const void* chunkAddr) { return colored; } } - return it->second; + return altFilePresent(it->second) ? it->second : nullptr; } } // namespace