RecipeButton.java

net.minecraft.client.gui.screens.recipebook.RecipeButton

信息

  • 全限定名:net.minecraft.client.gui.screens.recipebook.RecipeButton
  • 类型:public class
  • 包:net.minecraft.client.gui.screens.recipebook
  • 源码路径:src/main/java/net/minecraft/client/gui/screens/recipebook/RecipeButton.java
  • 起始行号:L25
  • 继承:AbstractWidget
  • 职责:

    TODO

字段/常量

  • SLOT_MANY_CRAFTABLE_SPRITE

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

      TODO

  • SLOT_CRAFTABLE_SPRITE

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

      TODO

  • SLOT_MANY_UNCRAFTABLE_SPRITE

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

      TODO

  • SLOT_UNCRAFTABLE_SPRITE

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

      TODO

  • ANIMATION_TIME

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

      TODO

  • BACKGROUND_SIZE

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

      TODO

  • MORE_RECIPES_TOOLTIP

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

      TODO

  • collection

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

      TODO

  • selectedEntries

    • 类型: List<RecipeButton.ResolvedEntry>
    • 修饰符: private
    • 源码定位: L34
    • 说明:

      TODO

  • allRecipesHaveSameResultDisplay

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

      TODO

  • slotSelectTime

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

      TODO

  • animationTime

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

      TODO

内部类/嵌套类型

  • net.minecraft.client.gui.screens.recipebook.RecipeButton.ResolvedEntry
    • 类型: record
    • 修饰符: private
    • 源码定位: L172
    • 说明:

      TODO

构造器

public RecipeButton(SlotSelectTime slotSelectTime) @ L39

  • 构造器名:RecipeButton
  • 源码定位:L39
  • 修饰符:public

参数:

  • slotSelectTime: SlotSelectTime

说明:

TODO

方法

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

public void init(RecipeCollection collection, boolean isFiltering, RecipeBookPage page, ContextMap resolutionContext) @ L44

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

参数:

  • collection: RecipeCollection
  • isFiltering: boolean
  • page: RecipeBookPage
  • resolutionContext: ContextMap

说明:

TODO

private static boolean allRecipesHaveSameResultDisplay(List<RecipeButton.ResolvedEntry> entries) @ L58

  • 方法名:allRecipesHaveSameResultDisplay
  • 源码定位:L58
  • 返回类型:boolean
  • 修饰符:private static

参数:

  • entries: List<RecipeButton.ResolvedEntry>

说明:

TODO

public RecipeCollection getCollection() @ L76

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

参数:

说明:

TODO

public void extractWidgetRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) @ L80

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

参数:

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

说明:

TODO

private boolean hasMultipleRecipes() @ L119

  • 方法名:hasMultipleRecipes
  • 源码定位:L119
  • 返回类型:boolean
  • 修饰符:private

参数:

说明:

TODO

public boolean isOnlyOption() @ L123

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

参数:

说明:

TODO

public RecipeDisplayId getCurrentRecipe() @ L127

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

参数:

说明:

TODO

public ItemStack getDisplayStack() @ L132

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

参数:

说明:

TODO

public List<Component> getTooltipText(ItemStack displayStack) @ L140

  • 方法名:getTooltipText
  • 源码定位:L140
  • 返回类型:List
  • 修饰符:public

参数:

  • displayStack: ItemStack

说明:

TODO

public void updateWidgetNarration(NarrationElementOutput output) @ L149

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

参数:

  • output: NarrationElementOutput

说明:

TODO

public int getWidth() @ L161

  • 方法名:getWidth
  • 源码定位:L161
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

protected boolean isValidClickButton(MouseButtonInfo buttonInfo) @ L166

  • 方法名:isValidClickButton
  • 源码定位:L166
  • 返回类型:boolean
  • 修饰符:protected

