Add retail catslime model support

This commit is contained in:
2026-07-23 00:19:46 +04:00
parent 01f476ca1b
commit 8375b95f7b
20 changed files with 116 additions and 0 deletions
+3
View File
@@ -41,6 +41,8 @@ if(TARGET WarcraftXL)
endif()
if(TARGET WarcraftXLHost)
wxl_collect_sources(WXL_MOONWELL_HOST
"${CMAKE_CURRENT_SOURCE_DIR}/modules/moonwell/host/*.cpp")
wxl_collect_sources(WXL_MODERN_ASSETS_HOST
"${WXL_EXTERNAL_MODULES_DIR}/wxl-modern-assets/host/*.cpp"
"${WXL_EXTERNAL_MODULES_DIR}/wxl-modern-assets/shared/*.cpp")
@@ -53,6 +55,7 @@ if(TARGET WarcraftXLHost)
"${WXL_EXTERNAL_MODULES_DIR}/wxl-modern-adt/shared/*.cpp")
target_sources(WarcraftXLHost PRIVATE
${WXL_MOONWELL_HOST}
${WXL_MODERN_ASSETS_HOST}
${WXL_MODERN_ADT_HOST})
endif()
@@ -0,0 +1,95 @@
// 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 <charconv>
#include <cstdint>
#include <mutex>
#include <string>
#include <string_view>
#include <system_error>
#include <unordered_map>
#include <vector>
namespace moonwell::host
{
namespace
{
constexpr std::string_view kFileDataMap = "WXLFileData.csv";
std::once_flag g_loadOnce;
std::unordered_map<uint32_t, std::string> 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<uint8_t> 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<const char*>(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;
}
}
Binary file not shown.
Binary file not shown.
+18
View File
@@ -0,0 +1,18 @@
# FileDataID,archive path
3730958,Creature/Catslime/catslime.m2
3732460,Creature/Catslime/catslime_3732460.blp
3732461,Creature/Catslime/catslime_3732461.blp
3732462,Creature/Catslime/catslime0097-00.anim
3732463,Creature/Catslime/catslime0096-00.anim
3732464,Creature/Catslime/catslime0098-00.anim
3732465,Creature/Catslime/catslime0100-00.anim
3732466,Creature/Catslime/catslime0099-00.anim
3732467,Creature/Catslime/catslime0101-00.anim
3732468,Creature/Catslime/catslime0069-00.anim
3732469,Creature/Catslime/catslime0123-00.anim
3732470,Creature/Catslime/catslime0061-00.anim
3732471,Creature/Catslime/catslime0075-00.anim
3732472,Creature/Catslime/catslime00.skin
3732473,Creature/Catslime/catslime_lod01.skin
3732474,Creature/Catslime/catslime_lod02.skin
3732475,Creature/Catslime/catslime_lod03.skin
1 # FileDataID archive path
2 3730958 Creature/Catslime/catslime.m2
3 3732460 Creature/Catslime/catslime_3732460.blp
4 3732461 Creature/Catslime/catslime_3732461.blp
5 3732462 Creature/Catslime/catslime0097-00.anim
6 3732463 Creature/Catslime/catslime0096-00.anim
7 3732464 Creature/Catslime/catslime0098-00.anim
8 3732465 Creature/Catslime/catslime0100-00.anim
9 3732466 Creature/Catslime/catslime0099-00.anim
10 3732467 Creature/Catslime/catslime0101-00.anim
11 3732468 Creature/Catslime/catslime0069-00.anim
12 3732469 Creature/Catslime/catslime0123-00.anim
13 3732470 Creature/Catslime/catslime0061-00.anim
14 3732471 Creature/Catslime/catslime0075-00.anim
15 3732472 Creature/Catslime/catslime00.skin
16 3732473 Creature/Catslime/catslime_lod01.skin
17 3732474 Creature/Catslime/catslime_lod02.skin
18 3732475 Creature/Catslime/catslime_lod03.skin