aboutsummaryrefslogtreecommitdiff
path: root/runtime/src/main/java/me
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/src/main/java/me')
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java4
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java2
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java63
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/craftable/CraftableFilter.java11
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/AutoCraftingEvaluator.java16
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/EntryWidget.java11
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/transfer/SimpleTransferHandlerImpl.java152
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/view/ViewsImpl.java167
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/InputSlotCrafter.java80
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/LegacyInputSlotCrafter.java113
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/NewInputSlotCrafter.java134
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/SlotAccessorRegistryImpl.java105
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultCategoryHandler.java19
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/plugin/common/runtime/DefaultRuntimePlugin.java52
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 3698aed64..6ea420004 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 1844edf1e..821dc8e82 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 259f7367f..38157049c 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
@@ -53,6 +53,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;
@@ -615,7 +616,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);
+ }
+ }
+