mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-08-30 17:17:55 +00:00
TurtlePlayer
This commit is contained in:
@@ -9,6 +9,9 @@ import com.mojang.authlib.GameProfile;
|
||||
import dan200.computercraft.api.lua.ILuaCallback;
|
||||
import dan200.computercraft.api.lua.MethodResult;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.shared.util.InventoryUtil;
|
||||
import dan200.computercraft.shared.util.ItemStorage;
|
||||
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
@@ -282,4 +285,8 @@ public interface ITurtleAccess
|
||||
* @see #updateUpgradeNBTData(TurtleSide)
|
||||
*/
|
||||
void updateUpgradeNBTData( @Nonnull TurtleSide side );
|
||||
|
||||
default ItemStorage getItemHandler() {
|
||||
return ItemStorage.wrap(this.getInventory());
|
||||
}
|
||||
}
|
||||
|
@@ -34,6 +34,10 @@ import java.util.function.Consumer;
|
||||
/**
|
||||
* Registers textures and models for items.
|
||||
*/
|
||||
@SuppressWarnings ({
|
||||
"MethodCallSideOnly",
|
||||
"LocalVariableDeclarationSideOnly"
|
||||
})
|
||||
public final class ClientRegistry
|
||||
{
|
||||
private static final String[] EXTRA_MODELS = new String[] {
|
||||
@@ -102,8 +106,8 @@ public final class ClientRegistry
|
||||
|
||||
// Setup turtle colours
|
||||
ColorProviderRegistry.ITEM.register((stack, tintIndex) -> tintIndex == 0 ? ((IColouredItem) stack.getItem()).getColour(stack) : 0xFFFFFF,
|
||||
ComputerCraft.Blocks.turtleNormal,
|
||||
ComputerCraft.Blocks.turtleAdvanced);
|
||||
Registry.ModBlocks.TURTLE_NORMAL,
|
||||
Registry.ModBlocks.TURTLE_ADVANCED);
|
||||
}
|
||||
|
||||
private static BakedModel bake(ModelLoader loader, UnbakedModel model) {
|
||||
|
@@ -5,6 +5,12 @@
|
||||
*/
|
||||
package dan200.computercraft.shared.turtle.core;
|
||||
|
||||
import java.util.OptionalInt;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.turtle.FakePlayer;
|
||||
@@ -13,6 +19,7 @@ import dan200.computercraft.shared.Registry;
|
||||
import dan200.computercraft.shared.util.FakeNetHandler;
|
||||
import dan200.computercraft.shared.util.InventoryUtil;
|
||||
import dan200.computercraft.shared.util.WorldUtil;
|
||||
|
||||
import net.minecraft.block.entity.SignBlockEntity;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityDimensions;
|
||||
@@ -28,13 +35,8 @@ import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.UUID;
|
||||
|
||||
@SuppressWarnings ("EntityConstructor")
|
||||
public final class TurtlePlayer extends FakePlayer
|
||||
{
|
||||
private static final GameProfile DEFAULT_PROFILE = new GameProfile(
|
||||
@@ -128,7 +130,7 @@ public final class TurtlePlayer extends FakePlayer
|
||||
@Override
|
||||
public EntityType<?> getType()
|
||||
{
|
||||
return Registry.ModEntities.TURTLE_PLAYER.get();
|
||||
return Registry.ModEntities.TURTLE_PLAYER;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -5,10 +5,19 @@
|
||||
*/
|
||||
package dan200.computercraft.shared.util;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import dan200.computercraft.api.turtle.FakePlayer;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.util.concurrent.Future;
|
||||
import io.netty.util.concurrent.GenericFutureListener;
|
||||
import net.minecraft.network.*;
|
||||
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.NetworkSide;
|
||||
import net.minecraft.network.NetworkState;
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.network.listener.PacketListener;
|
||||
import net.minecraft.network.packet.c2s.play.AdvancementTabC2SPacket;
|
||||
import net.minecraft.network.packet.c2s.play.BoatPaddleStateC2SPacket;
|
||||
@@ -52,14 +61,8 @@ import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket;
|
||||
import net.minecraft.network.packet.c2s.play.UpdateSignC2SPacket;
|
||||
import net.minecraft.network.packet.c2s.play.UpdateStructureBlockC2SPacket;
|
||||
import net.minecraft.network.packet.c2s.play.VehicleMoveC2SPacket;
|
||||
import net.minecraft.network.play.client.*;
|
||||
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
public class FakeNetHandler extends ServerPlayNetworkHandler
|
||||
{
|
||||
|
@@ -5,25 +5,19 @@
|
||||
*/
|
||||
package dan200.computercraft.shared.util;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.inventory.SidedInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.CapabilityItemHandler;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
import net.minecraftforge.items.wrapper.InvWrapper;
|
||||
import net.minecraftforge.items.wrapper.SidedInvWrapper;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public final class InventoryUtil
|
||||
{
|
||||
@@ -37,14 +31,13 @@ public final class InventoryUtil
|
||||
|
||||
public static boolean areItemsStackable( @Nonnull ItemStack a, @Nonnull ItemStack b )
|
||||
{
|
||||
return a == b || ItemHandlerHelper.canItemStacksStack( a, b );
|
||||
return a == b || (a.getItem() == b.getItem() && ItemStack.areTagsEqual( a, b ));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if two items are "mostly" equivalent. Namely, they have the same item and damage, and identical
|
||||
* share stacks.
|
||||
*
|
||||
* This is largely based on {@link net.minecraftforge.common.crafting.IngredientNBT#test(ItemStack)}. It is
|
||||
* sufficient to ensure basic information (such as enchantments) are the same, while not having to worry about
|
||||
* capabilities.
|
||||
*
|
||||
@@ -61,34 +54,32 @@ public final class InventoryUtil
|
||||
|
||||
// A more expanded form of ItemStack.areShareTagsEqual, but allowing an empty tag to be equal to a
|
||||
// null one.
|
||||
CompoundTag shareTagA = a.getItem().getShareTag( a );
|
||||
CompoundTag shareTagB = b.getItem().getShareTag( b );
|
||||
CompoundTag shareTagA = a.getTag();
|
||||
CompoundTag shareTagB = b.getTag();
|
||||
if( shareTagA == shareTagB ) return true;
|
||||
if( shareTagA == null ) return shareTagB.isEmpty();
|
||||
if( shareTagB == null ) return shareTagA.isEmpty();
|
||||
return shareTagA.equals( shareTagB );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static ItemStack copyItem( @Nonnull ItemStack a )
|
||||
{
|
||||
return a.copy();
|
||||
}
|
||||
|
||||
// Methods for finding inventories:
|
||||
|
||||
public static IItemHandler getInventory( World world, BlockPos pos, Direction side )
|
||||
public static Inventory getInventory( World world, BlockPos pos, Direction side )
|
||||
{
|
||||
// Look for tile with inventory
|
||||
BlockEntity tileEntity = world.getBlockEntity( pos );
|
||||
if( tileEntity != null )
|
||||
int y = pos.getY();
|
||||
if( y >= 0 && y < world.getHeight() )
|
||||
{
|
||||
LazyOptional<IItemHandler> itemHandler = tileEntity.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side );
|
||||
if( itemHandler.isPresent() )
|
||||
BlockEntity tileEntity = world.getBlockEntity( pos );
|
||||
if( tileEntity instanceof Inventory )
|
||||
{
|
||||
return itemHandler.orElseThrow( NullPointerException::new );
|
||||
}
|
||||
else if( side != null && tileEntity instanceof SidedInventory )
|
||||
{
|
||||
return new SidedInvWrapper( (SidedInventory) tileEntity, side );
|
||||
}
|
||||
else if( tileEntity instanceof Inventory )
|
||||
{
|
||||
return new InvWrapper( (Inventory) tileEntity );
|
||||
return (Inventory) tileEntity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,28 +99,34 @@ public final class InventoryUtil
|
||||
Entity entity = hit.getKey();
|
||||
if( entity instanceof Inventory )
|
||||
{
|
||||
return new InvWrapper( (Inventory) entity );
|
||||
return (Inventory) entity;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ItemStorage getStorage( World world, BlockPos pos, Direction side )
|
||||
{
|
||||
Inventory inventory = getInventory( world, pos, side );
|
||||
return inventory == null ? null : ItemStorage.wrap( inventory, side );
|
||||
}
|
||||
|
||||
// Methods for placing into inventories:
|
||||
|
||||
@Nonnull
|
||||
public static ItemStack storeItems( @Nonnull ItemStack itemstack, IItemHandler inventory, int begin )
|
||||
public static ItemStack storeItems( @Nonnull ItemStack itemstack, ItemStorage inventory, int begin )
|
||||
{
|
||||
return storeItems( itemstack, inventory, 0, inventory.getSlots(), begin );
|
||||
return storeItems( itemstack, inventory, 0, inventory.size(), begin );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static ItemStack storeItems( @Nonnull ItemStack itemstack, IItemHandler inventory )
|
||||
public static ItemStack storeItems( @Nonnull ItemStack itemstack, ItemStorage inventory )
|
||||
{
|
||||
return storeItems( itemstack, inventory, 0, inventory.getSlots(), 0 );
|
||||
return storeItems( itemstack, inventory, 0, inventory.size(), 0 );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static ItemStack storeItems( @Nonnull ItemStack stack, IItemHandler inventory, int start, int range, int begin )
|
||||
public static ItemStack storeItems( @Nonnull ItemStack stack, ItemStorage inventory, int start, int range, int begin )
|
||||
{
|
||||
if( stack.isEmpty() ) return ItemStack.EMPTY;
|
||||
|
||||
@@ -139,7 +136,7 @@ public final class InventoryUtil
|
||||
{
|
||||
int slot = start + (i + begin - start) % range;
|
||||
if( remainder.isEmpty() ) break;
|
||||
remainder = inventory.insertItem( slot, remainder, false );
|
||||
remainder = inventory.store( slot, remainder, false );
|
||||
}
|
||||
return areItemsEqual( stack, remainder ) ? stack : remainder;
|
||||
}
|
||||
@@ -147,51 +144,42 @@ public final class InventoryUtil
|
||||
// Methods for taking out of inventories
|
||||
|
||||
@Nonnull
|
||||
public static ItemStack takeItems( int count, IItemHandler inventory, int begin )
|
||||
public static ItemStack takeItems( int count, ItemStorage inventory, int begin )
|
||||
{
|
||||
return takeItems( count, inventory, 0, inventory.getSlots(), begin );
|
||||
return takeItems( count, inventory, 0, inventory.size(), begin );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static ItemStack takeItems( int count, IItemHandler inventory )
|
||||
public static ItemStack takeItems( int count, ItemStorage inventory )
|
||||
{
|
||||
return takeItems( count, inventory, 0, inventory.getSlots(), 0 );
|
||||
return takeItems( count, inventory, 0, inventory.size(), 0 );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static ItemStack takeItems( int count, IItemHandler inventory, int start, int range, int begin )
|
||||
public static ItemStack takeItems( int count, ItemStorage inventory, int start, int range, int begin )
|
||||
{
|
||||
// Combine multiple stacks from inventory into one if necessary
|
||||
ItemStack partialStack = ItemStack.EMPTY;
|
||||
for( int i = 0; i < range; i++ )
|
||||
{
|
||||
int slot = start + (i + begin - start) % range;
|
||||
|
||||
// If we've extracted all items, return
|
||||
if( count <= 0 ) break;
|
||||
|
||||
// If this doesn't slot, abort.
|
||||
ItemStack stack = inventory.getStackInSlot( slot );
|
||||
if( !stack.isEmpty() && (partialStack.isEmpty() || areItemsStackable( stack, partialStack )) )
|
||||
ItemStack extracted = inventory.take( slot, count, partialStack, false );
|
||||
if( extracted.isEmpty() ) continue;
|
||||
|
||||
count -= extracted.getCount();
|
||||
if( partialStack.isEmpty() )
|
||||
{
|
||||
ItemStack extracted = inventory.extractItem( slot, count, false );
|
||||
if( !extracted.isEmpty() )
|
||||
{
|
||||
if( partialStack.isEmpty() )
|
||||
{
|
||||
// If we've extracted for this first time, then limit the count to the maximum stack size.
|
||||
partialStack = extracted;
|
||||
count = Math.min( count, extracted.getMaxCount() );
|
||||
}
|
||||
else
|
||||
{
|
||||
partialStack.increment( extracted.getCount() );
|
||||
}
|
||||
|
||||
count -= extracted.getCount();
|
||||
}
|
||||
// If we've extracted for this first time, then limit the count to the maximum stack size.
|
||||
partialStack = extracted;
|
||||
count = Math.min( count, extracted.getMaxCount() );
|
||||
}
|
||||
else
|
||||
{
|
||||
partialStack.increment( extracted.getCount() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return partialStack;
|
||||
|
229
src/main/java/dan200/computercraft/shared/util/ItemStorage.java
Normal file
229
src/main/java/dan200/computercraft/shared/util/ItemStorage.java
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
|
||||
package dan200.computercraft.shared.util;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.inventory.SidedInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
/**
|
||||
* The most cutesy alternative of {@code IItemHandler} the world has ever seen.
|
||||
*/
|
||||
public interface ItemStorage {
|
||||
int size();
|
||||
|
||||
@Nonnull
|
||||
ItemStack take(int slot, int limit, @Nonnull ItemStack filter, boolean simulate);
|
||||
|
||||
@Nonnull
|
||||
ItemStack store(int slot, @Nonnull ItemStack stack, boolean simulate);
|
||||
|
||||
default ItemStorage view(int start, int size) {
|
||||
return new View(this, start, size);
|
||||
}
|
||||
|
||||
class InventoryWrapper implements ItemStorage {
|
||||
private final Inventory inventory;
|
||||
|
||||
InventoryWrapper(Inventory inventory) {
|
||||
this.inventory = inventory;
|
||||
}
|
||||
|
||||
private void setAndDirty(int slot, @Nonnull ItemStack stack) {
|
||||
inventory.setStack(slot, stack);
|
||||
inventory.markDirty();
|
||||
}
|
||||
|
||||
protected boolean canExtract(int slot, ItemStack stack) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return inventory.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public ItemStack take(int slot, int limit, @Nonnull ItemStack filter, boolean simulate) {
|
||||
ItemStack existing = inventory.getStack(slot);
|
||||
if (existing.isEmpty() || !canExtract(slot, existing) || (!filter.isEmpty() && !areStackable(existing, filter))) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
if (simulate) {
|
||||
existing = existing.copy();
|
||||
if (existing.getCount() > limit) {
|
||||
existing.setCount(limit);
|
||||
}
|
||||
return existing;
|
||||
} else if (existing.getCount() < limit) {
|
||||
setAndDirty(slot, ItemStack.EMPTY);
|
||||
return existing;
|
||||
} else {
|
||||
ItemStack result = existing.split(limit);
|
||||
setAndDirty(slot, existing);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public ItemStack store(int slot, @Nonnull ItemStack stack, boolean simulate) {
|
||||
if (stack.isEmpty() || !inventory.isValid(slot, stack)) {
|
||||
return stack;
|
||||
}
|
||||
|
||||
ItemStack existing = inventory.getStack(slot);
|
||||
if (existing.isEmpty()) {
|
||||
int limit = Math.min(stack.getMaxCount(), inventory.getMaxCountPerStack());
|
||||
if (limit <= 0) {
|
||||
return stack;
|
||||
}
|
||||
|
||||
if (stack.getCount() < limit) {
|
||||
if (!simulate) {
|
||||
setAndDirty(slot, stack);
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
} else {
|
||||
stack = stack.copy();
|
||||
ItemStack insert = stack.split(limit);
|
||||
if (!simulate) {
|
||||
setAndDirty(slot, insert);
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
} else if (areStackable(stack, existing)) {
|
||||
int limit = Math.min(existing.getMaxCount(), inventory.getMaxCountPerStack()) - existing.getCount();
|
||||
if (limit <= 0) {
|
||||
return stack;
|
||||
}
|
||||
|
||||
if (stack.getCount() < limit) {
|
||||
if (!simulate) {
|
||||
existing.increment(stack.getCount());
|
||||
setAndDirty(slot, existing);
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
} else {
|
||||
stack = stack.copy();
|
||||
stack.decrement(limit);
|
||||
if (!simulate) {
|
||||
existing.increment(limit);
|
||||
setAndDirty(slot, existing);
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
} else {
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SidedInventoryWrapper extends InventoryWrapper {
|
||||
private final SidedInventory inventory;
|
||||
private final Direction facing;
|
||||
|
||||
SidedInventoryWrapper(SidedInventory inventory, Direction facing) {
|
||||
super(inventory);
|
||||
this.inventory = inventory;
|
||||
this.facing = facing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return inventory.getAvailableSlots(facing).length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canExtract(int slot, ItemStack stack) {
|
||||
return super.canExtract(slot, stack) && inventory.canExtract(slot, stack, facing);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack take(int slot, int limit, @Nonnull ItemStack filter, boolean simulate) {
|
||||
int[] slots = inventory.getAvailableSlots(facing);
|
||||
return slot >= 0 && slot < slots.length ? super.take(slots[slot], limit, filter, simulate) : ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack store(int slot, @Nonnull ItemStack stack, boolean simulate) {
|
||||
int[] slots = inventory.getAvailableSlots(facing);
|
||||
if (slot < 0 || slot >= slots.length) {
|
||||
return stack;
|
||||
}
|
||||
|
||||
int mappedSlot = slots[slot];
|
||||
if (!inventory.canInsert(slot, stack, facing)) {
|
||||
return stack;
|
||||
}
|
||||
return super.store(mappedSlot, stack, simulate);
|
||||
}
|
||||
}
|
||||
|
||||
class View implements ItemStorage {
|
||||
private final ItemStorage parent;
|
||||
private final int start;
|
||||
private final int size;
|
||||
|
||||
View(ItemStorage parent, int start, int size) {
|
||||
this.parent = parent;
|
||||
this.start = start;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack take(int slot, int limit, @Nonnull ItemStack filter, boolean simulate) {
|
||||
if (slot < start || slot >= start + size) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
return parent.take(slot - start, limit, filter, simulate);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack store(int slot, @Nonnull ItemStack stack, boolean simulate) {
|
||||
if (slot < start || slot >= start + size) {
|
||||
return stack;
|
||||
}
|
||||
return parent.store(slot - start, stack, simulate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStorage view(int start, int size) {
|
||||
return new View(this.parent, this.start + start, size);
|
||||
}
|
||||
}
|
||||
|
||||
static ItemStorage wrap(Inventory inventory) {
|
||||
return new InventoryWrapper(inventory);
|
||||
}
|
||||
|
||||
static ItemStorage wrap(@Nonnull SidedInventory inventory, @Nonnull Direction facing) {
|
||||
return new SidedInventoryWrapper(inventory, facing);
|
||||
}
|
||||
|
||||
static ItemStorage wrap(@Nonnull Inventory inventory, @Nonnull Direction facing) {
|
||||
return inventory instanceof SidedInventory ? new SidedInventoryWrapper((SidedInventory) inventory, facing) : new InventoryWrapper(inventory);
|
||||
}
|
||||
|
||||
static boolean areStackable(@Nonnull ItemStack a, @Nonnull ItemStack b) {
|
||||
return a == b || (a.getItem() == b.getItem() && ItemStack.areTagsEqual(a, b));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user