From 92ed91dbe4ec7249ef9a69f3861d7240e8d7e81e Mon Sep 17 00:00:00 2001 From: DualFroz Date: Sun, 6 Sep 2026 16:17:16 +0200 Subject: [PATCH] feat: add advancementTriggerName and parseAdvancementTriggerName --- core/src/Advancement.cpp | 163 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/core/src/Advancement.cpp b/core/src/Advancement.cpp index 2f51439..a6111bc 100644 --- a/core/src/Advancement.cpp +++ b/core/src/Advancement.cpp @@ -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 AdvancementTree::missingParents() const { + std::vector 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 AdvancementProgress::notify(const AdvancementCriterion::Event& event, + long long tick) { + std::vector 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 AdvancementProgress::completedCriteria(const AdvancementId& id) const { + std::vector 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 AdvancementProgress::grantedIds() const { + std::vector 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(AdvancementCriterion::Trigger::Count); ++i) { + AdvancementCriterion::Trigger trigger = static_cast(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); + } +