From 9ea4a22e9a194fd8fdc2fb03226ab38ee175a6cc Mon Sep 17 00:00:00 2001 From: shedaniel Date: Mon, 26 Oct 2020 10:49:27 +0800 Subject: Favorites Dragging Signed-off-by: shedaniel --- .../me/shedaniel/rei/RoughlyEnoughItemsCore.java | 108 ++- .../me/shedaniel/rei/compat/LBASupportPlugin.java | 59 ++ .../shedaniel/rei/gui/ContainerScreenOverlay.java | 235 +++--- .../me/shedaniel/rei/gui/OverlaySearchField.java | 3 + .../me/shedaniel/rei/gui/RecipeViewingScreen.java | 4 - .../rei/gui/VillagerRecipeViewingScreen.java | 6 +- .../java/me/shedaniel/rei/gui/modules/Menu.java | 6 +- .../entries/EntryStackSubsetsMenuEntry.java | 3 +- .../rei/gui/modules/entries/GameModeMenuEntry.java | 2 +- .../gui/modules/entries/SubSubsetsMenuEntry.java | 3 +- .../rei/gui/modules/entries/WeatherMenuEntry.java | 2 +- .../rei/gui/plugin/DefaultRuntimePlugin.java | 124 +++ .../rei/gui/widget/EntryListEntryWidget.java | 33 +- .../shedaniel/rei/gui/widget/EntryListWidget.java | 55 +- .../me/shedaniel/rei/gui/widget/EntryWidget.java | 28 +- .../rei/gui/widget/FavoritesListWidget.java | 915 ++++++++++++++++++--- .../main/java/me/shedaniel/rei/impl/Animator.java | 97 +++ .../me/shedaniel/rei/impl/ConfigManagerImpl.java | 32 +- .../me/shedaniel/rei/impl/ConfigObjectImpl.java | 17 +- .../rei/impl/FavoriteEntryTypeRegistryImpl.java | 107 +++ .../me/shedaniel/rei/impl/RecipeHelperImpl.java | 1 + 21 files changed, 1509 insertions(+), 331 deletions(-) create mode 100644 RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/compat/LBASupportPlugin.java create mode 100644 RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/impl/Animator.java create mode 100644 RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/impl/FavoriteEntryTypeRegistryImpl.java (limited to 'RoughlyEnoughItems-runtime/src/main/java') diff --git a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java index 2bb94e36e..9ea31b888 100644 --- a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java +++ b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java @@ -25,11 +25,17 @@ package me.shedaniel.rei; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import me.shedaniel.cloth.api.client.events.v0.ClothClientHooks; +import me.shedaniel.clothconfig2.api.LazyResettable; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.math.api.Executor; import me.shedaniel.rei.api.*; +import me.shedaniel.rei.api.favorites.FavoriteEntry; +import me.shedaniel.rei.api.favorites.FavoriteEntryType; +import me.shedaniel.rei.api.favorites.FavoriteMenuEntry; import me.shedaniel.rei.api.fluid.FluidSupportProvider; import me.shedaniel.rei.api.fractions.Fraction; import me.shedaniel.rei.api.plugins.REIPluginV0; @@ -66,6 +72,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.chat.FormattedText; import net.minecraft.network.chat.TextComponent; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; import net.minecraft.world.InteractionResult; import net.minecraft.world.inventory.CraftingMenu; import net.minecraft.world.inventory.Slot; @@ -77,6 +84,7 @@ import net.minecraft.world.level.material.Fluid; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; @@ -88,6 +96,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.BiFunction; import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Stream; import static me.shedaniel.rei.impl.Internals.attachInstance; @@ -180,6 +189,94 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer { return new FillRectangleDrawableConsumer(rectangle, color); } }, Internals.WidgetsProvider.class); + attachInstance((Supplier) FavoriteEntryTypeRegistryImpl::getInstance, "favoriteEntryTypeRegistry"); + attachInstance((BiFunction, Supplier, FavoriteEntry>) (supplier, toJson) -> new FavoriteEntry() { + LazyResettable value = new LazyResettable<>(supplier); + + @Override + public FavoriteEntry getUnwrapped() { + FavoriteEntry entry = value.get(); + if (entry == null) { + value.reset(); + } + return Objects.requireNonNull(entry).getUnwrapped(); + } + + @Override + public UUID getUuid() { + return getUnwrapped().getUuid(); + } + + @Override + public boolean isInvalid() { + try { + return getUnwrapped().isInvalid(); + } catch (Exception e) { + return true; + } + } + + @Override + public EntryStack getWidget(boolean showcase) { + return getUnwrapped().getWidget(showcase); + } + + @Override + public boolean doAction(int button) { + return getUnwrapped().doAction(button); + } + + @Override + public @NotNull Optional>> getMenuEntries() { + return getUnwrapped().getMenuEntries(); + } + + @Override + public int hashIgnoreAmount() { + return getUnwrapped().hashIgnoreAmount(); + } + + @Override + public FavoriteEntry copy() { + return FavoriteEntry.delegate(supplier, toJson); + } + + @Override + public ResourceLocation getType() { + return getUnwrapped().getType(); + } + + @Override + public @NotNull JsonObject toJson(@NotNull JsonObject to) { + if (toJson == null) { + return getUnwrapped().toJson(to); + } + + JsonObject object = toJson.get(); + for (Map.Entry entry : object.entrySet()) { + to.add(entry.getKey(), entry.getValue()); + } + return to; + } + + @Override + public boolean isSame(FavoriteEntry other) { + return getUnwrapped().isSame(other.getUnwrapped()); + } + }, "delegateFavoriteEntry"); + attachInstance((Function) (object) -> { + String type = GsonHelper.getAsString(object, FavoriteEntry.TYPE_KEY); + switch (type) { + case "stack": + case "item": + case "fluid": + case "empty": + return FavoriteEntry.fromEntryStack(EntryStack.readFromJson(object)); + default: + ResourceLocation id = new ResourceLocation(type); + return Objects.requireNonNull(Objects.requireNonNull(FavoriteEntryType.registry().get(id)).fromJson(object)); + } + }, "favoriteEntryFromJson"); attachInstance((BiFunction<@Nullable Point, Collection, Tooltip>) QueuedTooltip::create, "tooltipProvider"); attachInstance((Function<@Nullable Boolean, ClickAreaHandler.Result>) successful -> new ClickAreaHandler.Result() { private List categories = Lists.newArrayList(); @@ -189,12 +286,12 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer { this.categories.add(category); return this; } - + @Override public boolean isSuccessful() { return successful; } - + @Override public Stream getCategories() { return categories.stream(); @@ -387,6 +484,13 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer { if (isDebugModeEnabled()) { registerPlugin(new REITestPlugin()); } + if (FabricLoader.getInstance().isModLoaded("libblockattributes-fluids")) { + try { + registerPlugin((REIPluginEntry) Class.forName("me.shedaniel.rei.compat.LBASupportPlugin").getConstructor().newInstance()); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } } private boolean shouldReturn(Screen screen) { diff --git a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/compat/LBASupportPlugin.java b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/compat/LBASupportPlugin.java new file mode 100644 index 000000000..d2e31a6f7 --- /dev/null +++ b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/compat/LBASupportPlugin.java @@ -0,0 +1,59 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020 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.compat; + +import alexiil.mc.lib.attributes.fluid.FluidAttributes; +import alexiil.mc.lib.attributes.fluid.GroupedFluidInvView; +import alexiil.mc.lib.attributes.fluid.amount.FluidAmount; +import me.shedaniel.rei.api.EntryStack; +import me.shedaniel.rei.api.RecipeHelper; +import me.shedaniel.rei.api.fluid.FluidSupportProvider; +import me.shedaniel.rei.api.fractions.Fraction; +import me.shedaniel.rei.api.plugins.REIPluginV0; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.InteractionResultHolder; + +import java.util.stream.Stream; + +public class LBASupportPlugin implements REIPluginV0 { + @Override + public ResourceLocation getPluginIdentifier() { + return new ResourceLocation("roughlyenoughitems", "lba_support"); + } + + @Override + public void registerOthers(RecipeHelper recipeHelper) { + FluidSupportProvider.getInstance().registerProvider(itemStack -> { + GroupedFluidInvView view = FluidAttributes.GROUPED_INV_VIEW.get(itemStack.getItemStack()); + if (view.getStoredFluids().size() > 0) + return InteractionResultHolder.success(view.getStoredFluids().stream() + .filter(fluidKey -> !fluidKey.isEmpty() && fluidKey.getRawFluid() != null) + .map(fluidKey -> { + FluidAmount amount = view.getAmount_F(fluidKey); + return EntryStack.create(fluidKey.getRawFluid(), Fraction.of(amount.whole, amount.numerator, amount.denominator)); + })); + return InteractionResultHolder.pass(Stream.empty()); + }); + } +} diff --git a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/ContainerScreenOverlay.java b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/ContainerScreenOverlay.java index 4e0a5e06b..08132ae85 100644 --- a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/ContainerScreenOverlay.java +++ b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/ContainerScreenOverlay.java @@ -35,6 +35,7 @@ import me.shedaniel.math.Rectangle; import me.shedaniel.math.impl.PointHelper; import me.shedaniel.rei.RoughlyEnoughItemsCore; import me.shedaniel.rei.api.*; +import me.shedaniel.rei.api.favorites.FavoriteEntry; import me.shedaniel.rei.api.widgets.Button; import me.shedaniel.rei.api.widgets.Tooltip; import me.shedaniel.rei.api.widgets.Widgets; @@ -72,11 +73,12 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.stream.Collectors; @ApiStatus.Internal public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverlay { - private static final ResourceLocation CHEST_GUI_TEXTURE = new ResourceLocation("roughlyenoughitems", "textures/gui/recipecontainer.png"); private static final List TOOLTIPS = Lists.newArrayList(); private static final List AFTER_RENDER = Lists.newArrayList(); @@ -120,22 +122,9 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl private Button leftButton, rightButton; @ApiStatus.Experimental private Rectangle subsetsButtonBounds; - @ApiStatus.Experimental - @Nullable - private Menu subsetsMenu = null; - private Widget wrappedSubsetsMenu = null; @Nullable - private Menu weatherMenu = null; - private Widget wrappedWeatherMenu = null; - private boolean renderWeatherMenu = false; - private Button weatherButton = null; - - @Nullable - private Menu gameModeMenu = null; - private Widget wrappedGameModeMenu = null; - private boolean renderGameModeMenu = false; - private Button gameModeButton = null; + private ContainerScreenOverlay.OverlayMenu overlayMenu = null; public static EntryListWidget getEntryListWidget() { return ENTRY_LIST_WIDGET; @@ -146,26 +135,67 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl return favoritesListWidget; } - @ApiStatus.Experimental - @Nullable - public Menu getSubsetsMenu() { - return subsetsMenu; + private static class OverlayMenu { + @NotNull + private UUID uuid; + @NotNull + private Menu menu; + @NotNull + private Widget wrappedMenu; + @NotNull + private Predicate inBounds; + + public OverlayMenu(@NotNull UUID uuid, @NotNull Menu menu, @NotNull Widget wrappedMenu, @NotNull Predicate inBounds) { + this.uuid = uuid; + this.menu = menu; + this.wrappedMenu = wrappedMenu; + this.inBounds = inBounds.or(point -> menu.getBounds().contains(point)); + } + } + + public boolean isMenuOpened(UUID uuid) { + return overlayMenu != null && overlayMenu.uuid.equals(uuid); + } + + public boolean isAnyMenuOpened() { + return overlayMenu != null; } - public void removeWeatherMenu() { - this.renderWeatherMenu = false; - Widget tmpWeatherMenu = wrappedWeatherMenu; - AFTER_RENDER.add(() -> this.widgets.remove(tmpWeatherMenu)); - this.weatherMenu = null; - this.wrappedWeatherMenu = null; + public boolean isMenuInBounds(UUID uuid) { + return isMenuOpened(uuid) && overlayMenu.inBounds.test(PointHelper.ofMouse()); } - public void removeGameModeMenu() { - this.renderGameModeMenu = false; - Widget tmpGameModeMenu = wrappedGameModeMenu; - AFTER_RENDER.add(() -> this.widgets.remove(tmpGameModeMenu)); - this.gameModeMenu = null; - this.wrappedGameModeMenu = null; + private void proceedOpenMenu(UUID uuid, Runnable runnable) { + proceedOpenMenuOrElse(uuid, runnable, menu -> {}); + } + + private void proceedOpenMenuOrElse(UUID uuid, Runnable runnable, Consumer orElse) { + if (overlayMenu == null || !overlayMenu.uuid.equals(uuid)) { + removeOverlayMenu(); + runnable.run(); + } else { + orElse.accept(this.overlayMenu); + } + } + + public void openMenu(UUID uuid, Menu menu, Predicate inPoint) { + this.overlayMenu = new OverlayMenu(uuid, menu, InternalWidgets.wrapTranslate(menu, 0, 0, 400), inPoint); + } + + @ApiStatus.Internal + @Nullable + public Menu getSubsetsMenu() { + if (isMenuOpened(Menu.SUBSETS)) + return this.overlayMenu.menu; + throw new IllegalStateException("Subsets menu accessed when subsets are not opened!"); + } + + @ApiStatus.Internal + public void removeOverlayMenu() { + OverlayMenu tmpOverlayMenu = this.overlayMenu; + if (tmpOverlayMenu != null) + AFTER_RENDER.add(() -> this.widgets.remove(tmpOverlayMenu.wrappedMenu)); + this.overlayMenu = null; } @Override @@ -181,17 +211,14 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl this.shouldReInit = false; //Update Variables this.children().clear(); - this.wrappedSubsetsMenu = null; - this.subsetsMenu = null; - this.weatherMenu = null; - this.renderWeatherMenu = false; - this.weatherButton = null; + this.removeOverlayMenu(); this.window = Minecraft.getInstance().getWindow(); this.bounds = DisplayHelper.getInstance().getOverlayBounds(ConfigObject.getInstance().getDisplayPanelLocation(), Minecraft.getInstance().screen); widgets.add(ENTRY_LIST_WIDGET); if (ConfigObject.getInstance().isFavoritesEnabled()) { if (favoritesListWidget == null) favoritesListWidget = new FavoritesListWidget(); +// favoritesListWidget.favoritePanel.resetRows(); widgets.add(favoritesListWidget); } ENTRY_LIST_WIDGET.updateArea(ScreenHelper.getSearchField() == null ? "" : null); @@ -268,20 +295,21 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl )); tmp.setZ(600); if (ConfigObject.getInstance().doesShowUtilsButtons()) { - widgets.add(gameModeButton = Widgets.createButton(ConfigObject.getInstance().isLowerConfigButton() ? new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getGuiScaledWidth() - 30 : 10, 10, 20, 20) : new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getGuiScaledWidth() - 55 : 35, 10, 20, 20), NarratorChatListener.NO_TITLE) + widgets.add(Widgets.createButton(ConfigObject.getInstance().isLowerConfigButton() ? new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getGuiScaledWidth() - 30 : 10, 10, 20, 20) : new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getGuiScaledWidth() - 55 : 35, 10, 20, 20), NarratorChatListener.NO_TITLE) .onRender((matrices, button) -> { - boolean tmpRender = renderGameModeMenu; - renderGameModeMenu = !renderWeatherMenu && (button.isFocused() || button.containsMouse(PointHelper.ofMouse()) || (wrappedGameModeMenu != null && wrappedGameModeMenu.containsMouse(PointHelper.ofMouse()))); - if (tmpRender != renderGameModeMenu) { - if (renderGameModeMenu) { - this.gameModeMenu = new Menu(new Point(button.getBounds().x, button.getBounds().getMaxY()), - CollectionUtils.filterAndMap(Arrays.asList(GameType.values()), mode -> mode != GameType.NOT_SET, GameModeMenuEntry::new)); - if (ConfigObject.getInstance().isLeftHandSidePanel()) - this.gameModeMenu.menuStartPoint.x -= this.gameModeMenu.getBounds().width - this.gameModeButton.getBounds().width; - this.wrappedGameModeMenu = InternalWidgets.wrapTranslate(InternalWidgets.wrapLateRenderable(gameModeMenu), 0, 0, 600); - AFTER_RENDER.add(() -> this.widgets.add(wrappedGameModeMenu)); - } else { - removeGameModeMenu(); + boolean isOpened = isMenuOpened(Menu.GAME_TYPE); + if (isOpened || !isAnyMenuOpened()) { + boolean inBounds = (button.isFocused() || button.containsMouse(PointHelper.ofMouse())) || isMenuInBounds(Menu.GAME_TYPE); + if (isOpened != inBounds) { + if (inBounds) { + Menu menu = new Menu(new Point(button.getBounds().x, button.getBounds().getMaxY()), + CollectionUtils.filterAndMap(Arrays.asList(GameType.values()), mode -> mode != GameType.NOT_SET, GameModeMenuEntry::new)); + if (ConfigObject.getInstance().isLeftHandSidePanel()) + menu.menuStartPoint.x -= menu.getBounds().width - button.getBounds().width; + openMenu(Menu.GAME_TYPE, menu, point -> button.isFocused() && button.containsMouse(PointHelper.ofMouse())); + } else { + removeOverlayMenu(); + } } } button.setText(new TextComponent(getGameModeShortText(getCurrentGameMode()))); @@ -289,20 +317,22 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl .focusable(false) .tooltipLine(I18n.get("text.rei.gamemode_button.tooltip.all")) .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y))); + Button weatherButton; widgets.add(weatherButton = Widgets.createButton(new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getGuiScaledWidth() - 30 : 10, 35, 20, 20), NarratorChatListener.NO_TITLE) .onRender((matrices, button) -> { - boolean tmpRender = renderWeatherMenu; - renderWeatherMenu = !renderGameModeMenu && (button.isFocused() || button.containsMouse(PointHelper.ofMouse()) || (wrappedWeatherMenu != null && wrappedWeatherMenu.containsMouse(PointHelper.ofMouse()))); - if (tmpRender != renderWeatherMenu) { - if (renderWeatherMenu) { - this.weatherMenu = new Menu(new Point(button.getBounds().x, button.getBounds().getMaxY()), - CollectionUtils.map(Weather.values(), WeatherMenuEntry::new)); - if (ConfigObject.getInstance().isLeftHandSidePanel()) - this.weatherMenu.menuStartPoint.x -= this.weatherMenu.getBounds().width - this.weatherButton.getBounds().width; - this.wrappedWeatherMenu = InternalWidgets.wrapTranslate(InternalWidgets.wrapLateRenderable(weatherMenu), 0, 0, 400); - AFTER_RENDER.add(() -> this.widgets.add(wrappedWeatherMenu)); - } else { - removeWeatherMenu(); + boolean isOpened = isMenuOpened(Menu.WEATHER); + if (isOpened || !isAnyMenuOpened()) { + boolean inBounds = (button.isFocused() || button.containsMouse(PointHelper.ofMouse())) || isMenuInBounds(Menu.WEATHER); + if (isOpened != inBounds) { + if (inBounds) { + Menu menu = new Menu(new Point(button.getBounds().x, button.getBounds().getMaxY()), + CollectionUtils.map(Weather.values(), WeatherMenuEntry::new)); + if (ConfigObject.getInstance().isLeftHandSidePanel()) + menu.menuStartPoint.x -= menu.getBounds().width - button.getBounds().width; + openMenu(Menu.WEATHER, menu, point -> button.isFocused() && button.containsMouse(PointHelper.ofMouse())); + } else { + removeOverlayMenu(); + } } } }) @@ -319,14 +349,11 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl if (ConfigObject.getInstance().isSubsetsEnabled()) { widgets.add(InternalWidgets.wrapLateRenderable(InternalWidgets.wrapTranslate(Widgets.createButton(subsetsButtonBounds, ClientHelperImpl.getInstance().isAprilFools.get() ? new TranslatableComponent("text.rei.tiny_potato") : new TranslatableComponent("text.rei.subsets")) .onClick(button -> { - if (subsetsMenu == null) { - wrappedSubsetsMenu = InternalWidgets.wrapTranslate(InternalWidgets.wrapLateRenderable(this.subsetsMenu = Menu.createSubsetsMenuFromRegistry(new Point(this.subsetsButtonBounds.x, this.subsetsButtonBounds.getMaxY()))), 0, 0, 400); - this.widgets.add(this.wrappedSubsetsMenu); - } else { - this.widgets.remove(this.wrappedSubsetsMenu); - this.subsetsMenu = null; - this.wrappedSubsetsMenu = null; - } + proceedOpenMenuOrElse(Menu.SUBSETS, () -> { + openMenu(Menu.SUBSETS, Menu.createSubsetsMenuFromRegistry(new Point(this.subsetsButtonBounds.x, this.subsetsButtonBounds.getMaxY())), point -> true); + }, menu -> { + removeOverlayMenu(); + }); }), 0, 0, 600))); } if (!ConfigObject.getInstance().isEntryListWidgetScrolled()) { @@ -559,24 +586,15 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl if (ScreenHelper.isOverlayVisible()) { ScreenHelper.getSearchField().laterRender(matrices, mouseX, mouseY, delta); for (Widget widget : widgets) { - if (widget instanceof LateRenderable && wrappedSubsetsMenu != widget && wrappedWeatherMenu != widget && wrappedGameModeMenu != widget) + if (widget instanceof LateRenderable && (overlayMenu == null || overlayMenu.wrappedMenu != widget)) widget.render(matrices, mouseX, mouseY, delta); } } - if (wrappedWeatherMenu != null) { - if (wrappedWeatherMenu.containsMouse(mouseX, mouseY)) { + if (overlayMenu != null) { + if (overlayMenu.wrappedMenu.containsMouse(mouseX, mouseY)) { TOOLTIPS.clear(); } - wrappedWeatherMenu.render(matrices, mouseX, mouseY, delta); - } else if (wrappedGameModeMenu != null) { - if (wrappedGameModeMenu.containsMouse(mouseX, mouseY)) { - TOOLTIPS.clear(); - } - wrappedGameModeMenu.render(matrices, mouseX, mouseY, delta); - } - if (wrappedSubsetsMenu != null) { - TOOLTIPS.clear(); - wrappedSubsetsMenu.render(matrices, mouseX, mouseY, delta); + overlayMenu.wrappedMenu.render(matrices, mouseX, mouseY, delta); } Screen currentScreen = Minecraft.getInstance().screen; if (!(currentScreen instanceof RecipeViewingScreen) || !((RecipeViewingScreen) currentScreen).choosePageActivated) @@ -633,11 +651,7 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl public boolean mouseScrolled(double mouseX, double mouseY, double amount) { if (!ScreenHelper.isOverlayVisible()) return false; - if (wrappedSubsetsMenu != null && wrappedSubsetsMenu.mouseScrolled(mouseX, mouseY, amount)) - return true; - if (wrappedWeatherMenu != null && wrappedWeatherMenu.mouseScrolled(mouseX, mouseY, amount)) - return true; - if (wrappedGameModeMenu != null && wrappedGameModeMenu.mouseScrolled(mouseX, mouseY, amount)) + if (overlayMenu != null && overlayMenu.wrappedMenu.mouseScrolled(mouseX, mouseY, amount)) return true; if (isInside(PointHelper.ofMouse())) { if (!ConfigObject.getInstance().isEntryListWidgetScrolled()) { @@ -657,9 +671,7 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl } for (Widget widget : widgets) if (widget != ENTRY_LIST_WIDGET && (favoritesListWidget == null || widget != favoritesListWidget) - && (wrappedSubsetsMenu == null || widget != wrappedSubsetsMenu) - && (wrappedWeatherMenu == null || widget != wrappedWeatherMenu) - && (wrappedGameModeMenu == null || widget != wrappedGameModeMenu) + && (overlayMenu == null || widget != overlayMenu.wrappedMenu) && widget.mouseScrolled(mouseX, mouseY, amount)) return true; return false; @@ -686,9 +698,9 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl } else if (ConfigObject.getInstance().getUsageKeybind().matchesKey(keyCode, scanCode)) { return ClientHelper.getInstance().openView(ClientHelper.ViewSearchBuilder.builder().addUsagesFor(stack).setInputNotice(stack).fillPreferredOpenedCategory()); } else if (ConfigObject.getInstance().getFavoriteKeyCode().matchesKey(keyCode, scanCode)) { - stack.setAmount(127); - if (!CollectionUtils.anyMatchEqualsEntryIgnoreAmount(ConfigObject.getInstance().getFavorites(), stack)) - ConfigObject.getInstance().getFavorites().add(stack); + FavoriteEntry favoriteEntry = FavoriteEntry.fromEntryStack(stack); + if (!ConfigObject.getInstance().getFavoriteEntries().contains(favoriteEntry)) + ConfigObject.getInstance().getFavoriteEntries().add(favoriteEntry); ConfigManager.getInstance().saveConfig(); FavoritesListWidget favoritesListWidget = ContainerScreenOverlay.getFavoritesListWidget(); if (favoritesListWidget != null) @@ -739,9 +751,9 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl } else if (ConfigObject.getInstance().getUsageKeybind().matchesMouse(button)) { return ClientHelper.getInstance().openView(ClientHelper.ViewSearchBuilder.builder().addUsagesFor(stack).setInputNotice(stack).fillPreferredOpenedCategory()); } else if (ConfigObject.getInstance().getFavoriteKeyCode().matchesMouse(button)) { - stack.setAmount(127); - if (!CollectionUtils.anyMatchEqualsEntryIgnoreAmount(ConfigObject.getInstance().getFavorites(), stack)) - ConfigObject.getInstance().getFavorites().add(stack); + FavoriteEntry favoriteEntry = FavoriteEntry.fromEntryStack(stack); + if (!ConfigObject.getInstance().getFavoriteEntries().contains(favoriteEntry)) + ConfigObject.getInstance().getFavoriteEntries().add(favoriteEntry); ConfigManager.getInstance().saveConfig(); FavoritesListWidget favoritesListWidget = ContainerScreenOverlay.getFavoritesListWidget(); if (favoritesListWidget != null) @@ -751,33 +763,16 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl } if (!ScreenHelper.isOverlayVisible()) return false; - if (wrappedSubsetsMenu != null && wrappedSubsetsMenu.mouseClicked(mouseX, mouseY, button)) { - this.setFocused(wrappedSubsetsMenu); - if (button == 0) - this.setDragging(true); - ScreenHelper.getSearchField().setFocused(false); - return true; - } - if (wrappedWeatherMenu != null) { - if (wrappedWeatherMenu.mouseClicked(mouseX, mouseY, button)) { - this.setFocused(wrappedWeatherMenu); - if (button == 0) - this.setDragging(true); - ScreenHelper.getSearchField().setFocused(false); - return true; - } else if (!wrappedWeatherMenu.containsMouse(mouseX, mouseY) && !weatherButton.containsMouse(mouseX, mouseY)) { - removeWeatherMenu(); - } - } - if (wrappedGameModeMenu != null) { - if (wrappedGameModeMenu.mouseClicked(mouseX, mouseY, button)) { - this.setFocused(wrappedGameModeMenu); + if (overlayMenu != null) { + if (overlayMenu.wrappedMenu.mouseClicked(mouseX, mouseY, button)) { + if (overlayMenu != null) this.setFocused(overlayMenu.wrappedMenu); + else this.setFocused(null); if (button == 0) this.setDragging(true); ScreenHelper.getSearchField().setFocused(false); return true; - } else if (!wrappedGameModeMenu.containsMouse(mouseX, mouseY) && !gameModeButton.containsMouse(mouseX, mouseY)) { - removeGameModeMenu(); + } else if (!overlayMenu.inBounds.test(new Point(mouseX, mouseY))) { + removeOverlayMenu(); } } if (ConfigObject.getInstance().areClickableRecipeArrowsEnabled()) { @@ -811,7 +806,7 @@ public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverl } } for (GuiEventListener element : widgets) - if (element != wrappedSubsetsMenu && element != wrappedWeatherMenu && element != wrappedGameModeMenu && element.mouseClicked(mouseX, mouseY, button)) { + if ((overlayMenu == null || element != overlayMenu.wrappedMenu) && element.mouseClicked(mouseX, mouseY, button)) { this.setFocused(element); if (button == 0) this.setDragging(true); diff --git a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/OverlaySearchField.java b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/OverlaySearchField.java index 9aff059ca..33caf9915 100644 --- a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/OverlaySearchField.java +++ b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/OverlaySearchField.java @@ -84,10 +84,13 @@ public class OverlaySearchField extends TextFieldWidget { @Override protected void renderSuggestion(PoseStack matrices, int x, int y) { + matrices.pushPose(); + matrices.translate(0, 0, 400); if (containsMouse(PointHelper.ofMouse()) || isFocused()) this.font.drawShadow(matrices, this.font.plainSubstrByWidth(this.getSuggestion(), this.getWidth()), x, y, REIHelper.getInstance().isDarkThemeEnabled() ? 0xccddaa3d : 0xddeaeaea); else this.font.drawShadow(matrices, this.font.plainSubstrByWidth(this.getSuggestion(), this.getWidth()), x, y, -6250336); + matrices.popPose(); } @Override diff --git a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/RecipeViewingScreen.java b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/RecipeViewingScreen.java index 9aa2f7da2..8c949bf75 100644 --- a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/RecipeViewingScreen.java +++ b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/RecipeViewingScreen.java @@ -197,7 +197,6 @@ public class RecipeViewingScreen extends Screen implements RecipeScreen { return true; if (keyCode == 256 || this.minecraft.options.keyInventory.matches(keyCode, scanCode)) { Minecraft.getInstance().setScreen(REIHelper.getInstance().getPreviousContainerScreen()); - ScreenHelper.getLastOverlay().init(); return true; } if (keyCode == 259) { @@ -359,7 +358,6 @@ public class RecipeViewingScreen extends Screen implements RecipeScreen { } children.addAll(tabs); - children.add(ScreenHelper.getLastOverlay(true, false)); children.addAll(widgets); children.addAll(preWidgets); } @@ -428,8 +426,6 @@ public class RecipeViewingScreen extends Screen implements RecipeScreen { if (tab.isSelected()) tab.render(matrices, mouseX, mouseY, delta); } - ScreenHelper.getLastOverlay().render(matrices, mouseX, mouseY, delta); - ScreenHelper.getLastOverlay().lateRender(matrices, mouseX, mouseY, delta); { ModifierKeyCode export = ConfigObject.getInstance().getExportImageKeybind(); if (export.matchesCurrentKey() || export.matchesCurrentMouse()) { diff --git a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/VillagerRecipeViewingScreen.java b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/VillagerRecipeViewingScreen.java index 183bea49d..cda292f4c 100644 --- a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/VillagerRecipeViewingScreen.java +++ b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/VillagerRecipeViewingScreen.java @@ -248,8 +248,6 @@ public class VillagerRecipeViewingScreen extends Screen implements RecipeScreen this.children.addAll(buttonList); this.widgets.addAll(tabs); this.children.addAll(widgets); - this.children.add(ScreenHelper.getLastOverlay(true, false)); - ScreenHelper.getLastOverlay().init(); } @Override @@ -360,7 +358,7 @@ public class VillagerRecipeViewingScreen extends Screen implements RecipeScreen for (Widget widget : widgets) { widget.render(matrices, mouseX, mouseY, delta); } - ScreenHelper.getLastOverlay().render(matrices, mouseX, mouseY, delta); + super.render(matrices, mouseX, mouseY, delta); RenderSystem.pushMatrix(); ScissorsHandler.INSTANCE.scissor(scrolling.getBounds()); for (Button button : buttonList) { @@ -380,7 +378,6 @@ public class VillagerRecipeViewingScreen extends Screen implements RecipeScreen scrolling.renderScrollBar(0, scrollBarAlpha, REIHelper.getInstance().isDarkThemeEnabled() ? 0.8f : 1f); ScissorsHandler.INSTANCE.removeLastScissor(); RenderSystem.popMatrix(); - ScreenHelper.getLastOverlay().lateRender(matrices, mouseX, mouseY, delta); } @Override @@ -436,7 +433,6 @@ public class VillagerRecipeViewingScreen extends Screen implements RecipeScreen return true; if (keyCode == 256 || this.minecraft.options.keyInventory.matches(keyCode, scanCode)) { Minecraft.getInstance().setScreen(REIHelper.getInstance().getPreviousContainerScreen()); - ScreenHelper.getLastOverlay().init(); return true; } if (keyCode == 259) { diff --git a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/Menu.java b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/Menu.java index b8c9348e3..f303f9efa 100644 --- a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/Menu.java +++ b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/Menu.java @@ -56,6 +56,10 @@ import java.util.stream.Collectors; @ApiStatus.Experimental @ApiStatus.Internal public class Menu extends WidgetWithBounds implements LateRenderable { + public static final UUID SUBSETS = UUID.randomUUID(); + public static final UUID WEATHER = UUID.randomUUID(); + public static final UUID GAME_TYPE = UUID.randomUUID(); + public final Point menuStartPoint; private final List entries = Lists.newArrayList(); public final ScrollingContainer scrolling = new ScrollingContainer() { @@ -245,7 +249,7 @@ public class Menu extends WidgetWithBounds implements LateRenderable { public boolean mouseClicked(double mouseX, double mouseY, int button) { if (scrolling.updateDraggingState(mouseX, mouseY, button)) return true; - return super.mouseClicked(mouseX, mouseY, button); + return super.mouseClicked(mouseX, mouseY, button) || getInnerBounds().contains(mouseX, mouseY); } @Override diff --git a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/entries/EntryStackSubsetsMenuEntry.java b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/entries/EntryStackSubsetsMenuEntry.java index 48fc5b56e..3231c868b 100644 --- a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/entries/EntryStackSubsetsMenuEntry.java +++ b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/entries/EntryStackSubsetsMenuEntry.java @@ -31,7 +31,6 @@ import me.shedaniel.rei.api.*; import me.shedaniel.rei.gui.ContainerScreenOverlay; import me.shedaniel.rei.gui.modules.Menu; import me.shedaniel.rei.gui.modules.MenuEntry; -import me.shedaniel.rei.impl.EntryRegistryImpl; import me.shedaniel.rei.impl.ScreenHelper; import me.shedaniel.rei.utils.CollectionUtils; import net.minecraft.client.gui.components.events.GuiEventListener; @@ -102,7 +101,7 @@ public class EntryStackSubsetsMenuEntry extends MenuEntry { if (subsetsMenu != null) recalculateFilter(subsetsMenu); ConfigManager.getInstance().saveConfig(); - ((EntryRegistryImpl) EntryRegistry.getInstance()).refilter(); + EntryRegistry.getInstance().refilter(); if (ScreenHelper.getSearchField() != null) ContainerScreenOverlay.getEntryListWidget().updateSearch(ScreenHelper.getSearchField().getText(), true); } diff --git a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/entries/GameModeMenuEntry.java b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/entries/GameModeMenuEntry.java index 5df418ccc..1e8ee8569 100644 --- a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/entries/GameModeMenuEntry.java +++ b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/entries/GameModeMenuEntry.java @@ -100,7 +100,7 @@ public class GameModeMenuEntry extends MenuEntry { if (rendering && mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + 12) { Minecraft.getInstance().player.chat(ConfigObject.getInstance().getGamemodeCommand().replaceAll("\\{gamemode}", gameMode.name().toLowerCase(Locale.ROOT))); minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); - ScreenHelper.getLastOverlay().removeGameModeMenu(); + ScreenHelper.getLastOverlay().removeOverlayMenu(); return true; } return super.mouseClicked(mouseX, mouseY, button); diff --git a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/entries/SubSubsetsMenuEntry.java b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/entries/SubSubsetsMenuEntry.java index 09dc108e4..306e3e369 100644 --- a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/entries/SubSubsetsMenuEntry.java +++ b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/entries/SubSubsetsMenuEntry.java @@ -34,7 +34,6 @@ import me.shedaniel.rei.gui.ContainerScreenOverlay; import me.shedaniel.rei.gui.modules.Menu; import me.shedaniel.rei.gui.modules.MenuEntry; import me.shedaniel.rei.gui.widget.TabWidget; -import me.shedaniel.rei.impl.EntryRegistryImpl; import me.shedaniel.rei.impl.ScreenHelper; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.events.GuiEventListener; @@ -152,7 +151,7 @@ public class SubSubsetsMenuEntry extends MenuEntry { Menu subsetsMenu = ScreenHelper.getLastOverlay().getSubsetsMenu(); setFiltered(filteredStacks, subsetsMenu, this, !(getFilteredRatio() > 0)); ConfigManager.getInstance().saveConfig(); - ((EntryRegistryImpl) EntryRegistry.getInstance()).refilter(); + EntryRegistry.getInstance().refilter(); if (ScreenHelper.getSearchField() != null) ContainerScreenOverlay.getEntryListWidget().updateSearch(ScreenHelper.getSearchField().getText(), true); } else { diff --git a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/entries/WeatherMenuEntry.java b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/entries/WeatherMenuEntry.java index 3edd74ce9..957d9b8a1 100644 --- a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/entries/WeatherMenuEntry.java +++ b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/modules/entries/WeatherMenuEntry.java @@ -101,7 +101,7 @@ public class WeatherMenuEntry extends MenuEntry { if (rendering && mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + 12) { Minecraft.getInstance().player.chat(ConfigObject.getInstance().getWeatherCommand().replaceAll("\\{weather}", weather.name().toLowerCase(Locale.ROOT))); minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); - ScreenHelper.getLastOverlay().removeWeatherMenu(); + ScreenHelper.getLastOverlay().removeOverlayMenu(); return true; } return super.mouseClicked(mouseX, mouseY, button); diff --git a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/plugin/DefaultRuntimePlugin.java b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/plugin/DefaultRuntimePlugin.java index 9f3ff4995..71f6f8dfe 100644 --- a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/plugin/DefaultRuntimePlugin.java +++ b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/plugin/DefaultRuntimePlugin.java @@ -23,27 +23,38 @@ package me.shedaniel.rei.gui.plugin; +import com.google.gson.JsonObject; import com.mojang.blaze3d.vertex.PoseStack; import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.*; +import me.shedaniel.rei.api.favorites.FavoriteEntry; +import me.shedaniel.rei.api.favorites.FavoriteEntryType; import me.shedaniel.rei.api.plugins.REIPluginV0; import me.shedaniel.rei.api.widgets.Panel; import me.shedaniel.rei.api.widgets.Tooltip; +import me.shedaniel.rei.gui.ContainerScreenOverlay; import me.shedaniel.rei.gui.RecipeViewingScreen; import me.shedaniel.rei.gui.VillagerRecipeViewingScreen; +import me.shedaniel.rei.gui.widget.FavoritesListWidget; import me.shedaniel.rei.impl.ClientHelperImpl; import me.shedaniel.rei.impl.RenderingEntry; import me.shedaniel.rei.plugin.autocrafting.DefaultCategoryHandler; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.TextComponent; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.Item; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collections; +import java.util.function.Function; @ApiStatus.Internal @Environment(EnvType.CLIENT) @@ -87,6 +98,14 @@ public class DefaultRuntimePlugin implements REIPluginV0 { return Collections.emptyList(); return Collections.singletonList(widget.getBounds().clone()); }); + /*baseBoundsHandler.registerExclusionZones(Screen.class, () -> { + FavoritesListWidget widget = ContainerScreenOverlay.getFavoritesListWidget(); + if (widget != null) { + if (widget.favoritePanelButton.isVisible()) + return Collections.singletonList(widget.favoritePanelButton.bounds); + } + return Collections.emptyList(); + });*/ displayHelper.registerProvider(new DisplayHelper.DisplayBoundsProvider() { @Override public Rectangle getScreenBounds(RecipeViewingScreen screen) { @@ -97,6 +116,11 @@ public class DefaultRuntimePlugin implements REIPluginV0 { public Class getBaseSupportedClass() { return RecipeViewingScreen.class; } + + @Override + public InteractionResult shouldScreenBeOverlayed(Class screen) { + return InteractionResult.SUCCESS; + } }); displayHelper.registerProvider(new DisplayHelper.DisplayBoundsProvider() { @Override @@ -108,11 +132,111 @@ public class DefaultRuntimePlugin implements REIPluginV0 { public Class getBaseSupportedClass() { return VillagerRecipeViewingScreen.class; } + + @Override + public InteractionResult shouldScreenBeOverlayed(Class screen) { + return InteractionResult.SUCCESS; + } }); } @Override public void registerOthers(RecipeHelper recipeHelper) { recipeHelper.registerAutoCraftingHandler(new DefaultCategoryHandler()); + FavoriteEntryType.registry().register(EntryStackFavoriteType.INSTANCE.id, EntryStackFavoriteType.INSTANCE); + } + + private enum EntryStackFavoriteType implements FavoriteEntryType { + INSTANCE(FavoriteEntryType.ENTRY_STACK); + + private final String key = "data"; + private ResourceLocation id; + + EntryStackFavoriteType(ResourceLocation id) { + this.id = id; + } + + @Override + public @NotNull EntryStackFavoriteEntry fromJson(@NotNull JsonObject object) { + return new EntryStackFavoriteEntry(EntryStack.readFromJson(GsonHelper.getAsJsonObject(object, key))); + } + + @Override + public @NotNull EntryStackFavoriteEntry fromArgs(Object... args) { + return new EntryStackFavoriteEntry((EntryStack) args[0]); + } + + @Override + public @NotNull JsonObject toJson(@NotNull EntryStackFavoriteEntry entry, @NotNull JsonObject object) { + object.add(key, entry.stack.toJson()); + return object; + } + } + + private static class EntryStackFavoriteEntry extends FavoriteEntry { + private static final Function CANCEL_FLUID_AMOUNT = s -> null; + private final EntryStack stack; + private final int hashIgnoreAmount; + + public EntryStackFavoriteEntry(EntryStack stack) { + this.stack = stack.copy(); + this.stack.setAmount(127); + if (this.stack.getType() == EntryStack.Type.ITEM) + this.stack.setting(EntryStack.Settings.RENDER_COUNTS, EntryStack.Settings.FALSE); + else if (this.stack.getType() == EntryStack.Type.ITEM) + this.stack.setting(EntryStack.Settings.Fluid.AMOUNT_TOOLTIP, CANCEL_FLUID_AMOUNT); + this.hashIgnoreAmount = stack.hashIgnoreAmount(); + } + + @Override + public boolean isInvalid() { + return this.stack.isEmpty(); + } + + @Override + public EntryStack getWidget(boolean showcase) { + return this.stack; + } + + @Override + public boolean doAction(int button) { + if (!ClientHelper.getInstance().isCheating()) return false; + EntryStack entry = stack.copy(); + if (!entry.isEmpty()) { + if (entry.getType() == EntryStack.Type.FLUID) { + Item bucketItem = entry.getFluid().getBucket(); + if (bucketItem != null) { + entry = EntryStack.create(bucketItem); + } + } + if (entry.getType() == EntryStack.Type.ITEM) + entry.setAmount(button != 1 && !Screen.hasShiftDown() ? 1 : entry.getItemStack().getMaxStackSize()); + return ClientHelper.getInstance().tryCheatingEntry(entry); + } + + return false; + } + + @Override + public int hashIgnoreAmount() { + return hashIgnoreAmount; + } + + @Override + public FavoriteEntry copy() { + return new EntryStackFavoriteEntry(stack.copy()); + } + + @Override + public ResourceLocation getType() { + return EntryStackFavoriteType.INSTANCE.id; + } + + @Override + public boolean isSame(FavoriteEntry other) { + if (!(other instanceof EntryStackFavoriteEntry)) return false; + EntryStackFavoriteEntry that = (EntryStackFavoriteEntry) other; + return stack.equalsIgnoreAmount(that.stack); + } } } diff --git a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/widget/EntryListEntryWidget.java b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/widget/EntryListEntryWidget.java index f01e16d37..f9ed3a95b 100644 --- a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/widget/EntryListEntryWidget.java +++ b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/widget/EntryListEntryWidget.java @@ -31,7 +31,7 @@ import me.shedaniel.rei.api.EntryStack; import net.minecraft.client.gui.screens.Screen; import net.minecraft.world.item.Item; -public class EntryListEntryWidget extends EntryWidget { +public abstract class EntryListEntryWidget extends EntryWidget { public int backupY; protected EntryListEntryWidget(Point point, int entrySize) { @@ -58,21 +58,28 @@ public class EntryListEntryWidget extends EntryWidget { public boolean mouseReleased(double mouseX, double mouseY, int button) { if (!interactable) return super.mouseReleased(mouseX, mouseY, button); - if (containsMouse(mouseX, mouseY) && ClientHelper.getInstance().isCheating()) { - EntryStack entry = getCurrentEntry().copy(); - if (!entry.isEmpty() && wasClicked()) { - if (entry.getType() == EntryStack.Type.FLUID) { - Item bucketItem = entry.getFluid().getBucket(); - if (bucketItem != null) { - entry = EntryStack.create(bucketItem); - } + if (containsMouse(mouseX, mouseY) && wasClicked() && doAction(mouseX, mouseY, button)) { + return true; + } + return super.mouseReleased(mouseX, mouseY, button); + } + + protected boolean doAction(double mouseX, double mouseY, int button) { + if (!ClientHelper.getInstance().isCheating()) return false; + EntryStack entry = getCurrentEntry().copy(); + if (!entry.isEmpty()) { + if (entry.getType() == EntryStack.Type.FLUID) { + Item bucketItem = entry.getFluid().getBucket(); + if (bucketItem != null) { + entry = EntryStack.create(bucketItem); } - if (entry.getType() == EntryStack.Type.ITEM) - entry.setAmount(button != 1 && !Screen.hasShiftDown() ? 1 : entry.getItemStack().getMaxStackSize()); - return ClientHelper.getInstance().tryCheatingEntry(entry); } + if (entry.getType() == EntryStack.Type.ITEM) + entry.setAmount(button != 1 && !Screen.hasShiftDown() ? 1 : entry.getItemStack().getMaxStackSize()); + return ClientHelper.getInstance().tryCheatingEntry(entry); } - return super.mouseReleased(mouseX, mouseY, button); + + return false; } @Override diff --git a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java index 3142f4517..862439d65 100644 --- a/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java +++ b/RoughlyEnoughItems-runtime/src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java @@ -24,6 +24,7 @@ package me.shedaniel.rei.gui.widget; import com.google.common.base.Stopwatch; +import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.Tesselator; @@ -56,6 +57,8 @@ import net.minecraft.util.Mth; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.Item; +import org.apache.commons.lang3.mutable.MutableInt; +import org.apache.commons.lang3.mutable.MutableLong; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -187,24 +190,32 @@ public class EntryListWidget extends WidgetWithBounds { return Mth.ceil(allStacks.size() / (float) entries.size()); } - public static void renderEntries(boolean debugTime, int[] size, long[] time, boolean fastEntryRendering, PoseStack matrices, int mouseX, int mouseY, float delta, List entries) { - if (entries.isEmpty()) return; - EntryListEntryWidget firstWidget = entries.get(0); + public static void renderEntries(MutableInt size, MutableLong time, boolean fastEntryRendering, PoseStack matrices, int mouseX, int mouseY, float delta, Iterable entries) { + renderEntries(true, size, time, fastEntryRendering, matrices, mouseX, mouseY, delta, entries); + } + + public static void renderEntries(boolean fastEntryRendering, PoseStack matrices, int mouseX, int mouseY, float delta, Iterable entries) { + renderEntries(false, null, null, fastEntryRendering, matrices, mouseX, mouseY, delta, entries); + } + + public static void renderEntries(boolean debugTime, MutableInt size, MutableLong time, boolean fastEntryRendering, PoseStack matrices, int mouseX, int mouseY, float delta, Iterable entries) { + T firstWidget = Iterables.getFirst(entries, null); + if (firstWidget == null) return; EntryStack first = firstWidget.getCurrentEntry(); if (fastEntryRendering && first instanceof OptimalEntryStack) { OptimalEntryStack firstStack = (OptimalEntryStack) first; firstStack.optimisedRenderStart(matrices, delta); long l = debugTime ? System.nanoTime() : 0; MultiBufferSource.BufferSource immediate = Minecraft.getInstance().renderBuffers().bufferSource(); - for (EntryListEntryWidget listEntry : entries) { + for (T listEntry : entries) { EntryStack currentEntry = listEntry.getCurrentEntry(); currentEntry.setZ(100); listEntry.drawBackground(matrices, mouseX, mouseY, delta); ((OptimalEntryStack) currentEntry).optimisedRenderBase(matrices, immediate, listEntry.getInnerBounds(), mouseX, mouseY, delta); - if (debugTime && !currentEntry.isEmpty()) size[0]++; + if (debugTime && !currentEntry.isEmpty()) size.increment(); } immediate.endBatch(); - for (EntryListEntryWidget listEntry : entries) { + for (T listEntry : entries) { EntryStack currentEntry = listEntry.getCurrentEntry(); ((OptimalEntryStack) currentEntry).optimisedRenderOverlay(matrices, listEntry.getInnerBounds(), mouseX, mouseY, delta); if (listEntry.containsMouse(mouseX, mouseY)) { @@ -212,17 +223,17 @@ public class EntryListWidget extends WidgetWithBounds { listEntry.drawHighlighted(matrices, mouseX, mouseY, delta); } } - if (debugTime) time[0] += (System.nanoTime() - l); + if (debugTime) time.add(System.nanoTime() - l); firstStack.optimisedRenderEnd(matrices, delta); } else { - for (EntryListEntryWidget entry : entries) { + for (T entry : entries) { if (entry.getCurrentEntry().isEmpty()) continue; if (debugTime) { - size[0]++; + size.increment(); long l = System.nanoTime(); entry.render(matrices, mouseX, mouseY, delta); - time[0] += (System.nanoTime() - l); + time.add(System.nanoTime() - l); } else entry.render(matrices, mouseX, mouseY, delta); } } @@ -230,8 +241,8 @@ public class EntryListWidget extends WidgetWithBounds { @Override public void render(PoseStack matrices, int mouseX, int mouseY, float delta) { - int[] size = {0}; - long[] time = {0}; + MutableInt size = new MutableInt(); + MutableLong time = new MutableLong(); long totalTimeStart = debugTime ? System.nanoTime() : 0; boolean fastEntryRendering = ConfigObject.getInstance().doesFastEntryRendering(); if (ConfigObject.getInstance().isEntryListWidgetScrolled()) { @@ -262,9 +273,9 @@ public class EntryListWidget extends WidgetWithBounds { }).limit(Math.max(0, allStacks.size() - i[0])); if (fastEntryRendering) { - entryStream.collect(Collectors.groupingBy(entryListEntry -> OptimalEntryStack.groupingHashFrom(entryListEntry.getCurrentEntry()))).forEach((integer, entries) -> { - renderEntries(debugTime, size, time, fastEntryRendering, matrices, mouseX, mouseY, delta, (List) entries); - }); + for (List entries : entryStream.collect(Collectors.groupingBy(entryListEntry -> OptimalEntryStack.groupingHashFrom(entryListEntry.getCurrentEntry()))).values()) { + renderEntries(debugTime, size, time, fastEntryRendering, matrices, mouseX, mouseY, delta, entries); + } } else { renderEntries(debugTime, size, time, fastEntryRendering, matrices, mouseX, mouseY, delta, entryStream.collect(Collectors.toList())); } @@ -278,16 +289,16 @@ public class EntryListWidget extends WidgetWithBounds { } if (fastEntryRendering) { entries.stream().collect(Collectors.groupingBy(entryListEntry -> OptimalEntryStack.groupingHashFrom(entryListEntry.getCurrentEntry()))).forEach((integer, entries) -> { - renderEntries(debugTime, size, time, fastEntryRendering, matrices, mouseX, mouseY, delta, (List) entries); + renderEntries(debugTime, size, time, fastEntryRendering, matrices, mouseX, mouseY, delta, entries); }); } else { - renderEntries(debugTime, size, time, fastEntryRendering, matrices, mouseX, mouseY, delta, (List) entries); + renderEntries(debugTime, size, time, fast