From 8248b4b51ee4535fb723b98a46f78b35695e5761 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Sun, 6 Sep 2026 15:42:14 +0200 Subject: [PATCH] feat: extend Advancement --- core/src/Advancement.cpp | 156 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/core/src/Advancement.cpp b/core/src/Advancement.cpp index ebb5a8b..2f51439 100644 --- a/core/src/Advancement.cpp +++ b/core/src/Advancement.cpp @@ -172,3 +172,159 @@ bool parseCriterionJson(const std::string& criterionName, const JsonValue& root, return true; } +} // namespace + +AdvancementCriterion::Event AdvancementCriterion::Event::itemObtained(ItemId item, int amount) { + Event event; + event.trigger = Trigger::ItemObtained; + event.item = item; + event.amount = amount; + return event; +} + +AdvancementCriterion::Event AdvancementCriterion::Event::mobKilled(Species species) { + Event event; + event.trigger = Trigger::MobKilled; + event.species = species; + return event; +} + +AdvancementCriterion::Event AdvancementCriterion::Event::dimensionEntered(DimensionId dimension) { + Event event; + event.trigger = Trigger::DimensionEntered; + event.dimension = dimension; + return event; +} + +AdvancementCriterion::Event AdvancementCriterion::Event::potionBrewed(PotionKind potion) { + Event event; + event.trigger = Trigger::PotionBrewed; + event.potion = potion; + return event; +} + +AdvancementCriterion::Event AdvancementCriterion::Event::villagerTraded( + VillagerProfession profession, ItemId purchased) { + Event event; + event.trigger = Trigger::VillagerTraded; + event.profession = profession; + event.item = purchased; + return event; +} + +AdvancementCriterion::Event AdvancementCriterion::Event::blockBroken(Block block, ItemId tool) { + Event event; + event.trigger = Trigger::BlockBroken; + event.block = block; + event.tool = tool; + return event; +} + +bool AdvancementCriterion::accepts(const Event& event) const { + if (event.trigger != trigger) return false; + if ((matchMask & MatchItem) != 0u && event.item != item) return false; + if ((matchMask & MatchBlock) != 0u && event.block != block) return false; + if ((matchMask & MatchSpecies) != 0u && event.species != species) return false; + if ((matchMask & MatchDimension) != 0u && event.dimension != dimension) return false; + if ((matchMask & MatchPotion) != 0u && event.potion != potion) return false; + if ((matchMask & MatchProfession) != 0u && event.profession != profession) return false; + if ((matchMask & MatchTool) != 0u && event.tool != tool) return false; + return true; +} + +const AdvancementCriterion* Advancement::findCriterion(const std::string& criterionName) const { + for (const AdvancementCriterion& criterion : criteria) + if (criterion.name == criterionName) return &criterion; + return nullptr; +} + +bool Advancement::satisfiedBy(const std::vector& completed) const { + if (criteria.empty()) return false; + auto isComplete = [&completed](const std::string& name) { + return std::find(completed.begin(), completed.end(), name) != completed.end(); + }; + if (requirements.empty()) { + for (const AdvancementCriterion& criterion : criteria) + if (!isComplete(criterion.name)) return false; + return true; + } + for (const std::vector& group : requirements) { + bool any = false; + for (const std::string& name : group) + if (isComplete(name)) any = true; + if (!any) return false; + } + return true; +} + +std::vector Advancement::danglingRequirements() const { + std::vector out; + for (const std::vector& group : requirements) + for (const std::string& name : group) + if (findCriterion(name) == nullptr) out.push_back(name); + return out; +} + +bool AdvancementTree::add(const Advancement& advancement) { + if (!advancement.id.valid()) return false; + if (nodes.count(advancement.id) > 0u) return false; + nodes[advancement.id] = advancement; + return true; +} + +void AdvancementTree::clear() { nodes.clear(); } + +const Advancement* AdvancementTree::find(const AdvancementId& id) const { + auto found = nodes.find(id); + return found == nodes.end() ? nullptr : &found->second; +} + +std::vector AdvancementTree::ids() const { + std::vector out; + out.reserve(nodes.size()); + for (const auto& node : nodes) out.push_back(node.first); + return out; +} + +std::vector AdvancementTree::roots() const { + std::vector out; + for (const auto& node : nodes) + if (node.second.isRoot()) out.push_back(node.first); + return out; +} + +std::vector AdvancementTree::childrenOf(const AdvancementId& id) const { + std::vector out; + for (const auto& node : nodes) + if (!node.second.isRoot() && node.second.parent == id) out.push_back(node.first); + return out; +} + +int AdvancementTree::depthOf(const AdvancementId& id) const { + const Advancement* node = find(id); + if (node == nullptr) return -1; + int depth = 0; + AdvancementId walk = id; + for (std::size_t step = 0u; step <= nodes.size(); ++step) { + const Advancement* here = find(walk); + if (here == nullptr) return -1; + if (here->isRoot()) return depth; + walk = here->parent; + ++depth; + } + return -1; +} + +bool AdvancementTree::cycleFrom(const AdvancementId& id) const { + std::vector seen; + AdvancementId walk = id; + for (;;) { + for (const AdvancementId& visited : seen) + if (visited == walk) return true; + seen.push_back(walk); + const Advancement* here = find(walk); + if (here == nullptr || here->isRoot()) return false; + walk = here->parent; + } +} +