AbstractContainerScreen.java

net.minecraft.client.gui.screens.inventory.AbstractContainerScreen

信息

  • 全限定名:net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
  • 类型:public abstract class
  • 包:net.minecraft.client.gui.screens.inventory
  • 源码路径:src/main/java/net/minecraft/client/gui/screens/inventory/AbstractContainerScreen.java
  • 起始行号:L33
  • 继承:Screen
  • 实现:MenuAccess
  • 职责:

    TODO

字段/常量

  • INVENTORY_LOCATION

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

      TODO

  • SLOT_HIGHLIGHT_BACK_SPRITE

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

      TODO

  • SLOT_HIGHLIGHT_FRONT_SPRITE

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

      TODO

  • BACKGROUND_TEXTURE_WIDTH

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

      TODO

  • BACKGROUND_TEXTURE_HEIGHT

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

      TODO

  • SNAPBACK_SPEED

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

      TODO

  • QUICKDROP_DELAY

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

      TODO

  • DEFAULT_IMAGE_WIDTH

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

      TODO

  • DEFAULT_IMAGE_HEIGHT

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

      TODO

  • imageWidth

    • 类型: int
    • 修饰符: protected final
    • 源码定位: L43
    • 说明:

      TODO

  • imageHeight

    • 类型: int
    • 修饰符: protected final
    • 源码定位: L44
    • 说明:

      TODO

  • titleLabelX

    • 类型: int
    • 修饰符: protected
    • 源码定位: L45
    • 说明:

      TODO

  • titleLabelY

    • 类型: int
    • 修饰符: protected
    • 源码定位: L46
    • 说明:

      TODO

  • inventoryLabelX

    • 类型: int
    • 修饰符: protected
    • 源码定位: L47
    • 说明:

      TODO

  • inventoryLabelY

    • 类型: int
    • 修饰符: protected
    • 源码定位: L48
    • 说明:

      TODO

  • itemSlotMouseActions

    • 类型: List<ItemSlotMouseAction>
    • 修饰符: private final
    • 源码定位: L49
    • 说明:

      TODO

  • menu

    • 类型: T
    • 修饰符: protected final
    • 源码定位: L50
    • 说明:

      TODO

  • playerInventoryTitle

    • 类型: Component
    • 修饰符: protected final
    • 源码定位: L51
    • 说明:

      TODO

  • hoveredSlot

    • 类型: Slot
    • 修饰符: protected
    • 源码定位: L52
    • 说明:

      TODO

  • clickedSlot

    • 类型: Slot
    • 修饰符: private
    • 源码定位: L53
    • 说明:

      TODO

  • quickdropSlot

    • 类型: Slot
    • 修饰符: private
    • 源码定位: L54
    • 说明:

      TODO

  • lastClickSlot

    • 类型: Slot
    • 修饰符: private
    • 源码定位: L55
    • 说明:

      TODO

  • snapbackData

    • 类型: AbstractContainerScreen.SnapbackData
    • 修饰符: private
    • 源码定位: L56
    • 说明:

      TODO

  • leftPos

    • 类型: int
    • 修饰符: protected
    • 源码定位: L57
    • 说明:

      TODO

  • topPos

    • 类型: int
    • 修饰符: protected
    • 源码定位: L58
    • 说明:

      TODO

  • isSplittingStack

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

      TODO

  • draggingItem

    • 类型: ItemStack
    • 修饰符: private
    • 源码定位: L60
    • 说明:

      TODO

  • quickdropTime

    • 类型: long
    • 修饰符: private
    • 源码定位: L61
    • 说明:

      TODO

  • quickCraftSlots

    • 类型: Set<Slot>
    • 修饰符: protected final
    • 源码定位: L62
    • 说明:

      TODO

  • isQuickCrafting

    • 类型: boolean
    • 修饰符: protected
    • 源码定位: L63
    • 说明:

      TODO

  • quickCraftingType

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

      TODO

  • quickCraftingButton

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

      TODO

  • skipNextRelease

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

      TODO

  • quickCraftingRemainder

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

      TODO

  • doubleclick

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

      TODO

  • lastQuickMoved

    • 类型: ItemStack
    • 修饰符: private
    • 源码定位: L70
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.gui.screens.inventory.AbstractContainerScreen.SnapbackData
    • 类型: record
    • 修饰符: private
    • 源码定位: L698
    • 说明:

      TODO

构造器

public AbstractContainerScreen(T menu, Inventory inventory, Component title) @ L72

  • 构造器名:AbstractContainerScreen
  • 源码定位:L72
  • 修饰符:public

参数:

  • menu: T
  • inventory: Inventory
  • title: Component

说明:

TODO

public AbstractContainerScreen(T menu, Inventory inventory, Component title, int imageWidth, int imageHeight) @ L76

  • 构造器名:AbstractContainerScreen
  • 源码定位:L76
  • 修饰符:public

参数:

  • menu: T
  • inventory: Inventory
  • title: Component
  • imageWidth: int
  • imageHeight: int

说明:

TODO

方法

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

protected void init() @ L90

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

参数:

说明:

TODO

protected void addItemSlotMouseAction(ItemSlotMouseAction itemSlotMouseAction) @ L98

  • 方法名:addItemSlotMouseAction
  • 源码定位:L98
  • 返回类型:void
  • 修饰符:protected

