Unknown 6 years ago
parent
commit
8434615fe1

+ 3 - 0
CHANGELOG.md

@@ -1,3 +1,6 @@
+## v2.7.2.85
+- Bundled with updated APIs for 1.14-pre1
+- New DisplayHelper for better bounds calculation
 ## v2.7.1.84
 - Bundled with updated APIs. Fixed crash.
 ## v2.7.0.83

+ 6 - 6
gradle.properties

@@ -1,9 +1,9 @@
-mod_version=2.7.1+build.84
-minecraft_version=19w14b
-yarn_version=19w14b.1
-fabric_version=0.2.6.121
-fabricloader_version=0.4.0+build.116
+mod_version=2.7.2+build.85
+minecraft_version=1.14 Pre-Release 1
+yarn_version=1.14 Pre-Release 1+build.3
+fabric_version=0.2.7+build.122
+fabricloader_version=0.4.0+build.119
 jankson_version=1.1.0
 cloth_events_version=0.3.1.23
-cloth_config_version=0.1.1.5
+cloth_config_version=0.1.2.6
 modmenu_version=1.2.1-45

+ 7 - 4
src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java

@@ -6,11 +6,9 @@ import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import me.shedaniel.cloth.api.ClientUtils;
 import me.shedaniel.cloth.hooks.ClothClientHooks;
-import me.shedaniel.rei.api.ItemRegistry;
-import me.shedaniel.rei.api.PluginDisabler;
-import me.shedaniel.rei.api.REIPlugin;
-import me.shedaniel.rei.api.RecipeHelper;
+import me.shedaniel.rei.api.*;
 import me.shedaniel.rei.client.*;
+import me.shedaniel.rei.client.ConfigManager;
 import me.shedaniel.rei.gui.ContainerScreenOverlay;
 import net.fabricmc.api.ClientModInitializer;
 import net.fabricmc.loader.api.FabricLoader;
