309 lines
11 KiB
Java
309 lines
11 KiB
Java
package net.minecraft.world.level.block.entity;
|
|
|
|
import java.util.stream.IntStream;
|
|
import net.minecraft.world.Container;
|
|
import net.minecraft.world.inventory.ShulkerBoxMenu;
|
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
|
import net.minecraft.world.entity.player.Inventory;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.level.block.Block;
|
|
import net.minecraft.world.ContainerHelper;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.network.chat.TranslatableComponent;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.sounds.SoundSource;
|
|
import net.minecraft.sounds.SoundEvents;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.level.LevelAccessor;
|
|
import java.util.List;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import net.minecraft.world.entity.MoverType;
|
|
import net.minecraft.world.level.material.PushReaction;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.phys.shapes.Shapes;
|
|
import net.minecraft.world.level.block.state.properties.Property;
|
|
import net.minecraft.world.level.block.ShulkerBoxBlock;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.world.phys.AABB;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.world.item.DyeColor;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.core.NonNullList;
|
|
import net.minecraft.world.WorldlyContainer;
|
|
|
|
public class ShulkerBoxBlockEntity extends RandomizableContainerBlockEntity implements WorldlyContainer, TickableBlockEntity {
|
|
private static final int[] SLOTS;
|
|
private NonNullList<ItemStack> itemStacks;
|
|
private int openCount;
|
|
private AnimationStatus animationStatus;
|
|
private float progress;
|
|
private float progressOld;
|
|
@Nullable
|
|
private DyeColor color;
|
|
private boolean loadColorFromBlock;
|
|
|
|
public ShulkerBoxBlockEntity(@Nullable final DyeColor bdg) {
|
|
super(BlockEntityType.SHULKER_BOX);
|
|
this.itemStacks = NonNullList.<ItemStack>withSize(27, ItemStack.EMPTY);
|
|
this.animationStatus = AnimationStatus.CLOSED;
|
|
this.color = bdg;
|
|
}
|
|
|
|
public ShulkerBoxBlockEntity() {
|
|
this((DyeColor)null);
|
|
this.loadColorFromBlock = true;
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
this.updateAnimation();
|
|
if (this.animationStatus == AnimationStatus.OPENING || this.animationStatus == AnimationStatus.CLOSING) {
|
|
this.moveCollidedEntities();
|
|
}
|
|
}
|
|
|
|
protected void updateAnimation() {
|
|
this.progressOld = this.progress;
|
|
switch (this.animationStatus) {
|
|
case CLOSED: {
|
|
this.progress = 0.0f;
|
|
break;
|
|
}
|
|
case OPENING: {
|
|
this.progress += 0.1f;
|
|
if (this.progress >= 1.0f) {
|
|
this.moveCollidedEntities();
|
|
this.animationStatus = AnimationStatus.OPENED;
|
|
this.progress = 1.0f;
|
|
this.doNeighborUpdates();
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case CLOSING: {
|
|
this.progress -= 0.1f;
|
|
if (this.progress <= 0.0f) {
|
|
this.animationStatus = AnimationStatus.CLOSED;
|
|
this.progress = 0.0f;
|
|
this.doNeighborUpdates();
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case OPENED: {
|
|
this.progress = 1.0f;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public AnimationStatus getAnimationStatus() {
|
|
return this.animationStatus;
|
|
}
|
|
|
|
public AABB getBoundingBox(final BlockState byg) {
|
|
return this.getBoundingBox(byg.<Direction>getValue(ShulkerBoxBlock.FACING));
|
|
}
|
|
|
|
public AABB getBoundingBox(final Direction fp) {
|
|
final float float3 = this.getProgress(1.0f);
|
|
return Shapes.block().bounds().expandTowards(0.5f * float3 * fp.getStepX(), 0.5f * float3 * fp.getStepY(), 0.5f * float3 * fp.getStepZ());
|
|
}
|
|
|
|
private AABB getTopBoundingBox(final Direction fp) {
|
|
final Direction fp2 = fp.getOpposite();
|
|
return this.getBoundingBox(fp).contract(fp2.getStepX(), fp2.getStepY(), fp2.getStepZ());
|
|
}
|
|
|
|
private void moveCollidedEntities() {
|
|
final BlockState byg2 = this.level.getBlockState(this.getBlockPos());
|
|
if (!(byg2.getBlock() instanceof ShulkerBoxBlock)) {
|
|
return;
|
|
}
|
|
final Direction fp3 = byg2.<Direction>getValue(ShulkerBoxBlock.FACING);
|
|
final AABB cvc4 = this.getTopBoundingBox(fp3).move(this.worldPosition);
|
|
final List<Entity> list5 = this.level.getEntities(null, cvc4);
|
|
if (list5.isEmpty()) {
|
|
return;
|
|
}
|
|
for (int integer6 = 0; integer6 < list5.size(); ++integer6) {
|
|
final Entity akn7 = list5.get(integer6);
|
|
if (akn7.getPistonPushReaction() != PushReaction.IGNORE) {
|
|
double double8 = 0.0;
|
|
double double9 = 0.0;
|
|
double double10 = 0.0;
|
|
final AABB cvc5 = akn7.getBoundingBox();
|
|
switch (fp3.getAxis()) {
|
|
case X: {
|
|
if (fp3.getAxisDirection() == Direction.AxisDirection.POSITIVE) {
|
|
double8 = cvc4.maxX - cvc5.minX;
|
|
}
|
|
else {
|
|
double8 = cvc5.maxX - cvc4.minX;
|
|
}
|
|
double8 += 0.01;
|
|
break;
|
|
}
|
|
case Y: {
|
|
if (fp3.getAxisDirection() == Direction.AxisDirection.POSITIVE) {
|
|
double9 = cvc4.maxY - cvc5.minY;
|
|
}
|
|
else {
|
|
double9 = cvc5.maxY - cvc4.minY;
|
|
}
|
|
double9 += 0.01;
|
|
break;
|
|
}
|
|
case Z: {
|
|
if (fp3.getAxisDirection() == Direction.AxisDirection.POSITIVE) {
|
|
double10 = cvc4.maxZ - cvc5.minZ;
|
|
}
|
|
else {
|
|
double10 = cvc5.maxZ - cvc4.minZ;
|
|
}
|
|
double10 += 0.01;
|
|
break;
|
|
}
|
|
}
|
|
akn7.move(MoverType.SHULKER_BOX, new Vec3(double8 * fp3.getStepX(), double9 * fp3.getStepY(), double10 * fp3.getStepZ()));
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getContainerSize() {
|
|
return this.itemStacks.size();
|
|
}
|
|
|
|
@Override
|
|
public boolean triggerEvent(final int integer1, final int integer2) {
|
|
if (integer1 == 1) {
|
|
if ((this.openCount = integer2) == 0) {
|
|
this.animationStatus = AnimationStatus.CLOSING;
|
|
this.doNeighborUpdates();
|
|
}
|
|
if (integer2 == 1) {
|
|
this.animationStatus = AnimationStatus.OPENING;
|
|
this.doNeighborUpdates();
|
|
}
|
|
return true;
|
|
}
|
|
return super.triggerEvent(integer1, integer2);
|
|
}
|
|
|
|
private void doNeighborUpdates() {
|
|
this.getBlockState().updateNeighbourShapes(this.getLevel(), this.getBlockPos(), 3);
|
|
}
|
|
|
|
@Override
|
|
public void startOpen(final Player ayg) {
|
|
if (!ayg.isSpectator()) {
|
|
if (this.openCount < 0) {
|
|
this.openCount = 0;
|
|
}
|
|
++this.openCount;
|
|
this.level.blockEvent(this.worldPosition, this.getBlockState().getBlock(), 1, this.openCount);
|
|
if (this.openCount == 1) {
|
|
this.level.playSound(null, this.worldPosition, SoundEvents.SHULKER_BOX_OPEN, SoundSource.BLOCKS, 0.5f, this.level.random.nextFloat() * 0.1f + 0.9f);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void stopOpen(final Player ayg) {
|
|
if (!ayg.isSpectator()) {
|
|
--this.openCount;
|
|
this.level.blockEvent(this.worldPosition, this.getBlockState().getBlock(), 1, this.openCount);
|
|
if (this.openCount <= 0) {
|
|
this.level.playSound(null, this.worldPosition, SoundEvents.SHULKER_BOX_CLOSE, SoundSource.BLOCKS, 0.5f, this.level.random.nextFloat() * 0.1f + 0.9f);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected Component getDefaultName() {
|
|
return new TranslatableComponent("container.shulkerBox", new Object[0]);
|
|
}
|
|
|
|
@Override
|
|
public void load(final CompoundTag jt) {
|
|
super.load(jt);
|
|
this.loadFromTag(jt);
|
|
}
|
|
|
|
@Override
|
|
public CompoundTag save(final CompoundTag jt) {
|
|
super.save(jt);
|
|
return this.saveToTag(jt);
|
|
}
|
|
|
|
public void loadFromTag(final CompoundTag jt) {
|
|
this.itemStacks = NonNullList.<ItemStack>withSize(this.getContainerSize(), ItemStack.EMPTY);
|
|
if (!this.tryLoadLootTable(jt) && jt.contains("Items", 9)) {
|
|
ContainerHelper.loadAllItems(jt, this.itemStacks);
|
|
}
|
|
}
|
|
|
|
public CompoundTag saveToTag(final CompoundTag jt) {
|
|
if (!this.trySaveLootTable(jt)) {
|
|
ContainerHelper.saveAllItems(jt, this.itemStacks, false);
|
|
}
|
|
return jt;
|
|
}
|
|
|
|
@Override
|
|
protected NonNullList<ItemStack> getItems() {
|
|
return this.itemStacks;
|
|
}
|
|
|
|
@Override
|
|
protected void setItems(final NonNullList<ItemStack> fy) {
|
|
this.itemStacks = fy;
|
|
}
|
|
|
|
@Override
|
|
public int[] getSlotsForFace(final Direction fp) {
|
|
return ShulkerBoxBlockEntity.SLOTS;
|
|
}
|
|
|
|
@Override
|
|
public boolean canPlaceItemThroughFace(final int integer, final ItemStack bek, @Nullable final Direction fp) {
|
|
return !(Block.byItem(bek.getItem()) instanceof ShulkerBoxBlock);
|
|
}
|
|
|
|
@Override
|
|
public boolean canTakeItemThroughFace(final int integer, final ItemStack bek, final Direction fp) {
|
|
return true;
|
|
}
|
|
|
|
public float getProgress(final float float1) {
|
|
return Mth.lerp(float1, this.progressOld, this.progress);
|
|
}
|
|
|
|
@Nullable
|
|
public DyeColor getColor() {
|
|
if (this.loadColorFromBlock) {
|
|
this.color = ShulkerBoxBlock.getColorFromBlock(this.getBlockState().getBlock());
|
|
this.loadColorFromBlock = false;
|
|
}
|
|
return this.color;
|
|
}
|
|
|
|
@Override
|
|
protected AbstractContainerMenu createMenu(final int integer, final Inventory ayf) {
|
|
return new ShulkerBoxMenu(integer, ayf, this);
|
|
}
|
|
|
|
static {
|
|
SLOTS = IntStream.range(0, 27).toArray();
|
|
}
|
|
|
|
public enum AnimationStatus {
|
|
CLOSED,
|
|
OPENING,
|
|
OPENED,
|
|
CLOSING;
|
|
}
|
|
}
|