From 4602896f82b8ccfd01346486bee9477a324f9bbf Mon Sep 17 00:00:00 2001 From: DualFroz Date: Wed, 2 Sep 2026 15:24:26 +0200 Subject: [PATCH] feat(vf): extend DataPack --- core/include/vf/DataPack.h | 98 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/core/include/vf/DataPack.h b/core/include/vf/DataPack.h index 23303f1..26801e2 100644 --- a/core/include/vf/DataPack.h +++ b/core/include/vf/DataPack.h @@ -154,3 +154,101 @@ struct BlockTag { bool contains(const ResourceId& member) const; }; +// Tags by id, with references between them flattened on demand. +class TagRegistry { +public: + // Applies replace/append semantics against what is already registered. + void define(const BlockTag& tag); + void clear(); + + bool has(const ResourceId& id) const; + const BlockTag* find(const ResourceId& id) const; + std::vector ids() const; + std::size_t size() const { return tags.size(); } + + // Flattens nested references into plain members, in declaration order and + // without duplicates. False when a reference cycles or names an unknown + // tag; `problem` then says which. + bool resolve(const ResourceId& id, std::vector& out) const; + bool resolve(const ResourceId& id, std::vector& out, std::string& problem) const; + + // True when the flattened tag holds `member`. + bool contains(const ResourceId& id, const ResourceId& member) const; + // True when following references from `id` comes back to a tag already on + // the path. + bool hasCycle(const ResourceId& id) const; + +private: + std::map tags; +}; + +// Loads any number of packs into one merged view. Packs are applied in order of +// meta().priority, insertion order breaking ties; a later pack overwrites a +// resource an earlier one defined, except for tags, which append unless the +// later tag sets "replace". +class DataPackLoader { +public: + void addPack(DataPack pack); + void clear(); + + // Parses every pack.json and every data/**/**.json, then interprets the + // known folders. Returns true when nothing was rejected; either way the + // resources that did load are available. + bool load(); + + const std::vector& errors() const { return problems; } + const std::vector& packs() const { return loaded; } + // Pack names in the order they were applied. + std::vector applyOrder() const; + + const std::map& recipes() const { return recipeSet; } + const std::map& lootTables() const { return lootSet; } + const TagRegistry& blockTags() const { return blockTagSet; } + const TagRegistry& itemTags() const { return itemTagSet; } + + const RecipeData* recipe(const ResourceId& id) const; + const LootTable* lootTable(const ResourceId& id) const; + + // Every parsed document that lived under data///, keyed by + // resource id. Advancement.h reads its own folder back out of here. + const std::map* documentsIn(const std::string& folder) const; + + // Registers every loaded recipe with an existing registry, on top of the + // built in ones. Returns how many were added. + int applyTo(CraftingRegistry& registry) const; + + // Rolls a loaded table through the existing loot roller. + LootRoll roll(const ResourceId& table, const LootContext& context) const; + + // Flattened tag members resolved against the block and item palettes. + // Members that name nothing in the palette are dropped. + bool blocksInTag(const ResourceId& tag, std::vector& out) const; + bool itemsInTag(const ResourceId& tag, std::vector& out) const; + + void reportError(const std::string& pack, const std::string& file, const std::string& reason); + +private: + void loadPack(DataPack& pack); + void ingest(DataPack& pack, const std::string& file, const std::string& folder, + const ResourceId& id, const JsonValue& root); + + std::vector loaded; + std::vector problems; + std::vector order; + std::map> folders; + std::map recipeSet; + std::map lootSet; + TagRegistry blockTagSet; + TagRegistry itemTagSet; +}; + +// Parsers for the individual document kinds, exposed so a caller can read one +// document without building a pack around it. `problem` is filled on failure. +bool parseRecipeJson(const JsonValue& root, const std::string& defaultSpace, RecipeData& out, + std::string& problem); +bool parseLootTableJson(const JsonValue& root, const std::string& defaultSpace, LootTable& out, + std::string& problem); +bool parseTagJson(const JsonValue& root, const std::string& defaultSpace, BlockTag& out, + std::string& problem); + +} // namespace vf