From 785f9051dc3d7f64165e9ca9a92a81142df0e340 Mon Sep 17 00:00:00 2001 From: brandon3055 Date: Thu, 11 Jan 2024 19:38:12 +1100 Subject: [PATCH] First round of tweaks based on covers feedback. --- build.gradle | 4 +- gradle.properties | 1 + .../java/codechicken/lib/colour/Colour.java | 72 +++++++ .../lib/gui/modular/ModularGui.java | 17 +- .../lib/gui/modular/ModularGuiContainer.java | 1 - .../lib/gui/modular/elements/GuiButton.java | 200 +++++++++--------- .../gui/modular/elements/GuiColourPicker.java | 95 +++++---- .../gui/modular/elements/GuiContextMenu.java | 12 +- .../lib/gui/modular/elements/GuiDialog.java | 172 ++++++++------- .../lib/gui/modular/elements/GuiElement.java | 48 ++--- .../gui/modular/elements/GuiEnergyBar.java | 99 +++++---- .../modular/elements/GuiEntityRenderer.java | 59 +----- .../gui/modular/elements/GuiFluidTank.java | 32 ++- .../gui/modular/elements/GuiItemStack.java | 2 +- .../gui/modular/elements/GuiManipulable.java | 78 ++----- .../gui/modular/elements/GuiProgressIcon.java | 2 +- .../gui/modular/elements/GuiRectangle.java | 84 ++++---- .../gui/modular/elements/GuiScrolling.java | 30 +-- .../lib/gui/modular/elements/GuiSlider.java | 46 ++-- .../lib/gui/modular/elements/GuiSlots.java | 193 +++++++++-------- .../lib/gui/modular/elements/GuiText.java | 30 +-- .../gui/modular/elements/GuiTextField.java | 39 ++-- .../lib/gui/modular/elements/GuiTextList.java | 30 +-- .../lib/gui/modular/elements/GuiTexture.java | 2 +- .../lib/gui/modular/lib/Assembly.java | 52 ----- .../lib/gui/modular/lib/BackgroundRender.java | 4 +- .../lib/gui/modular/lib/ColourState.java | 85 +------- .../lib/gui/modular/lib/CursorHelper.java | 38 +++- .../lib/gui/modular/lib/ForegroundRender.java | 2 +- .../lib/gui/modular/lib/GuiRender.java | 46 ++-- .../lib/gui/modular/lib/SliderState.java | 26 +-- .../lib/gui/modular/lib/TextState.java | 21 +- ...oolTipHandler.java => TooltipHandler.java} | 5 +- .../gui/modular/lib/container/DataSync.java | 6 +- .../lib/gui/modular/lib/geometry/Borders.java | 20 +- .../lib/geometry/ConstrainedGeometry.java | 31 +-- .../gui/modular/lib/geometry/Constraint.java | 8 +- .../modular/lib/geometry/ConstraintImpl.java | 2 +- .../gui/modular/lib/geometry/Direction.java | 6 +- .../gui/modular/lib/geometry/GuiParent.java | 42 +--- .../gui/modular/lib/geometry/Position.java | 20 +- .../gui/modular/sprite/ModAtlasHolder.java | 39 +++- .../gui/modular/sprite/ModSpriteLoader.java | 38 ---- .../sprite/ModSpriteResourceLoader.java | 110 ---------- .../codechicken/lib/internal/ClientInit.java | 9 + .../lib/internal/network/CCLNetwork.java | 6 +- .../internal/network/ClientPacketHandler.java | 5 +- .../internal/network/ServerPacketHandler.java | 22 ++ .../container/data/AbstractDataStore.java | 9 +- .../container/data/BooleanData.java | 9 +- .../container/data/ByteData.java | 9 +- .../container/data/DoubleData.java | 9 +- .../container/data/FloatData.java | 9 +- .../container/data/FluidData.java | 13 +- .../container/data/IntData.java | 9 +- .../container/data/LongData.java | 9 +- .../container/data/ShortData.java | 9 +- .../modular/ModularGuiContainerMenu.java | 81 +++---- .../assets/codechickenlib/atlases/gui.json | 9 + .../textures/gui/cursors/drag.png | Bin 0 -> 4183 bytes .../textures/gui/cursors/resize_diag_tlbr.png | Bin 0 -> 3987 bytes .../textures/gui/cursors/resize_diag_trbl.png | Bin 0 -> 4339 bytes .../textures/gui/cursors/resize_h.png | Bin 0 -> 3325 bytes .../textures/gui/cursors/resize_v.png | Bin 0 -> 3955 bytes .../gui/dynamic/button_borderless.png | Bin 0 -> 8152 bytes .../gui/dynamic/button_borderless_pressed.png | Bin 0 -> 12424 bytes .../textures/gui/dynamic/button_highlight.png | Bin 0 -> 10447 bytes .../dynamic/button_highlight_borderless.png | Bin 0 -> 14008 bytes .../gui/dynamic/button_highlight_pressed.png | Bin 0 -> 14458 bytes .../textures/gui/dynamic/button_pressed.png | Bin 0 -> 12741 bytes .../textures/gui/dynamic/button_vanilla.png | Bin 0 -> 8373 bytes .../gui/dynamic/button_vanilla_disabled.png | Bin 0 -> 6849 bytes .../textures/gui/dynamic/gui_borderless.png | Bin 0 -> 6281 bytes .../textures/gui/dynamic/gui_vanilla.png | Bin 0 -> 6532 bytes .../textures/gui/widgets/energy_empty.png | Bin 0 -> 8061 bytes .../textures/gui/widgets/energy_full.png | Bin 0 -> 13959 bytes .../gui/widgets/progress_arrow_empty.png | Bin 0 -> 7299 bytes .../gui/widgets/progress_arrow_full.png | Bin 0 -> 6769 bytes .../textures/gui/widgets/slot.png | Bin 0 -> 2123 bytes .../textures/gui/widgets/slot_large.png | Bin 0 -> 5546 bytes 80 files changed, 883 insertions(+), 1283 deletions(-) delete mode 100644 src/main/java/codechicken/lib/gui/modular/lib/Assembly.java rename src/main/java/codechicken/lib/gui/modular/lib/{ToolTipHandler.java => TooltipHandler.java} (96%) delete mode 100644 src/main/java/codechicken/lib/gui/modular/sprite/ModSpriteLoader.java delete mode 100644 src/main/java/codechicken/lib/gui/modular/sprite/ModSpriteResourceLoader.java create mode 100644 src/main/java/codechicken/lib/internal/network/ServerPacketHandler.java rename src/main/java/codechicken/lib/{gui/modular/lib => inventory}/container/data/AbstractDataStore.java (75%) rename src/main/java/codechicken/lib/{gui/modular/lib => inventory}/container/data/BooleanData.java (76%) rename src/main/java/codechicken/lib/{gui/modular/lib => inventory}/container/data/ByteData.java (75%) rename src/main/java/codechicken/lib/{gui/modular/lib => inventory}/container/data/DoubleData.java (75%) rename src/main/java/codechicken/lib/{gui/modular/lib => inventory}/container/data/FloatData.java (75%) rename src/main/java/codechicken/lib/{gui/modular/lib => inventory}/container/data/FluidData.java (75%) rename src/main/java/codechicken/lib/{gui/modular/lib => inventory}/container/data/IntData.java (75%) rename src/main/java/codechicken/lib/{gui/modular/lib => inventory}/container/data/LongData.java (75%) rename src/main/java/codechicken/lib/{gui/modular/lib => inventory}/container/data/ShortData.java (75%) create mode 100644 src/main/resources/assets/codechickenlib/atlases/gui.json create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/cursors/drag.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/cursors/resize_diag_tlbr.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/cursors/resize_diag_trbl.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/cursors/resize_h.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/cursors/resize_v.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_borderless.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_borderless_pressed.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_highlight.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_highlight_borderless.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_highlight_pressed.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_pressed.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_vanilla.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_vanilla_disabled.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/dynamic/gui_borderless.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/dynamic/gui_vanilla.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/widgets/energy_empty.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/widgets/energy_full.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/widgets/progress_arrow_empty.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/widgets/progress_arrow_full.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/widgets/slot.png create mode 100644 src/main/resources/assets/codechickenlib/textures/gui/widgets/slot_large.png diff --git a/build.gradle b/build.gradle index 52a1b05b..324c29a2 100644 --- a/build.gradle +++ b/build.gradle @@ -83,8 +83,8 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' - compileOnly(fg.deobf("mezz.jei:jei-${config.mc_version}-common-api:${config.jei_version}")) - compileOnly(fg.deobf("mezz.jei:jei-${config.mc_version}-forge-api:${config.jei_version}")) + compileOnly(fg.deobf("mezz.jei:jei-${mc_version}-common-api:${jei_version}")) + compileOnly(fg.deobf("mezz.jei:jei-${mc_version}-forge-api:${jei_version}")) } test { diff --git a/gradle.properties b/gradle.properties index 37d4aca9..6f3ff3aa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,3 +3,4 @@ org.gradle.daemon=false mc_version=1.20.1 forge_version=47.1.65 mod_version=4.4.0 +jei_version=15.2.0.27 diff --git a/src/main/java/codechicken/lib/colour/Colour.java b/src/main/java/codechicken/lib/colour/Colour.java index 00edece3..fa94af40 100644 --- a/src/main/java/codechicken/lib/colour/Colour.java +++ b/src/main/java/codechicken/lib/colour/Colour.java @@ -134,6 +134,78 @@ public Colour set(float[] floats) { return set(floats[0], floats[1], floats[2], floats[3]); } + public Colour r(float r) { + this.r = (byte) (255F * r); + return this; + } + + public Colour g(float g) { + this.g = (byte) (255F * g); + return this; + } + + public Colour b(float b) { + this.b = (byte) (255F * b); + return this; + } + + public Colour a(float a) { + this.a = (byte) (255F * a); + return this; + } + + public Colour r(int r) { + this.r = (byte) r; + return this; + } + + public Colour g(int g) { + this.g = (byte) g; + return this; + } + + public Colour b(int b) { + this.b = (byte) b; + return this; + } + + public Colour a(int a) { + this.a = (byte) a; + return this; + } + + public float r() { + return r / 255F; + } + + public float g() { + return g / 255F; + } + + public float b() { + return b / 255F; + } + + public float a() { + return a / 255F; + } + + public float rI() { + return r & 0xFF; + } + + public float gI() { + return g & 0xFF; + } + + public float bI() { + return b & 0xFF; + } + + public float aI() { + return a & 0xFF; + } + /** * Flips a color between ABGR and RGBA. * diff --git a/src/main/java/codechicken/lib/gui/modular/ModularGui.java b/src/main/java/codechicken/lib/gui/modular/ModularGui.java index 5b531a17..6fcb4e6f 100644 --- a/src/main/java/codechicken/lib/gui/modular/ModularGui.java +++ b/src/main/java/codechicken/lib/gui/modular/ModularGui.java @@ -6,6 +6,7 @@ import codechicken.lib.gui.modular.lib.geometry.Constraint; import codechicken.lib.gui.modular.lib.geometry.GeoParam; import codechicken.lib.gui.modular.lib.geometry.GuiParent; +import net.covers1624.quack.collection.FastStream; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.screens.Screen; @@ -55,7 +56,6 @@ public class ModularGui implements GuiParent { private Screen parentScreen; private Component guiTitle = Component.empty(); - private GuiElement focused; private ResourceLocation newCursor = null; private final Map> slotHandlers = new HashMap<>(); @@ -492,17 +492,6 @@ public double ySize() { //=== Other ===// -// @Override -// public void setFocused(@Nullable GuiElement element) { -// focused = element; -// } -// -// @Nullable -// @Override -// public GuiElement getFocused() { -// return focused; -// } - public double computeMouseX() { return mc.mouseHandler.xpos() * (double) mc.getWindow().getGuiScaledWidth() / (double) mc.getWindow().getScreenWidth(); } @@ -552,8 +541,8 @@ public void removeJEIExclude(GuiElement element) { jeiExclusions.remove(element); } - public Stream> getJeiExclusions() { - return jeiExclusions.stream().filter(GuiElement::isEnabled); + public FastStream> getJeiExclusions() { + return FastStream.of(jeiExclusions).filter(GuiElement::isEnabled); } /** diff --git a/src/main/java/codechicken/lib/gui/modular/ModularGuiContainer.java b/src/main/java/codechicken/lib/gui/modular/ModularGuiContainer.java index a2168912..a770f997 100644 --- a/src/main/java/codechicken/lib/gui/modular/ModularGuiContainer.java +++ b/src/main/java/codechicken/lib/gui/modular/ModularGuiContainer.java @@ -71,7 +71,6 @@ public void render(@NotNull GuiGraphics graphics, int mouseX, int mouseY, float imageWidth = (int) root.getValue(GeoParam.WIDTH); imageHeight = (int) root.getValue(GeoParam.HEIGHT); - modularGui.setVanillaSlotRendering(false); if (modularGui.renderBackground()) { renderBackground(graphics); } diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiButton.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiButton.java index 8b2cb051..b8df4d2b 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiButton.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiButton.java @@ -47,6 +47,106 @@ public GuiButton(@NotNull GuiParent parent) { super(parent); } + /** + * Creates a new gui button that looks and acts exactly like a standard vanilla button. + */ + public static GuiButton vanilla(@NotNull GuiParent parent, @Nullable Component label, Runnable onClick) { + return vanilla(parent, label).onClick(onClick); + } + + /** + * Creates a new gui button that looks and acts exactly like a standard vanilla button. + */ + public static GuiButton vanilla(@NotNull GuiParent parent, @Nullable Component label) { + GuiButton button = new GuiButton(parent); + GuiTexture texture = new GuiTexture(button, CCGuiTextures.getter(() -> button.toggleState() ? "dynamic/button_highlight" : "dynamic/button_vanilla")); + texture.dynamicTexture(); + GuiRectangle highlight = new GuiRectangle(button).border(() -> button.hoverTime() > 0 ? 0xFFFFFFFF : 0); + + Constraints.bind(texture, button); + Constraints.bind(highlight, button); + + if (label != null) { + button.setLabel(new GuiText(button, label)); + Constraints.bind(button.getLabel(), button, 0, 2, 0, 2); + } + + return button; + } + + /** + * Creates a vanilla button with a "press" animation. + */ + public static GuiButton vanillaAnimated(@NotNull GuiParent parent, Component label, Runnable onPress) { + return vanillaAnimated(parent, label == null ? null : () -> label, onPress); + } + + /** + * Creates a vanilla button with a "press" animation. + */ + public static GuiButton vanillaAnimated(@NotNull GuiParent parent, @Nullable Supplier label, Runnable onPress) { + return vanillaAnimated(parent, label).onPress(onPress); + } + + //TODO Could use a quad-sliced texture for this. + + /** + * Creates a vanilla button with a "press" animation. + */ + public static GuiButton vanillaAnimated(@NotNull GuiParent parent, Component label) { + return vanillaAnimated(parent, label == null ? null : () -> label); + } + + /** + * Creates a vanilla button with a "press" animation. + */ + public static GuiButton vanillaAnimated(@NotNull GuiParent parent, @Nullable Supplier label) { + GuiButton button = new GuiButton(parent); + GuiTexture texture = new GuiTexture(button, CCGuiTextures.getter(() -> button.toggleState() || button.isPressed() ? "dynamic/button_pressed" : "dynamic/button_vanilla")); + texture.dynamicTexture(); + GuiRectangle highlight = new GuiRectangle(button).border(() -> button.isMouseOver() ? 0xFFFFFFFF : 0); + + Constraints.bind(texture, button); + Constraints.bind(highlight, button); + + if (label != null) { + button.setLabel(new GuiText(button, label) + .constrain(TOP, Constraint.relative(button.get(TOP), () -> button.isPressed() ? -0.5D : 0.5D).precise()) + .constrain(LEFT, Constraint.relative(button.get(LEFT), () -> button.isPressed() ? 1.5D : 2.5D).precise()) + .constrain(WIDTH, Constraint.relative(button.get(WIDTH), -4)) + .constrain(HEIGHT, Constraint.match(button.get(HEIGHT))) + ); + } + + return button; + } + + /** + * Super simple button that is just a coloured rectangle with a label. + */ + public static GuiButton flatColourButton(@NotNull GuiParent parent, @Nullable Supplier label, Function buttonColour) { + return flatColourButton(parent, label, buttonColour, null); + } + + /** + * Super simple button that is just a coloured rectangle with a label. + */ + public static GuiButton flatColourButton(@NotNull GuiParent parent, @Nullable Supplier label, Function buttonColour, @Nullable Function borderColour) { + GuiButton button = new GuiButton(parent); + GuiRectangle background = new GuiRectangle(button) + .fill(() -> buttonColour.apply(button.isMouseOver() || button.toggleState() || button.isPressed())) + .border(borderColour == null ? null : () -> borderColour.apply(button.isMouseOver() || button.toggleState() || button.isPressed())); + Constraints.bind(background, button); + + if (label != null) { + GuiText text = new GuiText(button, label); + button.setLabel(text); + Constraints.bind(text, button, 0, 2, 0, 2); + } + + return button; + } + /** * When creating buttons with labels, use this method to store a reference to the label in the button fore easy retrival later. * @@ -232,104 +332,4 @@ public boolean mouseReleased(double mouseX, double mouseY, int button, boolean c pressed = false; return consumed; } - - /** - * Creates a new gui button that looks and acts exactly like a standard vanilla button. - */ - public static GuiButton vanilla(@NotNull GuiParent parent, @Nullable Component label, Runnable onClick) { - return vanilla(parent, label).onClick(onClick); - } - - /** - * Creates a new gui button that looks and acts exactly like a standard vanilla button. - */ - public static GuiButton vanilla(@NotNull GuiParent parent, @Nullable Component label) { - GuiButton button = new GuiButton(parent); - GuiTexture texture = new GuiTexture(button, CCGuiTextures.getter(() -> button.toggleState() ? "dynamic/button_highlight" : "dynamic/button_vanilla")); - texture.dynamicTexture(); - GuiRectangle highlight = new GuiRectangle(button).border(() -> button.hoverTime() > 0 ? 0xFFFFFFFF : 0); - - Constraints.bind(texture, button); - Constraints.bind(highlight, button); - - if (label != null) { - button.setLabel(new GuiText(button, label)); - Constraints.bind(button.getLabel(), button, 0, 2, 0, 2); - } - - return button; - } - - /** - * Creates a vanilla button with a "press" animation. - */ - public static GuiButton vanillaAnimated(@NotNull GuiParent parent, Component label, Runnable onPress) { - return vanillaAnimated(parent, label == null ? null : () -> label, onPress); - } - - /** - * Creates a vanilla button with a "press" animation. - */ - public static GuiButton vanillaAnimated(@NotNull GuiParent parent, @Nullable Supplier label, Runnable onPress) { - return vanillaAnimated(parent, label).onPress(onPress); - } - - //TODO Could use a quad-sliced texture for this. - - /** - * Creates a vanilla button with a "press" animation. - */ - public static GuiButton vanillaAnimated(@NotNull GuiParent parent, Component label) { - return vanillaAnimated(parent, label == null ? null : () -> label); - } - - /** - * Creates a vanilla button with a "press" animation. - */ - public static GuiButton vanillaAnimated(@NotNull GuiParent parent, @Nullable Supplier label) { - GuiButton button = new GuiButton(parent); - GuiTexture texture = new GuiTexture(button, CCGuiTextures.getter(() -> button.toggleState() || button.isPressed() ? "dynamic/button_pressed" : "dynamic/button_vanilla")); - texture.dynamicTexture(); - GuiRectangle highlight = new GuiRectangle(button).border(() -> button.isMouseOver() ? 0xFFFFFFFF : 0); - - Constraints.bind(texture, button); - Constraints.bind(highlight, button); - - if (label != null) { - button.setLabel(new GuiText(button, label) - .constrain(TOP, Constraint.relative(button.get(TOP), () -> button.isPressed() ? -0.5D : 0.5D).precise()) - .constrain(LEFT, Constraint.relative(button.get(LEFT), () -> button.isPressed() ? 1.5D : 2.5D).precise()) - .constrain(WIDTH, Constraint.relative(button.get(WIDTH), -4)) - .constrain(HEIGHT, Constraint.match(button.get(HEIGHT))) - ); - } - - return button; - } - - /** - * Super simple button that is just a coloured rectangle with a label. - */ - public static GuiButton flatColourButton(@NotNull GuiParent parent, @Nullable Supplier label, Function buttonColour) { - return flatColourButton(parent, label, buttonColour, null); - } - - /** - * Super simple button that is just a coloured rectangle with a label. - */ - public static GuiButton flatColourButton(@NotNull GuiParent parent, @Nullable Supplier label, Function buttonColour, @Nullable Function borderColour) { - GuiButton button = new GuiButton(parent); - GuiRectangle background = new GuiRectangle(button) - .fill(() -> buttonColour.apply(button.isMouseOver() || button.toggleState() || button.isPressed())) - .border(borderColour == null ? null : () -> borderColour.apply(button.isMouseOver() || button.toggleState() || button.isPressed())); - Constraints.bind(background, button); - - if (label != null) { - GuiText text = new GuiText(button, label); - button.setLabel(text); - Constraints.bind(text, button, 0, 2, 0, 2); - } - - return button; - } } diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiColourPicker.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiColourPicker.java index bcc7c4d8..96f1a117 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiColourPicker.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiColourPicker.java @@ -1,5 +1,6 @@ package codechicken.lib.gui.modular.elements; +import codechicken.lib.colour.Colour; import codechicken.lib.gui.modular.lib.*; import codechicken.lib.gui.modular.lib.geometry.Axis; import codechicken.lib.gui.modular.lib.geometry.GuiParent; @@ -25,52 +26,12 @@ public GuiColourPicker(@NotNull GuiParent parent) { super(parent); } - public GuiColourPicker setColourState(ColourState colourState) { - this.colourState = colourState; - return this; - } - - public ColourState getState() { - return colourState; - } - - public SliderState sliderStateAlpha() { - return SliderState.forSlider(() -> (double) colourState.alpha(), e -> colourState.setAlpha(e.floatValue()), () -> -1D / (Screen.hasShiftDown() ? 16 : 64)); - } - - public SliderState sliderStateRed() { - return SliderState.forSlider(() -> (double) colourState.red(), e -> colourState.setRed(e.floatValue()), () -> -1D / (Screen.hasShiftDown() ? 16 : 64)); - } - - public SliderState sliderStateGreen() { - return SliderState.forSlider(() -> (double) colourState.green(), e -> colourState.setGreen(e.floatValue()), () -> -1D / (Screen.hasShiftDown() ? 16 : 64)); - } - - public SliderState sliderStateBlue() { - return SliderState.forSlider(() -> (double) colourState.blue(), e -> colourState.setBlue(e.floatValue()), () -> -1D / (Screen.hasShiftDown() ? 16 : 64)); - } - - public TextState getTextState() { - return TextState.create(colourState::getHexColour, colourState::setHexColour); - } - - public GuiButton getOkButton() { - return okButton; - } - - /** - * If cancel button is disabled, ok button will automatically resize. - * */ - public GuiButton getCancelButton() { - return cancelButton; - } - public static GuiColourPicker create(GuiParent guiParent, ColourState colourState) { return create(guiParent, colourState, true); } public static GuiColourPicker create(GuiParent guiParent, ColourState colourState, boolean hasAlpha) { - int initialColour = colourState.get(); + Colour initialColour = colourState.getColour(); GuiColourPicker picker = new GuiColourPicker(guiParent.getModularGui().getRoot()); picker.setOpaque(true); picker.setColourState(colourState); @@ -80,11 +41,11 @@ public static GuiColourPicker create(GuiParent guiParent, ColourState colourS Constraints.bind(background, picker.getContentElement()); var hexField = GuiTextField.create(background, 0xFF000000, 0xFF505050, 0xe0e0e0); - hexField.primary + hexField.field() .setTextState(picker.getTextState()) .setMaxLength(hasAlpha ? 8 : 6) .setFilter(s -> s.isEmpty() || validHex(s)); - hexField.container + hexField.container() .setOpaque(true) .constrain(HEIGHT, literal(12)) .constrain(TOP, relative(background.get(TOP), 4)) @@ -92,7 +53,7 @@ public static GuiColourPicker create(GuiParent guiParent, ColourState colourS .constrain(RIGHT, relative(background.get(RIGHT), -4)); SliderBG slider = makeSlider(background, 0xFFFF0000, picker.sliderStateRed()) - .constrain(TOP, relative(hexField.container.get(BOTTOM), 2)); + .constrain(TOP, relative(hexField.container().get(BOTTOM), 2)); slider = makeSlider(background, 0xFF00FF00, picker.sliderStateGreen()) .constrain(TOP, relative(slider.get(BOTTOM), 1)); @@ -104,7 +65,7 @@ public static GuiColourPicker create(GuiParent guiParent, ColourState colourS slider = makeSlider(background, 0xFFFFFFFF, picker.sliderStateAlpha()) .constrain(TOP, relative(slider.get(BOTTOM), 1)); } else { - colourState.setAlpha(0); + colourState.set(colourState.getColour().a(0)); } ColourPreview preview = new ColourPreview(background, () -> hasAlpha ? colourState.get() : (colourState.get() | 0xFF000000)) @@ -194,7 +155,7 @@ public boolean mouseReleased(double mouseX, double mouseY, int button, boolean c } @Override - public void renderBehind(GuiRender render, double mouseX, double mouseY, float partialTicks) { + public void renderBackground(GuiRender render, double mouseX, double mouseY, float partialTicks) { render.fill(xMin(), yMin(), xMin() + 1, yMax(), colour); render.fill(xMax() - 1, yMin(), xMax(), yMax(), colour); render.fill(xMin() + 1, yCenter() - 0.5, xMax() - 1, yCenter() + 0.5, colour); @@ -216,7 +177,7 @@ public ColourPreview(@NotNull GuiParent parent, Supplier colour) { } @Override - public void renderBehind(GuiRender render, double mouseX, double mouseY, float partialTicks) { + public void renderBackground(GuiRender render, double mouseX, double mouseY, float partialTicks) { render.pushScissorRect(xMin(), yMin(), xSize(), ySize()); for (int x = 0; xMin() + (x * 2) < xMax(); x++) { for (int y = 0; yMin() + (y * 2) < yMax(); y++) { @@ -228,6 +189,46 @@ public void renderBehind(GuiRender render, double mouseX, double mouseY, float p render.rect(getRectangle(), colour.get()); } } + + public GuiColourPicker setColourState(ColourState colourState) { + this.colourState = colourState; + return this; + } + + public ColourState getState() { + return colourState; + } + + public SliderState sliderStateAlpha() { + return SliderState.forSlider(() -> (double) colourState.getColour().a(), e -> colourState.set(colourState.getColour().a(e.floatValue())), () -> -1D / (Screen.hasShiftDown() ? 16 : 64)); + } + + public SliderState sliderStateRed() { + return SliderState.forSlider(() -> (double) colourState.getColour().r(), e -> colourState.set(colourState.getColour().r(e.floatValue())), () -> -1D / (Screen.hasShiftDown() ? 16 : 64)); + } + + public SliderState sliderStateGreen() { + return SliderState.forSlider(() -> (double) colourState.getColour().g(), e -> colourState.set(colourState.getColour().g(e.floatValue())), () -> -1D / (Screen.hasShiftDown() ? 16 : 64)); + } + + public SliderState sliderStateBlue() { + return SliderState.forSlider(() -> (double) colourState.getColour().b(), e -> colourState.set(colourState.getColour().b(e.floatValue())), () -> -1D / (Screen.hasShiftDown() ? 16 : 64)); + } + + public TextState getTextState() { + return TextState.create(colourState::getHexColour, colourState::setHexColour); + } + + public GuiButton getOkButton() { + return okButton; + } + + /** + * If cancel button is disabled, ok button will automatically resize. + * */ + public GuiButton getCancelButton() { + return cancelButton; + } } diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiContextMenu.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiContextMenu.java index 122385c1..77c2b343 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiContextMenu.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiContextMenu.java @@ -36,6 +36,12 @@ public GuiContextMenu(ModularGui gui) { super(gui.getRoot()); } + public static GuiContextMenu tooltipStyleMenu(GuiParent parent) { + GuiContextMenu menu = new GuiContextMenu(parent.getModularGui()); + Constraints.bind(GuiRectangle.toolTipBackground(menu), menu); + return menu; + } + public GuiContextMenu setCloseOnItemClicked(boolean closeOnItemClicked) { this.closeOnItemClicked = closeOnItemClicked; return this; @@ -126,10 +132,4 @@ public GuiContextMenu setNormalizedPos(double x, double y) { constrain(TOP, dynamic(() -> Math.min(Math.max(y, 0), scaledScreenHeight() - ySize()))); return this; } - - public static GuiContextMenu tooltipStyleMenu(GuiParent parent) { - GuiContextMenu menu = new GuiContextMenu(parent.getModularGui()); - Constraints.bind(GuiRectangle.toolTipBackground(menu), menu); - return menu; - } } diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiDialog.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiDialog.java index 7f39f9b4..064e1f9f 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiDialog.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiDialog.java @@ -31,6 +31,90 @@ protected GuiDialog(@NotNull GuiParent parent) { super(parent); } + /** + * Option dialog builder with pre-configured background and button builders. + * + * @param parent Can be any gui element (Will just be used to get the root element) + * @param title Sets a separate title that will be displayed above the main dialog text. (Optional) + * @param dialogText The main dialog text. + * @param width The dialog width, (Height will automatically adjust based on content.) + * @param options The list of options for this dialog. + */ + public static GuiDialog optionsDialog(@NotNull GuiParent parent, @Nullable Component title, Component dialogText, int width, Option... options) { + return optionsDialog(parent, title, dialogText, GuiRectangle::toolTipBackground, GuiDialog::defaultButton, width, options); + } + + /** + * Option dialog builder with pre-configured background and button builders. + * + * @param parent Can be any gui element (Will just be used to get the root element) + * @param dialogText The main dialog text. + * @param width The dialog width, (Height will automatically adjust based on content.) + * @param options The list of options for this dialog. + */ + public static GuiDialog optionsDialog(@NotNull GuiParent parent, Component dialogText, int width, Option... options) { + return optionsDialog(parent, null, dialogText, width, options); + } + + /** + * Creates a simple info dialog for displaying information to the user. + * The dialog has a single "Ok" button that will close the dialog + * + * @param parent Can be any gui element (Will just be used to get the root element) + * @param title Sets a separate title that will be displayed above the main dialog text. (Optional) + * @param dialogText The main dialog text. + * @param width The dialog width, (Height will automatically adjust based on content.) + */ + public static GuiDialog infoDialog(@NotNull GuiParent parent, @Nullable Component title, Component dialogText, int width, @Nullable Runnable okAction) { + return optionsDialog(parent, title, dialogText, width, neutral(Component.translatable("gui.ok"), okAction)); + } + + /** + * Creates a simple info dialog for displaying information to the user. + * The dialog has a single "Ok" button that will close the dialog + * + * @param parent Can be any gui element (Will just be used to get the root element) + * @param title Sets a separate title that will be displayed above the main dialog text. (Optional) + * @param dialogText The main dialog text. + * @param width The dialog width, (Height will automatically adjust based on content.) + */ + public static GuiDialog infoDialog(@NotNull GuiParent parent, @Nullable Component title, Component dialogText, int width) { + return infoDialog(parent, title, dialogText, width, null); + } + + /** + * Creates a simple info dialog for displaying information to the user. + * The dialog has a single "Ok" button that will close the dialog + * + * @param parent Can be any gui element (Will just be used to get the root element) + * @param dialogText The main dialog text. + * @param width The dialog width, (Height will automatically adjust based on content.) + */ + public static GuiDialog infoDialog(@NotNull GuiParent parent, Component dialogText, int width) { + return infoDialog(parent, null, dialogText, width); + } + + /** + * Create a green "Primary" button option. + */ + public static Option primary(Component text, @Nullable Runnable action) { + return new Option(text, action, hovered -> hovered ? 0xFF44AA44 : 0xFF118811); + } + + /** + * Create a grey "Neutral" button option. + */ + public static Option neutral(Component text, @Nullable Runnable action) { + return new Option(text, action, hovered -> hovered ? 0xFF909090 : 0xFF505050); + } + + /** + * Create a red "Caution" button option. + */ + public static Option caution(Component text, @Nullable Runnable action) { + return new Option(text, action, hovered -> hovered ? 0xFFAA4444 : 0xFF881111); + } + /** * @param blockKeyInput Prevent keyboard inputs from being sent to the rest of the gui while this dialog is open. * Default: true. @@ -153,91 +237,5 @@ private static GuiButton defaultButton(GuiDialog dialog, Option option) { return button; } - /** - * Option dialog builder with pre-configured background and button builders. - * - * @param parent Can be any gui element (Will just be used to get the root element) - * @param title Sets a separate title that will be displayed above the main dialog text. (Optional) - * @param dialogText The main dialog text. - * @param width The dialog width, (Height will automatically adjust based on content.) - * @param options The list of options for this dialog. - */ - public static GuiDialog optionsDialog(@NotNull GuiParent parent, @Nullable Component title, Component dialogText, int width, Option... options) { - return optionsDialog(parent, title, dialogText, GuiRectangle::toolTipBackground, GuiDialog::defaultButton, width, options); - } - - /** - * Option dialog builder with pre-configured background and button builders. - * - * @param parent Can be any gui element (Will just be used to get the root element) - * @param dialogText The main dialog text. - * @param width The dialog width, (Height will automatically adjust based on content.) - * @param options The list of options for this dialog. - */ - public static GuiDialog optionsDialog(@NotNull GuiParent parent, Component dialogText, int width, Option... options) { - return optionsDialog(parent, null, dialogText, width, options); - } - - /** - * Creates a simple info dialog for displaying information to the user. - * The dialog has a single "Ok" button that will close the dialog - * - * @param parent Can be any gui element (Will just be used to get the root element) - * @param title Sets a separate title that will be displayed above the main dialog text. (Optional) - * @param dialogText The main dialog text. - * @param width The dialog width, (Height will automatically adjust based on content.) - */ - public static GuiDialog infoDialog(@NotNull GuiParent parent, @Nullable Component title, Component dialogText, int width, @Nullable Runnable okAction) { - return optionsDialog(parent, title, dialogText, width, neutral(Component.translatable("gui.ok"), okAction)); - } - - /** - * Creates a simple info dialog for displaying information to the user. - * The dialog has a single "Ok" button that will close the dialog - * - * @param parent Can be any gui element (Will just be used to get the root element) - * @param title Sets a separate title that will be displayed above the main dialog text. (Optional) - * @param dialogText The main dialog text. - * @param width The dialog width, (Height will automatically adjust based on content.) - */ - public static GuiDialog infoDialog(@NotNull GuiParent parent, @Nullable Component title, Component dialogText, int width) { - return infoDialog(parent, title, dialogText, width, null); - } - - /** - * Creates a simple info dialog for displaying information to the user. - * The dialog has a single "Ok" button that will close the dialog - * - * @param parent Can be any gui element (Will just be used to get the root element) - * @param dialogText The main dialog text. - * @param width The dialog width, (Height will automatically adjust based on content.) - */ - public static GuiDialog infoDialog(@NotNull GuiParent parent, Component dialogText, int width) { - return infoDialog(parent, null, dialogText, width); - } - - /** - * Create a green "Primary" button option. - */ - public static Option primary(Component text, @Nullable Runnable action) { - return new Option(text, action, hovered -> hovered ? 0xFF44AA44 : 0xFF118811); - } - - /** - * Create a grey "Neutral" button option. - */ - public static Option neutral(Component text, @Nullable Runnable action) { - return new Option(text, action, hovered -> hovered ? 0xFF909090 : 0xFF505050); - } - - /** - * Create a red "Caution" button option. - */ - public static Option caution(Component text, @Nullable Runnable action) { - return new Option(text, action, hovered -> hovered ? 0xFFAA4444 : 0xFF881111); - } - - public record Option(Component text, @Nullable Runnable action, Function colour) { - - } + public record Option(Component text, @Nullable Runnable action, Function colour) {} } diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiElement.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiElement.java index 5c51af86..5f5d6db8 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiElement.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiElement.java @@ -8,6 +8,7 @@ import codechicken.lib.gui.modular.lib.geometry.GuiParent; import codechicken.lib.gui.modular.lib.geometry.Position; import codechicken.lib.gui.modular.lib.geometry.Rectangle; +import net.covers1624.quack.util.SneakyUtils; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.network.chat.Component; @@ -39,20 +40,19 @@ *

