From 38495e59c1d35ff8f66810d90e5c3477247db538 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 20 Aug 2021 16:49:12 +0700 Subject: [PATCH] Mattery screen rework for panels test --- .../dbotthepony/mc/otm/menu/MatteryMenu.java | 15 +- .../mc/otm/menu/slot/MatterySlot.java | 6 + .../mc/otm/screen/MatterPanelScreen.java | 1 - .../mc/otm/screen/MatteryScreen.java | 510 +++++++++++++++--- .../dbotthepony/mc/otm/screen/RGBAColor.java | 39 ++ .../mc/otm/screen/RenderHelper.java | 68 +++ .../mc/otm/screen/panels/EditablePanel.java | 73 ++- .../mc/otm/screen/panels/FramePanel.java | 2 +- .../mc/otm/screen/panels/SlotPanel.java | 121 +++++ .../resources/META-INF/accesstransformer.cfg | 16 + 10 files changed, 780 insertions(+), 71 deletions(-) create mode 100644 src/main/java/ru/dbotthepony/mc/otm/screen/RGBAColor.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/screen/panels/SlotPanel.java diff --git a/src/main/java/ru/dbotthepony/mc/otm/menu/MatteryMenu.java b/src/main/java/ru/dbotthepony/mc/otm/menu/MatteryMenu.java index f04ab8bc4..7b5e2aa34 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/menu/MatteryMenu.java +++ b/src/main/java/ru/dbotthepony/mc/otm/menu/MatteryMenu.java @@ -22,7 +22,8 @@ public abstract class MatteryMenu extends AbstractContainerMenu { protected Inventory inventory; protected Player ply; - public final ArrayList widget_list = new ArrayList<>(); + public final ArrayList> widget_list = new ArrayList<>(); + public final ArrayList inventory_slots = new ArrayList<>(); protected MatteryMenu(@Nullable MenuType p_38851_, int p_38852_, Inventory inventory) { super(p_38851_, p_38852_); @@ -35,7 +36,7 @@ public abstract class MatteryMenu extends AbstractContainerMenu { this.tile = tile; } - public void addWidget(AbstractWidget widget, Consumer> consumer) { + public void addWidget(AbstractWidget widget, Consumer> consumer) { if (widget_list.contains(widget)) return; @@ -55,7 +56,9 @@ public abstract class MatteryMenu extends AbstractContainerMenu { for (int i = 0; i < 3; ++i) { for (int j = 0; j < 9; ++j) { - Slot slot = this.addSlot(new Slot(inventory, j + i * 9 + 9, 8 + j * 18, offset + i * 18)); + var slot = new MatterySlot(inventory, j + i * 9 + 9, 8 + j * 18, 14 + i * 18); + inventory_slots.add(slot); + this.addSlot(slot); if (first) { first = false; @@ -64,10 +67,12 @@ public abstract class MatteryMenu extends AbstractContainerMenu { } } - Slot last = null; + MatterySlot last = null; for (int k = 0; k < 9; ++k) { - last = this.addSlot(new Slot(inventory, k, 8 + k * 18, offset + 58)); + last = new MatterySlot(inventory, k, 8 + k * 18, 14 + 58); + this.addSlot(last); + inventory_slots.add(last); } inventory_slot_index_end = last.index; diff --git a/src/main/java/ru/dbotthepony/mc/otm/menu/slot/MatterySlot.java b/src/main/java/ru/dbotthepony/mc/otm/menu/slot/MatterySlot.java index 53ce04c28..2b6666b14 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/menu/slot/MatterySlot.java +++ b/src/main/java/ru/dbotthepony/mc/otm/menu/slot/MatterySlot.java @@ -9,11 +9,17 @@ import ru.dbotthepony.mc.otm.container.MatteryContainer; // Just a sign that this slot needs auto draw // or belongs to MatteryContainer + +// or needs a fkin x y changed public class MatterySlot extends Slot { public boolean auto_bg; + public int x; + public int y; public MatterySlot(Container p_40223_, int index, int x, int y, boolean auto_bg) { super(p_40223_, index, x, y); + this.x = x; + this.y = y; this.auto_bg = auto_bg; } diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/MatterPanelScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/MatterPanelScreen.java index 53c439746..e5ed2c0d1 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/MatterPanelScreen.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/MatterPanelScreen.java @@ -256,7 +256,6 @@ public class MatterPanelScreen extends MatteryScreen { } } - @Override protected void renderForeground(PoseStack stack, int mouseX, int mouseY, float p_98421_) { if (open_pattern != null) { RenderSystem.disableDepthTest(); diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/MatteryScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/MatteryScreen.java index 2f26b3aa4..0ecbb7868 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/MatteryScreen.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/MatteryScreen.java @@ -1,14 +1,26 @@ package ru.dbotthepony.mc.otm.screen; +import com.google.common.collect.Sets; +import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.ChatFormatting; +import net.minecraft.Util; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.components.Widget; +import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.ClickType; import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; import ru.dbotthepony.mc.otm.OverdriveThatMatters; import ru.dbotthepony.mc.otm.menu.MatteryMenu; import ru.dbotthepony.mc.otm.menu.slot.BatterySlot; @@ -17,27 +29,115 @@ import ru.dbotthepony.mc.otm.menu.slot.MachineOutputSlot; import ru.dbotthepony.mc.otm.menu.slot.MatterContainerInputSlot; import ru.dbotthepony.mc.otm.menu.widget.AbstractWidget; import ru.dbotthepony.mc.otm.screen.panels.EditablePanel; +import ru.dbotthepony.mc.otm.screen.panels.FramePanel; +import ru.dbotthepony.mc.otm.screen.panels.SlotPanel; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.awt.*; import java.util.ArrayList; +import java.util.Set; +/** + * This class encapsulate most of logic for handling EditablePanel and it's children + * It inherits AbstractContainerScreen, but most of methods of AbstractContainerScreen are re implemented or straight removed + * since they are present inside EditablePanel subclasses, therefore it inherits + * + * It inherits AbstractContainerScreen just for signature compatibility + * + * Such as slots, they are not drawn inside MatteryScreen, but instead + * drawn by SlotPanel(s) + * + * @param type of menu, which extends MatteryMenu + */ public class MatteryScreen extends AbstractContainerScreen { protected static final ResourceLocation CONTAINER_BASE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/generic_machine.png"); public static final ResourceLocation WIDGETS = new ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets.png"); + public static final float SNAPBACK_SPEED = 100.0F; + public static final int QUICKDROP_DELAY = 500; + public static final int DOUBLECLICK_SPEED = 250; + public static final int SLOT_ITEM_BLIT_OFFSET = 100; + public static final int HOVER_ITEM_BLIT_OFFSET = 200; + + public final T menu; + public final Component playerInventoryTitle; + + @Nullable + public Slot hoveredSlot; + @Nullable + public Slot clickedSlot; + @Nullable + public Slot snapbackEnd; + @Nullable + public Slot quickdropSlot; + @Nullable + public Slot lastClickSlot; + + protected int leftPos; + protected int topPos; + protected boolean isSplittingStack; + protected ItemStack draggingItem = ItemStack.EMPTY; + protected int snapbackStartX; + protected int snapbackStartY; + protected long snapbackTime; + protected ItemStack snapbackItem = ItemStack.EMPTY; + protected long quickdropTime; + public final Set quickCraftSlots = Sets.newHashSet(); + + public boolean isQuickCrafting() { + return isQuickCrafting; + } + + protected boolean isQuickCrafting; + + public int getQuickCraftingType() { + return quickCraftingType; + } + + protected int quickCraftingType; + protected int quickCraftingButton; + protected boolean skipNextRelease; + protected int quickCraftingRemainder; + protected long lastClickTime; + protected int lastClickButton; + protected boolean doubleclick; + protected ItemStack lastQuickMoved = ItemStack.EMPTY; + protected ResourceLocation CONTAINER_BACKGROUND() { return CONTAINER_BASE; } protected ArrayList panels = new ArrayList<>(); + public FramePanel inventory; - public MatteryScreen(T p_97741_, Inventory p_97742_, Component p_97743_) { - super(p_97741_, p_97742_, p_97743_); + public MatteryScreen(T menu, Inventory inventory, Component title) { + super(menu, inventory, title); + this.menu = menu; + playerInventoryTitle = inventory.getDisplayName(); - imageWidth = 176; - imageHeight = 178; - titleLabelY = 4; + if (menu.inventory_slots.size() != 0) { + this.inventory = new FramePanel(this, null, 0, 0, 18 * 9 + 16, 3 * 18 + 18 + 24, inventory.getDisplayName()); + panels.add(this.inventory); - inventoryLabelY = imageHeight - 92; + for (var slot : menu.inventory_slots) { + new SlotPanel<>( + this, + this.inventory, + slot.x, + slot.y, + 18, 18, + slot); + } + } + } + + public ItemRenderer getItemRenderer() { + return itemRenderer; + } + + public Font getFont() { + return font; } @Override @@ -48,7 +148,9 @@ public class MatteryScreen extends AbstractContainerScree } } - return super.mouseClicked(p_97748_, p_97749_, p_97750_); + // this.slotClicked(null, -999, p_97750_, ClickType.THROW); + + return true; } @Override @@ -59,7 +161,7 @@ public class MatteryScreen extends AbstractContainerScree } } - return super.mouseDragged(p_97752_, p_97753_, p_97754_, p_97755_, p_97756_); + return true; } @Override @@ -70,7 +172,10 @@ public class MatteryScreen extends AbstractContainerScree } } - return super.mouseReleased(p_97812_, p_97813_, p_97814_); + // handle quick moving ("quickcraft") by ourselves if we depressed outside of slot + onMouseReleasedSlot(null, p_97812_, p_97813_, p_97814_, true); + + return true; } @Override @@ -81,24 +186,39 @@ public class MatteryScreen extends AbstractContainerScree } } - return super.mouseScrolled(p_94686_, p_94687_, p_94688_); + return true; } @Override public boolean keyPressed(int p_97765_, int p_97766_, int p_97767_) { + InputConstants.Key mouseKey = InputConstants.getKey(p_97765_, p_97766_); + for (var panel : panels) { if (panel.keyPressed(p_97765_, p_97766_, p_97767_)) { return true; } } + boolean handled = this.checkHotbarKeyPressed(p_97765_, p_97766_);// Forge MC-146650: Needs to return true when the key is handled + if (this.hoveredSlot != null && this.hoveredSlot.hasItem()) { + if (this.minecraft.options.keyPickItem.isActiveAndMatches(mouseKey)) { + this.slotClicked(this.hoveredSlot, this.hoveredSlot.index, 0, ClickType.CLONE); + handled = true; + } else if (this.minecraft.options.keyDrop.isActiveAndMatches(mouseKey)) { + this.slotClicked(this.hoveredSlot, this.hoveredSlot.index, hasControlDown() ? 1 : 0, ClickType.THROW); + handled = true; + } + } else if (this.minecraft.options.keyDrop.isActiveAndMatches(mouseKey)) { + handled = true; // Forge MC-146650: Emulate MC bug, so we don't drop from hotbar when pressing drop without hovering over a item. + } + + // return handled; + + // nothing dangerous in super method return super.keyPressed(p_97765_, p_97766_, p_97767_); } - @Override protected void renderTooltip(PoseStack pose, int mouseX, int mouseY) { - super.renderTooltip(pose, mouseX, mouseY); - if (this.hoveredSlot == null && menu.getCarried().isEmpty()) { for (AbstractWidget widget : menu.widget_list) { if (widget.renderTooltip(this, pose, leftPos, topPos, mouseX, mouseY)) { @@ -108,69 +228,339 @@ public class MatteryScreen extends AbstractContainerScree } } + public void renderFloatingItem(ItemStack p_97783_, int p_97784_, int p_97785_, String p_97786_) { + PoseStack posestack = RenderSystem.getModelViewStack(); + posestack.translate(0.0D, 0.0D, 32.0D); + + RenderSystem.applyModelViewMatrix(); + this.setBlitOffset(200); + this.itemRenderer.blitOffset = 200.0F; + + net.minecraft.client.gui.Font font = net.minecraftforge.client.RenderProperties.get(p_97783_).getFont(p_97783_); + if (font == null) font = this.font; + + this.itemRenderer.renderAndDecorateItem(p_97783_, p_97784_, p_97785_); + this.itemRenderer.renderGuiItemDecorations(font, p_97783_, p_97784_, p_97785_ - (this.draggingItem.isEmpty() ? 0 : 8), p_97786_); + + this.setBlitOffset(0); + this.itemRenderer.blitOffset = 0.0F; + } + @Override - public void render(PoseStack pose, int mouseX, int mouseY, float p_98421_) { - for (AbstractWidget widget : menu.widget_list) { - widget.updateIsHovered(leftPos, topPos, mouseX, mouseY); + protected void renderBg(PoseStack p_97787_, float p_97788_, int p_97789_, int p_97790_) { + + } + + @Override + public void render(PoseStack pose, int mouse_x, int mouse_y, float flag) { + int render_x = this.leftPos; + int render_y = this.topPos; + + // dark background + this.renderBackground(pose); + + hoveredSlot = null; + + // renderBg + for (AbstractWidget widget : menu.widget_list) { + widget.renderBackground(this, pose, leftPos, topPos, mouse_x, mouse_y); } - this.renderBackground(pose); - super.render(pose, mouseX, mouseY, p_98421_); - this.renderForeground(pose, mouseX, mouseY, p_98421_); - this.renderTooltip(pose, mouseX, mouseY); - } + for (var panel : panels) { + panel.render(pose, mouse_x, mouse_y, flag); + } - protected void renderRegularSlot(PoseStack pose, int x, int y) { - this.blit(pose, leftPos + x - 1, topPos + y - 1, 0, 96, 18, 18); - } + net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.GuiContainerEvent.DrawBackground(this, pose, mouse_x, mouse_y)); - protected void renderOutputSlot(PoseStack pose, int x, int y) { - this.blit(pose, leftPos + x - 5, topPos + y - 5, 18, 96, 26, 26); - } + RenderSystem.disableDepthTest(); - protected void renderBatterySlot(PoseStack pose, int x, int y) { - renderRegularSlot(pose, x, y); - this.blit(pose, leftPos + x - 1, topPos + y - 1, 0, 114, 18, 18); - } + // Screen.super.render + for (Widget widget : this.renderables) { + widget.render(pose, mouse_x, mouse_y, flag); + } + // /Screen.super.render - protected void renderForeground(PoseStack stack, int mouseX, int mouseY, float p_98421_) { + RenderSystem.disableDepthTest(); - } + net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.GuiContainerEvent.DrawForeground(this, pose, mouse_x, mouse_y)); - public Font getFont() { - return font; - } + var itemstack = this.draggingItem.isEmpty() ? this.menu.getCarried() : this.draggingItem; - @Override - protected void renderBg(PoseStack pose, float p_97788_, int mouseX, int mouseY) { - RenderSystem.setShader(GameRenderer::getPositionTexShader); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - RenderSystem.setShaderTexture(0, CONTAINER_BACKGROUND()); - // PoseStack, x, y, image_start_x, image_start_y, rect_size_x, rect_size_y - this.blit(pose, leftPos, topPos, 0, 0, this.imageWidth, this.imageHeight); + if (!itemstack.isEmpty()) { + int i2 = this.draggingItem.isEmpty() ? 8 : 16; + String override_count = null; - RenderSystem.setShader(GameRenderer::getPositionTexShader); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - RenderSystem.setShaderTexture(0, WIDGETS); + if (this.isQuickCrafting && this.quickCraftSlots.size() > 1) { + itemstack = itemstack.copy(); + itemstack.setCount(this.quickCraftingRemainder); - for (Slot slot : menu.slots) { - if (slot instanceof BatterySlot slot1 && slot1.auto_bg) { - renderBatterySlot(pose, slot1.x, slot1.y); - } else if (slot instanceof MachineOutputSlot slot1 && slot1.auto_bg) { - if (slot1.is_main_output) { - renderOutputSlot(pose, slot1.x, slot1.y); - } else { - renderRegularSlot(pose, slot1.x, slot1.y); + if (itemstack.isEmpty()) { + override_count = ChatFormatting.YELLOW + "0"; + } + } + + this.renderFloatingItem(itemstack, mouse_x - render_x - 8, mouse_y - render_y - i2, override_count); + } + + if (this.menu.getCarried().isEmpty()) { + if (this.hoveredSlot != null && this.hoveredSlot.hasItem()) { + this.renderTooltip(pose, this.hoveredSlot.getItem(), mouse_x, mouse_y); + } else { + for (var panel : panels) { + panel.renderPost(pose, mouse_x, mouse_y, flag); } - } else if (slot instanceof MatterySlot slot1 && slot1.auto_bg) { - renderRegularSlot(pose, slot1.x, slot1.y); - } else if (slot instanceof MatterContainerInputSlot slot1 && slot1.auto_bg) { - renderRegularSlot(pose, slot1.x, slot1.y); } } - for (AbstractWidget widget : menu.widget_list) { - widget.renderBackground(this, pose, leftPos, topPos, mouseX, mouseY); + RenderSystem.enableDepthTest(); + } + + // AbstractContainerScreen + public void recalculateQuickCraftRemaining() { + ItemStack itemstack = this.menu.getCarried(); + + if (!itemstack.isEmpty() && this.isQuickCrafting) { + if (this.quickCraftingType == 2) { + this.quickCraftingRemainder = itemstack.getMaxStackSize(); + } else { + this.quickCraftingRemainder = itemstack.getCount(); + + for(Slot slot : this.quickCraftSlots) { + ItemStack itemstack1 = itemstack.copy(); + ItemStack itemstack2 = slot.getItem(); + int i = itemstack2.isEmpty() ? 0 : itemstack2.getCount(); + AbstractContainerMenu.getQuickCraftSlotCount(this.quickCraftSlots, this.quickCraftingType, itemstack1, i); + int j = Math.min(itemstack1.getMaxStackSize(), slot.getMaxStackSize(itemstack1)); + if (itemstack1.getCount() > j) { + itemstack1.setCount(j); + } + + this.quickCraftingRemainder -= itemstack1.getCount() - i; + } + + } + } + } + + public void onSlotClicked(MatterySlot slot, int mouse_button) { + InputConstants.Key mouseKey = InputConstants.Type.MOUSE.getOrCreate(mouse_button); + boolean flag = this.minecraft.options.keyPickItem.isActiveAndMatches(mouseKey); + + long i = Util.getMillis(); + + this.doubleclick = this.lastClickSlot == slot && i - this.lastClickTime < 250L && this.lastClickButton == mouse_button; + this.skipNextRelease = false; + + if (mouse_button != 0 && mouse_button != 1 && !flag) { + this.checkHotbarMouseClicked(mouse_button); + } else if (!this.isQuickCrafting) { + if (this.menu.getCarried().isEmpty()) { + if (this.minecraft.options.keyPickItem.isActiveAndMatches(mouseKey)) { + this.slotClicked(slot, slot.index, mouse_button, ClickType.CLONE); + } else { + boolean shift_click = (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), 340) || InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), 344)); + ClickType clicktype = ClickType.PICKUP; + + if (shift_click) { + this.lastQuickMoved = slot != null && slot.hasItem() ? slot.getItem().copy() : ItemStack.EMPTY; + clicktype = ClickType.QUICK_MOVE; + } + + this.slotClicked(slot, slot.index, mouse_button, clicktype); + } + + this.skipNextRelease = true; + } else { + this.isQuickCrafting = true; + this.quickCraftingButton = mouse_button; + this.quickCraftSlots.clear(); + + if (mouse_button == 0) { + this.quickCraftingType = 0; + } else if (mouse_button == 1) { + this.quickCraftingType = 1; + } else if (this.minecraft.options.keyPickItem.isActiveAndMatches(mouseKey)) { + this.quickCraftingType = 2; + } + } + } + + this.lastClickSlot = slot; + this.lastClickTime = i; + this.lastClickButton = mouse_button; + } + + public void checkHotbarMouseClicked(int mouse_code) { + if (this.hoveredSlot != null && this.menu.getCarried().isEmpty()) { + if (this.minecraft.options.keySwapOffhand.matchesMouse(mouse_code)) { + this.slotClicked(this.hoveredSlot, this.hoveredSlot.index, 40, ClickType.SWAP); + return; + } + + for (int i = 0; i < 9; ++i) { + if (this.minecraft.options.keyHotbarSlots[i].matchesMouse(mouse_code)) { + this.slotClicked(this.hoveredSlot, this.hoveredSlot.index, i, ClickType.SWAP); + } + } + } + } + + public void onSlotMouseDragged(@Nonnull MatterySlot slot, int click_type) { + ItemStack itemstack = this.menu.getCarried(); + + if (this.clickedSlot != null && this.minecraft.options.touchscreen) { + if (click_type == 0 || click_type == 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 && AbstractContainerMenu.canItemQuickReplace(slot, this.draggingItem, false)) { + long i = Util.getMillis(); + if (this.quickdropSlot == slot) { + if (i - this.quickdropTime > 500L) { + this.slotClicked(this.clickedSlot, this.clickedSlot.index, 0, ClickType.PICKUP); + this.slotClicked(slot, slot.index, 1, ClickType.PICKUP); + this.slotClicked(this.clickedSlot, this.clickedSlot.index, 0, ClickType.PICKUP); + this.quickdropTime = i + 750L; + this.draggingItem.shrink(1); + } + } else { + this.quickdropSlot = slot; + this.quickdropTime = i; + } + } + } + } else if (this.isQuickCrafting && !itemstack.isEmpty() && (itemstack.getCount() > this.quickCraftSlots.size() || this.quickCraftingType == 2) && AbstractContainerMenu.canItemQuickReplace(slot, itemstack, true) && slot.mayPlace(itemstack) && this.menu.canDragTo(slot)) { + this.quickCraftSlots.add(slot); + this.recalculateQuickCraftRemaining(); + } + } + + public void onMouseReleasedSlot(@Nullable MatterySlot slot, double p_97812_, double p_97813_, int p_97814_, boolean outside) { + int i = this.leftPos; + int j = this.topPos; + InputConstants.Key mouseKey = InputConstants.Type.MOUSE.getOrCreate(p_97814_); + int k = outside ? -999 : slot != null ? slot.index : -1; + + if (this.doubleclick && p_97814_ == 0 && slot != null && this.menu.canTakeItemForPickAll(ItemStack.EMPTY, slot)) { + if (hasShiftDown()) { + if (!this.lastQuickMoved.isEmpty()) { + for(Slot slot2 : this.menu.slots) { + if (slot2 != null && slot2.mayPickup(this.minecraft.player) && slot2.hasItem() && slot2.isSameInventory(slot) && AbstractContainerMenu.canItemQuickReplace(slot2, this.lastQuickMoved, true)) { + this.slotClicked(slot2, slot2.index, p_97814_, ClickType.QUICK_MOVE); + } + } + } + } else { + this.slotClicked(slot, k, p_97814_, ClickType.PICKUP_ALL); + } + + this.doubleclick = false; + this.lastClickTime = 0L; + } else { + if (this.isQuickCrafting && this.quickCraftingButton != p_97814_) { + this.isQuickCrafting = false; + this.quickCraftSlots.clear(); + this.skipNextRelease = true; + return; + } + + if (this.skipNextRelease) { + this.skipNextRelease = false; + return; + } + + if (this.clickedSlot != null && this.minecraft.options.touchscreen) { + if (p_97814_ == 0 || p_97814_ == 1) { + if (this.draggingItem.isEmpty() && slot != this.clickedSlot) { + this.draggingItem = this.clickedSlot.getItem(); + } + + boolean flag2 = AbstractContainerMenu.canItemQuickReplace(slot, this.draggingItem, false); + if (k != -1 && !this.draggingItem.isEmpty() && flag2) { + this.slotClicked(this.clickedSlot, this.clickedSlot.index, p_97814_, ClickType.PICKUP); + this.slotClicked(slot, k, 0, ClickType.PICKUP); + if (this.menu.getCarried().isEmpty()) { + this.snapbackItem = ItemStack.EMPTY; + } else { + this.slotClicked(this.clickedSlot, this.clickedSlot.index, p_97814_, ClickType.PICKUP); + this.snapbackStartX = Mth.floor(p_97812_ - (double)i); + this.snapbackStartY = Mth.floor(p_97813_ - (double)j); + this.snapbackEnd = this.clickedSlot; + this.snapbackItem = this.draggingItem; + this.snapbackTime = Util.getMillis(); + } + } else if (!this.draggingItem.isEmpty()) { + this.snapbackStartX = Mth.floor(p_97812_ - (double)i); + this.snapbackStartY = Mth.floor(p_97813_ - (double)j); + this.snapbackEnd = this.clickedSlot; + this.snapbackItem = this.draggingItem; + this.snapbackTime = Util.getMillis(); + } + + this.draggingItem = ItemStack.EMPTY; + this.clickedSlot = null; + } + } else if (this.isQuickCrafting && !this.quickCraftSlots.isEmpty()) { + this.slotClicked((Slot)null, -999, AbstractContainerMenu.getQuickcraftMask(0, this.quickCraftingType), ClickType.QUICK_CRAFT); + + for(Slot slot1 : this.quickCraftSlots) { + this.slotClicked(slot1, slot1.index, AbstractContainerMenu.getQuickcraftMask(1, this.quickCraftingType), ClickType.QUICK_CRAFT); + } + + this.slotClicked((Slot)null, -999, AbstractContainerMenu.getQuickcraftMask(2, this.quickCraftingType), ClickType.QUICK_CRAFT); + } else if (!this.menu.getCarried().isEmpty()) { + if (this.minecraft.options.keyPickItem.isActiveAndMatches(mouseKey)) { + this.slotClicked(slot, k, p_97814_, ClickType.CLONE); + } else { + boolean flag1 = k != -999 && (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), 340) || InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), 344)); + + if (flag1) { + this.lastQuickMoved = slot.hasItem() ? slot.getItem().copy() : ItemStack.EMPTY; + } + + this.slotClicked(slot, k, p_97814_, flag1 ? ClickType.QUICK_MOVE : ClickType.PICKUP); + } + } + } + + if (this.menu.getCarried().isEmpty()) { + this.lastClickTime = 0L; + } + + this.isQuickCrafting = false; + } + + public void slotClicked(Slot p_97778_, int p_97779_, int p_97780_, ClickType p_97781_) { + if (p_97778_ != null) { + p_97779_ = p_97778_.index; + } + + this.minecraft.gameMode.handleInventoryMouseClick(this.menu.containerId, p_97779_, p_97780_, p_97781_, this.minecraft.player); + } + + protected boolean checkHotbarKeyPressed(int p_97806_, int p_97807_) { + if (this.menu.getCarried().isEmpty() && this.hoveredSlot != null) { + if (this.minecraft.options.keySwapOffhand.isActiveAndMatches(InputConstants.getKey(p_97806_, p_97807_))) { + this.slotClicked(this.hoveredSlot, this.hoveredSlot.index, 40, ClickType.SWAP); + return true; + } + + for (int i = 0; i < 9; ++i) { + if (this.minecraft.options.keyHotbarSlots[i].isActiveAndMatches(InputConstants.getKey(p_97806_, p_97807_))) { + this.slotClicked(this.hoveredSlot, this.hoveredSlot.index, i, ClickType.SWAP); + return true; + } + } + } + + return false; + } + + @Override + protected void containerTick() { + for (var panel : panels) { + panel.tick(); } } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/RGBAColor.java b/src/main/java/ru/dbotthepony/mc/otm/screen/RGBAColor.java new file mode 100644 index 000000000..72855c4cb --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/RGBAColor.java @@ -0,0 +1,39 @@ +package ru.dbotthepony.mc.otm.screen; + +public record RGBAColor(float r, float g, float b, float a) { + public RGBAColor(float r, float g, float b, float a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + public RGBAColor(int r, int g, int b) { + this(r / 255F, g / 255F, b / 255F, 1F); + } + + public RGBAColor(int r, int g, int b, int a) { + this(r / 255F, g / 255F, b / 255F, a / 255F); + } + + public static RGBAColor inv(int color) { + var r = ((color & 0xFF000000) >>> 24) / 255F; + var g = ((color & 0xFF0000) >>> 16) / 255F; + var b = ((color & 0xFF00) >>> 8) / 255F; + var a = (color & 0xFF) / 255F; + + return new RGBAColor(a, b, g, r); + } + + public RGBAColor(int color) { + this(((color & 0xFF000000) >>> 24) / 255F, ((color & 0xFF0000) >>> 16) / 255F, ((color & 0xFF00) >>> 8) / 255F, (color & 0xFF) / 255F); + } + + public int toInt() { + var r = (int) this.r; + var g = (int) this.g; + var b = (int) this.b; + + return r << 16 | g << 8 | b; + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/RenderHelper.java b/src/main/java/ru/dbotthepony/mc/otm/screen/RenderHelper.java index 5981036a3..fb9ee6eb5 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/RenderHelper.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/RenderHelper.java @@ -295,6 +295,7 @@ public class RenderHelper { float x, float y ) { + RenderSystem.setShaderTexture(0, WIDGETS); drawTexturedRectAuto(stack, x, y, 18, 18, 0, 96, 256, 256); } @@ -303,6 +304,7 @@ public class RenderHelper { float x, float y ) { + RenderSystem.setShaderTexture(0, WIDGETS); drawTexturedRectAuto(stack, x, y, 26, 26, 18, 96, 256, 256); } @@ -335,4 +337,70 @@ public class RenderHelper { bottom_left_window_corner.renderRaw(stack, x, y + height - 6, 6, 6); bottom_right_window_corner.renderRaw(stack, x + width - 6, y + height - 6, 6, 6); } + + public static RGBAColor getDrawColor() { + return rect_color; + } + + public static void setDrawColor(RGBAColor rect_color) { + RenderHelper.rect_color = rect_color; + } + + private static RGBAColor rect_color = new RGBAColor(255, 255, 255, 255); + + /** + * Draws a solid color rectangle on screen, defined by last setDrawColor(RGBColor rect_color) call + * + * @param matrix matrix to translate by + * @param x x screen coordinate + * @param y y screen coordinate + * @param width rectangle width + * @param height rectangle height + */ + public static void drawRect( + Matrix4f matrix, + float x, + float y, + float width, + float height + ) { + RenderSystem.disableTexture(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.setShader(GameRenderer::getPositionColorShader); + + var tess = Tesselator.getInstance(); + BufferBuilder builder = tess.getBuilder(); + + builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + + builder.vertex(matrix, x, y + height, depth_z).color(rect_color.r(), rect_color.g(), rect_color.b(), rect_color.a()).endVertex(); + builder.vertex(matrix, x + width, y + height, depth_z).color(rect_color.r(), rect_color.g(), rect_color.b(), rect_color.a()).endVertex(); + builder.vertex(matrix, x + width, y, depth_z).color(rect_color.r(), rect_color.g(), rect_color.b(), rect_color.a()).endVertex(); + builder.vertex(matrix, x, y, depth_z).color(rect_color.r(), rect_color.g(), rect_color.b(), rect_color.a()).endVertex(); + + tess.end(); + + RenderSystem.disableBlend(); + RenderSystem.enableTexture(); + } + + /** + * Draws a solid color rectangle on screen, defined by last setDrawColor(RGBColor rect_color) call + * + * @param stack stack to translate by + * @param x x screen coordinate + * @param y y screen coordinate + * @param width rectangle width + * @param height rectangle height + */ + public static void drawRect( + PoseStack stack, + float x, + float y, + float width, + float height + ) { + drawRect(stack.last().pose(), x, y, width, height); + } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/panels/EditablePanel.java b/src/main/java/ru/dbotthepony/mc/otm/screen/panels/EditablePanel.java index ec327f813..d93a20f19 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/panels/EditablePanel.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/panels/EditablePanel.java @@ -27,6 +27,11 @@ public class EditablePanel implements GuiEventListener { protected boolean focused = false; private boolean focused_internal = false; + // updated from render + // tells whenever is mouse within this panel's boundaries + // doesn't tell whenever it is hovered directly above and not on children + public boolean is_hovered = false; + // relative to parent // updated inside performLayout of parent if docked private float x; @@ -72,6 +77,19 @@ public class EditablePanel implements GuiEventListener { } + protected void innerRenderPost(PoseStack stack, float mouse_x, float mouse_y, float flag) { + + } + + /** + * Called on first pass + * background, items, buttons should be drawn from innerRender + * + * @param stack + * @param mouse_x + * @param mouse_y + * @param flag + */ public void render(PoseStack stack, float mouse_x, float mouse_y, float flag) { if (!getVisible()) { return; @@ -85,6 +103,10 @@ public class EditablePanel implements GuiEventListener { if (parent == null) { parent_x = x; parent_y = y; + + is_hovered = mouse_x >= x && mouse_x <= x + width && mouse_y >= y && mouse_y <= y + height; + } else { + is_hovered = parent.is_hovered && mouse_x >= parent_x && mouse_x <= parent_x + width && mouse_y >= parent_y && mouse_y <= parent_y + height; } innerRender(stack, mouse_x, mouse_y, flag); @@ -99,6 +121,29 @@ public class EditablePanel implements GuiEventListener { } } + /** + * Called on second pass + * tooltips and otherwise "on top of everything" should be drawn from innerRenderPost + * + * @param stack + * @param mouse_x + * @param mouse_y + * @param flag + */ + public void renderPost(PoseStack stack, float mouse_x, float mouse_y, float flag) { + if (!getVisible()) { + return; + } + + innerRenderPost(stack, mouse_x, mouse_y, flag); + + for (var child : children) { + if (child.getVisible()) { + child.innerRenderPost(stack, mouse_x, mouse_y, flag); + } + } + } + public void setDocking(Dock docking) { if (docking != this.docking) { this.docking = docking; @@ -574,10 +619,14 @@ public class EditablePanel implements GuiEventListener { } public boolean mouseClickedChecked(double mouse_x, double mouse_y, int flag) { + if (!getVisible()) + return false; + var pos = localToScreen(); if (getIgnoreMouseEventBoundaries() || pos.x <= mouse_x && pos.x + width >= mouse_x && pos.y <= mouse_y && pos.y + height >= mouse_y) { - return mouseClicked(mouse_x, mouse_y, flag); + mouseClicked(mouse_x, mouse_y, flag); + return true; } return false; @@ -607,10 +656,14 @@ public class EditablePanel implements GuiEventListener { } public boolean mouseReleasedChecked(double mouse_x, double mouse_y, int flag) { + if (!getVisible()) + return false; + var pos = localToScreen(); if (getIgnoreMouseEventBoundaries() || pos.x <= mouse_x && pos.x + width >= mouse_x && pos.y <= mouse_y && pos.y + height >= mouse_y) { - return mouseReleased(mouse_x, mouse_y, flag); + mouseReleased(mouse_x, mouse_y, flag); + return true; } return false; @@ -640,10 +693,14 @@ public class EditablePanel implements GuiEventListener { } public boolean mouseDraggedChecked(double mouse_x, double mouse_y, int flag, double drag_x, double drag_y) { + if (!getVisible()) + return false; + var pos = localToScreen(); if (getIgnoreMouseEventBoundaries() || pos.x <= mouse_x && pos.x + width >= mouse_x && pos.y <= mouse_y && pos.y + height >= mouse_y) { - return mouseDragged(mouse_x, mouse_y, flag, drag_x, drag_y); + mouseDragged(mouse_x, mouse_y, flag, drag_x, drag_y); + return true; } return false; @@ -666,10 +723,14 @@ public class EditablePanel implements GuiEventListener { } public boolean mouseScrolledChecked(double mouse_x, double mouse_y, double scroll) { + if (!getVisible()) + return false; + var pos = localToScreen(); if (getIgnoreMouseEventBoundaries() || pos.x <= mouse_x && pos.x + width >= mouse_x && pos.y <= mouse_y && pos.y + height >= mouse_y) { - return mouseScrolled(mouse_x, mouse_y, scroll); + mouseScrolled(mouse_x, mouse_y, scroll); + return true; } return false; @@ -756,4 +817,8 @@ public class EditablePanel implements GuiEventListener { var pos = localToScreen(); return mouse_x >= pos.x && mouse_x <= pos.x + width && mouse_y >= pos.y && mouse_y + height <= pos.y; } + + public void tick() { + + } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/panels/FramePanel.java b/src/main/java/ru/dbotthepony/mc/otm/screen/panels/FramePanel.java index 6d42a4153..b3138503c 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/panels/FramePanel.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/panels/FramePanel.java @@ -16,7 +16,7 @@ public class FramePanel extends EditablePanel implements NarratableEntry { public FramePanel(@Nonnull MatteryScreen screen, @Nullable EditablePanel parent, float x, float y, float width, float height, Component title) { super(screen, parent, x, y, width, height); this.title = title; - setDockPadding(4, screen.getFont().lineHeight + 2, 4, 4); + setDockPadding(4, 14, 4, 4); } protected boolean dragging = false; diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/panels/SlotPanel.java b/src/main/java/ru/dbotthepony/mc/otm/screen/panels/SlotPanel.java new file mode 100644 index 000000000..817db23fa --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/panels/SlotPanel.java @@ -0,0 +1,121 @@ +package ru.dbotthepony.mc.otm.screen.panels; + +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.ChatFormatting; +import net.minecraft.Util; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.ClickType; +import ru.dbotthepony.mc.otm.OverdriveThatMatters; +import ru.dbotthepony.mc.otm.menu.slot.MatterySlot; +import ru.dbotthepony.mc.otm.screen.MatteryScreen; +import ru.dbotthepony.mc.otm.screen.RGBAColor; +import ru.dbotthepony.mc.otm.screen.RenderHelper; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class SlotPanel extends EditablePanel { + public final T slot; + + public SlotPanel(@Nonnull MatteryScreen screen, @Nullable EditablePanel parent, float x, float y, float width, float height, T slot) { + super(screen, parent, x, y, width, height); + this.slot = slot; + } + + public final RGBAColor SLOT_HIGHLIGHT = new RGBAColor(255, 255, 255, 100); + public final RGBAColor SLOT_HIGHLIGHT_DRAG = new RGBAColor(200, 200, 200, 150); + + @Override + protected boolean mouseClickedInner(double mouse_x, double mouse_y, int button) { + OverdriveThatMatters.LOGGER.info("click"); + screen.onSlotClicked(slot, button); + return true; + } + + @Override + protected boolean mouseDraggedInner(double mouse_x, double mouse_y, int mouse_code, double drag_x, double drag_y) { + screen.onSlotMouseDragged(slot, mouse_code); + return true; + } + + @Override + protected boolean mouseReleasedInner(double mouse_x, double mouse_y, int flag) { + screen.onMouseReleasedSlot(slot, mouse_x, mouse_y, flag, false); + return true; + } + + protected void renderSlotBackground(PoseStack stack, float mouse_x, float mouse_y, float flag) { + RenderHelper.drawRegularSlot(stack, parent_x, parent_y); + } + + @Override + protected void innerRender(PoseStack stack, float mouse_x, float mouse_y, float flag) { + renderSlotBackground(stack, mouse_x, mouse_y, flag); + + var itemstack = slot.getItem(); + var carried = screen.menu.getCarried(); + var drag_hit = false; + String count_override = null; + + if (!carried.isEmpty() && screen.isQuickCrafting() && screen.quickCraftSlots.contains(slot)) { + if (screen.quickCraftSlots.size() == 1) { + return; + } + + if (AbstractContainerMenu.canItemQuickReplace(slot, carried, true) && screen.menu.canDragTo(slot)) { + itemstack = carried.copy(); + drag_hit = true; + + AbstractContainerMenu.getQuickCraftSlotCount(screen.quickCraftSlots, screen.getQuickCraftingType(), itemstack, slot.getItem().isEmpty() ? 0 : slot.getItem().getCount()); + int k = Math.min(itemstack.getMaxStackSize(), slot.getMaxStackSize(itemstack)); + + if (itemstack.getCount() > k) { + count_override = ChatFormatting.YELLOW.toString() + k; + itemstack.setCount(k); + } + } else { + screen.quickCraftSlots.remove(slot); + screen.recalculateQuickCraftRemaining(); + } + } + + RenderSystem.setShader(GameRenderer::getPositionTexShader); + + if (drag_hit) { + RenderHelper.setDrawColor(SLOT_HIGHLIGHT_DRAG); + RenderHelper.drawRect(stack, parent_x + 1, parent_y + 1, getWidth() - 1, getHeight() - 1); + } + + if (!itemstack.isEmpty()) { + RenderSystem.enableDepthTest(); + + var system_stack = RenderSystem.getModelViewStack(); + + system_stack.pushPose(); + system_stack.translate(parent_x + 1, parent_y + 1, 0); + RenderSystem.applyModelViewMatrix(); + + // Thanks Mojang + // Very cool + // (for int x, int y, which are then cast into doubles anyway) + screen.getItemRenderer().renderAndDecorateItem(Minecraft.getInstance().player, itemstack, 0, 0, 10 /* Z Pos ? */); + screen.getItemRenderer().renderGuiItemDecorations(screen.getFont(), itemstack, 0, 0, count_override); + + system_stack.popPose(); + RenderSystem.applyModelViewMatrix(); + } + + if (is_hovered) { + screen.hoveredSlot = slot; + + RenderSystem.disableDepthTest(); + RenderHelper.setDrawColor(SLOT_HIGHLIGHT); + RenderHelper.drawRect(stack, parent_x + 1, parent_y + 1, getWidth() - 1, getHeight() - 1); + RenderSystem.enableDepthTest(); + } + } +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index fe5968c62..d57cc8b56 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -1,2 +1,18 @@ # Make Screen.title be public and easily modifiable public-f net.minecraft.client.gui.screens.Screen f_96539_ # title + +# for accessing and setting from MatteryScreen class +# protected net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_97724_ # lastQuickMoved +# protected net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_97723_ # doubleclick +# protected net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_97709_ # lastClickSlot +# protected net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_97721_ # lastClickTime +# protected net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_97722_ # lastClickButton +# protected net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_97719_ # skipNextRelease +# protected net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_97706_ # clickedSlot +# protected net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_97710_ # isSplittingStack +# protected net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_97738_ # isQuickCrafting +# protected net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_97718_ # quickCraftingButton +# protected net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_97717_ # quickCraftingType + +# for overriding from MatteryScreen class +# protected net.minecraft.client.gui.screens.inventory.AbstractContainerScreen m_97744_ # findSlot (DD)Lnet/minecraft/world/inventory/Slot;