feat: add parseLootTableJson and parseTagJson to DataPack
This commit is contained in:
1 parent
7991f6c660
commit
c2493cb50a
1 file changed
+160
@@ -474,3 +474,163 @@ bool parseRecipeJson(const JsonValue& root, const std::string& defaultSpace, Rec
|
|||||||
parsed.allowMirror = root.boolOr("mirror", true);
|
parsed.allowMirror = root.boolOr("mirror", true);
|
||||||
} else if (kindName == "craftingShapeless") {
|
} else if (kindName == "craftingShapeless") {
|
||||||
parsed.kind = RecipeData::Kind::Shapeless;
|
parsed.kind = RecipeData::Kind::Shapeless;
|
||||||
|
const JsonValue* ingredients = root.find("ingredients");
|
||||||
|
if (ingredients == nullptr || !ingredients->isArray() || ingredients->elements().empty()) {
|
||||||
|
problem = "\"ingredients\" must be a non empty array";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ingredients->elements().size() > static_cast<std::size_t>(craftGridCells)) {
|
||||||
|
problem = "\"ingredients\" holds more than the grid can take";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const JsonValue& element : ingredients->elements()) {
|
||||||
|
if (!element.isString()) {
|
||||||
|
problem = "\"ingredients\" holds a non string entry";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ResourceId id;
|
||||||
|
ItemId ingredient = ItemId::None;
|
||||||
|
if (!ResourceId::parse(element.stringValue(), defaultSpace, id) ||
|
||||||
|
!resolveItemId(id, ingredient)) {
|
||||||
|
problem = "no such item: " + element.stringValue();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
parsed.ingredients.push_back(ingredient);
|
||||||
|
}
|
||||||
|
} else if (kindName == "smelting") {
|
||||||
|
parsed.kind = RecipeData::Kind::Smelting;
|
||||||
|
if (!readItemField(root, "ingredient", defaultSpace, parsed.smeltInput, problem))
|
||||||
|
return false;
|
||||||
|
parsed.smeltSeconds = static_cast<float>(root.numberOr("seconds", 10.0));
|
||||||
|
parsed.experience = static_cast<float>(root.numberOr("experience", 0.0));
|
||||||
|
if (parsed.smeltSeconds <= 0.0f) {
|
||||||
|
problem = "\"seconds\" must be above zero";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (parsed.experience < 0.0f) {
|
||||||
|
problem = "\"experience\" cannot be negative";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
problem = "unknown recipe type: " + kindName;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
out = parsed;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseLootTableJson(const JsonValue& root, const std::string& defaultSpace, LootTable& out,
|
||||||
|
std::string& problem) {
|
||||||
|
if (!root.isObject()) {
|
||||||
|
problem = "a loot table must be an object";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const JsonValue* pools = root.find("pools");
|
||||||
|
if (pools == nullptr || !pools->isArray() || pools->elements().empty()) {
|
||||||
|
problem = "\"pools\" must be a non empty array";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LootTable parsed;
|
||||||
|
for (const JsonValue& poolJson : pools->elements()) {
|
||||||
|
if (!poolJson.isObject()) {
|
||||||
|
problem = "every pool must be an object";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LootPool pool;
|
||||||
|
if (!readCountRange(poolJson, "rolls", pool.minRolls, pool.maxRolls, problem)) return false;
|
||||||
|
pool.bonusRollsPerLooting = static_cast<int>(poolJson.intOr("bonusRollsPerLooting", 0));
|
||||||
|
if (pool.bonusRollsPerLooting < 0) {
|
||||||
|
problem = "\"bonusRollsPerLooting\" cannot be negative";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const JsonValue* entries = poolJson.find("entries");
|
||||||
|
if (entries == nullptr || !entries->isArray() || entries->elements().empty()) {
|
||||||
|
problem = "every pool needs a non empty \"entries\" array";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const JsonValue& entryJson : entries->elements()) {
|
||||||
|
if (!entryJson.isObject()) {
|
||||||
|
problem = "every loot entry must be an object";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LootEntry entry;
|
||||||
|
if (!readItemField(entryJson, "item", defaultSpace, entry.item, problem)) return false;
|
||||||
|
entry.weight = static_cast<int>(entryJson.intOr("weight", 1));
|
||||||
|
if (entry.weight < 1) {
|
||||||
|
problem = "\"weight\" must be at least 1";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!readCountRange(entryJson, "count", entry.minCount, entry.maxCount, problem))
|
||||||
|
return false;
|
||||||
|
// An authored range is meant to be rolled; the roller only does that
|
||||||
|
// when the CountRange function is on the entry.
|
||||||
|
if (entry.maxCount > entry.minCount) entry.functions |= LootEntry::CountRange;
|
||||||
|
entry.chance = static_cast<float>(entryJson.numberOr("chance", 1.0));
|
||||||
|
entry.chancePerLevel = static_cast<float>(entryJson.numberOr("chancePerLevel", 0.0));
|
||||||
|
if (entry.chance < 0.0f || entry.chance > 1.0f) {
|
||||||
|
problem = "\"chance\" must sit between 0 and 1";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!readFlagList(entryJson, "conditions", lootConditionFlags,
|
||||||
|
sizeof(lootConditionFlags) / sizeof(lootConditionFlags[0]),
|
||||||
|
entry.conditions, problem))
|
||||||
|
return false;
|
||||||
|
if (!readFlagList(entryJson, "functions", lootFunctionFlags,
|
||||||
|
sizeof(lootFunctionFlags) / sizeof(lootFunctionFlags[0]),
|
||||||
|
entry.functions, problem))
|
||||||
|
return false;
|
||||||
|
pool.entries.push_back(entry);
|
||||||
|
}
|
||||||
|
parsed.pools.push_back(pool);
|
||||||
|
}
|
||||||
|
out = parsed;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseTagJson(const JsonValue& root, const std::string& defaultSpace, BlockTag& out,
|
||||||
|
std::string& problem) {
|
||||||
|
if (!root.isObject()) {
|
||||||
|
problem = "a tag must be an object";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const JsonValue* values = root.find("values");
|
||||||
|
if (values == nullptr || !values->isArray()) {
|
||||||
|
problem = "\"values\" must be an array";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
BlockTag parsed;
|
||||||
|
parsed.replace = root.boolOr("replace", false);
|
||||||
|
for (const JsonValue& element : values->elements()) {
|
||||||
|
if (!element.isString()) {
|
||||||
|
problem = "\"values\" holds a non string entry";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
BlockTag::Entry entry;
|
||||||
|
std::string text = element.stringValue();
|
||||||
|
if (!text.empty() && text[0] == '#') {
|
||||||
|
entry.reference = true;
|
||||||
|
text = text.substr(1);
|
||||||
|
}
|
||||||
|
if (!ResourceId::parse(text, defaultSpace, entry.id)) {
|
||||||
|
problem = "not a valid resource id: " + element.stringValue();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
parsed.entries.push_back(entry);
|
||||||
|
}
|
||||||
|
out = parsed;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataPackLoader::addPack(DataPack pack) { loaded.push_back(std::move(pack)); }
|
||||||
|
|
||||||
|
void DataPackLoader::clear() {
|
||||||
|
loaded.clear();
|
||||||
|
problems.clear();
|
||||||
|
order.clear();
|
||||||
|
folders.clear();
|
||||||
|
recipeSet.clear();
|
||||||
|
lootSet.clear();
|
||||||
|
blockTagSet.clear();
|
||||||
|
itemTagSet.clear();
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user