263 lines
9.7 KiB
Java
263 lines
9.7 KiB
Java
package net.minecraft.world.level.block;
|
|
|
|
import com.google.common.base.MoreObjects;
|
|
import com.mojang.serialization.MapCodec;
|
|
import java.util.Optional;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.sounds.SoundEvents;
|
|
import net.minecraft.sounds.SoundSource;
|
|
import net.minecraft.util.RandomSource;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.item.ItemStack;
|
|
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.LevelReader;
|
|
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.DirectionProperty;
|
|
import net.minecraft.world.level.gameevent.GameEvent;
|
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
public class TripWireHookBlock extends Block {
|
|
public static final MapCodec<TripWireHookBlock> CODEC = simpleCodec(TripWireHookBlock::new);
|
|
public static final DirectionProperty FACING = HorizontalDirectionalBlock.FACING;
|
|
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
|
|
public static final BooleanProperty ATTACHED = BlockStateProperties.ATTACHED;
|
|
protected static final int WIRE_DIST_MIN = 1;
|
|
protected static final int WIRE_DIST_MAX = 42;
|
|
private static final int RECHECK_PERIOD = 10;
|
|
protected static final int AABB_OFFSET = 3;
|
|
protected static final VoxelShape NORTH_AABB = Block.box(5.0, 0.0, 10.0, 11.0, 10.0, 16.0);
|
|
protected static final VoxelShape SOUTH_AABB = Block.box(5.0, 0.0, 0.0, 11.0, 10.0, 6.0);
|
|
protected static final VoxelShape WEST_AABB = Block.box(10.0, 0.0, 5.0, 16.0, 10.0, 11.0);
|
|
protected static final VoxelShape EAST_AABB = Block.box(0.0, 0.0, 5.0, 6.0, 10.0, 11.0);
|
|
|
|
@Override
|
|
public MapCodec<TripWireHookBlock> codec() {
|
|
return CODEC;
|
|
}
|
|
|
|
public TripWireHookBlock(BlockBehaviour.Properties properties) {
|
|
super(properties);
|
|
this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(POWERED, false).setValue(ATTACHED, false));
|
|
}
|
|
|
|
@Override
|
|
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
|
|
switch ((Direction)state.getValue(FACING)) {
|
|
case EAST:
|
|
default:
|
|
return EAST_AABB;
|
|
case WEST:
|
|
return WEST_AABB;
|
|
case SOUTH:
|
|
return SOUTH_AABB;
|
|
case NORTH:
|
|
return NORTH_AABB;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
|
|
Direction direction = state.getValue(FACING);
|
|
BlockPos blockPos = pos.relative(direction.getOpposite());
|
|
BlockState blockState = level.getBlockState(blockPos);
|
|
return direction.getAxis().isHorizontal() && blockState.isFaceSturdy(level, blockPos, direction);
|
|
}
|
|
|
|
@Override
|
|
protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
|
|
return direction.getOpposite() == state.getValue(FACING) && !state.canSurvive(level, pos)
|
|
? Blocks.AIR.defaultBlockState()
|
|
: super.updateShape(state, direction, neighborState, level, pos, neighborPos);
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
|
BlockState blockState = this.defaultBlockState().setValue(POWERED, false).setValue(ATTACHED, false);
|
|
LevelReader levelReader = context.getLevel();
|
|
BlockPos blockPos = context.getClickedPos();
|
|
Direction[] directions = context.getNearestLookingDirections();
|
|
|
|
for (Direction direction : directions) {
|
|
if (direction.getAxis().isHorizontal()) {
|
|
Direction direction2 = direction.getOpposite();
|
|
blockState = blockState.setValue(FACING, direction2);
|
|
if (blockState.canSurvive(levelReader, blockPos)) {
|
|
return blockState;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public void setPlacedBy(Level level, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) {
|
|
calculateState(level, pos, state, false, false, -1, null);
|
|
}
|
|
|
|
public static void calculateState(
|
|
Level level, BlockPos pos, BlockState hookState, boolean attaching, boolean shouldNotifyNeighbours, int searchRange, @Nullable BlockState state
|
|
) {
|
|
Optional<Direction> optional = hookState.getOptionalValue(FACING);
|
|
if (optional.isPresent()) {
|
|
Direction direction = (Direction)optional.get();
|
|
boolean bl = (Boolean)hookState.getOptionalValue(ATTACHED).orElse(false);
|
|
boolean bl2 = (Boolean)hookState.getOptionalValue(POWERED).orElse(false);
|
|
Block block = hookState.getBlock();
|
|
boolean bl3 = !attaching;
|
|
boolean bl4 = false;
|
|
int i = 0;
|
|
BlockState[] blockStates = new BlockState[42];
|
|
|
|
for (int j = 1; j < 42; j++) {
|
|
BlockPos blockPos = pos.relative(direction, j);
|
|
BlockState blockState = level.getBlockState(blockPos);
|
|
if (blockState.is(Blocks.TRIPWIRE_HOOK)) {
|
|
if (blockState.getValue(FACING) == direction.getOpposite()) {
|
|
i = j;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!blockState.is(Blocks.TRIPWIRE) && j != searchRange) {
|
|
blockStates[j] = null;
|
|
bl3 = false;
|
|
} else {
|
|
if (j == searchRange) {
|
|
blockState = MoreObjects.firstNonNull(state, blockState);
|
|
}
|
|
|
|
boolean bl5 = !(Boolean)blockState.getValue(TripWireBlock.DISARMED);
|
|
boolean bl6 = (Boolean)blockState.getValue(TripWireBlock.POWERED);
|
|
bl4 |= bl5 && bl6;
|
|
blockStates[j] = blockState;
|
|
if (j == searchRange) {
|
|
level.scheduleTick(pos, block, 10);
|
|
bl3 &= bl5;
|
|
}
|
|
}
|
|
}
|
|
|
|
bl3 &= i > 1;
|
|
bl4 &= bl3;
|
|
BlockState blockState2 = block.defaultBlockState().trySetValue(ATTACHED, bl3).trySetValue(POWERED, bl4);
|
|
if (i > 0) {
|
|
BlockPos blockPosx = pos.relative(direction, i);
|
|
Direction direction2 = direction.getOpposite();
|
|
level.setBlock(blockPosx, blockState2.setValue(FACING, direction2), 3);
|
|
notifyNeighbors(block, level, blockPosx, direction2);
|
|
emitState(level, blockPosx, bl3, bl4, bl, bl2);
|
|
}
|
|
|
|
emitState(level, pos, bl3, bl4, bl, bl2);
|
|
if (!attaching) {
|
|
level.setBlock(pos, blockState2.setValue(FACING, direction), 3);
|
|
if (shouldNotifyNeighbours) {
|
|
notifyNeighbors(block, level, pos, direction);
|
|
}
|
|
}
|
|
|
|
if (bl != bl3) {
|
|
for (int k = 1; k < i; k++) {
|
|
BlockPos blockPos2 = pos.relative(direction, k);
|
|
BlockState blockState3 = blockStates[k];
|
|
if (blockState3 != null) {
|
|
level.setBlock(blockPos2, blockState3.trySetValue(ATTACHED, bl3), 3);
|
|
if (!level.getBlockState(blockPos2).isAir()) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
|
|
calculateState(level, pos, state, false, true, -1, null);
|
|
}
|
|
|
|
private static void emitState(Level level, BlockPos pos, boolean attached, boolean powered, boolean wasAttached, boolean wasPowered) {
|
|
if (powered && !wasPowered) {
|
|
level.playSound(null, pos, SoundEvents.TRIPWIRE_CLICK_ON, SoundSource.BLOCKS, 0.4F, 0.6F);
|
|
level.gameEvent(null, GameEvent.BLOCK_ACTIVATE, pos);
|
|
} else if (!powered && wasPowered) {
|
|
level.playSound(null, pos, SoundEvents.TRIPWIRE_CLICK_OFF, SoundSource.BLOCKS, 0.4F, 0.5F);
|
|
level.gameEvent(null, GameEvent.BLOCK_DEACTIVATE, pos);
|
|
} else if (attached && !wasAttached) {
|
|
level.playSound(null, pos, SoundEvents.TRIPWIRE_ATTACH, SoundSource.BLOCKS, 0.4F, 0.7F);
|
|
level.gameEvent(null, GameEvent.BLOCK_ATTACH, pos);
|
|
} else if (!attached && wasAttached) {
|
|
level.playSound(null, pos, SoundEvents.TRIPWIRE_DETACH, SoundSource.BLOCKS, 0.4F, 1.2F / (level.random.nextFloat() * 0.2F + 0.9F));
|
|
level.gameEvent(null, GameEvent.BLOCK_DETACH, pos);
|
|
}
|
|
}
|
|
|
|
private static void notifyNeighbors(Block block, Level level, BlockPos pos, Direction direction) {
|
|
level.updateNeighborsAt(pos, block);
|
|
level.updateNeighborsAt(pos.relative(direction.getOpposite()), block);
|
|
}
|
|
|
|
@Override
|
|
protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
|
|
if (!movedByPiston && !state.is(newState.getBlock())) {
|
|
boolean bl = (Boolean)state.getValue(ATTACHED);
|
|
boolean bl2 = (Boolean)state.getValue(POWERED);
|
|
if (bl || bl2) {
|
|
calculateState(level, pos, state, true, false, -1, null);
|
|
}
|
|
|
|
if (bl2) {
|
|
level.updateNeighborsAt(pos, this);
|
|
level.updateNeighborsAt(pos.relative(((Direction)state.getValue(FACING)).getOpposite()), this);
|
|
}
|
|
|
|
super.onRemove(state, level, pos, newState, movedByPiston);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected int getSignal(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
|
|
return state.getValue(POWERED) ? 15 : 0;
|
|
}
|
|
|
|
@Override
|
|
protected int getDirectSignal(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
|
|
if (!(Boolean)state.getValue(POWERED)) {
|
|
return 0;
|
|
} else {
|
|
return state.getValue(FACING) == direction ? 15 : 0;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected boolean isSignalSource(BlockState state) {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
protected BlockState rotate(BlockState state, Rotation rotation) {
|
|
return state.setValue(FACING, rotation.rotate(state.getValue(FACING)));
|
|
}
|
|
|
|
@Override
|
|
protected BlockState mirror(BlockState state, Mirror mirror) {
|
|
return state.rotate(mirror.getRotation(state.getValue(FACING)));
|
|
}
|
|
|
|
@Override
|
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
|
builder.add(FACING, POWERED, ATTACHED);
|
|
}
|
|
}
|