--- a/net/minecraft/world/level/block/TripWireHookBlock.java
+++ b/net/minecraft/world/level/block/TripWireHookBlock.java
@@ -6,11 +6,14 @@
 import javax.annotation.Nullable;
 import net.minecraft.core.BlockPos;
 import net.minecraft.core.Direction;
+import net.minecraft.core.Holder;
 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.Entity;
 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.level.BlockGetter;
@@ -26,8 +29,13 @@
 import net.minecraft.world.level.gameevent.GameEvent;
 import net.minecraft.world.phys.shapes.CollisionContext;
 import net.minecraft.world.phys.shapes.VoxelShape;
+// CraftBukkit start
+import org.bukkit.craftbukkit.block.CraftBlock;
+import org.bukkit.event.block.BlockRedstoneEvent;
+// CraftBukkit end
 
 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;
@@ -36,67 +44,69 @@
     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);
+    protected static final VoxelShape NORTH_AABB = Block.box(5.0D, 0.0D, 10.0D, 11.0D, 10.0D, 16.0D);
+    protected static final VoxelShape SOUTH_AABB = Block.box(5.0D, 0.0D, 0.0D, 11.0D, 10.0D, 6.0D);
+    protected static final VoxelShape WEST_AABB = Block.box(10.0D, 0.0D, 5.0D, 16.0D, 10.0D, 11.0D);
+    protected static final VoxelShape EAST_AABB = Block.box(0.0D, 0.0D, 5.0D, 6.0D, 10.0D, 11.0D);
 
     @Override
     public MapCodec<TripWireHookBlock> codec() {
-        return CODEC;
+        return TripWireHookBlock.CODEC;
     }
 
     public TripWireHookBlock(BlockBehaviour.Properties settings) {
         super(settings);
-        this.registerDefaultState(
-            this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(POWERED, Boolean.valueOf(false)).setValue(ATTACHED, Boolean.valueOf(false))
-        );
+        this.registerDefaultState((BlockState) ((BlockState) ((BlockState) ((BlockState) this.stateDefinition.any()).setValue(TripWireHookBlock.FACING, Direction.NORTH)).setValue(TripWireHookBlock.POWERED, false)).setValue(TripWireHookBlock.ATTACHED, false));
     }
 
     @Override
     protected VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) {
-        switch ((Direction)state.getValue(FACING)) {
+        switch ((Direction) state.getValue(TripWireHookBlock.FACING)) {
             case EAST:
             default:
-                return EAST_AABB;
+                return TripWireHookBlock.EAST_AABB;
             case WEST:
-                return WEST_AABB;
+                return TripWireHookBlock.WEST_AABB;
             case SOUTH:
-                return SOUTH_AABB;
+                return TripWireHookBlock.SOUTH_AABB;
             case NORTH:
-                return NORTH_AABB;
+                return TripWireHookBlock.NORTH_AABB;
         }
     }
 
     @Override
     protected boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
-        Direction direction = state.getValue(FACING);
-        BlockPos blockPos = pos.relative(direction.getOpposite());
-        BlockState blockState = world.getBlockState(blockPos);
-        return direction.getAxis().isHorizontal() && blockState.isFaceSturdy(world, blockPos, direction);
+        Direction enumdirection = (Direction) state.getValue(TripWireHookBlock.FACING);
+        BlockPos blockposition1 = pos.relative(enumdirection.getOpposite());
+        BlockState iblockdata1 = world.getBlockState(blockposition1);
+
+        return enumdirection.getAxis().isHorizontal() && iblockdata1.isFaceSturdy(world, blockposition1, enumdirection);
     }
 
     @Override
     protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
