feat: extend DataPack
This commit is contained in:
1 parent
c2493cb50a
commit
db3b841aec
1 file changed
+184
@@ -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
|
||||
Reference in new issue
Block a user