package net.minecraft.world.level.block; import com.google.common.base.MoreObjects; import com.mojang.serialization.MapCodec; import java.util.Map; import java.util.Optional; import javax.annotation.Nullable; 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.LevelReader; import net.minecraft.world.level.ScheduledTickAccess; 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.gameevent.GameEvent; import net.minecraft.world.level.redstone.ExperimentalRedstoneUtils; import net.minecraft.world.level.redstone.Orientation; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; public class TripWireHookBlock extends Block { public static final MapCodec CODEC = simpleCodec(TripWireHookBlock::new); public static final EnumProperty 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; private static final Map SHAPES = Shapes.rotateHorizontal(Block.boxZ(6.0, 0.0, 10.0, 10.0, 16.0)); @Override public MapCodec codec() { return CODEC; } public TripWireHookBlock(BlockBehaviour.Properties p_57676_) { super(p_57676_); this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(POWERED, false).setValue(ATTACHED, false)); } @Override protected VoxelShape getShape(BlockState p_57740_, BlockGetter p_57741_, BlockPos p_57742_, CollisionContext p_57743_) { return SHAPES.get(p_57740_.getValue(FACING)); } @Override protected boolean canSurvive(BlockState p_57721_, LevelReader p_57722_, BlockPos p_57723_) { Direction direction = p_57721_.getValue(FACING); BlockPos blockpos = p_57723_.relative(direction.getOpposite()); BlockState blockstate = p_57722_.getBlockState(blockpos); return direction.getAxis().isHorizontal() && blockstate.isFaceSturdy(p_57722_, blockpos, direction); } @Override protected BlockState updateShape( BlockState p_57731_, LevelReader p_368766_, ScheduledTickAccess p_365650_, BlockPos p_57735_, Direction p_57732_, BlockPos p_57736_, BlockState p_57733_, RandomSource p_361546_ ) { return p_57732_.getOpposite() == p_57731_.getValue(FACING) && !p_57731_.canSurvive(p_368766_, p_57735_) ? Blocks.AIR.defaultBlockState() : super.updateShape(p_57731_, p_368766_, p_365650_, p_57735_, p_57732_, p_57736_, p_57733_, p_361546_); } @Nullable @Override public BlockState getStateForPlacement(BlockPlaceContext p_57678_) { BlockState blockstate = this.defaultBlockState().setValue(POWERED, false).setValue(ATTACHED, false); LevelReader levelreader = p_57678_.getLevel(); BlockPos blockpos = p_57678_.getClickedPos(); Direction[] adirection = p_57678_.getNearestLookingDirections(); for (Direction direction : adirection) { if (direction.getAxis().isHorizontal()) { Direction direction1 = direction.getOpposite(); blockstate = blockstate.setValue(FACING, direction1); if (blockstate.canSurvive(levelreader, blockpos)) { return blockstate; } } } return null; } @Override public void setPlacedBy(Level p_57680_, BlockPos p_57681_, BlockState p_57682_, LivingEntity p_57683_, ItemStack p_57684_) { calculateState(p_57680_, p_57681_, p_57682_, false, false, -1, null); } public static void calculateState( Level p_57686_, BlockPos p_57687_, BlockState p_57688_, boolean p_57689_, boolean p_57690_, int p_57691_, @Nullable BlockState p_57692_ ) { Optional optional = p_57688_.getOptionalValue(FACING); if (optional.isPresent()) { Direction direction = optional.get(); boolean flag = p_57688_.getOptionalValue(ATTACHED).orElse(false); boolean flag1 = p_57688_.getOptionalValue(POWERED).orElse(false); Block block = p_57688_.getBlock(); boolean flag2 = !p_57689_; boolean flag3 = false; int i = 0; BlockState[] ablockstate = new BlockState[42]; for (int j = 1; j < 42; j++) { BlockPos blockpos = p_57687_.relative(direction, j); BlockState blockstate = p_57686_.getBlockState(blockpos); if (blockstate.is(Blocks.TRIPWIRE_HOOK)) { if (blockstate.getValue(FACING) == direction.getOpposite()) { i = j; } break; } if (!blockstate.is(Blocks.TRIPWIRE) && j != p_57691_) { ablockstate[j] = null; flag2 = false; } else { if (j == p_57691_) { blockstate = MoreObjects.firstNonNull(p_57692_, blockstate); } boolean flag4 = !blockstate.getValue(TripWireBlock.DISARMED); boolean flag5 = blockstate.getValue(TripWireBlock.POWERED); flag3 |= flag4 && flag5; ablockstate[j] = blockstate; if (j == p_57691_) { p_57686_.scheduleTick(p_57687_, block, 10); flag2 &= flag4; } } } flag2 &= i > 1; flag3 &= flag2; BlockState blockstate1 = block.defaultBlockState().trySetValue(ATTACHED, flag2).trySetValue(POWERED, flag3); if (i > 0) { BlockPos blockpos1 = p_57687_.relative(direction, i); Direction direction1 = direction.getOpposite(); p_57686_.setBlock(blockpos1, blockstate1.setValue(FACING, direction1), 3); notifyNeighbors(block, p_57686_, blockpos1, direction1); emitState(p_57686_, blockpos1, flag2, flag3, flag, flag1); } emitState(p_57686_, p_57687_, flag2, flag3, flag, flag1); if (!p_57689_) { p_57686_.setBlock(p_57687_, blockstate1.setValue(FACING, direction), 3); if (p_57690_) { notifyNeighbors(block, p_57686_, p_57687_, direction); } } if (flag != flag2) { for (int k = 1; k < i; k++) { BlockPos blockpos2 = p_57687_.relative(direction, k); BlockState blockstate2 = ablockstate[k]; if (blockstate2 != null) { BlockState blockstate3 = p_57686_.getBlockState(blockpos2); if (blockstate3.is(Blocks.TRIPWIRE) || blockstate3.is(Blocks.TRIPWIRE_HOOK)) { p_57686_.setBlock(blockpos2, blockstate2.trySetValue(ATTACHED, flag2), 3); } } } } } } @Override protected void tick(BlockState p_222610_, ServerLevel p_222611_, BlockPos p_222612_, RandomSource p_222613_) { calculateState(p_222611_, p_222612_, p_222610_, false, true, -1, null); } private static void emitState(Level p_222603_, BlockPos p_222604_, boolean p_222605_, boolean p_222606_, boolean p_222607_, boolean p_222608_) { if (p_222606_ && !p_222608_) { p_222603_.playSound(null, p_222604_, SoundEvents.TRIPWIRE_CLICK_ON, SoundSource.BLOCKS, 0.4F, 0.6F); p_222603_.gameEvent(null, GameEvent.BLOCK_ACTIVATE, p_222604_); } else if (!p_222606_ && p_222608_) { p_222603_.playSound(null, p_222604_, SoundEvents.TRIPWIRE_CLICK_OFF, SoundSource.BLOCKS, 0.4F, 0.5F); p_222603_.gameEvent(null, GameEvent.BLOCK_DEACTIVATE, p_222604_); } else if (p_222605_ && !p_222607_) { p_222603_.playSound(null, p_222604_, SoundEvents.TRIPWIRE_ATTACH, SoundSource.BLOCKS, 0.4F, 0.7F); p_222603_.gameEvent(null, GameEvent.BLOCK_ATTACH, p_222604_); } else if (!p_222605_ && p_222607_) { p_222603_.playSound(null, p_222604_, SoundEvents.TRIPWIRE_DETACH, SoundSource.BLOCKS, 0.4F, 1.2F / (p_222603_.random.nextFloat() * 0.2F + 0.9F)); p_222603_.gameEvent(null, GameEvent.BLOCK_DETACH, p_222604_); } } private static void notifyNeighbors(Block p_312237_, Level p_57694_, BlockPos p_57695_, Direction p_57696_) { Direction direction = p_57696_.getOpposite(); Orientation orientation = ExperimentalRedstoneUtils.initialOrientation(p_57694_, direction, Direction.UP); p_57694_.updateNeighborsAt(p_57695_, p_312237_, orientation); p_57694_.updateNeighborsAt(p_57695_.relative(direction), p_312237_, orientation); } @Override protected void affectNeighborsAfterRemoval(BlockState p_394362_, ServerLevel p_392228_, BlockPos p_392478_, boolean p_391414_) { if (!p_391414_) { boolean flag = p_394362_.getValue(ATTACHED); boolean flag1 = p_394362_.getValue(POWERED); if (flag || flag1) { calculateState(p_392228_, p_392478_, p_394362_, true, false, -1, null); } if (flag1) { notifyNeighbors(this, p_392228_, p_392478_, p_394362_.getValue(FACING)); } } } @Override protected int getSignal(BlockState p_57710_, BlockGetter p_57711_, BlockPos p_57712_, Direction p_57713_) { return p_57710_.getValue(POWERED) ? 15 : 0; } @Override protected int getDirectSignal(BlockState p_57745_, BlockGetter p_57746_, BlockPos p_57747_, Direction p_57748_) { if (!p_57745_.getValue(POWERED)) { return 0; } else { return p_57745_.getValue(FACING) == p_57748_ ? 15 : 0; } } @Override protected boolean isSignalSource(BlockState p_57750_) { return true; } @Override protected BlockState rotate(BlockState p_57728_, Rotation p_57729_) { return p_57728_.setValue(FACING, p_57729_.rotate(p_57728_.getValue(FACING))); } @Override protected BlockState mirror(BlockState p_57725_, Mirror p_57726_) { return p_57725_.rotate(p_57726_.getRotation(p_57725_.getValue(FACING))); } @Override protected void createBlockStateDefinition(StateDefinition.Builder p_57738_) { p_57738_.add(FACING, POWERED, ATTACHED); } }