minecraft-src/net/minecraft/world/level/block/TripWireBlock.java
2025-07-04 01:41:11 +03:00

218 lines
8.2 KiB
Java

package net.minecraft.world.level.block;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.List;
import java.util.Map;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
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.Property;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class TripWireBlock extends Block {
public static final MapCodec<TripWireBlock> CODEC = RecordCodecBuilder.mapCodec(
instance -> instance.group(BuiltInRegistries.BLOCK.byNameCodec().fieldOf("hook").forGetter(tripWireBlock -> tripWireBlock.hook), propertiesCodec())
.apply(instance, TripWireBlock::new)
);
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
public static final BooleanProperty ATTACHED = BlockStateProperties.ATTACHED;
public static final BooleanProperty DISARMED = BlockStateProperties.DISARMED;
public static final BooleanProperty NORTH = PipeBlock.NORTH;
public static final BooleanProperty EAST = PipeBlock.EAST;
public static final BooleanProperty SOUTH = PipeBlock.SOUTH;
public static final BooleanProperty WEST = PipeBlock.WEST;
private static final Map<Direction, BooleanProperty> PROPERTY_BY_DIRECTION = CrossCollisionBlock.PROPERTY_BY_DIRECTION;
protected static final VoxelShape AABB = Block.box(0.0, 1.0, 0.0, 16.0, 2.5, 16.0);
protected static final VoxelShape NOT_ATTACHED_AABB = Block.box(0.0, 0.0, 0.0, 16.0, 8.0, 16.0);
private static final int RECHECK_PERIOD = 10;
private final Block hook;
@Override
public MapCodec<TripWireBlock> codec() {
return CODEC;
}
public TripWireBlock(Block hook, BlockBehaviour.Properties properties) {
super(properties);
this.registerDefaultState(
this.stateDefinition
.any()
.setValue(POWERED, false)
.setValue(ATTACHED, false)
.setValue(DISARMED, false)
.setValue(NORTH, false)
.setValue(EAST, false)
.setValue(SOUTH, false)
.setValue(WEST, false)
);
this.hook = hook;
}
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return state.getValue(ATTACHED) ? AABB : NOT_ATTACHED_AABB;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockGetter blockGetter = context.getLevel();
BlockPos blockPos = context.getClickedPos();
return this.defaultBlockState()
.setValue(NORTH, this.shouldConnectTo(blockGetter.getBlockState(blockPos.north()), Direction.NORTH))
.setValue(EAST, this.shouldConnectTo(blockGetter.getBlockState(blockPos.east()), Direction.EAST))
.setValue(SOUTH, this.shouldConnectTo(blockGetter.getBlockState(blockPos.south()), Direction.SOUTH))
.setValue(WEST, this.shouldConnectTo(blockGetter.getBlockState(blockPos.west()), Direction.WEST));
}
@Override
protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
return direction.getAxis().isHorizontal()
? state.setValue((Property)PROPERTY_BY_DIRECTION.get(direction), this.shouldConnectTo(neighborState, direction))
: super.updateShape(state, direction, neighborState, level, pos, neighborPos);
}
@Override
protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
if (!oldState.is(state.getBlock())) {
this.updateSource(level, pos, state);
}
}
@Override
protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
if (!movedByPiston && !state.is(newState.getBlock())) {
this.updateSource(level, pos, state.setValue(POWERED, true));
}
}
@Override
public BlockState playerWillDestroy(Level level, BlockPos pos, BlockState state, Player player) {
if (!level.isClientSide && !player.getMainHandItem().isEmpty() && player.getMainHandItem().is(Items.SHEARS)) {
level.setBlock(pos, state.setValue(DISARMED, true), 4);
level.gameEvent(player, GameEvent.SHEAR, pos);
}
return super.playerWillDestroy(level, pos, state, player);
}
private void updateSource(Level level, BlockPos pos, BlockState state) {
for (Direction direction : new Direction[]{Direction.SOUTH, Direction.WEST}) {
for (int i = 1; i < 42; i++) {
BlockPos blockPos = pos.relative(direction, i);
BlockState blockState = level.getBlockState(blockPos);
if (blockState.is(this.hook)) {
if (blockState.getValue(TripWireHookBlock.FACING) == direction.getOpposite()) {
TripWireHookBlock.calculateState(level, blockPos, blockState, false, true, i, state);
}
break;
}
if (!blockState.is(this)) {
break;
}
}
}
}
@Override
protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
if (!level.isClientSide) {
if (!(Boolean)state.getValue(POWERED)) {
this.checkPressed(level, pos);
}
}
}
@Override
protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if ((Boolean)level.getBlockState(pos).getValue(POWERED)) {
this.checkPressed(level, pos);
}
}
private void checkPressed(Level level, BlockPos pos) {
BlockState blockState = level.getBlockState(pos);
boolean bl = (Boolean)blockState.getValue(POWERED);
boolean bl2 = false;
List<? extends Entity> list = level.getEntities(null, blockState.getShape(level, pos).bounds().move(pos));
if (!list.isEmpty()) {
for (Entity entity : list) {
if (!entity.isIgnoringBlockTriggers()) {
bl2 = true;
break;
}
}
}
if (bl2 != bl) {
blockState = blockState.setValue(POWERED, bl2);
level.setBlock(pos, blockState, 3);
this.updateSource(level, pos, blockState);
}
if (bl2) {
level.scheduleTick(new BlockPos(pos), this, 10);
}
}
public boolean shouldConnectTo(BlockState state, Direction direction) {
return state.is(this.hook) ? state.getValue(TripWireHookBlock.FACING) == direction.getOpposite() : state.is(this);
}
@Override
protected BlockState rotate(BlockState state, Rotation rotation) {
switch (rotation) {
case CLOCKWISE_180:
return state.setValue(NORTH, (Boolean)state.getValue(SOUTH))
.setValue(EAST, (Boolean)state.getValue(WEST))
.setValue(SOUTH, (Boolean)state.getValue(NORTH))
.setValue(WEST, (Boolean)state.getValue(EAST));
case COUNTERCLOCKWISE_90:
return state.setValue(NORTH, (Boolean)state.getValue(EAST))
.setValue(EAST, (Boolean)state.getValue(SOUTH))
.setValue(SOUTH, (Boolean)state.getValue(WEST))
.setValue(WEST, (Boolean)state.getValue(NORTH));
case CLOCKWISE_90:
return state.setValue(NORTH, (Boolean)state.getValue(WEST))
.setValue(EAST, (Boolean)state.getValue(NORTH))
.setValue(SOUTH, (Boolean)state.getValue(EAST))
.setValue(WEST, (Boolean)state.getValue(SOUTH));
default:
return state;
}
}
@Override
protected BlockState mirror(BlockState state, Mirror mirror) {
switch (mirror) {
case LEFT_RIGHT:
return state.setValue(NORTH, (Boolean)state.getValue(SOUTH)).setValue(SOUTH, (Boolean)state.getValue(NORTH));
case FRONT_BACK:
return state.setValue(EAST, (Boolean)state.getValue(WEST)).setValue(WEST, (Boolean)state.getValue(EAST));
default:
return super.mirror(state, mirror);
}
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(POWERED, ATTACHED, DISARMED, NORTH, EAST, WEST, SOUTH);
}
}