diff options
Diffstat (limited to 'runtime')
14 files changed, 789 insertions, 140 deletions
diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java index 4104d5210..732ca00cd 100644 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java @@ -55,6 +55,7 @@ import me.shedaniel.rei.impl.common.logging.performance.PerformanceLoggerImpl; import me.shedaniel.rei.impl.common.plugins.PluginManagerImpl; import me.shedaniel.rei.impl.common.registry.RecipeManagerContextImpl; import me.shedaniel.rei.impl.common.transfer.MenuInfoRegistryImpl; +import me.shedaniel.rei.impl.common.transfer.SlotAccessorRegistryImpl; import me.shedaniel.rei.impl.init.PluginDetector; import me.shedaniel.rei.impl.init.PrimitivePlatformAdapter; import net.minecraft.resources.ResourceLocation; @@ -142,7 +143,8 @@ public class RoughlyEnoughItemsCore { Internals.attachInstanceSupplier(new PluginManagerImpl<>( REIServerPlugin.class, view -> view.then(PluginView.getInstance()), - new MenuInfoRegistryImpl()), "serverPluginManager"); + new MenuInfoRegistryImpl(), + new SlotAccessorRegistryImpl()), "serverPluginManager"); } public static void _reloadPlugins(@Nullable ReloadStage stage) { diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java index 5d5d53d8f..5874799a3 100644 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java @@ -81,6 +81,7 @@ import me.shedaniel.rei.impl.client.search.SearchProviderImpl; import me.shedaniel.rei.impl.client.search.SearchRuntime; import me.shedaniel.rei.impl.client.search.method.InputMethodRegistryImpl; import me.shedaniel.rei.impl.client.subsets.SubsetsRegistryImpl; +import me.shedaniel.rei.impl.client.transfer.SimpleTransferHandlerImpl; import me.shedaniel.rei.impl.client.transfer.TransferHandlerRegistryImpl; import me.shedaniel.rei.impl.client.view.ViewsImpl; import me.shedaniel.rei.impl.common.InternalLogger; @@ -159,6 +160,7 @@ public class RoughlyEnoughItemsCoreClient { ClientInternals.attachInstance((Function<Object, Tooltip.Entry>) QueuedTooltip.TooltipEntryImpl::new, "tooltipEntryProvider"); ClientInternals.attachInstance((BiFunction<Component, List<FavoriteMenuEntry>, FavoriteMenuEntry>) SubMenuEntry::new, "subMenuEntry"); ClientInternals.attachInstance((BiFunction<Component, BooleanValue, FavoriteMenuEntry>) (text, value) -> ToggleMenuEntry.of(text, value::get, value), "toggleEntry"); + ClientInternals.attachInstanceSupplier(SimpleTransferHandlerImpl.INSTANCE, "simpleTransferHandler"); ClientInternals.attachInstance((Function<@Nullable Boolean, ClickArea.Result>) successful -> new ClickArea.Result() { private List<CategoryIdentifier<?>> categories = Lists.newArrayList(); private BooleanSupplier execute = () -> { diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java index 64a433dbe..5e8e49475 100644 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java @@ -28,20 +28,35 @@ import dev.architectury.networking.transformers.SplitPacketTransformer; import io.netty.buffer.Unpooled; import me.shedaniel.rei.api.common.category.CategoryIdentifier; import me.shedaniel.rei.api.common.display.Display; +import me.shedaniel.rei.api.common.entry.EntryIngredient; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.entry.InputIngredient; +import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; +import me.shedaniel.rei.api.common.transfer.info.stack.SlotAccessor; +import me.shedaniel.rei.api.common.transfer.info.stack.SlotAccessorRegistry; import me.shedaniel.rei.impl.common.transfer.InputSlotCrafter; +import me.shedaniel.rei.impl.common.transfer.LegacyInputSlotCrafter; +import me.shedaniel.rei.impl.common.transfer.NewInputSlotCrafter; import net.minecraft.ChatFormatting; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.Mth; import net.minecraft.world.Container; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.InventoryMenu; import net.minecraft.world.inventory.RecipeBookMenu; import net.minecraft.world.item.ItemStack; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; +import java.util.Map; public class RoughlyEnoughItemsNetwork { public static final ResourceLocation DELETE_ITEMS_PACKET = new ResourceLocation("roughlyenoughitems", "delete_item"); @@ -50,6 +65,7 @@ public class RoughlyEnoughItemsNetwork { public static final ResourceLocation CREATE_ITEMS_GRAB_PACKET = new ResourceLocation("roughlyenoughitems", "create_item_grab"); public static final ResourceLocation CREATE_ITEMS_MESSAGE_PACKET = new ResourceLocation("roughlyenoughitems", "ci_msg"); public static final ResourceLocation MOVE_ITEMS_PACKET = new ResourceLocation("roughlyenoughitems", "move_items"); + public static final ResourceLocation MOVE_ITEMS_NEW_PACKET = new ResourceLocation("roughlyenoughitems", "move_items_new"); public static final ResourceLocation NOT_ENOUGH_ITEMS_PACKET = new ResourceLocation("roughlyenoughitems", "og_not_enough"); public static void onInitialize() { @@ -122,7 +138,7 @@ public class RoughlyEnoughItemsNetwork { try { boolean shift = packetByteBuf.readBoolean(); try { - InputSlotCrafter<AbstractContainerMenu, Container, Display> crafter = InputSlotCrafter.start(category, container, player, packetByteBuf.readAnySizeNbt(), shift); + LegacyInputSlotCrafter<AbstractContainerMenu, Container, Display> crafter = LegacyInputSlotCrafter.start(category, container, player, packetByteBuf.readAnySizeNbt(), shift); } catch (InputSlotCrafter.NotEnoughMaterialsException e) { if (!(container instanceof RecipeBookMenu)) { return; @@ -147,5 +163,50 @@ public class RoughlyEnoughItemsNetwork { e.printStackTrace(); } }); + NetworkManager.registerReceiver(NetworkManager.c2s(), MOVE_ITEMS_NEW_PACKET, Collections.singletonList(new SplitPacketTransformer()), (packetByteBuf, context) -> { + ServerPlayer player = (ServerPlayer) context.getPlayer(); + CategoryIdentifier<Display> category = CategoryIdentifier.of(packetByteBuf.readResourceLocation()); + AbstractContainerMenu container = player.containerMenu; + InventoryMenu playerContainer = player.inventoryMenu; + try { + boolean shift = packetByteBuf.readBoolean(); + try { + CompoundTag nbt = packetByteBuf.readAnySizeNbt(); + List<InputIngredient<ItemStack>> inputs = readInputs(nbt.getCompound("Inputs")); + List<SlotAccessor> input = readSlots(container, player, nbt.getList("InputSlots", Tag.TAG_COMPOUND)); + List<SlotAccessor> inventory = readSlots(container, player, nbt.getList("InventorySlots", Tag.TAG_COMPOUND)); + NewInputSlotCrafter<AbstractContainerMenu, Container> crafter = new NewInputSlotCrafter<>(container, input, inventory, inputs); + crafter.fillInputSlots(player, shift); + } catch (InputSlotCrafter.NotEnoughMaterialsException e) { + if (!(container instanceof RecipeBookMenu)) { + return; + } + } catch (IllegalStateException e) { + player.sendSystemMessage(Component.translatable(e.getMessage()).withStyle(ChatFormatting.RED)); + } catch (Exception e) { + player.sendSystemMessage(Component.translatable("error.rei.internal.error", e.getMessage()).withStyle(ChatFormatting.RED)); + e.printStackTrace(); + } + } catch (Exception e) { + e.printStackTrace(); + } + }); + } + + private static List<SlotAccessor> readSlots(AbstractContainerMenu menu, Player player, ListTag tag) { + List<SlotAccessor> slots = new ArrayList<>(); + for (Tag t : tag) { + slots.add(SlotAccessorRegistry.getInstance().read(menu, player, (CompoundTag) t)); + } + return slots; + } + + private static List<InputIngredient<ItemStack>> readInputs(CompoundTag tag) { + List<InputIngredient<ItemStack>> inputs = new ArrayList<>(); + for (Map.Entry<String, Tag> entry : tag.tags.entrySet()) { + InputIngredient<EntryStack<?>> stacks = InputIngredient.of(Integer.parseInt(entry.getKey()), EntryIngredient.read((ListTag) entry.getValue())); + inputs.add(InputIngredient.withType(stacks, VanillaEntryTypes.ITEM)); + } + return inputs; } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/craftable/CraftableFilter.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/craftable/CraftableFilter.java index 56dd69632..41063cdf4 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/craftable/CraftableFilter.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/craftable/CraftableFilter.java @@ -27,12 +27,15 @@ import it.unimi.dsi.fastutil.longs.Long2LongMap; import it.unimi.dsi.fastutil.longs.Long2LongMaps; import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap; import me.shedaniel.rei.impl.client.ClientHelperImpl; +import net.minecraft.client.Minecraft; +import net.minecraft.world.inventory.AbstractContainerMenu; public class CraftableFilter { public static final CraftableFilter INSTANCE = new CraftableFilter(); private boolean dirty = false; private Long2LongMap invStacks = new Long2LongOpenHashMap(); private Long2LongMap containerStacks = new Long2LongOpenHashMap(); + private long menuId = -2; public void markDirty() { dirty = true; @@ -49,6 +52,14 @@ public class CraftableFilter { public void tick() { if (dirty) return; + AbstractContainerMenu menu = Minecraft.getInstance().player.containerMenu; + long currentMenuId = menu == null ? -1 : menu.containerId; + if (currentMenuId != menuId) { + menuId = currentMenuId; + markDirty(); + } + if (dirty) return; + Long2LongMap currentStacks; try { currentStacks = ClientHelperImpl.getInstance()._getInventoryItemsTypes(); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/AutoCraftingEvaluator.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/AutoCraftingEvaluator.java index ba1379b02..665420cfb 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/AutoCraftingEvaluator.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/AutoCraftingEvaluator.java @@ -32,6 +32,7 @@ import me.shedaniel.rei.api.client.registry.transfer.TransferHandler; import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry; import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRenderer; import me.shedaniel.rei.api.common.display.Display; +import me.shedaniel.rei.api.common.transfer.info.MenuTransferException; import me.shedaniel.rei.api.common.util.CollectionUtils; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; @@ -41,10 +42,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.resources.ResourceLocation; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Locale; +import java.util.*; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; @@ -99,7 +97,15 @@ public class AutoCraftingEvaluator { for (TransferHandler transferHandler : TransferHandlerRegistry.getInstance()) { try { - TransferHandler.Result transferResult = transferHandler.handle(context); + TransferHandler.ApplicabilityResult applicabilityResult = transferHandler.checkApplicable(context); + if (!applicabilityResult.isApplicable()) continue; + TransferHandler.Result transferResult; + + if (applicabilityResult.isSuccessful()) { + transferResult = transferHandler.handle(context); + } else { + transferResult = applicabilityResult.getError(); + } if (transferResult.isBlocking() && actuallyCrafting) { if (transferResult.isReturningToScreen()) { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java index 777b44d06..f5369814c 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java @@ -54,6 +54,7 @@ import me.shedaniel.rei.api.common.category.CategoryIdentifier; import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.plugins.PluginManager; +import me.shedaniel.rei.api.common.transfer.info.MenuTransferException; import me.shedaniel.rei.api.common.util.FormattingUtils; import me.shedaniel.rei.impl.client.REIRuntimeImpl; import me.shedaniel.rei.impl.client.gui.InternalTextures; @@ -613,7 +614,15 @@ public class EntryWidget extends Slot implements DraggableStackProviderWidget { if (handler != null) { AbstractContainerScreen<?> containerScreen = REIRuntime.getInstance().getPreviousContainerScreen(); TransferHandler.Context context = TransferHandler.Context.create(true, Screen.hasShiftDown() || button == 1, containerScreen, display); - TransferHandler.Result transferResult = handler.handle(context); + TransferHandler.ApplicabilityResult applicabilityResult = handler.checkApplicable(context); + if (!applicabilityResult.isApplicable()) return false; + TransferHandler.Result transferResult; + + if (applicabilityResult.isSuccessful()) { + transferResult = handler.handle(context); + } else { + transferResult = applicabilityResult.getError(); + } if (transferResult.isBlocking()) { minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/transfer/SimpleTransferHandlerImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/transfer/SimpleTransferHandlerImpl.java new file mode 100644 index 000000000..ef7d59c79 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/transfer/SimpleTransferHandlerImpl.java @@ -0,0 +1,152 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 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.impl.client.transfer; + +import dev.architectury.networking.NetworkManager; +import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.ints.IntLinkedOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import me.shedaniel.rei.RoughlyEnoughItemsNetwork; +import me.shedaniel.rei.api.client.ClientHelper; +import me.shedaniel.rei.api.client.registry.transfer.TransferHandler; +import me.shedaniel.rei.api.client.registry.transfer.simple.SimpleTransferHandler; +import me.shedaniel.rei.api.common.entry.InputIngredient; +import me.shedaniel.rei.api.common.transfer.RecipeFinder; +import me.shedaniel.rei.api.common.transfer.info.stack.SlotAccessor; +import me.shedaniel.rei.api.common.transfer.info.stack.SlotAccessorRegistry; +import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.api.common.util.EntryIngredients; +import me.shedaniel.rei.impl.ClientInternals; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.gui.screens.recipebook.RecipeUpdateListener; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; + +import java.util.ArrayList; +import java.util.List; + +public enum SimpleTransferHandlerImpl implements ClientInternals.SimpleTransferHandler { + INSTANCE; + + @Override + public TransferHandler.Result handle(TransferHandler.Context context, SimpleTransferHandler.MissingInputRenderer missingInputRenderer, List<InputIngredient<ItemStack>> inputs, Iterable<SlotAccessor> inputSlots, Iterable<SlotAccessor> inventorySlots) { + AbstractContainerScreen<?> containerScreen = context.getContainerScreen(); + List<InputIngredient<ItemStack>> missing = SimpleTransferHandlerImpl.hasItemsIndexed(context, inventorySlots, inputs); + + if (!missing.isEmpty()) { + IntSet missingIndices = new IntLinkedOpenHashSet(missing.size()); + for (InputIngredient<ItemStack> ingredient : missing) { + missingIndices.add(ingredient.getDisplayIndex()); + } + return TransferHandler.Result.createFailed(Component.translatable("error.rei.not.enough.materials")) + .renderer((matrices, mouseX, mouseY, delta, widgets, bounds, d) -> { + missingInputRenderer.renderMissingInput(context, inputs, missing, missingIndices, matrices, mouseX, mouseY, delta, widgets, bounds); + }) + .tooltipMissing(CollectionUtils.map(missing, ingredient -> EntryIngredients.ofItemStacks(ingredient.get()))); + } + + if (!ClientHelper.getInstance().canUseMovePackets()) { + return TransferHandler.Result.createFailed(Component.translatable("error.rei.not.on.server")); + } + + if (!context.isActuallyCrafting()) { + return TransferHandler.Result.createSuccessful(); + } + + context.getMinecraft().setScreen(containerScreen); + if (containerScreen instanceof RecipeUpdateListener listener) { + listener.getRecipeBookComponent().ghostRecipe.clear(); + } + + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeResourceLocation(context.getDisplay().getCategoryIdentifier().getIdentifier()); + buf.writeBoolean(context.isStackedCrafting()); + + buf.writeNbt(save(context, inputs, inputSlots, inventorySlots)); + NetworkManager.sendToServer(RoughlyEnoughItemsNetwork.MOVE_ITEMS_NEW_PACKET, buf); + return TransferHandler.Result.createSuccessful(); + } + + private CompoundTag save(TransferHandler.Context context, List<InputIngredient<ItemStack>> inputs, Iterable<SlotAccessor> inputSlots, Iterable<SlotAccessor> inventorySlots) { + CompoundTag tag = new CompoundTag(); + tag.put("Inputs", saveInputs(inputs)); + tag.put("InventorySlots", saveSlots(context,inventorySlots)); + tag.put("InputSlots", saveSlots(context, inputSlots)); + return tag; + } + + private Tag saveSlots(TransferHandler.Context context, Iterable<SlotAccessor> slots) { + ListTag tag = new ListTag(); + + for (SlotAccessor slot : slots) { + tag.add(SlotAccessorRegistry.getInstance().save(context.getMenu(), context.getMinecraft().player, slot)); + } + + return tag; + } + + private Tag saveInputs(List<InputIngredient<ItemStack>> inputs) { + CompoundTag tag = new CompoundTag(); + + for (InputIngredient<ItemStack> input : inputs) { + tag.put(String.valueOf(input.getIndex()), EntryIngredients.ofItemStacks(input.get()).saveIngredient()); + } + + return tag; + } + + public static List<InputIngredient<ItemStack>> hasItemsIndexed(TransferHandler.Context context, Iterable<SlotAccessor> inventorySlots, List<InputIngredient<ItemStack>> inputs) { + // Create a clone of player's inventory, and count + RecipeFinder recipeFinder = new RecipeFinder(); + for (SlotAccessor slot : inventorySlots) { + recipeFinder.addNormalItem(slot.getItemStack()); + } + List<InputIngredient<ItemStack>> missing = new ArrayList<>(); + for (InputIngredient<ItemStack> possibleStacks : inputs) { + boolean done = possibleStacks.get().isEmpty(); + for (ItemStack possibleStack : possibleStacks.get()) { + if (!done) { + int invRequiredCount = possibleStack.getCount(); + int key = RecipeFinder.getItemId(possibleStack); + while (invRequiredCount > 0 && recipeFinder.contains(key)) { + invRequiredCount--; + recipeFinder.take(key, 1); + } + if (invRequiredCount <= 0) { + done = true; + break; + } + } + } + if (!done) { + missing.add(possibleStacks); + } + } + return missing; + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java index 36c84a396..54fe8ba5f 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java @@ -30,11 +30,14 @@ import com.google.common.collect.Sets; import it.unimi.dsi.fastutil.longs.Long2LongMap; import it.unimi.dsi.fastutil.longs.Long2LongMaps; import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap; +import me.shedaniel.rei.api.client.REIRuntime; import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.registry.category.CategoryRegistry; import me.shedaniel.rei.api.client.registry.display.DisplayCategory; import me.shedaniel.rei.api.client.registry.display.DisplayRegistry; import me.shedaniel.rei.api.client.registry.display.DynamicDisplayGenerator; +import me.shedaniel.rei.api.client.registry.transfer.TransferHandler; +import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry; import me.shedaniel.rei.api.client.view.ViewSearchBuilder; import me.shedaniel.rei.api.client.view.Views; import me.shedaniel.rei.api.common.category.CategoryIdentifier; @@ -60,9 +63,11 @@ import me.shedaniel.rei.impl.client.registry.display.DisplaysHolder; import me.shedaniel.rei.impl.client.util.CrashReportUtils; import me.shedaniel.rei.impl.common.InternalLogger; import me.shedaniel.rei.impl.display.DisplaySpec; +import me.shedaniel.rei.plugin.autocrafting.DefaultCategoryHandler; import net.minecraft.CrashReport; import net.minecraft.ReportedException; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.client.player.LocalPlayer; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.inventory.AbstractContainerMenu; @@ -429,86 +434,32 @@ public class ViewsImpl implements Views { AbstractContainerMenu menu = Minecraft.getInstance().player.containerMenu; Set<EntryStack<?>> craftables = new HashSet<>(); - boolean onlyIncludeHasMenu = false; + AbstractContainerScreen<?> containerScreen = REIRuntime.getInstance().getPreviousContainerScreen(); for (Map.Entry<CategoryIdentifier<?>, List<Display>> entry : DisplayRegistry.getInstance().getAll().entrySet()) { - class InfoSerializationContext implements MenuSerializationContext<AbstractContainerMenu, LocalPlayer, Display> { - @Override - public AbstractContainerMenu getMenu() { - return menu; - } - - @Override - public LocalPlayer getPlayerEntity() { - return Minecraft.getInstance().player; - } - - @Override - public CategoryIdentifier<Display> getCategoryIdentifier() { - return (CategoryIdentifier<Display>) entry.getKey(); - } - } - - InfoSerializationContext context = new InfoSerializationContext(); + MenuSerializationContext<AbstractContainerMenu, LocalPlayer, Display> context = createLegacyContext(menu, entry.getKey().cast()); List<Display> displays = entry.getValue(); for (Display display : displays) { try { - MenuInfo<AbstractContainerMenu, Display> info = menu != null ? - MenuInfoRegistry.getInstance().getClient(display, context, menu) - : null; + TransferHandler.Context transferContext = TransferHandler.Context.create(false, false, containerScreen, display); + boolean successful = matchesLegacyRequirements(menu, context, display); - if (onlyIncludeHasMenu && info == null) { - continue; - } - - Iterable<SlotAccessor> inputSlots = info != null ? Iterables.concat(info.getInputSlots(context.withDisplay(display)), info.getInventorySlots(context.withDisplay(display))) : Collections.emptySet(); - int slotsCraftable = 0; - boolean containsNonEmpty = false; - List<EntryIngredient> requiredInput = display.getRequiredEntries(); - Long2LongMap invCount = new Long2LongOpenHashMap(info == null ? CraftableFilter.INSTANCE.getInvStacks() : Long2LongMaps.EMPTY_MAP); - for (SlotAccessor inputSlot : inputSlots) { - ItemStack stack = inputSlot.getItemStack(); - - EntryDefinition<ItemStack> definition; - try { - definition = VanillaEntryTypes.ITEM.getDefinition(); - } catch (NullPointerException e) { - break; - } - - if (!stack.isEmpty()) { - long hash = definition.hash(null, stack, ComparisonContext.FUZZY); - long newCount = invCount.get(hash) + Math.max(0, stack.getCount()); - invCount.put(hash, newCount); - } - } - for (EntryIngredient slot : requiredInput) { - if (slot.isEmpty()) { - slotsCraftable++; - continue; - } - for (EntryStack<?> slotPossible : slot) { - if (slotPossible.getType() != VanillaEntryTypes.ITEM) continue; - ItemStack stack = slotPossible.castValue(); - long hashFuzzy = EntryStacks.hashFuzzy(slotPossible); - long availableAmount = invCount.get(hashFuzzy); - if (availableAmount >= stack.getCount()) { - invCount.put(hashFuzzy, availableAmount - stack.getCount()); - containsNonEmpty = true; - slotsCraftable++; - break; + if (!successful) { + for (TransferHandler handler : TransferHandlerRegistry.getInstance()) { + if (!(handler instanceof DefaultCategoryHandler) && handler.checkApplicable(transferContext).isSuccessful()) { + if (handler.handle(transferContext).isSuccessful()) { + successful = true; + break; + } } } } - if (slotsCraftable == display.getRequiredEntries().size() && containsNonEmpty) { - if (info != null && !onlyIncludeHasMenu) { - onlyIncludeHasMenu = true; - craftables.clear(); - } - - display.getOutputEntries().stream().flatMap(Collection::stream).collect(Collectors.toCollection(() -> craftables)); - } + + if (!successful) continue; + + display.getOutputEntries().stream().flatMap(Collection::stream) + .collect(Collectors.toCollection(() -> craftables)); } catch (Throwable t) { InternalLogger.getInstance().warn("Error while checking if display is craftable", t); } @@ -517,6 +468,82 @@ public class ViewsImpl implements Views { return craftables; } + private static MenuSerializationContext<AbstractContainerMenu, LocalPlayer, Display> createLegacyContext(AbstractContainerMenu menu, CategoryIdentifier<Display> categoryIdentifier) { + class InfoSerializationContext implements MenuSerializationContext<AbstractContainerMenu, LocalPlayer, Display> { + @Override + public AbstractContainerMenu getMenu() { + return menu; + } + + @Override + public LocalPlayer getPlayerEntity() { + return Minecraft.getInstance().player; + } + + @Override + public CategoryIdentifier<Display> getCategoryIdentifier() { + return categoryIdentifier; + } + } + + return new InfoSerializationContext(); + } + + private static boolean matchesLegacyRequirements(AbstractContainerMenu menu, + MenuSerializationContext<AbstractContainerMenu, LocalPlayer, Display> context, + Display display) { + MenuInfo<AbstractContainerMenu, Display> info = menu != null ? + MenuInfoRegistry.getInstance().getClient(display, context, menu) + : null; + + if (menu != null && info == null) { + return false; + } + + Iterable<SlotAccessor> inputSlots = info != null ? Iterables.concat(info.getInputSlots(context.withDisplay(display)), info.getInventorySlots(context.withDisplay(display))) : Collections.emptySet(); + int slotsCraftable = 0; + boolean containsNonEmpty = false; + List<EntryIngredient> requiredInput = display.getRequiredEntries(); + Long2LongMap invCount = new Long2LongOpenHashMap(info == null ? CraftableFilter.INSTANCE.getInvStacks() : Long2LongMaps.EMPTY_MAP); + for (SlotAccessor inputSlot : inputSlots) { + ItemStack stack = inputSlot.getItemStack(); + + EntryDefinition<ItemStack> definition; + try { + definition = VanillaEntryTypes.ITEM.getDefinition(); + } catch (NullPointerException e) { + break; + } + + if (!stack.isEmpty()) { + long hash = definition.hash(null, stack, ComparisonContext.FUZZY); + long newCount = invCount.get(hash) + Math.max(0, stack.getCount()); + invCount.put(hash, newCount); + } + } + + for (EntryIngredient slot : requiredInput) { + if (slot.isEmpty()) { + slotsCraftable++; + continue; + } + for (EntryStack<?> slotPossible : slot) { + if (slotPossible.getType() != VanillaEntryTypes.ITEM) continue; + ItemStack stack = slotPossible.castValue(); + long hashFuzzy = EntryStacks.hashFuzzy(slotPossible); + long availableAmount = invCount.get(hashFuzzy); + if (availableAmount >= stack.getCount()) { + invCount.put(hashFuzzy, availableAmount - stack.getCount()); + containsNonEmpty = true; + slotsCraftable++; + break; + } + } + } + + return slotsCraftable == display.getR |
