Browse Source

New Cheating Style: Grab

Signed-off-by: shedaniel <daniel@shedaniel.me>
shedaniel 5 years ago
parent
commit
02f92581f5

+ 1 - 1
gradle.properties

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

+ 0 - 6
src/main/java/me/shedaniel/rei/REIModMenuEntryPoint.java

@@ -28,12 +28,6 @@ import io.github.prospector.modmenu.api.ModMenuApi;
 import me.shedaniel.rei.api.ConfigManager;
 import me.shedaniel.rei.api.ConfigManager;
 
 
 public class REIModMenuEntryPoint implements ModMenuApi {
 public class REIModMenuEntryPoint implements ModMenuApi {
-    
-    @Override
-    public String getModId() {
-        return "roughlyenoughitems";
-    }
-    
     @Override
     @Override
     public ConfigScreenFactory<?> getModConfigScreenFactory() {
     public ConfigScreenFactory<?> getModConfigScreenFactory() {
         return parent -> ConfigManager.getInstance().getConfigScreen(parent);
         return parent -> ConfigManager.getInstance().getConfigScreen(parent);

+ 20 - 8
src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java

@@ -33,6 +33,8 @@ import me.shedaniel.rei.gui.ContainerScreenOverlay;
 import me.shedaniel.rei.impl.*;
 import me.shedaniel.rei.impl.*;
 import me.shedaniel.rei.tests.plugin.REITestPlugin;
 import me.shedaniel.rei.tests.plugin.REITestPlugin;
 import net.fabricmc.api.ClientModInitializer;
 import net.fabricmc.api.ClientModInitializer;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
 import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
 import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
 import net.fabricmc.loader.api.FabricLoader;
 import net.fabricmc.loader.api.FabricLoader;
 import net.fabricmc.loader.api.ModContainer;
 import net.fabricmc.loader.api.ModContainer;
@@ -71,6 +73,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Executors;
 
 
 @ApiStatus.Internal
 @ApiStatus.Internal
+@Environment(EnvType.CLIENT)
 public class RoughlyEnoughItemsCore implements ClientModInitializer {
 public class RoughlyEnoughItemsCore implements ClientModInitializer {
     
     
     @ApiStatus.Internal public static final Logger LOGGER = LogManager.getFormatterLogger("REI");
     @ApiStatus.Internal public static final Logger LOGGER = LogManager.getFormatterLogger("REI");
@@ -145,7 +148,7 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer {
     }
     }
     
     
     public static boolean canUsePackets() {
     public static boolean canUsePackets() {
-        return ClientSidePacketRegistry.INSTANCE.canServerReceive(RoughlyEnoughItemsNetwork.CREATE_ITEMS_PACKET) && ClientSidePacketRegistry.INSTANCE.canServerReceive(RoughlyEnoughItemsNetwork.DELETE_ITEMS_PACKET);
+        return ClientSidePacketRegistry.INSTANCE.canServerReceive(RoughlyEnoughItemsNetwork.CREATE_ITEMS_PACKET) && ClientSidePacketRegistry.INSTANCE.canServerReceive(RoughlyEnoughItemsNetwork.CREATE_ITEMS_GRAB_PACKET) && ClientSidePacketRegistry.INSTANCE.canServerReceive(RoughlyEnoughItemsNetwork.DELETE_ITEMS_PACKET);
     }
     }
     
     
     @ApiStatus.Internal
     @ApiStatus.Internal
@@ -170,6 +173,10 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer {
         return System.getProperty("rei.test", "false").equals("true");
         return System.getProperty("rei.test", "false").equals("true");
     }
     }
     
     
+    public static boolean canDeleteItems() {
+        return hasPermissionToUsePackets() || MinecraftClient.getInstance().interactionManager.hasCreativeInventory();
+    }
+    
     @SuppressWarnings("deprecation")
     @SuppressWarnings("deprecation")
     @Override
     @Override
     public void onInitializeClient() {
     public void onInitializeClient() {
@@ -344,17 +351,22 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer {
         });
         });
         ClothClientHooks.SCREEN_MOUSE_CLICKED.register((minecraftClient, screen, v, v1, i) -> {
         ClothClientHooks.SCREEN_MOUSE_CLICKED.register((minecraftClient, screen, v, v1, i) -> {
             isLeftModePressed = true;
             isLeftModePressed = true;
-            if (screen instanceof CreativeInventoryScreen)
-                if (ScreenHelper.isOverlayVisible() && ScreenHelper.getLastOverlay().mouseClicked(v, v1, i)) {
-                    screen.setFocused(ScreenHelper.getLastOverlay());
-                    if (i == 0)
-                        screen.setDragging(true);
-                    return ActionResult.SUCCESS;
-                }
+            if (ScreenHelper.getOptionalOverlay().isPresent())
+                if (screen instanceof CreativeInventoryScreen)
+                    if (ScreenHelper.isOverlayVisible() && ScreenHelper.getLastOverlay().mouseClicked(v, v1, i)) {
+                        screen.setFocused(ScreenHelper.getLastOverlay());
+                        if (i == 0)
+                            screen.setDragging(true);
+                        return ActionResult.SUCCESS;
+                    }
             return ActionResult.PASS;
             return ActionResult.PASS;
         });
         });
         ClothClientHooks.SCREEN_MOUSE_RELEASED.register((minecraftClient, screen, v, v1, i) -> {
         ClothClientHooks.SCREEN_MOUSE_RELEASED.register((minecraftClient, screen, v, v1, i) -> {
             isLeftModePressed = false;
             isLeftModePressed = false;
+            if (ScreenHelper.getOptionalOverlay().isPresent())
+                if (ScreenHelper.isOverlayVisible() && ScreenHelper.getLastOverlay().mouseReleased(v, v1, i)) {
+                    return ActionResult.SUCCESS;
+                }
             return ActionResult.PASS;
             return ActionResult.PASS;
         });
         });
         ClothClientHooks.SCREEN_MOUSE_SCROLLED.register((minecraftClient, screen, v, v1, v2) -> {
         ClothClientHooks.SCREEN_MOUSE_SCROLLED.register((minecraftClient, screen, v, v1, v2) -> {

+ 25 - 0
src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java

@@ -27,6 +27,7 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Maps;
 import io.netty.buffer.Unpooled;
 import io.netty.buffer.Unpooled;
 import me.shedaniel.math.api.Executor;
 import me.shedaniel.math.api.Executor;
+import me.shedaniel.rei.api.EntryStack;
 import me.shedaniel.rei.server.InputSlotCrafter;
 import me.shedaniel.rei.server.InputSlotCrafter;
 import net.fabricmc.api.ModInitializer;
 import net.fabricmc.api.ModInitializer;
 import net.fabricmc.fabric.api.network.ServerSidePacketRegistry;
 import net.fabricmc.fabric.api.network.ServerSidePacketRegistry;
@@ -34,6 +35,7 @@ import net.fabricmc.loader.api.FabricLoader;
 import net.minecraft.container.Container;
 import net.minecraft.container.Container;
 import net.minecraft.container.CraftingContainer;
 import net.minecraft.container.CraftingContainer;
 import net.minecraft.container.PlayerContainer;
 import net.minecraft.container.PlayerContainer;
+import net.minecraft.entity.player.PlayerInventory;
 import net.minecraft.item.ItemStack;
 import net.minecraft.item.ItemStack;
 import net.minecraft.network.PacketByteBuf;
 import net.minecraft.network.PacketByteBuf;
 import net.minecraft.server.network.ServerPlayerEntity;
 import net.minecraft.server.network.ServerPlayerEntity;
@@ -41,6 +43,7 @@ import net.minecraft.text.TranslatableText;
 import net.minecraft.util.Formatting;
 import net.minecraft.util.Formatting;
 import net.minecraft.util.Identifier;
 import net.minecraft.util.Identifier;
 import net.minecraft.util.Util;
 import net.minecraft.util.Util;
+import net.minecraft.util.math.MathHelper;
 
 
 import java.util.Comparator;
 import java.util.Comparator;
 import java.util.List;
 import java.util.List;
@@ -50,6 +53,7 @@ public class RoughlyEnoughItemsNetwork implements ModInitializer {
     
     
     public static final Identifier DELETE_ITEMS_PACKET = new Identifier("roughlyenoughitems", "delete_item");
     public static final Identifier DELETE_ITEMS_PACKET = new Identifier("roughlyenoughitems", "delete_item");
     public static final Identifier CREATE_ITEMS_PACKET = new Identifier("roughlyenoughitems", "create_item");
     public static final Identifier CREATE_ITEMS_PACKET = new Identifier("roughlyenoughitems", "create_item");
+    public static final Identifier CREATE_ITEMS_GRAB_PACKET = new Identifier("roughlyenoughitems", "create_item_grab");
     public static final Identifier CREATE_ITEMS_MESSAGE_PACKET = new Identifier("roughlyenoughitems", "ci_msg");
     public static final Identifier CREATE_ITEMS_MESSAGE_PACKET = new Identifier("roughlyenoughitems", "ci_msg");
     public static final Identifier MOVE_ITEMS_PACKET = new Identifier("roughlyenoughitems", "move_items");
     public static final Identifier MOVE_ITEMS_PACKET = new Identifier("roughlyenoughitems", "move_items");
     public static final Identifier NOT_ENOUGH_ITEMS_PACKET = new Identifier("roughlyenoughitems", "og_not_enough");
     public static final Identifier NOT_ENOUGH_ITEMS_PACKET = new Identifier("roughlyenoughitems", "og_not_enough");
@@ -84,6 +88,27 @@ public class RoughlyEnoughItemsNetwork implements ModInitializer {
                 } else
                 } else
                     player.addMessage(new TranslatableText("text.rei.failed_cheat_items"), false);
                     player.addMessage(new TranslatableText("text.rei.failed_cheat_items"), false);
             });
             });
+            ServerSidePacketRegistry.INSTANCE.register(CREATE_ITEMS_GRAB_PACKET, (packetContext, packetByteBuf) -> {
+                ServerPlayerEntity player = (ServerPlayerEntity) packetContext.getPlayer();
+                if (player.getServer().getPermissionLevel(player.getGameProfile()) < player.getServer().getOpPermissionLevel()) {
+                    player.addMessage(new TranslatableText("text.rei.no_permission_cheat").formatted(Formatting.RED), false);
+                    return;
+                }
+                
+                PlayerInventory inventory = player.inventory;
+                ItemStack itemStack = packetByteBuf.readItemStack();
+                EntryStack stack = EntryStack.create(itemStack.copy());
+                if (!inventory.getCursorStack().isEmpty() && EntryStack.create(inventory.getCursorStack()).equalsIgnoreAmount(stack)) {
+                    stack.setAmount(MathHelper.clamp(stack.getAmount() + inventory.getCursorStack().getCount(), 1, stack.getItemStack().getMaxCount()));
+                } else if (!inventory.getCursorStack().isEmpty()) {
+                    inventory.setCursorStack(ItemStack.EMPTY);
+                    player.updateCursorStack();
+                    return;
+                }
+                inventory.setCursorStack(stack.getItemStack().copy());
+                player.updateCursorStack();
+                ServerSidePacketRegistry.INSTANCE.sendToPlayer(player, RoughlyEnoughItemsNetwork.CREATE_ITEMS_MESSAGE_PACKET, new PacketByteBuf(Unpooled.buffer()).writeItemStack(itemStack.copy()).writeString(player.getEntityName(), 32767));
+            });
             ServerSidePacketRegistry.INSTANCE.register(MOVE_ITEMS_PACKET, (packetContext, packetByteBuf) -> {
             ServerSidePacketRegistry.INSTANCE.register(MOVE_ITEMS_PACKET, (packetContext, packetByteBuf) -> {
                 Identifier category = packetByteBuf.readIdentifier();
                 Identifier category = packetByteBuf.readIdentifier();
                 ServerPlayerEntity player = (ServerPlayerEntity) packetContext.getPlayer();
                 ServerPlayerEntity player = (ServerPlayerEntity) packetContext.getPlayer();

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

@@ -26,6 +26,8 @@ package me.shedaniel.rei.api;
 import me.shedaniel.rei.gui.RecipeScreen;
 import me.shedaniel.rei.gui.RecipeScreen;
 import me.shedaniel.rei.impl.ClientHelperImpl;
 import me.shedaniel.rei.impl.ClientHelperImpl;
 import me.shedaniel.rei.utils.CollectionUtils;
 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.MinecraftClient;
 import net.minecraft.client.gui.screen.Screen;
 import net.minecraft.client.gui.screen.Screen;
 import net.minecraft.item.Item;
 import net.minecraft.item.Item;
@@ -41,6 +43,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.Set;
 import java.util.Set;
 
 
+@Environment(EnvType.CLIENT)
 public interface ClientHelper {
 public interface ClientHelper {
     
     
     /**
     /**

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

@@ -29,10 +29,13 @@ import me.shedaniel.rei.gui.config.RecipeBorderType;
 import me.shedaniel.rei.gui.config.RecipeScreenType;
 import me.shedaniel.rei.gui.config.RecipeScreenType;
 import me.shedaniel.rei.gui.config.SearchFieldLocation;
 import me.shedaniel.rei.gui.config.SearchFieldLocation;
 import me.shedaniel.rei.impl.ConfigManagerImpl;
 import me.shedaniel.rei.impl.ConfigManagerImpl;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
 import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.ApiStatus;
 
 
 import java.util.List;
 import java.util.List;
 
 
+@Environment(EnvType.CLIENT)
 public interface ConfigObject {
 public interface ConfigObject {
     
     
     /**
     /**
@@ -56,6 +59,8 @@ public interface ConfigObject {
     
     
     boolean isUsingDarkTheme();
     boolean isUsingDarkTheme();
     
     
+    boolean isGrabbingItems();
+    
     boolean isToastDisplayedOnCopyIdentifier();
     boolean isToastDisplayedOnCopyIdentifier();
     
     
     boolean doesRenderEntryEnchantmentGlint();
     boolean doesRenderEntryEnchantmentGlint();

+ 5 - 3
src/main/java/me/shedaniel/rei/gui/ContainerScreenOverlay.java

@@ -250,9 +250,11 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
                             tooltips += "\n  ";
                             tooltips += "\n  ";
                             if (!ClientHelper.getInstance().isCheating())
                             if (!ClientHelper.getInstance().isCheating())
                                 tooltips += "\n" + I18n.translate("text.rei.cheating_disabled");
                                 tooltips += "\n" + I18n.translate("text.rei.cheating_disabled");
-                            else if (!RoughlyEnoughItemsCore.hasOperatorPermission())
-                                tooltips += "\n" + I18n.translate("text.rei.cheating_enabled_no_perms");
-                            else if (RoughlyEnoughItemsCore.hasPermissionToUsePackets())
+                            else if (!RoughlyEnoughItemsCore.hasOperatorPermission()) {
+                                if (minecraft.interactionManager.hasCreativeInventory())
+                                    tooltips += "\n" + I18n.translate("text.rei.cheating_limited_creative_enabled");
+                                else tooltips += "\n" + I18n.translate("text.rei.cheating_enabled_no_perms");
+                            } else if (RoughlyEnoughItemsCore.hasPermissionToUsePackets())
                                 tooltips += "\n" + I18n.translate("text.rei.cheating_enabled");
                                 tooltips += "\n" + I18n.translate("text.rei.cheating_enabled");
                             else
                             else
                                 tooltips += "\n" + I18n.translate("text.rei.cheating_limited_enabled");
                                 tooltips += "\n" + I18n.translate("text.rei.cheating_limited_enabled");

+ 43 - 0
src/main/java/me/shedaniel/rei/gui/config/ItemCheatingStyle.java

@@ -0,0 +1,43 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.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 ItemCheatingStyle implements SelectionListEntry.Translatable {
+    GRAB,
+    GIVE;
+    
+    @Override
+    public @NotNull String getKey() {
+        return I18n.translate("config.roughlyenoughitems.cheatingStyle." + name().toLowerCase(Locale.ROOT));
+    }
+}

+ 98 - 0
src/main/java/me/shedaniel/rei/gui/widget/EntryListEntryWidget.java

@@ -0,0 +1,98 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.gui.widget;
+
+import me.shedaniel.math.Point;
+import me.shedaniel.rei.api.ClientHelper;
+import me.shedaniel.rei.api.ConfigObject;
+import me.shedaniel.rei.api.EntryStack;
+import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.item.Item;
+
+import static me.shedaniel.rei.gui.widget.EntryListWidget.entrySize;
+
+public class EntryListEntryWidget extends EntryWidget {
+    public int backupY;
+    
+    protected EntryListEntryWidget(Point point) {
+        super(point);
+        this.backupY = point.y;
+        getBounds().width = getBounds().height = entrySize();
+    }
+    
+    @Override
+    protected void drawHighlighted(MatrixStack matrices, int mouseX, int mouseY, float delta) {
+        if (!getCurrentEntry().isEmpty())
+            super.drawHighlighted(matrices, mouseX, mouseY, delta);
+    }
+    
+    @Override
+    public void queueTooltip(MatrixStack matrices, int mouseX, int mouseY, float delta) {
+        if (ClientHelper.getInstance().isCheating() && !minecraft.player.inventory.getCursorStack().isEmpty()) {
+            return;
+        }
+        super.queueTooltip(matrices, mouseX, mouseY, delta);
+    }
+    
+    @Override
+    public boolean mouseReleased(double mouseX, double mouseY, int button) {
+        if (!interactable)
+            return super.mouseReleased(mouseX, mouseY, button);
+        if (containsMouse(mouseX, mouseY) && ClientHelper.getInstance().isCheating()) {
+            EntryStack entry = getCurrentEntry().copy();
+            if (!entry.isEmpty()) {
+                if (entry.getType() == EntryStack.Type.FLUID) {
+                    Item bucketItem = entry.getFluid().getBucketItem();
+                    if (bucketItem != null) {
+                        entry = EntryStack.create(bucketItem);
+                    }
+                }
+                if (entry.getType() == EntryStack.Type.ITEM)
+                    entry.setAmount(button != 1 && !Screen.hasShiftDown() ? 1 : entry.getItemStack().getMaxCount());
+                return ClientHelper.getInstance().tryCheatingEntry(entry);
+            }
+        }
+        return super.mouseReleased(mouseX, mouseY, button);
+    }
+    
+    @Override
+    protected boolean cancelDeleteItems(EntryStack stack) {
+        if (!interactable || !ConfigObject.getInstance().isGrabbingItems())
+            return super.cancelDeleteItems(stack);
+        if (ClientHelper.getInstance().isCheating()) {
+            EntryStack entry = getCurrentEntry().copy();
+            if (!entry.isEmpty()) {
+                if (entry.getType() == EntryStack.Type.FLUID) {
+                    Item bucketItem = entry.getFluid().getBucketItem();
+                    if (bucketItem != null) {
+                        entry = EntryStack.create(bucketItem);
+                    }
+                }
+                return entry.equalsIgnoreAmount(stack);
+            }
+        }
+        return super.cancelDeleteItems(stack);
+    }
+}

+ 30 - 53
src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java

@@ -40,7 +40,6 @@ import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.impl.SearchArgument;
 import me.shedaniel.rei.impl.SearchArgument;
 import me.shedaniel.rei.utils.CollectionUtils;
 import me.shedaniel.rei.utils.CollectionUtils;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.gui.screen.Screen;
 import net.minecraft.client.network.ClientPlayerEntity;
 import net.minecraft.client.network.ClientPlayerEntity;
 import net.minecraft.client.render.Tessellator;
 import net.minecraft.client.render.Tessellator;
 import net.minecraft.client.render.VertexConsumerProvider;
 import net.minecraft.client.render.VertexConsumerProvider;
@@ -359,8 +358,23 @@ public class EntryListWidget extends WidgetWithBounds {
                 }
                 }
             }
             }
         }
         }
-        if (containsMouse(mouseX, mouseY) && ClientHelper.getInstance().isCheating() && !minecraft.player.inventory.getCursorStack().isEmpty() && RoughlyEnoughItemsCore.hasPermissionToUsePackets())
+        if (containsMouse(mouseX, mouseY) && ClientHelper.getInstance().isCheating() && !minecraft.player.inventory.getCursorStack().isEmpty() && RoughlyEnoughItemsCore.canDeleteItems()) {
+            EntryStack stack = EntryStack.create(minecraft.player.inventory.getCursorStack().copy());
+            if (stack.getType() == EntryStack.Type.FLUID) {
+                Item bucketItem = stack.getFluid().getBucketItem();
+                if (bucketItem != null) {
+                    stack = EntryStack.create(bucketItem);
+                }
+            }
+            for (Widget child : children()) {
+                if (child.containsMouse(mouseX, mouseY) && child instanceof EntryWidget) {
+                    if (((EntryWidget) child).cancelDeleteItems(stack)) {
+                        return;
+                    }
+                }
+            }
             Tooltip.create(new TranslatableText("text.rei.delete_items")).queue();
             Tooltip.create(new TranslatableText("text.rei.delete_items")).queue();
+        }
     }
     }
     
     
     private int getScrollbarMinX() {
     private int getScrollbarMinX() {
@@ -553,74 +567,37 @@ public class EntryListWidget extends WidgetWithBounds {
             if (scrolling.updateDraggingState(double_1, double_2, int_1))
             if (scrolling.updateDraggingState(double_1, double_2, int_1))
                 return true;
                 return true;
         }
         }
-        
-        if (containsMouse(double_1, double_2)) {
+        for (Widget widget : children())
+            if (widget.mouseClicked(double_1, double_2, int_1))
+                return true;
+        return false;
+    }
+    
+    @Override
+    public boolean mouseReleased(double mouseX, double mouseY, int button) {
+        if (containsMouse(mouseX, mouseY)) {
+            for (Widget widget : children())
+                if (widget.mouseReleased(mouseX, mouseY, button))
+                    return true;
             ClientPlayerEntity player = minecraft.player;
             ClientPlayerEntity player = minecraft.player;
-            if (ClientHelper.getInstance().isCheating() && !player.inventory.getCursorStack().isEmpty() && RoughlyEnoughItemsCore.hasPermissionToUsePackets()) {
+            if (ClientHelper.getInstance().isCheating() && !player.inventory.getCursorStack().isEmpty() && RoughlyEnoughItemsCore.canDeleteItems()) {
                 ClientHelper.getInstance().sendDeletePacket();
                 ClientHelper.getInstance().sendDeletePacket();
                 return true;
                 return true;
             }
             }
             if (!player.inventory.getCursorStack().isEmpty() && RoughlyEnoughItemsCore.hasPermissionToUsePackets())
             if (!player.inventory.getCursorStack().isEmpty() && RoughlyEnoughItemsCore.hasPermissionToUsePackets())
                 return false;
                 return false;
-            for (Widget widget : children())
-                if (widget.mouseClicked(double_1, double_2, int_1))
-                    return true;
         }
         }
         return false;
         return false;
     }
     }
     
     
-    private class EntryListEntry extends EntryWidget {
-        private int backupY;
-        
+    private class EntryListEntry extends EntryListEntryWidget {
         private EntryListEntry(int x, int y) {
         private EntryListEntry(int x, int y) {
             super(new Point(x, y));
             super(new Point(x, y));
-            this.backupY = y;
-            getBounds().width = getBounds().height = entrySize();
-        }
-        
-        @Override
-        public void drawBackground(MatrixStack matrices, int mouseX, int mouseY, float delta) {
-            super.drawBackground(matrices, mouseX, mouseY, delta);
         }
         }
         
         
         @Override
         @Override
         public boolean containsMouse(double mouseX, double mouseY) {
         public boolean containsMouse(double mouseX, double mouseY) {
             return super.containsMouse(mouseX, mouseY) && bounds.contains(mouseX, mouseY);
             return super.containsMouse(mouseX, mouseY) && bounds.contains(mouseX, mouseY);
         }
         }
-        
-        @Override
-        public void drawHighlighted(MatrixStack matrices, int mouseX, int mouseY, float delta) {
-            if (getCurrentEntry().getType() != EntryStack.Type.EMPTY)
-                super.drawHighlighted(matrices, mouseX, mouseY, delta);
-        }
-        
-        @Override
-        public void queueTooltip(MatrixStack matrices, int mouseX, int mouseY, float delta) {
-            if (!ClientHelper.getInstance().isCheating() || minecraft.player.inventory.getCursorStack().isEmpty()) {
-                super.queueTooltip(matrices, mouseX, mouseY, delta);
-            }
-        }
-        
-        @Override
-        public boolean mouseClicked(double mouseX, double mouseY, int button) {
-            if (!interactable)
-                return super.mouseClicked(mouseX, mouseY, button);
-            if (containsMouse(mouseX, mouseY) && ClientHelper.getInstance().isCheating()) {
-                EntryStack entry = getCurrentEntry().copy();
-                if (!entry.isEmpty()) {
-                    if (entry.getType() == EntryStack.Type.FLUID) {
-                        Item bucketItem = entry.getFluid().getBucketItem();
-                        if (bucketItem != null) {
-                            entry = EntryStack.create(bucketItem);
-                        }
-                    }
-                    if (entry.getType() == EntryStack.Type.ITEM)
-                        entry.setAmount(button != 1 && !Screen.hasShiftDown() ? 1 : entry.getItemStack().getMaxCount());
-                    ClientHelper.getInstance().tryCheatingEntry(entry);
-                    return true;
-                }
-            }
-            return super.mouseClicked(mouseX, mouseY, button);
-        }
     }
     }
 }
 }

+ 6 - 1
src/main/java/me/shedaniel/rei/gui/widget/EntryWidget.java

@@ -349,7 +349,7 @@ public class EntryWidget extends Slot {
     }
     }
     
     
     @Override
     @Override
-    public boolean mouseClicked(double mouseX, double mouseY, int button) {
+    public boolean mouseReleased(double mouseX, double mouseY, int button) {
         if (!interactable)
         if (!interactable)
             return false;
             return false;
         if (containsMouse(mouseX, mouseY)) {
         if (containsMouse(mouseX, mouseY)) {
@@ -361,6 +361,11 @@ public class EntryWidget extends Slot {
         return false;
         return false;
     }
     }
     
     
+    @ApiStatus.Internal
+    protected boolean cancelDeleteItems(EntryStack stack) {
+        return false;
+    }
+    
     protected boolean reverseFavoritesAction() {
     protected boolean reverseFavoritesAction() {
         return false;
         return false;
     }
     }

+ 32 - 48
src/main/java/me/shedaniel/rei/gui/widget/FavoritesListWidget.java

@@ -37,8 +37,9 @@ import me.shedaniel.rei.api.widgets.Tooltip;
 import me.shedaniel.rei.gui.config.EntryPanelOrdering;
 import me.shedaniel.rei.gui.config.EntryPanelOrdering;
 import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.utils.CollectionUtils;
 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.MinecraftClient;
-import net.minecraft.client.gui.screen.Screen;
 import net.minecraft.client.network.ClientPlayerEntity;
 import net.minecraft.client.network.ClientPlayerEntity;
 import net.minecraft.client.util.math.MatrixStack;
 import net.minecraft.client.util.math.MatrixStack;
 import net.minecraft.item.Item;
 import net.minecraft.item.Item;
@@ -134,8 +135,23 @@ public class FavoritesListWidget extends WidgetWithBounds {
         updatePosition(delta);
         updatePosition(delta);
         scrolling.renderScrollBar(0, 1, REIHelper.getInstance().isDarkThemeEnabled() ? 0.8f : 1f);
         scrolling.renderScrollBar(0, 1, REIHelper.getInstance().isDarkThemeEnabled() ? 0.8f : 1f);
         ScissorsHandler.INSTANCE.removeLastScissor();
         ScissorsHandler.INSTANCE.removeLastScissor();
-        if (containsMouse(mouseX, mouseY) && ClientHelper.getInstance().isCheating() && !minecraft.player.inventory.getCursorStack().isEmpty() && RoughlyEnoughItemsCore.hasPermissionToUsePackets())
+        if (containsMouse(mouseX, mouseY) && ClientHelper.getInstance().isCheating() && !minecraft.player.inventory.getCursorStack().isEmpty() && RoughlyEnoughItemsCore.canDeleteItems()) {
+            EntryStack stack = EntryStack.create(minecraft.player.inventory.getCursorStack().copy());
+            if (stack.getType() == EntryStack.Type.FLUID) {
+                Item bucketItem = stack.getFluid().getBucketItem();
+                if (bucketItem != null) {
+                    stack = EntryStack.create(bucketItem);
+                }
+            }
+            for (Widget child : children()) {
+                if (child.containsMouse(mouseX, mouseY) && child instanceof EntryWidget) {
+                    if (((EntryWidget) child).cancelDeleteItems(stack)) {
+                        return;
+                    }
+                }
+            }
             Tooltip.create(new TranslatableText("text.rei.delete_items")).queue();
             Tooltip.create(new TranslatableText("text.rei.delete_items")).queue();
+        }
     }
     }
     
     
     @Override
     @Override
@@ -243,29 +259,32 @@ public class FavoritesListWidget extends WidgetWithBounds {
     public boolean mouseClicked(double double_1, double double_2, int int_1) {
     public boolean mouseClicked(double double_1, double double_2, int int_1) {
         if (scrolling.updateDraggingState(double_1, double_2, int_1))
         if (scrolling.updateDraggingState(double_1, double_2, int_1))
             return true;
             return true;
-        
-        if (containsMouse(double_1, double_2)) {
+        for (Widget widget : children())
+            if (widget.mouseClicked(double_1, double_2, int_1))
+                return true;
+        return false;
+    }
+    
+    @Override
+    public boolean mouseReleased(double mouseX, double mouseY, int button) {
+        if (containsMouse(mouseX, mouseY)) {
+            for (Widget widget : children())
+                if (widget.mouseReleased(mouseX, mouseY, button))
+                    return true;
             ClientPlayerEntity player = minecraft.player;
             ClientPlayerEntity player = minecraft.player;
-            if (ClientHelper.getInstance().isCheating() && !player.inventory.getCursorStack().isEmpty() && RoughlyEnoughItemsCore.hasPermissionToUsePackets()) {
+            if (ClientHelper.getInstance().isCheating() && !player.inventory.getCursorStack().isEmpty() && RoughlyEnoughItemsCore.canDeleteItems()) {
                 ClientHelper.getInstance().sendDeletePacket();
                 ClientHelper.getInstance().sendDeletePacket();
                 return true;
                 return true;
             }
             }
             if (!player.inventory.getCursorStack().isEmpty() && RoughlyEnoughItemsCore.hasPermissionToUsePackets())
             if (!player.inventory.getCursorStack().isEmpty() && RoughlyEnoughItemsCore.hasPermissionToUsePackets())
                 return false;
                 return false;
-            for (Widget widget : children())
-                if (widget.mouseClicked(double_1, double_2, int_1))
-                    return true;
         }
         }
         return false;
         return false;
     }
     }
     
     
-    private class EntryListEntry extends EntryWidget {
-        private int backupY;
-        
+    private class EntryListEntry extends EntryListEntryWidget {
         private EntryListEntry(int x, int y) {
         private EntryListEntry(int x, int y) {
             super(new Point(x, y));
             super(new Point(x, y));
-            this.backupY = y;
-            getBounds().width = getBounds().height = entrySize();
         }
         }
         
         
         @Override
         @Override
@@ -273,44 +292,9 @@ public class FavoritesListWidget extends WidgetWithBounds {
             return super.containsMouse(mouseX, mouseY) && bounds.contains(mouseX, mouseY);
             return super.containsMouse(mouseX, mouseY) && bounds.contains(mouseX, mouseY);
         }
         }
         
         
-        @Override
-        protected void drawHighlighted(MatrixStack matrices, int mouseX, int mouseY, float delta) {
-            if (!getCurrentEntry().isEmpty())
-                super.drawHighlighted(matrices, mouseX, mouseY, delta);
-        }
-        
         @Override
         @Override
         protected boolean reverseFavoritesAction() {
         protected boolean reverseFavoritesAction() {
             return true;
             return true;
         }
         }
-        
-        @Override
-        public void queueTooltip(MatrixStack matrices, int mouseX, int mouseY, float delta) {
-            if (!ClientHelper.getInstance().isCheating() || minecraft.player.inventory.getCursorStack().isEmpty()) {
-                super.queueTooltip(matrices, mouseX, mouseY, delta);
-            }
-        }
-        
-        @Override
-        public boolean mouseClicked(double mouseX, double mouseY, int button) {
-            if (!interactable)
-                return super.mouseClicked(mouseX, mouseY, button);
-            if (containsMouse(mouseX, mouseY) && ClientHelper.getInstance().isCheating()) {
-                EntryStack entry = getCurrentEntry().copy();
-                if (!entry.isEmpty()) {
-                    if (entry.getType() == EntryStack.Type.FLUID) {
-                        Item bucketItem = entry.getFluid().getBucketItem();
-                        if (bucketItem != null) {
-                            entry = EntryStack.create(bucketItem);
-                        }
-                    }
-                    if (entry.getType() == EntryStack.Type.ITEM)
-                        entry.setAmount(button != 1 && !Screen.hasShiftDown() ? 1 : entry.getItemStack().getMaxCount());
-                    ClientHelper.getInstance().tryCheatingEntry(entry);
-                    return true;
-                }
-            }
-            return super.mouseClicked(mouseX, mouseY, button);
-        }
     }
     }
 }
 }

+ 19 - 3
src/main/java/me/shedaniel/rei/impl/ClientHelperImpl.java

@@ -34,6 +34,8 @@ import me.shedaniel.rei.gui.RecipeViewingScreen;
 import me.shedaniel.rei.gui.VillagerRecipeViewingScreen;
 import me.shedaniel.rei.gui.VillagerRecipeViewingScreen;
 import me.shedaniel.rei.gui.config.RecipeScreenType;
 import me.shedaniel.rei.gui.config.RecipeScreenType;
 import net.fabricmc.api.ClientModInitializer;
 import net.fabricmc.api.ClientModInitializer;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
 import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
 import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
 import net.fabricmc.loader.api.FabricLoader;
 import net.fabricmc.loader.api.FabricLoader;
 import net.fabricmc.loader.api.ModContainer;
 import net.fabricmc.loader.api.ModContainer;
@@ -42,6 +44,7 @@ import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.gui.screen.Screen;
 import net.minecraft.client.gui.screen.Screen;
 import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
 import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
 import net.minecraft.client.util.NarratorManager;
 import net.minecraft.client.util.NarratorManager;
+import net.minecraft.entity.player.PlayerInventory;
 import net.minecraft.item.Item;
 import net.minecraft.item.Item;
 import net.minecraft.item.ItemStack;
 import net.minecraft.item.ItemStack;
 import net.minecraft.item.Items;
 import net.minecraft.item.Items;
@@ -52,6 +55,7 @@ import net.minecraft.text.TranslatableText;
 import net.minecraft.util.Formatting;
 import net.minecraft.util.Formatting;
 import net.minecraft.util.Identifier;
 import net.minecraft.util.Identifier;
 import net.minecraft.util.Lazy;
 import net.minecraft.util.Lazy;
+import net.minecraft.util.math.MathHelper;
 import net.minecraft.util.registry.Registry;
 import net.minecraft.util.registry.Registry;
 import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.NotNull;
@@ -61,6 +65,7 @@ import java.time.LocalDateTime;
 import java.util.*;
 import java.util.*;
 
 
 @ApiStatus.Internal
 @ApiStatus.Internal
+@Environment(EnvType.CLIENT)
 public class ClientHelperImpl implements ClientHelper, ClientModInitializer {
 public class ClientHelperImpl implements ClientHelper, ClientModInitializer {
     
     
     private static ClientHelperImpl instance;
     private static ClientHelperImpl instance;
@@ -139,8 +144,9 @@ public class ClientHelperImpl implements ClientHelper, ClientModInitializer {
     
     
     @Override
     @Override
     public void sendDeletePacket() {
     public void sendDeletePacket() {
-        if (REIHelper.getInstance().getPreviousContainerScreen() instanceof CreativeInventoryScreen) {
+        if (MinecraftClient.getInstance().currentScreen instanceof CreativeInventoryScreen) {
             MinecraftClient.getInstance().player.inventory.setCursorStack(ItemStack.EMPTY);
             MinecraftClient.getInstance().player.inventory.setCursorStack(ItemStack.EMPTY);
+            ((CreativeInventoryScreen) MinecraftClient.getInstance().currentScreen).isCursorDragging = false;
             return;
             return;
         }
         }
         ClientSidePacketRegistry.INSTANCE.sendToServer(RoughlyEnoughItemsNetwork.DELETE_ITEMS_PACKET, new PacketByteBuf(Unpooled.buffer()));
         ClientSidePacketRegistry.INSTANCE.sendToServer(RoughlyEnoughItemsNetwork.DELETE_ITEMS_PACKET, new PacketByteBuf(Unpooled.buffer()));
@@ -151,9 +157,19 @@ public class ClientHelperImpl implements ClientHelper, ClientModInitializer {
         if (entry.getType() != EntryStack.Type.ITEM)
         if (entry.getType() != EntryStack.Type.ITEM)
             return false;
             return false;
         ItemStack cheatedStack = entry.getItemStack().copy();
         ItemStack cheatedStack = entry.getItemStack().copy();
-        if (RoughlyEnoughItemsCore.canUsePackets()) {
+        if (ConfigObject.getInstance().isGrabbingItems() && MinecraftClient.getInstance().currentScreen instanceof CreativeInventoryScreen) {
+            PlayerInventory inventory = MinecraftClient.getInstance().player.inventory;
+            EntryStack stack = entry.copy();
+            if (!inventory.getCursorStack().isEmpty() && EntryStack.create(inventory.getCursorStack()).equalsIgnoreAmount(stack)) {
+                stack.setAmount(MathHelper.clamp(stack.getAmount() + inventory.getCursorStack().getCount(), 1, stack.getItemStack().getMaxCount()));
+            } else if (!inventory.getCursorStack().isEmpty()) {
+                return false;
+            }
+            inventory.setCursorStack(stack.getItemStack().copy());
+            return true;
+        } else if (RoughlyEnoughItemsCore.canUsePackets()) {
             try {
             try {
-                ClientSidePacketRegistry.INSTANCE.sendToServer(RoughlyEnoughItemsNetwork.CREATE_ITEMS_PACKET, new PacketByteBuf(Unpooled.buffer()).writeItemStack(cheatedStack));
+                ClientSidePacketRegistry.INSTANCE.sendToServer(ConfigObject.getInstance().isGrabbingItems() ? RoughlyEnoughItemsNetwork.CREATE_ITEMS_GRAB_PACKET : RoughlyEnoughItemsNetwork.CREATE_ITEMS_PACKET, new PacketByteBuf(Unpooled.buffer()).writeItemStack(cheatedStack));
                 return true;
                 return true;
             } catch (Exception e) {
             } catch (Exception e) {
                 return false;
                 return false;

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

@@ -32,6 +32,8 @@ import me.shedaniel.clothconfig2.api.ModifierKeyCode;
 import me.shedaniel.rei.api.ConfigObject;
 import me.shedaniel.rei.api.ConfigObject;
 import me.shedaniel.rei.api.EntryStack;
 import me.shedaniel.rei.api.EntryStack;
 import me.shedaniel.rei.gui.config.*;
 import me.shedaniel.rei.gui.config.*;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
 import net.minecraft.client.util.InputUtil;
 import net.minecraft.client.util.InputUtil;
 import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.ApiStatus;
 
 
@@ -44,6 +46,7 @@ import java.util.List;
 
 
 @ApiStatus.Internal
 @ApiStatus.Internal
 @Config(name = "roughlyenoughitems/config")
 @Config(name = "roughlyenoughitems/config")
+@Environment(EnvType.CLIENT)
 public class ConfigObjectImpl implements ConfigObject, ConfigData {
 public class ConfigObjectImpl implements ConfigObject, ConfigData {
     
     
     @ConfigEntry.Category("basics") @ConfigEntry.Gui.TransitiveObject @DontApplyFieldName
     @ConfigEntry.Category("basics") @ConfigEntry.Gui.TransitiveObject @DontApplyFieldName
@@ -90,6 +93,11 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData {
         return appearance.theme == AppearanceTheme.DARK;
         return appearance.theme == AppearanceTheme.DARK;
     }
     }
     
     
+    @Override
+    public boolean isGrabbingItems() {
+        return basics.cheatingStyle == ItemCheatingStyle.GRAB;
+    }
+    
     @Override
     @Override
     public boolean isToastDisplayedOnCopyIdentifier() {
     public boolean isToastDisplayedOnCopyIdentifier() {
         return advanced.accessibility.toastDisplayedOnCopyIdentifier;
         return advanced.accessibility.toastDisplayedOnCopyIdentifier;
@@ -351,6 +359,8 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData {
         @ConfigEntry.Gui.CollapsibleObject(startExpanded = true)
         @ConfigEntry.Gui.CollapsibleObject(startExpanded = true)
         private KeyBindings keyBindings = new KeyBindings();
         private KeyBindings keyBindings = new KeyBindings();
         @Comment("Declares whether REI is visible.") @ConfigEntry.Gui.Excluded private boolean overlayVisible = true;
         @Comment("Declares whether REI is visible.") @ConfigEntry.Gui.Excluded private boolean overlayVisible = true;
+        @ConfigEntry.Gui.EnumHandler(option = ConfigEntry.Gui.EnumHandler.EnumDisplayOption.BUTTON)
+        private ItemCheatingStyle cheatingStyle = ItemCheatingStyle.GRAB;
     }
     }
     
     
     public static class KeyBindings {
     public static class KeyBindings {

+ 4 - 0
src/main/resources/assets/roughlyenoughitems/lang/en_us.json

@@ -5,6 +5,7 @@
   "text.rei.cheating_enabled": "§cCheating Enabled",
   "text.rei.cheating_enabled": "§cCheating Enabled",
   "text.rei.cheating_limited_enabled": "§bCheating Enabled (Using Commands)",
   "text.rei.cheating_limited_enabled": "§bCheating Enabled (Using Commands)",
   "text.rei.cheating_enabled_no_perms": "§7Cheating §cEnabled §7(No Permission)",
   "text.rei.cheating_enabled_no_perms": "§7Cheating §cEnabled §7(No Permission)",
+  "text.rei.cheating_limited_creative_enabled": "§aCheating Enabled (Using Creative)",
   "text.rei.no_permission_cheat": "Operator permissions are required to cheat items",
   "text.rei.no_permission_cheat": "Operator permissions are required to cheat items",
   "text.rei.search.field.suggestion": "Search...",
   "text.rei.search.field.suggestion": "Search...",
   "category.rei.crafting": "Crafting",
   "category.rei.crafting": "Crafting",
@@ -118,6 +119,9 @@
   "config.roughlyenoughitems.keyBindings.copyRecipeIdentifierKeybind": "Copy Recipe Identifier:",
   "config.roughlyenoughitems.keyBindings.copyRecipeIdentifierKeybind": "Copy Recipe Identifier:",
   "config.roughlyenoughitems.keyBindings.exportImageKeybind": "Export Recipe:",
   "config.roughlyenoughitems.keyBindings.exportImageKeybind": "Export Recipe:",
   "config.roughlyenoughitems.keyBindings.favoriteKeybind": "Favorite Entry:",
   "config.roughlyenoughitems.keyBindings.favoriteKeybind": "Favorite Entry:",
+  "config.roughlyenoughitems.cheatingStyle": "Cheating Style:",
+  "config.roughlyenoughitems.cheatingStyle.grab": "Grab",
+  "config.roughlyenoughitems.cheatingStyle.give": "Give",
   "config.roughlyenoughitems.recipeScreenType": "Recipe Screen Type:",
   "config.roughlyenoughitems.recipeScreenType": "Recipe Screen Type:",
   "config.roughlyenoughitems.recipeScreenType.config": "Recipe Screen Type: %s",
   "config.roughlyenoughitems.recipeScreenType.config": "Recipe Screen Type: %s",
   "config.roughlyenoughitems.recipeScreenType.unset": "Not Set",
   "config.roughlyenoughitems.recipeScreenType.unset": "Not Set",

+ 1 - 0
src/main/resources/rei.aw

@@ -9,6 +9,7 @@ accessible field net/minecraft/client/gui/screen/ingame/ContainerScreen y I
 accessible field net/minecraft/client/gui/screen/ingame/ContainerScreen containerWidth I
 accessible field net/minecraft/client/gui/screen/ingame/ContainerScreen containerWidth I
 accessible field net/minecraft/client/gui/screen/ingame/ContainerScreen containerHeight I
 accessible field net/minecraft/client/gui/screen/ingame/ContainerScreen containerHeight I
 accessible field net/minecraft/client/gui/screen/ingame/ContainerScreen focusedSlot Lnet/minecraft/screen/slot/Slot;
 accessible field net/minecraft/client/gui/screen/ingame/ContainerScreen focusedSlot Lnet/minecraft/screen/slot/Slot;
+accessible field net/minecraft/client/gui/screen/ingame/ContainerScreen isCursorDragging Z
 accessible field net/minecraft/client/gui/widget/TexturedButtonWidget texture Lnet/minecraft/util/Identifier;
 accessible field net/minecraft/client/gui/widget/TexturedButtonWidget texture Lnet/minecraft/util/Identifier;
 accessible method net/minecraft/client/gui/DrawableHelper drawTexturedQuad (Lnet/minecraft/util/math/Matrix4f;IIIIIFFFF)V
 accessible method net/minecraft/client/gui/DrawableHelper drawTexturedQuad (Lnet/minecraft/util/math/Matrix4f;IIIIIFFFF)V
 accessible field net/minecraft/recipe/SmithingRecipe base Lnet/minecraft/recipe/Ingredient;
 accessible field net/minecraft/recipe/SmithingRecipe base Lnet/minecraft/recipe/Ingredient;