From 77e7fe9c97e6ad5bd9b519798f8cf23546ba75ed Mon Sep 17 00:00:00 2001 From: DualFroz Date: Sun, 6 Sep 2026 22:30:12 +0200 Subject: [PATCH] feat: add layoutFor to ContainerMenu --- core/src/ContainerMenu.cpp | 155 +++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/core/src/ContainerMenu.cpp b/core/src/ContainerMenu.cpp index c929d20..aa898ce 100644 --- a/core/src/ContainerMenu.cpp +++ b/core/src/ContainerMenu.cpp @@ -154,3 +154,158 @@ const char* menuSlotRoleName(MenuSlot::Role role) { namespace { +std::vector buildLayout(MenuKind kind, MenuLayout& layout) { + std::vector slots; + layout = MenuLayout{}; + layout.kind = kind; + + switch (kind) { + case MenuKind::PlayerInventory: { + layout.craftFirst = 0; + layout.craftWidth = 2; + layout.craftHeight = 2; + appendSection(slots, MenuSlot::Role::CraftInput, 4, SlotFilter::Kind::Any, false, 0); + layout.resultSlot = static_cast(slots.size()); + appendSection(slots, MenuSlot::Role::CraftResult, 1, SlotFilter::Kind::Nothing, true, 0); + appendPlayerSections(slots, layout, true); + break; + } + case MenuKind::CraftingTable: { + layout.craftFirst = 0; + layout.craftWidth = 3; + layout.craftHeight = 3; + appendSection(slots, MenuSlot::Role::CraftInput, 9, SlotFilter::Kind::Any, false, 0); + layout.resultSlot = static_cast(slots.size()); + appendSection(slots, MenuSlot::Role::CraftResult, 1, SlotFilter::Kind::Nothing, true, 0); + appendPlayerSections(slots, layout, false); + break; + } + case MenuKind::Chest: + case MenuKind::LargeChest: { + int size = kind == MenuKind::Chest ? 27 : 54; + layout.storageFirst = 0; + layout.storageCount = size; + appendSection(slots, MenuSlot::Role::Storage, size, SlotFilter::Kind::Any, false, 0); + appendPlayerSections(slots, layout, false); + break; + } + case MenuKind::Furnace: { + layout.storageFirst = 0; + layout.storageCount = 3; + appendSection(slots, MenuSlot::Role::SmeltInput, 1, SlotFilter::Kind::Smeltable, false, 0); + appendSection(slots, MenuSlot::Role::FuelInput, 1, SlotFilter::Kind::Fuel, false, 0); + appendSection(slots, MenuSlot::Role::SmeltOutput, 1, SlotFilter::Kind::Nothing, true, 0); + appendPlayerSections(slots, layout, false); + break; + } + case MenuKind::BrewingStand: { + layout.storageFirst = 0; + layout.storageCount = 5; + appendSection(slots, MenuSlot::Role::BrewBottle, 3, SlotFilter::Kind::Any, false, 1); + appendSection(slots, MenuSlot::Role::BrewIngredient, 1, + SlotFilter::Kind::BrewIngredient, false, 0); + appendSection(slots, MenuSlot::Role::FuelInput, 1, SlotFilter::Kind::Fuel, false, 0); + appendPlayerSections(slots, layout, false); + break; + } + case MenuKind::EnchantingTable: { + layout.storageFirst = 0; + layout.storageCount = 2; + appendSection(slots, MenuSlot::Role::EnchantItem, 1, SlotFilter::Kind::Enchantable, + false, 0); + appendSection(slots, MenuSlot::Role::EnchantLapis, 1, SlotFilter::Kind::Lapis, false, 0); + appendPlayerSections(slots, layout, false); + break; + } + case MenuKind::Anvil: { + layout.storageFirst = 0; + layout.storageCount = 3; + appendSection(slots, MenuSlot::Role::AnvilInput, 2, SlotFilter::Kind::Repairable, + false, 0); + appendSection(slots, MenuSlot::Role::AnvilResult, 1, SlotFilter::Kind::Nothing, true, 0); + appendPlayerSections(slots, layout, false); + break; + } + case MenuKind::Villager: { + layout.storageFirst = 0; + layout.storageCount = 3; + appendSection(slots, MenuSlot::Role::TradeInput, 2, SlotFilter::Kind::Any, false, 0); + appendSection(slots, MenuSlot::Role::TradeResult, 1, SlotFilter::Kind::Nothing, true, 0); + appendPlayerSections(slots, layout, false); + break; + } + case MenuKind::Hopper: { + layout.storageFirst = 0; + layout.storageCount = 5; + appendSection(slots, MenuSlot::Role::Storage, 5, SlotFilter::Kind::Any, false, 0); + appendPlayerSections(slots, layout, false); + break; + } + case MenuKind::Count: + break; + } + + layout.totalSlots = static_cast(slots.size()); + return slots; +} + +} // namespace + +MenuLayout layoutFor(MenuKind kind) { + MenuLayout layout; + buildLayout(kind, layout); + return layout; +} + +CraftingView::CraftingView(ContainerMenu& menu) : menu(&menu) {} + +int CraftingView::width() const { return menu->layout().craftWidth; } +int CraftingView::height() const { return menu->layout().craftHeight; } +int CraftingView::cellCount() const { return menu->hasCrafting() ? menu->layout().craftCells() : 0; } + +MetaStack& CraftingView::input(int x, int y) { return inputAt(y * width() + x); } +const MetaStack& CraftingView::input(int x, int y) const { return inputAt(y * width() + x); } + +MetaStack& CraftingView::inputAt(int cell) { + return menu->stackAt(menu->layout().craftFirst + cell); +} + +const MetaStack& CraftingView::inputAt(int cell) const { + return menu->stackAt(menu->layout().craftFirst + cell); +} + +CraftGrid CraftingView::gridOfIds() const { + CraftGrid grid{}; + int w = width(); + for (int cell = 0; cell < cellCount(); ++cell) { + const MetaStack& stack = inputAt(cell); + if (stack.empty()) continue; + int row = cell / w; + int column = cell % w; + grid[static_cast(row * craftGridWidth + column)] = stack.item; + } + return grid; +} + +void CraftingView::refresh() { + int resultSlot = menu->layout().resultSlot; + if (resultSlot < 0) return; + MetaStack& target = menu->stackAt(resultSlot); + if (!menu->hasCrafting()) { + target.clear(); + return; + } + CraftResult match = menu->registry()->craftMatch(gridOfIds()); + if (!match.valid()) { + target.clear(); + return; + } + target = makeStack(match.item, match.count); +} + +const MetaStack& CraftingView::result() const { + return menu->resultStack(); +} + +bool CraftingView::hasResult() const { return !result().empty(); } +