OverlayRecipeComponent.java

net.minecraft.client.gui.screens.recipebook.OverlayRecipeComponent

信息

  • 全限定名:net.minecraft.client.gui.screens.recipebook.OverlayRecipeComponent
  • 类型:public class
  • 包:net.minecraft.client.gui.screens.recipebook
  • 源码路径:src/main/java/net/minecraft/client/gui/screens/recipebook/OverlayRecipeComponent.java
  • 起始行号:L33
  • 实现:GuiEventListener, Renderable
  • 职责:

    TODO

字段/常量

  • OVERLAY_RECIPE_SPRITE

    • 类型: Identifier
    • 修饰符: private static final
    • 源码定位: L34
    • 说明:

      TODO

  • MAX_ROW

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L35
    • 说明:

      TODO

  • MAX_ROW_LARGE

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L36
    • 说明:

      TODO

  • ITEM_RENDER_SCALE

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L37
    • 说明:

      TODO

  • BUTTON_SIZE

    • 类型: int
    • 修饰符: public static final
    • 源码定位: L38
    • 说明:

      TODO

  • recipeButtons

    • 类型: List<OverlayRecipeComponent.OverlayRecipeButton>
    • 修饰符: private final
    • 源码定位: L39
    • 说明:

      TODO

  • isVisible

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L40
    • 说明:

      TODO

  • x

    • 类型: int
    • 修饰符: private
    • 源码定位: L41
    • 说明:

      TODO

  • y

    • 类型: int
    • 修饰符: private
    • 源码定位: L42
    • 说明:

      TODO

  • collection

    • 类型: RecipeCollection
    • 修饰符: private
    • 源码定位: L43
    • 说明:

      TODO

  • lastRecipeClicked

    • 类型: RecipeDisplayId
    • 修饰符: private
    • 源码定位: L44
    • 说明:

      TODO

  • slotSelectTime

    • 类型: SlotSelectTime
    • 修饰符: private final
    • 源码定位: L45
    • 说明:

      TODO

  • isFurnaceMenu

    • 类型: boolean
    • 修饰符: private final
    • 源码定位: L46
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.gui.screens.recipebook.OverlayRecipeComponent.OverlayCraftingRecipeButton

    • 类型: class
    • 修饰符: private
    • 源码定位: L165
    • 说明:

      TODO

  • net.minecraft.client.gui.screens.recipebook.OverlayRecipeComponent.OverlayRecipeButton

    • 类型: class
    • 修饰符: private abstract
    • 源码定位: L218
    • 说明:

      TODO

  • net.minecraft.client.gui.screens.recipebook.OverlayRecipeComponent.OverlayRecipeButton.Pos

    • 类型: record
    • 修饰符: protected
    • 源码定位: L259
    • 说明:

      TODO

  • net.minecraft.client.gui.screens.recipebook.OverlayRecipeComponent.OverlaySmeltingRecipeButton

    • 类型: class
    • 修饰符: private
    • 源码定位: L277
    • 说明:

      TODO

构造器

public OverlayRecipeComponent(SlotSelectTime slotSelectTime, boolean isFurnaceMenu) @ L48

  • 构造器名:OverlayRecipeComponent
  • 源码定位:L48
  • 修饰符:public

参数:

  • slotSelectTime: SlotSelectTime
  • isFurnaceMenu: boolean

说明:

TODO

方法

下面的方法块按源码顺序生成。

public void init(RecipeCollection collection, ContextMap context, boolean isFiltering, int buttonX, int buttonY, int centerX, int centerY, float buttonWidth) @ L53

  • 方法名:init
  • 源码定位:L53
  • 返回类型:void
  • 修饰符:public

参数:

  • collection: RecipeCollection
  • context: ContextMap
  • isFiltering: boolean
  • buttonX: int
  • buttonY: int
  • centerX: int
  • centerY: int
  • buttonWidth: float

说明:

TODO

public RecipeCollection getRecipeCollection() @ L103

  • 方法名:getRecipeCollection
  • 源码定位:L103
  • 返回类型:RecipeCollection
  • 修饰符:public

参数:

说明:

TODO

public RecipeDisplayId getLastRecipeClicked() @ L107

  • 方法名:getLastRecipeClicked
  • 源码定位:L107
  • 返回类型:RecipeDisplayId
  • 修饰符:public

参数:

说明:

TODO

public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) @ L111

  • 方法名:mouseClicked
  • 源码定位:L111
  • 返回类型:boolean
  • 修饰符:public

参数:

  • event: MouseButtonEvent
  • doubleClick: boolean

说明:

TODO

