mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-07 09:33:51 +00:00
feat(editor): add --list-missing-sidecars for actionable open-format triage
--info-extract reports sidecar coverage % per format, but doesn't say
which files are missing. This makes it actionable:
wowee_editor --list-missing-sidecars Data/
Output: one path per line, prefixed with the missing extension so
shell tools can filter:
png Data/Textures/Skybox/Sky01.blp
json Data/DBFilesClient/SoundEntries.dbc
wom Data/Character/Human/Male/HumanMale.m2
Pipe into xargs to drive a targeted re-extract:
wowee_editor --list-missing-sidecars Data/ |
awk '/^png/ {print $2}' |
xargs asset_extract --emit-png-only
Skips WMO group files (Foo_NNN.wmo) since only the parent file gets
a .wob sidecar — they would otherwise inflate the missing list with
hundreds of false positives per WMO.
Exit 1 when anything is missing (so CI can gate). JSON mode emits
arrays per format type for programmatic consumption. Verified
against synthetic dir with 5 files (4 lacking sidecars + 1 with
.png present): all 4 reported, the one with sidecar correctly
omitted.
This commit is contained in:
parent
8f6315f155
commit
270fcd8e55
1 changed files with 85 additions and 1 deletions
|
|
@ -439,6 +439,8 @@ static void printUsage(const char* argv0) {
|
|||
std::printf(" Print WOT/WHM terrain metadata (tile, chunks, height range) and exit\n");
|
||||
std::printf(" --info-extract <dir> [--json]\n");
|
||||
std::printf(" Walk extracted asset tree and report open-format coverage and exit\n");
|
||||
std::printf(" --list-missing-sidecars <dir> [--json]\n");
|
||||
std::printf(" List proprietary files lacking open-format sidecars (one per line)\n");
|
||||
std::printf(" --info-zone <dir|json> [--json]\n");
|
||||
std::printf(" Print zone.json fields (manifest, tiles, audio, flags) and exit\n");
|
||||
std::printf(" --info-creatures <p> [--json]\n");
|
||||
|
|
@ -469,7 +471,8 @@ int main(int argc, char* argv[]) {
|
|||
static const char* kArgRequired[] = {
|
||||
"--data", "--info", "--info-wob", "--info-woc", "--info-wot",
|
||||
"--info-creatures", "--info-objects", "--info-quests",
|
||||
"--info-extract", "--info-zone", "--info-wcp", "--list-wcp",
|
||||
"--info-extract", "--list-missing-sidecars",
|
||||
"--info-zone", "--info-wcp", "--list-wcp",
|
||||
"--unpack-wcp", "--pack-wcp",
|
||||
"--validate", "--validate-wom", "--validate-wob", "--validate-woc",
|
||||
"--validate-whm", "--validate-all", "--zone-summary",
|
||||
|
|
@ -829,6 +832,87 @@ int main(int argc, char* argv[]) {
|
|||
std::printf("\n");
|
||||
std::printf(" (run `asset_extract --emit-open` to fill missing sidecars)\n");
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--list-missing-sidecars") == 0 && i + 1 < argc) {
|
||||
// Actionable counterpart to --info-extract: emit one line per
|
||||
// proprietary file lacking its open-format sidecar. Pipe into
|
||||
// xargs to drive a targeted re-extract:
|
||||
// wowee_editor --list-missing-sidecars Data/ |
|
||||
// awk '/\.blp$/ {print}' |
|
||||
// xargs asset_extract --emit-png-only
|
||||
std::string dataDir = argv[++i];
|
||||
bool jsonOut = (i + 1 < argc &&
|
||||
std::strcmp(argv[i + 1], "--json") == 0);
|
||||
if (jsonOut) i++;
|
||||
namespace fs = std::filesystem;
|
||||
if (!fs::exists(dataDir)) {
|
||||
std::fprintf(stderr, "list-missing-sidecars: %s does not exist\n",
|
||||
dataDir.c_str());
|
||||
return 1;
|
||||
}
|
||||
std::vector<std::string> missingPng, missingJson, missingWom,
|
||||
missingWob, missingWhm;
|
||||
for (auto& entry : fs::recursive_directory_iterator(dataDir)) {
|
||||
if (!entry.is_regular_file()) continue;
|
||||
std::string ext = entry.path().extension().string();
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
std::string base = entry.path().string();
|
||||
if (base.size() > ext.size())
|
||||
base = base.substr(0, base.size() - ext.size());
|
||||
auto missing = [&](const char* sidecarExt) {
|
||||
return !fs::exists(base + sidecarExt);
|
||||
};
|
||||
if (ext == ".blp" && missing(".png"))
|
||||
missingPng.push_back(entry.path().string());
|
||||
else if (ext == ".dbc" && missing(".json"))
|
||||
missingJson.push_back(entry.path().string());
|
||||
else if (ext == ".m2" && missing(".wom"))
|
||||
missingWom.push_back(entry.path().string());
|
||||
else if (ext == ".wmo") {
|
||||
// Group files (Foo_NNN.wmo) don't get individual sidecars
|
||||
// — only the parent file gets a .wob.
|
||||
std::string fname = entry.path().filename().string();
|
||||
auto under = fname.rfind('_');
|
||||
bool isGroup = (under != std::string::npos &&
|
||||
fname.size() - under == 8);
|
||||
if (!isGroup && missing(".wob"))
|
||||
missingWob.push_back(entry.path().string());
|
||||
}
|
||||
else if (ext == ".adt" && missing(".whm"))
|
||||
missingWhm.push_back(entry.path().string());
|
||||
}
|
||||
size_t total = missingPng.size() + missingJson.size() +
|
||||
missingWom.size() + missingWob.size() +
|
||||
missingWhm.size();
|
||||
if (jsonOut) {
|
||||
nlohmann::json j;
|
||||
j["dir"] = dataDir;
|
||||
j["totalMissing"] = total;
|
||||
j["missing"] = {
|
||||
{"png", missingPng},
|
||||
{"json", missingJson},
|
||||
{"wom", missingWom},
|
||||
{"wob", missingWob},
|
||||
{"whm", missingWhm},
|
||||
};
|
||||
std::printf("%s\n", j.dump(2).c_str());
|
||||
return total == 0 ? 0 : 1;
|
||||
}
|
||||
// Plain mode: one path per line, sorted by group, prefixed with
|
||||
// the missing extension so awk/grep can filter.
|
||||
auto emit = [](const char* tag, const std::vector<std::string>& files) {
|
||||
for (const auto& f : files) std::printf("%s\t%s\n", tag, f.c_str());
|
||||
};
|
||||
emit("png", missingPng);
|
||||
emit("json", missingJson);
|
||||
emit("wom", missingWom);
|
||||
emit("wob", missingWob);
|
||||
emit("whm", missingWhm);
|
||||
std::fprintf(stderr,
|
||||
"%zu missing (PNG=%zu JSON=%zu WOM=%zu WOB=%zu WHM=%zu)\n",
|
||||
total, missingPng.size(), missingJson.size(),
|
||||
missingWom.size(), missingWob.size(), missingWhm.size());
|
||||
return total == 0 ? 0 : 1;
|
||||
} else if (std::strcmp(argv[i], "--info-zone") == 0 && i + 1 < argc) {
|
||||
// Parse a zone.json and print every manifest field. Useful when
|
||||
// diffing two zones or auditing the audio/flag setup before
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue