feat: add advancementTriggerName and parseAdvancementTriggerName
This commit is contained in:
1 parent
8248b4b51e
commit
92ed91dbe4
1 file changed
+163
@@ -328,3 +328,166 @@ bool AdvancementTree::cycleFrom(const AdvancementId& id) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AdvancementTree::hasCycle() const {
|
||||||
|
for (const auto& node : nodes)
|
||||||
|
if (cycleFrom(node.first)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<AdvancementId> AdvancementTree::missingParents() const {
|
||||||
|
std::vector<AdvancementId> out;
|
||||||
|
for (const auto& node : nodes) {
|
||||||
|
if (node.second.isRoot()) continue;
|
||||||
|
if (find(node.second.parent) == nullptr) out.push_back(node.first);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<AdvancementId> AdvancementProgress::notify(const AdvancementCriterion::Event& event,
|
||||||
|
long long tick) {
|
||||||
|
std::vector<AdvancementId> justGranted;
|
||||||
|
for (const AdvancementId& id : source->ids()) {
|
||||||
|
const Advancement* node = source->find(id);
|
||||||
|
bool touched = false;
|
||||||
|
for (const AdvancementCriterion& criterion : node->criteria) {
|
||||||
|
if (!criterion.accepts(event)) continue;
|
||||||
|
CriterionState& state = states[id][criterion.name];
|
||||||
|
if (state.done) continue;
|
||||||
|
state.progress += event.amount;
|
||||||
|
if (state.progress >= criterion.requiredCount) {
|
||||||
|
state.progress = criterion.requiredCount;
|
||||||
|
state.done = true;
|
||||||
|
state.tick = tick;
|
||||||
|
}
|
||||||
|
touched = true;
|
||||||
|
}
|
||||||
|
if (!touched || granted(id)) continue;
|
||||||
|
if (!node->satisfiedBy(completedCriteria(id))) continue;
|
||||||
|
|
||||||
|
grants[id] = tick;
|
||||||
|
experience += node->reward.experience;
|
||||||
|
for (const ResourceId& recipe : node->reward.recipes) {
|
||||||
|
if (std::find(recipes.begin(), recipes.end(), recipe) == recipes.end())
|
||||||
|
recipes.push_back(recipe);
|
||||||
|
}
|
||||||
|
for (const ResourceId& table : node->reward.lootTables) {
|
||||||
|
if (std::find(lootTables.begin(), lootTables.end(), table) == lootTables.end())
|
||||||
|
lootTables.push_back(table);
|
||||||
|
}
|
||||||
|
justGranted.push_back(id);
|
||||||
|
}
|
||||||
|
return justGranted;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AdvancementProgress::criterionDone(const AdvancementId& id,
|
||||||
|
const std::string& criterion) const {
|
||||||
|
auto node = states.find(id);
|
||||||
|
if (node == states.end()) return false;
|
||||||
|
auto state = node->second.find(criterion);
|
||||||
|
return state != node->second.end() && state->second.done;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AdvancementProgress::criterionProgress(const AdvancementId& id,
|
||||||
|
const std::string& criterion) const {
|
||||||
|
auto node = states.find(id);
|
||||||
|
if (node == states.end()) return 0;
|
||||||
|
auto state = node->second.find(criterion);
|
||||||
|
return state == node->second.end() ? 0 : state->second.progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
long long AdvancementProgress::criterionTick(const AdvancementId& id,
|
||||||
|
const std::string& criterion) const {
|
||||||
|
auto node = states.find(id);
|
||||||
|
if (node == states.end()) return -1;
|
||||||
|
auto state = node->second.find(criterion);
|
||||||
|
return state == node->second.end() ? -1 : state->second.tick;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> AdvancementProgress::completedCriteria(const AdvancementId& id) const {
|
||||||
|
std::vector<std::string> out;
|
||||||
|
auto node = states.find(id);
|
||||||
|
if (node == states.end()) return out;
|
||||||
|
for (const auto& state : node->second)
|
||||||
|
if (state.second.done) out.push_back(state.first);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AdvancementProgress::granted(const AdvancementId& id) const { return grants.count(id) > 0u; }
|
||||||
|
|
||||||
|
long long AdvancementProgress::grantedTick(const AdvancementId& id) const {
|
||||||
|
auto found = grants.find(id);
|
||||||
|
return found == grants.end() ? -1 : found->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AdvancementProgress::visible(const AdvancementId& id) const {
|
||||||
|
const Advancement* node = source->find(id);
|
||||||
|
if (node == nullptr) return false;
|
||||||
|
if (!node->hidden) return true;
|
||||||
|
if (granted(id)) return true;
|
||||||
|
return !node->isRoot() && granted(node->parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<AdvancementId> AdvancementProgress::grantedIds() const {
|
||||||
|
std::vector<AdvancementId> out;
|
||||||
|
out.reserve(grants.size());
|
||||||
|
for (const auto& grant : grants) out.push_back(grant.first);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* advancementTriggerName(AdvancementCriterion::Trigger trigger) {
|
||||||
|
switch (trigger) {
|
||||||
|
case AdvancementCriterion::Trigger::ItemObtained: return "itemObtained";
|
||||||
|
case AdvancementCriterion::Trigger::MobKilled: return "mobKilled";
|
||||||
|
case AdvancementCriterion::Trigger::DimensionEntered: return "dimensionEntered";
|
||||||
|
case AdvancementCriterion::Trigger::PotionBrewed: return "potionBrewed";
|
||||||
|
case AdvancementCriterion::Trigger::VillagerTraded: return "villagerTraded";
|
||||||
|
case AdvancementCriterion::Trigger::BlockBroken: return "blockBroken";
|
||||||
|
case AdvancementCriterion::Trigger::Count: break;
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseAdvancementTriggerName(const std::string& text, AdvancementCriterion::Trigger& out) {
|
||||||
|
for (int i = 0; i < static_cast<int>(AdvancementCriterion::Trigger::Count); ++i) {
|
||||||
|
AdvancementCriterion::Trigger trigger = static_cast<AdvancementCriterion::Trigger>(i);
|
||||||
|
if (text == advancementTriggerName(trigger)) {
|
||||||
|
out = trigger;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseAdvancementJson(const JsonValue& root, const std::string& defaultSpace, Advancement& out,
|
||||||
|
std::string& problem) {
|
||||||
|
if (!root.isObject()) {
|
||||||
|
problem = "an advancement must be an object";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Advancement parsed;
|
||||||
|
bool present = false;
|
||||||
|
if (!readOptionalResource(root, "parent", defaultSpace, parsed.parent, present, problem))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (const JsonValue* display = root.find("display")) {
|
||||||
|
if (!display->isObject()) {
|
||||||
|
problem = "\"display\" must be an object";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
parsed.title = display->stringOr("title", "");
|
||||||
|
parsed.description = display->stringOr("description", "");
|
||||||
|
parsed.hidden = display->boolOr("hidden", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const JsonValue* criteria = root.find("criteria");
|
||||||
|
if (criteria == nullptr || !criteria->isObject() || criteria->members().empty()) {
|
||||||
|
problem = "\"criteria\" must be a non empty object";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const JsonValue::Member& member : criteria->members()) {
|
||||||
|
AdvancementCriterion criterion;
|
||||||
|
if (!parseCriterionJson(member.first, member.second, defaultSpace, criterion, problem))
|
||||||
|
return false;
|
||||||
|
parsed.criteria.push_back(criterion);
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user