@@ -41,6 +39,7 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer {
     private static final RecipeHelper RECIPE_HELPER = new RecipeHelperImpl();
     private static final PluginDisabler PLUGIN_DISABLER = new PluginDisablerImpl();
     private static final ItemRegistry ITEM_REGISTRY = new ItemRegistryImpl();
+    private static final DisplayHelper DISPLAY_HELPER = new DisplayHelperImpl();
     private static final Map<Identifier, REIPlugin> plugins = Maps.newHashMap();
     private static ConfigManager configManager;
     
@@ -64,6 +63,10 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer {
         return PLUGIN_DISABLER;
     }
     
+    public static DisplayHelper getDisplayHelper() {
+        return DISPLAY_HELPER;
+    }
+    
     public static REIPlugin registerPlugin(Identifier identifier, REIPlugin plugin) {
         plugins.put(identifier, plugin);
         RoughlyEnoughItemsCore.LOGGER.info("[REI] Registered plugin %s from %s", identifier.toString(), plugin.getClass().getSimpleName());

+ 32 - 0
src/main/java/me/shedaniel/rei/api/DisplayHelper.java

@@ -0,0 +1,32 @@
+package me.shedaniel.rei.api;
+
+import me.shedaniel.rei.RoughlyEnoughItemsCore;
+
+import java.awt.*;
+import java.util.List;
+
+public interface DisplayHelper {
+    
+    List<DisplayBoundsHandler> getSortedBoundsHandlers(Class screenClass);
+    
+    DisplayBoundsHandler getResponsibleBoundsHandler(Class screenClass);
+    
+    void registerBoundsHandler(DisplayBoundsHandler handler);
+    
+    public static interface DisplayBoundsHandler<T> {
+        Class getBaseSupportedClass();
+        
+        Rectangle getLeftBounds(T screen);
+        
+        Rectangle getRightBounds(T screen);
+        
+        default Rectangle getItemListArea(Rectangle rectangle) {
+            return new Rectangle(rectangle.x + 2, rectangle.y + 24, rectangle.width - 4, rectangle.height - (RoughlyEnoughItemsCore.getConfigManager().getConfig().sideSearchField ? 27 + 22 : 27));
+        }
+        
+        default float getPriority() {
+            return 0f;
+        }
+    }
+    
+}

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

@@ -1,5 +1,5 @@
 package me.shedaniel.rei.api;
 
 public enum PluginFunction {
-    REGISTER_ITEMS, REGISTER_CATEGORIES, REGISTER_RECIPE_DISPLAYS, REGISTER_SPEED_CRAFT, REGISTER_OTHERS;
+    REGISTER_ITEMS, REGISTER_CATEGORIES, REGISTER_RECIPE_DISPLAYS, REGISTER_SPEED_CRAFT, REGISTER_BOUNDS, REGISTER_OTHERS;
 }

+ 2 - 0
src/main/java/me/shedaniel/rei/api/REIPlugin.java

@@ -13,6 +13,8 @@ public interface REIPlugin {
     @Deprecated
     default void registerSpeedCraft(RecipeHelper recipeHelper) {}
     
+    default void registerBounds(DisplayHelper displayHelper) {}
+    
     default void registerOthers(RecipeHelper recipeHelper) {}
     
     default int getPriority() {

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

@@ -51,15 +51,15 @@ public interface RecipeCategory<T extends RecipeDisplay> {
     }
     
     default int getDisplayHeight() {
-        return getDisplaySettings().getDisplayHeight(this);
+        return RecipeHelper.getInstance().getCachedCategorySettings(getIdentifier()).map(settings -> settings.getDisplayHeight(this)).orElse(0);
     }
     
     default int getDisplayWidth(T display) {
-        return getDisplaySettings().getDisplayWidth(this, display);
+        return RecipeHelper.getInstance().getCachedCategorySettings(getIdentifier()).map(settings -> settings.getDisplayWidth(this, display)).orElse(0);
     }
     
     default int getMaximumRecipePerPage() {
-        return getDisplaySettings().getMaximumRecipePerPage(this);
+        return RecipeHelper.getInstance().getCachedCategorySettings(getIdentifier()).map(settings -> settings.getMaximumRecipePerPage(this)).orElse(0);
     }
     
     default boolean checkTags() {

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

@@ -51,4 +51,6 @@ public interface RecipeHelper {
     
     boolean isDisplayVisible(RecipeDisplay display, boolean respectConfig);
     
+    Optional<DisplaySettings> getCachedCategorySettings(Identifier category);
+    
 }

+ 3 - 3
src/main/java/me/shedaniel/rei/client/ClientHelper.java

@@ -131,9 +131,9 @@ public class ClientHelper implements ClientModInitializer {
     private void registerFabricKeyBinds() {
         String category = "key.rei.category";
         KeyBindingRegistryImpl.INSTANCE.addCategory(category);
-        KeyBindingRegistryImpl.INSTANCE.register(RECIPE = FabricKeyBinding.Builder.create(RECIPE_KEYBIND, InputUtil.Type.KEY_KEYBOARD, 82, category).build());
-        KeyBindingRegistryImpl.INSTANCE.register(USAGE = FabricKeyBinding.Builder.create(USAGE_KEYBIND, InputUtil.Type.KEY_KEYBOARD, 85, category).build());
-        KeyBindingRegistryImpl.INSTANCE.register(HIDE = FabricKeyBinding.Builder.create(HIDE_KEYBIND, InputUtil.Type.KEY_KEYBOARD, 79, category).build());
+        KeyBindingRegistryImpl.INSTANCE.register(RECIPE = FabricKeyBinding.Builder.create(RECIPE_KEYBIND, InputUtil.Type.KEYSYM, 82, category).build());
+        KeyBindingRegistryImpl.INSTANCE.register(USAGE = FabricKeyBinding.Builder.create(USAGE_KEYBIND, InputUtil.Type.KEYSYM, 85, category).build());
+        KeyBindingRegistryImpl.INSTANCE.register(HIDE = FabricKeyBinding.Builder.create(HIDE_KEYBIND, InputUtil.Type.KEYSYM, 79, category).build());
     }
     
 }

+ 66 - 0
src/main/java/me/shedaniel/rei/client/DisplayHelperImpl.java

@@ -0,0 +1,66 @@
+package me.shedaniel.rei.client;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import me.shedaniel.rei.api.DisplayHelper;
+
+import java.awt.*;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+public class DisplayHelperImpl implements DisplayHelper {
+    
+    private static final Comparator BOUNDS_HANDLER_COMPARATOR = Comparator.comparingDouble(value -> {
+        if (value instanceof DisplayBoundsHandler)
+            return (double) ((DisplayBoundsHandler) value).getPriority();
+        return -Double.MAX_VALUE;
+    }).reversed();
+    private static final DisplayBoundsHandler EMPTY = new DisplayBoundsHandler() {
+        @Override
+        public Class getBaseSupportedClass() {
+            return null;
+        }
+        
+        @Override
+        public Rectangle getLeftBounds(Object screen) {
+            return new Rectangle();
+        }
+        
+        @Override
+        public Rectangle getRightBounds(Object screen) {
+            return new Rectangle();
+        }
+    };
+    private List<DisplayBoundsHandler> screenDisplayBoundsHandlerMap = Lists.newArrayList();
+    private Map<Class, DisplayBoundsHandler> handlerCache = Maps.newHashMap();
+    
+    @Override
+    public List<DisplayBoundsHandler> getSortedBoundsHandlers(Class screenClass) {
+        List<DisplayBoundsHandler> list = Lists.newArrayList(screenDisplayBoundsHandlerMap.stream().filter(handler -> handler.getBaseSupportedClass().isAssignableFrom(screenClass)).collect(Collectors.toList()));
+        list.sort(BOUNDS_HANDLER_COMPARATOR);
+        return list;
+    }
+    
+    @Override
+    public DisplayBoundsHandler getResponsibleBoundsHandler(Class screenClass) {
+        Optional<DisplayBoundsHandler> handler = handlerCache.entrySet().stream().filter(entry -> entry.getKey().equals(screenClass)).map(Map.Entry::getValue).findAny();
+        if (handler.isPresent())
+            return handler.get();
+        List<DisplayBoundsHandler> sortedBoundsHandlers = getSortedBoundsHandlers(screenClass);
+        handlerCache.put(screenClass, sortedBoundsHandlers.isEmpty() ? EMPTY : sortedBoundsHandlers.get(0));
+        return handlerCache.get(screenClass);
+    }
+    
+    @Override
+    public void registerBoundsHandler(DisplayBoundsHandler handler) {
+        screenDisplayBoundsHandlerMap.add(handler);
+    }
+    
+    public void resetCache() {
+        handlerCache.clear();
+    }
+    
+}

+ 11 - 0
src/main/java/me/shedaniel/rei/client/RecipeHelperImpl.java

@@ -23,6 +23,7 @@ public class RecipeHelperImpl implements RecipeHelper {
     }).reversed();
     private final AtomicInteger recipeCount = new AtomicInteger();
     private final Map<Identifier, List<RecipeDisplay>> recipeCategoryListMap = Maps.newHashMap();
+    private final Map<Identifier, DisplaySettings> categoryDisplaySettingsMap = Maps.newHashMap();
     private final List<RecipeCategory> categories = Lists.newArrayList();
     private final Map<Identifier, ButtonAreaSupplier> speedCraftAreaSupplierMap = Maps.newHashMap();
     private final Map<Identifier, List<SpeedCraftFunctional>> speedCraftFunctionalMap = Maps.newHashMap();
@@ -62,6 +63,7 @@ public class RecipeHelperImpl implements RecipeHelper {
     @Override
     public void registerCategory(RecipeCategory category) {
         categories.add(category);
+        categoryDisplaySettingsMap.put(category.getIdentifier(), category.getDisplaySettings());
         recipeCategoryListMap.put(category.getIdentifier(), Lists.newLinkedList());
     }
     
@@ -180,7 +182,9 @@ public class RecipeHelperImpl implements RecipeHelper {
         this.categories.clear();
         this.speedCraftAreaSupplierMap.clear();
         this.speedCraftFunctionalMap.clear();
+        this.categoryDisplaySettingsMap.clear();
         this.displayVisibilityHandlers.clear();
+        ((DisplayHelperImpl) RoughlyEnoughItemsCore.getDisplayHelper()).resetCache();
         long startTime = System.currentTimeMillis();
         List<REIPlugin> plugins = new LinkedList<>(RoughlyEnoughItemsCore.getPlugins());
         plugins.sort((first, second) -> {
@@ -202,6 +206,8 @@ public class RecipeHelperImpl implements RecipeHelper {
                 plugin.registerRecipeDisplays(this);
             if (RoughlyEnoughItemsCore.getConfigManager().getConfig().enableLegacySpeedCraftSupport && pluginDisabler.isFunctionEnabled(identifier, PluginFunction.REGISTER_SPEED_CRAFT))
                 plugin.registerSpeedCraft(this);
+            if (pluginDisabler.isFunctionEnabled(identifier, PluginFunction.REGISTER_BOUNDS))
+                plugin.registerBounds(RoughlyEnoughItemsCore.getDisplayHelper());
             if (pluginDisabler.isFunctionEnabled(identifier, PluginFunction.REGISTER_OTHERS))
                 plugin.registerOthers(this);
         });
@@ -272,4 +278,9 @@ public class RecipeHelperImpl implements RecipeHelper {
         return true;
     }
     
+    @Override
+    public Optional<DisplaySettings> getCachedCategorySettings(Identifier category) {
+        return categoryDisplaySettingsMap.entrySet().stream().filter(entry -> entry.getKey().equals(category)).map(Map.Entry::getValue).findAny();
+    }
+    
 }

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

@@ -4,6 +4,7 @@ import com.google.common.collect.Lists;
 import com.mojang.blaze3d.platform.GlStateManager;
 import me.shedaniel.cloth.api.ClientUtils;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
+import me.shedaniel.rei.api.DisplayHelper;
 import me.shedaniel.rei.client.ClientHelper;
 import me.shedaniel.rei.client.ScreenHelper;
 import me.shedaniel.rei.client.Weather;
@@ -53,10 +54,11 @@ public class ContainerScreenOverlay extends AbstractParentElement implements Dra
         //Update Variables
         this.children().clear();
         this.window = MinecraftClient.getInstance().window;
-        this.rectangle = calculateBoundary();
+        DisplayHelper.DisplayBoundsHandler boundsHandler = RoughlyEnoughItemsCore.getDisplayHelper().getResponsibleBoundsHandler(MinecraftClient.getInstance().currentScreen.getClass());
+        this.rectangle = RoughlyEnoughItemsCore.getConfigManager().getConfig().mirrorItemPanel ? boundsHandler.getLeftBounds(MinecraftClient.getInstance().currentScreen) : boundsHandler.getRightBounds(MinecraftClient.getInstance().currentScreen);
         this.lastLeft = getLeft();
         widgets.add(this.itemListOverlay = new ItemListOverlay(page));
-        itemListOverlay.updateList(getItemListArea(), page, searchTerm);
+        itemListOverlay.updateList(boundsHandler, boundsHandler.getItemListArea(rectangle), page, searchTerm);
         
         widgets.add(buttonLeft = new ButtonWidget(rectangle.x, rectangle.y + 5, 16, 16, new TranslatableTextComponent("text.rei.left_arrow")) {
             @Override
@@ -64,7 +66,7 @@ public class ContainerScreenOverlay extends AbstractParentElement implements Dra
                 page--;
                 if (page < 0)
                     page = getTotalPage();
-                itemListOverlay.updateList(getItemListArea(), page, searchTerm);
+                itemListOverlay.updateList(boundsHandler, boundsHandler.getItemListArea(rectangle), page, searchTerm);
             }
             
             @Override
@@ -83,7 +85,7 @@ public class ContainerScreenOverlay extends AbstractParentElement implements Dra
                 page++;
                 if (page > getTotalPage())
                     page = 0;
-                itemListOverlay.updateList(getItemListArea(), page, searchTerm);
+                itemListOverlay.updateList(boundsHandler, boundsHandler.getItemListArea(rectangle), page, searchTerm);
             }
             
             @Override
@@ -201,7 +203,7 @@ public class ContainerScreenOverlay extends AbstractParentElement implements Dra
             public void onLabelClicked() {
                 MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F));
                 page = 0;
-                itemListOverlay.updateList(getItemListArea(), page, searchTerm);
+                itemListOverlay.updateList(boundsHandler, boundsHandler.getItemListArea(rectangle), page, searchTerm);
             }
             
             @Override
@@ -213,7 +215,7 @@ public class ContainerScreenOverlay extends AbstractParentElement implements Dra
             ScreenHelper.searchField = new SearchFieldWidget(0, 0, 0, 0);
         ScreenHelper.searchField.setChangedListener(s -> {
             searchTerm = s;
-            itemListOverlay.updateList(getItemListArea(), page, searchTerm);
+            itemListOverlay.updateList(boundsHandler, boundsHandler.getItemListArea(rectangle), page, searchTerm);
         });
         ScreenHelper.searchField.getBounds().setBounds(getTextFieldArea());
         this.widgets.add(ScreenHelper.searchField);
@@ -223,7 +225,7 @@ public class ContainerScreenOverlay extends AbstractParentElement implements Dra
                 @Override
                 public void onPressed() {
                     RoughlyEnoughItemsCore.getConfigManager().toggleCraftableOnly();
-                    itemListOverlay.updateList(getItemListArea(), page, searchTerm);
+                    itemListOverlay.updateList(boundsHandler, boundsHandler.getItemListArea(rectangle), page, searchTerm);
                 }
                 
                 @Override
@@ -233,7 +235,7 @@ public class ContainerScreenOverlay extends AbstractParentElement implements Dra
                 }
             });
         
-        this.itemListOverlay.updateList(getItemListArea(), page, searchTerm);
+        this.itemListOverlay.updateList(boundsHandler, boundsHandler.getItemListArea(rectangle), page, searchTerm);
     }
     
     private Weather getNextWeather() {
@@ -303,10 +305,6 @@ public class ContainerScreenOverlay extends AbstractParentElement implements Dra
         return I18n.translate(String.format("%s%s", "text.rei.", ClientHelper.isCheating() ? "cheat" : "nocheat"));
     }
     
