aboutsummaryrefslogtreecommitdiff
path: root/runtime/src/main/java
diff options
context:
space:
mode:
authorshedaniel <daniel@shedaniel.me>2022-01-27 09:51:57 +0800
committershedaniel <daniel@shedaniel.me>2022-01-27 10:39:48 +0800
commit2961a0449da999a5b8198bd043b6bad26879667d (patch)
tree8c2e6aee249c18f3d3b812dcd4eb72443d887687 /runtime/src/main/java
parentd095053af792cc5b6368772a7c4e36914ca097f5 (diff)
downloadRoughlyEnoughItems-2961a0449da999a5b8198bd043b6bad26879667d.tar.gz
RoughlyEnoughItems-2961a0449da999a5b8198bd043b6bad26879667d.tar.bz2
RoughlyEnoughItems-2961a0449da999a5b8198bd043b6bad26879667d.zip
Close #724
- Sort displays so craftable ones are on the top - Add Ctrl+Click shortcut to move items immediately - Improve TransferHandler API to allow renderers even when it is "successful"
Diffstat (limited to 'runtime/src/main/java')
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/AutoCraftingEvaluator.java177
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryListWidget.java67
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/InternalWidgets.java141
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java87
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultCategoryHandler.java40
5 files changed, 337 insertions, 175 deletions
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/AutoCraftingEvaluator.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/AutoCraftingEvaluator.java
new file mode 100644
index 000000000..7cd3e3a93
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/AutoCraftingEvaluator.java
@@ -0,0 +1,177 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.widget;
+
+import me.shedaniel.math.Point;
+import me.shedaniel.rei.api.client.REIRuntime;
+import me.shedaniel.rei.api.client.gui.widgets.Tooltip;
+import me.shedaniel.rei.api.client.overlay.ScreenOverlay;
+import me.shedaniel.rei.api.client.registry.transfer.TransferHandler;
+import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry;
+import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRenderer;
+import me.shedaniel.rei.api.common.display.Display;
+import me.shedaniel.rei.api.common.util.CollectionUtils;
+import net.minecraft.ChatFormatting;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
+import net.minecraft.client.resources.language.I18n;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.MutableComponent;
+import net.minecraft.network.chat.TextComponent;
+import net.minecraft.network.chat.TranslatableComponent;
+import net.minecraft.resources.ResourceLocation;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+public class AutoCraftingEvaluator {
+ public static class AutoCraftingResult {
+ public int tint = 0;
+ public boolean successful = false;
+ public TransferHandler successfulHandler;
+ public boolean hasApplicable = false;
+ public TransferHandlerRenderer renderer;
+ public BiConsumer<Point, Consumer<Tooltip>> tooltipRenderer;
+ }
+
+ public static AutoCraftingResult evaluateAutoCrafting(boolean actuallyCrafting, boolean stackedCrafting, Display display, Supplier<Collection<ResourceLocation>> idsSupplier) {
+ AbstractContainerScreen<?> containerScreen = REIRuntime.getInstance().getPreviousContainerScreen();
+ AutoCraftingResult result = new AutoCraftingResult();
+ final List<Component> errorTooltip = new ArrayList<>();
+ result.tooltipRenderer = (pos, sink) -> {
+ List<Component> str = new ArrayList<>(errorTooltip);
+
+ if (Minecraft.getInstance().options.advancedItemTooltips && idsSupplier != null) {
+ Collection<ResourceLocation> locations = idsSupplier.get();
+ if (!locations.isEmpty()) {
+ str.add(new TextComponent(" "));
+ for (ResourceLocation location : locations) {
+ String t = I18n.get("text.rei.recipe_id", "", location.toString());
+ if (t.startsWith("\n")) {
+ t = t.substring("\n".length());
+ }
+ str.add(new TextComponent(t).withStyle(ChatFormatting.GRAY));
+ }
+ }
+ }
+
+ sink.accept(Tooltip.create(pos, str));
+ };
+
+ if (containerScreen == null) {
+ errorTooltip.add(new TranslatableComponent("error.rei.not.supported.move.items").withStyle(ChatFormatting.RED));
+ return result;
+ }
+
+ List<TransferHandler.Result> errors = new ArrayList<>();
+ TransferHandler.Context context = TransferHandler.Context.create(actuallyCrafting, stackedCrafting, containerScreen, display);
+
+ for (TransferHandler transferHandler : TransferHandlerRegistry.getInstance()) {
+ try {
+ TransferHandler.Result transferResult = transferHandler.handle(context);
+
+ if (transferResult.isBlocking() && actuallyCrafting) {
+ if (transferResult.isReturningToScreen()) {
+ Minecraft.getInstance().setScreen(containerScreen);
+ REIRuntime.getInstance().getOverlay().ifPresent(ScreenOverlay::queueReloadOverlay);
+ }
+
+ break;
+ }
+
+ if (transferResult.isApplicable()) {
+ result.hasApplicable = true;
+ result.tint = transferResult.getColor();
+
+ TransferHandlerRenderer transferHandlerRenderer = transferResult.getRenderer(transferHandler, context);
+ if (transferHandlerRenderer != null) {
+ result.renderer = transferHandlerRenderer;
+ }
+
+ if (transferResult.getTooltipRenderer() != null) {
+ BiConsumer<Point, TransferHandler.Result.TooltipSink> tooltipRenderer = transferResult.getTooltipRenderer();
+ result.tooltipRenderer = (point, tooltipConsumer) -> tooltipRenderer.accept(point, tooltipConsumer::accept);
+ }
+
+ if (transferResult.isSuccessful()) {
+ errors.clear();
+ result.successful = true;
+ result.successfulHandler = transferHandler;
+ result.renderer = null;
+ break;
+ }
+
+ errors.add(transferResult);
+
+ if (transferResult.isBlocking()) {
+ break;
+ }
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (!result.hasApplicable) {
+ errorTooltip.clear();
+ errorTooltip.add(new TranslatableComponent("error.rei.not.supported.move.items").withStyle(ChatFormatting.RED));
+ return result;
+ }
+
+ if (errors.isEmpty()) {
+ errorTooltip.clear();
+ errorTooltip.add(new TranslatableComponent("text.auto_craft.move_items"));
+ } else {
+ errorTooltip.clear();
+ List<Component> tooltipsFilled = new ArrayList<>();
+ for (TransferHandler.Result error : errors) {
+ error.fillTooltip(tooltipsFilled);
+ }
+
+ if (errors.size() == 1) {
+ for (Component tooltipFilled : tooltipsFilled) {
+ MutableComponent colored = tooltipFilled.copy().withStyle(ChatFormatting.RED);
+ if (!CollectionUtils.anyMatch(errorTooltip, ss -> ss.getString().equalsIgnoreCase(tooltipFilled.getString()))) {
+ errorTooltip.add(colored);
+ }
+ }
+ } else {
+ errorTooltip.add(new TranslatableComponent("error.rei.multi.errors").withStyle(ChatFormatting.RED));
+ for (Component tooltipFilled : tooltipsFilled) {
+ MutableComponent colored = new TextComponent("- ").withStyle(ChatFormatting.RED)
+ .append(tooltipFilled.copy().withStyle(ChatFormatting.RED));
+ if (!CollectionUtils.anyMatch(errorTooltip, ss -> ss.getString().equalsIgnoreCase(colored.getString()))) {
+ errorTooltip.add(colored);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryListWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryListWidget.java
index f8e58ed33..53029ff4b 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryListWidget.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryListWidget.java
@@ -52,8 +52,11 @@ import me.shedaniel.rei.api.client.gui.widgets.Widget;
import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds;
import me.shedaniel.rei.api.client.overlay.OverlayListWidget;
import me.shedaniel.rei.api.client.overlay.ScreenOverlay;
+import me.shedaniel.rei.api.client.registry.display.DisplayRegistry;
import me.shedaniel.rei.api.client.registry.screen.OverlayDecider;
import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry;
+import me.shedaniel.rei.api.client.registry.transfer.TransferHandler;
+import me.shedaniel.rei.api.common.display.Display;
import me.shedaniel.rei.api.common.entry.EntryStack;
import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes;
import me.shedaniel.rei.api.common.util.EntryStacks;
@@ -62,8 +65,11 @@ import me.shedaniel.rei.impl.client.config.ConfigManagerImpl;
import me.shedaniel.rei.impl.client.config.ConfigObjectImpl;
import me.shedaniel.rei.impl.client.gui.ScreenOverlayImpl;
import me.shedaniel.rei.impl.client.search.AsyncSearchManager;
+import me.shedaniel.rei.impl.client.view.ViewsImpl;
+import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
+import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.network.chat.Component;
@@ -76,10 +82,12 @@ import net.minecraft.world.item.ItemStack;
import org.apache.commons.lang3.mutable.MutableInt;
import org.apache.commons.lang3.mutable.MutableLong;
import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -257,7 +265,7 @@ public class EntryListWidget extends WidgetWithBounds implements OverlayListWidg
@Override
public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
if (!hasSpace()) return;
-
+
MutableInt size = new MutableInt();
MutableLong time = new MutableLong();
long totalTimeStart = debugTime ? System.nanoTime() : 0;
@@ -559,6 +567,9 @@ public class EntryListWidget extends WidgetWithBounds implements OverlayListWidg
}
private class EntryListEntry extends EntryListEntryWidget {
+ private Display display;
+ private Optional<TransferHandler> transferHandler;
+
private EntryListEntry(int x, int y, int entrySize) {
super(new Point(x, y), entrySize);
}
@@ -567,5 +578,59 @@ public class EntryListWidget extends WidgetWithBounds implements OverlayListWidg
public boolean containsMouse(double mouseX, double mouseY) {
return super.containsMouse(mouseX, mouseY) && containsChecked(mouseX, mouseY, true);
}
+
+ public TransferHandler getTransferHandler() {
+ for (List<Display> displays : DisplayRegistry.getInstance().getAll().values()) {
+ for (Display display : displays) {
+ if (ViewsImpl.isRecipesFor(getEntries(), display)) {
+ AutoCraftingEvaluator.AutoCraftingResult result = AutoCraftingEvaluator.evaluateAutoCrafting(false, false, display, null);
+ if (result.successful) {
+ this.display = display;
+ return result.successfulHandler;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ @Nullable
+ public Tooltip getCurrentTooltip(Point point) {
+ Tooltip tooltip = super.getCurrentTooltip(point);
+
+ if (tooltip != null && getTransferHandler() != null) {
+ tooltip.add(new TranslatableComponent("text.auto_craft.move_items.tooltip").withStyle(ChatFormatting.YELLOW));
+ }
+
+ return tooltip;
+ }
+
+ @Override
+ protected boolean doAction(double mouseX, double mouseY, int button) {
+ if (!ClientHelper.getInstance().isCheating() && !(Minecraft.getInstance().screen instanceof DisplayScreen) && Screen.hasControlDown()) {
+ try {
+ TransferHandler handler = getTransferHandler();
+
+ if (handler != null) {
+ AbstractContainerScreen<?> containerScreen = REIRuntime.getInstance().getPreviousContainerScreen();
+ TransferHandler.Context context = TransferHandler.Context.create(true, Screen.hasShiftDown() || button == 1, containerScreen, display);
+ TransferHandler.Result transferResult = handler.handle(context);
+
+ if (transferResult.isBlocking()) {
+ if (transferResult.isReturningToScreen() && Minecraft.getInstance().screen != containerScreen) {
+ Minecraft.getInstance().setScreen(containerScreen);
+ REIRuntime.getInstance().getOverlay().ifPresent(ScreenOverlay::queueReloadOverlay);
+ }
+ return true;
+ }
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+ return super.doAction(mouseX, mouseY, button);
+ }
}
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/InternalWidgets.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/InternalWidgets.java
index ce4f7d463..e39b48fc5 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/InternalWidgets.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/InternalWidgets.java
@@ -28,33 +28,25 @@ import com.mojang.blaze3d.vertex.PoseStack;
import me.shedaniel.math.Point;
import me.shedaniel.math.Rectangle;
import me.shedaniel.math.impl.PointHelper;
-import me.shedaniel.rei.api.client.REIRuntime;
import me.shedaniel.rei.api.client.config.ConfigObject;
import me.shedaniel.rei.api.client.gui.DrawableConsumer;
import me.shedaniel.rei.api.client.gui.widgets.*;
import me.shedaniel.rei.api.client.registry.display.DisplayCategory;
-import me.shedaniel.rei.api.client.registry.transfer.TransferHandler;
-import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerErrorRenderer;
-import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry;
import me.shedaniel.rei.api.common.display.Display;
-import me.shedaniel.rei.api.common.util.CollectionUtils;
import me.shedaniel.rei.impl.ClientInternals;
import me.shedaniel.rei.impl.client.gui.toast.CopyRecipeIdentifierToast;
import me.shedaniel.rei.impl.client.gui.widget.basewidgets.*;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
-import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.events.GuiEventListener;
-import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
+import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.resources.language.I18n;
-import net.minecraft.network.chat.*;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.FormattedText;
import net.minecraft.resources.ResourceLocation;
-import org.apache.commons.lang3.mutable.Mutable;
-import org.apache.commons.lang3.mutable.MutableObject;
import org.jetbrains.annotations.ApiStatus;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
@@ -66,44 +58,10 @@ public final class InternalWidgets {
private InternalWidgets() {}
public static Widget createAutoCraftingButtonWidget(Rectangle displayBounds, Rectangle rectangle, Component text, Supplier<Display> displaySupplier, Supplier<Collection<ResourceLocation>> idsSupplier, List<Widget> setupDisplay, DisplayCategory<?> category) {
- AbstractContainerScreen<?> containerScreen = REIRuntime.getInstance().getPreviousContainerScreen();
- Mutable<List<Component>> errorTooltip = new MutableObject<>(new ArrayList<>());
Button autoCraftingButton = Widgets.createButton(rectangle, text)
.focusable(false)
.onClick(button -> {
- TransferHandler.Context context = TransferHandler.Context.create(true, containerScreen, displaySupplier.get());
- for (TransferHandler autoTransferHandler : TransferHandlerRegistry.getInstance())
- try {
- TransferHandler.Result result = autoTransferHandler.handle(context);
- if (result.isBlocking()) {
- if (result.isReturningToScreen()) {
- break;
- }
- return;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- Minecraft.getInstance().setScreen(containerScreen);
- REIRuntime.getInstance().getOverlay().get().queueReloadOverlay();
- })
- .tooltipSupplier(button -> {
- List<Component> str = new ArrayList<>(errorTooltip.getValue());
-
- if (Minecraft.getInstance().options.advancedItemTooltips) {
- Collection<ResourceLocation> locations = idsSupplier.get();
- if (!locations.isEmpty()) {
- str.add(new TextComponent(" "));
- for (ResourceLocation location : locations) {
- String t = I18n.get("text.rei.recipe_id", "", location.toString());
- if (t.startsWith("\n")) {
- t = t.substring("\n".length());
- }
- str.add(new TextComponent(t).withStyle(ChatFormatting.GRAY));
- }
- }
- }
- return str.toArray(new Component[0]);
+ AutoCraftingEvaluator.evaluateAutoCrafting(true, Screen.hasShiftDown(), displaySupplier.get(), idsSupplier);
});
return new DelegateWidget(autoCraftingButton) {
boolean didJustRender = false;
@@ -111,85 +69,32 @@ public final class InternalWidgets {
@Override
public void render(PoseStack poses, int mouseX, int mouseY, float delta) {
didJustRender = false;
- autoCraftingButton.setEnabled(false);
- autoCraftingButton.setTint(0);
- if (containerScreen == null) {
- errorTooltip.setValue(Lists.newArrayList(new TranslatableComponent("error.rei.not.supported.move.items").withStyle(ChatFormatting.RED)));
- renderIf(false, poses, mouseX, mouseY, delta);
- return;
- }
+ AutoCraftingEvaluator.AutoCraftingResult result = AutoCraftingEvaluator.evaluateAutoCrafting(false, false, displaySupplier.get(), idsSupplier);
- List<TransferHandler.Result> errors = new ArrayList<>();
- boolean hasApplicable = false;
- TransferHandlerErrorRenderer errorRenderer = null;
- TransferHandler.Context context = TransferHandler.Context.create(false, containerScreen, displaySupplier.get());
- for (TransferHandler transferHandler : TransferHandlerRegistry.getInstance()) {
- try {
- TransferHandler.Result result = transferHandler.handle(context);
- if (result.isApplicable()) {
- hasApplicable = true;
- autoCraftingButton.setTint(result.getColor());
-
- if (result.isSuccessful()) {
- errors.clear();
- autoCraftingButton.setEnabled(true);
- errorRenderer = null;
- break;
- }
-
- errors.add(result);
- TransferHandlerErrorRenderer transferHandlerErrorRenderer = result.getErrorRenderer(transferHandler, context);
- if (transferHandlerErrorRenderer != null) {
- errorRenderer = transferHandlerErrorRenderer;
- }
-
- if (result.isBlocking()) {
- break;
- }
- }
- } catch (Throwable e) {
- e.printStackTrace();
- }
- }
+ autoCraftingButton.setEnabled(result.successful);
+ autoCraftingButton.setTint(result.tint);
- if (!hasApplicable) {
- errorTooltip.setValue(Lists.newArrayList(new TranslatableComponent("error.rei.not.supported.move.items").withStyle(ChatFormatting.RED)));
- renderIf(false, poses, mouseX, mouseY, delta);
- return;
+ if (result.hasApplicable && (containsMouse(mouseX, mouseY) || autoCraftingButton.isFocused()) && result.renderer != null) {
+ result.renderer.render(poses, mouseX, mouseY, delta, setupDisplay, displayBounds, displaySupplier.get());
}
- if ((containsMouse(mouseX, mouseY) || autoCraftingButton.isFocused()) && errorRenderer != null) {
- errorRenderer.render(poses, mouseX, mouseY, delta, setupDisplay, displayBounds, displaySupplier.get());
- }
- if (errors.isEmpty()) {
- errorTooltip.setValue(Lists.newArrayList(new TranslatableComponent("text.auto_craft.move_items")));
- } else {
- errorTooltip.setValue(Lists.newArrayList());
- List<Component> tooltipsFilled = new ArrayList<>();
- for (TransferHandler.Result error : errors) {
- error.fillTooltip(tooltipsFilled);
- }
-
- if (errors.size() == 1) {
- for (Component tooltipFilled : tooltipsFilled) {
- MutableComponent colored = tooltipFilled.copy().withStyle(ChatFormatting.RED);
- if (!CollectionUtils.anyMatch(errorTooltip.getValue(), ss -> ss.getString().equalsIgnoreCase(tooltipFilled.getString()))) {
- errorTooltip.getValue().add(colored);
- }
- }
- } else {
- errorTooltip.getValue().add(new TranslatableComponent("error.rei.multi.errors").withStyle(ChatFormatting.RED));
- for (Component tooltipFilled : tooltipsFilled) {
- MutableComponent colored = new TextComponent("- ").withStyle(ChatFormatting.RED)
- .append(tooltipFilled.copy().withStyle(ChatFormatting.RED));
- if (!CollectionUtils.anyMatch(errorTooltip.getValue(), ss -> ss.getString().equalsIgnoreCase(colored.getString()))) {
- errorTooltip.getValue().add(colored);
- }
- }
+ renderIf(result.hasApplicable, poses, mouseX, mouseY, delta);
+
+ if (didJustRender) {
+ if (!autoCraftingButton.isFocused() && containsMouse(mouseX, mouseY)) {
+ tryTooltip(result, new Point(mouseX, mouseY));
+ } else if (autoCraftingButton.isFocused()) {
+ Rectangle bounds = autoCraftingButton.getBounds();
+ tryTooltip(result, new Point(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2));
}
}
- renderIf(true, poses, mouseX, mouseY, delta);
+ }
+
+ private void tryTooltip(AutoCraftingEvaluator.AutoCraftingResult result, Point point) {
+ if (result.tooltipRenderer != null) {
+ result.tooltipRenderer.accept(point, Tooltip::queue);
+ }
}
private void renderIf(boolean should, PoseStack poseStack, int mouseX, int mouseY, float delta) {
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java
index cf5f765d3..fcfc17807 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java
@@ -24,6 +24,8 @@
package me.shedaniel.rei.impl.client.view;
import com.google.common.base.Stopwatch;
+import com.google.common.collect.AbstractIterator;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import me.shedaniel.rei.RoughlyEnoughItemsCore;
@@ -48,6 +50,7 @@ import me.shedaniel.rei.api.common.util.CollectionUtils;
import me.shedaniel.rei.api.common.util.EntryIngredients;
import me.shedaniel.rei.api.common.util.EntryStacks;
import me.shedaniel.rei.impl.client.gui.craftable.CraftableFilter;
+import me.shedaniel.rei.impl.client.gui.widget.AutoCraftingEvaluator;
import me.shedaniel.rei.impl.display.DisplaySpec;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
@@ -102,29 +105,15 @@ public class ViewsImpl implements Views {
for (Display display : allRecipesFromCategory) {
if (!displayRegistry.isDisplayVisible(display)) continue;
if (!recipesForStacks.isEmpty()) {
- back:
- for (List<? extends EntryStack<?>> results : display.getOutputEntries()) {
- for (EntryStack<?> otherEntry : results) {
- for (EntryStack<?> recipesFor : recipesForStacks) {
- if (EntryStacks.equalsFuzzy(otherEntry, recipesFor)) {
- set.add(display);
- break back;
- }
- }
- }
+ if (isRecipesFor(recipesForStacks, display)) {
+ set.add(display);
+ break;
}
}
if (!usagesForStacks.isEmpty()) {
- back:
- for (List<? extends EntryStack<?>> input : display.getInputEntries()) {
- for (EntryStack<?> otherEntry : input) {
- for (EntryStack<?> usagesFor : usagesForStacks) {
- if (EntryStacks.equalsFuzzy(otherEntry, usagesFor)) {
- set.add(display);
- break back;
- }
- }
- }
+ if (isUsagesFor(usagesForStacks, display)) {
+ set.add(display);
+ break;
}
}
}
@@ -220,7 +209,7 @@ public class ViewsImpl implements Views {
Map<Wrapped, Wrapped> wrappedSet = new LinkedHashMap<>();
List<Wrapped> wrappeds = new ArrayList<>();
- for (Display display : entry.getValue()) {
+ for (Display display : sortAutoCrafting(entry.getValue())) {
Wrapped wrapped = new Wrapped(display);
if (wrappedSet.containsKey(wrapped)) {
wrappedSet.get(wrapped).add(display);
@@ -245,6 +234,62 @@ public class ViewsImpl implements Views {
return resultSpeced;
}
+ public static boolean isRecipesFor(List<EntryStack<?>> stacks, Display display) {
+ return checkUsages(stacks, display, display.getOutputEntries());
+ }
+
+ public static boolean isUsagesFor(List<EntryStack<?>> stacks, Display display) {
+ return checkUsages(stacks, display, display.getInputEntries());
+ }
+
+ private static boolean checkUsages(List<EntryStack<?>> stacks, Display display, List<EntryIngredient> entries) {
+ for (List<? extends EntryStack<?>> results : entries) {
+ for (EntryStack<?> otherEntry : results) {
+ for (EntryStack<?> recipesFor : stacks) {
+ if (EntryStacks.equalsFuzzy(otherEntry, recipesFor)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static Iterable<Display> sortAutoCrafting(List<Display> displays) {
+ Set<Display> successfulDisplays = new LinkedHashSet<>();
+ Set<Display> applicableDisplays = new LinkedHashSet<>();
+
+ for (Display display : displays) {
+ AutoCraftingEvaluator.AutoCraftingResult result = AutoCraftingEvaluator.evaluateAutoCrafting(false, false, display, null);
+
+ if (result.successful) {
+ successfulDisplays.add(display);
+ } else if (result.hasApplicable) {
+ applicableDisplays.add(display);
+ }
+ }
+
+ return Iterables.concat(successfulDisplays, applicableDisplays, () -> new AbstractIterator<Display>() {
+ Iterator<Display> iterator = displays.iterator();
+
+ @Override
+ protected Display computeNext() {
+ while (iterator.hasNext()) {
+ Display next = iterator.next();
+
+ if (successfulDisplays.contains(next) || applicableDisplays.contains(next)) {
+ continue;
+ }
+
+ return next;
+ }
+
+ return endOfData();
+ }
+ });
+ }
+
private static <T extends Display> void generateLiveDisplays(DisplayRegistry displayRegistry, DynamicDisplayGenerator<T> generator, ViewSearchBuilder builder, Consumer<T> displayConsumer) {
for (EntryStack<?> stack : builder.getRecipesFor()) {
Optional<List<T>> recipeForDisplays = generator.getRecipeFor(stack);
diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultCategoryHandler.java b/runtime/src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultCategoryHandler.java
index 3441b32f2..371509d34 100644
--- a/runtime/src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultCategoryHandler.java
+++ b/runtime/src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultCategoryHandler.java
@@ -30,7 +30,6 @@ import it.unimi.dsi.fastutil.ints.IntList;
import me.shedaniel.rei.RoughlyEnoughItemsNetwork;
import me.shedaniel.rei.api.client.ClientHelper;
import me.shedaniel.rei.api.client.registry.transfer.TransferHandler;
-import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerErrorRenderer;
import me.shedaniel.rei.api.common.category.CategoryIdentifier;
import me.shedaniel.rei.api.common.display.Display;
import me.shedaniel.rei.api.common.transfer.RecipeFinder;
@@ -49,26 +48,11 @@ import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.item.ItemStack;
-import org.jetbrains.annotations.Nullable;
import java.util.List;
@Environment(EnvType.CLIENT)
public class DefaultCategoryHandler implements TransferHandler {
- private static class ErrorData {
- private MenuInfoContext<AbstractContainerMenu, Player, Display> menuInfoContext;
- private MenuInfo<AbstractContainerMenu, Display> menuInfo;
- private List<List<ItemStack>> inputs;
- private IntList intList;
-
- public ErrorData(MenuInfoContext<AbstractContainerMenu, Player, Display> menuInfoContext, MenuInfo<AbstractContainerMenu, Display> menuInfo, List<List<ItemStack>> inputs, IntList intList) {
- this.menuInfoContext = menuInfoContext;
- this.menuInfo = menuInfo;
- this.inputs = inputs;
- this.intList = intList;
- }
- }
-
@Override
public Result handle(Context context) {
Display display = context.getDisplay();
@@ -94,7 +78,10 @@ public class DefaultCategoryHandler implements TransferHandler {
List<List<ItemStack>> input = menuInfo.getInputs(menuInfoContext, false);
IntList intList = hasItems(menuInfoContext, menu, menuInfo, display, input);
if (!intList.isEmpty()) {
- return Result.createFailed(new TranslatableComponent("error.rei.not.enough.materials")).errorRenderer(new ErrorData(menuInfoContext, menuInfo, input, intList));
+ return Result.createFailed(new TranslatableComponent("error.rei.not.enough.materials"))
+ .renderer((matrices, mouseX, mouseY, delta, widgets, bounds, d) -> {
+ menuInfo.renderMissingInput(menuInfoContext, input, intList, matrices, mouseX, mouseY, delta, widgets, bounds);
+ });
}
if (!ClientHelper.getInstance().canUseMovePackets()) {
return Result.createFailed(new TranslatableComponent("error.rei.not.on.server"));
@@ -109,7 +96,7 @@ public class DefaultCategoryHandler implements TransferHandler {
}
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
buf.writeResourceLocation(display.getCategoryIdentifier().getIdentifier());
- buf.writeBoolean(Screen.hasShiftDown());
+ buf.writeBoolean(context.isStackedCrafting());
buf.writeNbt(menuInfo.save(menuInfoContext, display));
NetworkManager.sendToServer(RoughlyEnoughItemsNetwork.MOVE_ITEMS_PACKET, buf);
@@ -117,23 +104,6 @@ public class DefaultCategoryHandler implements TransferHandler {
}
@Override
- @Environment(EnvType.CLIENT)
- @Nullable
- public TransferHandlerErrorRenderer provideErrorRenderer(Context context, Object data) {