Przeglądaj źródła

Improved Auto Crafting System

Unknown 5 lat temu
rodzic
commit
4edf69caca

+ 37 - 0
src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java

@@ -22,14 +22,22 @@ import net.fabricmc.loader.api.FabricLoader;
 import net.fabricmc.loader.api.ModContainer;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.gui.Element;
+import net.minecraft.client.gui.screen.Screen;
 import net.minecraft.client.gui.screen.ingame.AbstractContainerScreen;
+import net.minecraft.client.gui.screen.ingame.CraftingTableScreen;
 import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
 import net.minecraft.client.gui.screen.ingame.InventoryScreen;
+import net.minecraft.client.gui.screen.recipebook.RecipeBookGhostSlots;
+import net.minecraft.client.gui.screen.recipebook.RecipeBookProvider;
 import net.minecraft.client.gui.screen.recipebook.RecipeBookWidget;
 import net.minecraft.client.gui.widget.TextFieldWidget;
 import net.minecraft.client.gui.widget.TexturedButtonWidget;
 import net.minecraft.client.resource.language.I18n;
+import net.minecraft.container.CraftingTableContainer;
+import net.minecraft.container.Slot;
 import net.minecraft.item.ItemStack;
+import net.minecraft.item.Items;
+import net.minecraft.recipe.Ingredient;
 import net.minecraft.text.LiteralText;
 import net.minecraft.util.ActionResult;
 import net.minecraft.util.Identifier;
@@ -141,6 +149,35 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer {
             String player = packetByteBuf.readString(32767);
             packetContext.getPlayer().addChatMessage(new LiteralText(I18n.translate("text.rei.cheat_items").replaceAll("\\{item_name}", ItemListOverlay.tryGetItemStackName(stack.copy())).replaceAll("\\{item_count}", stack.copy().getCount() + "").replaceAll("\\{player_name}", player)), false);
         });
+        ClientSidePacketRegistry.INSTANCE.register(RoughlyEnoughItemsNetwork.NOT_ENOUGH_ITEMS_PACKET, (packetContext, packetByteBuf) -> {
+            Screen currentScreen = MinecraftClient.getInstance().currentScreen;
+            if (currentScreen instanceof CraftingTableScreen) {
+                RecipeBookWidget recipeBookGui = ((RecipeBookProvider) currentScreen).getRecipeBookGui();
+                RecipeBookGhostSlots ghostSlots = ((RecipeBookGuiHooks) recipeBookGui).rei_getGhostSlots();
+                ghostSlots.reset();
+                
+                List<List<ItemStack>> input = Lists.newArrayList();
+                int mapSize = packetByteBuf.readInt();
+                for (int i = 0; i < mapSize; i++) {
+                    List<ItemStack> list = Lists.newArrayList();
+                    int count = packetByteBuf.readInt();
+                    for (int j = 0; j < count; j++) {
+                        list.add(packetByteBuf.readItemStack());
+                    }
+                    input.add(list);
+                }
+                
+                ghostSlots.addSlot(Ingredient.ofItems(Items.STONE), 381203812, 12738291);
+                CraftingTableContainer container = ((CraftingTableScreen) currentScreen).getContainer();
+                for (int i = 0; i < input.size(); i++) {
+                    List<ItemStack> stacks = input.get(i);
+                    if (!stacks.isEmpty()) {
+                        Slot slot = container.getSlot(i + container.getCraftingResultSlotIndex() + 1);
+                        ghostSlots.addSlot(Ingredient.ofStacks(stacks.toArray(new ItemStack[0])), slot.xPosition, slot.yPosition);
+                    }
+                }
+            }
+        });
     }
     
     @SuppressWarnings("deprecation")

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

@@ -5,9 +5,14 @@
 
 package me.shedaniel.rei;
 
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 import io.netty.buffer.Unpooled;
+import me.shedaniel.rei.server.InputSlotCrafter;
 import net.fabricmc.api.ModInitializer;
 import net.fabricmc.fabric.api.network.ServerSidePacketRegistry;
+import net.minecraft.container.CraftingContainer;
+import net.minecraft.container.PlayerContainer;
 import net.minecraft.item.ItemStack;
 import net.minecraft.server.network.ServerPlayerEntity;
 import net.minecraft.text.TranslatableText;
