mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-07 17:43:51 +00:00
feat(editor): add --add-item, introducing zone items.json content type
Introduces a new per-zone content file alongside creatures.json /
objects.json / quests.json. Schema: {"items": [{id, name, quality,
displayId, itemLevel, stackable}, ...]}. Inline JSON manipulation
via nlohmann::json — items are simple records and don't yet need
NpcSpawner-style infrastructure.
ID assignment: pass 0 (or omit) to auto-pick the smallest unused
positive integer so numbering stays contiguous. Explicit IDs are
honored. Duplicate IDs rejected with exit 1 so collisions are
visible.
Quality is 0..6 (poor/common/uncommon/rare/epic/legendary/artifact)
— summary line maps the number to the human name so users see what
they wrote.
Verified: auto-id sequential (1, 2) → explicit id (99) honored →
duplicate id rejected with exit 1; JSON schema stable, quality
labels correct, file auto-created on first call. Brings command
count to 196.
This commit is contained in:
parent
d28094593c
commit
dd36182cd3
1 changed files with 109 additions and 1 deletions
|
|
@ -528,6 +528,8 @@ static void printUsage(const char* argv0) {
|
|||
std::printf(" Synthesize a placeholder texture (solid hex color or 'checker'/'grid'); default 256x256\n");
|
||||
std::printf(" --gen-mesh <wom-base> <cube|plane|sphere> [size]\n");
|
||||
std::printf(" Synthesize a procedural WOM primitive with proper normals, UVs, and bounds\n");
|
||||
std::printf(" --add-item <zoneDir> <name> [id] [quality] [displayId] [itemLevel]\n");
|
||||
std::printf(" Append one item entry to <zoneDir>/items.json (auto-creates the file)\n");
|
||||
std::printf(" --convert-dbc-json <dbc-path> [out.json]\n");
|
||||
std::printf(" Convert one DBC file to wowee JSON sidecar format\n");
|
||||
std::printf(" --convert-json-dbc <json-path> [out.dbc]\n");
|
||||
|
|
@ -930,7 +932,7 @@ int main(int argc, char* argv[]) {
|
|||
"--check-zone-refs", "--check-zone-content",
|
||||
"--check-project-content", "--check-project-refs",
|
||||
"--export-zone-deps-md", "--export-zone-spawn-png",
|
||||
"--add-creature", "--add-object", "--add-quest",
|
||||
"--add-creature", "--add-object", "--add-quest", "--add-item",
|
||||
"--add-quest-objective", "--add-quest-reward-item", "--set-quest-reward",
|
||||
"--remove-quest-objective", "--clone-quest", "--clone-creature",
|
||||
"--clone-object",
|
||||
|
|
@ -12476,6 +12478,112 @@ int main(int argc, char* argv[]) {
|
|||
std::printf("Added creature '%s' to %s (now %zu total)\n",
|
||||
name.c_str(), path.c_str(), spawner.spawnCount());
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--add-item") == 0 && i + 2 < argc) {
|
||||
// Append one item entry to <zoneDir>/items.json. Inline
|
||||
// JSON without a dedicated editor class — items.json is
|
||||
// a simple {"items": [...]} array of records, and the
|
||||
// schema is small enough that we don't need NpcSpawner-
|
||||
// style infrastructure yet.
|
||||
//
|
||||
// Schema per item:
|
||||
// id (uint32) — Item.dbc primary key (auto-increments
|
||||
// from 1 if omitted)
|
||||
// name (string)
|
||||
// quality (uint8) — 0..6 (poor..artifact, default 1)
|
||||
// displayId (uint32) — ItemDisplayInfo index (default 0)
|
||||
// itemLevel (uint32) — default 1
|
||||
// stackable (uint32) — max stack size (default 1)
|
||||
std::string zoneDir = argv[++i];
|
||||
std::string name = argv[++i];
|
||||
namespace fs = std::filesystem;
|
||||
if (!fs::exists(zoneDir)) {
|
||||
std::fprintf(stderr,
|
||||
"add-item: zone '%s' does not exist\n", zoneDir.c_str());
|
||||
return 1;
|
||||
}
|
||||
uint32_t id = 0, displayId = 0, itemLevel = 1;
|
||||
uint32_t quality = 1;
|
||||
if (i + 1 < argc && argv[i + 1][0] != '-') {
|
||||
try { id = static_cast<uint32_t>(std::stoul(argv[++i])); }
|
||||
catch (...) {}
|
||||
}
|
||||
if (i + 1 < argc && argv[i + 1][0] != '-') {
|
||||
try { quality = static_cast<uint32_t>(std::stoul(argv[++i])); }
|
||||
catch (...) {}
|
||||
if (quality > 6) quality = 1;
|
||||
}
|
||||
if (i + 1 < argc && argv[i + 1][0] != '-') {
|
||||
try { displayId = static_cast<uint32_t>(std::stoul(argv[++i])); }
|
||||
catch (...) {}
|
||||
}
|
||||
if (i + 1 < argc && argv[i + 1][0] != '-') {
|
||||
try { itemLevel = static_cast<uint32_t>(std::stoul(argv[++i])); }
|
||||
catch (...) {}
|
||||
}
|
||||
std::string path = zoneDir + "/items.json";
|
||||
nlohmann::json doc = nlohmann::json::object({{"items",
|
||||
nlohmann::json::array()}});
|
||||
if (fs::exists(path)) {
|
||||
std::ifstream in(path);
|
||||
try { in >> doc; } catch (...) {
|
||||
std::fprintf(stderr,
|
||||
"add-item: %s exists but is not valid JSON\n",
|
||||
path.c_str());
|
||||
return 1;
|
||||
}
|
||||
if (!doc.contains("items") || !doc["items"].is_array()) {
|
||||
doc["items"] = nlohmann::json::array();
|
||||
}
|
||||
}
|
||||
// Auto-assign id if user passed 0 / nothing — pick the
|
||||
// smallest unused positive integer so the items.json
|
||||
// numbering stays contiguous.
|
||||
if (id == 0) {
|
||||
std::set<uint32_t> used;
|
||||
for (const auto& it : doc["items"]) {
|
||||
if (it.contains("id") && it["id"].is_number_unsigned()) {
|
||||
used.insert(it["id"].get<uint32_t>());
|
||||
}
|
||||
}
|
||||
id = 1;
|
||||
while (used.count(id)) ++id;
|
||||
}
|
||||
// Reject duplicate id so the user notices a collision.
|
||||
for (const auto& it : doc["items"]) {
|
||||
if (it.contains("id") && it["id"].is_number_unsigned() &&
|
||||
it["id"].get<uint32_t>() == id) {
|
||||
std::fprintf(stderr,
|
||||
"add-item: id %u already in use in %s\n",
|
||||
id, path.c_str());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
nlohmann::json item = {
|
||||
{"id", id},
|
||||
{"name", name},
|
||||
{"quality", quality},
|
||||
{"displayId", displayId},
|
||||
{"itemLevel", itemLevel},
|
||||
{"stackable", 1},
|
||||
};
|
||||
doc["items"].push_back(item);
|
||||
std::ofstream out(path);
|
||||
if (!out) {
|
||||
std::fprintf(stderr,
|
||||
"add-item: failed to write %s\n", path.c_str());
|
||||
return 1;
|
||||
}
|
||||
out << doc.dump(2);
|
||||
out.close();
|
||||
static const char* qualityNames[] = {
|
||||
"poor", "common", "uncommon", "rare", "epic",
|
||||
"legendary", "artifact"
|
||||
};
|
||||
std::printf("Added item '%s' (id=%u, quality=%s, ilvl=%u) to %s (now %zu total)\n",
|
||||
name.c_str(), id,
|
||||
qualityNames[quality], itemLevel,
|
||||
path.c_str(), doc["items"].size());
|
||||
return 0;
|
||||
} else if (std::strcmp(argv[i], "--scaffold-zone") == 0 && i + 1 < argc) {
|
||||
// Generate a minimal valid empty zone — useful for kickstarting
|
||||
// a new authoring session without needing to launch the GUI.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue