Implements opening containers from items with and without a block context.

This commit is contained in:
Sebastian Hartte
2020-06-14 21:23:42 +02:00
parent bdd522e8d9
commit d43e8d19dd
30 changed files with 342 additions and 204 deletions
@@ -23,16 +23,16 @@ import appeng.api.parts.IPartHost;
import appeng.api.util.AEPartLocation;
import appeng.api.util.DimensionalCoord;
import appeng.parts.AEBasePart;
import appeng.parts.misc.PartInterface;
import com.google.common.base.Preconditions;
import io.netty.handler.codec.DecoderException;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext;
import net.minecraft.network.PacketBuffer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import org.apache.commons.lang3.NotImplementedException;
/**
* Describes how a container the player has opened was originally
@@ -47,7 +47,16 @@ import org.apache.commons.lang3.NotImplementedException;
public final class ContainerLocator {
private enum Type {
ITEM,
/**
* An item used from the player's inventory.
*/
PLAYER_INVENTORY,
/**
* An item used from the player's inventory, but right-clicked
* on a block face, has block position and side in addition to the
* above.
*/
PLAYER_INVENTORY_WITH_BLOCK_CONTEXT,
BLOCK,
PART
}
@@ -82,9 +91,38 @@ public final class ContainerLocator {
return new ContainerLocator(Type.PART, -1, dimensionId, te.getPos(), AEPartLocation.fromFacing(side));
}
public static ContainerLocator forHand(Hand hand) {
// FIXME can we get an inventory location for the hand?
throw new IllegalStateException();
/**
* Construct a container locator for an item being used on a block. The item could still open a container
* for itself, but it might also open a special container for the block being right-clicked.
*/
public static ContainerLocator forItemUseContext(ItemUseContext context) {
PlayerEntity player = context.getPlayer();
if (player == null) {
throw new IllegalArgumentException("Cannot open a container without a player");
}
int dimensionId = player.world.getDimension().getType().getId();
int slot = getPlayerInventorySlotFromHand(player, context.getHand());
AEPartLocation side = AEPartLocation.fromFacing(context.getFace());
return new ContainerLocator(Type.PLAYER_INVENTORY_WITH_BLOCK_CONTEXT, slot, dimensionId, context.getPos(), side);
}
public static ContainerLocator forHand(PlayerEntity player, Hand hand) {
int slot = getPlayerInventorySlotFromHand(player, hand);
return new ContainerLocator(Type.PLAYER_INVENTORY, slot, -1, null, null);
}
private static int getPlayerInventorySlotFromHand(PlayerEntity player, Hand hand) {
ItemStack is = player.getHeldItem(hand);
if (is.isEmpty()) {
throw new IllegalArgumentException("Cannot open an item-inventory with empty hands");
}
int invSize = player.inventory.getSizeInventory();
for (int i = 0; i < invSize; i++) {
if (player.inventory.getStackInSlot(i) == is) {
return i;
}
}
throw new IllegalArgumentException("Could not find item held in hand " + hand + " in player inventory");
}
public static ContainerLocator forPart(AEBasePart part) {
@@ -100,11 +138,11 @@ public final class ContainerLocator {
}
public boolean hasItemIndex() {
return type == Type.ITEM;
return type == Type.PLAYER_INVENTORY || type == Type.PLAYER_INVENTORY_WITH_BLOCK_CONTEXT;
}
public int getItemIndex() {
Preconditions.checkState(type == Type.ITEM);
Preconditions.checkState(hasItemIndex());
return itemIndex;
}
@@ -113,36 +151,43 @@ public final class ContainerLocator {
}
public boolean hasBlockPos() {
return type == Type.BLOCK || type == Type.PART;
return type == Type.BLOCK || type == Type.PART || type == Type.PLAYER_INVENTORY_WITH_BLOCK_CONTEXT;
}
public BlockPos getBlockPos() {
Preconditions.checkState(type == Type.BLOCK || type == Type.PART);
Preconditions.checkState(hasBlockPos());
return blockPos;
}
public boolean hasSide() {
return type == Type.PART;
return type == Type.PART || type == Type.PLAYER_INVENTORY_WITH_BLOCK_CONTEXT;
}
public AEPartLocation getSide() {
Preconditions.checkState(type == Type.PART);
Preconditions.checkState(hasSide());
return side;
}
public void write(PacketBuffer buf) {
switch (type) {
case ITEM:
case PLAYER_INVENTORY:
buf.writeByte(0);
buf.writeInt(itemIndex);
break;
case BLOCK:
case PLAYER_INVENTORY_WITH_BLOCK_CONTEXT:
buf.writeByte(1);
buf.writeInt(itemIndex);
buf.writeInt(dimensionId);
buf.writeBlockPos(blockPos);
buf.writeByte(side.ordinal());
break;
case BLOCK:
buf.writeByte(22);
buf.writeInt(dimensionId);
buf.writeBlockPos(blockPos);
break;
case PART:
buf.writeByte(2);
buf.writeByte(3);
buf.writeInt(dimensionId);
buf.writeBlockPos(blockPos);
buf.writeByte(side.ordinal());
@@ -157,13 +202,21 @@ public final class ContainerLocator {
switch (type) {
case 0:
return new ContainerLocator(
Type.ITEM,
Type.PLAYER_INVENTORY,
buf.readInt(),
-1,
null,
null
);
case 1:
return new ContainerLocator(
Type.PLAYER_INVENTORY_WITH_BLOCK_CONTEXT,
buf.readInt(),
buf.readInt(),
buf.readBlockPos(),
AEPartLocation.values()[buf.readByte()]
);
case 2:
return new ContainerLocator(
Type.BLOCK,
-1,
@@ -171,7 +224,7 @@ public final class ContainerLocator {
buf.readBlockPos(),
null
);
case 2:
case 3:
return new ContainerLocator(
Type.PART,
-1,
@@ -184,4 +237,25 @@ public final class ContainerLocator {
}
}
@Override
public String toString() {
StringBuilder result = new StringBuilder(type.name());
result.append('{');
if (hasItemIndex()) {
result.append("slot=").append(itemIndex).append(',');
}
if (hasBlockPos()) {
result.append("dim=").append(dimensionId).append(',');
result.append("pos=").append(blockPos).append(',');
}
if (hasSide()) {
result.append("side=").append(side).append(',');
}
if (result.charAt(result.length() - 1) == ',') {
result.setLength(result.length() - 1);
}
result.append('}');
return result.toString();
}
}