参数:

  • buttonInfo: MouseButtonInfo

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class RecipeButton extends AbstractWidget {
    private static final Identifier SLOT_MANY_CRAFTABLE_SPRITE = Identifier.withDefaultNamespace("recipe_book/slot_many_craftable");
    private static final Identifier SLOT_CRAFTABLE_SPRITE = Identifier.withDefaultNamespace("recipe_book/slot_craftable");
    private static final Identifier SLOT_MANY_UNCRAFTABLE_SPRITE = Identifier.withDefaultNamespace("recipe_book/slot_many_uncraftable");
    private static final Identifier SLOT_UNCRAFTABLE_SPRITE = Identifier.withDefaultNamespace("recipe_book/slot_uncraftable");
    private static final float ANIMATION_TIME = 15.0F;
    private static final int BACKGROUND_SIZE = 25;
    private static final Component MORE_RECIPES_TOOLTIP = Component.translatable("gui.recipebook.moreRecipes");
    private RecipeCollection collection = RecipeCollection.EMPTY;
    private List<RecipeButton.ResolvedEntry> selectedEntries = List.of();
    private boolean allRecipesHaveSameResultDisplay;
    private final SlotSelectTime slotSelectTime;
    private float animationTime;
 
    public RecipeButton(SlotSelectTime slotSelectTime) {
        super(0, 0, 25, 25, CommonComponents.EMPTY);
        this.slotSelectTime = slotSelectTime;
    }
 
    public void init(RecipeCollection collection, boolean isFiltering, RecipeBookPage page, ContextMap resolutionContext) {
        this.collection = collection;
        List<RecipeDisplayEntry> fittingRecipes = collection.getSelectedRecipes(
            isFiltering ? RecipeCollection.CraftableStatus.CRAFTABLE : RecipeCollection.CraftableStatus.ANY
        );
        this.selectedEntries = fittingRecipes.stream().map(entry -> new RecipeButton.ResolvedEntry(entry.id(), entry.resultItems(resolutionContext))).toList();
        this.allRecipesHaveSameResultDisplay = allRecipesHaveSameResultDisplay(this.selectedEntries);
        List<RecipeDisplayId> newlyShownRecipes = fittingRecipes.stream().map(RecipeDisplayEntry::id).filter(page.getRecipeBook()::willHighlight).toList();
        if (!newlyShownRecipes.isEmpty()) {
            newlyShownRecipes.forEach(page::recipeShown);
            this.animationTime = 15.0F;
        }
    }
 
    private static boolean allRecipesHaveSameResultDisplay(List<RecipeButton.ResolvedEntry> entries) {
        Iterator<ItemStack> itemsIterator = entries.stream().flatMap(e -> e.displayItems().stream()).iterator();
        if (!itemsIterator.hasNext()) {
            return true;
        } else {
            ItemStack firstItem = itemsIterator.next();
 
            while (itemsIterator.hasNext()) {
                ItemStack nextItem = itemsIterator.next();
                if (!ItemStack.isSameItemSameComponents(firstItem, nextItem)) {
                    return false;
                }
            }
 
            return true;
        }
    }
 
    public RecipeCollection getCollection() {
        return this.collection;
    }
 
    @Override
    public void extractWidgetRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) {
        Identifier sprite;
        if (this.collection.hasCraftable()) {
            if (this.hasMultipleRecipes()) {
                sprite = SLOT_MANY_CRAFTABLE_SPRITE;
            } else {
                sprite = SLOT_CRAFTABLE_SPRITE;
            }
        } else if (this.hasMultipleRecipes()) {
            sprite = SLOT_MANY_UNCRAFTABLE_SPRITE;
        } else {
            sprite = SLOT_UNCRAFTABLE_SPRITE;
        }
 
        boolean shouldAnimate = this.animationTime > 0.0F;
        if (shouldAnimate) {
            float squeeze = 1.0F + 0.1F * (float)Math.sin(this.animationTime / 15.0F * (float) Math.PI);
            graphics.pose().pushMatrix();
            graphics.pose().translate(this.getX() + 8, this.getY() + 12);
            graphics.pose().scale(squeeze, squeeze);
            graphics.pose().translate(-(this.getX() + 8), -(this.getY() + 12));
            this.animationTime -= a;
        }
 
        graphics.blitSprite(RenderPipelines.GUI_TEXTURED, sprite, this.getX(), this.getY(), this.width, this.height);
        ItemStack currentItemStack = this.getDisplayStack();
        int offset = 4;
        if (this.hasMultipleRecipes() && this.allRecipesHaveSameResultDisplay) {
            graphics.item(currentItemStack, this.getX() + offset + 1, this.getY() + offset + 1, 0);
            offset--;
        }
 
        graphics.fakeItem(currentItemStack, this.getX() + offset, this.getY() + offset);
        if (shouldAnimate) {
            graphics.pose().popMatrix();
        }
    }
 
    private boolean hasMultipleRecipes() {
        return this.selectedEntries.size() > 1;
    }
 
    public boolean isOnlyOption() {
        return this.selectedEntries.size() == 1;
    }
 
    public RecipeDisplayId getCurrentRecipe() {
        int index = this.slotSelectTime.currentIndex() % this.selectedEntries.size();
        return this.selectedEntries.get(index).id;
    }
 
    public ItemStack getDisplayStack() {
        int currentIndex = this.slotSelectTime.currentIndex();
        int entryCount = this.selectedEntries.size();
        int offsetIndex = currentIndex / entryCount;
        int entryIndex = currentIndex - entryCount * offsetIndex;
        return this.selectedEntries.get(entryIndex).selectItem(offsetIndex);
    }
 
    public List<Component> getTooltipText(ItemStack displayStack) {
        List<Component> texts = new ArrayList<>(Screen.getTooltipFromItem(Minecraft.getInstance(), displayStack));
        if (this.hasMultipleRecipes()) {
            texts.add(MORE_RECIPES_TOOLTIP);
        }
 
        return texts;
    }
 
    @Override
    public void updateWidgetNarration(NarrationElementOutput output) {
        output.add(NarratedElementType.TITLE, Component.translatable("narration.recipe", this.getDisplayStack().getHoverName()));
        if (this.hasMultipleRecipes()) {
            output.add(
                NarratedElementType.USAGE, Component.translatable("narration.button.usage.hovered"), Component.translatable("narration.recipe.usage.more")
            );
        } else {
            output.add(NarratedElementType.USAGE, Component.translatable("narration.button.usage.hovered"));
        }
    }
 
    @Override
    public int getWidth() {
        return 25;
    }
 
    @Override
    protected boolean isValidClickButton(MouseButtonInfo buttonInfo) {
        return buttonInfo.button() == 0 || buttonInfo.button() == 1;
    }
 
    @OnlyIn(Dist.CLIENT)
    private record ResolvedEntry(RecipeDisplayId id, List<ItemStack> displayItems) {
        public ItemStack selectItem(int index) {
            if (this.displayItems.isEmpty()) {
                return ItemStack.EMPTY;
            } else {
                int offset = index % this.displayItems.size();
                return this.displayItems.get(offset);
            }
        }
    }
}

引用的其他类