Ver código fonte

Fix #370 and changes to how screens are handled

Signed-off-by: shedaniel <daniel@shedaniel.me>
shedaniel 5 anos atrás
pai
commit
17a5079c79

+ 1 - 1
gradle.properties

@@ -1,5 +1,5 @@
 org.gradle.jvmargs=-Xmx3G
-mod_version=4.6.6
+mod_version=4.7.0
 supported_version=1.16.x
 minecraft_version=1.16.1
 yarn_version=1.16.1+build.4+legacy.20w09a+build.8

+ 3 - 3
src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java

@@ -72,8 +72,10 @@ public class RoughlyEnoughItemsNetwork implements ModInitializer {
                     player.addMessage(new TranslatableText("text.rei.no_permission_cheat").formatted(Formatting.RED), false);
                     return;
                 }
-                if (!player.inventory.getCursorStack().isEmpty())
+                if (!player.inventory.getCursorStack().isEmpty()) {
                     player.inventory.setCursorStack(ItemStack.EMPTY);
+                    player.updateCursorStack();
+                }
             });
             ServerSidePacketRegistry.INSTANCE.register(CREATE_ITEMS_PACKET, (packetContext, packetByteBuf) -> {
                 ServerPlayerEntity player = (ServerPlayerEntity) packetContext.getPlayer();
@@ -100,8 +102,6 @@ public class RoughlyEnoughItemsNetwork implements ModInitializer {
                 if (!inventory.getCursorStack().isEmpty() && ItemStack.areItemsEqual(inventory.getCursorStack(), stack) && ItemStack.areTagsEqual(inventory.getCursorStack(), stack)) {
                     stack.setCount(MathHelper.clamp(stack.getCount() + inventory.getCursorStack().getCount(), 1, stack.getMaxCount()));
                 } else if (!inventory.getCursorStack().isEmpty()) {
-                    inventory.setCursorStack(ItemStack.EMPTY);
-                    player.updateCursorStack();
                     return;
                 }
                 inventory.setCursorStack(stack.copy());

+ 4 - 1
src/main/java/me/shedaniel/rei/api/BaseBoundsHandler.java

@@ -25,12 +25,15 @@ package me.shedaniel.rei.api;
 
 import me.shedaniel.math.Rectangle;
 import me.shedaniel.rei.impl.DisplayHelperImpl;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
 import net.minecraft.client.gui.screen.Screen;
 
 import java.util.List;
 import java.util.function.Supplier;
 
-public interface BaseBoundsHandler extends DisplayHelper.DisplayBoundsHandler<Screen> {
+@Environment(EnvType.CLIENT)
+public interface BaseBoundsHandler extends OverlayDecider {
     
     static BaseBoundsHandler getInstance() {
         return ((DisplayHelperImpl) DisplayHelper.getInstance()).getBaseBoundsHandler();

+ 6 - 5
src/main/java/me/shedaniel/rei/api/ConfigObject.java

@@ -24,10 +24,7 @@
 package me.shedaniel.rei.api;
 
 import me.shedaniel.clothconfig2.api.ModifierKeyCode;
-import me.shedaniel.rei.gui.config.EntryPanelOrdering;
-import me.shedaniel.rei.gui.config.RecipeBorderType;
-import me.shedaniel.rei.gui.config.RecipeScreenType;
-import me.shedaniel.rei.gui.config.SearchFieldLocation;
+import me.shedaniel.rei.gui.config.*;
 import me.shedaniel.rei.impl.ConfigManagerImpl;
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
@@ -77,7 +74,11 @@ public interface ConfigObject {
     
     SearchFieldLocation getSearchFieldLocation();
     
-    boolean isLeftHandSidePanel();
+    default boolean isLeftHandSidePanel() {
+        return getDisplayPanelLocation() == DisplayPanelLocation.LEFT;
+    }
+    
+    DisplayPanelLocation getDisplayPanelLocation();
     
     boolean isCraftableFilterEnabled();
     

+ 64 - 19
src/main/java/me/shedaniel/rei/api/DisplayHelper.java

@@ -25,14 +25,19 @@ package me.shedaniel.rei.api;
 
 import me.shedaniel.math.Rectangle;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
+import me.shedaniel.rei.gui.config.DisplayPanelLocation;
 import me.shedaniel.rei.gui.config.SearchFieldLocation;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
 import net.minecraft.util.ActionResult;
+import org.jetbrains.annotations.ApiStatus;
 
 import java.util.List;
 import java.util.function.Supplier;
 
 import static net.minecraft.util.ActionResult.PASS;
 
+@Environment(EnvType.CLIENT)
 public interface DisplayHelper {
     
     /**
@@ -49,8 +54,12 @@ public interface DisplayHelper {
      * @return the sorted list of responsible bounds handlers
      * @see DisplayHelper#getResponsibleBoundsHandler(Class) for the unsorted version
      */
+    @Deprecated
+    @ApiStatus.ScheduledForRemoval
     List<DisplayBoundsHandler<?>> getSortedBoundsHandlers(Class<?> screenClass);
     
+    List<OverlayDecider> getSortedOverlayDeciders(Class<?> screenClass);
+    
     /**
      * Gets all registered overlay deciders
      *
@@ -59,12 +68,14 @@ public interface DisplayHelper {
     List<OverlayDecider> getAllOverlayDeciders();
     
     /**
-     * Gets all responsible bounds handlers
+     * Gets the responsible bounds handlers
      *
      * @param screenClass the class for checking responsible bounds handlers
      * @return the the list of responsible bounds handlers
      * @see DisplayHelper#getSortedBoundsHandlers(Class) for the sorted version
      */
+    @Deprecated
+    @ApiStatus.ScheduledForRemoval
     DisplayBoundsHandler<?> getResponsibleBoundsHandler(Class<?> screenClass);
     
     /**
@@ -74,6 +85,40 @@ public interface DisplayHelper {
      */
     void registerHandler(OverlayDecider decider);
     
+    default <T> void registerProvider(DisplayBoundsProvider<T> provider) {
+        registerHandler(provider);
+    }
+    
+    /**
+     * Gets the left bounds of the overlay
+     *
+     * @param screen the current screen
+     * @return the left bounds
+     */
+    <T> Rectangle getOverlayBounds(DisplayPanelLocation location, T screen);
+    
+    interface DisplayBoundsProvider<T> extends OverlayDecider {
+        /**
+         * @param screen the screen
+         * @return the boundary of the base container panel.
+         */
+        Rectangle getScreenBounds(T screen);
+        
+        /**
+         * Gets the base supported class for the bounds handler
+         *
+         * @return the base class
+         */
+        Class<?> getBaseSupportedClass();
+        
+        @Override
+        default boolean isHandingScreen(Class<?> screen) {
+            return getBaseSupportedClass().isAssignableFrom(screen);
+        }
+    }
+    
+    @Deprecated
+    @ApiStatus.ScheduledForRemoval
     interface DisplayBoundsHandler<T> extends OverlayDecider {
         /**
          * Gets the base supported class for the bounds handler
@@ -114,18 +159,20 @@ public interface DisplayHelper {
          * @see BaseBoundsHandler#registerExclusionZones(Class, Supplier) for easier api
          */
         default ActionResult canItemSlotWidgetFit(int left, int top, T screen, Rectangle fullBounds) {
+            ActionResult fit = isInZone(left, top);
+            if (fit == ActionResult.FAIL)
+                return ActionResult.FAIL;
+            ActionResult fit2 = isInZone(left + 18, top + 18);
+            if (fit2 == ActionResult.FAIL)
+                return ActionResult.FAIL;
+            if (fit == ActionResult.SUCCESS && fit2 == ActionResult.SUCCESS)
+                return ActionResult.SUCCESS;
             return PASS;
         }
         
-        /**
-         * Checks if mouse is inside the overlay
-         *
-         * @param mouseX mouse's x coordinates
-         * @param mouseY mouse's y coordinates
-         * @return whether mouse is inside the overlay
-         */
+        @Override
         default ActionResult isInZone(double mouseX, double mouseY) {
-            return PASS;
+            return OverlayDecider.super.isInZone(mouseX, mouseY);
         }
         
         /**
@@ -143,26 +190,24 @@ public interface DisplayHelper {
             return new Rectangle(rectangle.x + 1, rectangle.y + 2 + offset, rectangle.width - 2, rectangle.height - 5 - offset);
         }
         
-        /**
-         * Checks if REI should recalculate the overlay bounds
-         *
-         * @param isOnRightSide whether the user has set the overlay to the right
-         * @param rectangle     the current overlay bounds
-         * @return whether REI should recalculate the overlay bounds
-         */
+        @Deprecated
+        @ApiStatus.ScheduledForRemoval
         default boolean shouldRecalculateArea(boolean isOnRightSide, Rectangle rectangle) {
             return false;
         }
         
+        @Override
+        default boolean shouldRecalculateArea(DisplayPanelLocation location, Rectangle rectangle) {
+            return shouldRecalculateArea(location == DisplayPanelLocation.RIGHT, rectangle);
+        }
+        
         /**
          * Gets the priority of the handler, the higher it is, the earlier it is called.
          *
          * @return the priority in float
          */
         @Override
-        default float getPriority() {
-            return 0f;
-        }
+        float getPriority();
     }
     
 }

+ 26 - 0
src/main/java/me/shedaniel/rei/api/OverlayDecider.java

@@ -23,8 +23,12 @@
 
 package me.shedaniel.rei.api;
 
+import me.shedaniel.math.Rectangle;
+import me.shedaniel.rei.gui.config.DisplayPanelLocation;
 import net.minecraft.util.ActionResult;
 
+import static net.minecraft.util.ActionResult.PASS;
+
 public interface OverlayDecider {
     boolean isHandingScreen(Class<?> screen);
     
@@ -40,4 +44,26 @@ public interface OverlayDecider {
     default float getPriority() {
         return 0f;
     }
+    
+    /**
+     * Checks if REI should recalculate the overlay bounds
+     *
+     * @param location  the location of the display panel
+     * @param rectangle the current overlay bounds
+     * @return whether REI should recalculate the overlay bounds
+     */
+    default boolean shouldRecalculateArea(DisplayPanelLocation location, Rectangle rectangle) {
+        return false;
+    }
+    
+    /**
+     * Checks if mouse is inside the overlay
+     *
+     * @param mouseX mouse's x coordinates
+     * @param mouseY mouse's y coordinates
+     * @return whether mouse is inside the overlay
+     */
+    default ActionResult isInZone(double mouseX, double mouseY) {
+        return PASS;
+    }
 }

+ 3 - 0
src/main/java/me/shedaniel/rei/api/REIHelper.java

@@ -26,12 +26,15 @@ package me.shedaniel.rei.api;
 import me.shedaniel.rei.api.widgets.Tooltip;
 import me.shedaniel.rei.gui.widget.TextFieldWidget;
 import me.shedaniel.rei.impl.ScreenHelper;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
 import net.minecraft.client.gui.screen.ingame.ContainerScreen;
 import net.minecraft.item.ItemStack;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.List;
 
+@Environment(EnvType.CLIENT)
 public interface REIHelper {
     
     /**

+ 3 - 0
src/main/java/me/shedaniel/rei/api/RecipeHelper.java

@@ -25,6 +25,8 @@ package me.shedaniel.rei.api;
 
 import me.shedaniel.math.Rectangle;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
 import net.minecraft.client.gui.screen.ingame.ContainerScreen;
 import net.minecraft.recipe.Recipe;
 import net.minecraft.recipe.RecipeManager;
@@ -37,6 +39,7 @@ import java.util.Optional;
 import java.util.function.Function;
 import java.util.function.Predicate;
 
+@Environment(EnvType.CLIENT)
 public interface RecipeHelper {
     
     /**

+ 12 - 16
src/main/java/me/shedaniel/rei/gui/ContainerScreenOverlay.java

@@ -186,16 +186,14 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
         this.renderWeatherMenu = false;
         this.weatherButton = null;
         this.window = MinecraftClient.getInstance().getWindow();
-        @SuppressWarnings({"RawTypeCanBeGeneric", "rawtypes"})
-        DisplayHelper.DisplayBoundsHandler boundsHandler = DisplayHelper.getInstance().getResponsibleBoundsHandler(MinecraftClient.getInstance().currentScreen.getClass());
-        this.bounds = ConfigObject.getInstance().isLeftHandSidePanel() ? boundsHandler.getLeftBounds(MinecraftClient.getInstance().currentScreen) : boundsHandler.getRightBounds(MinecraftClient.getInstance().currentScreen);
+        this.bounds = DisplayHelper.getInstance().getOverlayBounds(ConfigObject.getInstance().getDisplayPanelLocation(), MinecraftClient.getInstance().currentScreen);
         widgets.add(ENTRY_LIST_WIDGET);
         if (ConfigObject.getInstance().isFavoritesEnabled()) {
             if (favoritesListWidget == null)
                 favoritesListWidget = new FavoritesListWidget();
             widgets.add(favoritesListWidget);
         }
-        ENTRY_LIST_WIDGET.updateArea(boundsHandler, ScreenHelper.getSearchField() == null ? "" : null);
+        ENTRY_LIST_WIDGET.updateArea(ScreenHelper.getSearchField() == null ? "" : null);
         if (ScreenHelper.getSearchField() == null) {
             ScreenHelper.setSearchField(new OverlaySearchField(0, 0, 0, 0));
         }
@@ -437,15 +435,13 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
             return new Rectangle(bounds.x + 2, window.getScaledHeight() - 22, bounds.width - 6 - widthRemoved, 18);
         if (searchFieldLocation == SearchFieldLocation.TOP_SIDE)
             return new Rectangle(bounds.x + 2, 4, bounds.width - 6 - widthRemoved, 18);
-        if (MinecraftClient.getInstance().currentScreen instanceof RecipeViewingScreen) {
-            RecipeViewingScreen widget = (RecipeViewingScreen) MinecraftClient.getInstance().currentScreen;
-            return new Rectangle(widget.getBounds().x, window.getScaledHeight() - 22, widget.getBounds().width - widthRemoved, 18);
-        }
-        if (MinecraftClient.getInstance().currentScreen instanceof VillagerRecipeViewingScreen) {
-            VillagerRecipeViewingScreen widget = (VillagerRecipeViewingScreen) MinecraftClient.getInstance().currentScreen;
-            return new Rectangle(widget.bounds.x, window.getScaledHeight() - 22, widget.bounds.width - widthRemoved, 18);
+        for (OverlayDecider decider : DisplayHelper.getInstance().getSortedOverlayDeciders(MinecraftClient.getInstance().currentScreen.getClass())) {
+            if (decider instanceof DisplayHelper.DisplayBoundsProvider) {
+                Rectangle containerBounds = ((DisplayHelper.DisplayBoundsProvider<Screen>) decider).getScreenBounds(MinecraftClient.getInstance().currentScreen);
+                return new Rectangle(containerBounds.x, window.getScaledHeight() - 22, containerBounds.width - widthRemoved, 18);
+            }
         }
-        return new Rectangle(REIHelper.getInstance().getPreviousContainerScreen().x, window.getScaledHeight() - 22, REIHelper.getInstance().getPreviousContainerScreen().containerWidth - widthRemoved, 18);
+        return new Rectangle();
     }
     
     private Rectangle getCraftableToggleArea() {
@@ -482,8 +478,8 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
             ENTRY_LIST_WIDGET.updateSearch(ScreenHelper.getSearchField().getText(), true);
             init();
         } else {
-            for (DisplayHelper.DisplayBoundsHandler<?> handler : DisplayHelper.getInstance().getSortedBoundsHandlers(minecraft.currentScreen.getClass())) {
-                if (handler != null && handler.shouldRecalculateArea(!ConfigObject.getInstance().isLeftHandSidePanel(), bounds)) {
+            for (OverlayDecider decider : DisplayHelper.getInstance().getSortedOverlayDeciders(minecraft.currentScreen.getClass())) {
+                if (decider != null && decider.shouldRecalculateArea(ConfigObject.getInstance().getDisplayPanelLocation(), bounds)) {
                     init();
                     break;
                 }
@@ -760,8 +756,8 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
     }
     
     public boolean isNotInExclusionZones(double mouseX, double mouseY) {
-        for (DisplayHelper.DisplayBoundsHandler<?> handler : DisplayHelper.getInstance().getSortedBoundsHandlers(MinecraftClient.getInstance().currentScreen.getClass())) {
-            ActionResult in = handler.isInZone(mouseX, mouseY);
+        for (OverlayDecider decider : DisplayHelper.getInstance().getSortedOverlayDeciders(MinecraftClient.getInstance().currentScreen.getClass())) {
+            ActionResult in = decider.isInZone(mouseX, mouseY);
             if (in != ActionResult.PASS)
                 return in == ActionResult.SUCCESS;
         }

+ 10 - 2
src/main/java/me/shedaniel/rei/gui/RecipeViewingScreen.java

@@ -57,14 +57,16 @@ import net.minecraft.sound.SoundEvents;
 import net.minecraft.text.LiteralText;
 import net.minecraft.text.Text;
 import net.minecraft.text.TranslatableText;
-import net.minecraft.util.Formatting;
 import net.minecraft.util.Identifier;
 import net.minecraft.util.math.MathHelper;
 import net.minecraft.util.math.Matrix4f;
 import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.*;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 import java.util.function.Supplier;
 
 @ApiStatus.Internal
@@ -497,6 +499,9 @@ public class RecipeViewingScreen extends Screen implements RecipeScreen {
         if (choosePageActivated) {
             return recipeChoosePageWidget.mouseDragged(double_1, double_2, int_1, double_3, double_4);
         }
+        for (Element entry : children())
+            if (entry.mouseDragged(double_1, double_2, int_1, double_3, double_4))
+                return true;
         return super.mouseDragged(double_1, double_2, int_1, double_3, double_4);
     }
     
@@ -505,6 +510,9 @@ public class RecipeViewingScreen extends Screen implements RecipeScreen {
         if (choosePageActivated) {
             return recipeChoosePageWidget.mouseReleased(double_1, double_2, int_1);
         }
+        for (Element entry : children())
+            if (entry.mouseReleased(double_1, double_2, int_1))
+                return true;
         return super.mouseReleased(double_1, double_2, int_1);
     }
     

+ 18 - 0
src/main/java/me/shedaniel/rei/gui/VillagerRecipeViewingScreen.java

@@ -258,6 +258,13 @@ public class VillagerRecipeViewingScreen extends Screen implements RecipeScreen
             scrollBarAlpha = 1;
             return true;
         }
+        for (Element entry : children())
+            if (entry.mouseClicked(mouseX, mouseY, int_1)) {
+                setFocused(entry);
+                if (int_1 == 0)
+                    setDragging(true);
+                return true;
+            }
         return super.mouseClicked(mouseX, mouseY, int_1);
     }
     
@@ -353,6 +360,14 @@ public class VillagerRecipeViewingScreen extends Screen implements RecipeScreen
         ScreenHelper.getLastOverlay().lateRender(matrices, mouseX, mouseY, delta);
     }
     
+    @Override
+    public boolean mouseReleased(double double_1, double double_2, int int_1) {
+        for (Element entry : children())
+            if (entry.mouseReleased(double_1, double_2, int_1))
+                return true;
+        return super.mouseReleased(double_1, double_2, int_1);
+    }
+    
     @Override
     public boolean mouseDragged(double mouseX, double mouseY, int int_1, double double_3, double double_4) {
         if (scrolling.mouseDragged(mouseX, mouseY, int_1, double_3, double_4)) {
@@ -360,6 +375,9 @@ public class VillagerRecipeViewingScreen extends Screen implements RecipeScreen
             scrollBarAlphaFuture = 1f;
             return true;
         }
+        for (Element entry : children())
+            if (entry.mouseDragged(mouseX, mouseY, int_1, double_3, double_4))
+                return true;
         return super.mouseDragged(mouseX, mouseY, int_1, double_3, double_4);
     }
     

+ 8 - 0
src/main/java/me/shedaniel/rei/gui/config/DisplayPanelLocation.java

@@ -24,15 +24,23 @@
 package me.shedaniel.rei.gui.config;
 
 import me.shedaniel.clothconfig2.gui.entries.SelectionListEntry;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
 import net.minecraft.client.resource.language.I18n;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.Locale;
 
+@Environment(EnvType.CLIENT)
 public enum DisplayPanelLocation implements SelectionListEntry.Translatable {
     LEFT,
     RIGHT;
     
+    public DisplayPanelLocation mirror() {
+        if (this == LEFT) return RIGHT;
+        return LEFT;
+    }
+    
     @Override
     public @NotNull String getKey() {
         return I18n.translate("config.roughlyenoughitems.accessibility.displayPanelLocation." + name().toLowerCase(Locale.ROOT));

+ 11 - 7
src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java

@@ -105,13 +105,17 @@ public class EntryListWidget extends WidgetWithBounds {
         return MathHelper.ceil(SIZE * ConfigObject.getInstance().getEntrySize());
     }
     
-    @SuppressWarnings("rawtypes")
     static boolean notSteppingOnExclusionZones(int left, int top, Rectangle listArea) {
         MinecraftClient instance = MinecraftClient.getInstance();
-        for (DisplayHelper.DisplayBoundsHandler sortedBoundsHandler : DisplayHelper.getInstance().getSortedBoundsHandlers(instance.currentScreen.getClass())) {
-            ActionResult fit = sortedBoundsHandler.canItemSlotWidgetFit(left, top, instance.currentScreen, listArea);
-            if (fit != ActionResult.PASS)
+        for (OverlayDecider decider : DisplayHelper.getInstance().getSortedOverlayDeciders(instance.currentScreen.getClass())) {
+            ActionResult fit = decider.isInZone(left, top);
+            if (fit == ActionResult.FAIL)
                 return fit == ActionResult.SUCCESS;
+            ActionResult fit2 = decider.isInZone(left + 18, top + 18);
+            if (fit2 == ActionResult.FAIL)
+                return fit == ActionResult.SUCCESS;
+            if (fit == ActionResult.SUCCESS && fit2 == ActionResult.SUCCESS)
+                return true;
         }
         return true;
     }
@@ -410,11 +414,11 @@ public class EntryListWidget extends WidgetWithBounds {
         return false;
     }
     
-    public void updateArea(DisplayHelper.DisplayBoundsHandler<?> boundsHandler, @Nullable String searchTerm) {
-        this.bounds = boundsHandler.getItemListArea(ScreenHelper.getLastOverlay().getBounds());
+    public void updateArea(@Nullable String searchTerm) {
+        this.bounds = ScreenHelper.getItemListArea(ScreenHelper.getLastOverlay().getBounds());
         FavoritesListWidget favoritesListWidget = ContainerScreenOverlay.getFavoritesListWidget();
         if (favoritesListWidget != null)
-            favoritesListWidget.updateFavoritesBounds(boundsHandler, searchTerm);
+            favoritesListWidget.updateFavoritesBounds(searchTerm);
         if (searchTerm != null)
             updateSearch(searchTerm, true);
         else if (allStacks == null || (favoritesListWidget != null && favoritesListWidget.favorites == null))

+ 2 - 3
src/main/java/me/shedaniel/rei/gui/widget/FavoritesListWidget.java

@@ -179,9 +179,8 @@ public class FavoritesListWidget extends WidgetWithBounds {
         return false;
     }
     
-    @SuppressWarnings("rawtypes")
-    public void updateFavoritesBounds(DisplayHelper.DisplayBoundsHandler boundsHandler, @Nullable String searchTerm) {
-        this.bounds = boundsHandler.getFavoritesListArea(!ConfigObject.getInstance().isLeftHandSidePanel() ? boundsHandler.getLeftBounds(MinecraftClient.getInstance().currentScreen) : boundsHandler.getRightBounds(MinecraftClient.getInstance().currentScreen));
+    public void updateFavoritesBounds(@Nullable String searchTerm) {
+        this.bounds = ScreenHelper.getFavoritesListArea(DisplayHelper.getInstance().getOverlayBounds(ConfigObject.getInstance().getDisplayPanelLocation().mirror(), MinecraftClient.getInstance().currentScreen));
     }
     
     public void updateSearch(EntryListWidget listWidget, String searchTerm) {

+ 10 - 30
src/main/java/me/shedaniel/rei/impl/BaseBoundsHandlerImpl.java

@@ -27,6 +27,9 @@ import com.google.common.collect.Lists;
 import me.shedaniel.math.Rectangle;
 import me.shedaniel.rei.api.BaseBoundsHandler;
 import me.shedaniel.rei.api.DisplayHelper;
+import me.shedaniel.rei.gui.config.DisplayPanelLocation;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.gui.screen.Screen;
 import net.minecraft.util.ActionResult;
@@ -38,6 +41,7 @@ import java.util.List;
 import java.util.function.Supplier;
 
 @ApiStatus.Internal
+@Environment(EnvType.CLIENT)
 public class BaseBoundsHandlerImpl implements BaseBoundsHandler {
     
     private static final Comparator<? super Rectangle> RECTANGLE_COMPARER = Comparator.comparingLong(Rectangle::hashCode);
@@ -46,18 +50,8 @@ public class BaseBoundsHandlerImpl implements BaseBoundsHandler {
     private List<Pair<Pair<Class<?>, Float>, Supplier<List<Rectangle>>>> list = Lists.newArrayList();
     
     @Override
-    public Class<?> getBaseSupportedClass() {
-        return Screen.class;
-    }
-    
-    @Override
-    public Rectangle getLeftBounds(Screen screen) {
-        return new Rectangle();
-    }
-    
-    @Override
-    public Rectangle getRightBounds(Screen screen) {
-        return new Rectangle();
+    public boolean isHandingScreen(Class<?> screen) {
+        return Screen.class.isAssignableFrom(screen);
     }
     
     @Override
@@ -78,30 +72,16 @@ public class BaseBoundsHandlerImpl implements BaseBoundsHandler {
     }
     
     @Override
-    public boolean shouldRecalculateArea(boolean isOnRightSide, Rectangle rectangle) {
-        long current = currentHashCode(isOnRightSide);
+    public boolean shouldRecalculateArea(DisplayPanelLocation location, Rectangle rectangle) {
+        long current = currentHashCode(location);
         if (lastArea == current)
             return false;
         lastArea = current;
         return true;
     }
     
-    private long currentHashCode(boolean isOnRightSide) {
-        DisplayHelper.DisplayBoundsHandler<Screen> handler = (DisplayHelper.DisplayBoundsHandler<Screen>) DisplayHelper.getInstance().getResponsibleBoundsHandler(MinecraftClient.getInstance().currentScreen.getClass());
-        return areasHashCode(isOnRightSide ? handler.getRightBounds(MinecraftClient.getInstance().currentScreen) : handler.getLeftBounds(MinecraftClient.getInstance().currentScreen), getExclusionZones(MinecraftClient.getInstance().currentScreen.getClass(), false));
-    }
-    
-    @Override
-    public ActionResult canItemSlotWidgetFit(int left, int top, Screen screen, Rectangle fullBounds) {
-        Class<? extends Screen> screenClass = screen.getClass();
-        for (Pair<Pair<Class<?>, Float>, Supplier<List<Rectangle>>> pair : list) {
-            if (pair.getLeft().getLeft().isAssignableFrom(screenClass))
-                for (Rectangle zone : pair.getRight().get()) {
-                    if (left + 18 >= zone.x && top + 18 >= zone.y && left <= zone.getMaxX() && top <= zone.getMaxY())
-                        return ActionResult.FAIL;
-                }
-        }
-        return ActionResult.PASS;
+    private long currentHashCode(DisplayPanelLocation location) {
+        return areasHashCode(DisplayHelper.getInstance().getOverlayBounds(location, MinecraftClient.getInstance().currentScreen), getExclusionZones(MinecraftClient.getInstance().currentScreen.getClass(), false));
     }
     
     @Override

+ 5 - 0
src/main/java/me/shedaniel/rei/impl/ClientHelperImpl.java

@@ -170,6 +170,11 @@ public class ClientHelperImpl implements ClientHelper, ClientModInitializer {
             inventory.setCursorStack(stack.getItemStack().copy());
             return true;
         } else if (RoughlyEnoughItemsCore.canUsePackets()) {
+            PlayerInventory inventory = MinecraftClient.getInstance().player.inventory;
+            EntryStack stack = entry.copy();
+            if (!inventory.getCursorStack().isEmpty() && !EntryStack.create(inventory.getCursorStack()).equalsIgnoreAmount(stack)) {
+                return false;
+            }
             try {
                 ClientSidePacketRegistry.INSTANCE.sendToServer(ConfigObject.getInstance().isGrabbingItems() ? RoughlyEnoughItemsNetwork.CREATE_ITEMS_GRAB_PACKET : RoughlyEnoughItemsNetwork.CREATE_ITEMS_PACKET, new PacketByteBuf(Unpooled.buffer()).writeItemStack(cheatedStack));
                 return true;

+ 2 - 2
src/main/java/me/shedaniel/rei/impl/ConfigObjectImpl.java

@@ -139,8 +139,8 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData {
     }
     
     @Override
-    public boolean isLeftHandSidePanel() {
-        return advanced.accessibility.displayPanelLocation == DisplayPanelLocation.LEFT;
+    public DisplayPanelLocation getDisplayPanelLocation() {
+        return advanced.accessibility.displayPanelLocation;
     }
     
     @Override

+ 40 - 6
src/main/java/me/shedaniel/rei/impl/DisplayHelperImpl.java

@@ -29,7 +29,12 @@ import me.shedaniel.math.Rectangle;
 import me.shedaniel.rei.api.BaseBoundsHandler;
 import me.shedaniel.rei.api.DisplayHelper;
 import me.shedaniel.rei.api.OverlayDecider;
+import me.shedaniel.rei.gui.config.DisplayPanelLocation;
 import me.shedaniel.rei.utils.CollectionUtils;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.util.Window;
 import org.jetbrains.annotations.ApiStatus;
 
 import java.util.Collections;
@@ -38,9 +43,10 @@ import java.util.List;
 import java.util.Map;
 
 @ApiStatus.Internal
+@Environment(EnvType.CLIENT)
 public class DisplayHelperImpl implements DisplayHelper {
     
-    private static final Comparator<OverlayDecider> BOUNDS_HANDLER_COMPARATOR;
+    private static final Comparator<OverlayDecider> BOUNDS_HANDLER_COMPARATOR = Comparator.comparingDouble(OverlayDecider::getPriority).reversed();
     private static final DisplayBoundsHandler<Object> EMPTY = new DisplayBoundsHandler<Object>() {
         @Override
         public Class<Object> getBaseSupportedClass() {
@@ -63,13 +69,9 @@ public class DisplayHelperImpl implements DisplayHelper {
         }
     };
     
-    static {
-        Comparator<OverlayDecider> comparator = Comparator.comparingDouble(OverlayDecider::getPriority);
-        BOUNDS_HANDLER_COMPARATOR = comparator.reversed();
-    }
-    
     private List<OverlayDecider> screenDisplayBoundsHandlers = Lists.newArrayList();
     private Map<Class<?>, DisplayBoundsHandler<?>> handlerCache = Maps.newHashMap();
+    private Map<Class<?>, List<OverlayDecider>> deciderSortedCache = Maps.newHashMap();
     private Map<Class<?>, List<DisplayBoundsHandler<?>>> handlerSortedCache = Maps.newHashMap();
     private BaseBoundsHandler baseBoundsHandler;
     private Class<?> tempScreen;
@@ -85,6 +87,16 @@ public class DisplayHelperImpl implements DisplayHelper {
         return handlerSortedCache.get(screenClass);
     }
     
+    @Override
+    public List<OverlayDecider> getSortedOverlayDeciders(Class<?> screenClass) {
+        List<OverlayDecider> possibleCached = deciderSortedCache.get(screenClass);
+        if (possibleCached != null)
+            return possibleCached;
+        tempScreen = screenClass;
+        deciderSortedCache.put(screenClass, (List) CollectionUtils.filter(screenDisplayBoundsHandlers, this::filterResponsible));
+        return deciderSortedCache.get(screenClass);
+    }
+    
     @Override
     public List<OverlayDecider> getAllOverlayDeciders() {
         return Collections.unmodifiableList(screenDisplayBoundsHandlers);
@@ -100,6 +112,28 @@ public class DisplayHelperImpl implements DisplayHelper {
         return handlerCache.get(screenClass);
     }
     
+    @Override
+    public <T> Rectangle getOverlayBounds(DisplayPanelLocation location, T screen) {
+        Window window = MinecraftClient.getInstance().getWindow();
+        int scaledWidth = window.getScaledWidth();
+        int scaledHeight = window.getScaledHeight();
+        for (OverlayDecider decider : getSortedOverlayDeciders(screen.getClass())) {
+            if (decider instanceof DisplayBoundsProvider) {
+                Rectangle containerBounds = ((DisplayBoundsProvider<T>) decider).getScreenBounds(screen);
+                if (location == DisplayPanelLocation.LEFT) {
+                    if (containerBounds.x < 10) continue;
+                    return new Rectangle(2, 0, containerBounds.x - 2, scaledHeight);
+                } else {
+                    if (scaledWidth - containerBounds.getMaxX() < 10) continue;
+                    return new Rectangle(containerBounds.getMaxX() + 2, 0, scaledWidth - containerBounds.getMaxX() - 4, scaledHeight);
+                }
+            } else if (decider instanceof DisplayBoundsHandler) {
+                return location == DisplayPanelLocation.LEFT ? ((DisplayBoundsHandler<T>) decider).getLeftBounds(screen) : ((DisplayBoundsHandler<T>) decider).getRightBounds(screen);
+            }
+        }
+        return new Rectangle();
+    }
+    
     private boolean filterResponsible(OverlayDecider handler) {
         return handler.isHandingScreen(tempScreen);
     }

+ 3 - 0
src/main/java/me/shedaniel/rei/impl/RecipeHelperImpl.java

@@ -34,6 +34,8 @@ import me.shedaniel.rei.api.plugins.REIPluginV0;
 import me.shedaniel.rei.api.subsets.SubsetsRegistry;
 import me.shedaniel.rei.impl.subsets.SubsetsRegistryImpl;
 import me.shedaniel.rei.utils.CollectionUtils;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
 import net.minecraft.client.gui.screen.ingame.ContainerScreen;
 import net.minecraft.recipe.Recipe;
 import net.minecraft.recipe.RecipeManager;
@@ -49,6 +51,7 @@ import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 @ApiStatus.Internal
+@Environment(EnvType.CLIENT)
 public class RecipeHelperImpl implements RecipeHelper {
     
     private static final Comparator<DisplayVisibilityHandler> VISIBILITY_HANDLER_COMPARATOR;

+ 14 - 0
src/main/java/me/shedaniel/rei/impl/ScreenHelper.java

@@ -28,6 +28,7 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import me.shedaniel.cloth.api.client.events.v0.ClothClientHooks;
 import me.shedaniel.math.Point;
+import me.shedaniel.math.Rectangle;
 import me.shedaniel.math.api.Executor;
 import me.shedaniel.rei.RoughlyEnoughItemsState;
 import me.shedaniel.rei.api.ConfigManager;
@@ -38,8 +39,11 @@ import me.shedaniel.rei.gui.ContainerScreenOverlay;
 import me.shedaniel.rei.gui.OverlaySearchField;
 import me.shedaniel.rei.gui.RecipeScreen;
 import me.shedaniel.rei.gui.WarningAndErrorScreen;
+import me.shedaniel.rei.gui.config.SearchFieldLocation;
 import me.shedaniel.rei.gui.widget.TextFieldWidget;
 import net.fabricmc.api.ClientModInitializer;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
 import net.fabricmc.fabric.api.event.client.ClientTickCallback;
 import net.fabricmc.loader.api.FabricLoader;
 import net.minecraft.client.MinecraftClient;
@@ -58,6 +62,7 @@ import java.util.List;
 import java.util.Optional;
 
 @ApiStatus.Internal
+@Environment(EnvType.CLIENT)
 public class ScreenHelper implements ClientModInitializer, REIHelper {
     
     private OverlaySearchField searchField;
@@ -203,6 +208,15 @@ public class ScreenHelper implements ClientModInitializer, REIHelper {
         ScreenHelper.instance = this;
     }
     
+    public static Rectangle getItemListArea(Rectangle bounds) {
+        return new Rectangle(bounds.x, bounds.y + 2 + (ConfigObject.getInstance().getSearchFieldLocation() == SearchFieldLocation.TOP_SIDE ? 24 : 0) + (ConfigObject.getInstance().isEntryListWidgetScrolled() ? 0 : 22), bounds.width, bounds.height - (ConfigObject.getInstance().getSearchFieldLocation() != SearchFieldLocation.CENTER ? 27 + 22 : 27) + (!ConfigObject.getInstance().isEntryListWidgetScrolled() ? 0 : 22));
+    }
+    
+    public static Rectangle getFavoritesListArea(Rectangle bounds) {
+        int offset = 6 + (!ConfigObject.getInstance().isLowerConfigButton() ? 25 : 0) + (ConfigObject.getInstance().doesShowUtilsButtons() ? 25 : 0);
+        return new Rectangle(bounds.x, bounds.y + 2 + offset, bounds.width, bounds.height - 5 - offset);
+    }
+    
     @Override
     public void onInitializeClient() {
         ClothClientHooks.SCREEN_INIT_PRE.register((client, screen, screenHooks) -> {

+ 16 - 46
src/main/java/me/shedaniel/rei/plugin/DefaultPlugin.java

@@ -66,6 +66,8 @@ import me.shedaniel.rei.plugin.stripping.DefaultStrippingCategory;
 import me.shedaniel.rei.plugin.stripping.DefaultStrippingDisplay;
 import me.shedaniel.rei.plugin.stripping.DummyAxeItem;
 import me.shedaniel.rei.utils.CollectionUtils;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
 import net.minecraft.block.ComposterBlock;
 import net.minecraft.block.entity.AbstractFurnaceBlockEntity;
 import net.minecraft.client.MinecraftClient;
@@ -89,6 +91,7 @@ import org.jetbrains.annotations.Nullable;
 
 import java.util.*;
 
+@Environment(EnvType.CLIENT)
 public class DefaultPlugin implements REIPluginV0 {
     
     public static final Identifier CRAFTING = new Identifier("minecraft", "plugins/crafting");
@@ -305,71 +308,38 @@ public class DefaultPlugin implements REIPluginV0 {
                 return Collections.emptyList();
             return Collections.singletonList(widget.getBounds().clone());
         });
-        displayHelper.registerHandler(new DisplayHelper.DisplayBoundsHandler<ContainerScreen<?>>() {
+        displayHelper.registerProvider(new DisplayHelper.DisplayBoundsProvider<ContainerScreen<?>>() {
             @Override
-            public Class<?> getBaseSupportedClass() {
-                return ContainerScreen.class;
+            public Rectangle getScreenBounds(ContainerScreen<?> screen) {
+                return new Rectangle(screen.x, screen.y, screen.containerWidth, screen.containerHeight);
             }
             
             @Override
-            public Rectangle getLeftBounds(ContainerScreen<?> screen) {
-                return new Rectangle(2, 0, screen.x - 4, screen.height);
+            public Class<?> getBaseSupportedClass() {
+                return ContainerScreen.class;
             }
-            
+        });
+        displayHelper.registerProvider(new DisplayHelper.DisplayBoundsProvider<RecipeViewingScreen>() {
             @Override
-            public Rectangle getRightBounds(ContainerScreen<?> screen) {
-                int startX = screen.x + screen.containerWidth + 2;
-                return new Rectangle(startX, 0, screen.width - startX - 2, screen.height);
+            public Rectangle getScreenBounds(RecipeViewingScreen screen) {
+                return screen.getBounds();
             }
             
-            @Override
-            public float getPriority() {
-                return -1.0f;
-            }
-        });
-        displayHelper.registerHandler(new DisplayHelper.DisplayBoundsHandler<RecipeViewingScreen>() {
             @Override
             public Class<?> getBaseSupportedClass() {
                 return RecipeViewingScreen.class;
             }
-            
-            @Override
-            public Rectangle getLeftBounds(RecipeViewingScreen screen) {
-                return new Rectangle(2, 0, screen.getBounds().x - 4, MinecraftClient.getInstance().getWindow().getScaledHeight());
-            }
-            
+        });
+        displayHelper.registerProvider(new DisplayHelper.DisplayBoundsProvider<VillagerRecipeViewingScreen>() {
             @Override
-            public Rectangle getRightBounds(RecipeViewingScreen screen) {
-                int startX = screen.getBounds().x + screen.getBounds().width + 2;
-                return new Rectangle(startX, 0, MinecraftClient.getInstance().getWindow().getScaledWidth() - startX - 2, MinecraftClient.getInstance().getWindow().getScaledHeight());
+            public Rectangle getScreenBounds(VillagerRecipeViewingScreen screen) {
+                return screen.bounds;
             }
             
-            @Override
-            public float getPriority() {
-                return -1.0f;
-            }
-        });
-        displayHelper.registerHandler(new DisplayHelper.DisplayBoundsHandler<VillagerRecipeViewingScreen>() {
             @Override
             public Class<?> getBaseSupportedClass() {
                 return VillagerRecipeViewingScreen.class;
             }
-            
-            @Override
-            public Rectangle getLeftBounds(VillagerRecipeViewingScreen screen) {
-                return new Rectangle(2, 0, screen.bounds.x - 4, MinecraftClient.getInstance().getWindow().getScaledHeight());
-            }
-            
-            @Override
-            public Rectangle getRightBounds(VillagerRecipeViewingScreen screen) {
-                int startX = screen.bounds.x + screen.bounds.width + 2;
-                return new Rectangle(startX, 0, MinecraftClient.getInstance().getWindow().getScaledWidth() - startX - 2, MinecraftClient.getInstance().getWindow().getScaledHeight());
-            }
-            
-            @Override
-            public float getPriority() {
-                return -1.0f;
-            }
         });
     }