diff options
| author | shedaniel <daniel@shedaniel.me> | 2023-09-01 20:00:22 +0800 |
|---|---|---|
| committer | shedaniel <daniel@shedaniel.me> | 2023-09-01 20:01:10 +0800 |
| commit | 21d144a7b605169578ba8e1dc1663d1ab042660d (patch) | |
| tree | c1be3b449d2f36290281a27b8bcdddf86e351d91 /runtime/src/main/java/me/shedaniel/rei/impl/common | |
| parent | 1833c18d5f3615d0a4a17689467b32df75dd92f1 (diff) | |
| parent | 8c03832d5ae716beba4047166505181cadd76e75 (diff) | |
| download | RoughlyEnoughItems-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')
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); + } +} |
