Code/net/minecraft/world/level/block/CrafterBlock.java

238 lines
11 KiB
Java
Raw Normal View History

2025-07-01 06:20:03 +00:00
package net.minecraft.world.level.block;
import com.mojang.serialization.MapCodec;
import java.util.Optional;
import javax.annotation.Nullable;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.FrontAndTop;
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.RandomSource;
import net.minecraft.world.Container;
import net.minecraft.world.Containers;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.item.crafting.CraftingInput;
import net.minecraft.world.item.crafting.CraftingRecipe;
import net.minecraft.world.item.crafting.RecipeCache;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.entity.CrafterBlockEntity;
import net.minecraft.world.level.block.entity.HopperBlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.level.redstone.Orientation;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
public class CrafterBlock extends BaseEntityBlock {
public static final MapCodec<CrafterBlock> CODEC = simpleCodec(CrafterBlock::new);
public static final BooleanProperty CRAFTING = BlockStateProperties.CRAFTING;
public static final BooleanProperty TRIGGERED = BlockStateProperties.TRIGGERED;
private static final EnumProperty<FrontAndTop> ORIENTATION = BlockStateProperties.ORIENTATION;
private static final int MAX_CRAFTING_TICKS = 6;
private static final int CRAFTING_TICK_DELAY = 4;
private static final RecipeCache RECIPE_CACHE = new RecipeCache(10);
private static final int CRAFTER_ADVANCEMENT_DIAMETER = 17;
public CrafterBlock(BlockBehaviour.Properties p_310228_) {
super(p_310228_);
this.registerDefaultState(this.stateDefinition.any().setValue(ORIENTATION, FrontAndTop.NORTH_UP).setValue(TRIGGERED, false).setValue(CRAFTING, false));
}
@Override
protected MapCodec<CrafterBlock> codec() {
return CODEC;
}
@Override
protected boolean hasAnalogOutputSignal(BlockState p_309929_) {
return true;
}
@Override
protected int getAnalogOutputSignal(BlockState p_311332_, Level p_310277_, BlockPos p_312038_) {
return p_310277_.getBlockEntity(p_312038_) instanceof CrafterBlockEntity crafterblockentity ? crafterblockentity.getRedstoneSignal() : 0;
}
@Override
protected void neighborChanged(BlockState p_309741_, Level p_312714_, BlockPos p_310958_, Block p_313237_, @Nullable Orientation p_364282_, boolean p_309615_) {
boolean flag = p_312714_.hasNeighborSignal(p_310958_);
boolean flag1 = p_309741_.getValue(TRIGGERED);
BlockEntity blockentity = p_312714_.getBlockEntity(p_310958_);
if (flag && !flag1) {
p_312714_.scheduleTick(p_310958_, this, 4);
p_312714_.setBlock(p_310958_, p_309741_.setValue(TRIGGERED, true), 2);
this.setBlockEntityTriggered(blockentity, true);
} else if (!flag && flag1) {
p_312714_.setBlock(p_310958_, p_309741_.setValue(TRIGGERED, false).setValue(CRAFTING, false), 2);
this.setBlockEntityTriggered(blockentity, false);
}
}
@Override
protected void tick(BlockState p_310321_, ServerLevel p_312701_, BlockPos p_311281_, RandomSource p_311092_) {
this.dispenseFrom(p_310321_, p_312701_, p_311281_);
}
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level p_310928_, BlockState p_311648_, BlockEntityType<T> p_310343_) {
return p_310928_.isClientSide ? null : createTickerHelper(p_310343_, BlockEntityType.CRAFTER, CrafterBlockEntity::serverTick);
}
private void setBlockEntityTriggered(@Nullable BlockEntity p_312888_, boolean p_312611_) {
if (p_312888_ instanceof CrafterBlockEntity crafterblockentity) {
crafterblockentity.setTriggered(p_312611_);
}
}
@Override
public BlockEntity newBlockEntity(BlockPos p_311818_, BlockState p_310225_) {
CrafterBlockEntity crafterblockentity = new CrafterBlockEntity(p_311818_, p_310225_);
crafterblockentity.setTriggered(p_310225_.hasProperty(TRIGGERED) && p_310225_.getValue(TRIGGERED));
return crafterblockentity;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext p_311294_) {
Direction direction = p_311294_.getNearestLookingDirection().getOpposite();
Direction direction1 = switch (direction) {
case DOWN -> p_311294_.getHorizontalDirection().getOpposite();
case UP -> p_311294_.getHorizontalDirection();
case NORTH, SOUTH, WEST, EAST -> Direction.UP;
};
return this.defaultBlockState()
.setValue(ORIENTATION, FrontAndTop.fromFrontAndTop(direction, direction1))
.setValue(TRIGGERED, p_311294_.getLevel().hasNeighborSignal(p_311294_.getClickedPos()));
}
@Override
public void setPlacedBy(Level p_311617_, BlockPos p_313069_, BlockState p_310230_, LivingEntity p_310379_, ItemStack p_311227_) {
if (p_310230_.getValue(TRIGGERED)) {
p_311617_.scheduleTick(p_313069_, this, 4);
}
}
@Override
protected void affectNeighborsAfterRemoval(BlockState p_395375_, ServerLevel p_396974_, BlockPos p_391725_, boolean p_392912_) {
Containers.updateNeighboursAfterDestroy(p_395375_, p_396974_, p_391725_);
}
@Override
protected InteractionResult useWithoutItem(BlockState p_309704_, Level p_312700_, BlockPos p_310945_, Player p_312953_, BlockHitResult p_309965_) {
if (!p_312700_.isClientSide && p_312700_.getBlockEntity(p_310945_) instanceof CrafterBlockEntity crafterblockentity) {
p_312953_.openMenu(crafterblockentity);
}
return InteractionResult.SUCCESS;
}
protected void dispenseFrom(BlockState p_313036_, ServerLevel p_310451_, BlockPos p_310774_) {
if (p_310451_.getBlockEntity(p_310774_) instanceof CrafterBlockEntity crafterblockentity) {
CraftingInput craftinginput = crafterblockentity.asCraftInput();
Optional<RecipeHolder<CraftingRecipe>> optional = getPotentialResults(p_310451_, craftinginput);
if (optional.isEmpty()) {
p_310451_.levelEvent(1050, p_310774_, 0);
} else {
RecipeHolder<CraftingRecipe> recipeholder = optional.get();
ItemStack itemstack = recipeholder.value().assemble(craftinginput, p_310451_.registryAccess());
if (itemstack.isEmpty()) {
p_310451_.levelEvent(1050, p_310774_, 0);
} else {
crafterblockentity.setCraftingTicksRemaining(6);
p_310451_.setBlock(p_310774_, p_313036_.setValue(CRAFTING, true), 2);
itemstack.onCraftedBySystem(p_310451_);
this.dispenseItem(p_310451_, p_310774_, crafterblockentity, itemstack, p_313036_, recipeholder);
for (ItemStack itemstack1 : recipeholder.value().getRemainingItems(craftinginput)) {
if (!itemstack1.isEmpty()) {
this.dispenseItem(p_310451_, p_310774_, crafterblockentity, itemstack1, p_313036_, recipeholder);
}
}
crafterblockentity.getItems().forEach(p_312802_ -> {
if (!p_312802_.isEmpty()) {
p_312802_.shrink(1);
}
});
crafterblockentity.setChanged();
}
}
}
}
public static Optional<RecipeHolder<CraftingRecipe>> getPotentialResults(ServerLevel p_367007_, CraftingInput p_342419_) {
return RECIPE_CACHE.get(p_367007_, p_342419_);
}
private void dispenseItem(
ServerLevel p_336186_, BlockPos p_312358_, CrafterBlockEntity p_309887_, ItemStack p_310474_, BlockState p_310667_, RecipeHolder<?> p_329387_
) {
Direction direction = p_310667_.getValue(ORIENTATION).front();
Container container = HopperBlockEntity.getContainerAt(p_336186_, p_312358_.relative(direction));
ItemStack itemstack = p_310474_.copy();
if (container != null && (container instanceof CrafterBlockEntity || p_310474_.getCount() > container.getMaxStackSize(p_310474_))) {
while (!itemstack.isEmpty()) {
ItemStack itemstack2 = itemstack.copyWithCount(1);
ItemStack itemstack1 = HopperBlockEntity.addItem(p_309887_, container, itemstack2, direction.getOpposite());
if (!itemstack1.isEmpty()) {
break;
}
itemstack.shrink(1);
}
} else if (container != null) {
while (!itemstack.isEmpty()) {
int i = itemstack.getCount();
itemstack = HopperBlockEntity.addItem(p_309887_, container, itemstack, direction.getOpposite());
if (i == itemstack.getCount()) {
break;
}
}
}
if (!itemstack.isEmpty()) {
Vec3 vec3 = Vec3.atCenterOf(p_312358_);
Vec3 vec31 = vec3.relative(direction, 0.7);
DefaultDispenseItemBehavior.spawnItem(p_336186_, itemstack, 6, direction, vec31);
for (ServerPlayer serverplayer : p_336186_.getEntitiesOfClass(ServerPlayer.class, AABB.ofSize(vec3, 17.0, 17.0, 17.0))) {
CriteriaTriggers.CRAFTER_RECIPE_CRAFTED.trigger(serverplayer, p_329387_.id(), p_309887_.getItems());
}
p_336186_.levelEvent(1049, p_312358_, 0);
p_336186_.levelEvent(2010, p_312358_, direction.get3DDataValue());
}
}
@Override
protected BlockState rotate(BlockState p_312403_, Rotation p_309910_) {
return p_312403_.setValue(ORIENTATION, p_309910_.rotation().rotate(p_312403_.getValue(ORIENTATION)));
}
@Override
protected BlockState mirror(BlockState p_310178_, Mirror p_311418_) {
return p_310178_.setValue(ORIENTATION, p_311418_.rotation().rotate(p_310178_.getValue(ORIENTATION)));
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> p_310076_) {
p_310076_.add(ORIENTATION, TRIGGERED, CRAFTING);
}
}