--- a/net/minecraft/world/level/block/CommandBlock.java
+++ b/net/minecraft/world/level/block/CommandBlock.java
@@ -29,10 +29,15 @@
 import net.minecraft.world.phys.BlockHitResult;
 import org.slf4j.Logger;
 
+import org.bukkit.event.block.BlockRedstoneEvent; // CraftBukkit
+
 public class CommandBlock extends BaseEntityBlock implements GameMasterBlock {
-    public static final MapCodec<CommandBlock> CODEC = RecordCodecBuilder.mapCodec(
-        instance -> instance.group(Codec.BOOL.fieldOf("automatic").forGetter(block -> block.automatic), propertiesCodec()).apply(instance, CommandBlock::new)
-    );
+
+    public static final MapCodec<CommandBlock> CODEC = RecordCodecBuilder.mapCodec((instance) -> {
+        return instance.group(Codec.BOOL.fieldOf("automatic").forGetter((blockcommand) -> {
+            return blockcommand.automatic;
+        }), propertiesCodec()).apply(instance, CommandBlock::new);
+    });
     private static final Logger LOGGER = LogUtils.getLogger();
     public static final DirectionProperty FACING = DirectionalBlock.FACING;
     public static final BooleanProperty CONDITIONAL = BlockStateProperties.CONDITIONAL;
@@ -40,34 +45,49 @@
 
     @Override
     public MapCodec<CommandBlock> codec() {
-        return CODEC;
+        return CommandBlock.CODEC;
     }
 
     public CommandBlock(boolean auto, BlockBehaviour.Properties settings) {
         super(settings);
-        this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(CONDITIONAL, Boolean.valueOf(false)));
+        this.registerDefaultState((BlockState) ((BlockState) ((BlockState) this.stateDefinition.any()).setValue(CommandBlock.FACING, Direction.NORTH)).setValue(CommandBlock.CONDITIONAL, false));
         this.automatic = auto;
     }
 
     @Override
     public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