@@ -15,11 +20,19 @@ import net.minecraft.util.Formatting;
 import net.minecraft.util.Identifier;
 import net.minecraft.util.PacketByteBuf;
 
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
 public class RoughlyEnoughItemsNetwork implements ModInitializer {
     
     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_MESSAGE_PACKET = new Identifier("roughlyenoughitems", "ci_msg");
+    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 UUID CRAFTING_TABLE_MOVE = UUID.fromString("190c2b2d-d1f6-4149-a4a8-62860189403e");
     
     @Override
     public void onInitialize() {
@@ -44,6 +57,45 @@ public class RoughlyEnoughItemsNetwork implements ModInitializer {
             } else
                 player.addChatMessage(new TranslatableText("text.rei.failed_cheat_items"), false);
         });
+        ServerSidePacketRegistry.INSTANCE.register(MOVE_ITEMS_PACKET, (packetContext, packetByteBuf) -> {
+            UUID type = packetByteBuf.readUuid();
+            ServerPlayerEntity player = (ServerPlayerEntity) packetContext.getPlayer();
+            CraftingContainer container = (CraftingContainer) player.container;
+            PlayerContainer playerContainer = player.playerContainer;
+            if (type.equals(CRAFTING_TABLE_MOVE)) {
+                try {
+                    boolean shift = packetByteBuf.readBoolean();
+                    Map<Integer, List<ItemStack>> input = Maps.newHashMap();
+                    int mapSize = packetByteBuf.readInt();
+                    for (int i = 0; i < mapSize; i++) {
+                        List<ItemStack> list = Lists.newArrayList();
+                        int count = packetByteBuf.readInt();
+                        for (int j = 0; j < count; j++) {
+                            list.add(packetByteBuf.readItemStack());
+                        }
+                        input.put(i, list);
+                    }
+                    try {
+                        InputSlotCrafter.start(container, player, input, shift);
+                    } catch (NullPointerException e) {
+                        PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer());
+                        buf.writeInt(input.size());
+                        input.entrySet().stream().sorted(Comparator.comparingInt(Map.Entry::getKey)).forEach(entry -> {
+                            List<ItemStack> stacks = entry.getValue();
+                            buf.writeInt(stacks.size());
+                            for (ItemStack stack : stacks) {
+                                buf.writeItemStack(stack);
+                            }
+                        });
+                        if (ServerSidePacketRegistry.INSTANCE.canPlayerReceive(player, NOT_ENOUGH_ITEMS_PACKET)) {
+                            ServerSidePacketRegistry.INSTANCE.sendToPlayer(player, NOT_ENOUGH_ITEMS_PACKET, buf);
+                        }
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        });
     }
     
 }

+ 1 - 0
src/main/java/me/shedaniel/rei/plugin/DefaultAutoCraftingPlugin.java

@@ -46,6 +46,7 @@ public class DefaultAutoCraftingPlugin implements REIPluginV0 {
         recipeHelper.registerAutoCraftingHandler(new AutoFurnaceBookHandler());
         recipeHelper.registerAutoCraftingHandler(new AutoSmokerBookHandler());
         recipeHelper.registerAutoCraftingHandler(new AutoBlastingBookHandler());
+        recipeHelper.registerAutoCraftingHandler(new AutoCraftingTableHandler());
     }
     
 }

+ 114 - 0
src/main/java/me/shedaniel/rei/plugin/autocrafting/AutoCraftingTableHandler.java

