feat(vf): extend ContainerMenu

This commit is contained in:
dualfroz committed 2026-09-02 11:21:17 +02:00
1 parent 48c7a48278
commit 54bbbed2f6
1 file changed
+104
+104
View File
@@ -158,3 +158,107 @@ public:
MetaStack& inputAt(int cell); MetaStack& inputAt(int cell);
const MetaStack& inputAt(int cell) const; const MetaStack& inputAt(int cell) const;
// Recomputes the result slot from the current grid. Cheap enough to call
// after every single change, which is exactly what the menu does.
void refresh();
const MetaStack& result() const;
bool hasResult() const;
// How many times the current grid could be crafted before running dry.
int maxCrafts() const;
// Takes the result once. Each input loses one item; a damageable ingredient
// is not eaten but comes back one durability point worse, and a broken one
// vanishes. Returns the crafted stack, empty when there was no recipe.
MetaStack takeResult();
// Shift-clicking the result: crafts until the grid runs out or the player
// has no room, pushing every batch into the player's sections.
int craftAll(int limit);
private:
void consumeOneRound();
CraftGrid gridOfIds() const;
ContainerMenu* menu;
};
class ContainerMenu {
public:
explicit ContainerMenu(MenuKind kind, const CraftingRegistry* registry = nullptr);
MenuKind kind() const { return menuKind; }
const MenuLayout& layout() const { return menuLayout; }
const CraftingRegistry* registry() const { return craftingRegistry; }
int slotCount() const { return static_cast<int>(slots.size()); }
MenuSlot& slot(int index) { return slots[static_cast<std::size_t>(index)]; }
const MenuSlot& slot(int index) const { return slots[static_cast<std::size_t>(index)]; }
MetaStack& stackAt(int index) { return slot(index).cell.stack; }
const MetaStack& stackAt(int index) const { return slot(index).cell.stack; }
bool validIndex(int index) const { return index >= 0 && index < slotCount(); }
bool canPlace(int index, const MetaStack& incoming) const;
// True when the slot's contents may leave it. Every slot allows this; the
// asymmetry is deliberate, a result slot gives but never takes.
bool canTake(int index) const;
// Puts what fits into the slot, honouring the filter and the cap.
int insertAt(int index, MetaStack& incoming);
MetaStack takeFrom(int index, int amount);
// Section walkers used by shift-click and by the double-click gather.
std::vector<int> slotsWithRole(MenuSlot::Role role) const;
std::vector<int> playerSectionSlots() const;
std::vector<int> containerSectionSlots() const;
bool isPlayerSection(int index) const;
// Fills matching stacks first and only then empty slots, which is the order
// a shift-click has to follow to feel right.
int distributeInto(const std::vector<int>& targets, MetaStack& incoming);
int totalOf(ItemId item) const;
int totalItems() const;
int usedSlots() const;
// Binds a world Container as the storage section. The menu copies the
// container in, and syncToContainer writes it back. ItemSlot has no room
// for enchantments or names, so anything richer than durability survives
// only inside the menu (or through stackListToNbt).
void bindContainer(Container& container);
void syncFromContainer();
void syncToContainer();
bool hasContainer() const { return bound != nullptr; }
void unbind();
// Creative mode is the one thing allowed to conjure items: a middle click
// clones a stack instead of doing nothing.
void setCreativeMode(bool enabled) { creative = enabled; }
bool creativeMode() const { return creative; }
bool hasCrafting() const { return menuLayout.hasCrafting() && craftingRegistry != nullptr; }
// A two-pointer handle, cheap to hand out by value and never stale.
CraftingView crafting();
const MetaStack& resultStack() const;
// Called by CraftingView and by every slot action that touched a craft
// input, so the result slot is never stale.
void refreshResult();
// Persists every slot losslessly, unlike the Container projection.
NbtTag toNbt() const;
bool fromNbt(const NbtTag& tag);
private:
void buildSlots();
MenuKind menuKind;
MenuLayout menuLayout;
const CraftingRegistry* craftingRegistry = nullptr;
std::vector<MenuSlot> slots;
Container* bound = nullptr;
bool creative = false;
};
} // namespace vf