minecraft-src/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
2025-07-04 02:00:41 +03:00

252 lines
7.5 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.HolderLookup;
import net.minecraft.core.NonNullList;
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, HolderLookup.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, HolderLookup.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);
}
}