参数:

  • itemSlotMouseAction: ItemSlotMouseAction

说明:

TODO

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

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

参数:

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

说明:

TODO

public void extractContents(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) @ L110

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

参数:

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

说明:

TODO

public void extractCarriedItem(GuiGraphicsExtractor graphics, int mouseX, int mouseY) @ L129

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

参数:

  • graphics: GuiGraphicsExtractor
  • mouseX: int
  • mouseY: int

说明:

TODO

public void extractSnapbackItem(GuiGraphicsExtractor graphics) @ L149

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

参数:

  • graphics: GuiGraphicsExtractor

说明:

TODO

protected void extractSlots(GuiGraphicsExtractor graphics, int mouseX, int mouseY) @ L164

  • 方法名:extractSlots
  • 源码定位:L164
  • 返回类型:void
  • 修饰符:protected

参数:

  • graphics: GuiGraphicsExtractor
  • mouseX: int
  • mouseY: int

说明:

TODO

public boolean mouseScrolled(double x, double y, double scrollX, double scrollY) @ L172

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

参数:

  • x: double
  • y: double
  • scrollX: double
  • scrollY: double

说明:

TODO

private void extractSlotHighlightBack(GuiGraphicsExtractor graphics) @ L186

  • 方法名:extractSlotHighlightBack
  • 源码定位:L186
  • 返回类型:void
  • 修饰符:private

参数:

  • graphics: GuiGraphicsExtractor

说明:

TODO

private void extractSlotHighlightFront(GuiGraphicsExtractor graphics) @ L192

  • 方法名:extractSlotHighlightFront
  • 源码定位:L192
  • 返回类型:void
  • 修饰符:private

参数:

  • graphics: GuiGraphicsExtractor

说明:

TODO

protected void extractTooltip(GuiGraphicsExtractor graphics, int mouseX, int mouseY) @ L198

  • 方法名:extractTooltip
  • 源码定位:L198
  • 返回类型:void
  • 修饰符:protected

参数:

  • graphics: GuiGraphicsExtractor
  • mouseX: int
  • mouseY: int

说明:

TODO

private boolean showTooltipWithItemInHand(ItemStack item) @ L209

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

参数:

  • item: ItemStack

说明:

TODO

protected List<Component> getTooltipFromContainerItem(ItemStack itemStack) @ L213

  • 方法名:getTooltipFromContainerItem
  • 源码定位:L213
  • 返回类型:List
  • 修饰符:protected

参数:

  • itemStack: ItemStack

说明:

TODO

private void extractFloatingItem(GuiGraphicsExtractor graphics, ItemStack carried, int x, int y, String itemCount) @ L217

  • 方法名:extractFloatingItem
  • 源码定位:L217
  • 返回类型:void
  • 修饰符:private

参数:

  • graphics: GuiGraphicsExtractor
  • carried: ItemStack
  • x: int
  • y: int
  • itemCount: String

说明:

TODO

protected void extractLabels(GuiGraphicsExtractor graphics, int xm, int ym) @ L222

  • 方法名:extractLabels
  • 源码定位:L222
  • 返回类型:void
  • 修饰符:protected

参数:

  • graphics: GuiGraphicsExtractor
  • xm: int
  • ym: int

说明:

TODO

protected void extractSlot(GuiGraphicsExtractor graphics, Slot slot, int mouseX, int mouseY) @ L227

  • 方法名:extractSlot
  • 源码定位:L227
  • 返回类型:void
  • 修饰符:protected

参数:

  • graphics: GuiGraphicsExtractor
  • slot: Slot
  • mouseX: int
  • mouseY: int

说明:

TODO

private void recalculateQuickCraftRemaining() @ L283

  • 方法名:recalculateQuickCraftRemaining
  • 源码定位:L283
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

private Slot getHoveredSlot(double x, double y) @ L304

  • 方法名:getHoveredSlot
  • 源码定位:L304
  • 返回类型:Slot
  • 修饰符:private

参数:

  • x: double
  • y: double

说明:

TODO

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

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

参数:

  • event: MouseButtonEvent
  • doubleClick: boolean

说明:

TODO

private void checkHotbarMouseClicked(MouseButtonEvent event) @ L391

  • 方法名:checkHotbarMouseClicked
  • 源码定位:L391
  • 返回类型:void
  • 修饰符:private

参数:

  • event: MouseButtonEvent

说明:

TODO

protected boolean hasClickedOutside(double mx, double my, int xo, int yo) @ L406

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

参数:

  • mx: double
  • my: double
  • xo: int
  • yo: int

说明:

TODO

public boolean mouseDragged(MouseButtonEvent event, double dx, double dy) @ L410

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

参数:

  • event: MouseButtonEvent
  • dx: double
  • dy: double

说明:

TODO

public boolean mouseReleased(MouseButtonEvent event) @ L446

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

参数:

  • event: MouseButtonEvent

说明:

TODO

public void clearDraggingState() @ L544

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

参数:

说明:

TODO

private boolean isHovering(Slot slot, double xm, double ym) @ L549

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

参数:

  • slot: Slot
  • xm: double
  • ym: double

说明:

TODO

protected boolean isHovering(int left, int top, int w, int h, double xm, double ym) @ L553

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

参数:

  • left: int
  • top: int
  • w: int
  • h: int
  • xm: double
  • ym: double

说明:

TODO