* Created by brandon3055 on 04/07/2023 */ -@SuppressWarnings ("unchecked") -public class GuiElement> extends ConstrainedGeometry implements ElementEvents, ToolTipHandler { +public class GuiElement> extends ConstrainedGeometry implements ElementEvents, TooltipHandler { @NotNull private GuiParent parent; private final List> addedQueue = new ArrayList<>(); - private final List> addedFirstQueue = new ArrayList<>(); private final List> removeQueue = new ArrayList<>(); private final List> childElements = new ArrayList<>(); + private final List> childElementsUnmodifiable = Collections.unmodifiableList(childElements); public boolean initialized = false; - private Font font; private Minecraft mc; + private Font font; private int screenWidth; private int screenHeight; @@ -83,18 +83,9 @@ public GuiParent getParent() { //=== Child Element Handling ===// - /** - * When creating custom gui elements, use this method to add any required child elements. - * With ModularGui v3 it is technically possible to add children in the constructor, - * But that may not always be supported. This is the preferred method. - */ - @Deprecated//I'm starting to just do everything in the element constructors. - protected void addChildElements() { - } - @Override public List> getChildren() { - return Collections.unmodifiableList(childElements); + return childElementsUnmodifiable; } /** @@ -138,10 +129,7 @@ protected void applyQueuedChildUpdates() { public void initElement(GuiParent parent) { removed = false; updateScreenData(parent.mc(), parent.font(), parent.scaledScreenWidth(), parent.scaledScreenHeight()); - if (!initialized) { - initialized = true; - addChildElements(); - } + initialized = true; } @Override @@ -210,12 +198,12 @@ protected void updateScreenData(Minecraft mc, Font font, int screenWidth, int sc public T setEnabled(boolean enabled) { this.enabled = () -> enabled; - return (T) this; + return SneakyUtils.unsafeCast(this); } public T setEnabled(@Nullable Supplier enabled) { this.enabled = enabled; - return (T) this; + return SneakyUtils.unsafeCast(this); } public boolean isEnabled() { @@ -228,7 +216,7 @@ public boolean isRemoved() { public T setEnableToolTip(Supplier enableToolTip) { this.enableToolTip = enableToolTip; - return (T) this; + return SneakyUtils.unsafeCast(this); } @Override @@ -266,7 +254,7 @@ public boolean isOpaque() { */ public T setOpaque(boolean opaque) { this.opaque = opaque; - return (T) this; + return SneakyUtils.unsafeCast(this); } /** @@ -299,7 +287,7 @@ public String toString() { */ public T jeiExclude() { getModularGui().jeiExclude(this); - return (T) this; + return SneakyUtils.unsafeCast(this); } /** @@ -307,7 +295,7 @@ public T jeiExclude() { */ public T removeJEIExclude() { getModularGui().removeJEIExclude(this); - return (T) this; + return SneakyUtils.unsafeCast(this); } //=== Render / Update ===// @@ -319,7 +307,7 @@ public T removeJEIExclude() { */ public T setRenderCull(@Nullable Rectangle renderCull) { this.renderCull = renderCull; - return (T) this; + return SneakyUtils.unsafeCast(this); } /** @@ -333,7 +321,7 @@ public T setRenderCull(@Nullable Rectangle renderCull) { */ public T setZStacking(boolean zStacking) { this.zStacking = zStacking; - return (T) this; + return SneakyUtils.unsafeCast(this); } public boolean zStacking() { @@ -383,7 +371,7 @@ public void render(GuiRender render, double mouseX, double mouseY, float partial applyQueuedChildUpdates(); if (this instanceof BackgroundRender bgr) { double depth = bgr.getBackgroundDepth(); - bgr.renderBehind(render, mouseX, mouseY, partialTicks); + bgr.renderBackground(render, mouseX, mouseY, partialTicks); if (depth > 0) { render.pose().translate(0, 0, depth); } @@ -409,7 +397,7 @@ public void render(GuiRender render, double mouseX, double mouseY, float partial if (this instanceof ForegroundRender fgr) { double depth = fgr.getForegroundDepth(); - fgr.renderInFront(render, mouseX, mouseY, partialTicks); + fgr.renderForeground(render, mouseX, mouseY, partialTicks); if (depth > 0) { render.pose().translate(0, 0, depth); } @@ -502,7 +490,7 @@ public Supplier> getTooltip() { @Override public T setTooltipDelay(int tooltipDelay) { this.hoverTextDelay = tooltipDelay; - return (T) this; + return SneakyUtils.unsafeCast(this); } @Override @@ -513,6 +501,6 @@ public int getTooltipDelay() { @Override public T setTooltip(@Nullable Supplier> tooltip) { this.toolTip = tooltip; - return (T) this; + return SneakyUtils.unsafeCast(this); } } diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiEnergyBar.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiEnergyBar.java index 8c653e61..478e86a8 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiEnergyBar.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiEnergyBar.java @@ -1,12 +1,11 @@ package codechicken.lib.gui.modular.elements; -import codechicken.lib.gui.modular.sprite.CCGuiTextures; -import codechicken.lib.gui.modular.sprite.Material; -import codechicken.lib.gui.modular.lib.Assembly; import codechicken.lib.gui.modular.lib.BackgroundRender; import codechicken.lib.gui.modular.lib.Constraints; import codechicken.lib.gui.modular.lib.GuiRender; import codechicken.lib.gui.modular.lib.geometry.GuiParent; +import codechicken.lib.gui.modular.sprite.CCGuiTextures; +import codechicken.lib.gui.modular.sprite.Material; import codechicken.lib.util.FormatUtil; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; @@ -42,6 +41,50 @@ public GuiEnergyBar(@NotNull GuiParent parent) { setToolTipFormatter(defaultFormatter()); } + /** + * Creates a simple energy bar using a simple slot as a background to make it look nice. + */ + public static EnergyBar simpleBar(@NotNull GuiParent parent) { + GuiRectangle container = GuiRectangle.vanillaSlot(parent); + GuiEnergyBar energyBar = new GuiEnergyBar(container); + Constraints.bind(energyBar, container, 1); + return new EnergyBar(container, energyBar); + } + + public static BiFunction> defaultFormatter() { + return (energy, capacity) -> { + List tooltip = new ArrayList<>(); + tooltip.add(Component.translatable("energy_bar.polylib.energy_storage").withStyle(DARK_AQUA)); + boolean shift = Screen.hasShiftDown(); + tooltip.add(Component.translatable("energy_bar.polylib.capacity") + .withStyle(GOLD) + .append(" ") + .append(Component.literal(shift ? FormatUtil.addCommas(capacity) : FormatUtil.formatNumber(capacity)) + .withStyle(GRAY) + .append(" ") + .append(Component.translatable("energy_bar.polylib.rf") + .withStyle(GRAY) + ) + ) + ); + tooltip.add(Component.translatable("energy_bar.polylib.stored") + .withStyle(GOLD) + .append(" ") + .append(Component.literal(shift ? FormatUtil.addCommas(energy) : FormatUtil.formatNumber(energy)) + .withStyle(GRAY) + ) + .append(" ") + .append(Component.translatable("energy_bar.polylib.rf") + .withStyle(GRAY) + ) + .append(Component.literal(String.format(" (%.2f%%)", ((double) energy / (double) capacity) * 100D)) + .withStyle(GRAY) + ) + ); + return tooltip; + }; + } + public GuiEnergyBar setEmptyTexture(Material emptyTexture) { this.emptyTexture = emptyTexture; return this; @@ -88,57 +131,13 @@ public GuiEnergyBar setToolTipFormatter(BiFunction> } @Override - public void renderBehind(GuiRender render, double mouseX, double mouseY, float partialTicks) { - float p = 1/128F; + public void renderBackground(GuiRender render, double mouseX, double mouseY, float partialTicks) { + float p = 1 / 128F; float height = getCapacity() <= 0 ? 0 : (float) ySize() * (getEnergy() / (float) getCapacity()); float texHeight = height * p; render.partialSprite(EMPTY.renderType(GuiRender::texColType), xMin(), yMin(), xMax(), yMax(), EMPTY.sprite(), 0F, 1F - (p * (float) ySize()), p * (float) xSize(), 1F, 0xFFFFFFFF); render.partialSprite(FULL.renderType(GuiRender::texColType), xMin(), yMin() + (ySize() - height), xMax(), yMax(), FULL.sprite(), 0F, 1F - texHeight, p * (float) xSize(), 1F, 0xFFFFFFFF); } - /** - * Creates a simple energy bar using a simple slot as a background to make it look nice. - */ - public static Assembly simpleBar(@NotNull GuiParent parent) { - GuiRectangle container = GuiRectangle.vanillaSlot(parent); - GuiEnergyBar energyBar = new GuiEnergyBar(container); - Constraints.bind(energyBar, container, 1); - return new Assembly<>(container, energyBar); - } - - - public static BiFunction> defaultFormatter() { - return (energy, capacity) -> { - List tooltip = new ArrayList<>(); - tooltip.add(Component.translatable("energy_bar.polylib.energy_storage").withStyle(DARK_AQUA)); - boolean shift = Screen.hasShiftDown(); - tooltip.add(Component.translatable("energy_bar.polylib.capacity") - .withStyle(GOLD) - .append(" ") - .append(Component.literal(shift ? FormatUtil.addCommas(capacity) : FormatUtil.formatNumber(capacity)) - .withStyle(GRAY) - .append(" ") - .append(Component.translatable("energy_bar.polylib.rf") - .withStyle(GRAY) - ) - ) - ); - tooltip.add(Component.translatable("energy_bar.polylib.stored") - .withStyle(GOLD) - .append(" ") - .append(Component.literal(shift ? FormatUtil.addCommas(energy) : FormatUtil.formatNumber(energy)) - .withStyle(GRAY) - ) - .append(" ") - .append(Component.translatable("energy_bar.polylib.rf") - .withStyle(GRAY) - ) - .append(Component.literal(String.format(" (%.2f%%)", ((double) energy / (double) capacity) * 100D)) - .withStyle(GRAY) - ) - ); - return tooltip; - }; - } - + public record EnergyBar(GuiRectangle container, GuiEnergyBar bar) {} } diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiEntityRenderer.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiEntityRenderer.java index 1ead30fc..ac09f9b3 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiEntityRenderer.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiEntityRenderer.java @@ -165,7 +165,7 @@ public double getBackgroundDepth() { } @Override - public void renderBehind(GuiRender render, double mouseX, double mouseY, float partialTicks) { + public void renderBackground(GuiRender render, double mouseX, double mouseY, float partialTicks) { if (invalidEntity) return; try { @@ -261,61 +261,4 @@ public static void renderEntityInInventory(GuiRender render, double pX, double p render.pose().popPose(); Lighting.setupFor3DItems(); } - -// public void renderEntityOnScreen(GuiRender render, int xPos, int yPos, int scale, float mouseX, float mouseY, LivingEntity entity, double rotation, boolean trackMouse, boolean drawName, double zOffset) { -// render.pose().pushPose(); -// float lookX = trackMouse ? (float) Math.atan(mouseX / 40.0F) : 0; -// float lookY = trackMouse ? (float) Math.atan(mouseY / 40.0F) : 0; -// -// if (drawName && entity instanceof RemotePlayer && Minecraft.getInstance().player != null) { -// entity.setPos(Minecraft.getInstance().player.getX(), Minecraft.getInstance().player.getY(), Minecraft.getInstance().player.getZ()); -// } else if (entity instanceof RemotePlayer) { -// entity.setPos(0, -1000, 0); -// } -// -// PoseStack posestack = RenderSystem.getModelViewStack(); -// posestack.pushPose(); -// posestack.translate(0, 0, 0); -// posestack.scale(1.0F, 1.0F, -1.0F); -// RenderSystem.applyModelViewMatrix(); -// -// PoseStack posestack1 = render.pose(); -// posestack1.translate(xPos, yPos, zOffset); -// posestack1.scale((float) scale, (float) scale, (float) scale); -// Quaternionf quaternion = Axis.ZP.rotationDegrees(180.0F); -// posestack1.mulPose(quaternion); -// posestack1.mulPose(Axis.YP.rotationDegrees((float) rotation)); -// -// float lastYBodyRot = entity.yBodyRot; -// float lastYRot = entity.getYRot(); -// float lastXRot = entity.getXRot(); -// float lastYHeadRotO = entity.yHeadRotO; -// float lastYHeadRot = entity.yHeadRot; -// -// entity.yBodyRot = 180.0F + lookX * 20.0F; -// entity.setYRot(180.0F + lookX * 40.0F); -// entity.setXRot(-lookY * 20.0F); -// entity.yHeadRot = entity.getYRot(); -// entity.yHeadRotO = entity.getYRot(); -// -// Lighting.setupForEntityInInventory(); -// EntityRenderDispatcher entityrenderdispatcher = Minecraft.getInstance().getEntityRenderDispatcher(); -// entityrenderdispatcher.setRenderShadow(false); -// MultiBufferSource.BufferSource buffers = render.buffers(); -// RenderSystem.runAsFancy(() -> { -// entityrenderdispatcher.render(entity, 0.0D, 0.0D, 0.0D, 0.0F, 1.0F, posestack1, buffers, 15728880); -// }); -// buffers.endBatch(); -// entityrenderdispatcher.setRenderShadow(true); -// entity.yBodyRot = lastYBodyRot; -// entity.setYRot(lastYRot); -// entity.setXRot(lastXRot); -// entity.yHeadRotO = lastYHeadRotO; -// entity.yHeadRot = lastYHeadRot; -// posestack.popPose(); -// RenderSystem.applyModelViewMatrix(); -// Lighting.setupFor3DItems(); -// -// render.pose().popPose(); -// } } diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiFluidTank.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiFluidTank.java index a03c60e9..a2d4eb9a 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiFluidTank.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiFluidTank.java @@ -1,14 +1,12 @@ package codechicken.lib.gui.modular.elements; -import codechicken.lib.fluid.FluidUtils; -import codechicken.lib.util.FormatUtil; -import codechicken.lib.gui.modular.lib.Assembly; import codechicken.lib.gui.modular.lib.BackgroundRender; import codechicken.lib.gui.modular.lib.Constraints; import codechicken.lib.gui.modular.lib.GuiRender; import codechicken.lib.gui.modular.lib.geometry.GuiParent; -import codechicken.lib.gui.modular.sprite.Material; import codechicken.lib.gui.modular.sprite.CCGuiTextures; +import codechicken.lib.gui.modular.sprite.Material; +import codechicken.lib.util.FormatUtil; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureAtlasSprite; @@ -17,11 +15,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluids; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions; import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.FluidUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -58,6 +53,16 @@ public GuiFluidTank(@NotNull GuiParent parent) { setToolTipFormatter(defaultFormatter()); } + /** + * Creates a simple tank using a simple slot as a background to make it look nice. + */ + public static FluidTank simpleTank(@NotNull GuiParent parent) { + GuiRectangle container = GuiRectangle.vanillaSlot(parent); + GuiFluidTank energyBar = new GuiFluidTank(container); + Constraints.bind(energyBar, container, 1); + return new FluidTank(container, energyBar); + } + /** * Sets the capacity of this tank in milli-buckets. */ @@ -132,7 +137,7 @@ public FluidStack getFluidStack() { } @Override - public void renderBehind(GuiRender render, double mouseX, double mouseY, float partialTicks) { + public void renderBackground(GuiRender render, double mouseX, double mouseY, float partialTicks) { FluidStack stack = getFluidStack(); Material fluidMat = Material.fromSprite(getStillTexture(stack)); @@ -174,16 +179,6 @@ private double computeGaugeSpacing() { return 0; } - /** - * Creates a simple tank using a simple slot as a background to make it look nice. - */ - public static Assembly simpleTank(@NotNull GuiParent parent) { - GuiRectangle container = GuiRectangle.vanillaSlot(parent); - GuiFluidTank energyBar = new GuiFluidTank(container); - Constraints.bind(energyBar, container, 1); - return new Assembly<>(container, energyBar); - } - public static BiFunction> defaultFormatter() { return (fluidStack, capacity) -> { List tooltip = new ArrayList<>(); @@ -253,4 +248,5 @@ public static TextureAtlasSprite getStillTexture(Fluid fluid) { return Minecraft.getInstance().getTextureAtlas(TextureAtlas.LOCATION_BLOCKS).apply(texture); } + public record FluidTank(GuiRectangle container, GuiFluidTank tank) {} } diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiItemStack.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiItemStack.java index 82cb73f4..2ff85905 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiItemStack.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiItemStack.java @@ -96,7 +96,7 @@ public double getBackgroundDepth() { } @Override - public void renderBehind(GuiRender render, double mouseX, double mouseY, float partialTicks) { + public void renderBackground(GuiRender render, double mouseX, double mouseY, float partialTicks) { ItemStack stack = this.stack.get(); if (stack.isEmpty()) return; diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiManipulable.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiManipulable.java index 373d9ecf..d95835e4 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiManipulable.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiManipulable.java @@ -1,6 +1,7 @@ package codechicken.lib.gui.modular.elements; import codechicken.lib.gui.modular.lib.ContentElement; +import codechicken.lib.gui.modular.lib.CursorHelper; import codechicken.lib.gui.modular.lib.geometry.Constraint; import codechicken.lib.gui.modular.lib.geometry.GeoParam; import codechicken.lib.gui.modular.lib.geometry.GuiParent; @@ -42,7 +43,7 @@ public class GuiManipulable extends GuiElement implements Conten private boolean dragLeft = false; private boolean dragBottom = false; private boolean dragRight = false; - private ResourceLocation[] cursors = null; + private boolean enableCursors = false; //Made available for external position restraints public int xMin = 0; @@ -128,8 +129,7 @@ public GuiManipulable addResizeHandles(int handleSize, boolean includeTopHandle) } public GuiManipulable addTopHandle(int handleSize) { -// if (topHandle != null) throw new IllegalStateException("Top handle already exists!"); - this.topHandle/* = new GuiRectangle(contentElement)*/ + this.topHandle .constrain(TOP, match(contentElement.get(TOP))) .constrain(LEFT, match(contentElement.get(LEFT))) .constrain(RIGHT, match(contentElement.get(RIGHT))) @@ -138,8 +138,7 @@ public GuiManipulable addTopHandle(int handleSize) { } public GuiManipulable addBottomHandle(int handleSize) { -// if (bottomHandle != null) throw new IllegalStateException("Bottom handle already exists!"); - this.bottomHandle/* = new GuiRectangle(contentElement)*/ + this.bottomHandle .constrain(BOTTOM, match(contentElement.get(BOTTOM))) .constrain(LEFT, match(contentElement.get(LEFT))) .constrain(RIGHT, match(contentElement.get(RIGHT))) @@ -148,8 +147,7 @@ public GuiManipulable addBottomHandle(int handleSize) { } public GuiManipulable addLeftHandle(int handleSize) { -// if (leftHandle != null) throw new IllegalStateException("Left handle already exists!"); - this.leftHandle/* = new GuiRectangle(contentElement)*/ + this.leftHandle .constrain(LEFT, match(contentElement.get(LEFT))) .constrain(TOP, match(contentElement.get(TOP))) .constrain(BOTTOM, match(contentElement.get(BOTTOM))) @@ -158,8 +156,7 @@ public GuiManipulable addLeftHandle(int handleSize) { } public GuiManipulable addRightHandle(int handleSize) { -// if (rightHandle != null) throw new IllegalStateException("Left handle already exists!"); - this.rightHandle /*= new GuiRectangle(contentElement)*/ + this.rightHandle .constrain(RIGHT, match(contentElement.get(RIGHT))) .constrain(TOP, match(contentElement.get(TOP))) .constrain(BOTTOM, match(contentElement.get(BOTTOM))) @@ -168,8 +165,7 @@ public GuiManipulable addRightHandle(int handleSize) { } public GuiManipulable addMoveHandle(int handleSize) { -// if (moveHandle != null) throw new IllegalStateException("Move handle already exists!"); - this.moveHandle/* = new GuiRectangle(contentElement)*/ + this.moveHandle .constrain(TOP, match(contentElement.get(TOP))) .constrain(LEFT, match(contentElement.get(LEFT))) .constrain(RIGHT, match(contentElement.get(RIGHT))) @@ -218,12 +214,10 @@ public GuiElement getBottomHandle() { } /** - * Set an array of 5 mouse cursor icons to be used when manipulating the gui element. - * These cursors are (in order) Drag (Any direction), Drag-Horizontal, Drag-Vertical, Drag-Corner (Top Right/Bottom Left), Drag-Corner (Top Left/Bottom Right) + * Enables rendering of custom mouse cursors when hovering over a draggable handle. */ - public GuiManipulable setCursors(ResourceLocation[] cursors) { - if (cursors != null && cursors.length != 5) throw new IllegalStateException("Must provide 5 cursor icons, no more, no less. Found "+ cursors.length); - this.cursors = cursors; + public GuiManipulable enableCursors(boolean enableCursors) { + this.enableCursors = enableCursors; return this; } @@ -261,7 +255,7 @@ public Rectangle getMaxSize() { @Override public void tick(double mouseX, double mouseY) { - if (cursors != null) { + if (enableCursors) { boolean posFlag = moveHandle != null && moveHandle.isMouseOver(); boolean topFlag = topHandle != null && topHandle.isMouseOver(); boolean leftFlag = leftHandle != null && leftHandle.isMouseOver(); @@ -271,15 +265,15 @@ public void tick(double mouseX, double mouseY) { if (any) { if (posFlag) { - getModularGui().setCursor(cursors[0]); + getModularGui().setCursor(CursorHelper.DRAG); } else if ((topFlag && leftFlag) || (bottomFlag && rightFlag)) { - getModularGui().setCursor(cursors[4]); + getModularGui().setCursor(CursorHelper.RESIZE_TLBR); } else if ((topFlag && rightFlag) || (bottomFlag && leftFlag)) { - getModularGui().setCursor(cursors[3]); + getModularGui().setCursor(CursorHelper.RESIZE_TRBL); } else if (topFlag || bottomFlag) { - getModularGui().setCursor(cursors[2]); + getModularGui().setCursor(CursorHelper.RESIZE_V); } else { - getModularGui().setCursor(cursors[1]); + getModularGui().setCursor(CursorHelper.RESIZE_H); } } } @@ -294,8 +288,6 @@ public void startDragging() { dragYOffset = (int) (mouseY - yMin); isDragging = true; dragPos = true; - onStartMove(mouseX, mouseY); - onStartManipulation(mouseX, mouseY); } @Override @@ -314,19 +306,11 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { isDragging = true; if (posFlag) { dragPos = true; - if (onStartMove(mouseX, mouseY)) { - isDragging = false; - return true; - } } else { dragTop = topFlag; dragLeft = leftFlag; dragBottom = bottomFlag; dragRight = rightFlag; - onStartResized(mouseX, mouseY); - } - if (onStartManipulation(mouseX, mouseY)) { - dragPos = dragTop = dragLeft = dragBottom = dragRight = false; } return true; } @@ -346,7 +330,6 @@ public void mouseMoved(double mouseX, double mouseY) { yMin += yMove; yMax += yMove; validatePosition(); - validateMove(previous, (int) mouseX, (int) mouseY); onMoved(); } else { Rectangle min = getMinSize(); @@ -378,7 +361,6 @@ public void mouseMoved(double mouseX, double mouseY) { validatePosition(); onResized(); } - onManipulated(mouseX, mouseY); } super.mouseMoved(mouseX, mouseY); } @@ -387,12 +369,6 @@ public void mouseMoved(double mouseX, double mouseY) { public boolean mouseReleased(double mouseX, double mouseY, int button, boolean consumed) { if (isDragging) { validatePosition(); - if (dragPos) { - onFinishMove(mouseX, mouseY); - } else { - onFinishResized(mouseX, mouseY); - } - onFinishManipulation(mouseX, mouseY); } isDragging = dragPos = dragTop = dragLeft = dragBottom = dragRight = false; return super.mouseReleased(mouseX, mouseY, button, consumed); @@ -419,28 +395,6 @@ protected void onResized() { } } - //TODO, In v2 these were made available for elements that extend GuiManipulable, In v3 i probably just want to add listener hooks. - protected void onManipulated(double mouseX, double mouseY) {} - - protected boolean onStartManipulation(double mouseX, double mouseY) { - return false; - } - - protected void onFinishManipulation(double mouseX, double mouseY) {} - - protected boolean onStartMove(double mouseX, double mouseY) { - return false; - } - - protected void onStartResized(double mouseX, double mouseY) {} - - protected void onFinishMove(double mouseX, double mouseY) {} - - protected void onFinishResized(double mouseX, double mouseY) {} - - protected void validateMove(Rectangle previous, double mouseX, double mouseY) { - } - public interface PositionRestraint { void restrainPosition(GuiManipulable draggable); } diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiProgressIcon.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiProgressIcon.java index 00449739..3e56ce61 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiProgressIcon.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiProgressIcon.java @@ -91,7 +91,7 @@ public double getProgress() { } @Override - public void renderBehind(GuiRender render, double mouseX, double mouseY, float partialTicks) { + public void renderBackground(GuiRender render, double mouseX, double mouseY, float partialTicks) { render.pose().pushPose(); double width = direction.getAxis() == Axis.X ? xSize() : ySize(); diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiRectangle.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiRectangle.java index b707d13f..0d034702 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiRectangle.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiRectangle.java @@ -31,6 +31,46 @@ public GuiRectangle(@NotNull GuiParent parent) { super(parent); } + /** + * Creates a rectangle that mimics the appearance of a vanilla inventory slot. + * Uses shadedRect to create the 3D "inset" look. + */ + public static GuiRectangle vanillaSlot(@NotNull GuiParent parent) { + return new GuiRectangle(parent).shadedRect(0xFF373737, 0xFFffffff, 0xFF8b8b8b, 0xFF8b8b8b); + } + + /** + * Creates a rectangle that mimics the appearance of a vanilla inventory slot, except inverted + * Uses shadedRect to create the 3D "popped out" appearance + */ + public static GuiRectangle invertedSlot(@NotNull GuiParent parent) { + return new GuiRectangle(parent).shadedRect(0xFFffffff, 0xFF373737, 0xFF8b8b8b, 0xFF8b8b8b); + } + + /** + * Creates a rectangle similar in appearance to a vanilla button, but with no texture and no black border. + */ + public static GuiRectangle planeButton(@NotNull GuiParent parent) { + return new GuiRectangle(parent).shadedRect(0xFFaaaaaa, 0xFF545454, 0xFF6f6f6f); + } + + public static GuiRectangle toolTipBackground(@NotNull GuiParent parent) { + return toolTipBackground(parent, 0xF0100010, 0x505000FF, 0x5028007f); + } + + public static GuiRectangle toolTipBackground(@NotNull GuiParent parent, int backgroundColour, int borderColourTop, int borderColourBottom) { + return toolTipBackground(parent, backgroundColour, backgroundColour, borderColourTop, borderColourBottom); + } + + public static GuiRectangle toolTipBackground(@NotNull GuiParent parent, int backgroundColourTop, int backgroundColourBottom, int borderColourTop, int borderColourBottom) { + return new GuiRectangle(parent) { + @Override + public void renderBackground(GuiRender render, double mouseX, double mouseY, float partialTicks) { + render.toolTipBackground(xMin(), yMin(), xSize(), ySize(), backgroundColourTop, backgroundColourBottom, borderColourTop, borderColourBottom, false); + } + }; + } + public GuiRectangle border(int border) { return border(() -> border); } @@ -113,53 +153,13 @@ public double getBorderWidth() { } @Override - public void renderBehind(GuiRender render, double mouseX, double mouseY, float partialTicks) { + public void renderBackground(GuiRender render, double mouseX, double mouseY, float partialTicks) { if (shadeTopLeft != null && shadeBottomRight != null && shadeCorners != null) { render.shadedRect(getRectangle(), getBorderWidth(), shadeTopLeft.get(), shadeBottomRight.get(), shadeCorners.get(), fill == null ? 0 : fill.get()); - } else if (border != null){ + } else if (border != null) { render.borderRect(getRectangle(), getBorderWidth(), fill == null ? 0 : fill.get(), border.get()); } else if (fill != null) { render.rect(getRectangle(), fill.get()); } } - - /** - * Creates a rectangle that mimics the appearance of a vanilla inventory slot. - * Uses shadedRect to create the 3D "inset" look. - */ - public static GuiRectangle vanillaSlot(@NotNull GuiParent parent) { - return new GuiRectangle(parent).shadedRect(0xFF373737, 0xFFffffff, 0xFF8b8b8b, 0xFF8b8b8b); - } - - /** - * Creates a rectangle that mimics the appearance of a vanilla inventory slot, except inverted - * Uses shadedRect to create the 3D "popped out" appearance - */ - public static GuiRectangle invertedSlot(@NotNull GuiParent parent) { - return new GuiRectangle(parent).shadedRect(0xFFffffff, 0xFF373737, 0xFF8b8b8b, 0xFF8b8b8b); - } - - /** - * Creates a rectangle similar in appearance to a vanilla button, but with no texture and no black border. - */ - public static GuiRectangle planeButton(@NotNull GuiParent parent) { - return new GuiRectangle(parent).shadedRect(0xFFaaaaaa, 0xFF545454, 0xFF6f6f6f); - } - - public static GuiRectangle toolTipBackground(@NotNull GuiParent parent) { - return toolTipBackground(parent, 0xF0100010, 0x505000FF, 0x5028007f); - } - - public static GuiRectangle toolTipBackground(@NotNull GuiParent parent, int backgroundColour, int borderColourTop, int borderColourBottom) { - return toolTipBackground(parent, backgroundColour, backgroundColour, borderColourTop, borderColourBottom); - } - - public static GuiRectangle toolTipBackground(@NotNull GuiParent parent, int backgroundColourTop, int backgroundColourBottom, int borderColourTop, int borderColourBottom) { - return new GuiRectangle(parent) { - @Override - public void renderBehind(GuiRender render, double mouseX, double mouseY, float partialTicks) { - render.toolTipBackground(xMin(), yMin(), xSize(), ySize(), backgroundColourTop, backgroundColourBottom, borderColourTop, borderColourBottom, false); - } - }; - } } diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiScrolling.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiScrolling.java index 8aa40767..c0c5f9e0 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiScrolling.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiScrolling.java @@ -1,6 +1,9 @@ package codechicken.lib.gui.modular.elements; -import codechicken.lib.gui.modular.lib.*; +import codechicken.lib.gui.modular.lib.Constraints; +import codechicken.lib.gui.modular.lib.ContentElement; +import codechicken.lib.gui.modular.lib.GuiRender; +import codechicken.lib.gui.modular.lib.SliderState; import codechicken.lib.gui.modular.lib.geometry.Axis; import codechicken.lib.gui.modular.lib.geometry.Constraint; import codechicken.lib.gui.modular.lib.geometry.GeoParam; @@ -173,7 +176,7 @@ public ContentElement constrain(GeoParam param, @Nullable Constraint constraint) } } - public static Assembly, GuiScrolling> simpleScrollWindow(@NotNull GuiParent parent, boolean verticalScrollBar, boolean horizontalScrollBar) { + public static ScrollWindow simpleScrollWindow(@NotNull GuiParent parent, boolean verticalScrollBar, boolean horizontalScrollBar) { GuiElement container = new GuiElement<>(parent); GuiRectangle background = GuiRectangle.vanillaSlot(container) .constrain(TOP, match(container.get(TOP))) @@ -184,32 +187,33 @@ public static Assembly, GuiScrolling> simpleScrollWindow GuiScrolling scroll = new GuiScrolling(background); Constraints.bind(scroll, background, 1); - var result = new Assembly<>(container, scroll); - + GuiSlider.ScrollBar verticalBar = null; if (verticalScrollBar) { - var bar = GuiSlider.vanillaScrollBar(container, Axis.Y); - bar.container + verticalBar = GuiSlider.vanillaScrollBar(container, Axis.Y); + verticalBar.container() .constrain(TOP, match(container.get(TOP))) .constrain(BOTTOM, relative(container.get(BOTTOM), horizontalScrollBar ? -10 : 0)) .constrain(RIGHT, match(container.get(RIGHT))) .constrain(WIDTH, Constraint.literal(9)); - bar.primary + verticalBar.slider() .setSliderState(scroll.scrollState(Axis.Y)) .setScrollableElement(scroll); - result.addParts(bar.container, bar.primary, bar.getPart(0)); } + GuiSlider.ScrollBar horizontalBar = null; if (horizontalScrollBar) { - var bar = GuiSlider.vanillaScrollBar(container, Axis.X); - bar.container + horizontalBar = GuiSlider.vanillaScrollBar(container, Axis.X); + horizontalBar.container() .constrain(BOTTOM, match(container.get(BOTTOM))) .constrain(LEFT, match(container.get(LEFT))) .constrain(RIGHT, relative(container.get(RIGHT), verticalScrollBar ? -10 : 0)) .constrain(HEIGHT, Constraint.literal(9)); - bar.primary + horizontalBar.slider() .setSliderState(scroll.scrollState(Axis.X)) .setScrollableElement(scroll); - result.addParts(bar.container, bar.primary, bar.getPart(0)); } - return result; + return new ScrollWindow(container, scroll, verticalBar, horizontalBar); + } + + public record ScrollWindow(GuiElement container, GuiScrolling scrolling, @Nullable GuiSlider.ScrollBar verticalBar, @Nullable GuiSlider.ScrollBar horizontalBar) { } } diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiSlider.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiSlider.java index 47d94246..2157ccf8 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiSlider.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiSlider.java @@ -57,6 +57,29 @@ public GuiSlider(@NotNull GuiParent parent, Axis axis, GuiElement slider) installSlider(slider); } + /** + * Vanilla does not really seem to have a standard for its scroll bars, + * But this is something that should at least fit in to a typical vanilla gui. + */ + public static ScrollBar vanillaScrollBar(GuiElement parent, Axis axis) { + GuiRectangle background = GuiRectangle.vanillaSlot(parent); + + GuiSlider slider = new GuiSlider(background, axis); + Constraints.bind(slider, background, 1); + + slider.installSlider(GuiRectangle.planeButton(slider)) + .bindSliderLength() + .bindSliderWidth(); + + GuiRectangle sliderHighlight = new GuiRectangle(slider.getSlider()) + .fill(0x5000b6FF) + .setEnabled(() -> slider.getSlider().isMouseOver()); + + Constraints.bind(sliderHighlight, slider.getSlider()); + + return new ScrollBar(background, slider, sliderHighlight); + } + /** * Set the slider state used by this slider element. * The slider state is used to get and set the slider position. @@ -239,26 +262,5 @@ public boolean mouseScrolled(double mouseX, double mouseY, double scroll) { return false; } - /** - * Vanilla does not really seem to have a standard for its scroll bars, - * But this is something that should at least fit in to a typical vanilla gui. - */ - public static Assembly vanillaScrollBar(GuiElement parent, Axis axis) { - GuiRectangle background = GuiRectangle.vanillaSlot(parent); - - GuiSlider slider = new GuiSlider(background, axis); - Constraints.bind(slider, background, 1); - - slider.installSlider(GuiRectangle.planeButton(slider)) - .bindSliderLength() - .bindSliderWidth(); - - GuiRectangle sliderHighlight = new GuiRectangle(slider.getSlider()) - .fill(0x5000b6FF) - .setEnabled(() -> slider.getSlider().isMouseOver()); - - Constraints.bind(sliderHighlight, slider.getSlider()); - - return new Assembly<>(background, slider).addParts(sliderHighlight); - } + public record ScrollBar(GuiRectangle container, GuiSlider slider, GuiRectangle highlight) {} } diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiSlots.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiSlots.java index 8c94d9da..9ce861eb 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiSlots.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiSlots.java @@ -1,6 +1,5 @@ package codechicken.lib.gui.modular.elements; -import codechicken.lib.gui.modular.lib.Assembly; import codechicken.lib.gui.modular.lib.BackgroundRender; import codechicken.lib.gui.modular.lib.GuiRender; import codechicken.lib.gui.modular.lib.container.ContainerScreenAccess; @@ -81,6 +80,101 @@ public GuiSlots(@NotNull GuiParent parent, ContainerScreenAccess screenAcc updateSlots(parent.getModularGui().getRoot()); } + //=== Construction Helpers ===// + + public static GuiSlots singleSlot(@NotNull GuiParent parent, ContainerScreenAccess screenAccess, SlotGroup slots) { + return singleSlot(parent, screenAccess, slots, 0); + } + + public static GuiSlots singleSlot(@NotNull GuiParent parent, ContainerScreenAccess screenAccess, SlotGroup slots, int index) { + return new GuiSlots(parent, screenAccess, slots, index, 1, 1); + } + + public static Player player(@NotNull GuiParent parent, ContainerScreenAccess screenAccess, SlotGroup mainSlots, SlotGroup hotBarSlots) { + return player(parent, screenAccess, mainSlots, hotBarSlots, 3); + } + + public static Player player(@NotNull GuiParent parent, ContainerScreenAccess screenAccess, SlotGroup mainSlots, SlotGroup hotBarSlots, int hotBarSpacing) { + int width = 18 * 9; + int height = 18 * 4 + hotBarSpacing; + GuiElement container = new GuiElement<>(parent) + .setZStacking(false) + .constrain(WIDTH, Constraint.literal(width)) + .constrain(HEIGHT, Constraint.literal(height)); + + GuiSlots main = new GuiSlots(container, screenAccess, mainSlots, 9) + .constrain(TOP, Constraint.midPoint(container.get(TOP), container.get(BOTTOM), height / -2D)) + .constrain(LEFT, Constraint.midPoint(container.get(LEFT), container.get(RIGHT), width / -2D)); + + GuiSlots bar = new GuiSlots(container, screenAccess, hotBarSlots, 9) + .constrain(TOP, relative(main.get(BOTTOM), hotBarSpacing)) + .constrain(LEFT, match(main.get(LEFT))); + return new Player(container, main, bar); + } + + public static PlayerWithArmor playerWithArmor(@NotNull GuiParent parent, ContainerScreenAccess screenAccess, SlotGroup mainSlots, SlotGroup hotBarSlots, SlotGroup armorSlots) { + return playerWithArmor(parent, screenAccess, mainSlots, hotBarSlots, armorSlots, 3, true); + } + + public static PlayerWithArmor playerWithArmor(@NotNull GuiParent parent, ContainerScreenAccess screenAccess, SlotGroup mainSlots, SlotGroup hotBarSlots, SlotGroup armorSlots, int groupSpacing, boolean slotIcons) { + int width = 18 * 10 + groupSpacing; + int height = 18 * 4 + groupSpacing; + GuiElement container = new GuiElement<>(parent) + .setZStacking(false) + .constrain(WIDTH, Constraint.literal(width)) + .constrain(HEIGHT, Constraint.literal(height)); + + GuiSlots armor = new GuiSlots(container, screenAccess, armorSlots, 1) + .setYSlotSpacing(groupSpacing / 3) + .setEmptyIcon(index -> slotIcons ? ARMOR_SLOTS[index] : null) + .constrain(TOP, Constraint.midPoint(container.get(TOP), container.get(BOTTOM), height / -2D)) + .constrain(LEFT, Constraint.midPoint(container.get(LEFT), container.get(RIGHT), width / -2D)); + + GuiSlots main = new GuiSlots(container, screenAccess, mainSlots, 9) + .constrain(TOP, match(armor.get(TOP))) + .constrain(LEFT, relative(armor.get(RIGHT), groupSpacing)); + + GuiSlots bar = new GuiSlots(container, screenAccess, hotBarSlots, 9) + .constrain(TOP, relative(main.get(BOTTOM), groupSpacing)) + .constrain(LEFT, match(main.get(LEFT))); + + return new PlayerWithArmor(container, main, bar, armor); + } + + public static PlayerAll playerAllSlots(@NotNull GuiParent parent, ContainerScreenAccess screenAccess, SlotGroup mainSlots, SlotGroup hotBarSlots, SlotGroup armorSlots, SlotGroup offhandSlots) { + return playerAllSlots(parent, screenAccess, mainSlots, hotBarSlots, armorSlots, offhandSlots, 3, true); + } + + public static PlayerAll playerAllSlots(@NotNull GuiParent parent, ContainerScreenAccess screenAccess, SlotGroup mainSlots, SlotGroup hotBarSlots, SlotGroup armorSlots, SlotGroup offhandSlots, int groupSpacing, boolean slotIcons) { + int width = 18 * 11 + groupSpacing * 2; + int height = 18 * 4 + groupSpacing; + GuiElement container = new GuiElement<>(parent) + .setZStacking(false) + .constrain(WIDTH, Constraint.literal(width)) + .constrain(HEIGHT, Constraint.literal(height)); + + GuiSlots armor = new GuiSlots(container, screenAccess, armorSlots, 1) + .setYSlotSpacing(groupSpacing / 3) + .setEmptyIcon(index -> slotIcons ? ARMOR_SLOTS[index] : null) + .constrain(TOP, Constraint.midPoint(container.get(TOP), container.get(BOTTOM), height / -2D)) + .constrain(LEFT, Constraint.midPoint(container.get(LEFT), container.get(RIGHT), width / -2D)); + + GuiSlots main = new GuiSlots(container, screenAccess, mainSlots, 9) + .constrain(TOP, match(armor.get(TOP))) + .constrain(LEFT, relative(armor.get(RIGHT), groupSpacing)); + + GuiSlots bar = new GuiSlots(container, screenAccess, hotBarSlots, 9) + .constrain(TOP, relative(main.get(BOTTOM), groupSpacing)) + .constrain(LEFT, match(main.get(LEFT))); + + GuiSlots offHand = new GuiSlots(container, screenAccess, offhandSlots, 1) + .setEmptyIcon(index -> slotIcons ? OFF_HAND_SLOT : null) + .constrain(TOP, match(bar.get(TOP))) + .constrain(LEFT, relative(bar.get(RIGHT), groupSpacing)); + + return new PlayerAll(container, main, bar, armor, offHand); + } + //=== Slots Setup ===// /** @@ -172,7 +266,7 @@ public void tick(double mouseX, double mouseY) { } @Override - public void renderBehind(GuiRender render, double mouseX, double mouseY, float partialTicks) { + public void renderBackground(GuiRender render, double mouseX, double mouseY, float partialTicks) { GuiElement root = getModularGui().getRoot(); updateSlots(root); @@ -210,98 +304,9 @@ public void renderBehind(GuiRender render, double mouseX, double mouseY, float p render.pose().popPose(); } - //=== Construction Helpers ===// - - public static GuiSlots singleSlot(@NotNull GuiParent parent, ContainerScreenAccess screenAccess, SlotGroup slots) { - return singleSlot(parent, screenAccess, slots, 0); - } - - public static GuiSlots singleSlot(@NotNull GuiParent parent, ContainerScreenAccess screenAccess, SlotGroup slots, int index) { - return new GuiSlots(parent, screenAccess, slots, index, 1, 1); - } - - public static Assembly, GuiSlots> player(@NotNull GuiParent parent, ContainerScreenAccess screenAccess, SlotGroup mainSlots, SlotGroup hotBarSlots) { - return player(parent, screenAccess, mainSlots, hotBarSlots, 3); - } - - public static Assembly, GuiSlots> player(@NotNull GuiParent parent, ContainerScreenAccess screenAccess, SlotGroup mainSlots, SlotGroup hotBarSlots, int hotBarSpacing) { - int width = 18 * 9; - int height = 18 * 4 + hotBarSpacing; - GuiElement container = new GuiElement<>(parent) - .setZStacking(false) - .constrain(WIDTH, Constraint.literal(width)) - .constrain(HEIGHT, Constraint.literal(height)); - - GuiSlots main = new GuiSlots(container, screenAccess, mainSlots, 9) - .constrain(TOP, Constraint.midPoint(container.get(TOP), container.get(BOTTOM), height / -2D)) - .constrain(LEFT, Constraint.midPoint(container.get(LEFT), container.get(RIGHT), width / -2D)); - - GuiSlots bar = new GuiSlots(container, screenAccess, hotBarSlots, 9) - .constrain(TOP, relative(main.get(BOTTOM), hotBarSpacing)) - .constrain(LEFT, match(main.get(LEFT))); - return new Assembly<>(container, main).addParts(bar); - } - - public static Assembly, GuiSlots> playerWithArmor(@NotNull GuiParent parent, ContainerScreenAccess screenAccess, SlotGroup mainSlots, SlotGroup hotBarSlots, SlotGroup armorSlots) { - return playerWithArmor(parent, screenAccess, mainSlots, hotBarSlots, armorSlots, 3, true); - } - - public static Assembly, GuiSlots> playerWithArmor(@NotNull GuiParent parent, ContainerScreenAccess screenAccess, SlotGroup mainSlots, SlotGroup hotBarSlots, SlotGroup armorSlots, int groupSpacing, boolean slotIcons) { - int width = 18 * 10 + groupSpacing; - int height = 18 * 4 + groupSpacing; - GuiElement container = new GuiElement<>(parent) - .setZStacking(false) - .constrain(WIDTH, Constraint.literal(width)) - .constrain(HEIGHT, Constraint.literal(height)); - - GuiSlots armor = new GuiSlots(container, screenAccess, armorSlots, 1) - .setYSlotSpacing(groupSpacing / 3) - .setEmptyIcon(index -> slotIcons ? ARMOR_SLOTS[index] : null) - .constrain(TOP, Constraint.midPoint(container.get(TOP), container.get(BOTTOM), height / -2D)) - .constrain(LEFT, Constraint.midPoint(container.get(LEFT), container.get(RIGHT), width / -2D)); - - GuiSlots main = new GuiSlots(container, screenAccess, mainSlots, 9) - .constrain(TOP, match(armor.get(TOP))) - .constrain(LEFT, relative(armor.get(RIGHT), groupSpacing)); - - GuiSlots bar = new GuiSlots(container, screenAccess, hotBarSlots, 9) - .constrain(TOP, relative(main.get(BOTTOM), groupSpacing)) - .constrain(LEFT, match(main.get(LEFT))); - - return new Assembly<>(container, main).addParts(bar, armor); - } - - public static Assembly, GuiSlots> playerAllSlots(@NotNull GuiParent parent, ContainerScreenAccess screenAccess, SlotGroup mainSlots, SlotGroup hotBarSlots, SlotGroup armorSlots, SlotGroup offhandSlots) { - return playerAllSlots(parent, screenAccess, mainSlots, hotBarSlots, armorSlots, offhandSlots, 3, true); - } - - public static Assembly, GuiSlots> playerAllSlots(@NotNull GuiParent parent, ContainerScreenAccess screenAccess, SlotGroup mainSlots, SlotGroup hotBarSlots, SlotGroup armorSlots, SlotGroup offhandSlots, int groupSpacing, boolean slotIcons) { - int width = 18 * 11 + groupSpacing * 2; - int height = 18 * 4 + groupSpacing; - GuiElement container = new GuiElement<>(parent) - .setZStacking(false) - .constrain(WIDTH, Constraint.literal(width)) - .constrain(HEIGHT, Constraint.literal(height)); - - GuiSlots armor = new GuiSlots(container, screenAccess, armorSlots, 1) - .setYSlotSpacing(groupSpacing / 3) - .setEmptyIcon(index -> slotIcons ? ARMOR_SLOTS[index] : null) - .constrain(TOP, Constraint.midPoint(container.get(TOP), container.get(BOTTOM), height / -2D)) - .constrain(LEFT, Constraint.midPoint(container.get(LEFT), container.get(RIGHT), width / -2D)); + public record Player(GuiElement container, GuiSlots main, GuiSlots hotBar) {} - GuiSlots main = new GuiSlots(container, screenAccess, mainSlots, 9) - .constrain(TOP, match(armor.get(TOP))) - .constrain(LEFT, relative(armor.get(RIGHT), groupSpacing)); + public record PlayerWithArmor(GuiElement container, GuiSlots main, GuiSlots hotBar, GuiSlots armor) {} - GuiSlots bar = new GuiSlots(container, screenAccess, hotBarSlots, 9) - .constrain(TOP, relative(main.get(BOTTOM), groupSpacing)) - .constrain(LEFT, match(main.get(LEFT))); - - GuiSlots offHand = new GuiSlots(container, screenAccess, offhandSlots, 1) - .setEmptyIcon(index -> slotIcons ? OFF_HAND_SLOT : null) - .constrain(TOP, match(bar.get(TOP))) - .constrain(LEFT, relative(bar.get(RIGHT), groupSpacing)); - - return new Assembly<>(container, main).addParts(bar, armor, offHand); - } + public record PlayerAll(GuiElement container, GuiSlots main, GuiSlots hotBar, GuiSlots armor, GuiSlots offHand) {} } diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiText.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiText.java index 23a6f270..2776c2d5 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiText.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiText.java @@ -208,7 +208,7 @@ public double getForegroundDepth() { } @Override - public void renderInFront(GuiRender render, double mouseX, double mouseY, float partialTicks) { + public void renderForeground(GuiRender render, double mouseX, double mouseY, float partialTicks) { Component component = getText(); if (component == null) return; Font font = render.font(); @@ -265,30 +265,4 @@ else if (tooLong && scroll) { stack.popPose(); } } -} - - - - - - - - - - - - - - - - - - - - - - - - - - +} \ No newline at end of file diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiTextField.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiTextField.java index dea19d7e..680b918c 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiTextField.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiTextField.java @@ -1,6 +1,5 @@ package codechicken.lib.gui.modular.elements; -import codechicken.lib.gui.modular.lib.Assembly; import codechicken.lib.gui.modular.lib.BackgroundRender; import codechicken.lib.gui.modular.lib.GuiRender; import codechicken.lib.gui.modular.lib.TextState; @@ -71,6 +70,24 @@ public GuiTextField(@NotNull GuiParent parent) { super(parent); } + /** + * Creates a simple text box with a simple bordered background. + * Using colours 0xFF000000, 0xFFFFFFFF, 0xE0E0E0 will get you a text box identical to the one in a command block + */ + public static TextField create(GuiElement parent, int backgroundColour, int borderColour, int textColour) { + GuiRectangle background = new GuiRectangle(parent) + .rectangle(backgroundColour, borderColour); + + GuiTextField textField = new GuiTextField(background) + .setTextColor(textColour) + .constrain(TOP, Constraint.relative(background.get(TOP), 1)) + .constrain(BOTTOM, Constraint.relative(background.get(BOTTOM), -1)) + .constrain(LEFT, Constraint.relative(background.get(LEFT), 4)) + .constrain(RIGHT, Constraint.relative(background.get(RIGHT), -4)); + + return new TextField(background, textField); + } + //=== Text field setup ===// /** @@ -576,7 +593,7 @@ public double getBackgroundDepth() { } @Override - public void renderBehind(GuiRender render, double mouseX, double mouseY, float partialTicks) { + public void renderBackground(GuiRender render, double mouseX, double mouseY, float partialTicks) { String value = getValue(); int colour = textColor.get(); @@ -638,22 +655,6 @@ public void tick(double mouseX, double mouseY) { tick++; } - /** - * Creates a simple text box with a simple bordered background. - * Using colours 0xFF000000, 0xFFFFFFFF, 0xE0E0E0 will get you a text box identical to the one in a command block - */ - public static Assembly create(GuiElement parent, int backgroundColour, int borderColour, int textColour) { - GuiRectangle background = new GuiRectangle(parent) - .rectangle(backgroundColour, borderColour); - - GuiTextField textField = new GuiTextField(background) - .setTextColor(textColour) - .constrain(TOP, Constraint.relative(background.get(TOP), 1)) - .constrain(BOTTOM, Constraint.relative(background.get(BOTTOM), -1)) - .constrain(LEFT, Constraint.relative(background.get(LEFT), 4)) - .constrain(RIGHT, Constraint.relative(background.get(RIGHT), -4)); - - return new Assembly<>(background, textField); - } + public record TextField(GuiRectangle container, GuiTextField field) {} } diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiTextList.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiTextList.java index 88efcb4f..865b935c 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiTextList.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiTextList.java @@ -147,7 +147,7 @@ public double getForegroundDepth() { } @Override - public void renderInFront(GuiRender render, double mouseX, double mouseY, float partialTicks) { + public void renderForeground(GuiRender render, double mouseX, double mouseY, float partialTicks) { List list = getText(); if (list.isEmpty()) return; Font font = render.font(); @@ -170,30 +170,4 @@ public void renderInFront(GuiRender render, double mouseX, double mouseY, float yPos += font.lineHeight + lineSpacing; } } -} - - - - - - - - - - - - - - - - - - - - - - - - - - +} \ No newline at end of file diff --git a/src/main/java/codechicken/lib/gui/modular/elements/GuiTexture.java b/src/main/java/codechicken/lib/gui/modular/elements/GuiTexture.java index a31967f7..da5c0577 100644 --- a/src/main/java/codechicken/lib/gui/modular/elements/GuiTexture.java +++ b/src/main/java/codechicken/lib/gui/modular/elements/GuiTexture.java @@ -98,7 +98,7 @@ public GuiTexture setColour(Supplier colour) { } @Override - public void renderBehind(GuiRender render, double mouseX, double mouseY, float partialTicks) { + public void renderBackground(GuiRender render, double mouseX, double mouseY, float partialTicks) { Material material = getMaterial(); if (material == null) return; if (dynamicBorders != null) { diff --git a/src/main/java/codechicken/lib/gui/modular/lib/Assembly.java b/src/main/java/codechicken/lib/gui/modular/lib/Assembly.java deleted file mode 100644 index 634ef366..00000000 --- a/src/main/java/codechicken/lib/gui/modular/lib/Assembly.java +++ /dev/null @@ -1,52 +0,0 @@ -package codechicken.lib.gui.modular.lib; - -import codechicken.lib.gui.modular.elements.GuiElement; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * This represents multiple gui elements that have been assembled into a functional component. - * This is primarily for used by the built-in element builders. But could be used in custom builders. - *

- * This is needed because a builder method for an element, cant always return just the relevant element. - * Take the scroll bar for example. - * The builtin scroll bar construction consists of a background element, - * with the scroll bar itself being a child of the background element - * constrained to the background element. - *

- * So the create method for a scroll bar needs to return the background element - * so that you can constrain int appropriately, but it also needs to return the slider element - * so that you can actually use it. That's what this container class is for. - *

- * Created by brandon3055 on 03/09/2023 - */ -public class Assembly, E extends GuiElement> { - /** - * This is the root/container element, Apply any relevant constraints to this element. - */ - public final C container; - /** - * This is the actual primary / functional element. - */ - public final E primary; - /** - * Contains any other elements that are part of this assembly - */ - public final List> parts = new ArrayList<>(); - - public Assembly(C container, E primary) { - this.container = container; - this.primary = primary; - } - - public Assembly addParts(GuiElement... parts) { - this.parts.addAll(Arrays.asList(parts)); - return this; - } - - public GuiElement getPart(int index) { - return parts.get(index); - } -} diff --git a/src/main/java/codechicken/lib/gui/modular/lib/BackgroundRender.java b/src/main/java/codechicken/lib/gui/modular/lib/BackgroundRender.java index 5516a947..0291e8af 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/BackgroundRender.java +++ b/src/main/java/codechicken/lib/gui/modular/lib/BackgroundRender.java @@ -12,7 +12,7 @@ public interface BackgroundRender { /** * Specifies the z depth of the background content. - * After {@link #renderBehind(GuiRender, double, double, float)} is called, the PoseStack will be translated by this amount in the z direction + * After {@link #renderBackground(GuiRender, double, double, float)} is called, the PoseStack will be translated by this amount in the z direction * before any assigned child elements are rendered. * Recommended minimum depth is 0.01 or 0.035 if this element renders text. (text shadows are rendered with a 0.03 offset) * @@ -29,6 +29,6 @@ default double getBackgroundDepth() { * * @param render Contains gui context information as well as essential render methods/utils including the PoseStack. */ - void renderBehind(GuiRender render, double mouseX, double mouseY, float partialTicks); + void renderBackground(GuiRender render, double mouseX, double mouseY, float partialTicks); } diff --git a/src/main/java/codechicken/lib/gui/modular/lib/ColourState.java b/src/main/java/codechicken/lib/gui/modular/lib/ColourState.java index bbd1d8f1..850e0f14 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/ColourState.java +++ b/src/main/java/codechicken/lib/gui/modular/lib/ColourState.java @@ -1,5 +1,8 @@ package codechicken.lib.gui.modular.lib; +import codechicken.lib.colour.Colour; +import codechicken.lib.colour.ColourARGB; + import java.util.Locale; import java.util.function.Consumer; import java.util.function.Supplier; @@ -11,86 +14,14 @@ public interface ColourState { int get(); - void set(int colour); - - default void set(int a, int r, int g, int b) { - set(a << 24 | r << 16 | g << 8 | b); - } - - default void set(int r, int g, int b) { - set(r << 16 | g << 8 | b); - } - - default void set(float a, float r, float g, float b) { - set((int) (a * 255), (int) (r * 255), (int) (g * 255), (int) (b * 255)); - } - - default void set(float r, float g, float b) { - set((int) (r * 255), (int) (g * 255), (int) (b * 255)); - } - - default void setAlpha(int a) { - set(get() & 0x00FFFFFF | a << 24); - } - - default void setRed(int r) { - set(get() & 0xFF00FFFF | r << 16); - } - - default void setGreen(int g) { - set(get() & 0xFFFF00FF | g << 8); + default ColourARGB getColour() { + return new ColourARGB(get()); } - default void setBlue(int b) { - set(get() & 0xFFFFFF00 | b); - } - - default void setAlpha(float a) { - setAlpha((int) (a * 255)); - } - - default void setRed(float r) { - setRed((int) (r * 255)); - } - - default void setGreen(float g) { - setGreen((int) (g * 255)); - } - - default void setBlue(float b) { - setBlue((int) (b * 255)); - } - - default int alphaI() { - return get() >> 24 & 0xFF; - } - - default int redI() { - return get() >> 16 & 0xFF; - } - - default int greenI() { - return get() >> 8 & 0xFF; - } - - default int blueI() { - return get() & 0xFF; - } - - default float alpha() { - return alphaI() / 255F; - } - - default float red() { - return redI() / 255F; - } - - default float green() { - return greenI() / 255F; - } + void set(int colour); - default float blue() { - return blueI() / 255F; + default void set(Colour colour) { + set(colour.argb()); } default String getHexColour() { diff --git a/src/main/java/codechicken/lib/gui/modular/lib/CursorHelper.java b/src/main/java/codechicken/lib/gui/modular/lib/CursorHelper.java index 2836f0c2..4ef4cd96 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/CursorHelper.java +++ b/src/main/java/codechicken/lib/gui/modular/lib/CursorHelper.java @@ -3,10 +3,14 @@ import codechicken.lib.CodeChickenLib; import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.Resource; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; import org.lwjgl.BufferUtils; import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWImage; +import org.lwjgl.system.MemoryUtil; import javax.imageio.ImageIO; import java.awt.*; @@ -14,22 +18,32 @@ import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; +import java.util.Optional; /** * Created by brandon3055 on 11/5/20. */ public class CursorHelper { + public static final Logger LOGGER = LogManager.getLogger(); - private static Map cursors = new HashMap<>(); + public static final ResourceLocation DRAG = new ResourceLocation(CodeChickenLib.MOD_ID, "textures/gui/cursors/drag.png"); + public static final ResourceLocation RESIZE_H = new ResourceLocation(CodeChickenLib.MOD_ID, "textures/gui/cursors/resize_h.png"); + public static final ResourceLocation RESIZE_V = new ResourceLocation(CodeChickenLib.MOD_ID, "textures/gui/cursors/resize_v.png"); + public static final ResourceLocation RESIZE_TRBL = new ResourceLocation(CodeChickenLib.MOD_ID, "textures/gui/cursors/resize_diag_trbl.png"); + public static final ResourceLocation RESIZE_TLBR = new ResourceLocation(CodeChickenLib.MOD_ID, "textures/gui/cursors/resize_diag_tlbr.png"); + + private static final Map cursors = new HashMap<>(); private static ResourceLocation active = null; - private static long createCursor(ResourceLocation resource) { + private static long createCursor(ResourceLocation cursorTexture) { try { - BufferedImage bufferedimage = ImageIO.read(Minecraft.getInstance().getResourceManager().getResource(resource).get().open()); + Resource resource = Minecraft.getInstance().getResourceManager().getResource(cursorTexture).orElse(null); + if (resource == null) return MemoryUtil.NULL; + BufferedImage bufferedimage = ImageIO.read(resource.open()); GLFWImage glfwImage = imageToGLFWImage(bufferedimage); return GLFW.glfwCreateCursor(glfwImage, 16, 16); } catch (Exception e) { - e.printStackTrace(); + LOGGER.warn("An error occurred while creating cursor", e); } return 0; } @@ -65,12 +79,7 @@ public static void setCursor(@Nullable ResourceLocation cursor) { active = cursor; long window = Minecraft.getInstance().getWindow().getWindow(); long newCursor = active == null ? 0 : cursors.computeIfAbsent(cursor, CursorHelper::createCursor); - try { - GLFW.glfwSetCursor(window, newCursor); - } - catch (Throwable e) { - e.printStackTrace(); - } + GLFW.glfwSetCursor(window, newCursor); } } @@ -79,4 +88,13 @@ public static void resetCursor() { setCursor(null); } } + + public static void onResourceReload() { + cursors.values().forEach(cursor -> { + if (cursor != MemoryUtil.NULL) { + GLFW.glfwDestroyCursor(cursor); + } + }); + cursors.clear(); + } } \ No newline at end of file diff --git a/src/main/java/codechicken/lib/gui/modular/lib/ForegroundRender.java b/src/main/java/codechicken/lib/gui/modular/lib/ForegroundRender.java index 58aa24d0..76dfcfb3 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/ForegroundRender.java +++ b/src/main/java/codechicken/lib/gui/modular/lib/ForegroundRender.java @@ -28,5 +28,5 @@ default double getForegroundDepth() { * * @param render Contains gui context information as well as essential render methods/utils including the PoseStack. */ - void renderInFront(GuiRender render, double mouseX, double mouseY, float partialTicks); + void renderForeground(GuiRender render, double mouseX, double mouseY, float partialTicks); } diff --git a/src/main/java/codechicken/lib/gui/modular/lib/GuiRender.java b/src/main/java/codechicken/lib/gui/modular/lib/GuiRender.java index 83e61678..a91b7bd8 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/GuiRender.java +++ b/src/main/java/codechicken/lib/gui/modular/lib/GuiRender.java @@ -35,7 +35,6 @@ import net.minecraft.network.chat.HoverEvent; import net.minecraft.network.chat.Style; import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.FastColor.ARGB32; import net.minecraft.util.FormattedCharSequence; import net.minecraft.util.Mth; import net.minecraft.world.entity.LivingEntity; @@ -236,14 +235,14 @@ public void gradientFillV(double xMin, double yMin, double xMax, double yMax, in */ public void gradientFillV(RenderType type, double xMin, double yMin, double xMax, double yMax, int topColour, int bottomColour) { VertexConsumer buffer = buffers().getBuffer(type); - float sA = (float) ARGB32.alpha(topColour) / 255.0F; - float sR = (float) ARGB32.red(topColour) / 255.0F; - float sG = (float) ARGB32.green(topColour) / 255.0F; - float sB = (float) ARGB32.blue(topColour) / 255.0F; - float eA = (float) ARGB32.alpha(bottomColour) / 255.0F; - float eR = (float) ARGB32.red(bottomColour) / 255.0F; - float eG = (float) ARGB32.green(bottomColour) / 255.0F; - float eB = (float) ARGB32.blue(bottomColour) / 255.0F; + float sA = a(topColour) / 255.0F; + float sR = r(topColour) / 255.0F; + float sG = g(topColour) / 255.0F; + float sB = b(topColour) / 255.0F; + float eA = a(bottomColour) / 255.0F; + float eR = r(bottomColour) / 255.0F; + float eG = g(bottomColour) / 255.0F; + float eB = b(bottomColour) / 255.0F; Matrix4f mat = pose.last().pose(); buffer.vertex(mat, (float) xMax, (float) yMax, 0).color(eR, eG, eB, eA).endVertex(); //R-B buffer.vertex(mat, (float) xMax, (float) yMin, 0).color(sR, sG, sB, sA).endVertex(); //R-T @@ -264,14 +263,14 @@ public void gradientFillH(double xMin, double yMin, double xMax, double yMax, in */ public void gradientFillH(RenderType type, double xMin, double yMin, double xMax, double yMax, int leftColour, int rightColour) { VertexConsumer buffer = buffers().getBuffer(type); - float sA = (float) ARGB32.alpha(leftColour) / 255.0F; - float sR = (float) ARGB32.red(leftColour) / 255.0F; - float sG = (float) ARGB32.green(leftColour) / 255.0F; - float sB = (float) ARGB32.blue(leftColour) / 255.0F; - float eA = (float) ARGB32.alpha(rightColour) / 255.0F; - float eR = (float) ARGB32.red(rightColour) / 255.0F; - float eG = (float) ARGB32.green(rightColour) / 255.0F; - float eB = (float) ARGB32.blue(rightColour) / 255.0F; + float sA = a(leftColour) / 255.0F; + float sR = r(leftColour) / 255.0F; + float sG = g(leftColour) / 255.0F; + float sB = b(leftColour) / 255.0F; + float eA = a(rightColour) / 255.0F; + float eR = r(rightColour) / 255.0F; + float eG = g(rightColour) / 255.0F; + float eB = b(rightColour) / 255.0F; Matrix4f mat = pose.last().pose(); buffer.vertex(mat, (float) xMax, (float) yMax, 0).color(eR, eG, eB, eA).endVertex(); //R-B buffer.vertex(mat, (float) xMax, (float) yMin, 0).color(eR, eG, eB, eA).endVertex(); //R-T @@ -1076,8 +1075,6 @@ public void dynamicTex(Material material, int x, int y, int width, int height, i } //Todo, This method can probably be made a lot more efficient. - // Also thinking a about a data generator to automatically stitch together these textures so there is no need to generate them dynamically. - // That would be a lot more efficient and more compatible with custom resource packs. private void dynamicTexInternal(Material material, int xPos, int yPos, int xSize, int ySize, int topBorder, int leftBorder, int bottomBorder, int rightBorder, float red, float green, float blue, float alpha) { TextureAtlasSprite sprite = material.sprite(); VertexConsumer buffer = material.buffer(buffers, GuiRender::texColType); @@ -1662,22 +1659,19 @@ public static int midColour(int colour1, int colour2) { } private static float r(int argb) { - return ARGB32.red(argb) / 255F; + return (argb >> 16 & 255) / 255F; } private static float g(int argb) { - return ARGB32.green(argb) / 255F; - + return (argb >> 8 & 255) / 255F; } private static float b(int argb) { - return ARGB32.blue(argb) / 255F; - + return (argb & 255) / 255F; } private static float a(int argb) { - return ARGB32.alpha(argb) / 255F; - + return (argb >>> 24) / 255F; } //Render Type Builders diff --git a/src/main/java/codechicken/lib/gui/modular/lib/SliderState.java b/src/main/java/codechicken/lib/gui/modular/lib/SliderState.java index c59c46ea..a9724798 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/SliderState.java +++ b/src/main/java/codechicken/lib/gui/modular/lib/SliderState.java @@ -2,6 +2,7 @@ import codechicken.lib.gui.modular.lib.geometry.Axis; import net.minecraft.client.gui.screens.Screen; +import org.jetbrains.annotations.Nullable; import java.util.function.Consumer; import java.util.function.Supplier; @@ -60,24 +61,7 @@ default boolean canScroll(Axis scrollAxis) { * Useful for things like simple slide control elements. */ static SliderState create(double speed) { - return new SliderState() { - double pos = 0; - - @Override - public double getPos() { - return pos; - } - - @Override - public void setPos(double pos) { - this.pos = pos; - } - - @Override - public double scrollSpeed() { - return speed; - } - }; + return create(speed, null); } /** @@ -85,7 +69,7 @@ public double scrollSpeed() { * And allows you to attach a change listener. * Useful for things like simple slide control elements. */ - static SliderState create(double speed, Consumer changeListener) { + static SliderState create(double speed, @Nullable Consumer changeListener) { return new SliderState() { double pos = 0; @@ -97,7 +81,9 @@ public double getPos() { @Override public void setPos(double pos) { this.pos = pos; - changeListener.accept(pos); + if (changeListener != null) { + changeListener.accept(pos); + } } @Override diff --git a/src/main/java/codechicken/lib/gui/modular/lib/TextState.java b/src/main/java/codechicken/lib/gui/modular/lib/TextState.java index ef9b9be5..f92af296 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/TextState.java +++ b/src/main/java/codechicken/lib/gui/modular/lib/TextState.java @@ -1,6 +1,7 @@ package codechicken.lib.gui.modular.lib; import codechicken.lib.gui.modular.elements.GuiTextField; +import org.jetbrains.annotations.Nullable; import java.util.function.Consumer; import java.util.function.Supplier; @@ -17,22 +18,10 @@ public interface TextState { void setText(String text); static TextState simpleState(String defaultValue) { - return new TextState() { - private String value = defaultValue; - - @Override - public String getText() { - return value; - } - - @Override - public void setText(String text) { - this.value = text; - } - }; + return simpleState(defaultValue, null); } - static TextState simpleState(String defaultValue, Consumer changeListener) { + static TextState simpleState(String defaultValue, @Nullable Consumer changeListener) { return new TextState() { private String value = defaultValue; @@ -44,7 +33,9 @@ public String getText() { @Override public void setText(String text) { this.value = text; - changeListener.accept(value); + if (changeListener != null) { + changeListener.accept(value); + } } }; } diff --git a/src/main/java/codechicken/lib/gui/modular/lib/ToolTipHandler.java b/src/main/java/codechicken/lib/gui/modular/lib/TooltipHandler.java similarity index 96% rename from src/main/java/codechicken/lib/gui/modular/lib/ToolTipHandler.java rename to src/main/java/codechicken/lib/gui/modular/lib/TooltipHandler.java index b0107b21..7bc1bb20 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/ToolTipHandler.java +++ b/src/main/java/codechicken/lib/gui/modular/lib/TooltipHandler.java @@ -1,6 +1,7 @@ package codechicken.lib.gui.modular.lib; import codechicken.lib.gui.modular.elements.GuiElement; +import net.covers1624.quack.util.SneakyUtils; import net.minecraft.network.chat.Component; import org.jetbrains.annotations.Nullable; @@ -11,7 +12,7 @@ /** * Created by brandon3055 on 01/09/2023 */ -public interface ToolTipHandler> { +public interface TooltipHandler> { Supplier> getTooltip(); @@ -86,7 +87,7 @@ default T setTooltip(@Nullable List tooltip) { default T setTooltip(@Nullable Supplier> tooltip, int tooltipDelay) { setTooltip(tooltip); setTooltipDelay(tooltipDelay); - return (T) this; + return SneakyUtils.unsafeCast(this); } /** diff --git a/src/main/java/codechicken/lib/gui/modular/lib/container/DataSync.java b/src/main/java/codechicken/lib/gui/modular/lib/container/DataSync.java index c126b077..7355bdce 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/container/DataSync.java +++ b/src/main/java/codechicken/lib/gui/modular/lib/container/DataSync.java @@ -1,8 +1,8 @@ package codechicken.lib.gui.modular.lib.container; -import codechicken.lib.gui.modular.lib.container.data.AbstractDataStore; +import codechicken.lib.data.MCDataInput; +import codechicken.lib.inventory.container.data.AbstractDataStore; import codechicken.lib.inventory.container.modular.ModularGuiContainerMenu; -import net.minecraft.network.FriendlyByteBuf; import java.util.function.Supplier; @@ -42,7 +42,7 @@ public void detectAndSend() { }); } - public void handleSyncPacket(FriendlyByteBuf buf) { + public void handleSyncPacket(MCDataInput buf) { dataStore.fromBytes(buf); } } diff --git a/src/main/java/codechicken/lib/gui/modular/lib/geometry/Borders.java b/src/main/java/codechicken/lib/gui/modular/lib/geometry/Borders.java index 073b9d5d..d9ef9ce7 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/geometry/Borders.java +++ b/src/main/java/codechicken/lib/gui/modular/lib/geometry/Borders.java @@ -6,10 +6,10 @@ * Created by brandon3055 on 28/08/2023 */ public final class Borders { - private double top; - private double left; - private double bottom; - private double right; + public double top; + public double left; + public double bottom; + public double right; public Borders(double top, double left, double bottom, double right) { this.top = top; @@ -46,32 +46,32 @@ public double right() { return right; } - public Borders setTop(double top) { + public Borders top(double top) { this.top = top; return this; } - public Borders setLeft(double left) { + public Borders left(double left) { this.left = left; return this; } - public Borders setBottom(double bottom) { + public Borders bottom(double bottom) { this.bottom = bottom; return this; } - public Borders setRight(double right) { + public Borders right(double right) { this.right = right; return this; } public Borders setTopBottom(double topBottom) { - return setTop(topBottom).setBottom(topBottom); + return top(topBottom).bottom(topBottom); } public Borders setLeftRight(double leftRight) { - return setLeft(leftRight).setLeftRight(leftRight); + return left(leftRight).setLeftRight(leftRight); } public Borders setBorders(double borders) { diff --git a/src/main/java/codechicken/lib/gui/modular/lib/geometry/ConstrainedGeometry.java b/src/main/java/codechicken/lib/gui/modular/lib/geometry/ConstrainedGeometry.java index d633775f..b0c62353 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/geometry/ConstrainedGeometry.java +++ b/src/main/java/codechicken/lib/gui/modular/lib/geometry/ConstrainedGeometry.java @@ -54,8 +54,9 @@ public abstract class ConstrainedGeometry> impl private AxisConfig yAxis = AxisConfig.NONE; //Permanently bound immutable position and rectangle elements. - private Position position = Position.create(this); - private Rectangle rectangle = Rectangle.create(this); + private final Position position = Position.create(this); + private final Rectangle rectangle = Rectangle.create(this); + private final Rectangle.Mutable childBounds = getRectangle().mutable(); private boolean strictMode = false; @@ -212,30 +213,6 @@ public GeoRef get(GeoParam param) { return new GeoRef(this, param); } - /** - * @param param The geometry parameter. - * @return The current value of the specified parameter. - */ - @Override - public double getValue(GeoParam param) { - switch (param) { - case LEFT: - return xMin(); - case RIGHT: - return xMax(); - case WIDTH: - return xSize(); - case TOP: - return yMin(); - case BOTTOM: - return yMax(); - case HEIGHT: - return ySize(); - default: - throw new IllegalStateException("Param: \"" + param + "\" Shouldn't Exist! Someone has broken my code! Go yell at them!"); - } - } - /** * @param param The geometry parameter to be constrained. * @param constraint The constraint to apply @@ -377,8 +354,6 @@ public Rectangle.Mutable addBoundsToRect(Rectangle.Mutable enclosingRect) { return enclosingRect; } - private Rectangle.Mutable childBounds = getRectangle().mutable(); - /** * @return a rectangle, the bounds of which enclose all enabled child elements. * If there are no enabled child elements the returned rect will have the position of this element, with zero size. diff --git a/src/main/java/codechicken/lib/gui/modular/lib/geometry/Constraint.java b/src/main/java/codechicken/lib/gui/modular/lib/geometry/Constraint.java index 6b30e8c7..63d80344 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/geometry/Constraint.java +++ b/src/main/java/codechicken/lib/gui/modular/lib/geometry/Constraint.java @@ -16,7 +16,7 @@ * * @see ConstrainedGeometry */ -public interface Constraint { +public sealed interface Constraint permits ConstraintImpl { /** * This method will return the current value of this constraint. @@ -151,10 +151,4 @@ static ConstraintImpl.MidPoint midPoint(GeoRef start, GeoRef end, double offset) static ConstraintImpl.MidPointDynamic midPoint(GeoRef start, GeoRef end, Supplier offset) { return new ConstraintImpl.MidPointDynamic(start, end, offset); } - - //TODO - // Between with offset - // Will att more as i start to use this system and figure out whats needed. - // - } diff --git a/src/main/java/codechicken/lib/gui/modular/lib/geometry/ConstraintImpl.java b/src/main/java/codechicken/lib/gui/modular/lib/geometry/ConstraintImpl.java index eab280ea..646abe93 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/geometry/ConstraintImpl.java +++ b/src/main/java/codechicken/lib/gui/modular/lib/geometry/ConstraintImpl.java @@ -8,7 +8,7 @@ /** * Created by brandon3055 on 04/07/2023 */ -public abstract class ConstraintImpl> implements Constraint { +public abstract non-sealed class ConstraintImpl> implements Constraint { protected boolean precise = false; protected Axis axis = null; diff --git a/src/main/java/codechicken/lib/gui/modular/lib/geometry/Direction.java b/src/main/java/codechicken/lib/gui/modular/lib/geometry/Direction.java index d8e5ce9e..9e2513e8 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/geometry/Direction.java +++ b/src/main/java/codechicken/lib/gui/modular/lib/geometry/Direction.java @@ -9,6 +9,8 @@ public enum Direction { DOWN(Axis.Y), RIGHT(Axis.X); + private static Direction[] VALUES = values(); + private final Axis axis; Direction(Axis axis) { @@ -25,11 +27,11 @@ public Direction opposite() { } public Direction rotateCW() { - return values()[(ordinal() + values().length - 1) % values().length]; + return values()[(ordinal() + VALUES.length - 1) % VALUES.length]; } public Direction rotateCCW() { - return values()[(ordinal() + 1) % values().length]; + return values()[(ordinal() + 1) % VALUES.length]; } public double rotationTo(Direction other) { diff --git a/src/main/java/codechicken/lib/gui/modular/lib/geometry/GuiParent.java b/src/main/java/codechicken/lib/gui/modular/lib/geometry/GuiParent.java index e5348e9b..9a2b8d77 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/geometry/GuiParent.java +++ b/src/main/java/codechicken/lib/gui/modular/lib/geometry/GuiParent.java @@ -1,10 +1,10 @@ package codechicken.lib.gui.modular.lib.geometry; -import com.google.common.annotations.Beta; import codechicken.lib.gui.modular.ModularGui; import codechicken.lib.gui.modular.elements.GuiElement; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; +import org.jetbrains.annotations.ApiStatus; import java.util.List; import java.util.function.Consumer; @@ -70,22 +70,14 @@ default GeoRef get(GeoParam param) { * @return The current value of the specified parameter. */ default double getValue(GeoParam param) { - switch (param) { - case LEFT: - return xMin(); - case RIGHT: - return xMax(); - case WIDTH: - return xSize(); - case TOP: - return yMin(); - case BOTTOM: - return yMax(); - case HEIGHT: - return ySize(); - default: - throw new IllegalStateException("Param: \"" + param + "\" Shouldn't Exist! Someone has broken my code! Go yell at them!"); - } + return switch (param) { + case LEFT -> xMin(); + case RIGHT -> xMax(); + case WIDTH -> xSize(); + case TOP -> yMin(); + case BOTTOM -> yMax(); + case HEIGHT -> ySize(); + }; } /** @@ -114,7 +106,7 @@ default double getValue(GeoParam param) { * @param createChild A consumer that is given this element to be used in the construction of the child element. * @return The parent element */ - @Beta + @ApiStatus.Experimental @SuppressWarnings ("unchecked") default T addChild(Consumer createChild) { createChild.accept((T) this); @@ -185,20 +177,6 @@ default void onScreenInit(Minecraft mc, Font font, int screenWidth, int screenHe getChildren().forEach(e -> e.onScreenInit(mc, font, screenWidth, screenHeight)); } - //TODO, May still keep this, but i currently have a different focus system in mind that *may* be better -// /** -// * Not sure how much this will get used, if at all, but allows an element to be specified as the globally focused element. -// * This does not have any effect at all on the base functionality of Modular Gui, it is up to individual elements to choose how they handle focus. -// * -// * @param element the element to be set as the current focused element, or null to clear focused element. -// */ -// void setFocused(@Nullable GuiElement element); -// -// /** -// * @return the current gloabally focused element, or null if no element is focused. -// */ -// @Nullable GuiElement getFocused(); - /** * Allows an element to override the {@link GuiElement#isMouseOver()} method of its children. * This is primarily used for things like scroll elements where mouseover interactions need to be blocked outside the view area. diff --git a/src/main/java/codechicken/lib/gui/modular/lib/geometry/Position.java b/src/main/java/codechicken/lib/gui/modular/lib/geometry/Position.java index 35b55ef6..c6187fbb 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/geometry/Position.java +++ b/src/main/java/codechicken/lib/gui/modular/lib/geometry/Position.java @@ -37,25 +37,7 @@ static Position create(GuiParent parent) { return new Bound(parent); } - record Immutable(double xPos, double yPos) implements Position { - @Override - public double x() { - return xPos; - } - - @Override - public double y() { - return yPos; - } - - @Override - public String toString() { - return "Immutable{" + - "x=" + x() + - ", y=" + y() + - '}'; - } - } + record Immutable(@Override double x, @Override double y) implements Position { } record Bound(GuiParent parent) implements Position { @Override diff --git a/src/main/java/codechicken/lib/gui/modular/sprite/ModAtlasHolder.java b/src/main/java/codechicken/lib/gui/modular/sprite/ModAtlasHolder.java index aebeb8c3..9d361894 100644 --- a/src/main/java/codechicken/lib/gui/modular/sprite/ModAtlasHolder.java +++ b/src/main/java/codechicken/lib/gui/modular/sprite/ModAtlasHolder.java @@ -5,14 +5,18 @@ import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackResources; import net.minecraft.server.packs.resources.PreparableReloadListener; +import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.util.profiling.ProfilerFiller; import org.jetbrains.annotations.NotNull; -import java.util.Objects; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import java.util.function.Predicate; +import java.util.stream.Stream; /** * Created by brandon3055 on 20/08/2023 @@ -50,12 +54,12 @@ public TextureAtlasSprite getSprite(ResourceLocation resourceLocation) { } @Override - public final @NotNull CompletableFuture reload(PreparationBarrier prepParrier, ResourceManager resourceManager, ProfilerFiller profiler, ProfilerFiller profiler2, Executor executor, Executor executor2) { - Objects.requireNonNull(prepParrier); - SpriteLoader spriteLoader = ModSpriteLoader.create(this.textureAtlas, modid); - return spriteLoader.loadAndStitch(resourceManager, this.atlasInfoLocation, 0, executor) + public final @NotNull CompletableFuture reload(PreparationBarrier prepBarrier, ResourceManager resourceManager, ProfilerFiller profiler, ProfilerFiller profiler2, Executor executor, Executor executor2) { + Objects.requireNonNull(prepBarrier); + SpriteLoader spriteLoader = SpriteLoader.create(this.textureAtlas); + return spriteLoader.loadAndStitch(new ModResourceManager(resourceManager, modid), this.atlasInfoLocation, 0, executor) .thenCompose(SpriteLoader.Preparations::waitForUpload) - .thenCompose(prepParrier::wait) + .thenCompose(prepBarrier::wait) .thenAcceptAsync((preparations) -> this.apply(preparations, profiler2), executor2); } @@ -71,4 +75,27 @@ private void apply(SpriteLoader.Preparations preparations, ProfilerFiller profil public void close() { this.textureAtlas.clearTextureData(); } + + public static class ModResourceManager implements ResourceManager { + private final ResourceManager wrapped; + private final String modid; + + public ModResourceManager(ResourceManager wrapped, String modid) { + this.wrapped = wrapped; + this.modid = modid; + } + + @Override + public Map listResources(String pPath, Predicate pFilter) { + return wrapped.listResources(pPath, pFilter.and(e -> e.getNamespace().equals(modid))); + } + + //@formatter:off + @Override public Set getNamespaces() { return wrapped.getNamespaces(); } + @Override public List getResourceStack(ResourceLocation pLocation) { return wrapped.getResourceStack(pLocation); } + @Override public Map> listResourceStacks(String pPath, Predicate pFilter) { return wrapped.listResourceStacks(pPath, pFilter); } + @Override public Stream listPacks() { return wrapped.listPacks(); } + @Override public Optional getResource(ResourceLocation pLocation) { return wrapped.getResource(pLocation); } + //@formatter:on + } } diff --git a/src/main/java/codechicken/lib/gui/modular/sprite/ModSpriteLoader.java b/src/main/java/codechicken/lib/gui/modular/sprite/ModSpriteLoader.java deleted file mode 100644 index fcfe0a2f..00000000 --- a/src/main/java/codechicken/lib/gui/modular/sprite/ModSpriteLoader.java +++ /dev/null @@ -1,38 +0,0 @@ -package codechicken.lib.gui.modular.sprite; - -import net.minecraft.client.renderer.texture.SpriteLoader; -import net.minecraft.client.renderer.texture.TextureAtlas; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.resources.ResourceManager; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; - -/** - * Custom sprite loader that allows filtering of resources based on mod id. - *

- * Created by brandon3055 on 21/08/2023 - */ -public class ModSpriteLoader extends SpriteLoader { - private final String modid; - - public ModSpriteLoader(ResourceLocation resourceLocation, int i, int j, int k, String modid) { - super(resourceLocation, i, j, k); - this.modid = modid; - } - - public static SpriteLoader create(TextureAtlas textureAtlas, String modid) { - return new ModSpriteLoader(textureAtlas.location(), textureAtlas.maxSupportedTextureSize(), textureAtlas.getWidth(), textureAtlas.getHeight(), modid); - } - - @Override - public CompletableFuture loadAndStitch(ResourceManager resourceManager, ResourceLocation resourceLocation, int i, Executor executor) { - return CompletableFuture.supplyAsync(() -> { - return ModSpriteResourceLoader.load(resourceManager, resourceLocation, modid).list(resourceManager); - }, executor).thenCompose((list) -> { - return runSpriteSuppliers(list, executor); - }).thenApply((list) -> { - return this.stitch(list, i, executor); - }); - } -} diff --git a/src/main/java/codechicken/lib/gui/modular/sprite/ModSpriteResourceLoader.java b/src/main/java/codechicken/lib/gui/modular/sprite/ModSpriteResourceLoader.java deleted file mode 100644 index 0bdef65a..00000000 --- a/src/main/java/codechicken/lib/gui/modular/sprite/ModSpriteResourceLoader.java +++ /dev/null @@ -1,110 +0,0 @@ -package codechicken.lib.gui.modular.sprite; - -import com.google.common.collect.ImmutableList; -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; -import com.mojang.logging.LogUtils; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.Dynamic; -import com.mojang.serialization.JsonOps; -import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; -import net.minecraft.client.renderer.texture.SpriteContents; -import net.minecraft.client.renderer.texture.atlas.SpriteSource; -import net.minecraft.client.renderer.texture.atlas.SpriteSources; -import net.minecraft.resources.FileToIdConverter; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.resources.Resource; -import net.minecraft.server.packs.resources.ResourceManager; -import org.slf4j.Logger; - -import java.io.BufferedReader; -import java.util.*; -import java.util.function.Predicate; -import java.util.function.Supplier; - -/** - * Custom sprite resource loader that allows filtering of resources based on mod id. - *

- * Created by brandon3055 on 21/08/2023 - */ -public class ModSpriteResourceLoader { - private static final Logger LOGGER = LogUtils.getLogger(); - private static final FileToIdConverter ATLAS_INFO_CONVERTER = new FileToIdConverter("atlases", ".json"); - private final List sources; - private final String modid; - - private ModSpriteResourceLoader(List list, String modid) { - this.sources = list; - this.modid = modid; - } - - public List> list(ResourceManager arg) { - final Map map = new HashMap(); - SpriteSource.Output output = new SpriteSource.Output() { - public void add(ResourceLocation location, SpriteSource.SpriteSupplier arg2) { - if (location.getNamespace().equals(modid)) { - SpriteSource.SpriteSupplier spriteSupplier = map.put(location, arg2); - if (spriteSupplier != null) { - spriteSupplier.discard(); - } - } - } - - public void removeAll(Predicate predicate) { - Iterator> iterator = map.entrySet().iterator(); - - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - if (predicate.test(entry.getKey())) { - entry.getValue().discard(); - iterator.remove(); - } - } - - } - }; - this.sources.forEach((arg3) -> arg3.run(arg, output)); - - ImmutableList.Builder> builder = ImmutableList.builder(); - builder.add(MissingTextureAtlasSprite::create); - builder.addAll(map.values()); - return builder.build(); - } - - public static ModSpriteResourceLoader load(ResourceManager arg, ResourceLocation arg2, String modid) { - ResourceLocation resourceLocation = ATLAS_INFO_CONVERTER.idToFile(arg2); - List list = new ArrayList<>(); - - for (Resource resource : arg.getResourceStack(resourceLocation)) { - try { - BufferedReader bufferedReader = resource.openAsReader(); - - try { - Dynamic dynamic = new Dynamic<>(JsonOps.INSTANCE, JsonParser.parseReader(bufferedReader)); - DataResult> var10001 = SpriteSources.FILE_CODEC.parse(dynamic); - Logger var10003 = LOGGER; - Objects.requireNonNull(var10003); - list.addAll(var10001.getOrThrow(false, var10003::error)); - } catch (Throwable var10) { - if (bufferedReader != null) { - try { - bufferedReader.close(); - } catch (Throwable var9) { - var10.addSuppressed(var9); - } - } - - throw var10; - } - - if (bufferedReader != null) { - bufferedReader.close(); - } - } catch (Exception var11) { - LOGGER.warn("Failed to parse atlas definition {} in pack {}", resourceLocation, resource.sourcePackId(), var11); - } - } - - return new ModSpriteResourceLoader(list, modid); - } -} diff --git a/src/main/java/codechicken/lib/internal/ClientInit.java b/src/main/java/codechicken/lib/internal/ClientInit.java index a0186ba8..e3414e88 100644 --- a/src/main/java/codechicken/lib/internal/ClientInit.java +++ b/src/main/java/codechicken/lib/internal/ClientInit.java @@ -3,6 +3,8 @@ import codechicken.lib.CodeChickenLib; import codechicken.lib.config.ConfigCategory; import codechicken.lib.config.ConfigSyncManager; +import codechicken.lib.gui.modular.lib.CursorHelper; +import codechicken.lib.gui.modular.sprite.CCGuiTextures; import codechicken.lib.model.CompositeItemModel; import codechicken.lib.model.ClassModelLoader; import codechicken.lib.render.CCRenderEventHandler; @@ -10,6 +12,7 @@ import net.covers1624.quack.util.CrashLock; import net.minecraftforge.client.event.ClientPlayerNetworkEvent; import net.minecraftforge.client.event.ModelEvent; +import net.minecraftforge.client.event.RegisterClientReloadListenersEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; @@ -36,6 +39,7 @@ public static void init() { bus.addListener(ClientInit::onClientSetup); bus.addListener(ClientInit::onRegisterGeometryLoaders); + bus.addListener(ClientInit::onResourceReload); } private static void onClientSetup(FMLClientSetupEvent event) { @@ -74,4 +78,9 @@ private static void onRegisterGeometryLoaders(ModelEvent.RegisterGeometryLoaders event.register("item_composite", new CompositeItemModel()); event.register("class", new ClassModelLoader()); } + + public static void onResourceReload(RegisterClientReloadListenersEvent event) { + event.registerReloadListener(CCGuiTextures.getAtlasHolder()); + CursorHelper.onResourceReload(); + } } diff --git a/src/main/java/codechicken/lib/internal/network/CCLNetwork.java b/src/main/java/codechicken/lib/internal/network/CCLNetwork.java index 99b73ea5..5fbd194b 100644 --- a/src/main/java/codechicken/lib/internal/network/CCLNetwork.java +++ b/src/main/java/codechicken/lib/internal/network/CCLNetwork.java @@ -15,6 +15,10 @@ public class CCLNetwork { //Client handled. public static final int C_ADD_LANDING_EFFECTS = 1; public static final int C_OPEN_CONTAINER = 10; + public static final int C_GUI_SYNC = 11; + + //Server handled. + public static final int S_GUI_SYNC = 1; //Login handled. public static final int L_CONFIG_SYNC = 1; @@ -22,8 +26,8 @@ public class CCLNetwork { public static void init() { netChannel = PacketCustomChannelBuilder.named(NET_CHANNEL)// .assignClientHandler(() -> ClientPacketHandler::new)// + .assignServerHandler(() -> ServerPacketHandler::new)// .assignLoginHandler(() -> LoginPacketHandler::new)// .build(); } - } diff --git a/src/main/java/codechicken/lib/internal/network/ClientPacketHandler.java b/src/main/java/codechicken/lib/internal/network/ClientPacketHandler.java index 8f7dd554..32bccf89 100644 --- a/src/main/java/codechicken/lib/internal/network/ClientPacketHandler.java +++ b/src/main/java/codechicken/lib/internal/network/ClientPacketHandler.java @@ -1,6 +1,7 @@ package codechicken.lib.internal.network; import codechicken.lib.inventory.container.ICCLContainerType; +import codechicken.lib.inventory.container.modular.ModularGuiContainerMenu; import codechicken.lib.packet.ICustomPacketHandler.IClientPacketHandler; import codechicken.lib.packet.PacketCustom; import codechicken.lib.render.particle.CustomParticleHandler; @@ -17,8 +18,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.registries.ForgeRegistries; -import static codechicken.lib.internal.network.CCLNetwork.C_ADD_LANDING_EFFECTS; -import static codechicken.lib.internal.network.CCLNetwork.C_OPEN_CONTAINER; +import static codechicken.lib.internal.network.CCLNetwork.*; /** * Created by covers1624 on 14/07/2017. @@ -36,6 +36,7 @@ public void handlePacket(PacketCustom packet, Minecraft mc, ClientPacketListener CustomParticleHandler.addLandingEffects(mc.level, pos, state, vec, numParticles); } case C_OPEN_CONTAINER -> handleOpenContainer(packet, mc); + case C_GUI_SYNC -> ModularGuiContainerMenu.handlePacketFromServer(mc.player, packet); } } diff --git a/src/main/java/codechicken/lib/internal/network/ServerPacketHandler.java b/src/main/java/codechicken/lib/internal/network/ServerPacketHandler.java new file mode 100644 index 00000000..4edab263 --- /dev/null +++ b/src/main/java/codechicken/lib/internal/network/ServerPacketHandler.java @@ -0,0 +1,22 @@ +package codechicken.lib.internal.network; + +import codechicken.lib.inventory.container.modular.ModularGuiContainerMenu; +import codechicken.lib.packet.ICustomPacketHandler.IServerPacketHandler; +import codechicken.lib.packet.PacketCustom; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerGamePacketListenerImpl; + +import static codechicken.lib.internal.network.CCLNetwork.S_GUI_SYNC; + +/** + * Created by covers1624 on 14/07/2017. + */ +public class ServerPacketHandler implements IServerPacketHandler { + + @Override + public void handlePacket(PacketCustom packet, ServerPlayer sender, ServerGamePacketListenerImpl handler) { + switch (packet.getType()) { + case S_GUI_SYNC -> ModularGuiContainerMenu.handlePacketFromClient(sender, packet); + } + } +} diff --git a/src/main/java/codechicken/lib/gui/modular/lib/container/data/AbstractDataStore.java b/src/main/java/codechicken/lib/inventory/container/data/AbstractDataStore.java similarity index 75% rename from src/main/java/codechicken/lib/gui/modular/lib/container/data/AbstractDataStore.java rename to src/main/java/codechicken/lib/inventory/container/data/AbstractDataStore.java index 3e895821..6120027d 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/container/data/AbstractDataStore.java +++ b/src/main/java/codechicken/lib/inventory/container/data/AbstractDataStore.java @@ -1,5 +1,7 @@ -package codechicken.lib.gui.modular.lib.container.data; +package codechicken.lib.inventory.container.data; +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; import net.minecraft.nbt.Tag; import net.minecraft.network.FriendlyByteBuf; @@ -10,7 +12,6 @@ * * Created by brandon3055 on 08/09/2023 */ -@Deprecated //Not sure if this will stay in CCL public abstract class AbstractDataStore { protected T value; @@ -30,9 +31,9 @@ public void setValue(T value) { public void markDirty(){} - public abstract void toBytes(FriendlyByteBuf buf); + public abstract void toBytes(MCDataOutput buf); - public abstract void fromBytes(FriendlyByteBuf buf); + public abstract void fromBytes(MCDataInput buf); public abstract Tag toTag(); diff --git a/src/main/java/codechicken/lib/gui/modular/lib/container/data/BooleanData.java b/src/main/java/codechicken/lib/inventory/container/data/BooleanData.java similarity index 76% rename from src/main/java/codechicken/lib/gui/modular/lib/container/data/BooleanData.java rename to src/main/java/codechicken/lib/inventory/container/data/BooleanData.java index 072ab113..23bc32c0 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/container/data/BooleanData.java +++ b/src/main/java/codechicken/lib/inventory/container/data/BooleanData.java @@ -1,5 +1,7 @@ -package codechicken.lib.gui.modular.lib.container.data; +package codechicken.lib.inventory.container.data; +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; import net.minecraft.nbt.ByteTag; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.Tag; @@ -8,7 +10,6 @@ /** * Created by brandon3055 on 09/09/2023 */ -@Deprecated //Not sure if this will stay in CCL public class BooleanData extends AbstractDataStore { public BooleanData() { @@ -20,12 +21,12 @@ public BooleanData(boolean defaultValue) { } @Override - public void toBytes(FriendlyByteBuf buf) { + public void toBytes(MCDataOutput buf) { buf.writeBoolean(value); } @Override - public void fromBytes(FriendlyByteBuf buf) { + public void fromBytes(MCDataInput buf) { value = buf.readBoolean(); } diff --git a/src/main/java/codechicken/lib/gui/modular/lib/container/data/ByteData.java b/src/main/java/codechicken/lib/inventory/container/data/ByteData.java similarity index 75% rename from src/main/java/codechicken/lib/gui/modular/lib/container/data/ByteData.java rename to src/main/java/codechicken/lib/inventory/container/data/ByteData.java index b7b93f65..c438282e 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/container/data/ByteData.java +++ b/src/main/java/codechicken/lib/inventory/container/data/ByteData.java @@ -1,5 +1,7 @@ -package codechicken.lib.gui.modular.lib.container.data; +package codechicken.lib.inventory.container.data; +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; import net.minecraft.nbt.ByteTag; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.Tag; @@ -8,7 +10,6 @@ /** * Created by brandon3055 on 09/09/2023 */ -@Deprecated //Not sure if this will stay in CCL public class ByteData extends AbstractDataStore { public ByteData() { @@ -20,12 +21,12 @@ public ByteData(byte defaultValue) { } @Override - public void toBytes(FriendlyByteBuf buf) { + public void toBytes(MCDataOutput buf) { buf.writeByte(value); } @Override - public void fromBytes(FriendlyByteBuf buf) { + public void fromBytes(MCDataInput buf) { value = buf.readByte(); } diff --git a/src/main/java/codechicken/lib/gui/modular/lib/container/data/DoubleData.java b/src/main/java/codechicken/lib/inventory/container/data/DoubleData.java similarity index 75% rename from src/main/java/codechicken/lib/gui/modular/lib/container/data/DoubleData.java rename to src/main/java/codechicken/lib/inventory/container/data/DoubleData.java index befd2f0d..990f9475 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/container/data/DoubleData.java +++ b/src/main/java/codechicken/lib/inventory/container/data/DoubleData.java @@ -1,5 +1,7 @@ -package codechicken.lib.gui.modular.lib.container.data; +package codechicken.lib.inventory.container.data; +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; import net.minecraft.nbt.DoubleTag; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.Tag; @@ -8,7 +10,6 @@ /** * Created by brandon3055 on 09/09/2023 */ -@Deprecated //Not sure if this will stay in CCL public class DoubleData extends AbstractDataStore { public DoubleData() { @@ -20,12 +21,12 @@ public DoubleData(double defaultValue) { } @Override - public void toBytes(FriendlyByteBuf buf) { + public void toBytes(MCDataOutput buf) { buf.writeDouble(value); } @Override - public void fromBytes(FriendlyByteBuf buf) { + public void fromBytes(MCDataInput buf) { value = buf.readDouble(); } diff --git a/src/main/java/codechicken/lib/gui/modular/lib/container/data/FloatData.java b/src/main/java/codechicken/lib/inventory/container/data/FloatData.java similarity index 75% rename from src/main/java/codechicken/lib/gui/modular/lib/container/data/FloatData.java rename to src/main/java/codechicken/lib/inventory/container/data/FloatData.java index d0adf0c1..6a135bca 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/container/data/FloatData.java +++ b/src/main/java/codechicken/lib/inventory/container/data/FloatData.java @@ -1,5 +1,7 @@ -package codechicken.lib.gui.modular.lib.container.data; +package codechicken.lib.inventory.container.data; +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; import net.minecraft.nbt.FloatTag; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.Tag; @@ -8,7 +10,6 @@ /** * Created by brandon3055 on 09/09/2023 */ -@Deprecated //Not sure if this will stay in CCL public class FloatData extends AbstractDataStore { public FloatData() { @@ -20,12 +21,12 @@ public FloatData(float defaultValue) { } @Override - public void toBytes(FriendlyByteBuf buf) { + public void toBytes(MCDataOutput buf) { buf.writeFloat(value); } @Override - public void fromBytes(FriendlyByteBuf buf) { + public void fromBytes(MCDataInput buf) { value = buf.readFloat(); } diff --git a/src/main/java/codechicken/lib/gui/modular/lib/container/data/FluidData.java b/src/main/java/codechicken/lib/inventory/container/data/FluidData.java similarity index 75% rename from src/main/java/codechicken/lib/gui/modular/lib/container/data/FluidData.java rename to src/main/java/codechicken/lib/inventory/container/data/FluidData.java index 4981b29a..62288a63 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/container/data/FluidData.java +++ b/src/main/java/codechicken/lib/inventory/container/data/FluidData.java @@ -1,5 +1,7 @@ -package codechicken.lib.gui.modular.lib.container.data; +package codechicken.lib.inventory.container.data; +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; import net.minecraft.network.FriendlyByteBuf; @@ -8,7 +10,6 @@ /** * Created by brandon3055 on 09/09/2023 */ -@Deprecated //Not sure if this will stay in CCL public class FluidData extends AbstractDataStore { public FluidData() { @@ -26,13 +27,13 @@ public void setValue(FluidStack value) { } @Override - public void toBytes(FriendlyByteBuf buf) { - value.writeToPacket(buf); + public void toBytes(MCDataOutput buf) { + buf.writeFluidStack(value); } @Override - public void fromBytes(FriendlyByteBuf buf) { - value = FluidStack.readFromPacket(buf); + public void fromBytes(MCDataInput buf) { + value = buf.readFluidStack(); } @Override diff --git a/src/main/java/codechicken/lib/gui/modular/lib/container/data/IntData.java b/src/main/java/codechicken/lib/inventory/container/data/IntData.java similarity index 75% rename from src/main/java/codechicken/lib/gui/modular/lib/container/data/IntData.java rename to src/main/java/codechicken/lib/inventory/container/data/IntData.java index 195f6175..fe43551a 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/container/data/IntData.java +++ b/src/main/java/codechicken/lib/inventory/container/data/IntData.java @@ -1,5 +1,7 @@ -package codechicken.lib.gui.modular.lib.container.data; +package codechicken.lib.inventory.container.data; +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; import net.minecraft.nbt.IntTag; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.Tag; @@ -8,7 +10,6 @@ /** * Created by brandon3055 on 09/09/2023 */ -@Deprecated //Not sure if this will stay in CCL public class IntData extends AbstractDataStore { public IntData() { @@ -20,12 +21,12 @@ public IntData(int defaultValue) { } @Override - public void toBytes(FriendlyByteBuf buf) { + public void toBytes(MCDataOutput buf) { buf.writeVarInt(value); } @Override - public void fromBytes(FriendlyByteBuf buf) { + public void fromBytes(MCDataInput buf) { value = buf.readVarInt(); } diff --git a/src/main/java/codechicken/lib/gui/modular/lib/container/data/LongData.java b/src/main/java/codechicken/lib/inventory/container/data/LongData.java similarity index 75% rename from src/main/java/codechicken/lib/gui/modular/lib/container/data/LongData.java rename to src/main/java/codechicken/lib/inventory/container/data/LongData.java index a92a6f80..9b928d9a 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/container/data/LongData.java +++ b/src/main/java/codechicken/lib/inventory/container/data/LongData.java @@ -1,5 +1,7 @@ -package codechicken.lib.gui.modular.lib.container.data; +package codechicken.lib.inventory.container.data; +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; import net.minecraft.nbt.LongTag; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.Tag; @@ -8,7 +10,6 @@ /** * Created by brandon3055 on 09/09/2023 */ -@Deprecated //Not sure if this will stay in CCL public class LongData extends AbstractDataStore { public LongData() { @@ -20,12 +21,12 @@ public LongData(long defaultValue) { } @Override - public void toBytes(FriendlyByteBuf buf) { + public void toBytes(MCDataOutput buf) { buf.writeVarLong(value); } @Override - public void fromBytes(FriendlyByteBuf buf) { + public void fromBytes(MCDataInput buf) { value = buf.readVarLong(); } diff --git a/src/main/java/codechicken/lib/gui/modular/lib/container/data/ShortData.java b/src/main/java/codechicken/lib/inventory/container/data/ShortData.java similarity index 75% rename from src/main/java/codechicken/lib/gui/modular/lib/container/data/ShortData.java rename to src/main/java/codechicken/lib/inventory/container/data/ShortData.java index 4c203c09..9a29d0dd 100644 --- a/src/main/java/codechicken/lib/gui/modular/lib/container/data/ShortData.java +++ b/src/main/java/codechicken/lib/inventory/container/data/ShortData.java @@ -1,5 +1,7 @@ -package codechicken.lib.gui.modular.lib.container.data; +package codechicken.lib.inventory.container.data; +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.ShortTag; import net.minecraft.nbt.Tag; @@ -8,7 +10,6 @@ /** * Created by brandon3055 on 09/09/2023 */ -@Deprecated //Not sure if this will stay in CCL public class ShortData extends AbstractDataStore { public ShortData() { @@ -20,12 +21,12 @@ public ShortData(short defaultValue) { } @Override - public void toBytes(FriendlyByteBuf buf) { + public void toBytes(MCDataOutput buf) { buf.writeShort(value); } @Override - public void fromBytes(FriendlyByteBuf buf) { + public void fromBytes(MCDataInput buf) { value = buf.readShort(); } diff --git a/src/main/java/codechicken/lib/inventory/container/modular/ModularGuiContainerMenu.java b/src/main/java/codechicken/lib/inventory/container/modular/ModularGuiContainerMenu.java index a2eb159c..f6f043cc 100644 --- a/src/main/java/codechicken/lib/inventory/container/modular/ModularGuiContainerMenu.java +++ b/src/main/java/codechicken/lib/inventory/container/modular/ModularGuiContainerMenu.java @@ -1,10 +1,15 @@ package codechicken.lib.inventory.container.modular; +import codechicken.lib.data.MCDataInput; +import codechicken.lib.data.MCDataOutput; import codechicken.lib.gui.modular.elements.GuiSlots; import codechicken.lib.gui.modular.lib.container.ContainerScreenAccess; import codechicken.lib.gui.modular.lib.container.DataSync; import codechicken.lib.gui.modular.lib.container.SlotGroup; import codechicken.lib.gui.modular.lib.geometry.GuiParent; +import codechicken.lib.internal.network.CCLNetwork; +import codechicken.lib.packet.PacketCustom; +import codechicken.lib.vec.Vector3; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.player.Inventory; @@ -25,6 +30,8 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; +import static codechicken.lib.internal.network.CCLNetwork.*; + /** * The base abstract ContainerMenu for all modular gui containers. *

@@ -38,8 +45,6 @@ public abstract class ModularGuiContainerMenu extends AbstractContainerMenu { public final Map slotGroupMap = new HashMap<>(); public final Map> zonedSlots = new HashMap<>(); public final List> dataSyncs = new ArrayList<>(); - private BiConsumer> serverToClientPacketHandler; - private Consumer> clientToServerPacketHandler; protected ModularGuiContainerMenu(@Nullable MenuType menuType, int containerId, Inventory inventory) { super(menuType, containerId); @@ -91,73 +96,37 @@ protected SlotGroup remoteSlotGroup() { } //=== Network ===// - - /** - * Set the server to client packet handler. - * As polylib does not have its own network implementation, the implementor of ModularGuiContainerMenu must provide their own if - * they wish to use the network functionality built into ModularGuiContainerMenu. - *

- * An example imeplementation may look something like: - *

-     * setServerToClientPacketHandler((player, packetWriter) -> {
-     *     FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
-     *     packetWriter.accept(buf);
-     *     MyNetwork.sendModularGuiMenuPacketToPlayer(player, buf);
-     * });
-     * 
- * Then, in your client side packet handler you would call {@link ModularGuiContainerMenu#handlePacketFromServer(Player, FriendlyByteBuf)} - * The player can be the client side player. - * - *

- * A server to client packet handler is required for the {@link DataSync} system to work. - */ - public void setServerToClientPacketHandler(BiConsumer> serverToClientPacketHandler) { - this.serverToClientPacketHandler = serverToClientPacketHandler; - } - - /** - * This should be implemented similar to {@link #setServerToClientPacketHandler(BiConsumer)} - * The difference being this will be sending packets in the other direction. - */ - public void setClientToServerPacketHandler(Consumer> clientToServerPacketHandler) { - this.clientToServerPacketHandler = clientToServerPacketHandler; - } - /** * Send a packet to the client side container. - * Requires a server to client packet handler to be installed via {@link #setServerToClientPacketHandler(BiConsumer)} * * @param packetId message id, Can be any value from 0 to 254, 255 is used by the {@link DataSync} system. * @param packetWriter Use this callback to write your data to the packet. */ - public void sendPacketToClient(int packetId, Consumer packetWriter) { - if (serverToClientPacketHandler != null && inventory.player instanceof ServerPlayer serverPlayer) { - serverToClientPacketHandler.accept(serverPlayer, buf -> { - buf.writeByte(containerId); - buf.writeByte((byte) packetId); - packetWriter.accept(buf); - }); + public void sendPacketToClient(int packetId, Consumer packetWriter) { + if (inventory.player instanceof ServerPlayer serverPlayer) { + PacketCustom packet = new PacketCustom(CCLNetwork.NET_CHANNEL, C_GUI_SYNC); + packet.writeByte(containerId); + packet.writeByte((byte) packetId); + packetWriter.accept(packet); + packet.sendToPlayer(serverPlayer); } } /** * Send a packet to the server side container. - * Requires a client to server packet handler to be installed via {@link #setClientToServerPacketHandler(Consumer)} * * @param packetId message id, Can be any value from 0 to 255 * @param packetWriter Use this callback to write your data to the packet. */ - public void sendPacketToServer(int packetId, Consumer packetWriter) { - if (clientToServerPacketHandler != null) { - clientToServerPacketHandler.accept(buf -> { - buf.writeByte(containerId); - buf.writeByte((byte) packetId); - packetWriter.accept(buf); - }); - } + public void sendPacketToServer(int packetId, Consumer packetWriter) { + PacketCustom packet = new PacketCustom(CCLNetwork.NET_CHANNEL, S_GUI_SYNC); + packet.writeByte(containerId); + packet.writeByte((byte) packetId); + packetWriter.accept(packet); + packet.sendToServer(); } - public static void handlePacketFromClient(Player player, FriendlyByteBuf packet) { + public static void handlePacketFromClient(Player player, MCDataInput packet) { int containerId = packet.readByte(); int packetId = packet.readByte() & 0xFF; if (player.containerMenu instanceof ModularGuiContainerMenu menu && menu.containerId == containerId) { @@ -167,13 +136,12 @@ public static void handlePacketFromClient(Player player, FriendlyByteBuf packet) /** * Override this in your container menu implementation in order to receive packets sent via {@link #sendPacketToServer(int, Consumer)} - * Requires a client to server packet handler to be installed via {@link #setClientToServerPacketHandler(Consumer)} */ - public void handlePacketFromClient(Player player, int packetId, FriendlyByteBuf packet) { + public void handlePacketFromClient(Player player, int packetId, MCDataInput packet) { } - public static void handlePacketFromServer(Player player, FriendlyByteBuf packet) { + public static void handlePacketFromServer(Player player, MCDataInput packet) { int containerId = packet.readByte(); int packetId = packet.readByte() & 0xFF; if (player.containerMenu instanceof ModularGuiContainerMenu menu && menu.containerId == containerId) { @@ -183,11 +151,10 @@ public static void handlePacketFromServer(Player player, FriendlyByteBuf packet) /** * Override this in your container menu implementation in order to receive packets sent via {@link #sendPacketToServer(int, Consumer)} - * Requires a server to client packet handler to be installed via {@link #setServerToClientPacketHandler(BiConsumer)} *

* Don't forget to call super if you plan on using the {@link DataSync} system. */ - public void handlePacketFromServer(Player player, int packetId, FriendlyByteBuf packet) { + public void handlePacketFromServer(Player player, int packetId, MCDataInput packet) { if (packetId == 255) { int index = packet.readByte() & 0xFF; if (dataSyncs.size() > index) { diff --git a/src/main/resources/assets/codechickenlib/atlases/gui.json b/src/main/resources/assets/codechickenlib/atlases/gui.json new file mode 100644 index 00000000..5da82735 --- /dev/null +++ b/src/main/resources/assets/codechickenlib/atlases/gui.json @@ -0,0 +1,9 @@ +{ + "sources": [ + { + "type": "directory", + "source": "gui", + "prefix": "gui/" + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/codechickenlib/textures/gui/cursors/drag.png b/src/main/resources/assets/codechickenlib/textures/gui/cursors/drag.png new file mode 100644 index 0000000000000000000000000000000000000000..1e8c3266ad6e5f5e3f99ec6652b4ab6e1e6ea8c4 GIT binary patch literal 4183 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 h?L?P) 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/codechickenlib/textures/gui/cursors/resize_diag_trbl.png b/src/main/resources/assets/codechickenlib/textures/gui/cursors/resize_diag_trbl.png new file mode 100644 index 0000000000000000000000000000000000000000..b306c6ba4b86116e5c22d20399474c5dbec375c9 GIT binary patch literal 4339 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/codechickenlib/textures/gui/cursors/resize_h.png b/src/main/resources/assets/codechickenlib/textures/gui/cursors/resize_h.png new file mode 100644 index 0000000000000000000000000000000000000000..07baa61c49b5bb6d4b3c49fe61a15c172599c9f6 GIT binary patch literal 3325 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 Hu0mjfOL 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_borderless.png b/src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_borderless.png new file mode 100644 index 0000000000000000000000000000000000000000..f1484440a40e387de4625f5a774eb84fc5c1c9d3 GIT binary patch literal 8152 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_borderless_pressed.png b/src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_borderless_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..7273c079cd5a16f01199ad9a8c3f2d9718a68859 GIT binary patch literal 12424 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 FV1kaFt{ngX literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_highlight_borderless.png b/src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_highlight_borderless.png new file mode 100644 index 0000000000000000000000000000000000000000..677d04c1f27e3470d58ec161bcbe8326fe859784 GIT binary patch literal 14008 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 D-GY*S literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_vanilla.png b/src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_vanilla.png new file mode 100644 index 0000000000000000000000000000000000000000..5e64e34babe124f2136081e47f342b05ae85af16 GIT binary patch literal 8373 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 LNkvXXu0mjfO5AST literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_vanilla_disabled.png b/src/main/resources/assets/codechickenlib/textures/gui/dynamic/button_vanilla_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..aa29d9977b7b451e1f3f1180ce0538d538eaf9df GIT binary patch literal 6849 zcmV;y8b0NTP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O1hxa%4FU``0Pv2wExWI9em-26OxYDCOpKb@xO} zxooFjzNdu%K~QPdfBwDAzwj?6@g}BRq>5Pli#1l?@S@oBuj)@{qyE%?@xFz>KdzhS z8y=SeeuwjCZukC%>*@8tV-D9pubXn;@#PM5-*^ldIJ3u#`MyY8_vgC1D=~GQ7g9@p zUuyT~_joM1yuL%$p`U~BZ}Wa3W<+Tw+!efE!3C>7%UMA<-wodhKV1;q=R(En5URni z80uXK0`jrF$8T%j1N0H($1C$Q`p;KCg74eC9)849ZjA8a*Ed}HJ@^{pw~51ZMgH@R z+THhd?)Toa?7hzJS`sQ5BvCR&EGwrY)U&B@B zfyy>6y6KwRZt3sg29_B8@)^IqA3o@{60)y;1mYC=<+jg2Y=#0XhhGNJ#o(W7aXN3+ z`GzZ)c{<$c9R_oF`H3x88J9Y?b-dLIA)w1w9t)2vOHBe#^;0-|b3_6R!G@K*= zrhsV{25|$z+&NKdc86$PwE;`pZ%gAdAJdyVe`=F*j=~L<+TCH$`ZlP;>gxCEa+c7s zx+TTnL10>S|CNL5$OzDmA4@;0m@-6a04yC|K&bZ|+s|$I5U0hkefokpVjTZt=I&w( zh2gAcKbYuq(qckPI?NAbW)5RI4Nt}$U&slj+(FlJmSXN&WPrNJfT1f!>F7Ea?*mhA zq(c9Wo;1e?t(lyaO8DEl;_n+FGQ$gi2~S|m-y{(#Hv)N6d$<&smEn zBXa3JS0^;(XXwHHk-k@HQdmA16XKZQ+6WNh7sboY)|6H-g zr`0?`cKr9el55`?BNyn^z{MdQwJEy#Eea4IYtX&7nOBH~a*A%#REL~SO@9MePB zSM>fwYA)n~^+8}Hk~hioZ`UG!&Dty@R2|s|{c$~qx!`L;?2*p4LZR>=0Y^a2wO-ba z#(|HBy}*=M9kQ2^0{+|1Jn}O6KDNfxU^t-Or6mr{5WZlG$EPAQKqxEm|UvB~tZ zc_CZP3*p@rL_fP zD9b|^scx8G9Fi71T2*6;@RyM*NyBRxpf+E|Rvh;u_N76v9}-FRRgvuG1g1gwAV{f` z88IA{2}lAg2-;s3!`iVm`~`{ZAbUcA5~YwsXB1)6~|-BM6aT9}p0=wRp}1a3gC>tj<%v#?e0tu_JKva-V@iR*9{H4tVz z?FleYsqzbvXYl1@;!&xEs)i`*y)l|lc6h(MGlHY2E87s+!nj!Mt9Ar>M}2=b*)?Nv z*kB!yL8Bp_02P7`BLV6wXOS`jx9Fl$NNX#Dw0s>Jie52@RV_MT8=yV)*2`N2md}L7 zr>AdN4}7fRJnDHGp$6?WUmWwP5iNtNiTi6}f&vuh!4hUv@LN*h~hL87j&6`J1zy=-$BD=EG!B+65UXO zjPck8n%HqtG97`$>e#84jm3e}nn3hVE>7stSp_pv6QWtoN^)f=1##O=)xXXG^AD0h zh&w9E`Yk~q^pjp5&cC*^dF)7o%Y&4l>qzje;Lql&fj))8&o$$%XmCfO;DWP|5$wKB zB^jX(gNQ}=N^%@zglJ)lAX(MZ69^Pzg+hQRs0GwG_zI(?OvgHsqme01A!-O9ND>G- zg31LVJ$Vd5V6KE>HzghTP-(Mjl$`}@&PnfvJb?nZ%4AL|vja5`H(1PmM35O~MYC>{ zDba}X|50lvYWJzav{v?&7_h|Q!xDGyXk_dGOWBIrTM<4PkD8fPla;(lYa4geu!6e5 z1+NR^${9a^SF8H$t1bnUWhJ1e)9L^&Q*B1qGL50Iqf;`$x1;+2ba%hyOurR#<^8Itt9X!BdC2@SL1*6G?l!=QGmV=Q&aPTd-Q8 zU+xI;(ZUDAth86stDs*7Bk-~J?I8X@5tn`Bg3;x*NMfoB0r1%=RT69WP5(++0FUa; zo#RQ2YZc`}RQs6em>3LnqBaM$v_judZGn>h?J^4GEm2@fKtl0AFDANLvI6}hiwC^$ z9YNrxYr-Dt-H6qifrOK4lTXWP8K0gCX_eX_Kbe-;TcZLa z!{{|Z=eZF-G(nSEuZ;?e0DymIxfg?m!>yd3GUNAPau#OGLxP?axUHoLd+gN-J-7qR zv9-vGsK%T$@J*9_kUvhtJx-B*XsTmN4g=Ghwoup~G#(9#p}3QT>9!Ua^$439C9F%2 zb>dddN^bE);vF)|0U2NzJmwU~MsP#c@tGe)*D8SK{?s9xk{;~+#i8@lz60Y zYYX5+o(JXy*NqLKE_OD5Y{71E9TZSTJm&C>xMA$HgtCCX{H5Cvx!GZM(4kIMlz}YT z*YKc!nJkrvJy;D$$)iFgKgS)g8OIUZ#**V$pMr`99G&mB2@*1f8yLOujt; zN-LE#9orla#|!JmM5M2K9IC3|dh_K3%_*%BD5H&tN)tONEbk1ei(>KEL>tDjE=UH) zq7p3@@lH)V_ev47Yf~_erD8%Zn4?P6h90_D)$6hHXCW0~c@$Lj70+qSgXHVWNe-*s zB`WgIDy#jbJrt1y%JpTqb@+JbCT?E4W7X)VgBk;2E4ZmRkO=BHw2>agdG?t!B&hBF ze5_(B5}-rTGPB-4x_BB>Eq2%VQDU^u(j%LME?&=lPOE`T&nVdl)M;ovv`t4rh_Y5@ zcogvZ-D0UzBiYpl=&-2W0Lhtx!81Y$2(*U5wQADQL+4EOY=?wF&q%;3fQJH@6$q;e zj-GlO|MHcKzOwNELC-=SwsL_dkfh0rr)rKv{rKJinDf?h`F7YtZ2*|r>a92=JIx+j zOT_BYwj*tESv5wR8dB)=^e(y+8N|FU$}3`eTF9xV6id(Z;49R!A*X>X)Z&zIbMC9O zri##+U}3O^q8eEd887G$yQ~?tRVrRFWnrp(*spB*tp&Jvob3AOH4x*eAg5CrnjUnx z>#FpS<@8YI9Ed&L;ym86$dA@aT>WfW3t|FIdZfcJZ+(?Lhcc)jvxPBON|AopWE|`} zBy4vLHod{3K<5TBV`bhOZ5mmL=*N!91VFQEAH)MP9>>sg&qwDUjt$iFk=gX{r}t*q zDowSUmbQi+Jz0Az3H8P)PxWI(`sSbmT`z?dU;AqE3Ej|R5vu*uyk19j+%5iTGsudp zlE-vuD5gM$!kWyn6G<(rwzdxD@5O8|{oTL+`4G*3*4#Qz6VeZ4#NI~joSAT^nx*bo z8lDrh_TZ^e4HPz$;M)UOD${j2ch$SU#%m z2?|MRVfXcb4Uxrb%u?WucE8Ejj<@~A(DTRw$zUGY@WLZ~+nH|F{;!N`vcnqK(1s>& zE&=8k%_2M`bc)#GEuO^kc$Jv}hjose^b{3k``FUBRK|4TV^GURJ=m!I`4k}iiOD04 zJ4Gj@@iey-0v_np7@eLivm%TZhK{Y=~!Gz~g?KsR5H3eAn4 zCJ(0l`ekhwG6F{a=})r{T*uo;sxyc4iO3gYz`}VxE%}8_)&#M7NCMjVU&)D(4P92r zKZ4EPb%(gM;uv_=C_R+tDd_te#-DiqiP$eOB3&9kGyCQ{?16qnCy-g`?&tPzmyHbg zb2cG_?4<;$p6R$BwxjZd3oNLd*1XM&4wfHZf+8!?y$KK8wu2xN;sPS!&Iwe^e*w`6 zee$78J^}y$0flKpLr_UWLm+T+Z)Rz1WdHyuk$sUpNW(xFhTpapi&PxUAmWgrI*0{P z5l5{;5h{dQp;ZTyOaGurLz3d+D7Y3J{8_9zxH#+T;3^1$KOjzyPKqv4;&(}*MT~bG z_we5LzTABW1RE8mSzY6RrrTyZnGmzNRk8aOVMJ&O7?qi2%t=xTzT@j20lweGd6s|O zpQBgJTMP(@#IwvWZQ>2$=}p_s#v_rw>4edX>5X4i15lB4w}pygSm_w|{F|{rdqqMskpsfL^2k000JJOGiWi z{{a60|De66lK=n!32;bRa{vGf6951U69E94oEQKA00(qQO+^Rf1rP}*F_7}{qkr8G@bI?pqm=b6TFY~M$(aU9!yrId6W zN6I;;aU9z}fn-QBAa&89J=l*xCwHbj1 zqLa?^Y`Wj5}9|ZBNJ~kPs0t`eB1D$Z^pqmPLGG>!$SBLQ zgjIkJn&-Ji@0~uZ0u8UY5cAkQ?gA4lJTg4bsQ`14p!j$^ngSG3IHUKD^t$HtdZm5e zJ3wUm2}8mNU})SaMa2YE?hP7_*r7aUTIha7kRoLmhP1A08it|0*Z<@sde*WmElpVN zl=s3YVS>wjiGZAQd*C!pT}WvWdjB|%G)+^Q=ed<1u18F$wYFJkB@ob3X)@<=k$C&TRt=YDU&e8iI@XzN-1sI z)>V|w01D@bk307!czLMu!Td~ykdnGD!hups`u6QxyNBOT?nNP>o>WC_Z929cBM?$$}vv3{C?^|3?dO5z06T?)mKtoBIz&;>G61U zoclPA3y+XcsxB;3`@Xk(lrDTPnIxA|=QxhEZCm>B<421i0<{!p8Z#2YZjhAMLqB4I zwbrf-Q3xV3OOQUNr^p0-cAygLOi<*8;JdDCHxFRB^ftIlf&ZDH0SrCE_V=znyJeMQ z+qPXI$y;yYh-x<5S~o0>O^(5JqHBm7zvKaICutNmL=KQFLC0~V*XxyDuh+#;tn*R( z>@xV;tn*A$5i+GtM8#Dql`@Ufu(#J2dZ-I{o@blL2#g|ndB@BYRgNonZ8SSUu}$5t zh+((MnFR+Wx?Vu6Nmpk8Ef#r3f^w?EQJEV|)+Kpjdbojj56dZ=CYCmWsaGb>Hkb;0 zZb#CXU+VHWeBdNSU=t}rujt-ry6jCA6{hihDntck@MzjhVigT>97`G#RH-2olW;68 zUf;cMpiz9B<-kP#pfJ~a%EPG;!BYbkj>eqJ$SF*XZX!*qk_8fBBMRD0RemzOs0u_) z3rP;Eg!dQGvz(jA33MJQH|LnqP&Tv13*6MKh-mmsoweCnBy*cq_c9vgb5sRn4DB5- zviKY)R#7!`U~C3pY0-qmxjE6->#6c_S(c9P>zZ|4yJ#T#)6*QT(p#!fcPT}z@SQBC zj`snL2PkYwRv1RnUH~ITJ%RW7QbcVq$5v4^5Wy9RtROzq_ew*s)N=&NrIfU7Tf?(f zMI2c>g#4KT@(eA>lBr>dlMekaFEcECa6+Y`{Q+{6XgaJlNwy@rB4}Bb3-`!mMVtV6 zt>rk(2Okkmc)RLtFFo(OJu1C?K7si-j;0i4^YX}z9<9GDOW%EZX>-6(7!h&rHYa^x z>dglY!cI*JG2C4_Z`!=I_Qoo@r<9VufB)WLSZ24z&=5C}aAJaFeTp0b3zg$q@;pCh ziSmIcTW&{jvQbx3e-q`oAtHW3V9nY=Ro*e*HS{D~({#0z(x$r-G~yFlhvcc&n$~sg z5Sj?jZqVyLalx4*Q<8my?U zJjmc)lBe(X)}uyg9LKb6TT27)=!n#uGWqN=YL9<4HHyv%{7IXfxuEaZiV}0D<}*!= ze%B^<1`tytjdgPL8K*|SYLmk=LU%OyGfs{Eq)pC_=_LgL5c z(e>;OI-hZBMB2@UsqI0qT(FVx(_0*bd={?YM`O5O*hPRIBrmx#4wM2DKl7(nRMF&| z;%*~^`R->FB4wkUC{3LxJF7#~CSS^+c5{52S*4JtLVP&lliGLS6yB;wZE|+Y^5KdK zZDD&w5Y;52zZ0h*MnrA$WgsHKsjRHauFA`fa6cPj5&!eg4PMchu6p1E+{0!6)6>Ph3Q~8;zi;0D+8E;N3YzHx-T!4@500 z^DRQ#&&DY-YvSFpw`els2Nt60z@4P%=Qba`6V)A)qh}P}$}yhX;j}nBdTLyNkr4r& zp6y57qJxh7&4Fq<4{2&$?nH6gOb!yB5z->Q0MGyWAxHiw!8rsQ5~dC@z;~j!fl0&p zP83TnPpZ>M(N0vz1GorJel5##Z67hR<}}y0p#5iY+F$T7*hlU}g~#L~W<`aZpL6;m z=EgKqv}ix!?&miju@lt|Mg3JH&B;ld7GW6jtYBD@~3Z9jFBQ1 zMvx)<@)_T*FbeIZ^xYmle`3R*(!Ik@RAzV(aedh6 vqbkoi2^%p%Co%7|6ZO|K!6E(SKcD{x6y=*Sul1!Y00000NkvXXu0mjfJp%3c literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/codechickenlib/textures/gui/dynamic/gui_borderless.png b/src/main/resources/assets/codechickenlib/textures/gui/dynamic/gui_borderless.png new file mode 100644 index 0000000000000000000000000000000000000000..87a64d8b40e597de2f289eb04e33545c063d897e GIT binary patch literal 6281 zcmeHKc{r5o`yYE$B9$dFMiiNSm?g?uR5G%LWR`arnHgp=sF0mb5=GfN*0iI^5@jtX zQ4TF+sZ=UkN}SU1eMfapUBB-?UDxmXUo+P`^S;mXxj*-Pf1dk!-sedq@7%gnK|=uo zfh@JNwcZ8(n~SeSvfytSGiU$;k-Hh@?9Sgs5kdpG90oH0fbv5F0Voi{WI!Mxy)Ev{ z)ORAqxlX6yMX(#w1h2E)XyF{ryp7g2)lC>I%-xetM?fQGH458j2M7P0i(OW0+xpi@ zOGQf4O(5gUkPhpO(|dn>iQDI@y2bMjV=wMm_)#B+ezvD*M^yI3M+!ECOgTjD>f89b zT6batxn@zXD)nB%>XW+h zd$+8k;hZYWguDlAYsl-w{h9vQbL$Z|dMNnUD4RUg1C<&JF=~dnb?*k`v=2@_%DB-WqivaBVSCv+xx-r9>Nj+Y=JuzvaPsaPy~eAgMSpeIYi|J<1u9vY1$)h|5#E*GVHzUr=y z-W)b^xg>YLdNA~O-0JWc<*gc_#}mm}0mWJ2aq7OAq3Lq|8_yvJmys(r`WM=^-Iz6B zdLF$7cJ6MXYCA-&EJ5a}Bh=hH%}1p7MpK>}^(b9__Y?VTVGZXzEtV{*p|m;d_wn`9 zF}(FznXO-=!hX*=hL!A(zg71%INl=z)4k&IiP)#zM~)rD_9{+~X|i^fVJ)3chKLTa zFmTJPWcHF+M?vyqUD;j7SM5!m<%v9kBt$K8DeqRry*J@{kF&d(43Sa9HlcyZ%XisC zf8q9!@zXfO`m3b^Y*86aUM25^OLZ2U*3e<|_mY?9Jua(cZuc7MuIcYhL<^V^Ilkej zV>j-aG!y6AMrw{o$A4I^Z`q~!ne4u0Hud>mu0!v_W;Aj#4kVbSk4_vqd6dD+bmvo_ z9V(9+KD(|{e$R#-l3goK42^Xuzg8qCEnR$cOHjnzAuaIMPeq$lNN z9nrxjU)^uVM}=~>th|?7lK8$L@j>Vd8#hwujXL>6Rp~p%YGX4hD%{?Zj1ldD=2de( z@jEmtwz*ow-`B??u<^MXRlXg6&_25R8?o5c* zxLirwcx-67jeDcr{WcTT3n6t`Lan?3j*qOUl%XjgO4wo^h>;R=W5!x)mZi zyl%D0^Va0l_@PtJDwLg5)P+0fTGzsP_zBXcy6Xy4cO*#rgg%jp=1%f@zhB(+ls^^? zjWn4sR}p!gTB``7SJBs%lidz{@v~Rv^l;Q$jgd2JEa8BYfCCRL2zLpcIfD_Pe|tQZ357g zt7y``adj(srZBoVo;5TYo5c?~9sWEQdE2}nepG3rm#lx1zsGFEsp1_5#I(~4_fJtn z3R4p+op_UNd0lN0wz_-yjrr1ks-txj--08-3Tcx|A4I!*-)RZ0FV%Gr@>sK1XYf(3 zZ+j8WI{~^Mkk2E(3o0G?bhh)jeErb5E6-2`^O`1U;qoG3lx&NZC=k8$ld@(?Oq;_e z-%UO>PW*Uk_9g7^F^?WD%Hi64WAbfkOytA4gDtCk=eMy9v2%Qw}Vq#k9_P0PnT z$_E|iJC9(mJ6|4DC^JY5YCkM}D1}`T1HCy=BE9?QCT!lKE|W1*s{gH1`PdFMzx(nY z6a8^gTe8*dyU*HOQK>Oj-Y^W^SW~(Ve_s_(Jijz=RAFe(^xr$Y6;cMB7i+CL8;&MRv&9+MuuH^jkQv; zM@31phh~k{mBlLyOGy>k_)x^XRz2%i`X!_J8!BKGo#!w-m3z-zD%T9!sP|ZxekepK z7I=RUJcJdtJnH-y9NGh&oO10@QeWGZJU*j#uW@A9V!E85{yGzH3k|R+T^2odz|!`K z{Zu+RwxR=Fh5_X=zo!)x2x@drO%;bHbA$Lbak15{ zEn&|Eeji3hbg37{lE}EQz_5Oqx}(qZU)2q`zOT`~+PoD3E%ivvu^ z;1eg}!hVIe4V4i!LzumZs?7zARvIV6xm+XwKWRKS~m+>C@l7a;t7 zW-xbqGSrI01)w+t4uOK(gfN3KuuTe3Q!brB+GV}vD+Tyu2J_?d14&4vP$)zQu?P;= z7l|ekiAWR%iNU}@1e_Pj=2Jr8Y@V)|;tPj0z@u@QfqW*14Ha`zs2l;`3CkCNAOK*2P#)+N{e#P`cJ}0dEW{G{GFgEOR-o8FAo)zjzheCm zo498oo$mty&Hv&30sSra1u%%RwSB$ zWeNl^7rLO(g|a14XkVQ0D8T@I!4YWprHkfAVfzB${Qg={-`bh~Ww3BGW3&m82*9ZX zJOhqHVW@B_4xEG-G?s{Gn9wO`8udqZ9*4mfQn-MHFPJHq4Ol=6*+ADXNNMmRTIdIe zbwYu28-;^oP|g@M34NCpnwTyCzFP)ByDx3v@&c|_ z$bXirubPQv{2zY4j>Z4b14#YL$xrF~ORisX{geVf1^!iCzvTKU1%3+rtGfQ*HZ6TwbxyV8?X41y2&?nS2T~*Bxgm|PgKiS^|K#KFKL40=;C!-gJSB_1~#d8SEwqp zC7n-XMYa#?Lt#k}e@TyhCuBoTiskL@B1)r?V#(| zT=2wQtwjQpWeUon4-Yfq?)O?f`tZa?g#-yGMT&xm5|SqnN)nPlDAKFQQBXugP!tPN zY)Fx!RK<>nf})}a1StwA3KsM}LC-n5-uvaO_1uEE4|7P}o_RN~u>FR8+B)?1^ z0)Z$wP$_QU(?)d3N`v<@R@gHLL^eO#!%N^s6T-MW4wDrEzywiT00u;|m=H+h;|_1{ zz2l~eUq+00l3@~^gWSp+O1v+4n;Z0Ci}LNOBmU6mOLf^u^yE+99k~A`bO=>uX3VW{Y zZWMAyFLXWY+(l7d6pPB8wS88p+_1!OePuH5&lvSFui3buy$_G%C}h3#C~N9`FZA;| zYmbi}Nvr+Z{NOVp;ed6(juvvWx)K)JHWXDG;^3DZ5K$kC)i0ovr{lULR@bij-1v0s zJ$d$`=_PviUw^&$v~NyJ-DJM$+wu9K75%>3BFwIJe0pmZ;Nl*hrm+&b!O7?Jp$9`^ zgR5(@EB7S^3eaESd4BWE9jcA>V%2dMOaAN+sZr)SEf1;fa9%s}EF?LjMQKoT(H)cK zm495Xx_L&-L1AdB`u_R5mp@CY9co?C*l^uHynhG2q+#X66GWQ%u8xYi4woy#r&Nb? zUC(`>n)#5BBkg@qa`wJ8X<{mCYd4lGoBOiOI;mVHX=8=4?p|77eO~Fk%b3K?#g@|R zo@}o3dJ`j-FY9A3OSgnVf*#th|KK;$w?z{xRxEx`Wz`vRvE?P>&~B+oxjy|>K6H5> z?XhFzD$?3cMJmPRaH7)(DZf#J4z`!Ffw&h}e7 zaR-LnshEv_=DInrY?vSwVBCibd3R3u-A&rBz+9qec%ptRxb&V!*;e=4)%ZFW1%zqP z6Std{g5Fq}c){2c_q$DsYo9ynWf20WsCs*_FM{qLTFNZMN1Z$vaOr3bEp~QZEGVL6 zSj}i@r&&+ejU7l@s`D{F>E=Q?jf^TANP0xlqnr>~=WNwmyCn;Y4DdtQU6*EJ8lG+Sp$u3Wz?D6=oq7BlujCAMw)+`&VV$b920 zV(<)~uy-JBq9S70(E7=%KIRASmz&Q*Z>jb!y{TB-M#(BoLw2wAeG{y9;t?NbA(Ml2 zCuZ81d`QevD5KDq$2og#`D8y+Pg+SiJe3@=B0XYJNz*I(9ny%5^-kY?x|QMHN~6nz z6sejLi}1rl{+axdw|PZnqY?V~z^CH{oYBnP`?NNudg{(^^?h02OdM#ePZ%*7fLi*( zS`(sLTM`@-{VQM9IcTT3NSS0VQ5CzIrJI_z(Wle!31;l_B(`XFX7F^;t-asqFUOix zj+7sKPI?yUCZoCJ`Wwl7cmg}m`h4-n=9D9j2Nhh7^+fvbs@H0td8w-x6JBE6w9TFM z>J>Th#GSri!rF5uBCgNyBMOGAM>$ou-;JghZ&wj}h6~X=P)miV4Q%x3YgxNti!aTe zJs2U&a{2ORruLC^$#XLnZ*9-H=Q3V#)|z; zBGBlyf4}ru*2|{o(~&)KL~FW^zQ!@sT<~D zc&NW|_C7%+JE2J;qWz`3hO0ayoIuf(*4tBbbQ7fag00!HYo1*?w;<_uDGjch3-;zV zN~;wT81Vsj(l<{IY?1B!C@rikj=chiUsUK@{q%_2GTSCk0V^jI7&wWJ~4B1cIX%-Ml2m;*Xc^C|f?* zJ62##zBsTwQ01+A_!8|ydv*}wk7ee%_$pAkmu88rtE&%Aed~5?9_TtlDc@aMsNjj8 zB`<$tl^M^s6~p?+R2Vr@{BsUKowS99^(God>g7}TZk0#ICaFCgv8w&NDV?;!kE$32 z&%%SJWp+N0DSIlFs=qQ<>+#2YTHC5pyVK)kv#<#L!+~dO=HTl!XVc&2TpB8p%u^~2 zkhxQBs47$B9WnFACFsob?gJ-@J4ZdYeRBEu3gdd#?yQ>Xso;_biwF4G=(y9&eyO#Z z<7KaOjOV-WYF;0|?i{qOv~bC5YH@+~>81-_;>Y*bF1PC5+iFlVmyx$=X4jr8)b+z1 z%lz*xre1&IKA~-Ndyj*|fNKR>W6gvs{v53+eSfls^O$|>*7sStaYqKKn+OS4X*QP2q(ZJyLyLAkX@2eGc=^q@xEQ_9 zs~GRfp6yfd;7eM@WUZ5xG7LDfTDU5{Z3phI)Lficl--4Hr>L#VNJf{!)t6D1jc?r+ zvU$!^<{m^k@FrwD<;ui4l?;VMh@_YD+w{lIb}0#0;{qSH$xvFxfZlb)uwd5Hmh~04VwRh5ZQ@wJ>iQbjH%e5=@Mp&Wc4_91XTC;fi z=0pF7_q!vJW|GcpMgU;XzC8WP{gWp%rOHwn+P*IypRf!n{pviF?v?S`816}qT4s2B zI4FVj#wMp1;Lyag*My?XTuxeBlWvrI^-DI$kUh$73yae%-8@d|H>D-9<)+R*^Sor* z521R|EgB9mPm$mGBFDB#YdFgC}M+GeBG zvHiZriHn4b$r14Mdym%<fSlO{P&T}Hh4ze)?N^)f~ zW1aVQPibwRotl1+Y^iFzJ5PiMwJ;J~^bZ5!ZSZHX!_O{`70&LYR~VPKkF?XJeY59s z#xrkn3fC(uSm2lp+`D#+|M{La$3;~aj;gq*T=R4~wL^F0!i}h1RhvT3-Ld?r&?XfN z9301|=d{A}V5F2J>D8sJwn>|c)Kr%~c8Q)#*SbPMrfyY7^Nfq7l`ag*d`lj9TF`M_ z&djJ#G6_{Pj}f1FE&lpsXuM8;#AnGVYl+R#z1xGua7T`tHEj7JtJx=wJkwBcL1yb4 zNU}@#qipT#F7AdJiL5;Gest)+dhk8K ztvAXI;B&%xbighGU<>qqMlk4q`*Xv2Aq(L!=qMlr2n9{~V5^v4nzVOta{b#wBtZZx zl)K;siv5eFfW`brtY7*js#yr<=Z=8xe{+Aa{wwwcW6;XU$(+KWhl{%BK(U02+Bau# z=q!f$!mBCMgy@fBnj#n`L?!|c;AjXMo=!wC&G1+}gTSPjGE9F$Ik5Qx8k-J?P#_%1 z0y$U!XG+8a1O(QUZic`U{qYC_7LP+P7<3{5V4C_f2>726E<6^Pm9&tbdnH0KK$MvY zU`E3LGz0;_(Ghrt83y4`z!MN?6M`AY#bcNZ>;j5GH($r$h0?&`WQEcK02G%Uuuvfq z+??dUu{wtl&VG4va9zY5J zBL$-Y6KEkCnBjtyM!#AM0|AjvXmD<$@dzy11B)@o;?1$>H5jxx8VyJN2pA=r)qh27 zf%-q1SS%R)vZ@K=J0{_bRcXs{1$tC~Kfd^oNyC5NWoDmAAj)O-bY5(>16v#KxzqsktKCncN zOZDbMAPTCYOAJy_s0kLz2ppX3WQHZx6g1T?oILOrJnz;zP)Ht;k6-)T+}(;+EF>sV zVeI+IIE^IEi?o!;zUdX4SUdf^Ux#1gpQe;R|JWK6a!n3$HB9g&>HcU+d`3!`*1YPi zikPp`I6m&(`1?;`S6r@?kKK&%oDaJzjI6zeQ%+Bom^!-g{J>;O3abDD5qDE;Yj(0R zN`y4=K7n zSk{Td(0rTi(4&(|>{=hTP8X51PNyq8O;e?JsIRKUHEBWv`c52!0&fap;KSCi6{da6 zK=YmWfTSXXYq0|3q?$%c$Y@Nl6WTk)LIUwb0O?MCD9rL>K~c9rVPw8D2gYI3_9Yl?K{E*n1mT2j>P dprjisR`Ic_wPKxI130P>2RmoV8C$=k{{ZiYXL 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 B_Fw=2 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/codechickenlib/textures/gui/widgets/slot_large.png b/src/main/resources/assets/codechickenlib/textures/gui/widgets/slot_large.png new file mode 100644 index 0000000000000000000000000000000000000000..61c28017fb4f9b4b83470a2fbefd48fc3e662ce6 GIT binary patch literal 5546 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 literal 0 HcmV?d00001