aboutsummaryrefslogtreecommitdiff
path: root/runtime/src/main/java/me/shedaniel/rei/impl/common
diff options
context:
space:
mode:
authorshedaniel <daniel@shedaniel.me>2023-09-01 20:00:22 +0800
committershedaniel <daniel@shedaniel.me>2023-09-01 20:01:10 +0800
commit21d144a7b605169578ba8e1dc1663d1ab042660d (patch)
treec1be3b449d2f36290281a27b8bcdddf86e351d91 /runtime/src/main/java/me/shedaniel/rei/impl/common
parent1833c18d5f3615d0a4a17689467b32df75dd92f1 (diff)
parent8c03832d5ae716beba4047166505181cadd76e75 (diff)
downloadRoughlyEnoughItems-21d144a7b605169578ba8e1dc1663d1ab042660d.tar.gz
RoughlyEnoughItems-21d144a7b605169578ba8e1dc1663d1ab042660d.tar.bz2
RoughlyEnoughItems-21d144a7b605169578ba8e1dc1663d1ab042660d.zip
Merge remote-tracking branch 'shedaniel/11.x-1.19.4' into 12.x-1.20
Diffstat (limited to 'runtime/src/main/java/me/shedaniel/rei/impl/common')
-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
4 files changed, 376 insertions, 56 deletions
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/InputSlotCrafter.java b/runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/InputSlotCrafter.java
index a4130307d..5de24ce18 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/InputSlotCrafter.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/InputSlotCrafter.java
@@ -25,16 +25,11 @@ package me.shedaniel.rei.impl.common.transfer;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
-import me.shedaniel.rei.api.common.category.CategoryIdentifier;
-import me.shedaniel.rei.api.common.display.Display;
+import me.shedaniel.rei.api.common.entry.InputIngredient;
import me.shedaniel.rei.api.common.transfer.RecipeFinder;
-import me.shedaniel.rei.api.common.transfer.info.MenuInfo;
-import me.shedaniel.rei.api.common.transfer.info.MenuInfoContext;
-import me.shedaniel.rei.api.common.transfer.info.MenuInfoRegistry;
import me.shedaniel.rei.api.common.transfer.info.stack.SlotAccessor;
import me.shedaniel.rei.api.common.util.CollectionUtils;
import net.minecraft.core.NonNullList;
-import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.inventory.AbstractContainerMenu;
@@ -44,59 +39,53 @@ import org.jetbrains.annotations.Nullable;
import java.util.Iterator;
import java.util.List;
-import java.util.Objects;
-public class InputSlotCrafter<T extends AbstractContainerMenu, C extends Container, D extends Display> implements MenuInfoContext<T, ServerPlayer, D> {
- protected CategoryIdentifier<D> category;
+public abstract class InputSlotCrafter<T extends AbstractContainerMenu, C extends Container> {
protected T container;
- protected MenuInfo<T, D> menuInfo;
private Iterable<SlotAccessor> inputStacks;
private Iterable<SlotAccessor> inventoryStacks;
- private ServerPlayer player;
+ protected ServerPlayer player;
- private InputSlotCrafter(CategoryIdentifier<D> category, T container) {
- this.category = category;
+ protected InputSlotCrafter(T container) {
this.container = container;
}
- public void setMenuInfo(MenuInfo<T, D> menuInfo) {
- this.menuInfo = menuInfo;
- }
-
- public static <T extends AbstractContainerMenu, C extends Container, D extends Display> InputSlotCrafter<T, C, D> start(CategoryIdentifier<D> category, T menu, ServerPlayer player, CompoundTag display, boolean hasShift) {
- InputSlotCrafter<T, C, D> crafter = new InputSlotCrafter<>(category, menu);
- MenuInfo<T, D> menuInfo = Objects.requireNonNull(MenuInfoRegistry.getInstance().get(category, menu, crafter, display), "Container Info does not exist on the server!");
- crafter.setMenuInfo(menuInfo);
- crafter.fillInputSlots(player, hasShift);
- return crafter;
- }
-
- private void fillInputSlots(ServerPlayer player, boolean hasShift) {
+ public void fillInputSlots(ServerPlayer player, boolean hasShift) {
this.player = player;
- this.inventoryStacks = this.menuInfo.getInventorySlots(this);
- this.inputStacks = this.menuInfo.getInputSlots(this);
+ this.inventoryStacks = this.getInventorySlots();
+ this.inputStacks = this.getInputSlots();
// Return the already placed items on the grid
this.cleanInputs();
RecipeFinder recipeFinder = new RecipeFinder();
- this.menuInfo.getRecipeFinderPopulator().populate(this, recipeFinder);
+ this.populateRecipeFinder(recipeFinder);
NonNullList<Ingredient> ingredients = NonNullList.create();
- for (List<ItemStack> itemStacks : this.menuInfo.getInputs(this, true)) {
- ingredients.add(CollectionUtils.toIngredient(itemStacks));
+ for (InputIngredient<ItemStack> itemStacks : this.getInputs()) {
+ ingredients.add(CollectionUtils.toIngredient(itemStacks.get()));
}
if (recipeFinder.findRecipe(ingredients, null)) {
this.fillInputSlots(recipeFinder, ingredients, hasShift);
} else {
this.cleanInputs();
- this.menuInfo.markDirty(this);
+ this.markDirty();
throw new NotEnoughMaterialsException();
}
- this.menuInfo.markDirty(this);
+ this.markDirty();
}
+ protected abstract Iterable<SlotAccessor> getInputSlots();
+
+ protected abstract Iterable<SlotAccessor> getInventorySlots();
+
+ protected abstract List<InputIngredient<ItemStack>> getInputs();
+
+ protected abstract void populateRecipeFinder(RecipeFinder recipeFinder);
+
+ protected abstract void markDirty();
+
public void alignRecipeToGrid(Iterable<SlotAccessor> inputStacks, Iterator<Integer> recipeItemIds, int craftsAmount) {
for (SlotAccessor inputStack : inputStacks) {
if (!recipeItemIds.hasNext()) {
@@ -155,9 +144,7 @@ public class InputSlotCrafter<T extends AbstractContainerMenu, C extends Contain
}
}
- protected void cleanInputs() {
- this.menuInfo.getInputCleanHandler().clean(this);
- }
+ protected abstract void cleanInputs();
@Nullable
public SlotAccessor takeInventoryStack(ItemStack itemStack) {
@@ -175,25 +162,6 @@ public class InputSlotCrafter<T extends AbstractContainerMenu, C extends Contain
return ItemStack.isSameItemSameTags(stack1, stack2);
}
- @Override
- public T getMenu() {
- return container;
- }
-
- @Override
- public ServerPlayer getPlayerEntity() {
- return player;
- }
-
- @Override
- public D getDisplay() {
- return menuInfo.getDisplay();
- }
-
- @Override
- public CategoryIdentifier<D> getCategoryIdentifier() {
- return category;
+ public static class NotEnoughMaterialsException extends RuntimeException {
}
-
- public static class NotEnoughMaterialsException extends RuntimeException {}
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/LegacyInputSlotCrafter.java b/runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/LegacyInputSlotCrafter.java
new file mode 100644
index 000000000..d05256111
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/LegacyInputSlotCrafter.java
@@ -0,0 +1,113 @@
+/*
+ * 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.common.transfer;
+
+import me.shedaniel.rei.api.common.category.CategoryIdentifier;
+import me.shedaniel.rei.api.common.display.Display;
+import me.shedaniel.rei.api.common.entry.InputIngredient;
+import me.shedaniel.rei.api.common.transfer.RecipeFinder;
+import me.shedaniel.rei.api.common.transfer.info.MenuInfo;
+import me.shedaniel.rei.api.common.transfer.info.MenuInfoContext;
+import me.shedaniel.rei.api.common.transfer.info.MenuInfoRegistry;
+import me.shedaniel.rei.api.common.transfer.info.stack.SlotAccessor;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.Container;
+import net.minecraft.world.inventory.AbstractContainerMenu;
+import net.minecraft.world.item.ItemStack;
+
+import java.util.List;
+import java.util.Objects;
+
+public class LegacyInputSlotCrafter<T extends AbstractContainerMenu, C extends Container, D extends Display> extends InputSlotCrafter<T, C> implements MenuInfoContext<T, ServerPlayer, D> {
+ protected CategoryIdentifier<D> category;
+ protected MenuInfo<T, D> menuInfo;
+
+ protected LegacyInputSlotCrafter(CategoryIdentifier<D> category, T container) {
+ super(container);
+ this.category = category;
+ }
+
+ public void setMenuInfo(MenuInfo<T, D> menuInfo) {
+ this.menuInfo = menuInfo;
+ }
+
+ public static <T extends AbstractContainerMenu, C extends Container, D extends Display> LegacyInputSlotCrafter<T, C, D> start(CategoryIdentifier<D> category, T menu, ServerPlayer player, CompoundTag display, boolean hasShift) {
+ LegacyInputSlotCrafter<T, C, D> crafter = new LegacyInputSlotCrafter<>(category, menu);
+ MenuInfo<T, D> menuInfo = Objects.requireNonNull(MenuInfoRegistry.getInstance().get(category, menu, crafter, display), "Container Info does not exist on the server!");
+ crafter.setMenuInfo(menuInfo);
+ crafter.fillInputSlots(player, hasShift);
+ return crafter;
+ }
+
+ @Override
+ protected Iterable<SlotAccessor> getInputSlots() {
+ return this.menuInfo.getInputSlots(this);
+ }
+
+ @Override
+ protected Iterable<SlotAccessor> getInventorySlots() {
+ return this.menuInfo.getInventorySlots(this);
+ }
+
+ @Override
+ protected List<InputIngredient<ItemStack>> getInputs() {
+ return this.menuInfo.getInputsIndexed(this, true);
+ }
+
+ @Override
+ protected void populateRecipeFinder(RecipeFinder recipeFinder) {
+ this.menuInfo.getRecipeFinderPopulator().populate(this, recipeFinder);
+ }
+
+ @Override
+ protected void markDirty() {
+ this.menuInfo.markDirty(this);
+ }
+
+ @Override
+ protected void cleanInputs() {
+ this.menuInfo.getInputCleanHandler().clean(this);
+ }
+
+ @Override
+ public T getMenu() {
+ return container;
+ }
+
+ @Override
+ public ServerPlayer getPlayerEntity() {
+ return player;
+ }
+
+ @Override
+ public D getDisplay() {
+ return menuInfo.getDisplay();
+ }
+
+ @Override
+ public CategoryIdentifier<D> getCategoryIdentifier() {
+ return category;
+ }
+}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/NewInputSlotCrafter.java b/runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/NewInputSlotCrafter.java
new file mode 100644
index 000000000..a2d35f24d
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/NewInputSlotCrafter.java
@@ -0,0 +1,134 @@
+/*
+ * 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.common.transfer;
+
+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 net.minecraft.world.Container;
+import net.minecraft.world.inventory.AbstractContainerMenu;
+import net.minecraft.world.item.ItemStack;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+public class NewInputSlotCrafter<T extends AbstractContainerMenu, C extends Container> extends InputSlotCrafter<T, C> {
+ protected final List<SlotAccessor> inputSlots;
+ protected final List<SlotAccessor> inventorySlots;
+ protected final List<InputIngredient<ItemStack>> inputs;
+
+ public NewInputSlotCrafter(T container, List<SlotAccessor> inputSlots, List<SlotAccessor> inventorySlots, List<InputIngredient<ItemStack>> inputs) {
+ super(container);
+ this.inputSlots = inputSlots;
+ this.inventorySlots = inventorySlots;
+ this.inputs = inputs;
+ }
+
+ @Override
+ protected Iterable<SlotAccessor> getInputSlots() {
+ return this.inputSlots;
+ }
+
+ @Override
+ protected Iterable<SlotAccessor> getInventorySlots() {
+ return this.inventorySlots;
+ }
+
+ @Override
+ protected List<InputIngredient<ItemStack>> getInputs() {
+ return this.inputs;
+ }
+
+ @Override
+ protected void populateRecipeFinder(RecipeFinder recipeFinder) {
+ for (SlotAccessor slot : getInventorySlots()) {
+ recipeFinder.addNormalItem(slot.getItemStack());
+ }
+ }
+
+ @Override
+ protected void markDirty() {
+ player.getInventory().setChanged();
+ container.sendAllDataToRemote();
+ }
+
+ @Override
+ protected void cleanInputs() {
+ for (SlotAccessor slot : getInputSlots()) {
+ ItemStack stackToReturn = slot.getItemStack();
+ if (!stackToReturn.isEmpty()) {
+ for (; !(stackToReturn = slot.getItemStack()).isEmpty(); slot.takeStack(1)) {
+ ItemStack stackToInsert = stackToReturn.copy();
+ stackToInsert.setCount(1);
+
+ if (!getDumpHandler().test(stackToInsert)) {
+ throw new IllegalStateException("rei.rei.no.slot.in.inv");
+ }
+ }
+ }
+ }
+ }
+
+ private Predicate<ItemStack> getDumpHandler() {
+ return (stackToDump) -> {
+ Iterable<SlotAccessor> inventoryStacks = getInventorySlots();
+ SlotAccessor occupiedSlotWithRoomForStack = getOccupiedSlotWithRoomForStack(stackToDump, inventoryStacks);
+ SlotAccessor emptySlot = getEmptySlot(inventoryStacks);
+
+ SlotAccessor nextSlot = occupiedSlotWithRoomForStack == null ? emptySlot : occupiedSlotWithRoomForStack;
+ if (nextSlot == null) {
+ return false;
+ }
+
+ ItemStack stack = stackToDump.copy();
+ stack.setCount(nextSlot.getItemStack().getCount() + stack.getCount());
+ nextSlot.setItemStack(stack);
+ return true;
+ };
+ }
+
+ static SlotAccessor getOccupiedSlotWithRoomForStack(ItemStack stack, Iterable<SlotAccessor> inventoryStacks) {
+ for (SlotAccessor inventoryStack : inventoryStacks) {
+ if (canStackAddMore(inventoryStack.getItemStack(), stack)) {
+ return inventoryStack;
+ }
+ }
+
+ return null;
+ }
+
+ static SlotAccessor getEmptySlot(Iterable<SlotAccessor> inventoryStacks) {
+ for (SlotAccessor inventoryStack : inventoryStacks) {
+ if (inventoryStack.getItemStack().isEmpty()) {
+ return inventoryStack;
+ }
+ }
+
+ return null;
+ }
+
+ static boolean canStackAddMore(ItemStack existingStack, ItemStack stack) {
+ return !existingStack.isEmpty() && ItemStack.isSameItemSameTags(existingStack, stack) && existingStack.isStackable() && existingStack.getCount() + stack.getCount() <= existingStack.getMaxStackSize();
+ }
+}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/SlotAccessorRegistryImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/SlotAccessorRegistryImpl.java
new file mode 100644
index 000000000..9d9654870
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/common/transfer/SlotAccessorRegistryImpl.java
@@ -0,0 +1,105 @@
+/*
+ * 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.common.transfer;
+
+import me.shedaniel.rei.api.common.plugins.REIServerPlugin;
+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.InternalLogger;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.inventory.AbstractContainerMenu;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Predicate;
+
+public class SlotAccessorRegistryImpl implements SlotAccessorRegistry {
+ private final Map<ResourceLocation, Serializer> map = new HashMap<>();
+
+ @Override
+ public void startReload() {
+ this.map.clear();
+ }
+
+ @Override
+ public void endReload() {
+ InternalLogger.getInstance().debug("Registered %d slot accessor serializers", map.size());
+ }
+
+ @Override
+ public void acceptPlugin(REIServerPlugin plugin) {
+ plugin.registerSlotAccessors(this);
+ }
+
+ @Override
+ public void register(ResourceLocation id, Predicate<SlotAccessor> accessorPredicate, Serializer serializer) {
+ this.map.put(id, new Serializer() {
+ @Override
+ public SlotAccessor read(AbstractContainerMenu menu, Player player, CompoundTag tag) {
+ return serializer.read(menu, player, tag);
+ }
+
+ @Override
+ @Nullable
+ public CompoundTag save(AbstractContainerMenu menu, Player player, SlotAccessor accessor) {
+ if (!accessorPredicate.test(accessor)) {
+ return null;
+ }
+ return serializer.save(menu, player, accessor);
+ }
+ });
+ InternalLogger.getInstance().debug("Added slot accessor serializer: %s [%s]", serializer, id);
+ }
+
+ @Override
+ @Nullable
+ public Serializer get(ResourceLocation id) {
+ return this.map.get(id);
+ }
+
+ @Override
+ public CompoundTag save(AbstractContainerMenu menu, Player player, SlotAccessor accessor) {
+ for (Map.Entry<ResourceLocation, Serializer> entry : map.entrySet()) {
+ CompoundTag tag = entry.getValue().save(menu, player, accessor);
+ if (tag != null) {
+ tag.putString("id", entry.getKey().toString());
+ return tag;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public SlotAccessor read(AbstractContainerMenu menu, Player player, CompoundTag tag) {
+ String id = tag.getString("id");
+ Serializer serializer = map.get(new ResourceLocation(id));
+ if (serializer == null) {
+ throw new NullPointerException("No serializer found for " + id);
+ }
+ return serializer.read(menu, player, tag);
+ }
+}