diff --git a/tools/asset_extract/path_mapper.cpp b/tools/asset_extract/path_mapper.cpp index e4e1c8c4..d9a0c3af 100644 --- a/tools/asset_extract/path_mapper.cpp +++ b/tools/asset_extract/path_mapper.cpp @@ -35,7 +35,12 @@ std::string PathMapper::extractAfterPrefix(const std::string& path, size_t prefi } std::string PathMapper::mapPath(const std::string& wowPath) { - // Preserve original casing in the remainder for filesystem readability + // Lowercase entire output path — WoW archives contain mixed-case variants + // of the same path which create duplicate directories on case-sensitive filesystems. + return toLower(mapPathImpl(wowPath)); +} + +std::string PathMapper::mapPathImpl(const std::string& wowPath) { std::string rest; // DBFilesClient\ → db/ @@ -63,21 +68,16 @@ std::string PathMapper::mapPath(const std::string& wowPath) { return "creature/" + fwd; } - // Item\ObjectComponents\{Type}\ → item/{type}/ + // Item\ObjectComponents\ → item/objectcomponents/ if (startsWithCI(wowPath, "Item\\ObjectComponents\\")) { rest = extractAfterPrefix(wowPath, 22); - std::string fwd = toForwardSlash(rest); - auto slash = fwd.find('/'); - if (slash != std::string::npos) { - return "item/" + toLower(fwd.substr(0, slash)) + "/" + fwd.substr(slash + 1); - } - return "item/" + fwd; + return "item/objectcomponents/" + toForwardSlash(rest); } - // Item\TextureComponents\ → item/texture/ + // Item\TextureComponents\ → item/texturecomponents/ if (startsWithCI(wowPath, "Item\\TextureComponents\\")) { rest = extractAfterPrefix(wowPath, 23); - return "item/texture/" + toForwardSlash(rest); + return "item/texturecomponents/" + toForwardSlash(rest); } // Interface\Icons\ → interface/icons/ diff --git a/tools/asset_extract/path_mapper.hpp b/tools/asset_extract/path_mapper.hpp index cad31c57..7369b000 100644 --- a/tools/asset_extract/path_mapper.hpp +++ b/tools/asset_extract/path_mapper.hpp @@ -16,11 +16,12 @@ public: /** * Map a WoW virtual path to a reorganized filesystem path. * @param wowPath Original WoW virtual path (backslash-separated) - * @return Reorganized relative path (forward-slash separated, original casing preserved) + * @return Reorganized relative path (forward-slash separated, fully lowercased) */ static std::string mapPath(const std::string& wowPath); private: + static std::string mapPathImpl(const std::string& wowPath); // Helpers for prefix matching (case-insensitive) static bool startsWithCI(const std::string& str, const std::string& prefix); static std::string toLower(const std::string& str);