feat: extend DataPack

This commit is contained in:
dualfroz committed 2026-09-07 13:27:21 +02:00
1 parent c2493cb50a
commit db3b841aec
1 file changed
+184
+184
View File
@@ -634,3 +634,187 @@ void DataPackLoader::clear() {
itemTagSet.clear();
}
void DataPackLoader::reportError(const std::string& pack, const std::string& file,
const std::string& reason) {
DataPackError failure;
failure.pack = pack;
failure.file = file;
failure.reason = reason;
problems.push_back(failure);
}
bool DataPackLoader::load() {
problems.clear();
order.clear();
folders.clear();
recipeSet.clear();
lootSet.clear();
blockTagSet.clear();
itemTagSet.clear();
std::vector<std::size_t> sequence(loaded.size());
for (std::size_t i = 0u; i < loaded.size(); ++i) sequence[i] = i;
std::stable_sort(sequence.begin(), sequence.end(), [this](std::size_t a, std::size_t b) {
return loaded[a].meta().priority < loaded[b].meta().priority;
});
for (std::size_t index : sequence) {
loadPack(loaded[index]);
order.push_back(loaded[index].meta().name);
}
return problems.empty();
}
void DataPackLoader::loadPack(DataPack& pack) {
if (const std::string* metaText = pack.fileContents("pack.json")) {
JsonParseResult parsed = parseJson(*metaText);
if (!parsed.ok) {
DataPackError failure;
failure.pack = pack.meta().name;
failure.file = "pack.json";
failure.reason = parsed.error.message;
failure.line = parsed.error.line;
failure.column = parsed.error.column;
problems.push_back(failure);
} else {
DataPackMeta meta;
std::string problem;
if (DataPackMeta::fromJson(parsed.root, meta, problem)) {
int keptPriority = pack.meta().priority;
pack.meta() = meta;
if (parsed.root.find("priority") == nullptr) pack.meta().priority = keptPriority;
} else {
reportError(pack.meta().name, "pack.json", problem);
}
}
}
for (const std::string& file : pack.filesUnder("data/")) {
if (!endsWith(file, ".json")) continue;
std::string space;
std::string folder;
std::string name;
if (!splitDataPath(file, space, folder, name)) {
reportError(pack.meta().name, file,
"path does not match data/<space>/<folder>/<name>.json with a known folder");
continue;
}
ResourceId id(space, name);
if (!id.valid()) {
reportError(pack.meta().name, file, "not a valid resource id: " + id.text());
continue;
}
JsonParseResult parsed = parseJson(*pack.fileContents(file));
if (!parsed.ok) {
DataPackError failure;
failure.pack = pack.meta().name;
failure.file = file;
failure.reason = parsed.error.message;
failure.line = parsed.error.line;
failure.column = parsed.error.column;
problems.push_back(failure);
continue;
}
ingest(pack, file, folder, id, parsed.root);
}
}
void DataPackLoader::ingest(DataPack& pack, const std::string& file, const std::string& folder,
const ResourceId& id, const JsonValue& root) {
folders[folder][id] = root;
const std::string& defaultSpace = pack.meta().defaultSpace;
std::string problem;
if (folder == "recipes") {
RecipeData recipe;
if (!parseRecipeJson(root, defaultSpace, recipe, problem)) {
reportError(pack.meta().name, file, problem);
return;
}
recipe.id = id;
recipeSet[id] = recipe;
return;
}
if (folder == "lootTables") {
LootTable table;
if (!parseLootTableJson(root, defaultSpace, table, problem)) {
reportError(pack.meta().name, file, problem);
return;
}
lootSet[id] = table;
return;
}
if (folder == "tags/blocks" || folder == "tags/items") {
BlockTag tag;
if (!parseTagJson(root, defaultSpace, tag, problem)) {
reportError(pack.meta().name, file, problem);
return;
}
tag.id = id;
if (folder == "tags/blocks") {
blockTagSet.define(tag);
} else {
itemTagSet.define(tag);
}
}
}
std::vector<std::string> DataPackLoader::applyOrder() const { return order; }
const RecipeData* DataPackLoader::recipe(const ResourceId& id) const {
auto found = recipeSet.find(id);
return found == recipeSet.end() ? nullptr : &found->second;
}
const LootTable* DataPackLoader::lootTable(const ResourceId& id) const {
auto found = lootSet.find(id);
return found == lootSet.end() ? nullptr : &found->second;
}
const std::map<ResourceId, JsonValue>* DataPackLoader::documentsIn(const std::string& folder) const {
auto found = folders.find(folder);
return found == folders.end() ? nullptr : &found->second;
}
int DataPackLoader::applyTo(CraftingRegistry& registry) const {
int added = 0;
for (const auto& entry : recipeSet) {
const RecipeData& recipe = entry.second;
switch (recipe.kind) {
case RecipeData::Kind::Shaped: registry.addShaped(recipe.toShaped()); break;
case RecipeData::Kind::Shapeless: registry.addShapeless(recipe.toShapeless()); break;
case RecipeData::Kind::Smelting: registry.addSmelting(recipe.toSmelting()); break;
}
++added;
}
return added;
}
LootRoll DataPackLoader::roll(const ResourceId& table, const LootContext& context) const {
const LootTable* found = lootTable(table);
if (found == nullptr) return LootRoll();
return rollLootTable(*found, context);
}
bool DataPackLoader::blocksInTag(const ResourceId& tag, std::vector<Block>& out) const {
out.clear();
std::vector<ResourceId> members;
if (!blockTagSet.resolve(tag, members)) return false;
for (const ResourceId& member : members) {
Block block = Block::Air;
if (resolveBlockId(member, block)) out.push_back(block);
}
return true;
}
bool DataPackLoader::itemsInTag(const ResourceId& tag, std::vector<ItemId>& out) const {
out.clear();
std::vector<ResourceId> members;
if (!itemTagSet.resolve(tag, members)) return false;
for (const ResourceId& member : members) {
ItemId item = ItemId::None;
if (resolveItemId(member, item)) out.push_back(item);
}
return true;
}
} // namespace vf