private void onStopHovering(Slot slot) @ L561

  • 方法名:onStopHovering
  • 源码定位:L561
  • 返回类型:void
  • 修饰符:private

参数:

  • slot: Slot

说明:

TODO

protected void slotClicked(Slot slot, int slotId, int buttonNum, ContainerInput containerInput) @ L571

  • 方法名:slotClicked
  • 源码定位:L571
  • 返回类型:void
  • 修饰符:protected

参数:

  • slot: Slot
  • slotId: int
  • buttonNum: int
  • containerInput: ContainerInput

说明:

TODO

void onMouseClickAction(Slot slot, ContainerInput containerInput) @ L580

  • 方法名:onMouseClickAction
  • 源码定位:L580
  • 返回类型:void
  • 修饰符:package-private

参数:

  • slot: Slot
  • containerInput: ContainerInput

说明:

TODO

protected void handleSlotStateChanged(int slotId, int containerId, boolean newState) @ L590

  • 方法名:handleSlotStateChanged
  • 源码定位:L590
  • 返回类型:void
  • 修饰符:protected

参数:

  • slotId: int
  • containerId: int
  • newState: boolean

说明:

TODO

public boolean keyPressed(KeyEvent event) @ L594

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

参数:

  • event: KeyEvent

说明:

TODO

protected boolean checkHotbarKeyPressed(KeyEvent event) @ L615

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

参数:

  • event: KeyEvent

说明:

TODO

public void removed() @ L633

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

参数:

说明:

TODO

public boolean isPauseScreen() @ L640

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

参数:

说明:

TODO

public boolean isInGameUi() @ L645

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

参数:

说明:

TODO

public final void tick() @ L650

  • 方法名:tick
  • 源码定位:L650
  • 返回类型:void
  • 修饰符:public final

参数:

说明:

TODO

protected void containerTick() @ L660

  • 方法名:containerTick
  • 源码定位:L660
  • 返回类型:void
  • 修饰符:protected

参数:

说明:

TODO

private boolean shouldAddSlotToQuickCraft(Slot slot, ItemStack carried) @ L663

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

参数:

  • slot: Slot
  • carried: ItemStack

说明:

TODO

private void quickCraftToSlots() @ L672

  • 方法名:quickCraftToSlots
  • 源码定位:L672
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

public T getMenu() @ L682

  • 方法名:getMenu
  • 源码定位:L682
  • 返回类型:T
  • 修饰符:public

参数:

说明:

TODO

public void onClose() @ L687

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

