Fix #2574: Use the fabric item API for auto input and auto output (#2585)

* Fix #2574: Use the fabric item API for auto input and auto output

* Only auto-insert at most 4 items at once
This commit is contained in:
Technici4n 2021-10-31 18:14:26 +01:00 committed by GitHub
parent 9958324539
commit b300456e77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 65 additions and 205 deletions

View file

@ -1,127 +0,0 @@
/*
* This file is part of RebornCore, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 TeamReborn
*
* 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 reborncore.api.items;
import net.minecraft.block.*;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.ChestBlockEntity;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.SidedInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import reborncore.common.util.ItemUtils;
public class InventoryUtils {
public static ItemStack insertItemStacked(Inventory inventory, ItemStack input, boolean simulate) {
ItemStack stack = input.copy();
for (int i = 0; i < inventory.size(); i++) {
ItemStack targetStack = inventory.getStack(i);
//Nice and simple, insert the item into a blank slot
if (targetStack.isEmpty()) {
if (!simulate) {
inventory.setStack(i, stack);
}
return ItemStack.EMPTY;
} else if (ItemUtils.isItemEqual(stack, targetStack, true, false)) {
int freeStackSpace = targetStack.getMaxCount() - targetStack.getCount();
if (freeStackSpace > 0) {
int transferAmount = Math.min(freeStackSpace, input.getCount());
if (!simulate) {
targetStack.increment(transferAmount);
}
stack.decrement(transferAmount);
}
}
}
return stack;
}
public static ItemStack insertItem(ItemStack input, Inventory inventory, Direction direction) {
ItemStack stack = input.copy();
if (inventory instanceof SidedInventory sidedInventory) {
for (int slot : sidedInventory.getAvailableSlots(direction)) {
if (sidedInventory.canInsert(slot, stack, direction)) {
stack = insertIntoInv(sidedInventory, slot, stack);
if (stack.isEmpty()) {
break;
}
}
}
return stack;
} else {
for (int i = 0; i < inventory.size() & !stack.isEmpty(); i++) {
if (inventory.isValid(i, stack)) {
stack = insertIntoInv(inventory, i, stack);
}
}
}
return stack;
}
@Nullable
public static Inventory getInventoryAt(World world, BlockPos blockPos) {
Inventory inventory = null;
BlockState blockState = world.getBlockState(blockPos);
Block block = blockState.getBlock();
if (block instanceof InventoryProvider) {
inventory = ((InventoryProvider) block).getInventory(blockState, world, blockPos);
} else if (block instanceof BlockEntityProvider) {
BlockEntity blockEntity = world.getBlockEntity(blockPos);
if (blockEntity instanceof Inventory) {
inventory = (Inventory) blockEntity;
if (inventory instanceof ChestBlockEntity && block instanceof ChestBlock) {
inventory = ChestBlock.getInventory((ChestBlock) block, blockState, world, blockPos, true);
}
}
}
return inventory;
}
private static ItemStack insertIntoInv(Inventory inventory, int slot, ItemStack input) {
ItemStack targetStack = inventory.getStack(slot);
ItemStack stack = input.copy();
//Nice and simple, insert the item into a blank slot
if (targetStack.isEmpty()) {
inventory.setStack(slot, stack);
return ItemStack.EMPTY;
} else if (ItemUtils.isItemEqual(stack, targetStack, true, false)) {
int freeStackSpace = targetStack.getMaxCount() - targetStack.getCount();
if (freeStackSpace > 0) {
int transferAmount = Math.min(freeStackSpace, stack.getCount());
targetStack.increment(transferAmount);
stack.decrement(transferAmount);
}
}
return stack;
}
}

View file

@ -25,10 +25,10 @@
package reborncore.common.blockentity;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import net.fabricmc.fabric.api.transfer.v1.item.InventoryStorage;
import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage;
import net.fabricmc.fabric.api.transfer.v1.storage.StorageUtil;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.SidedInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.StringNbtReader;
@ -37,8 +37,6 @@ import org.apache.commons.lang3.Validate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import reborncore.RebornCore;
import reborncore.api.items.InventoryUtils;
import reborncore.common.util.ItemUtils;
import reborncore.common.util.NBTSerializable;
import reborncore.common.util.RebornInventory;
@ -291,53 +289,14 @@ public class SlotConfiguration implements NBTSerializable {
if (targetStack.getMaxCount() == targetStack.getCount()) {
return;
}
Inventory sourceInv = InventoryUtils.getInventoryAt(machineBase.getWorld(), machineBase.getPos().offset(side));
if (sourceInv == null) {
return;
}
IntList availableSlots = null;
if (sourceInv instanceof SidedInventory) {
availableSlots = IntArrayList.wrap(((SidedInventory) sourceInv).getAvailableSlots(side.getOpposite()));
}
for (int i = 0; i < sourceInv.size(); i++) {
if (availableSlots != null && !availableSlots.contains(i)) {
continue;
}
ItemStack sourceStack = sourceInv.getStack(i);
if (sourceStack.isEmpty()) {
continue;
}
if(!canInsertItem(slotID, sourceStack, side, machineBase)){
continue;
}
if (sourceInv instanceof SidedInventory && !((SidedInventory) sourceInv).canExtract(i, sourceStack, side.getOpposite())) {
continue;
}
//Checks if we are going to merge stacks that the items are the same
if (!targetStack.isEmpty()) {
if (!ItemUtils.isItemEqual(sourceStack, targetStack, true, false)) {
continue;
}
}
int extract = 4;
if (!targetStack.isEmpty()) {
extract = Math.min(targetStack.getMaxCount() - targetStack.getCount(), extract);
}
ItemStack extractedStack = sourceInv.removeStack(i, extract);
if (targetStack.isEmpty()) {
inventory.setStack(slotID, extractedStack);
} else {
inventory.getStack(slotID).increment(extractedStack.getCount());
}
inventory.setHashChanged();
break;
}
StorageUtil.move(
ItemStorage.SIDED.find(machineBase.getWorld(), machineBase.getPos().offset(side), side.getOpposite()),
InventoryStorage.of(machineBase, null).getSlot(slotID),
iv -> true,
4, // Move up to 4 per tick.
null
);
}
private void handleItemOutput(MachineBaseBlockEntity machineBase) {
@ -346,13 +305,14 @@ public class SlotConfiguration implements NBTSerializable {
if (sourceStack.isEmpty()) {
return;
}
Inventory destInventory = InventoryUtils.getInventoryAt(machineBase.getWorld(), machineBase.getPos().offset(side));
if (destInventory == null) {
return;
}
ItemStack stack = InventoryUtils.insertItem(sourceStack, destInventory, side.getOpposite());
inventory.setStack(slotID, stack);
StorageUtil.move(
InventoryStorage.of(machineBase, null).getSlot(slotID),
ItemStorage.SIDED.find(machineBase.getWorld(), machineBase.getPos().offset(side), side.getOpposite()),
iv -> true,
Long.MAX_VALUE,
null
);
}
@NotNull

View file

@ -24,6 +24,10 @@
package reborncore.common.blocks;
import net.fabricmc.fabric.api.transfer.v1.item.InventoryStorage;
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant;
import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleSlotStorage;
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.InventoryProvider;
@ -50,7 +54,6 @@ import reborncore.api.ToolManager;
import reborncore.api.blockentity.IMachineGuiHandler;
import reborncore.api.blockentity.IUpgrade;
import reborncore.api.blockentity.IUpgradeable;
import reborncore.api.items.InventoryUtils;
import reborncore.common.BaseBlockEntityProvider;
import reborncore.common.blockentity.MachineBaseBlockEntity;
import reborncore.common.fluid.FluidUtil;
@ -196,11 +199,14 @@ public abstract class BlockMachineBase extends BaseBlockEntityProvider implement
}
} else if (stack.getItem() instanceof IUpgrade && blockEntity instanceof IUpgradeable upgradeableEntity) {
if (upgradeableEntity.canBeUpgraded()) {
if (InventoryUtils.insertItemStacked(upgradeableEntity.getUpgradeInvetory(), stack,
true).getCount() > 0) {
stack = InventoryUtils.insertItemStacked(upgradeableEntity.getUpgradeInvetory(), stack, false);
playerIn.setStackInHand(Hand.MAIN_HAND, stack);
return ActionResult.SUCCESS;
int inserted = (int) insertItemStacked(
InventoryStorage.of(upgradeableEntity.getUpgradeInvetory(), null),
ItemVariant.of(stack),
stack.getCount()
);
if (inserted > 0) {
stack.decrement(inserted);
return ActionResult.success(worldIn.isClient());
}
}
}
@ -214,6 +220,28 @@ public abstract class BlockMachineBase extends BaseBlockEntityProvider implement
return super.onUse(state, worldIn, pos, playerIn, hand, hitResult);
}
// TODO: use the fabric one when it will be PR'ed.
@SuppressWarnings({"deprecation", "UnstableApiUsage"})
public static long insertItemStacked(InventoryStorage inventory, ItemVariant variant, long maxAmount) {
long inserted = 0;
try (Transaction tx = Transaction.openOuter()) {
outer: for (int loop = 0; loop < 2; ++loop) {
for (SingleSlotStorage<ItemVariant> slot : inventory.getSlots()) {
if (slot.getResource().equals(variant) || loop == 1) {
inserted += slot.insert(variant, maxAmount - inserted, tx);
if (inserted == maxAmount) {
break outer;
}
}
}
}
tx.commit();
}
return inserted;
}
@SuppressWarnings("deprecation")
@Override
public BlockState rotate(BlockState state, BlockRotation rotation) {

View file

@ -24,11 +24,13 @@
package techreborn.blockentity.machine.tier1;
import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage;
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant;
import net.fabricmc.fabric.api.transfer.v1.storage.Storage;
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.entity.HopperBlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.sound.SoundCategory;
@ -44,8 +46,6 @@ import techreborn.init.ModSounds;
import techreborn.init.TRBlockEntities;
import techreborn.init.TRContent;
import static reborncore.api.items.InventoryUtils.getInventoryAt;
public class ResinBasinBlockEntity extends MachineBaseBlockEntity {
private Direction direction = Direction.NORTH;
@ -92,16 +92,15 @@ public class ResinBasinBlockEntity extends MachineBaseBlockEntity {
// Try and deposit
if (isFull) {
// Get inventory
Inventory invBelow = getInventoryBelow();
Storage<ItemVariant> invBelow = getInventoryBelow();
if (invBelow != null) {
ItemStack out = new ItemStack(TRContent.Parts.SAP, (Math.random() <= 0.5) ? 1 : 2);
out = HopperBlockEntity.transfer(null, invBelow, out, Direction.UP);
if (out.isEmpty()) {
// Successfully deposited
isFull = false;
shouldUpdateState = true;
try (Transaction tx = Transaction.openOuter()) {
int sentAmount = (Math.random() <= 0.5) ? 1 : 2;
if (invBelow.insert(ItemVariant.of(TRContent.Parts.SAP), sentAmount, tx) > 0) {
tx.commit();
isFull = false;
shouldUpdateState = true;
}
}
}
}
@ -170,8 +169,8 @@ public class ResinBasinBlockEntity extends MachineBaseBlockEntity {
direction = world.getBlockState(pos).get(ResinBasinBlock.FACING).getOpposite();
}
private Inventory getInventoryBelow() {
return getInventoryAt(this.getWorld(), this.pos.offset(Direction.DOWN));
private Storage<ItemVariant> getInventoryBelow() {
return ItemStorage.SIDED.find(this.getWorld(), this.pos.offset(Direction.DOWN), Direction.UP);
}
private boolean validPlacement() {