public boolean isMouseOver(double mouseX, double mouseY) @ L127

  • 方法名:isMouseOver
  • 源码定位:L127
  • 返回类型:boolean
  • 修饰符:public

参数:

  • mouseX: double
  • mouseY: double

说明:

TODO

public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) @ L132

  • 方法名:extractRenderState
  • 源码定位:L132
  • 返回类型:void
  • 修饰符:public

参数:

  • graphics: GuiGraphicsExtractor
  • mouseX: int
  • mouseY: int
  • a: float

说明:

TODO

public void setVisible(boolean visible) @ L147

  • 方法名:setVisible
  • 源码定位:L147
  • 返回类型:void
  • 修饰符:public

参数:

  • visible: boolean

说明:

TODO

public boolean isVisible() @ L151

  • 方法名:isVisible
  • 源码定位:L151
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public void setFocused(boolean focused) @ L155

  • 方法名:setFocused
  • 源码定位:L155
  • 返回类型:void
  • 修饰符:public

参数:

  • focused: boolean

说明:

TODO

public boolean isFocused() @ L159

  • 方法名:isFocused
  • 源码定位:L159
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class OverlayRecipeComponent implements GuiEventListener, Renderable {
    private static final Identifier OVERLAY_RECIPE_SPRITE = Identifier.withDefaultNamespace("recipe_book/overlay_recipe");
    private static final int MAX_ROW = 4;
    private static final int MAX_ROW_LARGE = 5;
    private static final float ITEM_RENDER_SCALE = 0.375F;
    public static final int BUTTON_SIZE = 25;
    private final List<OverlayRecipeComponent.OverlayRecipeButton> recipeButtons = Lists.newArrayList();
    private boolean isVisible;
    private int x;
    private int y;
    private RecipeCollection collection = RecipeCollection.EMPTY;
    private @Nullable RecipeDisplayId lastRecipeClicked;
    private final SlotSelectTime slotSelectTime;
    private final boolean isFurnaceMenu;
 
    public OverlayRecipeComponent(SlotSelectTime slotSelectTime, boolean isFurnaceMenu) {
        this.slotSelectTime = slotSelectTime;
        this.isFurnaceMenu = isFurnaceMenu;
    }
 
    public void init(
        RecipeCollection collection, ContextMap context, boolean isFiltering, int buttonX, int buttonY, int centerX, int centerY, float buttonWidth
    ) {
        this.collection = collection;
        List<RecipeDisplayEntry> craftable = collection.getSelectedRecipes(RecipeCollection.CraftableStatus.CRAFTABLE);
        List<RecipeDisplayEntry> unCraftable = isFiltering
            ? Collections.emptyList()
            : collection.getSelectedRecipes(RecipeCollection.CraftableStatus.NOT_CRAFTABLE);
        int craftables = craftable.size();
        int total = craftables + unCraftable.size();
        int maxRow = total <= 16 ? 4 : 5;
        int rows = (int)Math.ceil((float)total / maxRow);
        this.x = buttonX;
        this.y = buttonY;
        float rightPos = this.x + Math.min(total, maxRow) * 25;
        float maxLeftPos = centerX + 50;
        if (rightPos > maxLeftPos) {
            this.x = (int)(this.x - buttonWidth * (int)((rightPos - maxLeftPos) / buttonWidth));
        }
 
        float bottomPos = this.y + rows * 25;
        float maxBottomPos = centerY + 50;
        if (bottomPos > maxBottomPos) {
            this.y = (int)(this.y - buttonWidth * Mth.ceil((bottomPos - maxBottomPos) / buttonWidth));
        }
 
        float topPos = this.y;
        float maxTopPos = centerY - 100;
        if (topPos < maxTopPos) {
            this.y = (int)(this.y - buttonWidth * Mth.ceil((topPos - maxTopPos) / buttonWidth));
        }
 
        this.isVisible = true;
        this.recipeButtons.clear();
 
        for (int i = 0; i < total; i++) {
            boolean canCraft = i < craftables;
            RecipeDisplayEntry recipe = canCraft ? craftable.get(i) : unCraftable.get(i - craftables);
            int x = this.x + 4 + 25 * (i % maxRow);
            int y = this.y + 5 + 25 * (i / maxRow);
            if (this.isFurnaceMenu) {
                this.recipeButtons.add(new OverlayRecipeComponent.OverlaySmeltingRecipeButton(x, y, recipe.id(), recipe.display(), context, canCraft));
            } else {
                this.recipeButtons.add(new OverlayRecipeComponent.OverlayCraftingRecipeButton(x, y, recipe.id(), recipe.display(), context, canCraft));
            }
        }
 
        this.lastRecipeClicked = null;
    }
 
    public RecipeCollection getRecipeCollection() {
        return this.collection;
    }
 
    public @Nullable RecipeDisplayId getLastRecipeClicked() {
        return this.lastRecipeClicked;
    }
 
    @Override
    public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) {
        if (event.button() != 0) {
            return false;
        } else {
            for (OverlayRecipeComponent.OverlayRecipeButton recipeButton : this.recipeButtons) {
                if (recipeButton.mouseClicked(event, doubleClick)) {
                    this.lastRecipeClicked = recipeButton.recipe;
                    return true;
                }
            }
 
            return false;
        }
    }
 
    @Override
    public boolean isMouseOver(double mouseX, double mouseY) {
        return false;
    }
 
    @Override
    public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) {
        if (this.isVisible) {
            int maxRow = this.recipeButtons.size() <= 16 ? 4 : 5;
            int width = Math.min(this.recipeButtons.size(), maxRow);
            int height = Mth.ceil((float)this.recipeButtons.size() / maxRow);
            int border = 4;
            graphics.blitSprite(RenderPipelines.GUI_TEXTURED, OVERLAY_RECIPE_SPRITE, this.x, this.y, width * 25 + 8, height * 25 + 8);
 
            for (OverlayRecipeComponent.OverlayRecipeButton component : this.recipeButtons) {
                component.extractRenderState(graphics, mouseX, mouseY, a);
            }
        }
    }
 
    public void setVisible(boolean visible) {
        this.isVisible = visible;
    }
 
    public boolean isVisible() {
        return this.isVisible;
    }
 
    @Override
    public void setFocused(boolean focused) {
    }
 
    @Override
    public boolean isFocused() {
        return false;
    }
 
    @OnlyIn(Dist.CLIENT)
    private class OverlayCraftingRecipeButton extends OverlayRecipeComponent.OverlayRecipeButton {
        private static final Identifier ENABLED_SPRITE = Identifier.withDefaultNamespace("recipe_book/crafting_overlay");
        private static final Identifier HIGHLIGHTED_ENABLED_SPRITE = Identifier.withDefaultNamespace("recipe_book/crafting_overlay_highlighted");
        private static final Identifier DISABLED_SPRITE = Identifier.withDefaultNamespace("recipe_book/crafting_overlay_disabled");
        private static final Identifier HIGHLIGHTED_DISABLED_SPRITE = Identifier.withDefaultNamespace("recipe_book/crafting_overlay_disabled_highlighted");
        private static final int GRID_WIDTH = 3;
        private static final int GRID_HEIGHT = 3;
 
        public OverlayCraftingRecipeButton(int x, int y, RecipeDisplayId id, RecipeDisplay recipe, ContextMap context, boolean isCraftable) {
            Objects.requireNonNull(OverlayRecipeComponent.this);
            super(x, y, id, isCraftable, calculateIngredientsPositions(recipe, context));
        }
 
        private static List<OverlayRecipeComponent.OverlayRecipeButton.Pos> calculateIngredientsPositions(RecipeDisplay recipe, ContextMap context) {
            List<OverlayRecipeComponent.OverlayRecipeButton.Pos> result = new ArrayList<>();
            switch (recipe) {
                case ShapedCraftingRecipeDisplay shaped:
                    PlaceRecipeHelper.placeRecipe(3, 3, shaped.width(), shaped.height(), shaped.ingredients(), (ingredient, gridIndex, gridXPos, gridYPos) -> {
                        List<ItemStack> itemsx = ingredient.resolveForStacks(context);
                        if (!itemsx.isEmpty()) {
                            result.add(createGridPos(gridXPos, gridYPos, itemsx));
                        }
                    });
                    break;
                case ShapelessCraftingRecipeDisplay shapeless:
                    label19: {
                        List<SlotDisplay> ingredients = shapeless.ingredients();
 
                        for (int i = 0; i < ingredients.size(); i++) {
                            List<ItemStack> items = ingredients.get(i).resolveForStacks(context);
                            if (!items.isEmpty()) {
                                result.add(createGridPos(i % 3, i / 3, items));
                            }
                        }
                        break label19;
                    }
                default:
            }
 
            return result;
        }
 
        @Override
        protected Identifier getSprite(boolean isCraftable) {
            if (isCraftable) {
                return this.isHoveredOrFocused() ? HIGHLIGHTED_ENABLED_SPRITE : ENABLED_SPRITE;
            } else {
                return this.isHoveredOrFocused() ? HIGHLIGHTED_DISABLED_SPRITE : DISABLED_SPRITE;
            }
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    private abstract class OverlayRecipeButton extends AbstractWidget {
        private final RecipeDisplayId recipe;
        private final boolean isCraftable;
        private final List<OverlayRecipeComponent.OverlayRecipeButton.Pos> slots;
 
        public OverlayRecipeButton(int x, int y, RecipeDisplayId recipe, boolean isCraftable, List<OverlayRecipeComponent.OverlayRecipeButton.Pos> slots) {
            Objects.requireNonNull(OverlayRecipeComponent.this);
            super(x, y, 24, 24, CommonComponents.EMPTY);
            this.slots = slots;
            this.recipe = recipe;
            this.isCraftable = isCraftable;
        }
 
        protected static OverlayRecipeComponent.OverlayRecipeButton.Pos createGridPos(int gridXPos, int gridYPos, List<ItemStack> itemStacks) {
            return new OverlayRecipeComponent.OverlayRecipeButton.Pos(3 + gridXPos * 7, 3 + gridYPos * 7, itemStacks);
        }
 
        protected abstract Identifier getSprite(boolean isCraftable);
 
        @Override
        public void updateWidgetNarration(NarrationElementOutput output) {
            this.defaultButtonNarrationText(output);
        }
 
        @Override
        public void extractWidgetRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) {
            graphics.blitSprite(RenderPipelines.GUI_TEXTURED, this.getSprite(this.isCraftable), this.getX(), this.getY(), this.width, this.height);
            float gridPosX = this.getX() + 2;
            float gridPosY = this.getY() + 2;
 
            for (OverlayRecipeComponent.OverlayRecipeButton.Pos pos : this.slots) {
                graphics.pose().pushMatrix();
                graphics.pose().translate(gridPosX + pos.x, gridPosY + pos.y);
                graphics.pose().scale(0.375F, 0.375F);
                graphics.pose().translate(-8.0F, -8.0F);
                graphics.item(pos.selectIngredient(OverlayRecipeComponent.this.slotSelectTime.currentIndex()), 0, 0);
                graphics.pose().popMatrix();
            }
        }
 
        @OnlyIn(Dist.CLIENT)
        protected record Pos(int x, int y, List<ItemStack> ingredients) {
            public Pos(int x, int y, List<ItemStack> ingredients) {
                if (ingredients.isEmpty()) {
                    throw new IllegalArgumentException("Ingredient list must be non-empty");
                } else {
                    this.x = x;
                    this.y = y;
                    this.ingredients = ingredients;
                }
            }
 
            public ItemStack selectIngredient(int currentIndex) {
                return this.ingredients.get(currentIndex % this.ingredients.size());
            }
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    private class OverlaySmeltingRecipeButton extends OverlayRecipeComponent.OverlayRecipeButton {
        private static final Identifier ENABLED_SPRITE = Identifier.withDefaultNamespace("recipe_book/furnace_overlay");
        private static final Identifier HIGHLIGHTED_ENABLED_SPRITE = Identifier.withDefaultNamespace("recipe_book/furnace_overlay_highlighted");
        private static final Identifier DISABLED_SPRITE = Identifier.withDefaultNamespace("recipe_book/furnace_overlay_disabled");
        private static final Identifier HIGHLIGHTED_DISABLED_SPRITE = Identifier.withDefaultNamespace("recipe_book/furnace_overlay_disabled_highlighted");
 
        public OverlaySmeltingRecipeButton(int x, int y, RecipeDisplayId id, RecipeDisplay recipe, ContextMap context, boolean isCraftable) {
            Objects.requireNonNull(OverlayRecipeComponent.this);
            super(x, y, id, isCraftable, calculateIngredientsPositions(recipe, context));
        }
 
        private static List<OverlayRecipeComponent.OverlayRecipeButton.Pos> calculateIngredientsPositions(RecipeDisplay recipe, ContextMap context) {
            if (recipe instanceof FurnaceRecipeDisplay furnaceRecipe) {
                List<ItemStack> items = furnaceRecipe.ingredient().resolveForStacks(context);
                if (!items.isEmpty()) {
                    return List.of(createGridPos(1, 1, items));
                }
            }
 
            return List.of();
        }
 
        @Override
        protected Identifier getSprite(boolean isCraftable) {
            if (isCraftable) {
                return this.isHoveredOrFocused() ? HIGHLIGHTED_ENABLED_SPRITE : ENABLED_SPRITE;
            } else {
                return this.isHoveredOrFocused() ? HIGHLIGHTED_DISABLED_SPRITE : DISABLED_SPRITE;
            }
        }
    }
}

引用的其他类