参数:

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public abstract class AbstractContainerScreen<T extends AbstractContainerMenu> extends Screen implements MenuAccess<T> {
    public static final Identifier INVENTORY_LOCATION = Identifier.withDefaultNamespace("textures/gui/container/inventory.png");
    private static final Identifier SLOT_HIGHLIGHT_BACK_SPRITE = Identifier.withDefaultNamespace("container/slot_highlight_back");
    private static final Identifier SLOT_HIGHLIGHT_FRONT_SPRITE = Identifier.withDefaultNamespace("container/slot_highlight_front");
    protected static final int BACKGROUND_TEXTURE_WIDTH = 256;
    protected static final int BACKGROUND_TEXTURE_HEIGHT = 256;
    private static final float SNAPBACK_SPEED = 100.0F;
    private static final int QUICKDROP_DELAY = 500;
    protected static final int DEFAULT_IMAGE_WIDTH = 176;
    protected static final int DEFAULT_IMAGE_HEIGHT = 166;
    protected final int imageWidth;
    protected final int imageHeight;
    protected int titleLabelX;
    protected int titleLabelY;
    protected int inventoryLabelX;
    protected int inventoryLabelY;
    private final List<ItemSlotMouseAction> itemSlotMouseActions;
    protected final T menu;
    protected final Component playerInventoryTitle;
    protected @Nullable Slot hoveredSlot;
    private @Nullable Slot clickedSlot;
    private @Nullable Slot quickdropSlot;
    private @Nullable Slot lastClickSlot;
    private AbstractContainerScreen.@Nullable SnapbackData snapbackData;
    protected int leftPos;
    protected int topPos;
    private boolean isSplittingStack;
    private ItemStack draggingItem = ItemStack.EMPTY;
    private long quickdropTime;
    protected final Set<Slot> quickCraftSlots = Sets.newHashSet();
    protected boolean isQuickCrafting;
    private int quickCraftingType;
    @MouseButtonInfo.MouseButton
    private int quickCraftingButton;
    private boolean skipNextRelease;
    private int quickCraftingRemainder;
    private boolean doubleclick;
    private ItemStack lastQuickMoved = ItemStack.EMPTY;
 
    public AbstractContainerScreen(T menu, Inventory inventory, Component title) {
        this(menu, inventory, title, 176, 166);
    }
 
    public AbstractContainerScreen(T menu, Inventory inventory, Component title, int imageWidth, int imageHeight) {
        super(title);
        this.menu = menu;
        this.playerInventoryTitle = inventory.getDisplayName();
        this.imageWidth = imageWidth;
        this.imageHeight = imageHeight;
        this.skipNextRelease = true;
        this.titleLabelX = 8;
        this.titleLabelY = 6;
        this.inventoryLabelX = 8;
        this.inventoryLabelY = imageHeight - 94;
        this.itemSlotMouseActions = new ArrayList<>();
    }
 
    @Override
    protected void init() {
        this.leftPos = (this.width - this.imageWidth) / 2;
        this.topPos = (this.height - this.imageHeight) / 2;
        this.itemSlotMouseActions.clear();
        this.addItemSlotMouseAction(new BundleMouseActions(this.minecraft));
    }
 
    protected void addItemSlotMouseAction(ItemSlotMouseAction itemSlotMouseAction) {
        this.itemSlotMouseActions.add(itemSlotMouseAction);
    }
 
    @Override
    public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) {
        this.extractContents(graphics, mouseX, mouseY, a);
        this.extractCarriedItem(graphics, mouseX, mouseY);
        this.extractSnapbackItem(graphics);
        this.extractTooltip(graphics, mouseX, mouseY);
    }
 
    public void extractContents(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) {
        int xo = this.leftPos;
        int yo = this.topPos;
        super.extractRenderState(graphics, mouseX, mouseY, a);
        graphics.pose().pushMatrix();
        graphics.pose().translate(xo, yo);
        this.extractLabels(graphics, mouseX, mouseY);
        Slot previouslyHoveredSlot = this.hoveredSlot;
        this.hoveredSlot = this.getHoveredSlot(mouseX, mouseY);
        this.extractSlotHighlightBack(graphics);
        this.extractSlots(graphics, mouseX, mouseY);
        this.extractSlotHighlightFront(graphics);
        if (previouslyHoveredSlot != null && previouslyHoveredSlot != this.hoveredSlot) {
            this.onStopHovering(previouslyHoveredSlot);
        }
 
        graphics.pose().popMatrix();
    }
 
    public void extractCarriedItem(GuiGraphicsExtractor graphics, int mouseX, int mouseY) {
        ItemStack carried = this.draggingItem.isEmpty() ? this.menu.getCarried() : this.draggingItem;
        if (!carried.isEmpty()) {
            int xOffset = 8;
            int yOffset = this.draggingItem.isEmpty() ? 8 : 16;
            String itemCount = null;
            if (!this.draggingItem.isEmpty() && this.isSplittingStack) {
                carried = carried.copyWithCount(Mth.ceil(carried.getCount() / 2.0F));
            } else if (this.isQuickCrafting && this.quickCraftSlots.size() > 1) {
                carried = carried.copyWithCount(this.quickCraftingRemainder);
                if (carried.isEmpty()) {
                    itemCount = ChatFormatting.YELLOW + "0";
                }
            }
 
            graphics.nextStratum();
            this.extractFloatingItem(graphics, carried, mouseX - 8, mouseY - yOffset, itemCount);
        }
    }
 
    public void extractSnapbackItem(GuiGraphicsExtractor graphics) {
        if (this.snapbackData != null) {
            float snapbackProgress = Mth.clamp((float)(Util.getMillis() - this.snapbackData.time) / 100.0F, 0.0F, 1.0F);
            int xd = this.snapbackData.end.x - this.snapbackData.start.x;
            int yd = this.snapbackData.end.y - this.snapbackData.start.y;
            int x = this.snapbackData.start.x + (int)(xd * snapbackProgress);
            int y = this.snapbackData.start.y + (int)(yd * snapbackProgress);
            graphics.nextStratum();
            this.extractFloatingItem(graphics, this.snapbackData.item, x, y, null);
            if (snapbackProgress >= 1.0F) {
                this.snapbackData = null;
            }
        }
    }
 
    protected void extractSlots(GuiGraphicsExtractor graphics, int mouseX, int mouseY) {
        for (Slot slot : this.menu.slots) {
            if (slot.isActive()) {
                this.extractSlot(graphics, slot, mouseX, mouseY);
            }
        }
    }
 
    @Override
    public boolean mouseScrolled(double x, double y, double scrollX, double scrollY) {
        if (this.hoveredSlot != null && this.hoveredSlot.hasItem()) {
            for (ItemSlotMouseAction itemMouseAction : this.itemSlotMouseActions) {
                if (itemMouseAction.matches(this.hoveredSlot)
                    && itemMouseAction.onMouseScrolled(scrollX, scrollY, this.hoveredSlot.index, this.hoveredSlot.getItem())) {
                    return true;
                }
            }
        }
 
        return false;
    }
 
    private void extractSlotHighlightBack(GuiGraphicsExtractor graphics) {
        if (this.hoveredSlot != null && this.hoveredSlot.isHighlightable()) {
            graphics.blitSprite(RenderPipelines.GUI_TEXTURED, SLOT_HIGHLIGHT_BACK_SPRITE, this.hoveredSlot.x - 4, this.hoveredSlot.y - 4, 24, 24);
        }
    }
 
    private void extractSlotHighlightFront(GuiGraphicsExtractor graphics) {
        if (this.hoveredSlot != null && this.hoveredSlot.isHighlightable()) {
            graphics.blitSprite(RenderPipelines.GUI_TEXTURED, SLOT_HIGHLIGHT_FRONT_SPRITE, this.hoveredSlot.x - 4, this.hoveredSlot.y - 4, 24, 24);
        }
    }
 
    protected void extractTooltip(GuiGraphicsExtractor graphics, int mouseX, int mouseY) {
        if (this.hoveredSlot != null && this.hoveredSlot.hasItem()) {
            ItemStack item = this.hoveredSlot.getItem();
            if (this.menu.getCarried().isEmpty() || this.showTooltipWithItemInHand(item)) {
                graphics.setTooltipForNextFrame(
                    this.font, this.getTooltipFromContainerItem(item), item.getTooltipImage(), mouseX, mouseY, item.get(DataComponents.TOOLTIP_STYLE)
                );
            }
        }
    }
 
    private boolean showTooltipWithItemInHand(ItemStack item) {
        return item.getTooltipImage().map(ClientTooltipComponent::create).map(ClientTooltipComponent::showTooltipWithItemInHand).orElse(false);
    }
 
    protected List<Component> getTooltipFromContainerItem(ItemStack itemStack) {
        return getTooltipFromItem(this.minecraft, itemStack);
    }
 
    private void extractFloatingItem(GuiGraphicsExtractor graphics, ItemStack carried, int x, int y, @Nullable String itemCount) {
        graphics.item(carried, x, y);
        graphics.itemDecorations(this.font, carried, x, y - (this.draggingItem.isEmpty() ? 0 : 8), itemCount);
    }
 
    protected void extractLabels(GuiGraphicsExtractor graphics, int xm, int ym) {
        graphics.text(this.font, this.title, this.titleLabelX, this.titleLabelY, -12566464, false);
        graphics.text(this.font, this.playerInventoryTitle, this.inventoryLabelX, this.inventoryLabelY, -12566464, false);
    }
 
    protected void extractSlot(GuiGraphicsExtractor graphics, Slot slot, int mouseX, int mouseY) {
        int x = slot.x;
        int y = slot.y;
        ItemStack itemStack = slot.getItem();
        boolean quickCraftStack = false;
        boolean done = slot == this.clickedSlot && !this.draggingItem.isEmpty() && !this.isSplittingStack;
        ItemStack carried = this.menu.getCarried();
        String itemCount = null;
        if (slot == this.clickedSlot && !this.draggingItem.isEmpty() && this.isSplittingStack && !itemStack.isEmpty()) {
            itemStack = itemStack.copyWithCount(itemStack.getCount() / 2);
        } else if (this.isQuickCrafting && this.quickCraftSlots.contains(slot) && !carried.isEmpty()) {
            if (this.quickCraftSlots.size() == 1) {
                return;
            }
 
            if (AbstractContainerMenu.canItemQuickReplace(slot, carried, true) && this.menu.canDragTo(slot)) {
                quickCraftStack = true;
                int maxSize = Math.min(carried.getMaxStackSize(), slot.getMaxStackSize(carried));
                int carry = slot.getItem().isEmpty() ? 0 : slot.getItem().getCount();
                int newCount = AbstractContainerMenu.getQuickCraftPlaceCount(this.quickCraftSlots.size(), this.quickCraftingType, carried) + carry;
                if (newCount > maxSize) {
                    newCount = maxSize;
                    itemCount = ChatFormatting.YELLOW.toString() + maxSize;
                }
 
                itemStack = carried.copyWithCount(newCount);
            } else {
                this.quickCraftSlots.remove(slot);
                this.recalculateQuickCraftRemaining();
            }
        }
 
        if (itemStack.isEmpty() && slot.isActive()) {
            Identifier icon = slot.getNoItemIcon();
            if (icon != null) {
                graphics.blitSprite(RenderPipelines.GUI_TEXTURED, icon, x, y, 16, 16);
                done = true;
            }
        }
 
        if (!done) {
            if (quickCraftStack) {
                graphics.fill(x, y, x + 16, y + 16, -2130706433);
            }
 
            int seed = slot.x + slot.y * this.imageWidth;
            if (slot.isFake()) {
                graphics.fakeItem(itemStack, x, y, seed);
            } else {
                graphics.item(itemStack, x, y, seed);
            }
 
            graphics.itemDecorations(this.font, itemStack, x, y, itemCount);
        }
    }
 
    private void recalculateQuickCraftRemaining() {
        ItemStack carried = this.menu.getCarried();
        if (!carried.isEmpty() && this.isQuickCrafting) {
            if (this.quickCraftingType == 2) {
                this.quickCraftingRemainder = carried.getMaxStackSize();
            } else {
                this.quickCraftingRemainder = carried.getCount();
 
                for (Slot slot : this.quickCraftSlots) {
                    ItemStack slotItemStack = slot.getItem();
                    int carry = slotItemStack.isEmpty() ? 0 : slotItemStack.getCount();
                    int maxSize = Math.min(carried.getMaxStackSize(), slot.getMaxStackSize(carried));
                    int newCount = Math.min(
                        AbstractContainerMenu.getQuickCraftPlaceCount(this.quickCraftSlots.size(), this.quickCraftingType, carried) + carry, maxSize
                    );
                    this.quickCraftingRemainder -= newCount - carry;
                }
            }
        }
    }
 
    private @Nullable Slot getHoveredSlot(double x, double y) {
        for (Slot slot : this.menu.slots) {
            if (slot.isActive() && this.isHovering(slot, x, y)) {
                return slot;
            }
        }
 
        return null;
    }
 
    @Override
    public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) {
        if (super.mouseClicked(event, doubleClick)) {
            return true;
        } else {
            boolean cloning = this.minecraft.options.keyPickItem.matchesMouse(event) && this.minecraft.player.hasInfiniteMaterials();
            Slot slot = this.getHoveredSlot(event.x(), event.y());
            this.doubleclick = this.lastClickSlot == slot && doubleClick;
            this.skipNextRelease = false;
            if (event.button() != 0 && event.button() != 1 && !cloning) {
                this.checkHotbarMouseClicked(event);
            } else {
                int xo = this.leftPos;
                int yo = this.topPos;
                boolean clickedOutside = this.hasClickedOutside(event.x(), event.y(), xo, yo);
                int slotId = -1;
                if (slot != null) {
                    slotId = slot.index;
                }
 
                if (clickedOutside) {
                    slotId = -999;
                }
 
                if (this.minecraft.options.touchscreen().get() && clickedOutside && this.menu.getCarried().isEmpty()) {
                    this.onClose();
                    return true;
                }
 
                if (slotId != -1) {
                    if (this.minecraft.options.touchscreen().get()) {
                        if (slot != null && slot.hasItem()) {
                            this.clickedSlot = slot;
                            this.draggingItem = ItemStack.EMPTY;
                            this.isSplittingStack = event.button() == 1;
                        } else {
                            this.clickedSlot = null;
                        }
                    } else if (!this.isQuickCrafting) {
                        if (this.menu.getCarried().isEmpty()) {
                            if (cloning) {
                                this.slotClicked(slot, slotId, event.button(), ContainerInput.CLONE);
                            } else {
                                boolean quickKey = slotId != -999 && event.hasShiftDown();
                                ContainerInput containerInput = ContainerInput.PICKUP;
                                if (quickKey) {
                                    this.lastQuickMoved = slot != null && slot.hasItem() ? slot.getItem().copy() : ItemStack.EMPTY;
                                    containerInput = ContainerInput.QUICK_MOVE;
                                } else if (slotId == -999) {
                                    containerInput = ContainerInput.THROW;
                                }
 
                                this.slotClicked(slot, slotId, event.button(), containerInput);
                            }
 
                            this.skipNextRelease = true;
                        } else {
                            this.isQuickCrafting = true;
                            this.quickCraftingButton = event.button();
                            this.quickCraftSlots.clear();
                            if (event.button() == 0) {
                                this.quickCraftingType = 0;
                            } else if (event.button() == 1) {
                                this.quickCraftingType = 1;
                            } else if (cloning) {
                                this.quickCraftingType = 2;
                            }
                        }
                    }
                }
            }
 
            this.lastClickSlot = slot;
            return true;
        }
    }
 
    private void checkHotbarMouseClicked(MouseButtonEvent event) {
        if (this.hoveredSlot != null && this.menu.getCarried().isEmpty()) {
            if (this.minecraft.options.keySwapOffhand.matchesMouse(event)) {
                this.slotClicked(this.hoveredSlot, this.hoveredSlot.index, 40, ContainerInput.SWAP);
                return;
            }
 
            for (int i = 0; i < 9; i++) {
                if (this.minecraft.options.keyHotbarSlots[i].matchesMouse(event)) {
                    this.slotClicked(this.hoveredSlot, this.hoveredSlot.index, i, ContainerInput.SWAP);
                }
            }
        }
    }
 
    protected boolean hasClickedOutside(double mx, double my, int xo, int yo) {
        return mx < xo || my < yo || mx >= xo + this.imageWidth || my >= yo + this.imageHeight;
    }
 
    @Override
    public boolean mouseDragged(MouseButtonEvent event, double dx, double dy) {
        Slot slot = this.getHoveredSlot(event.x(), event.y());
        ItemStack carried = this.menu.getCarried();
        if (this.clickedSlot != null && this.minecraft.options.touchscreen().get()) {
            if (event.button() == 0 || event.button() == 1) {
                if (this.draggingItem.isEmpty()) {
                    if (slot != this.clickedSlot && !this.clickedSlot.getItem().isEmpty()) {
                        this.draggingItem = this.clickedSlot.getItem().copy();
                    }
                } else if (this.draggingItem.getCount() > 1 && slot != null && AbstractContainerMenu.canItemQuickReplace(slot, this.draggingItem, false)) {
                    long time = Util.getMillis();
                    if (this.quickdropSlot == slot) {
                        if (time - this.quickdropTime > 500L) {
                            this.slotClicked(this.clickedSlot, this.clickedSlot.index, 0, ContainerInput.PICKUP);
                            this.slotClicked(slot, slot.index, 1, ContainerInput.PICKUP);
                            this.slotClicked(this.clickedSlot, this.clickedSlot.index, 0, ContainerInput.PICKUP);
                            this.quickdropTime = time + 750L;
                            this.draggingItem.shrink(1);
                        }
                    } else {
                        this.quickdropSlot = slot;
                        this.quickdropTime = time;
                    }
                }
            }
 
            return true;
        } else if (slot != null && this.shouldAddSlotToQuickCraft(slot, carried) && this.quickCraftSlots.add(slot)) {
            this.recalculateQuickCraftRemaining();
            return true;
        } else {
            return slot == null && this.menu.getCarried().isEmpty() ? super.mouseDragged(event, dx, dy) : true;
        }
    }
 
    @Override
    public boolean mouseReleased(MouseButtonEvent event) {
        Slot slot = this.getHoveredSlot(event.x(), event.y());
        int xo = this.leftPos;
        int yo = this.topPos;
        boolean clickedOutside = this.hasClickedOutside(event.x(), event.y(), xo, yo);
        int slotId = -1;
        if (slot != null) {
            slotId = slot.index;
        }
 
        if (clickedOutside) {
            slotId = -999;
        }
 
        if (this.doubleclick && slot != null && event.button() == 0 && this.menu.canTakeItemForPickAll(ItemStack.EMPTY, slot)) {
            if (event.hasShiftDown()) {
                if (!this.lastQuickMoved.isEmpty()) {
                    for (Slot target : this.menu.slots) {
                        if (target != null
                            && target.mayPickup(this.minecraft.player)
                            && target.hasItem()
                            && target.container == slot.container
                            && AbstractContainerMenu.canItemQuickReplace(target, this.lastQuickMoved, true)) {
                            this.slotClicked(target, target.index, event.button(), ContainerInput.QUICK_MOVE);
                        }
                    }
                }
            } else {
                this.slotClicked(slot, slotId, event.button(), ContainerInput.PICKUP_ALL);
            }
 
            this.doubleclick = false;
        } else {
            if (this.isQuickCrafting && this.quickCraftingButton != event.button()) {
                this.isQuickCrafting = false;
                this.quickCraftSlots.clear();
                this.skipNextRelease = true;
                return true;
            }
 
            if (this.skipNextRelease) {
                this.skipNextRelease = false;
                return true;
            }
 
            if (this.clickedSlot != null && this.minecraft.options.touchscreen().get()) {
                if (event.button() == 0 || event.button() == 1) {
                    if (this.draggingItem.isEmpty() && slot != this.clickedSlot) {
                        this.draggingItem = this.clickedSlot.getItem();
                    }
 
                    boolean canReplace = AbstractContainerMenu.canItemQuickReplace(slot, this.draggingItem, false);
                    if (slotId != -1 && !this.draggingItem.isEmpty() && canReplace) {
                        this.slotClicked(this.clickedSlot, this.clickedSlot.index, event.button(), ContainerInput.PICKUP);
                        this.slotClicked(slot, slotId, 0, ContainerInput.PICKUP);
                        if (this.menu.getCarried().isEmpty()) {
                            this.snapbackData = null;
                        } else {
                            this.slotClicked(this.clickedSlot, this.clickedSlot.index, event.button(), ContainerInput.PICKUP);
                            this.snapbackData = new AbstractContainerScreen.SnapbackData(
                                this.draggingItem,
                                new Vector2i((int)event.x(), (int)event.y()),
                                new Vector2i(this.clickedSlot.x + xo, this.clickedSlot.y + yo),
                                Util.getMillis()
                            );
                        }
                    } else if (!this.draggingItem.isEmpty()) {
                        this.snapbackData = new AbstractContainerScreen.SnapbackData(
                            this.draggingItem,
                            new Vector2i((int)event.x(), (int)event.y()),
                            new Vector2i(this.clickedSlot.x + xo, this.clickedSlot.y + yo),
                            Util.getMillis()
                        );
                    }
 
                    this.clearDraggingState();
                }
            } else if (this.isQuickCrafting && !this.quickCraftSlots.isEmpty()) {
                this.quickCraftToSlots();
            } else if (!this.menu.getCarried().isEmpty()) {
                if (this.minecraft.options.keyPickItem.matchesMouse(event)) {
                    this.slotClicked(slot, slotId, event.button(), ContainerInput.CLONE);
                } else {
                    boolean quickKey = slotId != -999 && event.hasShiftDown();
                    if (quickKey) {
                        this.lastQuickMoved = slot != null && slot.hasItem() ? slot.getItem().copy() : ItemStack.EMPTY;
                    }
 
                    this.slotClicked(slot, slotId, event.button(), quickKey ? ContainerInput.QUICK_MOVE : ContainerInput.PICKUP);
                }
            }
        }
 
        this.isQuickCrafting = false;
        return super.mouseReleased(event);
    }
 
    public void clearDraggingState() {
        this.draggingItem = ItemStack.EMPTY;
        this.clickedSlot = null;
    }
 
    private boolean isHovering(Slot slot, double xm, double ym) {
        return this.isHovering(slot.x, slot.y, 16, 16, xm, ym);
    }
 
    protected boolean isHovering(int left, int top, int w, int h, double xm, double ym) {
        int xo = this.leftPos;
        int yo = this.topPos;
        xm -= xo;
        ym -= yo;
        return xm >= left - 1 && xm < left + w + 1 && ym >= top - 1 && ym < top + h + 1;
    }
 
    private void onStopHovering(Slot slot) {
        if (slot.hasItem()) {
            for (ItemSlotMouseAction itemMouseAction : this.itemSlotMouseActions) {
                if (itemMouseAction.matches(slot)) {
                    itemMouseAction.onStopHovering(slot);
                }
            }
        }
    }
 
    protected void slotClicked(Slot slot, int slotId, int buttonNum, ContainerInput containerInput) {
        if (slot != null) {
            slotId = slot.index;
        }
 
        this.onMouseClickAction(slot, containerInput);
        this.minecraft.gameMode.handleContainerInput(this.menu.containerId, slotId, buttonNum, containerInput, this.minecraft.player);
    }
 
    void onMouseClickAction(@Nullable Slot slot, ContainerInput containerInput) {
        if (slot != null && slot.hasItem()) {
            for (ItemSlotMouseAction itemMouseAction : this.itemSlotMouseActions) {
                if (itemMouseAction.matches(slot)) {
                    itemMouseAction.onSlotClicked(slot, containerInput);
                }
            }
        }
    }
 
    protected void handleSlotStateChanged(int slotId, int containerId, boolean newState) {
        this.minecraft.gameMode.handleSlotStateChanged(slotId, containerId, newState);
    }
 
    @Override
    public boolean keyPressed(KeyEvent event) {
        if (super.keyPressed(event)) {
            return true;
        } else if (this.minecraft.options.keyInventory.matches(event)) {
            this.onClose();
            return true;
        } else {
            this.checkHotbarKeyPressed(event);
            if (this.hoveredSlot != null && this.hoveredSlot.hasItem()) {
                if (this.minecraft.options.keyPickItem.matches(event)) {
                    this.slotClicked(this.hoveredSlot, this.hoveredSlot.index, 0, ContainerInput.CLONE);
                } else if (this.minecraft.options.keyDrop.matches(event)) {
                    this.slotClicked(this.hoveredSlot, this.hoveredSlot.index, event.hasControlDown() ? 1 : 0, ContainerInput.THROW);
                }
            }
 
            return false;
        }
    }
 
    protected boolean checkHotbarKeyPressed(KeyEvent event) {
        if (this.menu.getCarried().isEmpty() && this.hoveredSlot != null) {
            if (this.minecraft.options.keySwapOffhand.matches(event)) {
                this.slotClicked(this.hoveredSlot, this.hoveredSlot.index, 40, ContainerInput.SWAP);
                return true;
            }
 
            for (int i = 0; i < 9; i++) {
                if (this.minecraft.options.keyHotbarSlots[i].matches(event)) {
                    this.slotClicked(this.hoveredSlot, this.hoveredSlot.index, i, ContainerInput.SWAP);
                    return true;
                }
            }
        }
 
        return false;
    }
 
    @Override
    public void removed() {
        if (this.minecraft.player != null) {
            this.menu.removed(this.minecraft.player);
        }
    }
 
    @Override
    public boolean isPauseScreen() {
        return false;
    }
 
    @Override
    public boolean isInGameUi() {
        return true;
    }
 
    @Override
    public final void tick() {
        super.tick();
        if (this.minecraft.player.isAlive() && !this.minecraft.player.isRemoved()) {
            this.containerTick();
        } else {
            this.minecraft.player.closeContainer();
        }
    }
 
    protected void containerTick() {
    }
 
    private boolean shouldAddSlotToQuickCraft(Slot slot, ItemStack carried) {
        return this.isQuickCrafting
            && !carried.isEmpty()
            && (carried.getCount() > this.quickCraftSlots.size() || this.quickCraftingType == 2)
            && AbstractContainerMenu.canItemQuickReplace(slot, carried, true)
            && slot.mayPlace(carried)
            && this.menu.canDragTo(slot);
    }
 
    private void quickCraftToSlots() {
        this.slotClicked(null, -999, AbstractContainerMenu.getQuickcraftMask(0, this.quickCraftingType), ContainerInput.QUICK_CRAFT);
 
        for (Slot quickSlot : this.quickCraftSlots) {
            this.slotClicked(quickSlot, quickSlot.index, AbstractContainerMenu.getQuickcraftMask(1, this.quickCraftingType), ContainerInput.QUICK_CRAFT);
        }
 
        this.slotClicked(null, -999, AbstractContainerMenu.getQuickcraftMask(2, this.quickCraftingType), ContainerInput.QUICK_CRAFT);
    }
 
    @Override
    public T getMenu() {
        return this.menu;
    }
 
    @Override
    public void onClose() {
        this.minecraft.player.closeContainer();
        if (this.hoveredSlot != null) {
            this.onStopHovering(this.hoveredSlot);
        }
 
        super.onClose();
    }
 
    @OnlyIn(Dist.CLIENT)
    private record SnapbackData(ItemStack item, Vector2i start, Vector2i end, long time) {
    }
}

