252 lines
7.4 KiB
Java
252 lines
7.4 KiB
Java
package net.minecraft.world.level.block.entity;
|
|
|
|
import java.util.Arrays;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.core.NonNullList;
|
|
import net.minecraft.core.HolderLookup.Provider;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.tags.ItemTags;
|
|
import net.minecraft.world.ContainerHelper;
|
|
import net.minecraft.world.Containers;
|
|
import net.minecraft.world.WorldlyContainer;
|
|
import net.minecraft.world.entity.player.Inventory;
|
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
|
import net.minecraft.world.inventory.BrewingStandMenu;
|
|
import net.minecraft.world.inventory.ContainerData;
|
|
import net.minecraft.world.item.Item;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.item.Items;
|
|
import net.minecraft.world.item.alchemy.PotionBrewing;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.block.BrewingStandBlock;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements WorldlyContainer {
|
|
private static final int INGREDIENT_SLOT = 3;
|
|
private static final int FUEL_SLOT = 4;
|
|
private static final int[] SLOTS_FOR_UP = new int[]{3};
|
|
private static final int[] SLOTS_FOR_DOWN = new int[]{0, 1, 2, 3};
|
|
private static final int[] SLOTS_FOR_SIDES = new int[]{0, 1, 2, 4};
|
|
public static final int FUEL_USES = 20;
|
|
public static final int DATA_BREW_TIME = 0;
|
|
public static final int DATA_FUEL_USES = 1;
|
|
public static final int NUM_DATA_VALUES = 2;
|
|
/**
|
|
* The items currently placed in the slots of the brewing stand.
|
|
*/
|
|
private NonNullList<ItemStack> items = NonNullList.withSize(5, ItemStack.EMPTY);
|
|
int brewTime;
|
|
private boolean[] lastPotionCount;
|
|
private Item ingredient;
|
|
int fuel;
|
|
protected final ContainerData dataAccess = new ContainerData() {
|
|
@Override
|
|
public int get(int index) {
|
|
return switch (index) {
|
|
case 0 -> BrewingStandBlockEntity.this.brewTime;
|
|
case 1 -> BrewingStandBlockEntity.this.fuel;
|
|
default -> 0;
|
|
};
|
|
}
|
|
|
|
@Override
|
|
public void set(int index, int value) {
|
|
switch (index) {
|
|
case 0:
|
|
BrewingStandBlockEntity.this.brewTime = value;
|
|
break;
|
|
case 1:
|
|
BrewingStandBlockEntity.this.fuel = value;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getCount() {
|
|
return 2;
|
|
}
|
|
};
|
|
|
|
public BrewingStandBlockEntity(BlockPos pos, BlockState state) {
|
|
super(BlockEntityType.BREWING_STAND, pos, state);
|
|
}
|
|
|
|
@Override
|
|
protected Component getDefaultName() {
|
|
return Component.translatable("container.brewing");
|
|
}
|
|
|
|
@Override
|
|
public int getContainerSize() {
|
|
return this.items.size();
|
|
}
|
|
|
|
@Override
|
|
protected NonNullList<ItemStack> getItems() {
|
|
return this.items;
|
|
}
|
|
|
|
@Override
|
|
protected void setItems(NonNullList<ItemStack> items) {
|
|
this.items = items;
|
|
}
|
|
|
|
public static void serverTick(Level level, BlockPos pos, BlockState state, BrewingStandBlockEntity blockEntity) {
|
|
ItemStack itemStack = blockEntity.items.get(4);
|
|
if (blockEntity.fuel <= 0 && itemStack.is(ItemTags.BREWING_FUEL)) {
|
|
blockEntity.fuel = 20;
|
|
itemStack.shrink(1);
|
|
setChanged(level, pos, state);
|
|
}
|
|
|
|
boolean bl = isBrewable(level.potionBrewing(), blockEntity.items);
|
|
boolean bl2 = blockEntity.brewTime > 0;
|
|
ItemStack itemStack2 = blockEntity.items.get(3);
|
|
if (bl2) {
|
|
blockEntity.brewTime--;
|
|
boolean bl3 = blockEntity.brewTime == 0;
|
|
if (bl3 && bl) {
|
|
doBrew(level, pos, blockEntity.items);
|
|
} else if (!bl || !itemStack2.is(blockEntity.ingredient)) {
|
|
blockEntity.brewTime = 0;
|
|
}
|
|
|
|
setChanged(level, pos, state);
|
|
} else if (bl && blockEntity.fuel > 0) {
|
|
blockEntity.fuel--;
|
|
blockEntity.brewTime = 400;
|
|
blockEntity.ingredient = itemStack2.getItem();
|
|
setChanged(level, pos, state);
|
|
}
|
|
|
|
boolean[] bls = blockEntity.getPotionBits();
|
|
if (!Arrays.equals(bls, blockEntity.lastPotionCount)) {
|
|
blockEntity.lastPotionCount = bls;
|
|
BlockState blockState = state;
|
|
if (!(state.getBlock() instanceof BrewingStandBlock)) {
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < BrewingStandBlock.HAS_BOTTLE.length; i++) {
|
|
blockState = blockState.setValue(BrewingStandBlock.HAS_BOTTLE[i], bls[i]);
|
|
}
|
|
|
|
level.setBlock(pos, blockState, 2);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return an array of size 3 where every element represents whether the respective slot is not empty
|
|
*/
|
|
private boolean[] getPotionBits() {
|
|
boolean[] bls = new boolean[3];
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
if (!this.items.get(i).isEmpty()) {
|
|
bls[i] = true;
|
|
}
|
|
}
|
|
|
|
return bls;
|
|
}
|
|
|
|
private static boolean isBrewable(PotionBrewing potionBrewing, NonNullList<ItemStack> items) {
|
|
ItemStack itemStack = items.get(3);
|
|
if (itemStack.isEmpty()) {
|
|
return false;
|
|
} else if (!potionBrewing.isIngredient(itemStack)) {
|
|
return false;
|
|
} else {
|
|
for (int i = 0; i < 3; i++) {
|
|
ItemStack itemStack2 = items.get(i);
|
|
if (!itemStack2.isEmpty() && potionBrewing.hasMix(itemStack2, itemStack)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static void doBrew(Level level, BlockPos pos, NonNullList<ItemStack> items) {
|
|
ItemStack itemStack = items.get(3);
|
|
PotionBrewing potionBrewing = level.potionBrewing();
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
items.set(i, potionBrewing.mix(itemStack, items.get(i)));
|
|
}
|
|
|
|
itemStack.shrink(1);
|
|
ItemStack itemStack2 = itemStack.getItem().getCraftingRemainder();
|
|
if (!itemStack2.isEmpty()) {
|
|
if (itemStack.isEmpty()) {
|
|
itemStack = itemStack2;
|
|
} else {
|
|
Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), itemStack2);
|
|
}
|
|
}
|
|
|
|
items.set(3, itemStack);
|
|
level.levelEvent(1035, pos, 0);
|
|
}
|
|
|
|
@Override
|
|
protected void loadAdditional(CompoundTag tag, Provider registries) {
|
|
super.loadAdditional(tag, registries);
|
|
this.items = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY);
|
|
ContainerHelper.loadAllItems(tag, this.items, registries);
|
|
this.brewTime = tag.getShort("BrewTime");
|
|
if (this.brewTime > 0) {
|
|
this.ingredient = this.items.get(3).getItem();
|
|
}
|
|
|
|
this.fuel = tag.getByte("Fuel");
|
|
}
|
|
|
|
@Override
|
|
protected void saveAdditional(CompoundTag tag, Provider registries) {
|
|
super.saveAdditional(tag, registries);
|
|
tag.putShort("BrewTime", (short)this.brewTime);
|
|
ContainerHelper.saveAllItems(tag, this.items, registries);
|
|
tag.putByte("Fuel", (byte)this.fuel);
|
|
}
|
|
|
|
@Override
|
|
public boolean canPlaceItem(int slot, ItemStack stack) {
|
|
if (slot == 3) {
|
|
PotionBrewing potionBrewing = this.level != null ? this.level.potionBrewing() : PotionBrewing.EMPTY;
|
|
return potionBrewing.isIngredient(stack);
|
|
} else {
|
|
return slot == 4
|
|
? stack.is(ItemTags.BREWING_FUEL)
|
|
: (stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE))
|
|
&& this.getItem(slot).isEmpty();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int[] getSlotsForFace(Direction side) {
|
|
if (side == Direction.UP) {
|
|
return SLOTS_FOR_UP;
|
|
} else {
|
|
return side == Direction.DOWN ? SLOTS_FOR_DOWN : SLOTS_FOR_SIDES;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean canPlaceItemThroughFace(int index, ItemStack itemStack, @Nullable Direction direction) {
|
|
return this.canPlaceItem(index, itemStack);
|
|
}
|
|
|
|
@Override
|
|
public boolean canTakeItemThroughFace(int index, ItemStack stack, Direction direction) {
|
|
return index == 3 ? stack.is(Items.GLASS_BOTTLE) : true;
|
|
}
|
|
|
|
@Override
|
|
protected AbstractContainerMenu createMenu(int containerId, Inventory inventory) {
|
|
return new BrewingStandMenu(containerId, inventory, this, this.dataAccess);
|
|
}
|
|
}
|