-        CommandBlockEntity commandBlockEntity = new CommandBlockEntity(pos, state);
-        commandBlockEntity.setAutomatic(this.automatic);
-        return commandBlockEntity;
+        CommandBlockEntity tileentitycommand = new CommandBlockEntity(pos, state);
+
+        tileentitycommand.setAutomatic(this.automatic);
+        return tileentitycommand;
     }
 
     @Override
     protected void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) {
         if (!world.isClientSide) {
-            if (world.getBlockEntity(pos) instanceof CommandBlockEntity commandBlockEntity) {
-                boolean bl = world.hasNeighborSignal(pos);
-                boolean bl2 = commandBlockEntity.isPowered();
-                commandBlockEntity.setPowered(bl);
-                if (!bl2 && !commandBlockEntity.isAutomatic() && commandBlockEntity.getMode() != CommandBlockEntity.Mode.SEQUENCE) {
-                    if (bl) {
-                        commandBlockEntity.markConditionMet();
-                        world.scheduleTick(pos, this, 1);
+            BlockEntity tileentity = world.getBlockEntity(pos);
+
+            if (tileentity instanceof CommandBlockEntity) {
+                CommandBlockEntity tileentitycommand = (CommandBlockEntity) tileentity;
+                boolean flag1 = world.hasNeighborSignal(pos);
+                boolean flag2 = tileentitycommand.isPowered();
+                // CraftBukkit start
+                org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ());
+                int old = flag2 ? 15 : 0;
+                int current = flag1 ? 15 : 0;
+
+                BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(bukkitBlock, old, current);
+                world.getCraftServer().getPluginManager().callEvent(eventRedstone);
+                flag1 = eventRedstone.getNewCurrent() > 0;
+                // CraftBukkit end
+
+                tileentitycommand.setPowered(flag1);
+                if (!flag2 && !tileentitycommand.isAutomatic() && tileentitycommand.getMode() != CommandBlockEntity.Mode.SEQUENCE) {
+                    if (flag1) {
+                        tileentitycommand.markConditionMet();
+                        world.scheduleTick(pos, (Block) this, 1);
                     }
+
                 }
             }
         }
@@ -75,32 +95,36 @@
 
     @Override
     protected void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
-        if (world.getBlockEntity(pos) instanceof CommandBlockEntity commandBlockEntity) {
-            BaseCommandBlock baseCommandBlock = commandBlockEntity.getCommandBlock();
-            boolean bl = !StringUtil.isNullOrEmpty(baseCommandBlock.getCommand());
-            CommandBlockEntity.Mode mode = commandBlockEntity.getMode();
-            boolean bl2 = commandBlockEntity.wasConditionMet();
-            if (mode == CommandBlockEntity.Mode.AUTO) {
-                commandBlockEntity.markConditionMet();
-                if (bl2) {
-                    this.execute(state, world, pos, baseCommandBlock, bl);
-                } else if (commandBlockEntity.isConditional()) {
-                    baseCommandBlock.setSuccessCount(0);
+        BlockEntity tileentity = world.getBlockEntity(pos);
+
+        if (tileentity instanceof CommandBlockEntity tileentitycommand) {
+            BaseCommandBlock commandblocklistenerabstract = tileentitycommand.getCommandBlock();
+            boolean flag = !StringUtil.isNullOrEmpty(commandblocklistenerabstract.getCommand());
+            CommandBlockEntity.Mode tileentitycommand_type = tileentitycommand.getMode();
+            boolean flag1 = tileentitycommand.wasConditionMet();
+
+            if (tileentitycommand_type == CommandBlockEntity.Mode.AUTO) {
+                tileentitycommand.markConditionMet();
+                if (flag1) {
+                    this.execute(state, world, pos, commandblocklistenerabstract, flag);
+                } else if (tileentitycommand.isConditional()) {
+                    commandblocklistenerabstract.setSuccessCount(0);
                 }
 
-                if (commandBlockEntity.isPowered() || commandBlockEntity.isAutomatic()) {
-                    world.scheduleTick(pos, this, 1);
+                if (tileentitycommand.isPowered() || tileentitycommand.isAutomatic()) {
+                    world.scheduleTick(pos, (Block) this, 1);
                 }
-            } else if (mode == CommandBlockEntity.Mode.REDSTONE) {
-                if (bl2) {
-                    this.execute(state, world, pos, baseCommandBlock, bl);
-                } else if (commandBlockEntity.isConditional()) {
-                    baseCommandBlock.setSuccessCount(0);
+            } else if (tileentitycommand_type == CommandBlockEntity.Mode.REDSTONE) {
+                if (flag1) {
+                    this.execute(state, world, pos, commandblocklistenerabstract, flag);
+                } else if (tileentitycommand.isConditional()) {
+                    commandblocklistenerabstract.setSuccessCount(0);
                 }
             }
 
             world.updateNeighbourForOutputSignal(pos, this);
         }
+
     }
 
     private void execute(BlockState state, Level world, BlockPos pos, BaseCommandBlock executor, boolean hasCommand) {
@@ -110,14 +134,15 @@
             executor.setSuccessCount(0);
         }
 
-        executeChain(world, pos, state.getValue(FACING));
+        CommandBlock.executeChain(world, pos, (Direction) state.getValue(CommandBlock.FACING));
     }
 
     @Override
     protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) {
-        BlockEntity blockEntity = world.getBlockEntity(pos);
-        if (blockEntity instanceof CommandBlockEntity && player.canUseGameMasterBlocks()) {
-            player.openCommandBlock((CommandBlockEntity)blockEntity);
+        BlockEntity tileentity = world.getBlockEntity(pos);
+
+        if (tileentity instanceof CommandBlockEntity && (player.canUseGameMasterBlocks() || (player.isCreative() && player.getBukkitEntity().hasPermission("minecraft.commandblock")))) { // Paper - command block permission
+            player.openCommandBlock((CommandBlockEntity) tileentity);
             return InteractionResult.sidedSuccess(world.isClientSide);
         } else {
             return InteractionResult.PASS;
@@ -131,25 +156,31 @@
 
     @Override
     protected int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) {
-        BlockEntity blockEntity = world.getBlockEntity(pos);
-        return blockEntity instanceof CommandBlockEntity ? ((CommandBlockEntity)blockEntity).getCommandBlock().getSuccessCount() : 0;
+        BlockEntity tileentity = world.getBlockEntity(pos);
+
+        return tileentity instanceof CommandBlockEntity ? ((CommandBlockEntity) tileentity).getCommandBlock().getSuccessCount() : 0;
     }
 
     @Override
     public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack itemStack) {
-        if (world.getBlockEntity(pos) instanceof CommandBlockEntity commandBlockEntity) {
-            BaseCommandBlock baseCommandBlock = commandBlockEntity.getCommandBlock();
+        BlockEntity tileentity = world.getBlockEntity(pos);
+
+        if (tileentity instanceof CommandBlockEntity tileentitycommand) {
+            BaseCommandBlock commandblocklistenerabstract = tileentitycommand.getCommandBlock();
+
             if (!world.isClientSide) {
                 if (!itemStack.has(DataComponents.BLOCK_ENTITY_DATA)) {
-                    baseCommandBlock.setTrackOutput(world.getGameRules().getBoolean(GameRules.RULE_SENDCOMMANDFEEDBACK));
-                    commandBlockEntity.setAutomatic(this.automatic);
+                    commandblocklistenerabstract.setTrackOutput(world.getGameRules().getBoolean(GameRules.RULE_SENDCOMMANDFEEDBACK));
+                    tileentitycommand.setAutomatic(this.automatic);
                 }
 
-                if (commandBlockEntity.getMode() == CommandBlockEntity.Mode.SEQUENCE) {
-                    boolean bl = world.hasNeighborSignal(pos);
-                    commandBlockEntity.setPowered(bl);
+                if (tileentitycommand.getMode() == CommandBlockEntity.Mode.SEQUENCE) {
+                    boolean flag = world.hasNeighborSignal(pos);
+
+                    tileentitycommand.setPowered(flag);
                 }
             }
+
         }
     }
 
@@ -160,58 +191,72 @@
 
     @Override
     protected BlockState rotate(BlockState state, Rotation rotation) {
-        return state.setValue(FACING, rotation.rotate(state.getValue(FACING)));
+        return (BlockState) state.setValue(CommandBlock.FACING, rotation.rotate((Direction) state.getValue(CommandBlock.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(CommandBlock.FACING)));
     }
 
     @Override
     protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
-        builder.add(FACING, CONDITIONAL);
+        builder.add(CommandBlock.FACING, CommandBlock.CONDITIONAL);
     }
 
     @Override
     public BlockState getStateForPlacement(BlockPlaceContext ctx) {
-        return this.defaultBlockState().setValue(FACING, ctx.getNearestLookingDirection().getOpposite());
+        return (BlockState) this.defaultBlockState().setValue(CommandBlock.FACING, ctx.getNearestLookingDirection().getOpposite());
     }
 
     private static void executeChain(Level world, BlockPos pos, Direction facing) {
-        BlockPos.MutableBlockPos mutableBlockPos = pos.mutable();
-        GameRules gameRules = world.getGameRules();
-        int i = gameRules.getInt(GameRules.RULE_MAX_COMMAND_CHAIN_LENGTH);
+        BlockPos.MutableBlockPos blockposition_mutableblockposition = pos.mutable();
+        GameRules gamerules = world.getGameRules();
 
-        while (i-- > 0) {
-            mutableBlockPos.move(facing);
-            BlockState blockState = world.getBlockState(mutableBlockPos);
-            Block block = blockState.getBlock();
-            if (!blockState.is(Blocks.CHAIN_COMMAND_BLOCK)
-                || !(world.getBlockEntity(mutableBlockPos) instanceof CommandBlockEntity commandBlockEntity)
-                || commandBlockEntity.getMode() != CommandBlockEntity.Mode.SEQUENCE) {
+        BlockState iblockdata;
+        int i;
+
+        for (i = gamerules.getInt(GameRules.RULE_MAX_COMMAND_CHAIN_LENGTH); i-- > 0; facing = (Direction) iblockdata.getValue(CommandBlock.FACING)) {
+            blockposition_mutableblockposition.move(facing);
+            iblockdata = world.getBlockState(blockposition_mutableblockposition);
+            Block block = iblockdata.getBlock();
+
+            if (!iblockdata.is(Blocks.CHAIN_COMMAND_BLOCK)) {
                 break;
             }
 
-            if (commandBlockEntity.isPowered() || commandBlockEntity.isAutomatic()) {
-                BaseCommandBlock baseCommandBlock = commandBlockEntity.getCommandBlock();
-                if (commandBlockEntity.markConditionMet()) {
-                    if (!baseCommandBlock.performCommand(world)) {
+            BlockEntity tileentity = world.getBlockEntity(blockposition_mutableblockposition);
+
+            if (!(tileentity instanceof CommandBlockEntity)) {
+                break;
+            }
+
+            CommandBlockEntity tileentitycommand = (CommandBlockEntity) tileentity;
+
+            if (tileentitycommand.getMode() != CommandBlockEntity.Mode.SEQUENCE) {
+                break;
+            }
+
+            if (tileentitycommand.isPowered() || tileentitycommand.isAutomatic()) {
+                BaseCommandBlock commandblocklistenerabstract = tileentitycommand.getCommandBlock();
+
+                if (tileentitycommand.markConditionMet()) {
+                    if (!commandblocklistenerabstract.performCommand(world)) {
                         break;
                     }
 
-                    world.updateNeighbourForOutputSignal(mutableBlockPos, block);
-                } else if (commandBlockEntity.isConditional()) {
-                    baseCommandBlock.setSuccessCount(0);
+                    world.updateNeighbourForOutputSignal(blockposition_mutableblockposition, block);
+                } else if (tileentitycommand.isConditional()) {
+                    commandblocklistenerabstract.setSuccessCount(0);
                 }
             }
-
-            facing = blockState.getValue(FACING);
         }
 
         if (i <= 0) {
-            int j = Math.max(gameRules.getInt(GameRules.RULE_MAX_COMMAND_CHAIN_LENGTH), 0);
-            LOGGER.warn("Command Block chain tried to execute more than {} steps!", j);
+            int j = Math.max(gamerules.getInt(GameRules.RULE_MAX_COMMAND_CHAIN_LENGTH), 0);
+
+            CommandBlock.LOGGER.warn("Command Block chain tried to execute more than {} steps!", j);
         }
+
     }
 }