-    private Rectangle getItemListArea() {
-        return new Rectangle(rectangle.x + 2, rectangle.y + 24, rectangle.width - 4, rectangle.height - (RoughlyEnoughItemsCore.getConfigManager().getConfig().sideSearchField ? 27 + 22 : 27));
-    }
-    
     public Rectangle getRectangle() {
         return rectangle;
     }
@@ -318,7 +316,8 @@ public class ContainerScreenOverlay extends AbstractParentElement implements Dra
             init(true);
         else if (RoughlyEnoughItemsCore.getConfigManager().isCraftableOnlyEnabled() && (!hasSameListContent(new LinkedList<>(ScreenHelper.inventoryStacks), currentStacks) || (currentStacks.size() != ScreenHelper.inventoryStacks.size()))) {
             ScreenHelper.inventoryStacks = ClientHelper.getInventoryItemsTypes();
-            itemListOverlay.updateList(getItemListArea(), page, searchTerm);
+            DisplayHelper.DisplayBoundsHandler boundsHandler = RoughlyEnoughItemsCore.getDisplayHelper().getResponsibleBoundsHandler(MinecraftClient.getInstance().currentScreen.getClass());
+            itemListOverlay.updateList(boundsHandler, boundsHandler.getItemListArea(rectangle), page, searchTerm);
         }
         GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F);
         GuiLighting.disable();
