diff options
Diffstat (limited to 'src/main/java')
6 files changed, 404 insertions, 1 deletions
diff --git a/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java b/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java index ad910dcfd..030059d56 100644 --- a/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java +++ b/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") diff --git a/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java b/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java index 2ff54e890..18551ca81 100644 --- a/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java +++ b/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(); + } + } + }); } } diff --git a/src/main/java/me/shedaniel/rei/plugin/DefaultAutoCraftingPlugin.java b/src/main/java/me/shedaniel/rei/plugin/DefaultAutoCraftingPlugin.java index 956322a5f..a36caf122 100644 --- a/src/main/java/me/shedaniel/rei/plugin/DefaultAutoCraftingPlugin.java +++ b/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()); } } diff --git a/src/main/java/me/shedaniel/rei/plugin/autocrafting/AutoCraftingTableHandler.java b/src/main/java/me/shedaniel/rei/plugin/autocrafting/AutoCraftingTableHandler.java new file mode 100644 index 000000000..34e9bb3df --- /dev/null +++ b/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; + } +} diff --git a/src/main/java/me/shedaniel/rei/plugin/crafting/DefaultCraftingCategory.java b/src/main/java/me/shedaniel/rei/plugin/crafting/DefaultCraftingCategory.java index a52e34a93..031ddd8f1 100644 --- a/src/main/java/me/shedaniel/rei/plugin/crafting/DefaultCraftingCategory.java +++ b/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; diff --git a/src/main/java/me/shedaniel/rei/server/InputSlotCrafter.java b/src/main/java/me/shedaniel/rei/server/InputSlotCrafter.java new file mode 100644 index 000000000..d621383a0 --- /dev/null +++ b/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; + } + +} |