-        return direction.getOpposite() == state.getValue(FACING) && !state.canSurvive(world, pos)
-            ? Blocks.AIR.defaultBlockState()
-            : super.updateShape(state, direction, neighborState, world, pos, neighborPos);
+        return direction.getOpposite() == state.getValue(TripWireHookBlock.FACING) && !state.canSurvive(world, pos) ? Blocks.AIR.defaultBlockState() : super.updateShape(state, direction, neighborState, world, pos, neighborPos);
     }
 
     @Nullable
     @Override
     public BlockState getStateForPlacement(BlockPlaceContext ctx) {
-        BlockState blockState = this.defaultBlockState().setValue(POWERED, Boolean.valueOf(false)).setValue(ATTACHED, Boolean.valueOf(false));
-        LevelReader levelReader = ctx.getLevel();
-        BlockPos blockPos = ctx.getClickedPos();
-        Direction[] directions = ctx.getNearestLookingDirections();
+        BlockState iblockdata = (BlockState) ((BlockState) this.defaultBlockState().setValue(TripWireHookBlock.POWERED, false)).setValue(TripWireHookBlock.ATTACHED, false);
+        Level world = ctx.getLevel();
+        BlockPos blockposition = ctx.getClickedPos();
+        Direction[] aenumdirection = ctx.getNearestLookingDirections();
+        Direction[] aenumdirection1 = aenumdirection;
+        int i = aenumdirection.length;
 
-        for (Direction direction : directions) {
-            if (direction.getAxis().isHorizontal()) {
-                Direction direction2 = direction.getOpposite();
-                blockState = blockState.setValue(FACING, direction2);
-                if (blockState.canSurvive(levelReader, blockPos)) {
-                    return blockState;
+        for (int j = 0; j < i; ++j) {
+            Direction enumdirection = aenumdirection1[j];
+
+            if (enumdirection.getAxis().isHorizontal()) {
+                Direction enumdirection1 = enumdirection.getOpposite();
+
+                iblockdata = (BlockState) iblockdata.setValue(TripWireHookBlock.FACING, enumdirection1);
+                if (iblockdata.canSurvive(world, blockposition)) {
+                    return iblockdata;
                 }
             }
         }
@@ -106,102 +116,122 @@
 
     @Override
     public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack itemStack) {
-        calculateState(world, pos, state, false, false, -1, null);
+        TripWireHookBlock.calculateState(world, pos, state, false, false, -1, (BlockState) null);
     }
 
-    public static void calculateState(Level world, BlockPos pos, BlockState state, boolean bl, boolean bl2, int i, @Nullable BlockState blockState) {
-        Optional<Direction> optional = state.getOptionalValue(FACING);
+    public static void calculateState(Level world, BlockPos pos, BlockState state, boolean flag, boolean flag1, int i, @Nullable BlockState iblockdata1) {
+        Optional<Direction> optional = state.getOptionalValue(TripWireHookBlock.FACING);
+
         if (optional.isPresent()) {
-            Direction direction = optional.get();
-            boolean bl3 = state.getOptionalValue(ATTACHED).orElse(false);
-            boolean bl4 = state.getOptionalValue(POWERED).orElse(false);
+            Direction enumdirection = (Direction) optional.get();
+            boolean flag2 = (Boolean) state.getOptionalValue(TripWireHookBlock.ATTACHED).orElse(false);
+            boolean flag3 = (Boolean) state.getOptionalValue(TripWireHookBlock.POWERED).orElse(false);
             Block block = state.getBlock();
-            boolean bl5 = !bl;
-            boolean bl6 = false;
+            boolean flag4 = !flag;
+            boolean flag5 = false;
             int j = 0;
-            BlockState[] blockStates = new BlockState[42];
+            BlockState[] aiblockdata = new BlockState[42];
 
-            for (int k = 1; k < 42; k++) {
-                BlockPos blockPos = pos.relative(direction, k);
-                BlockState blockState2 = world.getBlockState(blockPos);
-                if (blockState2.is(Blocks.TRIPWIRE_HOOK)) {
-                    if (blockState2.getValue(FACING) == direction.getOpposite()) {
+            BlockPos blockposition1;
+
+            for (int k = 1; k < 42; ++k) {
+                blockposition1 = pos.relative(enumdirection, k);
+                BlockState iblockdata2 = world.getBlockState(blockposition1);
+
+                if (iblockdata2.is(Blocks.TRIPWIRE_HOOK)) {
+                    if (iblockdata2.getValue(TripWireHookBlock.FACING) == enumdirection.getOpposite()) {
                         j = k;
                     }
                     break;
                 }
 
-                if (!blockState2.is(Blocks.TRIPWIRE) && k != i) {
-                    blockStates[k] = null;
-                    bl5 = false;
+                if (!iblockdata2.is(Blocks.TRIPWIRE) && k != i) {
+                    aiblockdata[k] = null;
+                    flag4 = false;
                 } else {
                     if (k == i) {
-                        blockState2 = MoreObjects.firstNonNull(blockState, blockState2);
+                        iblockdata2 = (BlockState) MoreObjects.firstNonNull(iblockdata1, iblockdata2);
                     }
 
-                    boolean bl7 = !blockState2.getValue(TripWireBlock.DISARMED);
-                    boolean bl8 = blockState2.getValue(TripWireBlock.POWERED);
-                    bl6 |= bl7 && bl8;
-                    blockStates[k] = blockState2;
+                    boolean flag6 = !(Boolean) iblockdata2.getValue(TripWireBlock.DISARMED);
+                    boolean flag7 = (Boolean) iblockdata2.getValue(TripWireBlock.POWERED);
+
+                    flag5 |= flag6 && flag7;
+                    aiblockdata[k] = iblockdata2;
                     if (k == i) {
                         world.scheduleTick(pos, block, 10);
-                        bl5 &= bl7;
+                        flag4 &= flag6;
                     }
                 }
             }
 
-            bl5 &= j > 1;
-            bl6 &= bl5;
-            BlockState blockState3 = block.defaultBlockState().trySetValue(ATTACHED, Boolean.valueOf(bl5)).trySetValue(POWERED, Boolean.valueOf(bl6));
+            flag4 &= j > 1;
+            flag5 &= flag4;
+            BlockState iblockdata3 = (BlockState) ((BlockState) block.defaultBlockState().trySetValue(TripWireHookBlock.ATTACHED, flag4)).trySetValue(TripWireHookBlock.POWERED, flag5);
+
             if (j > 0) {
-                BlockPos blockPos2 = pos.relative(direction, j);
-                Direction direction2 = direction.getOpposite();
-                world.setBlock(blockPos2, blockState3.setValue(FACING, direction2), 3);
-                notifyNeighbors(block, world, blockPos2, direction2);
-                emitState(world, blockPos2, bl5, bl6, bl3, bl4);
+                blockposition1 = pos.relative(enumdirection, j);
+                Direction enumdirection1 = enumdirection.getOpposite();
+
+                world.setBlock(blockposition1, (BlockState) iblockdata3.setValue(TripWireHookBlock.FACING, enumdirection1), 3);
+                TripWireHookBlock.notifyNeighbors(block, world, blockposition1, enumdirection1);
+                TripWireHookBlock.emitState(world, blockposition1, flag4, flag5, flag2, flag3);
             }
 
-            emitState(world, pos, bl5, bl6, bl3, bl4);
-            if (!bl) {
-                world.setBlock(pos, blockState3.setValue(FACING, direction), 3);
-                if (bl2) {
-                    notifyNeighbors(block, world, pos, direction);
+            // CraftBukkit start
+            BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(CraftBlock.at(world, pos), 15, 0);
+            world.getCraftServer().getPluginManager().callEvent(eventRedstone);
+
+            if (eventRedstone.getNewCurrent() > 0) {
+                return;
+            }
+            // CraftBukkit end
+
+            TripWireHookBlock.emitState(world, pos, flag4, flag5, flag2, flag3);
+            if (!flag) {
+                if (world.getBlockState(pos).getBlock() == Blocks.TRIPWIRE_HOOK) // Paper - Validate tripwire hook placement before update
+                world.setBlock(pos, (BlockState) iblockdata3.setValue(TripWireHookBlock.FACING, enumdirection), 3);
+                if (flag1) {
+                    TripWireHookBlock.notifyNeighbors(block, world, pos, enumdirection);
                 }
             }
 
-            if (bl3 != bl5) {
-                for (int l = 1; l < j; l++) {
-                    BlockPos blockPos3 = pos.relative(direction, l);
-                    BlockState blockState4 = blockStates[l];
-                    if (blockState4 != null) {
-                        world.setBlock(blockPos3, blockState4.trySetValue(ATTACHED, Boolean.valueOf(bl5)), 3);
-                        if (!world.getBlockState(blockPos3).isAir()) {
+            if (flag2 != flag4) {
+                for (int l = 1; l < j; ++l) {
+                    BlockPos blockposition2 = pos.relative(enumdirection, l);
+                    BlockState iblockdata4 = aiblockdata[l];
+
+                    if (iblockdata4 != null) {
+                        if (world.getBlockState(blockposition2).is(Blocks.TRIPWIRE) || io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowTripwireDisarmingExploits) { // Paper - Fix tripwire disarming not working as intended
+                        world.setBlock(blockposition2, (BlockState) iblockdata4.trySetValue(TripWireHookBlock.ATTACHED, flag4), 3);
                         }
                     }
                 }
             }
+
         }
     }
 
     @Override
     protected void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
-        calculateState(world, pos, state, false, true, -1, null);
+        TripWireHookBlock.calculateState(world, pos, state, false, true, -1, (BlockState) null);
     }
 
     private static void emitState(Level world, BlockPos pos, boolean attached, boolean on, boolean detached, boolean off) {
         if (on && !off) {
-            world.playSound(null, pos, SoundEvents.TRIPWIRE_CLICK_ON, SoundSource.BLOCKS, 0.4F, 0.6F);
-            world.gameEvent(null, GameEvent.BLOCK_ACTIVATE, pos);
+            world.playSound((Player) null, pos, SoundEvents.TRIPWIRE_CLICK_ON, SoundSource.BLOCKS, 0.4F, 0.6F);
+            world.gameEvent((Entity) null, (Holder) GameEvent.BLOCK_ACTIVATE, pos);
         } else if (!on && off) {
-            world.playSound(null, pos, SoundEvents.TRIPWIRE_CLICK_OFF, SoundSource.BLOCKS, 0.4F, 0.5F);
-            world.gameEvent(null, GameEvent.BLOCK_DEACTIVATE, pos);
+            world.playSound((Player) null, pos, SoundEvents.TRIPWIRE_CLICK_OFF, SoundSource.BLOCKS, 0.4F, 0.5F);
+            world.gameEvent((Entity) null, (Holder) GameEvent.BLOCK_DEACTIVATE, pos);
         } else if (attached && !detached) {
-            world.playSound(null, pos, SoundEvents.TRIPWIRE_ATTACH, SoundSource.BLOCKS, 0.4F, 0.7F);
-            world.gameEvent(null, GameEvent.BLOCK_ATTACH, pos);
+            world.playSound((Player) null, pos, SoundEvents.TRIPWIRE_ATTACH, SoundSource.BLOCKS, 0.4F, 0.7F);
+            world.gameEvent((Entity) null, (Holder) GameEvent.BLOCK_ATTACH, pos);
         } else if (!attached && detached) {
-            world.playSound(null, pos, SoundEvents.TRIPWIRE_DETACH, SoundSource.BLOCKS, 0.4F, 1.2F / (world.random.nextFloat() * 0.2F + 0.9F));
-            world.gameEvent(null, GameEvent.BLOCK_DETACH, pos);
+            world.playSound((Player) null, pos, SoundEvents.TRIPWIRE_DETACH, SoundSource.BLOCKS, 0.4F, 1.2F / (world.random.nextFloat() * 0.2F + 0.9F));
+            world.gameEvent((Entity) null, (Holder) GameEvent.BLOCK_DETACH, pos);
         }
+
     }
 
     private static void notifyNeighbors(Block block, Level world, BlockPos pos, Direction direction) {
@@ -212,15 +242,16 @@
     @Override
     protected void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean moved) {
         if (!moved && !state.is(newState.getBlock())) {
-            boolean bl = state.getValue(ATTACHED);
-            boolean bl2 = state.getValue(POWERED);
-            if (bl || bl2) {
-                calculateState(world, pos, state, true, false, -1, null);
+            boolean flag1 = (Boolean) state.getValue(TripWireHookBlock.ATTACHED);
+            boolean flag2 = (Boolean) state.getValue(TripWireHookBlock.POWERED);
+
+            if (flag1 || flag2) {
+                TripWireHookBlock.calculateState(world, pos, state, true, false, -1, (BlockState) null);
             }
 
-            if (bl2) {
+            if (flag2) {
                 world.updateNeighborsAt(pos, this);
-                world.updateNeighborsAt(pos.relative(state.getValue(FACING).getOpposite()), this);
+                world.updateNeighborsAt(pos.relative(((Direction) state.getValue(TripWireHookBlock.FACING)).getOpposite()), this);
             }
 
             super.onRemove(state, world, pos, newState, moved);
@@ -229,16 +260,12 @@
 
     @Override
     protected int getSignal(BlockState state, BlockGetter world, BlockPos pos, Direction direction) {
-        return state.getValue(POWERED) ? 15 : 0;
+        return (Boolean) state.getValue(TripWireHookBlock.POWERED) ? 15 : 0;
     }
 
     @Override
     protected int getDirectSignal(BlockState state, BlockGetter world, BlockPos pos, Direction direction) {
-        if (!state.getValue(POWERED)) {
-            return 0;
-        } else {
-            return state.getValue(FACING) == direction ? 15 : 0;
-        }
+        return !(Boolean) state.getValue(TripWireHookBlock.POWERED) ? 0 : (state.getValue(TripWireHookBlock.FACING) == direction ? 15 : 0);
     }
 
     @Override
@@ -248,16 +275,16 @@
 
     @Override
     protected BlockState rotate(BlockState state, Rotation rotation) {
-        return state.setValue(FACING, rotation.rotate(state.getValue(FACING)));
+        return (BlockState) state.setValue(TripWireHookBlock.FACING, rotation.rotate((Direction) state.getValue(TripWireHookBlock.FACING)));
     }
 
     @Override
     protected BlockState mirror(BlockState state, Mirror mirror) {
-        return state.rotate(mirror.getRotation(state.getValue(FACING)));
+        return state.rotate(mirror.getRotation((Direction) state.getValue(TripWireHookBlock.FACING)));
     }
 
     @Override
     protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
-        builder.add(FACING, POWERED, ATTACHED);
+        builder.add(TripWireHookBlock.FACING, TripWireHookBlock.POWERED, TripWireHookBlock.ATTACHED);
     }
 }