@@ -415,26 +414,6 @@ public class ContainerScreenOverlay extends AbstractParentElement implements Dra
         GuiLighting.disable();
     }
     
-    private Rectangle calculateBoundary() {
-        try {
-            if (!RoughlyEnoughItemsCore.getConfigManager().getConfig().mirrorItemPanel) {
-                int startX = ScreenHelper.getLastContainerScreenHooks().rei_getContainerLeft() + ScreenHelper.getLastContainerScreenHooks().rei_getContainerWidth() + 10;
-                int width = window.getScaledWidth() - startX;
-                if (MinecraftClient.getInstance().currentScreen instanceof RecipeViewingScreen) {
-                    RecipeViewingScreen widget = (RecipeViewingScreen) MinecraftClient.getInstance().currentScreen;
-                    startX = widget.getBounds().x + widget.getBounds().width + 10;
-                    width = window.getScaledWidth() - startX;
-                }
-                return new Rectangle(startX, 0, width, window.getScaledHeight());
-            }
-            return new Rectangle(4, 0, getLeft() - 6, window.getScaledHeight());
-        } catch (Exception e) {
-            RoughlyEnoughItemsCore.LOGGER.info("[REI] Error calculating boundary, report the issue!");
-            e.printStackTrace();
-            return new Rectangle();
-        }
-    }
-    
     private int getLeft() {
         if (MinecraftClient.getInstance().currentScreen instanceof RecipeViewingScreen) {
             RecipeViewingScreen widget = (RecipeViewingScreen) MinecraftClient.getInstance().currentScreen;

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

@@ -3,6 +3,7 @@ package me.shedaniel.rei.gui.widget;
 import com.google.common.collect.Lists;
 import me.shedaniel.cloth.api.ClientUtils;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
+import me.shedaniel.rei.api.DisplayHelper;
 import me.shedaniel.rei.api.RecipeHelper;
 import me.shedaniel.rei.client.ClientHelper;
 import me.shedaniel.rei.client.ItemListOrdering;
@@ -78,8 +79,8 @@ public class ItemListOverlay extends Widget {
             ScreenHelper.getLastOverlay().addTooltip(QueuedTooltip.create(I18n.translate("text.rei.delete_items")));
     }
     
-    public void updateList(Rectangle bounds, int page, String searchTerm) {
-        this.rectangle = bounds;
+    public void updateList(DisplayHelper.DisplayBoundsHandler boundsHandler, Rectangle rectangle, int page, String searchTerm) {
+        this.rectangle = rectangle;
         this.page = page;
         this.widgets = Lists.newLinkedList();
         calculateListSize(rectangle);

+ 84 - 1
src/main/java/me/shedaniel/rei/plugin/DefaultPlugin.java

@@ -3,13 +3,17 @@ package me.shedaniel.rei.plugin;
 import com.google.common.collect.Lists;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
 import me.shedaniel.rei.api.*;
+import me.shedaniel.rei.client.ScreenHelper;
+import me.shedaniel.rei.gui.RecipeViewingScreen;
 import me.shedaniel.rei.listeners.GhostSlotsHooks;
 import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.gui.ContainerScreen;
 import net.minecraft.client.gui.Screen;
 import net.minecraft.client.gui.container.BlastFurnaceScreen;
 import net.minecraft.client.gui.container.CraftingTableScreen;
 import net.minecraft.client.gui.container.FurnaceScreen;
 import net.minecraft.client.gui.container.SmokerScreen;
+import net.minecraft.client.gui.ingame.CreativePlayerInventoryScreen;
 import net.minecraft.client.gui.ingame.PlayerInventoryScreen;
 import net.minecraft.enchantment.Enchantment;
 import net.minecraft.enchantment.EnchantmentHelper;
@@ -27,7 +31,9 @@ import net.minecraft.recipe.crafting.ShapelessRecipe;
 import net.minecraft.util.Identifier;
 import net.minecraft.util.registry.Registry;
 
+import java.awt.*;
 import java.util.*;
+import java.util.List;
 
 public class DefaultPlugin implements REIPlugin {
     
@@ -52,7 +58,7 @@ public class DefaultPlugin implements REIPlugin {
             pluginDisabler.disablePluginFunction(PLUGIN, PluginFunction.REGISTER_ITEMS);
             pluginDisabler.disablePluginFunction(PLUGIN, PluginFunction.REGISTER_CATEGORIES);
             pluginDisabler.disablePluginFunction(PLUGIN, PluginFunction.REGISTER_RECIPE_DISPLAYS);
-            pluginDisabler.disablePluginFunction(PLUGIN, PluginFunction.REGISTER_SPEED_CRAFT);
+            pluginDisabler.disablePluginFunction(PLUGIN, PluginFunction.REGISTER_OTHERS);
         }
     }
     
@@ -121,6 +127,83 @@ public class DefaultPlugin implements REIPlugin {
         });
     }
     
+    @Override
+    public void registerBounds(DisplayHelper displayHelper) {
+        displayHelper.registerBoundsHandler(new DisplayHelper.DisplayBoundsHandler() {
+            @Override
+            public Class getBaseSupportedClass() {
+                return ContainerScreen.class;
+            }
+            
+            @Override
+            public Rectangle getLeftBounds(Object screen) {
+                if (MinecraftClient.getInstance().player.getRecipeBook().isGuiOpen())
+                    return new Rectangle(2, 0, ScreenHelper.getLastContainerScreenHooks().rei_getContainerLeft() - 4 - 147 - 30, MinecraftClient.getInstance().window.getScaledHeight());
+                return new Rectangle(2, 0, ScreenHelper.getLastContainerScreenHooks().rei_getContainerLeft() - 4, MinecraftClient.getInstance().window.getScaledHeight());
+            }
+            
+            @Override
+            public Rectangle getRightBounds(Object screen) {
+                int startX = ScreenHelper.getLastContainerScreenHooks().rei_getContainerLeft() + ScreenHelper.getLastContainerScreenHooks().rei_getContainerWidth() + 2;
+                return new Rectangle(startX, 0, MinecraftClient.getInstance().window.getScaledWidth() - startX - 2, MinecraftClient.getInstance().window.getScaledHeight());
+            }
+            
+            @Override
+            public float getPriority() {
+                return -1.0f;
+            }
+        });
+        displayHelper.registerBoundsHandler(new DisplayHelper.DisplayBoundsHandler() {
+            @Override
+            public Class getBaseSupportedClass() {
+                return RecipeViewingScreen.class;
+            }
+            
+            @Override
+            public Rectangle getLeftBounds(Object screen) {
+                return new Rectangle(2, 0, ((RecipeViewingScreen) screen).getBounds().x - 4, MinecraftClient.getInstance().window.getScaledHeight());
+            }
+            
+            @Override
+            public Rectangle getRightBounds(Object screen) {
+                int startX = ((RecipeViewingScreen) screen).getBounds().x + ((RecipeViewingScreen) screen).getBounds().width + 2;
+                return new Rectangle(startX, 0, MinecraftClient.getInstance().window.getScaledWidth() - startX - 2, MinecraftClient.getInstance().window.getScaledHeight());
+            }
+            
+            @Override
+            public float getPriority() {
+                return -1.0f;
+            }
+        });
+        displayHelper.registerBoundsHandler(new DisplayHelper.DisplayBoundsHandler() {
+            @Override
+            public Class getBaseSupportedClass() {
+                return CreativePlayerInventoryScreen.class;
+            }
+            
+            @Override
+            public Rectangle getLeftBounds(Object screen) {
+                return new Rectangle(2, 0, ScreenHelper.getLastContainerScreenHooks().rei_getContainerLeft() - 2, MinecraftClient.getInstance().window.getScaledHeight());
+            }
+            
+            @Override
+            public Rectangle getRightBounds(Object screen) {
+                int startX = ScreenHelper.getLastContainerScreenHooks().rei_getContainerLeft() + ScreenHelper.getLastContainerScreenHooks().rei_getContainerWidth();
+                return new Rectangle(startX, 0, MinecraftClient.getInstance().window.getScaledWidth() - startX - 2, MinecraftClient.getInstance().window.getScaledHeight());
+            }
+            
+            @Override
+            public Rectangle getItemListArea(Rectangle rectangle) {
+                return new Rectangle(rectangle.x + 1, rectangle.y + 24, rectangle.width - 2, rectangle.height - (RoughlyEnoughItemsCore.getConfigManager().getConfig().sideSearchField ? 27 + 22 : 27));
+            }
+            
+            @Override
+            public float getPriority() {
+                return -0.9f;
+            }
+        });
+    }
+    
     @Override
     public void registerOthers(RecipeHelper recipeHelper) {
         recipeHelper.registerRecipeVisibilityHandler(new DisplayVisibilityHandler() {

+ 9 - 3
src/main/java/me/shedaniel/rei/utils/ClothScreenRegistry.java

@@ -2,12 +2,13 @@ package me.shedaniel.rei.utils;
 
 import me.shedaniel.cloth.api.ConfigScreenBuilder;
 import me.shedaniel.cloth.gui.entries.BooleanListEntry;
-import me.shedaniel.cloth.gui.entries.IntegerListEntry;
+import me.shedaniel.cloth.gui.entries.IntegerSliderEntry;
 import me.shedaniel.cloth.gui.entries.StringListEntry;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
 import me.shedaniel.rei.gui.config.ItemListOrderingEntry;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.gui.Screen;
+import net.minecraft.client.resource.language.I18n;
 import net.minecraft.util.Pair;
 
 import java.io.IOException;
@@ -26,8 +27,13 @@ public class ClothScreenRegistry {
         ConfigScreenBuilder.CategoryBuilder appearance = builder.addCategory("text.rei.config.appearance");
         appearance.addOption(new BooleanListEntry("text.rei.config.side_search_box", RoughlyEnoughItemsCore.getConfigManager().getConfig().sideSearchField, "text.cloth-config.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().sideSearchField = bool));
         appearance.addOption(new ItemListOrderingEntry("text.rei.config.list_ordering", new Pair<>(RoughlyEnoughItemsCore.getConfigManager().getConfig().itemListOrdering, RoughlyEnoughItemsCore.getConfigManager().getConfig().isAscending)));
-        appearance.addOption(new BooleanListEntry("text.rei.config.mirror_rei", RoughlyEnoughItemsCore.getConfigManager().getConfig().mirrorItemPanel, "text.cloth-config.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().mirrorItemPanel = bool));
-        appearance.addOption(new IntegerListEntry("text.rei.config.max_recipes_per_page", RoughlyEnoughItemsCore.getConfigManager().getConfig().maxRecipePerPage, "text.cloth-config.reset_value", () -> 3, i -> RoughlyEnoughItemsCore.getConfigManager().getConfig().maxRecipePerPage = i).setMinimum(2).setMaximum(99));
+        appearance.addOption(new BooleanListEntry("text.rei.config.item_list_position", RoughlyEnoughItemsCore.getConfigManager().getConfig().mirrorItemPanel, "text.cloth-config.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().mirrorItemPanel = bool) {
+            @Override
+            public String getYesNoText(boolean bool) {
+                return I18n.translate(bool ? "text.rei.config.item_list_position.left" : "text.rei.config.item_list_position.right");
+            }
+        });
+        appearance.addOption(new IntegerSliderEntry("text.rei.config.max_recipes_per_page", 2, 99, RoughlyEnoughItemsCore.getConfigManager().getConfig().maxRecipePerPage, "text.cloth-config.reset_value", () -> 3, i -> RoughlyEnoughItemsCore.getConfigManager().getConfig().maxRecipePerPage = i));
         ConfigScreenBuilder.CategoryBuilder modules = builder.addCategory("text.rei.config.modules");
         modules.addOption(new BooleanListEntry("text.rei.config.enable_craftable_only", RoughlyEnoughItemsCore.getConfigManager().getConfig().enableCraftableOnlyButton, "text.cloth-config.reset_value", () -> true, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().enableCraftableOnlyButton = bool));
         modules.addOption(new BooleanListEntry("text.rei.config.enable_util_buttons", RoughlyEnoughItemsCore.getConfigManager().getConfig().showUtilsButtons, "text.cloth-config.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().showUtilsButtons = bool));

+ 3 - 1
src/main/resources/assets/roughlyenoughitems/lang/en_us.json

@@ -21,7 +21,9 @@
   "text.rei.config": "Config",
   "text.rei.config_tooltip": "Open Config Screen\n§7Shift-Click to toggle cheat mode",
   "text.rei.config.side_search_box": "Side Search Box: ",
-  "text.rei.config.mirror_rei": "Mirror REI Widgets: ",
+  "text.rei.config.item_list_position": "REI Item List Position: ",
+  "text.rei.config.item_list_position.left": "Left",
+  "text.rei.config.item_list_position.right": "Right",
   "text.rei.cheat_items": "Gave [{item_name}§f] x{item_count} to {player_name}.",
   "text.rei.failed_cheat_items": "§cFailed to give items.",
   "text.rei.config.list_ordering": "Item List Ordering:",