From ab7a2bb72b9ee9591049d4ec3c8815d57986bd2c Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sun, 19 Feb 2023 02:05:30 +0800 Subject: Mini Displays Favorites --- .../impl/client/config/FavoritesConfigManager.java | 2 +- .../collapsible/CollapsibleConfigManager.java | 2 +- .../DelegatingFavoriteEntryProviderImpl.java | 11 ++ .../client/gui/dragging/CurrentDraggingStack.java | 33 ++-- .../collapsible/CollapsibleEntriesScreen.java | 23 +++ .../screen/collapsible/CollapsibleEntryWidget.java | 23 +++ .../client/gui/widget/DisplayCompositeWidget.java | 80 ++++++++-- .../gui/widget/favorites/FavoritesListWidget.java | 4 +- .../listeners/FavoritesRegionListener.java | 12 ++ .../gui/widget/favorites/panel/FavoritesPanel.java | 5 +- .../panel/rows/FavoritesPanelEntriesRow.java | 7 +- .../gui/widget/region/EntryStacksRegionWidget.java | 96 +++++++++++- .../gui/widget/region/RegionDraggableStack.java | 25 --- .../client/gui/widget/region/RegionListener.java | 13 ++ .../client/util/AbstractIndexedCyclingList.java | 2 +- .../rei/impl/client/util/ClientTickCounter.java | 2 +- .../impl/client/util/ConcatenatedListIterator.java | 2 +- .../rei/impl/client/util/CyclingList.java | 2 +- .../client/util/OriginalRetainingCyclingList.java | 2 +- .../client/runtime/DefaultClientRuntimePlugin.java | 171 ++++++++++++++++++++- 20 files changed, 440 insertions(+), 77 deletions(-) (limited to 'runtime/src/main/java') diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/FavoritesConfigManager.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/FavoritesConfigManager.java index b4a73f007..7c10ded8a 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/FavoritesConfigManager.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/FavoritesConfigManager.java @@ -1,6 +1,6 @@ /* * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel + * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 shedaniel * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/collapsible/CollapsibleConfigManager.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/collapsible/CollapsibleConfigManager.java index edcca423d..1a7781111 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/config/collapsible/CollapsibleConfigManager.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/config/collapsible/CollapsibleConfigManager.java @@ -1,6 +1,6 @@ /* * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel + * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 shedaniel * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/favorites/DelegatingFavoriteEntryProviderImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/favorites/DelegatingFavoriteEntryProviderImpl.java index 17d34c12f..e84b9f942 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/favorites/DelegatingFavoriteEntryProviderImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/favorites/DelegatingFavoriteEntryProviderImpl.java @@ -27,8 +27,11 @@ import com.mojang.serialization.DataResult; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.favorites.FavoriteMenuEntry; import me.shedaniel.rei.api.client.gui.Renderer; +import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponent; +import me.shedaniel.rei.api.client.gui.widgets.Slot; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Objects; @@ -93,6 +96,8 @@ public class DelegatingFavoriteEntryProviderImpl extends FavoriteEntry { @Override public FavoriteEntry copy() { + if (value != null && toJson != null) return value.copy(); + if (value != null) return FavoriteEntry.delegateResult(() -> DataResult.success(value.copy()), toJson); return FavoriteEntry.delegateResult(supplier, toJson); } @@ -114,4 +119,10 @@ public class DelegatingFavoriteEntryProviderImpl extends FavoriteEntry { public boolean isSame(FavoriteEntry other) { return getUnwrapped().isSame(other.getUnwrapped()); } + + @Override + @Nullable + public DraggableComponent asDraggableComponent(Slot slot) { + return getUnwrapped().asDraggableComponent(slot); + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/dragging/CurrentDraggingStack.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/dragging/CurrentDraggingStack.java index 838c14516..4e1cbc59f 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/dragging/CurrentDraggingStack.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/dragging/CurrentDraggingStack.java @@ -26,9 +26,7 @@ package me.shedaniel.rei.impl.client.gui.dragging; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.clothconfig2.api.animator.NumberAnimator; import me.shedaniel.clothconfig2.api.animator.ValueAnimator; -import me.shedaniel.math.FloatingRectangle; -import me.shedaniel.math.Point; -import me.shedaniel.math.Rectangle; +import me.shedaniel.math.*; import me.shedaniel.rei.RoughlyEnoughItemsCoreClient; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.drag.DraggableBoundsProvider; @@ -87,13 +85,14 @@ public class CurrentDraggingStack extends Widget implements LateRenderable, Drag if (entry.dragging) { matrices.pushPose(); matrices.translate(0, 0, 600); - entry.bounds.update(delta); + entry.point.update(delta); + entry.dimension.update(delta); int width = entry.component.getWidth(); int height = entry.component.getHeight(); Vec2 mouseStartOffset = entry.mouseStartOffset; - entry.bounds.setTo(new FloatingRectangle(mouseX - width / 2 - mouseStartOffset.x, mouseY - height / 2 - mouseStartOffset.y, width, height), - reducedMotion ? 0 : 30); - entry.component.render(matrices, entry.bounds.value().getBounds(), mouseX, mouseY, delta); + entry.point.setTo(new FloatingPoint(mouseX - mouseStartOffset.x * width, mouseY - mouseStartOffset.y * height), reducedMotion ? 0 : 30); + entry.dimension.setTo(new FloatingDimension(width, height), reducedMotion ? 0 : 700); + entry.component.render(matrices, getCurrentBounds(), mouseX, mouseY, delta); matrices.popPose(); VoxelShape shape = entry.getBoundsProvider().bounds(); @@ -216,16 +215,18 @@ public class CurrentDraggingStack extends Widget implements LateRenderable, Drag public Point getCurrentPosition() { if (!isDraggingComponent()) return null; Vec2 mouseStartOffset = entry.mouseStartOffset; - FloatingRectangle rectangle = entry.bounds.value(); - return new Point(rectangle.getCenterX() + mouseStartOffset.x, rectangle.getCenterY() + mouseStartOffset.y); + FloatingPoint point = entry.point.value(); + FloatingDimension dimension = entry.dimension.value(); + return new Point(point.x + mouseStartOffset.x * dimension.width, point.y + mouseStartOffset.y * dimension.height); } @Override @Nullable public Rectangle getCurrentBounds() { if (!isDraggingComponent()) return null; - FloatingRectangle rectangle = entry.bounds.value(); - return rectangle.getBounds(); + FloatingPoint point = entry.point.value(); + FloatingDimension dimension = entry.dimension.value(); + return new Rectangle(point.x - dimension.width / 2, point.y - dimension.height / 2, dimension.width, dimension.height); } @Override @@ -249,7 +250,8 @@ public class CurrentDraggingStack extends Widget implements LateRenderable, Drag private final DraggableComponent component; private final Point start; private long startDragging = -1; - private final ValueAnimator bounds; + private final ValueAnimator point; + private final ValueAnimator dimension; private final Vec2 mouseStartOffset; private boolean dragging = false; private DraggableBoundsProvider boundsProvider; @@ -257,9 +259,10 @@ public class CurrentDraggingStack extends Widget implements LateRenderable, Drag private DraggableEntry(DraggableComponent component, Point start) { this.component = component; this.start = start; - this.bounds = ValueAnimator.ofFloatingRectangle() - .setAs(component.getOriginBounds(start).getFloatingBounds()); - this.mouseStartOffset = new Vec2((float) (start.x - bounds.value().getCenterX()), (float) (start.y - bounds.value().getCenterY())); + FloatingRectangle floatingBounds = component.getOriginBounds(start).getFloatingBounds(); + this.point = ValueAnimator.ofFloatingPoint().setAs(new FloatingPoint(floatingBounds.getCenterX(), floatingBounds.getCenterY())); + this.dimension = ValueAnimator.ofFloatingDimension().setAs(new FloatingDimension(floatingBounds.width, floatingBounds.height)); + this.mouseStartOffset = new Vec2((float) (start.x - point.value().x) / (float) dimension.value().width, (float) (start.y - point.value().y) / (float) dimension.value().height); } public DraggableBoundsProvider getBoundsProvider() { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/collapsible/CollapsibleEntriesScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/collapsible/CollapsibleEntriesScreen.java index cb5ff971c..483f37dff 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/collapsible/CollapsibleEntriesScreen.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/collapsible/CollapsibleEntriesScreen.java @@ -1,3 +1,26 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 shedaniel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.shedaniel.rei.impl.client.gui.screen.collapsible; import com.google.common.collect.Multimap; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/collapsible/CollapsibleEntryWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/collapsible/CollapsibleEntryWidget.java index 187313152..1ade1dbeb 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/collapsible/CollapsibleEntryWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/screen/collapsible/CollapsibleEntryWidget.java @@ -1,3 +1,26 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 shedaniel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package me.shedaniel.rei.impl.client.gui.screen.collapsible; import com.mojang.blaze3d.systems.RenderSystem; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DisplayCompositeWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DisplayCompositeWidget.java index 0e040ebf6..a2a1b915f 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DisplayCompositeWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/DisplayCompositeWidget.java @@ -27,14 +27,15 @@ import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.config.ConfigObject; +import me.shedaniel.rei.api.client.gui.config.RecipeBorderType; import me.shedaniel.rei.api.client.gui.drag.DraggedAcceptorResult; import me.shedaniel.rei.api.client.gui.drag.DraggingContext; import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponent; import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentProviderWidget; -import me.shedaniel.rei.api.client.gui.widgets.DelegateWidgetWithBounds; -import me.shedaniel.rei.api.client.gui.widgets.Widget; -import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.client.gui.widgets.*; import me.shedaniel.rei.api.common.display.Display; +import me.shedaniel.rei.api.common.entry.EntryIngredient; +import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; import me.shedaniel.rei.impl.display.DisplaySpec; @@ -47,10 +48,12 @@ import java.util.stream.StreamSupport; public class DisplayCompositeWidget extends DelegateWidgetWithBounds implements DraggableComponentProviderWidget { private final DisplaySpec display; + private final List widgets; public DisplayCompositeWidget(DisplaySpec display, List widgets, Rectangle bounds) { super(Widgets.concat(widgets), () -> bounds); this.display = display; + this.widgets = widgets; } @Override @@ -62,7 +65,9 @@ public class DisplayCompositeWidget extends DelegateWidgetWithBounds implements .findFirst() .orElseGet(() -> { if (containsMouse(mouseX, mouseY)) { - return (DraggableComponent) (DraggableComponent) new DisplayDraggableComponent(widget, display.provideInternalDisplay(), getBounds(), getBounds()); + return (DraggableComponent) (DraggableComponent) new DisplayDraggableComponent( + Widgets.concat(CollectionUtils.filterToList(widgets, w -> !(w instanceof Panel))), + display.provideInternalDisplay(), getBounds(), getBounds()); } else { return null; } @@ -114,22 +119,41 @@ public class DisplayCompositeWidget extends DelegateWidgetWithBounds implements private final Display display; private final Rectangle originBounds; private final Rectangle bounds; + private final Panel panel; + private final Slot slot; + public boolean onFavoritesRegion; public DisplayDraggableComponent(Widget widget, Display display, Rectangle originBounds, Rectangle bounds) { this.widget = widget; this.display = display; this.originBounds = originBounds; this.bounds = bounds; + this.panel = Widgets.createRecipeBase(bounds.clone()); + this.slot = Widgets.createSlot(new Rectangle()) + .disableBackground() + .disableHighlight() + .disableTooltips(); + for (EntryIngredient ingredient : display.getOutputEntries()) { + slot.entries(ingredient); + } } @Override public int getWidth() { - return bounds.width; + if (this.onFavoritesRegion) { + return 18; + } + + return bounds.width / 2; } @Override public int getHeight() { - return bounds.height; + if (this.onFavoritesRegion) { + return 18; + } + + return bounds.height / 2; } @Override @@ -139,11 +163,47 @@ public class DisplayCompositeWidget extends DelegateWidgetWithBounds implements @Override public void render(PoseStack matrices, Rectangle bounds, int mouseX, int mouseY, float delta) { + if (DraggingContext.getInstance().isDraggingComponent()) { + FavoritesListWidget favorites = ScreenOverlayImpl.getFavoritesListWidget(); + if (favorites != null) { + Rectangle favoritesBounds = favorites.getRegion().getBounds(); + if (!this.onFavoritesRegion && new Rectangle(favoritesBounds.x + 5, favoritesBounds.y + 5, favoritesBounds.width - 10, favoritesBounds.height - 10) + .contains(DraggingContext.getInstance().getCurrentPosition())) { + this.onFavoritesRegion = true; + } else if (this.onFavoritesRegion && !favoritesBounds.contains(DraggingContext.getInstance().getCurrentPosition())) { + this.onFavoritesRegion = false; + } + } else { + this.onFavoritesRegion = false; + } + } else { + this.onFavoritesRegion = false; + } + matrices.pushPose(); - matrices.translate(bounds.getX(), bounds.getY(), 0); - matrices.scale(bounds.width / (float) this.bounds.getWidth(), bounds.height / (float) this.bounds.getHeight(), 1); - matrices.translate(-this.bounds.getX(), -this.bounds.getY(), 0); - widget.render(matrices, -1000, -1000, delta); + if (bounds.width <= Math.max(18, this.bounds.width / 2 - 6) && bounds.height <= Math.max(18, this.bounds.height / 2 - 6) && this.onFavoritesRegion) { + this.panel.yTextureOffset(RecipeBorderType.LIGHTER.getYOffset()); + this.panel.getBounds().setBounds(bounds); + this.panel.render(matrices, mouseX, mouseY, delta); + matrices.pushPose(); + matrices.translate(0, 0.5, 0); + this.slot.getBounds().setBounds(bounds.getCenterX() - 7, bounds.getCenterY() - 7, 14, 14); + this.slot.render(matrices, mouseX, mouseY, delta); + matrices.popPose(); + } else { + this.panel.yTextureOffset(ConfigObject.getInstance().getRecipeBorderType().getYOffset()); + matrices.pushPose(); + matrices.translate(bounds.getX(), bounds.getY(), 1); + matrices.scale(bounds.width / (float) this.bounds.getWidth(), bounds.height / (float) this.bounds.getHeight(), 1); + matrices.translate(-this.bounds.getX(), -this.bounds.getY(), 0); + this.panel.getBounds().setBounds(this.bounds); + this.panel.render(matrices, mouseX, mouseY, delta); + matrices.popPose(); + matrices.translate(bounds.getX(), bounds.getY(), 1); + matrices.scale(bounds.width / (float) this.bounds.getWidth(), bounds.height / (float) this.bounds.getHeight(), 1); + matrices.translate(-this.bounds.getX(), -this.bounds.getY(), 0); + widget.render(matrices, -1000, -1000, delta); + } matrices.popPose(); } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesListWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesListWidget.java index db5a2c9f3..0b285f0f9 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesListWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/FavoritesListWidget.java @@ -126,9 +126,9 @@ public class FavoritesListWidget extends WidgetWithBounds implements DraggableCo @Override @Nullable public DraggableComponent getHovered(DraggingContext context, double mouseX, double mouseY) { - DraggableComponent stack = region.getHoveredStack(context, mouseX, mouseY); + DraggableComponent stack = region.getHovered(context, mouseX, mouseY); if (stack != null) return (DraggableComponent) stack; - stack = systemRegion.getHoveredStack(context, mouseX, mouseY); + stack = systemRegion.getHovered(context, mouseX, mouseY); if (stack != null) return (DraggableComponent) stack; if (favoritePanel.containsMouse(mouseX, mouseY)) { stack = favoritePanel.getHoveredStack(mouseX, mouseY); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/listeners/FavoritesRegionListener.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/listeners/FavoritesRegionListener.java index 078be4703..1e8f9cce8 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/listeners/FavoritesRegionListener.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/listeners/FavoritesRegionListener.java @@ -27,6 +27,8 @@ import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.gui.drag.DraggableStack; import me.shedaniel.rei.api.client.gui.drag.DraggingContext; +import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponent; +import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesEntriesManager; import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; import me.shedaniel.rei.impl.client.gui.widget.region.RealRegionEntry; @@ -36,6 +38,7 @@ import net.minecraft.client.gui.screens.Screen; import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -69,6 +72,15 @@ public class FavoritesRegionListener implements RegionListener { return FavoriteEntry.fromEntryStack(stack.getStack().copy()); } + @Override + @Nullable + public FavoriteEntry convertDraggableComponent(DraggingContext context, DraggableComponent component) { + return component.getIf() + .map(Supplier::get) + .map(FavoriteEntry::fromDisplay) + .orElse(null); + } + @Override public void onSetNewEntries(List> regionEntryListEntries) { favoritesListWidget.setSystemRegionEntries(null); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesPanel.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesPanel.java index 21dd3a2f0..c0c0830f5 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesPanel.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/FavoritesPanel.java @@ -35,6 +35,7 @@ import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; import me.shedaniel.rei.api.client.gui.drag.DraggableStack; +import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponent; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; @@ -148,10 +149,10 @@ public class FavoritesPanel extends WidgetWithBounds { } @Nullable - public DraggableStack getHoveredStack(double mouseX, double mouseY) { + public DraggableComponent getHoveredStack(double mouseX, double mouseY) { for (FavoritesPanelRow row : rows.get()) { if (row instanceof FavoritesPanelEntriesRow entriesRow) { - DraggableStack hoveredStack = entriesRow.getHoveredStack(mouseX, mouseY); + DraggableComponent hoveredStack = entriesRow.getHoveredStack(mouseX, mouseY); if (hoveredStack != null) { return hoveredStack; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEntriesRow.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEntriesRow.java index 034ae0095..8a55c331f 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEntriesRow.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/favorites/panel/rows/FavoritesPanelEntriesRow.java @@ -31,7 +31,7 @@ import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; -import me.shedaniel.rei.api.client.gui.drag.DraggableStack; +import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponent; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; import me.shedaniel.rei.api.client.gui.widgets.TooltipContext; import me.shedaniel.rei.api.client.util.ClientEntryStacks; @@ -39,6 +39,7 @@ import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.impl.client.gui.widget.DisplayedEntryWidget; import me.shedaniel.rei.impl.client.gui.widget.favorites.panel.FavoritesPanel; +import me.shedaniel.rei.impl.client.gui.widget.region.EntryStacksRegionWidget; import me.shedaniel.rei.impl.client.gui.widget.region.RealRegionEntry; import me.shedaniel.rei.impl.client.gui.widget.region.RegionDraggableStack; import net.minecraft.client.gui.components.events.GuiEventListener; @@ -118,12 +119,12 @@ public class FavoritesPanelEntriesRow extends FavoritesPanelRow { } @Nullable - public DraggableStack getHoveredStack(double mouseX, double mouseY) { + public DraggableComponent getHoveredStack(double mouseX, double mouseY) { for (SectionFavoriteWidget widget : widgets) { if (widget.containsMouse(mouseX, mouseY + panel.getScrolledAmount())) { RealRegionEntry entry = new RealRegionEntry<>(panel.getParent().getRegion(), widget.entry.copy(), entrySize()); entry.size.setAs(entrySize() * 100); - return new RegionDraggableStack<>(entry, widget); + return EntryStacksRegionWidget.wrapDraggable(new RegionDraggableStack<>(entry, widget), entry.region, entry); } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/EntryStacksRegionWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/EntryStacksRegionWidget.java index 724735edc..a8903ca37 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/EntryStacksRegionWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/EntryStacksRegionWidget.java @@ -37,7 +37,12 @@ import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.entry.region.RegionEntry; -import me.shedaniel.rei.api.client.gui.drag.*; +import me.shedaniel.rei.api.client.gui.drag.DraggableStack; +import me.shedaniel.rei.api.client.gui.drag.DraggedAcceptorResult; +import me.shedaniel.rei.api.client.gui.drag.DraggingContext; +import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponent; +import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentProviderWidget; +import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentVisitorWidget; import me.shedaniel.rei.api.client.gui.widgets.Widget; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; import me.shedaniel.rei.api.common.entry.EntrySerializer; @@ -62,7 +67,7 @@ import java.util.stream.Stream; import static me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget.entrySize; -public class EntryStacksRegionWidget> extends WidgetWithBounds implements DraggableStackProviderWidget, DraggableStackVisitorWidget { +public class EntryStacksRegionWidget> extends WidgetWithBounds implements DraggableComponentProviderWidget, DraggableComponentVisitorWidget { public final RegionListener listener; protected int blockedCount; private Rectangle bounds = new Rectangle(), innerBounds; @@ -178,17 +183,81 @@ public class EntryStacksRegionWidget> extends WidgetWit @Override @Nullable - public DraggableStack getHoveredStack(DraggingContext context, double mouseX, double mouseY) { + public DraggableComponent getHovered(DraggingContext context, double mouseX, double mouseY) { if (innerBounds.contains(mouseX, mouseY)) { for (RealRegionEntry entry : entries.values()) { if (entry.getWidget().containsMouse(mouseX, mouseY) && listener.canBeDragged(entry)) { - return new RegionDraggableStack<>(entry, null); + DraggableComponent component = listener.convertToDraggableComponent(entry); + return (DraggableComponent) wrapDraggable(component, this, entry); } } } + return null; } + public static > DraggableComponent wrapDraggable(DraggableComponent component, EntryStacksRegionWidget region, RealRegionEntry entry) { + return new DraggableComponent<>() { + private int previousIndex = -1; + + @Override + public T get() { + return component.get(); + } + + @Override + public int getWidth() { + return component.getWidth(); + } + + @Override + public int getHeight() { + return component.getHeight(); + } + + @Override + public void drag() { + if (region.listener.removeOnDrag()) { + previousIndex = region.indexOf(entry); + region.remove(entry, EntryStacksRegionWidget.RemovalMode.MIGRATED); + } + + component.drag(); + } + + @Override + public void release(DraggedAcceptorResult result) { + component.release(result); + + if (result != DraggedAcceptorResult.CONSUMED) { + if (!entry.region.listener.removeOnDrag()) { + DraggingContext.getInstance().renderBack(this, DraggingContext.getInstance().getCurrentPosition(), + () -> entry.pos.value().getLocation()); + } else if (result == DraggedAcceptorResult.ACCEPTED) { + DraggingContext context = DraggingContext.getInstance(); + double x = context.getCurrentPosition().x; + double y = context.getCurrentPosition().y + entry.region.getScrollAmount(); + entry.region.drop(entry, x, y, previousIndex); + } else { + entry.region.drop(entry); + } + } else { + entry.region.listener.onConsumed(entry); + } + } + + @Override + public void render(PoseStack matrices, Point position, int mouseX, int mouseY, float delta) { + component.render(matrices, position, mouseX, mouseY, delta); + } + + @Override + public void render(PoseStack matrices, Rectangle bounds, int mouseX, int mouseY, float delta) { + component.render(matrices, bounds, mouseX, mouseY, delta); + } + }; + } + public EntryStack getFocusedStack() { Point mouse = mouse(); if (innerBounds.contains(mouse)) { @@ -209,6 +278,13 @@ public class EntryStacksRegionWidget> extends WidgetWit } @Override + public DraggedAcceptorResult acceptDragged(DraggingContext context, DraggableComponent component) { + return component.>getIf() + .map(comp -> acceptDraggedStack(context, DraggableStack.from(comp))) + .orElse(innerBounds.contains(context.getCurrentPosition()) && drop(context, component) + ? DraggedAcceptorResult.CONSUMED : DraggedAcceptorResult.PASS); + } + public DraggedAcceptorResult acceptDraggedStack(DraggingContext context, DraggableStack stack) { return checkDraggedStacks(context, stack) .filter(entry -> innerBounds.contains(context.getCurrentPosition())) @@ -223,6 +299,14 @@ public class EntryStacksRegionWidget> extends WidgetWit }).isPresent() ? DraggedAcceptorResult.CONSUMED : DraggedAcceptorResult.PASS; } + public boolean drop(DraggingContext context, DraggableComponent component) { + T regionEntry = listener.convertDraggableComponent(context, component); + if (regionEntry == null) return false; + RealRegionEntry entry = new RealRegionEntry<>(this, regionEntry, entrySize()); + entry.size.setAs(entrySize() * 100); + return drop(entry); + } + public Optional> checkDraggedStacks(DraggingContext context, DraggableStack stack) { EntrySerializer serializer = stack.getStack().getDefinition().getSerializer(); if (serializer != null && (stack instanceof RegionDraggableStack || (serializer.supportReading() && serializer.supportSaving()))) { @@ -348,7 +432,9 @@ public class EntryStacksRegionWidget> extends WidgetWit private int getReleaseIndex(@Nullable Point position) { DraggingContext context = DraggingContext.getInstance(); if (position == null) position = context.getCurrentPosition(); - if (context.isDraggingStack() && bounds.contains(position) && checkDraggedStacks(context.cast(), context.getCurrentStack()).isPresent()) { + boolean draggingStack = context.isDraggingStack() && bounds.contains(position) && checkDraggedStacks(context.cast(), context.getCurrentStack()).isPresent(); + boolean draggingComponent = draggingStack || (context.isDraggingComponent() && bounds.contains(position) && this.listener.convertDraggableComponent(context.cast(), context.getDragged()) != null); + if (draggingStack || draggingComponent) { int entrySize = entrySize(); int width = innerBounds.width / entrySize; int currentX = 0; diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionDraggableStack.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionDraggableStack.java index 5a93c2033..51a94a9d4 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionDraggableStack.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionDraggableStack.java @@ -23,11 +23,9 @@ package me.shedaniel.rei.impl.client.gui.widget.region; -import me.shedaniel.math.Point; import me.shedaniel.rei.api.client.entry.region.RegionEntry; import me.shedaniel.rei.api.client.gui.drag.DraggableStack; import me.shedaniel.rei.api.client.gui.drag.DraggedAcceptorResult; -import me.shedaniel.rei.api.client.gui.drag.DraggingContext; import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds; import me.shedaniel.rei.api.common.entry.EntryStack; @@ -35,7 +33,6 @@ public class RegionDraggableStack> implements Draggable private RealRegionEntry entry; private EntryStack stack; private WidgetWithBounds showcaseWidget; - private int previousIndex = -1; public RegionDraggableStack(RealRegionEntry entry, WidgetWithBounds showcaseWidget) { this.entry = entry; @@ -50,10 +47,6 @@ public class RegionDraggableStack> implements Draggable @Override public void drag() { - if (showcaseWidget == null && entry.region.listener.removeOnDrag()) { - previousIndex = entry.region.indexOf(entry); - entry.region.remove(entry, EntryStacksRegionWidget.RemovalMode.MIGRATED); - } } public RealRegionEntry getEntry() { @@ -62,24 +55,6 @@ public class RegionDraggableStack> implements Draggable @Override public void release(DraggedAcceptorResult result) { - if (result != DraggedAcceptorResult.CONSUMED) { - if (!entry.region.listener.removeOnDrag()) { - DraggingContext.getInstance().renderBackToPosition(this, DraggingContext.getInstance().getCurrentPosition(), - () -> entry.pos.value().getLocation()); - } else if (showcaseWidget != null) { - DraggingContext.getInstance().renderBackToPosition(this, DraggingContext.getInstance().getCurrentPosition(), - () -> new Point(showcaseWidget.getBounds().x, showcaseWidget.getBounds().y)); - } else if (result == DraggedAcceptorResult.ACCEPTED) { - DraggingContext context = DraggingContext.getInstance(); - double x = context.getCurrentPosition().x; - double y = context.getCurrentPosition().y + entry.region.getScrollAmount(); - entry.region.drop(entry, x, y, previousIndex); - } else { - entry.region.drop(entry); - } - } else { - entry.region.listener.onConsumed(entry); - } } public WidgetWithBounds getShowcaseWidget() { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionListener.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionListener.java index e480348c4..829933230 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionListener.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/region/RegionListener.java @@ -27,6 +27,7 @@ import me.shedaniel.rei.api.client.entry.region.RegionEntry; import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.gui.drag.DraggableStack; import me.shedaniel.rei.api.client.gui.drag.DraggingContext; +import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponent; import me.shedaniel.rei.impl.client.gui.widget.entrylist.EntryListWidget; import net.minecraft.client.gui.screens.Screen; import org.jetbrains.annotations.Nullable; @@ -42,6 +43,11 @@ public interface RegionListener> { return null; } + @Nullable + default T convertDraggableComponent(DraggingContext context, DraggableComponent component) { + return null; + } + default boolean canAcceptDrop(RealRegionEntry entry) { return true; } @@ -72,4 +78,11 @@ public interface RegionListener> { default boolean notSteppingOnExclusionZones(int left, int top, int width, int height) { return EntryListWidget.notSteppingOnExclusionZones(left, top, width, height); } + + @Nullable + default DraggableComponent convertToDraggableComponent(RealRegionEntry entry) { + DraggableComponent component = entry.getEntry().asDraggableComponent(entry.getWidget()); + if (component != null) return component; + return new RegionDraggableStack<>(entry, null); + } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/util/AbstractIndexedCyclingList.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/util/AbstractIndexedCyclingList.java index 199afbb29..c22e9662b 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/util/AbstractIndexedCyclingList.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/util/AbstractIndexedCyclingList.java @@ -1,6 +1,6 @@ /* * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel + * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 shedaniel * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/util/ClientTickCounter.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/util/ClientTickCounter.java index 03e2d9de8..4df85beda 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/util/ClientTickCounter.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/util/ClientTickCounter.java @@ -1,6 +1,6 @@ /* * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel + * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 shedaniel * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/util/ConcatenatedListIterator.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/util/ConcatenatedListIterator.java index eedd2b0cf..73169e421 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/util/ConcatenatedListIterator.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/util/ConcatenatedListIterator.java @@ -1,6 +1,6 @@ /* * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel + * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 shedaniel * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/util/CyclingList.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/util/CyclingList.java index 2fb060d7a..35f2283e7 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/util/CyclingList.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/util/CyclingList.java @@ -1,6 +1,6 @@ /* * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel + * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 shedaniel * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/util/OriginalRetainingCyclingList.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/util/OriginalRetainingCyclingList.java index f66e65723..aeb557d45 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/util/OriginalRetainingCyclingList.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/util/OriginalRetainingCyclingList.java @@ -1,6 +1,6 @@ /* * This file is licensed under the MIT License, part of Roughly Enough Items. - * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel + * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 shedaniel * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/DefaultClientRuntimePlugin.java b/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/DefaultClientRuntimePlugin.java index ee5dc388c..cdbec40ac 100644 --- a/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/DefaultClientRuntimePlugin.java +++ b/runtime/src/main/java/me/shedaniel/rei/plugin/client/runtime/DefaultClientRuntimePlugin.java @@ -36,13 +36,14 @@ import me.shedaniel.rei.api.client.favorites.FavoriteEntry; import me.shedaniel.rei.api.client.favorites.FavoriteEntryType; import me.shedaniel.rei.api.client.gui.AbstractRenderer; import me.shedaniel.rei.api.client.gui.Renderer; +import me.shedaniel.rei.api.client.gui.config.RecipeBorderType; +import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponent; import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentProviderWidget; import me.shedaniel.rei.api.client.gui.drag.component.DraggableComponentVisitorWidget; -import me.shedaniel.rei.api.client.gui.widgets.Panel; -import me.shedaniel.rei.api.client.gui.widgets.Tooltip; -import me.shedaniel.rei.api.client.gui.widgets.TooltipContext; -import me.shedaniel.rei.api.client.gui.widgets.Widgets; +import me.shedaniel.rei.api.client.gui.widgets.*; import me.shedaniel.rei.api.client.plugins.REIClientPlugin; +import me.shedaniel.rei.api.client.registry.category.CategoryRegistry; +import me.shedaniel.rei.api.client.registry.display.DisplayCategory; import me.shedaniel.rei.api.client.registry.display.DisplayRegistry; import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; import me.shedaniel.rei.api.client.registry.screen.ExclusionZones; @@ -50,18 +51,25 @@ import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry; import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry; import me.shedaniel.rei.api.client.search.method.InputMethodRegistry; import me.shedaniel.rei.api.client.util.ClientEntryStacks; +import me.shedaniel.rei.api.common.category.CategoryIdentifier; +import me.shedaniel.rei.api.common.display.Display; +import me.shedaniel.rei.api.common.display.DisplaySerializerRegistry; +import me.shedaniel.rei.api.common.entry.EntryIngredient; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.plugins.PluginManager; import me.shedaniel.rei.api.common.plugins.REIPlugin; import me.shedaniel.rei.api.common.registry.Reloadable; +import me.shedaniel.rei.api.common.util.CollectionUtils; import me.shedaniel.rei.api.common.util.EntryStacks; import me.shedaniel.rei.impl.client.ClientHelperImpl; import me.shedaniel.rei.impl.client.REIRuntimeImpl; import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl; import me.shedaniel.rei.impl.client.gui.screen.DefaultDisplayViewingScreen; +import me.shedaniel.rei.impl.client.gui.widget.DisplayCompositeWidget; import me.shedaniel.rei.impl.client.gui.widget.favorites.FavoritesListWidget; import me.shedaniel.rei.impl.client.search.method.DefaultInputMethod; import me.shedaniel.rei.impl.client.search.method.unihan.*; +import me.shedaniel.rei.impl.common.InternalLogger; import me.shedaniel.rei.impl.common.entry.type.EntryRegistryImpl; import me.shedaniel.rei.impl.common.entry.type.EntryRegistryListener; import me.shedaniel.rei.impl.common.util.HNEntryStackWrapper; @@ -75,8 +83,7 @@ import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import java.util.Collections; -import java.util.List; +import java.util.*; import java.util.function.Function; @Environment(EnvType.CLIENT) @@ -101,7 +108,7 @@ public class DefaultClientRuntimePlugin implements REIClientPlugin { public void registerEntries(EntryRegistry registry) { if (ClientHelperImpl.getInstance().isAprilFools.get()) { registry.addEntry(ClientEntryStacks.of(new AbstractRenderer() { - private ResourceLocation id = new ResourceLocation("roughlyenoughitems", "textures/gui/kirb.png"); + private final ResourceLocation id = new ResourceLocation("roughlyenoughitems", "textures/gui/kirb.png"); @Override public void render(PoseStack matrices, Rectangle bounds, int mouseX, int mouseY, float delta) { @@ -162,6 +169,7 @@ public class DefaultClientRuntimePlugin implements REIClientPlugin { @Override public void registerFavorites(FavoriteEntryType.Registry registry) { registry.register(EntryStackFavoriteType.INSTANCE.id, EntryStackFavoriteType.INSTANCE); + registry.register(DisplayFavoriteType.INSTANCE.id, DisplayFavoriteType.INSTANCE); } @Override @@ -183,7 +191,7 @@ public class DefaultClientRuntimePlugin implements REIClientPlugin { INSTANCE(FavoriteEntryType.ENTRY_STACK); private final String key = "data"; - private ResourceLocation id; + private final ResourceLocation id; EntryStackFavoriteType(ResourceLocation id) { this.id = id; @@ -263,4 +271,151 @@ public class DefaultClientRuntimePlugin implements REIClientPlugin { return EntryStacks.equalsExact(stack, that.stack); } } + + private enum DisplayFavoriteType implements FavoriteEntryType { + INSTANCE(FavoriteEntryType.DISPLAY); + + private final String key = "data"; + private final ResourceLocation id; + + DisplayFavoriteType(ResourceLocation id) { + this.id = id; + } + + @Override + public DataResult read(CompoundTag object) { + try { + if (object.contains("Data")) { + Display display = DisplaySerializerRegistry.getInstance().read(CategoryIdentifier.of(object.getString("CategoryID")), object.getCompound("Data")); + return DataResult.success(new DisplayFavoriteEntry(display, UUID.fromString(object.getString("UUID"))), Lifecycle.stable()); + } else { + return DataResult.success(new DisplayFavoriteEntry(null, UUID.fromString(object.getString("UUID"))), Lifecycle.stable()); + } + } catch (Throwable throwable) { + return DataResult.error(throwable.getMessage()); + } + } + + @Override + public DataResult fromArgs(Object... args) { + if (args.length == 0) return DataResult.error("Cannot create DisplayFavoriteEntry from empty args!"); + if (!(args[0] instanceof Display display)) + return DataResult.error("Creation of DisplayFavoriteEntry from args expected Display as the first argument!"); + return DataResult.success(new DisplayFavoriteEntry(display, UUID.randomUUID()), Lifecycle.stable()); + } + + @Override + public CompoundTag save(DisplayFavoriteEntry entry, CompoundTag tag) { + boolean hasSerializer = DisplaySerializerRegistry.getInstance().hasSerializer(entry.display.getCategoryIdentifier()); + tag.putString("CategoryID", entry.display.getCategoryIdentifier().toString()); + tag.putString("UUID", entry.uuid.toString()); + + if (hasSerializer) { + try { + tag.put("Data", DisplaySerializerRegistry.getInstance().save(entry.display, new CompoundTag())); + } catch (Exception e) { + InternalLogger.getInstance().warn("Failed to save display favorite entry", e); + } + } + + return tag; + } + } + + private static class DisplayFavoriteEntry extends FavoriteEntry { + private static final Function, String> CANCEL_FLUID_AMOUNT = s -> null; + private final Display display; + private final UUID uuid; + private final long hash; + + public DisplayFavoriteEntry(Display display, UUID uuid) { + this.display = display; + this.uuid = uuid; + this.hash = uuid.hashCode(); + } + + @Override + public UUID getUuid() { + return uuid; + } + + @Override + public boolean isInvalid() { + return this.display == null; + } + + @Override + public Renderer getRenderer(boolean showcase) { + Panel panel = Widgets.createRecipeBase(new Rectangle(0, 0, 18, 18)) + .yTextureOffset(RecipeBorderType.LIGHTER.getYOffset()); + Slot slot = Widgets.createSlot(new Rectangle()) + .disableBackground() + .disableHighlight() + .disableTooltips(); + for (EntryIngredient ingredient : display.getOutputEntries()) { + slot.entries(ingredient); + } + return new AbstractRenderer() { + @Override + public void render(PoseStack matrices, Rectangle bounds, int mouseX, int mouseY, float delta) { + matrices.pushPose(); + matrices.translate(bounds.getX(), bounds.getY(), 1); + matrices.scale(bounds.width / (float) panel.getBounds().getWidth(), bounds.height / (float) panel.getBounds().getHeight(), 1); + panel.render(matrices, mouseX, mouseY, delta); + matrices.popPose(); + if (bounds.width > 4 && bounds.height > 4) { + matrices.pushPose(); + matrices.translate(0, 0.5, 0); + slot.getBounds().setBounds(bounds.x + 2, bounds.y + 2, bounds.width - 4, bounds.height - 4); + slot.render(matrices, mouseX, mouseY, delta); + matrices.popPose(); + } + } + }; + } + + @Override + public boolean doAction(int button) { + ClientHelperImpl.getInstance() + .openDisplayViewingScreen(Map.of(CategoryRegistry.getInstance().get(display.getCategoryIdentifier()).getCategory(), List.of(display)), + null, List.of(), List.of()); + Widgets.produceClickSound(); + return true; + } + + @Override + public long hashIgnoreAmount() { + return hash; + } + + @Override + public FavoriteEntry copy() { + return new DisplayFavoriteEntry(this.display, this.uuid); + } + + @Override + public ResourceLocation getType() { + return DisplayFavoriteType.INSTANCE.id; + } + + @Override + public boolean isSame(FavoriteEntry other) { + if (!(other instanceof DisplayFavoriteEntry that)) return false; + return Objects.equals(this.uuid, that.uuid); + } + + @Override + @Nullable + public DraggableComponent asDraggableComponent(Slot slot) { + CategoryRegistry.CategoryConfiguration configuration = CategoryRegistry.getInstance().get((CategoryIdentifier) display.getCategoryIdentifier()); + DisplayCategory category = configuration.getCategory(); + Rectangle displayBounds = new Rectangle(0, 0, category.getDisplayWidth(display), category.getDisplayHeight()); + List widgets = configuration.getView(display).setupDisplay(display, displayBounds); + DisplayCompositeWidget.DisplayDraggableComponent component = new DisplayCompositeWidget.DisplayDraggableComponent( + Widgets.concat(CollectionUtils.filterToList(widgets, w -> !(w instanceof Panel))), + display, slot.getInnerBounds(), displayBounds); + component.onFavoritesRegion = true; + return component; + } + } } -- cgit