@@ -0,0 +1,114 @@
+/*
+ * Roughly Enough Items by Danielshe.
+ * Licensed under the MIT License.
+ */
+
+package me.shedaniel.rei.plugin.autocrafting;
+
+import com.google.common.collect.Lists;
+import io.netty.buffer.Unpooled;
+import me.shedaniel.rei.RoughlyEnoughItemsNetwork;
+import me.shedaniel.rei.api.AutoCraftingHandler;
+import me.shedaniel.rei.api.RecipeDisplay;
+import me.shedaniel.rei.gui.ContainerScreenOverlay;
+import me.shedaniel.rei.listeners.RecipeBookGuiHooks;
+import me.shedaniel.rei.plugin.crafting.DefaultCraftingCategory;
+import me.shedaniel.rei.plugin.crafting.DefaultCraftingDisplay;
+import me.shedaniel.rei.plugin.crafting.DefaultShapedDisplay;
+import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.client.gui.screen.ingame.AbstractContainerScreen;
+import net.minecraft.client.gui.screen.ingame.CraftingTableScreen;
+import net.minecraft.client.gui.screen.recipebook.RecipeBookProvider;
+import net.minecraft.container.CraftingContainer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.DefaultedList;
+import net.minecraft.util.PacketByteBuf;
+
+import java.util.List;
+import java.util.function.Supplier;
+
+public class AutoCraftingTableHandler implements AutoCraftingHandler {
+    @Override
+    public boolean handle(Supplier<RecipeDisplay> displaySupplier, MinecraftClient minecraft, Screen recipeViewingScreen, AbstractContainerScreen<?> parentScreen, ContainerScreenOverlay overlay) {
+        minecraft.openScreen(parentScreen);
+        ((RecipeBookGuiHooks) ((RecipeBookProvider) parentScreen).getRecipeBookGui()).rei_getGhostSlots().reset();
+        DefaultCraftingDisplay display = (DefaultCraftingDisplay) displaySupplier.get();
+        PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer());
+        buf.writeUuid(RoughlyEnoughItemsNetwork.CRAFTING_TABLE_MOVE);
+        buf.writeBoolean(Screen.hasShiftDown());
+        CraftingContainer craftingContainer = (CraftingContainer) parentScreen.getContainer();
+        
+        List<List<ItemStack>> ogInput = display.getInput();
+        List<List<ItemStack>> input = Lists.newArrayListWithCapacity(craftingContainer.getCraftingWidth() * craftingContainer.getCraftingHeight());
+        for (int i = 0; i < craftingContainer.getCraftingWidth() * craftingContainer.getCraftingHeight(); i++) {
+            input.add(Lists.newArrayList());
+        }
+        for (int i = 0; i < ogInput.size(); i++) {
+            List<ItemStack> ogStacks = ogInput.get(i);
+            if (display instanceof DefaultShapedDisplay) {
+                if (!ogInput.get(i).isEmpty())
+                    input.set(DefaultCraftingCategory.getSlotWithSize(display, i), ogInput.get(i));
+            } else if (!ogInput.get(i).isEmpty())
+                input.set(i, ogInput.get(i));
+        }
+        
+        buf.writeInt(input.size());
+        for (List<ItemStack> stacks : input) {
+            buf.writeInt(stacks.size());
+            for (ItemStack stack : stacks) {
+                buf.writeItemStack(stack);
+            }
+        }
+        ClientSidePacketRegistry.INSTANCE.sendToServer(RoughlyEnoughItemsNetwork.MOVE_ITEMS_PACKET, buf);
+        return true;
+    }
+    
+    @Override
+    public boolean canHandle(Supplier<RecipeDisplay> displaySupplier, MinecraftClient minecraft, Screen recipeViewingScreen, AbstractContainerScreen<?> parentScreen, ContainerScreenOverlay overlay) {
+        if (parentScreen instanceof CraftingTableScreen && displaySupplier.get() instanceof DefaultCraftingDisplay && canUseMovePackets()) {
+            return hasItems(displaySupplier.get().getInput());
+        }
+        return false;
+    }
+    
+    @Override
+    public double getPriority() {
+        return -10;
+    }
+    
+    public boolean canUseMovePackets() {
+        return ClientSidePacketRegistry.INSTANCE.canServerReceive(RoughlyEnoughItemsNetwork.MOVE_ITEMS_PACKET);
+    }
+    
+    public boolean hasItems(List<List<ItemStack>> inputs) {
+        // Create a clone of player's inventory, and count
+        DefaultedList<ItemStack> copyMain = DefaultedList.create();
+        for (ItemStack stack : MinecraftClient.getInstance().player.inventory.main) {
+            copyMain.add(stack.copy());
+        }
+        for (List<ItemStack> possibleStacks : inputs) {
+            boolean done = possibleStacks.isEmpty();
+            for (ItemStack possibleStack : possibleStacks) {
+                if (!done) {
+                    int invRequiredCount = possibleStack.getCount();
+                    for (ItemStack stack : copyMain) {
+                        if (ItemStack.areItemsEqualIgnoreDamage(possibleStack, stack)) {
+                            while (invRequiredCount > 0 && !stack.isEmpty()) {
+                                invRequiredCount--;
+                                stack.decrement(1);
+                            }
+                        }
+                    }
+                    if (invRequiredCount <= 0) {
+                        done = true;
+                    }
+                }
+            }
+            if (!done)
+                return false;
+        }
+        return true;
+    }
+}

