224 lines
8.3 KiB
Java
224 lines
8.3 KiB
Java
package net.minecraft.world.item;
|
|
|
|
import java.util.Map;
|
|
import net.minecraft.advancements.CriteriaTriggers;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.component.DataComponents;
|
|
import net.minecraft.core.registries.Registries;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.server.level.ServerPlayer;
|
|
import net.minecraft.sounds.SoundEvent;
|
|
import net.minecraft.sounds.SoundSource;
|
|
import net.minecraft.world.InteractionResult;
|
|
import net.minecraft.world.entity.item.ItemEntity;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.flag.FeatureFlagSet;
|
|
import net.minecraft.world.item.component.BlockItemStateProperties;
|
|
import net.minecraft.world.item.component.CustomData;
|
|
import net.minecraft.world.item.component.ItemContainerContents;
|
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
|
import net.minecraft.world.item.context.UseOnContext;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.block.Block;
|
|
import net.minecraft.world.level.block.ShulkerBoxBlock;
|
|
import net.minecraft.world.level.block.SoundType;
|
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.gameevent.GameEvent;
|
|
import net.minecraft.world.level.gameevent.GameEvent.Context;
|
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
public class BlockItem extends Item {
|
|
@Deprecated
|
|
private final Block block;
|
|
|
|
public BlockItem(Block block, Item.Properties properties) {
|
|
super(properties);
|
|
this.block = block;
|
|
}
|
|
|
|
@Override
|
|
public InteractionResult useOn(UseOnContext context) {
|
|
InteractionResult interactionResult = this.place(new BlockPlaceContext(context));
|
|
return !interactionResult.consumesAction() && context.getItemInHand().has(DataComponents.CONSUMABLE)
|
|
? super.use(context.getLevel(), context.getPlayer(), context.getHand())
|
|
: interactionResult;
|
|
}
|
|
|
|
public InteractionResult place(BlockPlaceContext context) {
|
|
if (!this.getBlock().isEnabled(context.getLevel().enabledFeatures())) {
|
|
return InteractionResult.FAIL;
|
|
} else if (!context.canPlace()) {
|
|
return InteractionResult.FAIL;
|
|
} else {
|
|
BlockPlaceContext blockPlaceContext = this.updatePlacementContext(context);
|
|
if (blockPlaceContext == null) {
|
|
return InteractionResult.FAIL;
|
|
} else {
|
|
BlockState blockState = this.getPlacementState(blockPlaceContext);
|
|
if (blockState == null) {
|
|
return InteractionResult.FAIL;
|
|
} else if (!this.placeBlock(blockPlaceContext, blockState)) {
|
|
return InteractionResult.FAIL;
|
|
} else {
|
|
BlockPos blockPos = blockPlaceContext.getClickedPos();
|
|
Level level = blockPlaceContext.getLevel();
|
|
Player player = blockPlaceContext.getPlayer();
|
|
ItemStack itemStack = blockPlaceContext.getItemInHand();
|
|
BlockState blockState2 = level.getBlockState(blockPos);
|
|
if (blockState2.is(blockState.getBlock())) {
|
|
blockState2 = this.updateBlockStateFromTag(blockPos, level, itemStack, blockState2);
|
|
this.updateCustomBlockEntityTag(blockPos, level, player, itemStack, blockState2);
|
|
updateBlockEntityComponents(level, blockPos, itemStack);
|
|
blockState2.getBlock().setPlacedBy(level, blockPos, blockState2, player, itemStack);
|
|
if (player instanceof ServerPlayer) {
|
|
CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer)player, blockPos, itemStack);
|
|
}
|
|
}
|
|
|
|
SoundType soundType = blockState2.getSoundType();
|
|
level.playSound(player, blockPos, this.getPlaceSound(blockState2), SoundSource.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F);
|
|
level.gameEvent(GameEvent.BLOCK_PLACE, blockPos, Context.of(player, blockState2));
|
|
itemStack.consume(1, player);
|
|
return InteractionResult.SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected SoundEvent getPlaceSound(BlockState state) {
|
|
return state.getSoundType().getPlaceSound();
|
|
}
|
|
|
|
@Nullable
|
|
public BlockPlaceContext updatePlacementContext(BlockPlaceContext context) {
|
|
return context;
|
|
}
|
|
|
|
private static void updateBlockEntityComponents(Level level, BlockPos poa, ItemStack stack) {
|
|
BlockEntity blockEntity = level.getBlockEntity(poa);
|
|
if (blockEntity != null) {
|
|
blockEntity.applyComponentsFromItemStack(stack);
|
|
blockEntity.setChanged();
|
|
}
|
|
}
|
|
|
|
protected boolean updateCustomBlockEntityTag(BlockPos pos, Level level, @Nullable Player player, ItemStack stack, BlockState state) {
|
|
return updateCustomBlockEntityTag(level, player, pos, stack);
|
|
}
|
|
|
|
@Nullable
|
|
protected BlockState getPlacementState(BlockPlaceContext context) {
|
|
BlockState blockState = this.getBlock().getStateForPlacement(context);
|
|
return blockState != null && this.canPlace(context, blockState) ? blockState : null;
|
|
}
|
|
|
|
private BlockState updateBlockStateFromTag(BlockPos pos, Level level, ItemStack stack, BlockState state) {
|
|
BlockItemStateProperties blockItemStateProperties = stack.getOrDefault(DataComponents.BLOCK_STATE, BlockItemStateProperties.EMPTY);
|
|
if (blockItemStateProperties.isEmpty()) {
|
|
return state;
|
|
} else {
|
|
BlockState blockState = blockItemStateProperties.apply(state);
|
|
if (blockState != state) {
|
|
level.setBlock(pos, blockState, 2);
|
|
}
|
|
|
|
return blockState;
|
|
}
|
|
}
|
|
|
|
protected boolean canPlace(BlockPlaceContext context, BlockState state) {
|
|
Player player = context.getPlayer();
|
|
return (!this.mustSurvive() || state.canSurvive(context.getLevel(), context.getClickedPos()))
|
|
&& context.getLevel().isUnobstructed(state, context.getClickedPos(), CollisionContext.placementContext(player));
|
|
}
|
|
|
|
protected boolean mustSurvive() {
|
|
return true;
|
|
}
|
|
|
|
protected boolean placeBlock(BlockPlaceContext context, BlockState state) {
|
|
return context.getLevel().setBlock(context.getClickedPos(), state, 11);
|
|
}
|
|
|
|
public static boolean updateCustomBlockEntityTag(Level level, @Nullable Player player, BlockPos pos, ItemStack stack) {
|
|
if (level.isClientSide) {
|
|
return false;
|
|
} else {
|
|
CustomData customData = stack.getOrDefault(DataComponents.BLOCK_ENTITY_DATA, CustomData.EMPTY);
|
|
if (!customData.isEmpty()) {
|
|
BlockEntityType<?> blockEntityType = customData.parseEntityType(level.registryAccess(), Registries.BLOCK_ENTITY_TYPE);
|
|
if (blockEntityType == null) {
|
|
return false;
|
|
}
|
|
|
|
BlockEntity blockEntity = level.getBlockEntity(pos);
|
|
if (blockEntity != null) {
|
|
BlockEntityType<?> blockEntityType2 = blockEntity.getType();
|
|
if (blockEntityType2 != blockEntityType) {
|
|
return false;
|
|
}
|
|
|
|
if (!blockEntityType2.onlyOpCanSetNbt() || player != null && player.canUseGameMasterBlocks()) {
|
|
return customData.loadInto(blockEntity, level.registryAccess());
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean shouldPrintOpWarning(ItemStack stack, @Nullable Player player) {
|
|
if (player != null && player.getPermissionLevel() >= 2) {
|
|
CustomData customData = stack.get(DataComponents.BLOCK_ENTITY_DATA);
|
|
if (customData != null) {
|
|
BlockEntityType<?> blockEntityType = customData.parseEntityType(player.level().registryAccess(), Registries.BLOCK_ENTITY_TYPE);
|
|
return blockEntityType != null && blockEntityType.onlyOpCanSetNbt();
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public Block getBlock() {
|
|
return this.block;
|
|
}
|
|
|
|
public void registerBlocks(Map<Block, Item> blockToItemMap, Item item) {
|
|
blockToItemMap.put(this.getBlock(), item);
|
|
}
|
|
|
|
@Override
|
|
public boolean canFitInsideContainerItems() {
|
|
return !(this.getBlock() instanceof ShulkerBoxBlock);
|
|
}
|
|
|
|
@Override
|
|
public void onDestroyed(ItemEntity itemEntity) {
|
|
ItemContainerContents itemContainerContents = itemEntity.getItem().set(DataComponents.CONTAINER, ItemContainerContents.EMPTY);
|
|
if (itemContainerContents != null) {
|
|
ItemUtils.onContainerDestroyed(itemEntity, itemContainerContents.nonEmptyItemsCopy());
|
|
}
|
|
}
|
|
|
|
public static void setBlockEntityData(ItemStack stack, BlockEntityType<?> blockEntityType, CompoundTag blockEntityData) {
|
|
blockEntityData.remove("id");
|
|
if (blockEntityData.isEmpty()) {
|
|
stack.remove(DataComponents.BLOCK_ENTITY_DATA);
|
|
} else {
|
|
BlockEntity.addEntityType(blockEntityData, blockEntityType);
|
|
stack.set(DataComponents.BLOCK_ENTITY_DATA, CustomData.of(blockEntityData));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public FeatureFlagSet requiredFeatures() {
|
|
return this.getBlock().requiredFeatures();
|
|
}
|
|
}
|