// SPDX-License-Identifier: GPL-3.0-or-later // FileDataID resolver for selected retail assets shipped in MoonWell patches. #include "Host.hpp" #include "core/Logger.hpp" #include "mpq/MpqStore.hpp" #include #include #include #include #include #include #include #include namespace moonwell::host { namespace { constexpr std::string_view kFileDataMap = "WXLFileData.csv"; std::once_flag g_loadOnce; std::unordered_map g_paths; std::string_view Trim(std::string_view value) { while (!value.empty() && (value.front() == ' ' || value.front() == '\t' || value.front() == '\r' || value.front() == '\n')) value.remove_prefix(1); while (!value.empty() && (value.back() == ' ' || value.back() == '\t' || value.back() == '\r' || value.back() == '\n')) value.remove_suffix(1); return value; } void Load() { const std::string root = wxl::host::ClientRoot(); wxl::host::mpq::MpqStore store; std::vector bytes; if (root.empty() || !store.Mount(root) || !store.ReadAll(kFileDataMap, bytes)) { WLOG_WARN("moonwell: FileDataID map '%.*s' was not found", int(kFileDataMap.size()), kFileDataMap.data()); return; } const std::string_view text(reinterpret_cast(bytes.data()), bytes.size()); size_t lineStart = 0; while (lineStart < text.size()) { size_t lineEnd = text.find('\n', lineStart); if (lineEnd == std::string_view::npos) lineEnd = text.size(); std::string_view line = Trim(text.substr(lineStart, lineEnd - lineStart)); lineStart = lineEnd + 1; if (line.empty() || line.front() == '#') continue; const size_t comma = line.find(','); if (comma == std::string_view::npos) continue; const std::string_view idText = Trim(line.substr(0, comma)); std::string_view pathText = Trim(line.substr(comma + 1)); uint32_t fileDataId = 0; const auto parsed = std::from_chars(idText.data(), idText.data() + idText.size(), fileDataId); if (parsed.ec != std::errc{} || parsed.ptr != idText.data() + idText.size() || fileDataId == 0 || pathText.empty()) continue; std::string path(pathText); for (char& c : path) if (c == '/') c = '\\'; g_paths[fileDataId] = std::move(path); } WLOG_INFO("moonwell: loaded %zu FileDataID path(s) from %.*s", g_paths.size(), int(kFileDataMap.size()), kFileDataMap.data()); } bool Resolve(uint32_t fileDataId, std::string& outPath) { std::call_once(g_loadOnce, &Load); const auto found = g_paths.find(fileDataId); if (found == g_paths.end()) return false; outPath = found->second; return true; } struct Registrar { Registrar() { wxl::host::RegisterResolver("moonwell-filedata", &Resolve); } }; Registrar g_registrar; } }