Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c905d0558e | |||
| 76ca0cc851 | |||
| 398245d27d | |||
| 887ab7879b | |||
| e3b8d2649e | |||
| e916cdea19 | |||
| befdaa456d | |||
| 7291fff664 | |||
| 790506fc7a | |||
| 87329f2633 | |||
| 8375b95f7b | |||
| 01f476ca1b | |||
| 63c9af7846 | |||
| f02f4d73f0 |
@@ -1,15 +1,20 @@
|
||||
[submodule "vendor/warcraftxl"]
|
||||
path = vendor/warcraftxl
|
||||
url = https://github.com/WarcraftXL/wxl-core.git
|
||||
branch = main
|
||||
[submodule "vendor/modules/wxl-modern-assets"]
|
||||
path = vendor/modules/wxl-modern-assets
|
||||
url = https://github.com/WarcraftXL/wxl-modern-assets.git
|
||||
branch = main
|
||||
[submodule "vendor/modules/wxl-modern-render"]
|
||||
path = vendor/modules/wxl-modern-render
|
||||
url = https://github.com/WarcraftXL/wxl-modern-render.git
|
||||
branch = main
|
||||
[submodule "vendor/modules/wxl-unit-outline"]
|
||||
path = vendor/modules/wxl-unit-outline
|
||||
url = https://github.com/WarcraftXL/wxl-unit-outline.git
|
||||
branch = main
|
||||
[submodule "vendor/modules/wxl-modern-adt"]
|
||||
path = vendor/modules/wxl-modern-adt
|
||||
url = https://github.com/WarcraftXL/wxl-modern-adt.git
|
||||
branch = main
|
||||
|
||||
@@ -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,102 @@
|
||||
# Автоматический импорт mount и pet
|
||||
|
||||
Список современных моделей находится в `custom-creatures.json`. В нём есть две независимые
|
||||
секции:
|
||||
|
||||
```json
|
||||
{
|
||||
"mounts": [
|
||||
"assets/creatures/my_mount"
|
||||
],
|
||||
"pets": [
|
||||
"assets/creatures/my_pet"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Папка должна быть результатом **Raw M2 export** из wow.export и содержать:
|
||||
|
||||
- один основной `.m2`;
|
||||
- `*.manifest.json`;
|
||||
- все упомянутые в manifest текстуры, skin, skeleton, bone и animation-файлы.
|
||||
|
||||
Разрешены абсолютные пути, например `C:/Users/sindo/wow.export/creature/catslime`, но для
|
||||
воспроизводимой сборки папку лучше скопировать внутрь репозитория и указать относительный путь.
|
||||
|
||||
## Что делает сборщик
|
||||
|
||||
При обычном запуске `tool.exe`, `run.ps1` или `deploy.ps1` сборщик:
|
||||
|
||||
1. читает manifest каждой модели и размещает retail M2 со всеми зависимостями в loose-каталоге
|
||||
`Data/Patch-WXL.MPQ`, создавая рядом `.mdx`-алиас для загрузчика WoW 3.3.5, чтобы WarcraftXL всегда
|
||||
преобразовывал MD21 до загрузки клиентом;
|
||||
2. генерирует `WXLFileData.csv` для WarcraftXL;
|
||||
3. дописывает модели в `CreatureModelData.dbc` и `CreatureDisplayInfo.dbc`;
|
||||
4. сохраняет стабильные ID в `custom-creatures.lock.json`;
|
||||
5. для `pets` создаёт companion summon spell и строку skill line `778`;
|
||||
6. кладёт серверные DBC, SQL и таблицу ID в `build/server-dbc`.
|
||||
|
||||
Полный `Spell.dbc` в патч не копируется. WarcraftXL читает компактный
|
||||
`WXLSpellOverrides.tsv` и при открытии DBC добавляет новые spell-записи к штатному файлу клиента.
|
||||
|
||||
Перестановка моделей в списке не меняет уже выданные ID. Lock-файл необходимо хранить в Git.
|
||||
|
||||
## Дополнительные параметры
|
||||
|
||||
Если значений по умолчанию недостаточно, вместо строки используется объект:
|
||||
|
||||
```json
|
||||
{
|
||||
"folder": "assets/creatures/my_mount",
|
||||
"key": "my_mount",
|
||||
"name": "My Mount",
|
||||
"name_ru": "Мой транспорт",
|
||||
"race_mask": 1101,
|
||||
"icon": "my_icon.jpg",
|
||||
"archive": "Creature/MyMount",
|
||||
"model_file": "my_mount.m2",
|
||||
"template_display_id": 2404,
|
||||
"display_scale": 1.0,
|
||||
"model_scale": 1.0,
|
||||
"collision_width": 0.6111,
|
||||
"collision_height": 2.031,
|
||||
"mount_height": 1.8657,
|
||||
"flags": 0
|
||||
}
|
||||
```
|
||||
|
||||
Для `mounts` по умолчанию клонируется верховая лошадь с display ID `2404`, для `pets` —
|
||||
компаньон-кот с display ID `5448`. Шаблон задаёт физические размеры, звук и прочие поля DBC;
|
||||
параметры объекта позволяют их переопределить.
|
||||
|
||||
Для `pets` поле `race_mask` ограничивает строку коллекции набором рас (`1101` — Альянс,
|
||||
`690` — Орда, `0` или отсутствие поля — все расы). Поле `icon` указывает JPG, PNG или TGA рядом
|
||||
с моделью либо путь от корня проекта. Сборщик конвертирует изображение в BLP2, выдаёт стабильный
|
||||
`spellIconID`, добавляет запись в `SpellIcon.dbc` через MoonWell provider и назначает её summon-spell.
|
||||
|
||||
## Конвертация иконок
|
||||
|
||||
Встроенная команда CLI преобразует JPG, PNG или TGA в совместимый с клиентом BLP2:
|
||||
|
||||
```powershell
|
||||
tool.exe icon "путь/к/icon.jpg" ["путь/к/icon.blp"]
|
||||
```
|
||||
|
||||
Если выходной путь не указан, `.blp` создаётся рядом с исходным файлом. Конвертер автоматически
|
||||
приводит изображение к ближайшему квадратному размеру степени двойки (не более 512×512), кодирует
|
||||
его в DXT1 и создаёт mipmap-уровни. Например, иконка 56×56 будет преобразована в 64×64.
|
||||
|
||||
## Установка на сервер
|
||||
|
||||
Для каждого элемента `pets` сборщик автоматически выдаёт `creatureEntry`, `summonSpellID` и
|
||||
`skillLineAbilityID`. Значения находятся в `build/server-dbc/custom-creatures.csv`.
|
||||
|
||||
1. Скопировать `CreatureModelData.dbc` и `CreatureDisplayInfo.dbc` из `build/server-dbc` в
|
||||
серверный каталог `data/dbc`.
|
||||
2. Применить `build/server-dbc/custom-creatures.sql` к `acore_world`.
|
||||
3. Перезапустить worldserver: DBC и таблицы `spell_dbc` загружаются только при старте.
|
||||
4. Для проверки изучить выданный spell командой `.learn <summonSpellID>`.
|
||||
|
||||
SQL создаёт `creature_template`, `creature_model_info`, `creature_template_model`, companion spell и строку skill line.
|
||||
Генерация полноценного mount spell для секции `mounts` остаётся отдельным этапом: mount требует
|
||||
другой spell-шаблон с аурами скорости и `SPELL_AURA_MOUNTED`.
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"base_dbc_dir": "assets/dbc/3.3.5a",
|
||||
"model_data_id_start": 50000,
|
||||
"display_info_id_start": 50000,
|
||||
"creature_entry_id_start": 5000000,
|
||||
"summon_spell_id_start": 110000,
|
||||
"skill_line_ability_id_start": 30000,
|
||||
"spell_icon_id_start": 50000,
|
||||
"defaults": {
|
||||
"mount_template_display_id": 2404,
|
||||
"pet_template_display_id": 5448
|
||||
},
|
||||
"mounts": [],
|
||||
"pets": [
|
||||
{
|
||||
"folder": "src/Data/patch-Z/Creature/Catslime",
|
||||
"name": "Cat Slime",
|
||||
"name_ru": "Котослизень",
|
||||
"display_scale": 0.3
|
||||
},
|
||||
{
|
||||
"folder": "src/Data/patch-Z/Creature/MoonkinHatchling_Alliance",
|
||||
"key": "moonkin_hatchling_alliance",
|
||||
"race_mask": 1101,
|
||||
"icon": "inv_misc_petmoonkinne.jpg",
|
||||
"name": "Moonkin Hatchling",
|
||||
"name_ru": "Лунный совушек",
|
||||
"display_scale": 0.3
|
||||
},
|
||||
{
|
||||
"folder": "src/Data/patch-Z/Creature/MoonkinHatchling_Horde",
|
||||
"key": "moonkin_hatchling_horde",
|
||||
"race_mask": 690,
|
||||
"icon": "inv_misc_petmoonkinta.jpg",
|
||||
"name": "Moonkin Hatchling",
|
||||
"name_ru": "Лунный совушек",
|
||||
"display_scale": 0.3
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"models": {
|
||||
"catslime": {
|
||||
"model_data_id": 50000,
|
||||
"display_info_id": 50000,
|
||||
"creature_entry": 5000000,
|
||||
"summon_spell_id": 110000,
|
||||
"skill_line_ability_id": 30000
|
||||
},
|
||||
"moonkin_hatchling_alliance": {
|
||||
"model_data_id": 50001,
|
||||
"display_info_id": 50001,
|
||||
"creature_entry": 5000001,
|
||||
"summon_spell_id": 110001,
|
||||
"skill_line_ability_id": 30001,
|
||||
"spell_icon_id": 50000
|
||||
},
|
||||
"moonkin_hatchling_horde": {
|
||||
"model_data_id": 50002,
|
||||
"display_info_id": 50002,
|
||||
"creature_entry": 5000002,
|
||||
"summon_spell_id": 110002,
|
||||
"skill_line_ability_id": 30002,
|
||||
"spell_icon_id": 50001
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -76,11 +76,12 @@ New-Item -ItemType Directory -Path $PackagePath -Force | Out-Null
|
||||
if (-not $SkipDataBuild) {
|
||||
Write-Host '[2/5] Building MPQ patches...'
|
||||
$tool = Join-Path $repoRoot 'tool\target\release\tool.exe'
|
||||
if (-not (Test-Path -LiteralPath $tool -PathType Leaf)) {
|
||||
$cargo = Get-Command cargo -ErrorAction SilentlyContinue
|
||||
if (-not $cargo) { throw 'Cargo was not found and the MPQ builder is not compiled.' }
|
||||
$cargo = Get-Command cargo -ErrorAction SilentlyContinue
|
||||
if ($cargo) {
|
||||
& $cargo.Source build --release --manifest-path (Join-Path $repoRoot 'tool\Cargo.toml')
|
||||
if ($LASTEXITCODE -ne 0) { throw 'MPQ builder compilation failed.' }
|
||||
} elseif (-not (Test-Path -LiteralPath $tool -PathType Leaf)) {
|
||||
throw 'Cargo was not found and the MPQ builder is not compiled.'
|
||||
}
|
||||
|
||||
& $tool (Join-Path $repoRoot 'src') $PackagePath
|
||||
|
||||
@@ -0,0 +1,354 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Appends compact MoonWell spell overrides to the stock 3.3.5 DBCs at open time.
|
||||
|
||||
#include "Host.hpp"
|
||||
#include "core/Logger.hpp"
|
||||
#include "mpq/MpqStore.hpp"
|
||||
|
||||
#include <cctype>
|
||||
#include <charconv>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#include <vector>
|
||||
|
||||
namespace moonwell::host
|
||||
{
|
||||
namespace
|
||||
{
|
||||
constexpr std::string_view kOverridesPath = "WXLSpellOverrides.tsv";
|
||||
constexpr std::string_view kSpellPath = "DBFilesClient\\Spell.dbc";
|
||||
constexpr std::string_view kSkillPath = "DBFilesClient\\SkillLineAbility.dbc";
|
||||
constexpr std::string_view kSpellIconPath = "DBFilesClient\\SpellIcon.dbc";
|
||||
constexpr uint32_t kSpellFields = 234;
|
||||
constexpr uint32_t kSpellRecordSize = kSpellFields * 4;
|
||||
constexpr uint32_t kSkillFields = 14;
|
||||
constexpr uint32_t kSkillRecordSize = kSkillFields * 4;
|
||||
constexpr uint32_t kSpellIconFields = 2;
|
||||
constexpr uint32_t kSpellIconRecordSize = kSpellIconFields * 4;
|
||||
constexpr char8_t kDescriptionPrefixUtf8[] =
|
||||
u8"\u041F\u0440\u0438\u0437\u044B\u0432\u0430\u0435\u0442 \u0438\u043B\u0438 \u043E\u0442\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u0441\u043F\u0443\u0442\u043D\u0438\u043A\u0430: ";
|
||||
|
||||
struct Override
|
||||
{
|
||||
uint32_t spellId = 0;
|
||||
uint32_t templateSpellId = 0;
|
||||
uint32_t creatureEntry = 0;
|
||||
uint32_t skillLineAbilityId = 0;
|
||||
uint32_t raceMask = 0;
|
||||
uint32_t spellIconId = 0;
|
||||
std::string iconPath;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
std::once_flag g_loadOnce;
|
||||
bool g_ready = false;
|
||||
std::vector<uint8_t> g_spellDbc;
|
||||
std::vector<uint8_t> g_skillDbc;
|
||||
std::vector<uint8_t> g_spellIconDbc;
|
||||
|
||||
uint32_t ReadU32(const uint8_t* data)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
std::memcpy(&value, data, sizeof(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
void WriteU32(uint8_t* data, uint32_t value)
|
||||
{
|
||||
std::memcpy(data, &value, sizeof(value));
|
||||
}
|
||||
|
||||
std::string_view Trim(std::string_view value)
|
||||
{
|
||||
while (!value.empty() && std::isspace(static_cast<unsigned char>(value.front())))
|
||||
value.remove_prefix(1);
|
||||
while (!value.empty() && std::isspace(static_cast<unsigned char>(value.back())))
|
||||
value.remove_suffix(1);
|
||||
return value;
|
||||
}
|
||||
|
||||
bool ParseU32(std::string_view text, uint32_t& value)
|
||||
{
|
||||
text = Trim(text);
|
||||
const auto parsed = std::from_chars(text.data(), text.data() + text.size(), value);
|
||||
return parsed.ec == std::errc{} && parsed.ptr == text.data() + text.size();
|
||||
}
|
||||
|
||||
bool SamePath(std::string_view left, std::string_view right)
|
||||
{
|
||||
if (left.size() != right.size()) return false;
|
||||
for (size_t i = 0; i < left.size(); ++i)
|
||||
{
|
||||
const unsigned char a = static_cast<unsigned char>(left[i] == '/' ? '\\' : left[i]);
|
||||
const unsigned char b = static_cast<unsigned char>(right[i] == '/' ? '\\' : right[i]);
|
||||
if (std::tolower(a) != std::tolower(b)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseOverrides(const std::vector<uint8_t>& bytes, std::vector<Override>& out)
|
||||
{
|
||||
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;
|
||||
|
||||
std::vector<std::string_view> fields;
|
||||
size_t fieldStart = 0;
|
||||
while (true)
|
||||
{
|
||||
const size_t tab = line.find('\t', fieldStart);
|
||||
if (tab == std::string_view::npos)
|
||||
{
|
||||
fields.push_back(Trim(line.substr(fieldStart)));
|
||||
break;
|
||||
}
|
||||
fields.push_back(Trim(line.substr(fieldStart, tab - fieldStart)));
|
||||
fieldStart = tab + 1;
|
||||
}
|
||||
|
||||
Override item;
|
||||
if (fields.size() == 5)
|
||||
{
|
||||
if (!ParseU32(fields[0], item.spellId) ||
|
||||
!ParseU32(fields[1], item.templateSpellId) ||
|
||||
!ParseU32(fields[2], item.creatureEntry) ||
|
||||
!ParseU32(fields[3], item.skillLineAbilityId) || fields[4].empty())
|
||||
return false;
|
||||
item.name.assign(fields[4]);
|
||||
}
|
||||
else if (fields.size() == 8)
|
||||
{
|
||||
if (!ParseU32(fields[0], item.spellId) ||
|
||||
!ParseU32(fields[1], item.templateSpellId) ||
|
||||
!ParseU32(fields[2], item.creatureEntry) ||
|
||||
!ParseU32(fields[3], item.skillLineAbilityId) ||
|
||||
!ParseU32(fields[4], item.raceMask) ||
|
||||
!ParseU32(fields[5], item.spellIconId) || fields[7].empty())
|
||||
return false;
|
||||
if (item.spellIconId != 0)
|
||||
{
|
||||
if (fields[6].empty() || fields[6] == "-") return false;
|
||||
item.iconPath.assign(fields[6]);
|
||||
}
|
||||
item.name.assign(fields[7]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
out.push_back(std::move(item));
|
||||
}
|
||||
return !out.empty();
|
||||
}
|
||||
|
||||
bool ValidateWdbc(const std::vector<uint8_t>& bytes, uint32_t fields, uint32_t recordSize,
|
||||
uint32_t& count, uint32_t& stringSize, size_t& recordsEnd)
|
||||
{
|
||||
if (bytes.size() < 20 || std::memcmp(bytes.data(), "WDBC", 4) != 0) return false;
|
||||
count = ReadU32(bytes.data() + 4);
|
||||
if (ReadU32(bytes.data() + 8) != fields || ReadU32(bytes.data() + 12) != recordSize)
|
||||
return false;
|
||||
stringSize = ReadU32(bytes.data() + 16);
|
||||
recordsEnd = 20ull + static_cast<size_t>(count) * recordSize;
|
||||
return recordsEnd <= bytes.size() && recordsEnd + stringSize == bytes.size();
|
||||
}
|
||||
|
||||
const uint8_t* FindSpell(const std::vector<uint8_t>& bytes, uint32_t count, uint32_t id)
|
||||
{
|
||||
for (uint32_t i = 0; i < count; ++i)
|
||||
{
|
||||
const uint8_t* row = bytes.data() + 20 + static_cast<size_t>(i) * kSpellRecordSize;
|
||||
if (ReadU32(row) == id) return row;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const uint8_t* FindSkillRow(const std::vector<uint8_t>& bytes, uint32_t count, uint32_t spellId)
|
||||
{
|
||||
for (uint32_t i = 0; i < count; ++i)
|
||||
{
|
||||
const uint8_t* row = bytes.data() + 20 + static_cast<size_t>(i) * kSkillRecordSize;
|
||||
if (ReadU32(row + 4) == 778 && ReadU32(row + 8) == spellId) return row;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool BuildSpellDbc(const std::vector<uint8_t>& base, const std::vector<Override>& overrides,
|
||||
std::vector<uint8_t>& out)
|
||||
{
|
||||
uint32_t count = 0, stringSize = 0;
|
||||
size_t recordsEnd = 0;
|
||||
if (!ValidateWdbc(base, kSpellFields, kSpellRecordSize, count, stringSize, recordsEnd))
|
||||
return false;
|
||||
|
||||
std::vector<uint8_t> records;
|
||||
records.reserve(overrides.size() * kSpellRecordSize);
|
||||
std::vector<uint8_t> strings;
|
||||
for (const Override& item : overrides)
|
||||
{
|
||||
const uint8_t* source = FindSpell(base, count, item.templateSpellId);
|
||||
if (!source) return false;
|
||||
const size_t recordStart = records.size();
|
||||
records.insert(records.end(), source, source + kSpellRecordSize);
|
||||
uint8_t* row = records.data() + recordStart;
|
||||
WriteU32(row, item.spellId);
|
||||
WriteU32(row + 110 * 4, item.creatureEntry);
|
||||
if (item.spellIconId != 0) WriteU32(row + 133 * 4, item.spellIconId);
|
||||
|
||||
const uint32_t nameOffset = stringSize + static_cast<uint32_t>(strings.size());
|
||||
strings.insert(strings.end(), item.name.begin(), item.name.end());
|
||||
strings.push_back(0);
|
||||
const std::string description =
|
||||
std::string(reinterpret_cast<const char*>(kDescriptionPrefixUtf8)) + item.name + ".";
|
||||
const uint32_t descriptionOffset = stringSize + static_cast<uint32_t>(strings.size());
|
||||
strings.insert(strings.end(), description.begin(), description.end());
|
||||
strings.push_back(0);
|
||||
for (uint32_t field = 136; field <= 151; ++field) WriteU32(row + field * 4, nameOffset);
|
||||
for (uint32_t field = 170; field <= 185; ++field) WriteU32(row + field * 4, descriptionOffset);
|
||||
for (uint32_t field = 187; field <= 202; ++field) WriteU32(row + field * 4, 0);
|
||||
}
|
||||
|
||||
out.reserve(base.size() + records.size() + strings.size());
|
||||
out.insert(out.end(), base.begin(), base.begin() + 20);
|
||||
WriteU32(out.data() + 4, count + static_cast<uint32_t>(overrides.size()));
|
||||
WriteU32(out.data() + 16, stringSize + static_cast<uint32_t>(strings.size()));
|
||||
out.insert(out.end(), base.begin() + 20, base.begin() + recordsEnd);
|
||||
out.insert(out.end(), records.begin(), records.end());
|
||||
out.insert(out.end(), base.begin() + recordsEnd, base.end());
|
||||
out.insert(out.end(), strings.begin(), strings.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BuildSkillDbc(const std::vector<uint8_t>& base, const std::vector<Override>& overrides,
|
||||
std::vector<uint8_t>& out)
|
||||
{
|
||||
uint32_t count = 0, stringSize = 0;
|
||||
size_t recordsEnd = 0;
|
||||
if (!ValidateWdbc(base, kSkillFields, kSkillRecordSize, count, stringSize, recordsEnd))
|
||||
return false;
|
||||
|
||||
std::vector<uint8_t> records;
|
||||
records.reserve(overrides.size() * kSkillRecordSize);
|
||||
for (const Override& item : overrides)
|
||||
{
|
||||
const uint8_t* source = FindSkillRow(base, count, item.templateSpellId);
|
||||
if (!source) return false;
|
||||
const size_t recordStart = records.size();
|
||||
records.insert(records.end(), source, source + kSkillRecordSize);
|
||||
uint8_t* row = records.data() + recordStart;
|
||||
WriteU32(row, item.skillLineAbilityId);
|
||||
WriteU32(row + 8, item.spellId);
|
||||
WriteU32(row + 12, item.raceMask);
|
||||
}
|
||||
|
||||
out.reserve(base.size() + records.size());
|
||||
out.insert(out.end(), base.begin(), base.begin() + 20);
|
||||
WriteU32(out.data() + 4, count + static_cast<uint32_t>(overrides.size()));
|
||||
out.insert(out.end(), base.begin() + 20, base.begin() + recordsEnd);
|
||||
out.insert(out.end(), records.begin(), records.end());
|
||||
out.insert(out.end(), base.begin() + recordsEnd, base.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BuildSpellIconDbc(const std::vector<uint8_t>& base, const std::vector<Override>& overrides,
|
||||
std::vector<uint8_t>& out)
|
||||
{
|
||||
uint32_t count = 0, stringSize = 0;
|
||||
size_t recordsEnd = 0;
|
||||
if (!ValidateWdbc(base, kSpellIconFields, kSpellIconRecordSize, count, stringSize, recordsEnd))
|
||||
return false;
|
||||
|
||||
std::vector<uint8_t> records;
|
||||
std::vector<uint8_t> strings;
|
||||
for (const Override& item : overrides)
|
||||
{
|
||||
if (item.spellIconId == 0) continue;
|
||||
for (uint32_t i = 0; i < count; ++i)
|
||||
{
|
||||
const uint8_t* row = base.data() + 20 + static_cast<size_t>(i) * kSpellIconRecordSize;
|
||||
if (ReadU32(row) == item.spellIconId) return false;
|
||||
}
|
||||
for (size_t i = 0; i < records.size(); i += kSpellIconRecordSize)
|
||||
if (ReadU32(records.data() + i) == item.spellIconId) return false;
|
||||
|
||||
const uint32_t pathOffset = stringSize + static_cast<uint32_t>(strings.size());
|
||||
const size_t recordStart = records.size();
|
||||
records.resize(recordStart + kSpellIconRecordSize);
|
||||
WriteU32(records.data() + recordStart, item.spellIconId);
|
||||
WriteU32(records.data() + recordStart + 4, pathOffset);
|
||||
strings.insert(strings.end(), item.iconPath.begin(), item.iconPath.end());
|
||||
strings.push_back(0);
|
||||
}
|
||||
|
||||
if (records.empty()) return true;
|
||||
out.reserve(base.size() + records.size() + strings.size());
|
||||
out.insert(out.end(), base.begin(), base.begin() + 20);
|
||||
WriteU32(out.data() + 4, count + static_cast<uint32_t>(records.size() / kSpellIconRecordSize));
|
||||
WriteU32(out.data() + 16, stringSize + static_cast<uint32_t>(strings.size()));
|
||||
out.insert(out.end(), base.begin() + 20, base.begin() + recordsEnd);
|
||||
out.insert(out.end(), records.begin(), records.end());
|
||||
out.insert(out.end(), base.begin() + recordsEnd, base.end());
|
||||
out.insert(out.end(), strings.begin(), strings.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
void Load()
|
||||
{
|
||||
const std::string root = wxl::host::ClientRoot();
|
||||
wxl::host::mpq::MpqStore store;
|
||||
std::vector<uint8_t> overrideBytes, spellBase, skillBase, spellIconBase;
|
||||
if (root.empty() || !store.Mount(root) || !store.ReadAll(kOverridesPath, overrideBytes))
|
||||
return;
|
||||
|
||||
std::vector<Override> overrides;
|
||||
if (!ParseOverrides(overrideBytes, overrides) ||
|
||||
!store.ReadAll(kSpellPath, spellBase) || !store.ReadAll(kSkillPath, skillBase) ||
|
||||
!store.ReadAll(kSpellIconPath, spellIconBase) ||
|
||||
!BuildSpellDbc(spellBase, overrides, g_spellDbc) ||
|
||||
!BuildSkillDbc(skillBase, overrides, g_skillDbc) ||
|
||||
!BuildSpellIconDbc(spellIconBase, overrides, g_spellIconDbc))
|
||||
{
|
||||
WLOG_ERROR("moonwell-spells: failed to build custom companion DBCs");
|
||||
return;
|
||||
}
|
||||
g_ready = true;
|
||||
WLOG_INFO("moonwell-spells: appended %zu companion spell(s)", overrides.size());
|
||||
}
|
||||
|
||||
bool Provide(std::string_view name, std::vector<uint8_t>& out)
|
||||
{
|
||||
if (!SamePath(name, kSpellPath) && !SamePath(name, kSkillPath) &&
|
||||
!SamePath(name, kSpellIconPath))
|
||||
return false;
|
||||
std::call_once(g_loadOnce, &Load);
|
||||
if (!g_ready) return false;
|
||||
if (SamePath(name, kSpellPath))
|
||||
out = g_spellDbc;
|
||||
else if (SamePath(name, kSkillPath))
|
||||
out = g_skillDbc;
|
||||
else
|
||||
{
|
||||
if (g_spellIconDbc.empty()) return false;
|
||||
out = g_spellIconDbc;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct Registrar
|
||||
{
|
||||
Registrar() { wxl::host::RegisterProvider("moonwell-companion-spells", &Provide); }
|
||||
};
|
||||
|
||||
Registrar g_registrar;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -420,6 +420,8 @@ namespace moonwell
|
||||
wxl::runtime::modules::RegisterBoot("moonwell", &InstallBoot);
|
||||
wxl::runtime::modules::Register(
|
||||
"moonwell-character-create-camera", &InstallCharacterCreateCamera);
|
||||
wxl::runtime::modules::Register(
|
||||
"moonwell-encounter-journal-models", &InstallEncounterJournalModelPreview);
|
||||
wxl::runtime::modules::Register("moonwell-log-flush", &InstallRuntimeLogFlush);
|
||||
}
|
||||
} g_registration;
|
||||
|
||||
@@ -37,6 +37,42 @@ if (-not $env:WOW_HOME) {
|
||||
$WOW_HOME = $env:WOW_HOME
|
||||
Write-Host "WOW_HOME = $WOW_HOME"
|
||||
|
||||
function Test-ExistingFileWriteAccess {
|
||||
param([Parameter(Mandatory=$true)][string]$Path)
|
||||
|
||||
try {
|
||||
$stream = [System.IO.File]::Open(
|
||||
$Path,
|
||||
[System.IO.FileMode]::Open,
|
||||
[System.IO.FileAccess]::Write,
|
||||
[System.IO.FileShare]::ReadWrite
|
||||
)
|
||||
$stream.Close()
|
||||
return $true
|
||||
} catch [System.UnauthorizedAccessException] {
|
||||
return $false
|
||||
} catch {
|
||||
# Sharing violations are handled later by Stop-WowRuntime. They do not
|
||||
# indicate that the whole script needs an elevated token.
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
||||
$installedWarcraftXL = Join-Path $WOW_HOME "WarcraftXL.dll"
|
||||
$isAdministrator = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
|
||||
[Security.Principal.WindowsBuiltInRole]::Administrator
|
||||
)
|
||||
|
||||
if ((Test-Path -LiteralPath $installedWarcraftXL -PathType Leaf) -and
|
||||
-not (Test-ExistingFileWriteAccess -Path $installedWarcraftXL) -and
|
||||
-not $isAdministrator) {
|
||||
Write-Host "WarcraftXL.dll requires administrator access. Requesting elevation..."
|
||||
$elevatedProcess = Start-Process -FilePath "powershell.exe" -Verb RunAs -PassThru -Wait `
|
||||
-WorkingDirectory $ROOT `
|
||||
-ArgumentList "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "`"$($MyInvocation.MyCommand.Path)`"", "-Env", $Env
|
||||
exit $elevatedProcess.ExitCode
|
||||
}
|
||||
|
||||
# --- Paths
|
||||
$SRC_DIR = Join-Path $ROOT "src"
|
||||
$DIST_DIR = Join-Path $ROOT "dist"
|
||||
@@ -44,11 +80,49 @@ $TOOL = Join-Path $ROOT "tool\target\release\tool.exe"
|
||||
$RELOAD_SCRIPT = Join-Path $ROOT "reload_wow.bat"
|
||||
$WXL_BUILD_SCRIPT = Join-Path $ROOT "build-warcraftxl.ps1"
|
||||
|
||||
# --- Ensure tool exists
|
||||
if (!(Test-Path $TOOL)) {
|
||||
Write-Host "Building Rust tool..."
|
||||
Push-Location (Join-Path $ROOT "tool")
|
||||
cargo build --release
|
||||
function Stop-WowRuntime {
|
||||
param([Parameter(Mandatory=$true)][string]$ClientPath)
|
||||
|
||||
$clientRoot = [System.IO.Path]::GetFullPath($ClientPath).TrimEnd('\') + '\'
|
||||
$runtimeProcesses = @(Get-Process -Name "Wow", "WarcraftXLHost" -ErrorAction SilentlyContinue | Where-Object {
|
||||
try {
|
||||
$_.Path -and $_.Path.StartsWith($clientRoot, [System.StringComparison]::OrdinalIgnoreCase)
|
||||
} catch {
|
||||
$false
|
||||
}
|
||||
})
|
||||
|
||||
if (-not $runtimeProcesses.Count) {
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host "Stopping the running WoW client and WarcraftXL host..."
|
||||
$runtimeProcesses | Stop-Process -Force
|
||||
|
||||
try {
|
||||
$runtimeProcesses | Wait-Process -Timeout 10 -ErrorAction Stop
|
||||
} catch {
|
||||
$stillRunning = @($runtimeProcesses | Where-Object { -not $_.HasExited })
|
||||
if ($stillRunning.Count) {
|
||||
$processNames = ($stillRunning | ForEach-Object { "$($_.ProcessName) (PID $($_.Id))" }) -join ", "
|
||||
throw "Could not stop processes that lock WarcraftXL files: $processNames"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# --- Always rebuild the tool so generated DBC/SQL formats match the current sources.
|
||||
$cargo = Get-Command cargo -ErrorAction SilentlyContinue
|
||||
if (-not $cargo) {
|
||||
throw "Cargo was not found; the MPQ/DBC builder cannot be refreshed."
|
||||
}
|
||||
Write-Host "Building Rust tool..."
|
||||
Push-Location (Join-Path $ROOT "tool")
|
||||
try {
|
||||
& $cargo.Source build --release
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Rust tool build failed with exit code $LASTEXITCODE."
|
||||
}
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
@@ -68,6 +142,12 @@ if (!(Test-Path (Join-Path $DIST_DIR "Data"))) {
|
||||
|
||||
# --- Build/package/deploy WarcraftXL before the dist sync. The packaged files
|
||||
# are uploaded by upload_to_s3.py and consumed by the launcher manifest.
|
||||
Stop-WowRuntime -ClientPath $WOW_HOME
|
||||
$creatureCache = Join-Path $WOW_HOME "Cache\WDB\ruRU\creaturecache.wdb"
|
||||
if (Test-Path -LiteralPath $creatureCache -PathType Leaf) {
|
||||
Remove-Item -LiteralPath $creatureCache -Force
|
||||
Write-Host "Cleared stale creature cache: $creatureCache"
|
||||
}
|
||||
Write-Host "Building and packaging WarcraftXL..."
|
||||
& $WXL_BUILD_SCRIPT -Configuration Release -ClientPath $WOW_HOME `
|
||||
-PackagePath $DIST_DIR -Deploy
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.3 MiB |
Binary file not shown.
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"fileDataID": 3730958,
|
||||
"textures": [
|
||||
{
|
||||
"fileDataID": 3732460,
|
||||
"file": "catslime_3732460.blp"
|
||||
},
|
||||
{
|
||||
"fileDataID": 3732461,
|
||||
"file": "catslime_3732461.blp"
|
||||
}
|
||||
],
|
||||
"skins": [
|
||||
{
|
||||
"fileDataID": 3732472,
|
||||
"file": "catslime00.skin"
|
||||
}
|
||||
],
|
||||
"lodSkins": [
|
||||
{
|
||||
"fileDataID": 3732473,
|
||||
"file": "catslime_lod01.skin"
|
||||
},
|
||||
{
|
||||
"fileDataID": 3732474,
|
||||
"file": "catslime_lod02.skin"
|
||||
},
|
||||
{
|
||||
"fileDataID": 3732475,
|
||||
"file": "catslime_lod03.skin"
|
||||
}
|
||||
],
|
||||
"anims": [
|
||||
{
|
||||
"fileDataID": 3732462,
|
||||
"file": "catslime0097-00.anim",
|
||||
"animID": 97,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 3732463,
|
||||
"file": "catslime0096-00.anim",
|
||||
"animID": 96,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 3732464,
|
||||
"file": "catslime0098-00.anim",
|
||||
"animID": 98,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 3732465,
|
||||
"file": "catslime0100-00.anim",
|
||||
"animID": 100,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 3732466,
|
||||
"file": "catslime0099-00.anim",
|
||||
"animID": 99,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 3732467,
|
||||
"file": "catslime0101-00.anim",
|
||||
"animID": 101,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 3732468,
|
||||
"file": "catslime0069-00.anim",
|
||||
"animID": 69,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 3732469,
|
||||
"file": "catslime0123-00.anim",
|
||||
"animID": 123,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 3732470,
|
||||
"file": "catslime0061-00.anim",
|
||||
"animID": 61,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 3732471,
|
||||
"file": "catslime0075-00.anim",
|
||||
"animID": 75,
|
||||
"subAnimID": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"fileDataID": 467885,
|
||||
"textures": [
|
||||
{
|
||||
"fileDataID": 467884,
|
||||
"file": "babymoonkinne.blp"
|
||||
},
|
||||
{
|
||||
"fileDataID": 944915,
|
||||
"file": "armorreflect4.blp"
|
||||
}
|
||||
],
|
||||
"skins": [
|
||||
{
|
||||
"fileDataID": 473055,
|
||||
"file": "babymoonkin_ne00.skin"
|
||||
}
|
||||
],
|
||||
"lodSkins": [],
|
||||
"anims": [
|
||||
{
|
||||
"fileDataID": 473051,
|
||||
"file": "babymoonkin_ne0074-00.anim",
|
||||
"animID": 74,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473072,
|
||||
"file": "babymoonkin_ne0062-00.anim",
|
||||
"animID": 62,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473068,
|
||||
"file": "babymoonkin_ne0060-00.anim",
|
||||
"animID": 60,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473061,
|
||||
"file": "babymoonkin_ne0070-00.anim",
|
||||
"animID": 70,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473038,
|
||||
"file": "babymoonkin_ne0097-00.anim",
|
||||
"animID": 97,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473067,
|
||||
"file": "babymoonkin_ne0096-00.anim",
|
||||
"animID": 96,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473047,
|
||||
"file": "babymoonkin_ne0098-00.anim",
|
||||
"animID": 98,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473040,
|
||||
"file": "babymoonkin_ne0100-00.anim",
|
||||
"animID": 100,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473035,
|
||||
"file": "babymoonkin_ne0099-00.anim",
|
||||
"animID": 99,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473041,
|
||||
"file": "babymoonkin_ne0101-00.anim",
|
||||
"animID": 101,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473031,
|
||||
"file": "babymoonkin_ne0069-00.anim",
|
||||
"animID": 69,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473050,
|
||||
"file": "babymoonkin_ne0069-01.anim",
|
||||
"animID": 69,
|
||||
"subAnimID": 1
|
||||
},
|
||||
{
|
||||
"fileDataID": 473046,
|
||||
"file": "babymoonkin_ne0069-02.anim",
|
||||
"animID": 69,
|
||||
"subAnimID": 2
|
||||
},
|
||||
{
|
||||
"fileDataID": 473042,
|
||||
"file": "babymoonkin_ne0069-03.anim",
|
||||
"animID": 69,
|
||||
"subAnimID": 3
|
||||
},
|
||||
{
|
||||
"fileDataID": 473060,
|
||||
"file": "babymoonkin_ne0061-00.anim",
|
||||
"animID": 61,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473030,
|
||||
"file": "babymoonkin_ne0067-00.anim",
|
||||
"animID": 67,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473037,
|
||||
"file": "babymoonkin_ne0075-00.anim",
|
||||
"animID": 75,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473069,
|
||||
"file": "babymoonkin_ne0133-00.anim",
|
||||
"animID": 133,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473057,
|
||||
"file": "babymoonkin_ne0134-00.anim",
|
||||
"animID": 134,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473074,
|
||||
"file": "babymoonkin_ne0123-00.anim",
|
||||
"animID": 123,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473056,
|
||||
"file": "babymoonkin_ne0128-00.anim",
|
||||
"animID": 128,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473029,
|
||||
"file": "babymoonkin_ne0129-00.anim",
|
||||
"animID": 129,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473073,
|
||||
"file": "babymoonkin_ne0079-00.anim",
|
||||
"animID": 79,
|
||||
"subAnimID": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"fileDataID": 467887,
|
||||
"textures": [
|
||||
{
|
||||
"fileDataID": 467886,
|
||||
"file": "babymoonkinta.blp"
|
||||
},
|
||||
{
|
||||
"fileDataID": 249237,
|
||||
"file": "..\\..\\item\\objectcomponents\\shield\\armorreflect4.blp"
|
||||
}
|
||||
],
|
||||
"skins": [
|
||||
{
|
||||
"fileDataID": 473058,
|
||||
"file": "babymoonkin_ta00.skin"
|
||||
}
|
||||
],
|
||||
"lodSkins": [],
|
||||
"anims": [
|
||||
{
|
||||
"fileDataID": 473066,
|
||||
"file": "babymoonkin_ta0074-00.anim",
|
||||
"animID": 74,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473039,
|
||||
"file": "babymoonkin_ta0062-00.anim",
|
||||
"animID": 62,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473064,
|
||||
"file": "babymoonkin_ta0060-00.anim",
|
||||
"animID": 60,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473075,
|
||||
"file": "babymoonkin_ta0070-00.anim",
|
||||
"animID": 70,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473053,
|
||||
"file": "babymoonkin_ta0097-00.anim",
|
||||
"animID": 97,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473032,
|
||||
"file": "babymoonkin_ta0096-00.anim",
|
||||
"animID": 96,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473076,
|
||||
"file": "babymoonkin_ta0098-00.anim",
|
||||
"animID": 98,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473071,
|
||||
"file": "babymoonkin_ta0100-00.anim",
|
||||
"animID": 100,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473036,
|
||||
"file": "babymoonkin_ta0099-00.anim",
|
||||
"animID": 99,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473048,
|
||||
"file": "babymoonkin_ta0101-00.anim",
|
||||
"animID": 101,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473065,
|
||||
"file": "babymoonkin_ta0069-00.anim",
|
||||
"animID": 69,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473044,
|
||||
"file": "babymoonkin_ta0069-01.anim",
|
||||
"animID": 69,
|
||||
"subAnimID": 1
|
||||
},
|
||||
{
|
||||
"fileDataID": 473070,
|
||||
"file": "babymoonkin_ta0069-02.anim",
|
||||
"animID": 69,
|
||||
"subAnimID": 2
|
||||
},
|
||||
{
|
||||
"fileDataID": 473052,
|
||||
"file": "babymoonkin_ta0069-03.anim",
|
||||
"animID": 69,
|
||||
"subAnimID": 3
|
||||
},
|
||||
{
|
||||
"fileDataID": 473062,
|
||||
"file": "babymoonkin_ta0061-00.anim",
|
||||
"animID": 61,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473043,
|
||||
"file": "babymoonkin_ta0067-00.anim",
|
||||
"animID": 67,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473045,
|
||||
"file": "babymoonkin_ta0075-00.anim",
|
||||
"animID": 75,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473034,
|
||||
"file": "babymoonkin_ta0133-00.anim",
|
||||
"animID": 133,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473063,
|
||||
"file": "babymoonkin_ta0134-00.anim",
|
||||
"animID": 134,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473054,
|
||||
"file": "babymoonkin_ta0123-00.anim",
|
||||
"animID": 123,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473049,
|
||||
"file": "babymoonkin_ta0128-00.anim",
|
||||
"animID": 128,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473033,
|
||||
"file": "babymoonkin_ta0129-00.anim",
|
||||
"animID": 129,
|
||||
"subAnimID": 0
|
||||
},
|
||||
{
|
||||
"fileDataID": 473059,
|
||||
"file": "babymoonkin_ta0079-00.anim",
|
||||
"animID": 79,
|
||||
"subAnimID": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
Binary file not shown.
+93
-2
@@ -353,6 +353,80 @@ EnsureColorMethods(HIGHLIGHT_FONT_COLOR)
|
||||
EnsureColorMethods(RED_FONT_COLOR)
|
||||
EnsureColorMethods(GREEN_FONT_COLOR)
|
||||
EnsureColorMethods(DISABLED_FONT_COLOR)
|
||||
|
||||
-- The imported Encounter Journal UI uses tooltip helpers introduced after
|
||||
-- 3.3.5. Keep their retail signatures, but implement them with the tooltip
|
||||
-- methods available in the 3.3.5 client.
|
||||
local function TooltipColorRGB(color, fallbackR, fallbackG, fallbackB)
|
||||
if type(color) == "table" then
|
||||
if color.GetRGB then
|
||||
return color:GetRGB()
|
||||
end
|
||||
|
||||
return color.r or fallbackR, color.g or fallbackG, color.b or fallbackB
|
||||
end
|
||||
|
||||
return fallbackR, fallbackG, fallbackB
|
||||
end
|
||||
|
||||
if not GameTooltip_AddColoredLine then
|
||||
function GameTooltip_AddColoredLine(tooltip, text, color, wrap)
|
||||
if not tooltip or not tooltip.AddLine then
|
||||
return
|
||||
end
|
||||
|
||||
local r, g, b = TooltipColorRGB(color, 1, 1, 1)
|
||||
tooltip:AddLine(text or "", r, g, b, wrap and true or false)
|
||||
end
|
||||
end
|
||||
|
||||
if not GameTooltip_AddNormalLine then
|
||||
function GameTooltip_AddNormalLine(tooltip, text, wrap)
|
||||
GameTooltip_AddColoredLine(tooltip, text, NORMAL_FONT_COLOR, wrap)
|
||||
end
|
||||
end
|
||||
|
||||
if not GameTooltip_AddHighlightLine then
|
||||
function GameTooltip_AddHighlightLine(tooltip, text, wrap)
|
||||
GameTooltip_AddColoredLine(tooltip, text, HIGHLIGHT_FONT_COLOR, wrap)
|
||||
end
|
||||
end
|
||||
|
||||
if not GameTooltip_AddBlankLineToTooltip then
|
||||
function GameTooltip_AddBlankLineToTooltip(tooltip)
|
||||
if tooltip and tooltip.AddLine then
|
||||
tooltip:AddLine(" ")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not GameTooltip_SetTitle then
|
||||
function GameTooltip_SetTitle(tooltip, text, color)
|
||||
if not tooltip then
|
||||
return
|
||||
end
|
||||
|
||||
local r, g, b = TooltipColorRGB(color or NORMAL_FONT_COLOR, 1, 0.82, 0)
|
||||
if tooltip.SetText then
|
||||
tooltip:SetText(text or "", r, g, b)
|
||||
elseif tooltip.AddLine then
|
||||
tooltip:AddLine(text or "", r, g, b)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not GameTooltip_ShowDisabledTooltip then
|
||||
function GameTooltip_ShowDisabledTooltip(tooltip, owner, text, anchor, offsetX, offsetY)
|
||||
if not tooltip or not owner then
|
||||
return
|
||||
end
|
||||
|
||||
tooltip:SetOwner(owner, anchor or "ANCHOR_RIGHT", offsetX or 0, offsetY or 0)
|
||||
GameTooltip_AddNormalLine(tooltip, text, true)
|
||||
tooltip:Show()
|
||||
end
|
||||
end
|
||||
|
||||
LOOTJOURNAL_SOURCE_TOOLTIP_HEAD = LOOTJOURNAL_SOURCE_TOOLTIP_HEAD or "Способ получения:"
|
||||
RETURN_TO_DEFAULT = RETURN_TO_DEFAULT or "Настройки по умолчанию"
|
||||
GUIDEBOOK = GUIDEBOOK or "Путеводитель"
|
||||
@@ -557,6 +631,23 @@ local function EnsureItemsCache()
|
||||
end
|
||||
|
||||
local itemsCache = type(_G.ItemsCache) == "table" and _G.ItemsCache or nil
|
||||
local compactItemsCache = _G.MoonWellEncounterJournalItemCache
|
||||
if type(compactItemsCache) == "table" then
|
||||
itemsCache = itemsCache or {}
|
||||
for itemID, compactData in pairs(compactItemsCache) do
|
||||
if type(itemID) == "number" and type(compactData) == "table" and not itemsCache[itemID] then
|
||||
itemsCache[itemID] = {
|
||||
[ITEM_CACHE_FIELD.NAME_ENGB] = compactData[1],
|
||||
[ITEM_CACHE_FIELD.NAME_RURU] = compactData[2],
|
||||
[ITEM_CACHE_FIELD.RARITY] = compactData[3],
|
||||
[ITEM_CACHE_FIELD.TEXTURE] = compactData[4],
|
||||
}
|
||||
end
|
||||
end
|
||||
_G.ItemsCache = itemsCache
|
||||
_G.MoonWellEncounterJournalItemCache = nil
|
||||
end
|
||||
|
||||
local fileIndex = 1
|
||||
local itemCacheTable = _G["ItemsCache" .. fileIndex]
|
||||
|
||||
@@ -711,8 +802,8 @@ local function EnsureItemCacheFrame()
|
||||
end
|
||||
|
||||
C_Item.GetItemInfo = function(item, skipClientCache, callback, ...)
|
||||
local name, link, quality, itemLevel, reqLevel, itemType, itemSubType, maxStack, equipSlot, icon, vendorPrice
|
||||
if ExistingCItemGetItemInfo then
|
||||
local name, link, quality, itemLevel, reqLevel, itemType, itemSubType, maxStack, equipSlot, icon, vendorPrice = C_Item.GetItemInfoCache(item)
|
||||
if not name and ExistingCItemGetItemInfo then
|
||||
name, link, quality, itemLevel, reqLevel, itemType, itemSubType, maxStack, equipSlot, icon, vendorPrice = ExistingCItemGetItemInfo(item, skipClientCache, nil, ...)
|
||||
end
|
||||
if not name then
|
||||
|
||||
+81
@@ -2,11 +2,92 @@
|
||||
-- The static fallback is loaded from Generated_EncounterJournal.lua, so the journal works
|
||||
-- without ever calling ApplyEncounterJournalData.
|
||||
|
||||
-- These entries belong to the Sirus-specific content pack that was mixed into
|
||||
-- the production export. They are not MoonWell content and must never reach
|
||||
-- the client, including when the journal is refreshed through AIO.
|
||||
local BLOCKED_INSTANCE_IDS = {
|
||||
[773] = true, -- Bronze Sanctum
|
||||
[774] = true, -- Tol'Garod Prison
|
||||
[776] = true, -- Sirus categories
|
||||
[777] = true, -- Sirus world bosses (Norigorn)
|
||||
}
|
||||
|
||||
local function RemoveBlockedInstances(data)
|
||||
local instances = data.JOURNALINSTANCE or data.instances
|
||||
local encounters = data.JOURNALENCOUNTER or data.encounters
|
||||
local creatures = data.JOURNALENCOUNTERCREATURE or data.creatures
|
||||
local items = data.JOURNALENCOUNTERITEM or data.items
|
||||
local sections = data.JOURNALENCOUNTERSECTION or data.sections
|
||||
local tierInstances = data.JOURNALTIERXINSTANCE or data.tierInstances
|
||||
local blockedEncounterIDs = {}
|
||||
|
||||
if type(encounters) == "table" then
|
||||
for instanceID in pairs(BLOCKED_INSTANCE_IDS) do
|
||||
local encounterList = encounters[instanceID]
|
||||
if type(encounterList) == "table" then
|
||||
for _, encounterInfo in ipairs(encounterList) do
|
||||
if type(encounterInfo) == "table" and type(encounterInfo[1]) == "number" then
|
||||
blockedEncounterIDs[encounterInfo[1]] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
encounters[instanceID] = nil
|
||||
end
|
||||
end
|
||||
|
||||
if type(instances) == "table" then
|
||||
for instanceID in pairs(BLOCKED_INSTANCE_IDS) do
|
||||
instances[instanceID] = nil
|
||||
end
|
||||
end
|
||||
|
||||
for encounterID in pairs(blockedEncounterIDs) do
|
||||
if type(creatures) == "table" then
|
||||
creatures[encounterID] = nil
|
||||
end
|
||||
if type(items) == "table" then
|
||||
items[encounterID] = nil
|
||||
end
|
||||
end
|
||||
|
||||
if type(sections) == "table" then
|
||||
for sectionID, sectionInfo in pairs(sections) do
|
||||
if type(sectionInfo) == "table" and blockedEncounterIDs[sectionInfo[7]] then
|
||||
sections[sectionID] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if type(tierInstances) == "table" then
|
||||
for instanceID in pairs(BLOCKED_INSTANCE_IDS) do
|
||||
tierInstances[instanceID] = nil
|
||||
end
|
||||
|
||||
for _, instanceList in pairs(tierInstances) do
|
||||
if type(instanceList) == "table" then
|
||||
local writeIndex = 1
|
||||
for readIndex = 1, #instanceList do
|
||||
local instanceID = instanceList[readIndex]
|
||||
if not BLOCKED_INSTANCE_IDS[instanceID] then
|
||||
instanceList[writeIndex] = instanceID
|
||||
writeIndex = writeIndex + 1
|
||||
end
|
||||
end
|
||||
for index = writeIndex, #instanceList do
|
||||
instanceList[index] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function ApplyEncounterJournalData(data)
|
||||
if type(data) ~= "table" then
|
||||
return
|
||||
end
|
||||
|
||||
RemoveBlockedInstances(data)
|
||||
|
||||
local function NormalizeTierInstances(tiers, tierInstances)
|
||||
if type(tiers) ~= "table" or type(tierInstances) ~= "table" then
|
||||
return tierInstances
|
||||
|
||||
+10104
File diff suppressed because it is too large
Load Diff
+8390
-7
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,8 @@
|
||||
|
||||
AchievementFactions.lua
|
||||
MoonWellClient.lua
|
||||
SoloLFGCompat.lua
|
||||
EncounterJournal\EncounterJournalItemCache.lua
|
||||
EncounterJournal\EncounterJournalCompat.lua
|
||||
EncounterJournal\SharedXML\SoundKitConstants.lua
|
||||
EncounterJournal\Generated_EncounterJournalData.lua
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
local SOLO_RANDOM_DUNGEONS = {
|
||||
[1258] = true,
|
||||
[1259] = true,
|
||||
[1260] = true,
|
||||
[1261] = true,
|
||||
[1262] = true,
|
||||
}
|
||||
|
||||
local GetStockTexCoordsForRole = GetTexCoordsForRole
|
||||
|
||||
function GetTexCoordsForRole(role)
|
||||
if role == "UNKNOWN" then
|
||||
local proposalExists, _, dungeonID = GetLFGProposal()
|
||||
if proposalExists and SOLO_RANDOM_DUNGEONS[dungeonID] then
|
||||
local _, tank, healer = GetLFGRoles()
|
||||
if tank then
|
||||
role = "TANK"
|
||||
elseif healer then
|
||||
role = "HEALER"
|
||||
else
|
||||
role = "DAMAGER"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return GetStockTexCoordsForRole(role)
|
||||
end
|
||||
Generated
+288
-7
@@ -82,6 +82,18 @@ version = "1.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
|
||||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.11.0"
|
||||
@@ -103,6 +115,12 @@ version = "3.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.25.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
@@ -170,6 +188,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.5"
|
||||
@@ -253,6 +277,12 @@ version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.7"
|
||||
@@ -313,12 +343,38 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exr"
|
||||
version = "1.74.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711fe42c9964295e01ee3fba3f9fe0e1d24b98886950d68efe81b1c76e21adf3"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"half",
|
||||
"lebe",
|
||||
"miniz_oxide",
|
||||
"num-complex",
|
||||
"pulp",
|
||||
"rayon-core",
|
||||
"smallvec",
|
||||
"zune-inflate",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "fdeflate"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
|
||||
dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.9"
|
||||
@@ -381,6 +437,27 @@ dependencies = [
|
||||
"wasip3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gif"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b"
|
||||
dependencies = [
|
||||
"color_quant",
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crunchy",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.5"
|
||||
@@ -416,6 +493,39 @@ version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.24.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder",
|
||||
"color_quant",
|
||||
"exr",
|
||||
"gif",
|
||||
"jpeg-decoder",
|
||||
"num-traits",
|
||||
"png",
|
||||
"qoi",
|
||||
"tiff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "image-blp"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b863207a84a413c9e3e94909828ac796d24b1a6f53baa88f186d4cf61eca691f"
|
||||
dependencies = [
|
||||
"color_quant",
|
||||
"image",
|
||||
"log",
|
||||
"nom",
|
||||
"spin",
|
||||
"texpresso",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "implode"
|
||||
version = "0.1.1"
|
||||
@@ -459,6 +569,15 @@ version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
|
||||
|
||||
[[package]]
|
||||
name = "jpeg-decoder"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07"
|
||||
dependencies = [
|
||||
"rayon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.91"
|
||||
@@ -484,6 +603,12 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
||||
|
||||
[[package]]
|
||||
name = "lebe"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
|
||||
|
||||
[[package]]
|
||||
name = "libbz2-rs-sys"
|
||||
version = "0.2.2"
|
||||
@@ -558,6 +683,12 @@ version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
@@ -568,6 +699,16 @@ dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
@@ -594,6 +735,16 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
@@ -665,6 +816,12 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pem-rfc7468"
|
||||
version = "0.7.0"
|
||||
@@ -703,7 +860,20 @@ checksum = "5a7ff566c5cb263cf6a9f3b8b8ccbeaf236c0b3516c184134c062863258b3789"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"indicatif",
|
||||
"thiserror",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.17.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"crc32fast",
|
||||
"fdeflate",
|
||||
"flate2",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -740,6 +910,38 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pulp"
|
||||
version = "0.22.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "046aa45b989642ec2e4717c8e72d677b13edd831a4d3b6cf37d9a3e54912496a"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"cfg-if",
|
||||
"libm",
|
||||
"num-complex",
|
||||
"paste",
|
||||
"pulp-wasm-simd-flag",
|
||||
"raw-cpuid",
|
||||
"reborrow",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pulp-wasm-simd-flag"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d8f70e07b9c3962945a74e59ca1c511bba65b6419468acc217c457d93f3c740"
|
||||
|
||||
[[package]]
|
||||
name = "qoi"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
@@ -819,6 +1021,15 @@ dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-cpuid"
|
||||
version = "11.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186"
|
||||
dependencies = [
|
||||
"bitflags 2.11.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.11.0"
|
||||
@@ -839,13 +1050,19 @@ dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reborrow"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.11.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -874,7 +1091,7 @@ version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.11.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
@@ -915,6 +1132,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -988,6 +1206,9 @@ name = "spin"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
@@ -1035,13 +1256,43 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "texpresso"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8550677e2259d675a7841cb1403db35f330cc9e58674c8c5caa12dd12c51dc71"
|
||||
dependencies = [
|
||||
"libm",
|
||||
"rayon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
"thiserror-impl 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1055,10 +1306,25 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiff"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"jpeg-decoder",
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tool"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"image-blp",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"walkdir",
|
||||
"wow-mpq",
|
||||
]
|
||||
@@ -1206,7 +1472,7 @@ version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.11.0",
|
||||
"hashbrown 0.15.5",
|
||||
"indexmap",
|
||||
"semver",
|
||||
@@ -1222,6 +1488,12 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.11"
|
||||
@@ -1377,7 +1649,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
"bitflags 2.11.0",
|
||||
"indexmap",
|
||||
"log",
|
||||
"serde",
|
||||
@@ -1434,7 +1706,7 @@ dependencies = [
|
||||
"rsa",
|
||||
"sha1",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1468,3 +1740,12 @@ name = "zmij"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||
|
||||
[[package]]
|
||||
name = "zune-inflate"
|
||||
version = "0.2.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02"
|
||||
dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
@@ -6,3 +6,7 @@ edition = "2024"
|
||||
[dependencies]
|
||||
walkdir = "2.5.0"
|
||||
wow-mpq = "0.6.4"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
image = { version = "0.24.9", default-features = false, features = ["jpeg", "png", "tga"] }
|
||||
image-blp = "1.2.0"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user