引用的其他类

  • BundleMouseActions

    • 引用位置: 构造调用
    • 关联成员: BundleMouseActions()
  • GuiGraphicsExtractor

    • 引用位置: 参数
  • ItemSlotMouseAction

    • 引用位置: 参数/字段
  • Screen

    • 引用位置: 继承
  • MenuAccess

    • 引用位置: 实现
  • KeyEvent

    • 引用位置: 参数
  • MouseButtonEvent

    • 引用位置: 参数
  • Component

    • 引用位置: 参数/字段/返回值
  • Identifier

    • 引用位置: 字段/方法调用
    • 关联成员: Identifier.withDefaultNamespace()
  • Mth

    • 引用位置: 方法调用
    • 关联成员: Mth.ceil(), Mth.clamp()
  • Util

    • 引用位置: 方法调用
    • 关联成员: Util.getMillis()
  • Inventory

    • 引用位置: 参数
  • AbstractContainerMenu

    • 引用位置: 方法调用
    • 关联成员: AbstractContainerMenu.canItemQuickReplace(), AbstractContainerMenu.getQuickCraftPlaceCount(), AbstractContainerMenu.getQuickcraftMask()
  • ContainerInput

    • 引用位置: 参数
  • Slot

    • 引用位置: 参数/字段/返回值
  • ItemStack

    • 引用位置: 参数/字段