+ 1 - 1
src/main/java/me/shedaniel/rei/plugin/crafting/DefaultCraftingCategory.java

@@ -83,7 +83,7 @@ public class DefaultCraftingCategory implements RecipeCategory<DefaultCraftingDi
         return widgets;
     }
     
-    private int getSlotWithSize(DefaultCraftingDisplay recipeDisplay, int num) {
+    public static int getSlotWithSize(DefaultCraftingDisplay recipeDisplay, int num) {
         if (recipeDisplay.getWidth() == 1) {
             if (num == 1)
                 return 3;

+ 199 - 0
src/main/java/me/shedaniel/rei/server/InputSlotCrafter.java

@@ -0,0 +1,199 @@
+/*
+ * Roughly Enough Items by Danielshe.
+ * Licensed under the MIT License.
+ */
+
+package me.shedaniel.rei.server;
+
+import com.google.common.collect.Lists;
+import net.minecraft.container.CraftingContainer;
+import net.minecraft.container.CraftingTableContainer;
+import net.minecraft.container.PlayerContainer;
+import net.minecraft.container.Slot;
+import net.minecraft.entity.player.PlayerInventory;
+import net.minecraft.inventory.Inventory;
+import net.minecraft.item.ItemStack;
+import net.minecraft.recipe.RecipeFinder;
+import net.minecraft.server.network.ServerPlayerEntity;
+import net.minecraft.util.DefaultedList;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class InputSlotCrafter<C extends Inventory> {
+    
+    protected final RecipeFinder recipeFinder = new RecipeFinder();
+    protected CraftingContainer<C> craftingContainer;
+    protected PlayerInventory inventory;
+    
+    private InputSlotCrafter(CraftingContainer<C> craftingContainer_1) {
+        this.craftingContainer = craftingContainer_1;
+    }
+    
+    public static <C extends Inventory> void start(CraftingContainer<C> craftingContainer_1, ServerPlayerEntity player, Map<Integer, List<ItemStack>> map, boolean shifting) {
+        new InputSlotCrafter<C>(craftingContainer_1).fillInputSlots(player, map, shifting);
+    }
+    
+    private void fillInputSlots(ServerPlayerEntity player, Map<Integer, List<ItemStack>> map, boolean boolean_1) {
+        this.inventory = player.inventory;
+        if (this.canReturnInputs() || player.isCreative()) {
+            // Return the already placed items on the grid
+            this.returnInputs();
+            
+            if (!hasItems(map)) {
+                craftingContainer.sendContentUpdates();
+                player.inventory.markDirty();
+                throw new NullPointerException();
+            }
+            
+            map.entrySet().stream().sorted(Comparator.comparingInt(Map.Entry::getKey)).forEach(entry -> {
+                int id = entry.getKey().intValue();
+                List<ItemStack> possibleStacks = entry.getValue();
+                boolean done = false;
+                for (ItemStack possibleStack : possibleStacks) {
+                    int requiredCount = possibleStack.getCount();
+                    int invCount = 0;
+                    for (ItemStack stack : inventory.main) {
+                        if (ItemStack.areItemsEqualIgnoreDamage(possibleStack, stack))
+                            invCount += stack.getCount();
+                    }
+                    if (invCount >= requiredCount) {
+                        for (ItemStack stack : inventory.main) {
+                            if (ItemStack.areItemsEqualIgnoreDamage(possibleStack, stack)) {
+                                Slot containerSlot = craftingContainer.getSlot(id + craftingContainer.getCraftingResultSlotIndex() + 1);
+                                while (containerSlot.getStack().getCount() < requiredCount && !stack.isEmpty()) {
+                                    if (containerSlot.getStack().isEmpty()) {
+                                        containerSlot.setStack(new ItemStack(stack.getItem(), 1));
+                                    } else {
+                                        containerSlot.getStack().setCount(containerSlot.getStack().getCount() + 1);
+                                    }
+                                    stack.setCount(stack.getCount() - 1);
+                                }
+                                if (containerSlot.getStack().getCount() >= requiredCount)
+                                    break;
+                            }
+                        }
+                        break;
+                    }
+                }
+            });
+            
+            craftingContainer.sendContentUpdates();
+            player.inventory.markDirty();
+        }
+    }
+    
+    private boolean hasItems(Map<Integer, List<ItemStack>> map) {
+        // Create a clone of player's inventory, and count
+        DefaultedList<ItemStack> copyMain = DefaultedList.create();
+        for (ItemStack stack : inventory.main) {
+            copyMain.add(stack.copy());
+        }
+        for (Map.Entry<Integer, List<ItemStack>> entry : map.entrySet()) {
+            List<ItemStack> possibleStacks = entry.getValue();
+            boolean done = possibleStacks.isEmpty();
+            for (ItemStack possibleStack : possibleStacks) {
+                if (!done) {
+                    int invRequiredCount = possibleStack.getCount();
+                    for (ItemStack stack : copyMain) {
+                        if (ItemStack.areItemsEqualIgnoreDamage(possibleStack, stack)) {
+                            while (invRequiredCount > 0 && !stack.isEmpty()) {
+                                invRequiredCount--;
+                                stack.decrement(1);
+                            }
+                        }
+                    }
+                    if (invRequiredCount <= 0) {
+                        done = true;
+                    }
+                }
+            }
+            if (!done)
+                return false;
+        }
+        return true;
+    }
+    
+    protected void returnInputs() {
+        for (int int_1 = 0; int_1 < this.craftingContainer.getCraftingWidth() * this.craftingContainer.getCraftingHeight() + 1; ++int_1) {
+            if (int_1 != this.craftingContainer.getCraftingResultSlotIndex() || !(this.craftingContainer instanceof CraftingTableContainer) && !(this.craftingContainer instanceof PlayerContainer)) {
+                this.returnSlot(int_1);
+            }
+        }
+        
+        this.craftingContainer.clearCraftingSlots();
+    }
+    
+    protected void returnSlot(int int_1) {
+        ItemStack itemStack_1 = this.craftingContainer.getSlot(int_1).getStack();
+        if (!itemStack_1.isEmpty()) {
+            for (; itemStack_1.getCount() > 0; this.craftingContainer.getSlot(int_1).takeStack(1)) {
+                int int_2 = this.inventory.getOccupiedSlotWithRoomForStack(itemStack_1);
+                if (int_2 == -1) {
+                    int_2 = this.inventory.getEmptySlot();
+                }
+                
+                ItemStack itemStack_2 = itemStack_1.copy();
+                itemStack_2.setCount(1);
+                if (!this.inventory.insertStack(int_2, itemStack_2)) {
+                    throw new IllegalStateException("Can't find any space for item in the inventory");
+                }
+            }
+            
+        }
+    }
+    
+    private boolean canReturnInputs() {
+        List<ItemStack> list_1 = Lists.newArrayList();
+        int int_1 = this.getFreeInventorySlots();
+        
+        for (int int_2 = 0; int_2 < this.craftingContainer.getCraftingWidth() * this.craftingContainer.getCraftingHeight() + 1; ++int_2) {
+            if (int_2 != this.craftingContainer.getCraftingResultSlotIndex()) {
+                ItemStack itemStack_1 = this.craftingContainer.getSlot(int_2).getStack().copy();
+                if (!itemStack_1.isEmpty()) {
+                    int int_3 = this.inventory.getOccupiedSlotWithRoomForStack(itemStack_1);
+                    if (int_3 == -1 && list_1.size() <= int_1) {
+                        Iterator var6 = list_1.iterator();
+                        
+                        while (var6.hasNext()) {
+                            ItemStack itemStack_2 = (ItemStack) var6.next();
+                            if (itemStack_2.isItemEqualIgnoreDamage(itemStack_1) && itemStack_2.getCount() != itemStack_2.getMaxCount() && itemStack_2.getCount() + itemStack_1.getCount() <= itemStack_2.getMaxCount()) {
+                                itemStack_2.increment(itemStack_1.getCount());
+                                itemStack_1.setCount(0);
+                                break;
+                            }
+                        }
+                        
+                        if (!itemStack_1.isEmpty()) {
+                            if (list_1.size() >= int_1) {
+                                return false;
+                            }
+                            
+                            list_1.add(itemStack_1);
+                        }
+                    } else if (int_3 == -1) {
+                        return false;
+                    }
+                }
+            }
+        }
+        
+        return true;
+    }
+    
+    private int getFreeInventorySlots() {
+        int int_1 = 0;
+        Iterator var2 = this.inventory.main.iterator();
+        while (var2.hasNext()) {
+            ItemStack itemStack_1 = (ItemStack) var2.next();
+            if (itemStack_1.isEmpty()) {
+                ++int_1;
+            }
+        }
+        return int_1;
+    }
+    
+}