From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Mon, 9 Aug 2021 20:45:46 -0700
Subject: [PATCH] Fire EntityChangeBlockEvent in more places

Co-authored-by: ChristopheG <61288881+chrisgdt@users.noreply.github.com>
Co-authored-by: maxcom1 <46265094+maxcom1@users.noreply.github.com>

diff --git a/src/main/java/net/minecraft/world/entity/LightningBolt.java b/src/main/java/net/minecraft/world/entity/LightningBolt.java
index bf5015c4bb68e5c46313bab1e59c0a4d45053b73..0471d9c85af02133f99cca4e181b83b58a3f1abc 100644
--- a/src/main/java/net/minecraft/world/entity/LightningBolt.java
+++ b/src/main/java/net/minecraft/world/entity/LightningBolt.java
@@ -99,7 +99,7 @@ public class LightningBolt extends Entity {
                 }
 
                 this.powerLightningRod();
-                LightningBolt.clearCopperOnLightningStrike(this.level(), this.getStrikePosition());
+                LightningBolt.clearCopperOnLightningStrike(this.level(), this.getStrikePosition(), this); // Paper - Call EntityChangeBlockEvent
                 this.gameEvent(GameEvent.LIGHTNING_STRIKE);
             }
         }
@@ -193,7 +193,7 @@ public class LightningBolt extends Entity {
         }
     }
 
-    private static void clearCopperOnLightningStrike(Level world, BlockPos pos) {
+    private static void clearCopperOnLightningStrike(Level world, BlockPos pos, Entity lightning) { // Paper - Call EntityChangeBlockEvent
         BlockState iblockdata = world.getBlockState(pos);
         BlockPos blockposition1;
         BlockState iblockdata1;
@@ -207,24 +207,29 @@ public class LightningBolt extends Entity {
         }
 
         if (iblockdata1.getBlock() instanceof WeatheringCopper) {
-            world.setBlockAndUpdate(blockposition1, WeatheringCopper.getFirst(world.getBlockState(blockposition1)));
+            // Paper start - Call EntityChangeBlockEvent
+            BlockState newBlock = WeatheringCopper.getFirst(world.getBlockState(blockposition1));
+            if (CraftEventFactory.callEntityChangeBlockEvent(lightning, blockposition1, newBlock)) {
+                world.setBlockAndUpdate(blockposition1, newBlock);
+            }
+            // Paper end - Call EntityChangeBlockEvent
             BlockPos.MutableBlockPos blockposition_mutableblockposition = pos.mutable();
             int i = world.random.nextInt(3) + 3;
 
             for (int j = 0; j < i; ++j) {
                 int k = world.random.nextInt(8) + 1;
 
-                LightningBolt.randomWalkCleaningCopper(world, blockposition1, blockposition_mutableblockposition, k);
+                LightningBolt.randomWalkCleaningCopper(world, blockposition1, blockposition_mutableblockposition, k, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent
             }
 
         }
     }
 
-    private static void randomWalkCleaningCopper(Level world, BlockPos pos, BlockPos.MutableBlockPos mutablePos, int count) {
+    private static void randomWalkCleaningCopper(Level world, BlockPos pos, BlockPos.MutableBlockPos mutablePos, int count, Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent
         mutablePos.set(pos);
 
         for (int j = 0; j < count; ++j) {
-            Optional<BlockPos> optional = LightningBolt.randomStepCleaningCopper(world, mutablePos);
+            Optional<BlockPos> optional = LightningBolt.randomStepCleaningCopper(world, mutablePos, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent
 
             if (optional.isEmpty()) {
                 break;
@@ -235,7 +240,7 @@ public class LightningBolt extends Entity {
 
     }
 
-    private static Optional<BlockPos> randomStepCleaningCopper(Level world, BlockPos pos) {
+    private static Optional<BlockPos> randomStepCleaningCopper(Level world, BlockPos pos, Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent
         Iterator iterator = BlockPos.randomInCube(world.random, 10, pos, 1).iterator();
 
         BlockPos blockposition1;
@@ -252,6 +257,7 @@ public class LightningBolt extends Entity {
 
         BlockPos blockposition1Final = blockposition1; // CraftBukkit - decompile error
         WeatheringCopper.getPrevious(iblockdata).ifPresent((iblockdata1) -> {
+            if (CraftEventFactory.callEntityChangeBlockEvent(lightning, blockposition1Final, iblockdata1)) // Paper - call EntityChangeBlockEvent
             world.setBlockAndUpdate(blockposition1Final, iblockdata1); // CraftBukkit - decompile error
         });
         world.levelEvent(3002, blockposition1, -1);
diff --git a/src/main/java/net/minecraft/world/item/AxeItem.java b/src/main/java/net/minecraft/world/item/AxeItem.java
index bc689df6b43d42566aed875de6aa0081341c5c44..9fd2d97ff0e05578a3e6a0b86dc1974691845c5d 100644
--- a/src/main/java/net/minecraft/world/item/AxeItem.java
+++ b/src/main/java/net/minecraft/world/item/AxeItem.java
@@ -61,6 +61,11 @@ public class AxeItem extends DiggerItem {
             return InteractionResult.PASS;
         } else {
             ItemStack itemStack = context.getItemInHand();
+            // Paper start - EntityChangeBlockEvent
+            if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, blockPos, optional.get())) {
+                return InteractionResult.PASS;
+            }
+            // Paper end
             if (player instanceof ServerPlayer) {
                 CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger((ServerPlayer)player, blockPos, itemStack);
             }
diff --git a/src/main/java/net/minecraft/world/item/EnderEyeItem.java b/src/main/java/net/minecraft/world/item/EnderEyeItem.java
index 37cfb9694dc06f693b7b54f20bc31dfd9f95c76c..4d8c98db89ae32baa407830d9380ece3b34c642a 100644
--- a/src/main/java/net/minecraft/world/item/EnderEyeItem.java
+++ b/src/main/java/net/minecraft/world/item/EnderEyeItem.java
@@ -44,6 +44,11 @@ public class EnderEyeItem extends Item {
                 return InteractionResult.SUCCESS;
             } else {
                 BlockState iblockdata1 = (BlockState) iblockdata.setValue(EndPortalFrameBlock.HAS_EYE, true);
+                // Paper start
+                if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(context.getPlayer(), blockposition, iblockdata1)) {
+                    return InteractionResult.PASS;
+                }
+                // Paper end
 
                 Block.pushEntitiesUp(iblockdata, iblockdata1, world, blockposition);
                 world.setBlock(blockposition, iblockdata1, 2);
diff --git a/src/main/java/net/minecraft/world/item/HoneycombItem.java b/src/main/java/net/minecraft/world/item/HoneycombItem.java
index decabf6fccaca3d1bfeba679ac71677d33315f5e..14d37bf64af719eae3ea154ea7f952cc27712b57 100644
--- a/src/main/java/net/minecraft/world/item/HoneycombItem.java
+++ b/src/main/java/net/minecraft/world/item/HoneycombItem.java
@@ -74,6 +74,14 @@ public class HoneycombItem extends Item implements SignApplicator {
         return getWaxed(blockState).map(state -> {
             Player player = context.getPlayer();
             ItemStack itemStack = context.getItemInHand();
+            // Paper start - EntityChangeBlockEvent
+            if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, blockPos, state)) {
+                if (!player.isCreative()) {
+                    player.containerMenu.sendAllDataToRemote();
+                }
+                return InteractionResult.PASS;
+            }
+            // Paper end
             if (player instanceof ServerPlayer) {
                 CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger((ServerPlayer)player, blockPos, itemStack);
             }
diff --git a/src/main/java/net/minecraft/world/item/PotionItem.java b/src/main/java/net/minecraft/world/item/PotionItem.java
index 042a9cf9c15fd30bc30e03d0e0311c70e40e6950..db038cb423c3b951890c81d833aa77ebcea3304f 100644
--- a/src/main/java/net/minecraft/world/item/PotionItem.java
+++ b/src/main/java/net/minecraft/world/item/PotionItem.java
@@ -109,6 +109,12 @@ public class PotionItem extends Item {
         BlockState iblockdata = world.getBlockState(blockposition);
 
         if (context.getClickedFace() != Direction.DOWN && iblockdata.is(BlockTags.CONVERTABLE_TO_MUD) && potioncontents.is(Potions.WATER)) {
+            // Paper start
+            if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entityhuman, blockposition, Blocks.MUD.defaultBlockState())) {
+                entityhuman.containerMenu.sendAllDataToRemote();
+                return InteractionResult.PASS;
+            }
+            // Paper end
             world.playSound((Player) null, blockposition, SoundEvents.GENERIC_SPLASH, SoundSource.BLOCKS, 1.0F, 1.0F);
             entityhuman.setItemInHand(context.getHand(), ItemUtils.createFilledResult(itemstack, entityhuman, new ItemStack(Items.GLASS_BOTTLE)));
             entityhuman.awardStat(Stats.ITEM_USED.get(itemstack.getItem()));
diff --git a/src/main/java/net/minecraft/world/item/ShovelItem.java b/src/main/java/net/minecraft/world/item/ShovelItem.java
index c0e96284bb470353c0e54ad4e0c2205017913e61..24f6a158e4759aac3be8da4cf5e0d40bd295355b 100644
--- a/src/main/java/net/minecraft/world/item/ShovelItem.java
+++ b/src/main/java/net/minecraft/world/item/ShovelItem.java
@@ -46,20 +46,29 @@ public class ShovelItem extends DiggerItem {
             Player player = context.getPlayer();
             BlockState blockState2 = FLATTENABLES.get(blockState.getBlock());
             BlockState blockState3 = null;
+            Runnable afterAction = null; // Paper
             if (blockState2 != null && level.getBlockState(blockPos.above()).isAir()) {
-                level.playSound(player, blockPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F);
+                afterAction = () -> level.playSound(player, blockPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); // Paper
                 blockState3 = blockState2;
             } else if (blockState.getBlock() instanceof CampfireBlock && blockState.getValue(CampfireBlock.LIT)) {
+                afterAction = () -> { // Paper
                 if (!level.isClientSide()) {
                     level.levelEvent(null, 1009, blockPos, 0);
                 }
 
                 CampfireBlock.dowse(context.getPlayer(), level, blockPos, blockState);
+                }; // Paper
                 blockState3 = blockState.setValue(CampfireBlock.LIT, Boolean.valueOf(false));
             }
 
             if (blockState3 != null) {
                 if (!level.isClientSide) {
+                    // Paper start
+                    if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(context.getPlayer(), blockPos, blockState3)) {
+                        return InteractionResult.PASS;
+                    }
+                    afterAction.run();
+                    // Paper end
                     level.setBlock(blockPos, blockState3, 11);
                     level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(player, blockState3));
                     if (player != null) {
diff --git a/src/main/java/net/minecraft/world/level/block/CakeBlock.java b/src/main/java/net/minecraft/world/level/block/CakeBlock.java
index 430312f4e67a253465c54e3fe5e5cfad365cfa22..ac40246f0bb4903b6623c02d7a3512b5208b264f 100644
--- a/src/main/java/net/minecraft/world/level/block/CakeBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/CakeBlock.java
@@ -64,7 +64,12 @@ public class CakeBlock extends Block {
 
             if (block instanceof CandleBlock) {
                 CandleBlock candleblock = (CandleBlock) block;
-
+                // Paper start - call change block event
+                if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, CandleCakeBlock.byCandle(candleblock))) {
+                    player.containerMenu.sendAllDataToRemote(); // update inv because candle could decrease
+                    return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
+                }
+                // Paper end - call change block event
                 if (!player.isCreative()) {
                     stack.shrink(1);
                 }
@@ -99,6 +104,14 @@ public class CakeBlock extends Block {
         if (!player.canEat(false)) {
             return InteractionResult.PASS;
         } else {
+            // Paper start - call change block event
+            int i = state.getValue(CakeBlock.BITES);
+            final BlockState newState = i < MAX_BITES ? state.setValue(CakeBlock.BITES, i + 1) : world.getFluidState(pos).createLegacyBlock();
+            if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, newState)) {
+                ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity().sendHealthUpdate();
+                return InteractionResult.PASS; // return a non-consume result to cake blocks don't drop their candles
+            }
+            // Paper end - call change block event
             player.awardStat(Stats.EAT_CAKE_SLICE);
             // CraftBukkit start
             // entityhuman.getFoodData().eat(2, 0.1F);
@@ -112,7 +125,7 @@ public class CakeBlock extends Block {
 
             ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity().sendHealthUpdate();
             // CraftBukkit end
-            int i = (Integer) state.getValue(CakeBlock.BITES);
+            // Paper - move up
 
             world.gameEvent((Entity) player, (Holder) GameEvent.EAT, pos);
             if (i < 6) {
diff --git a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java
index 804adb5ed92dfcf4c29c756dd95d7164150a9666..19fa8a9f935e9063497f8c0bd7909036fa0af2b7 100644
--- a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java
@@ -239,6 +239,11 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder {
         if (i < 8 && ComposterBlock.COMPOSTABLES.containsKey(stack.getItem())) {
             if (i < 7 && !world.isClientSide) {
                 BlockState iblockdata1 = ComposterBlock.addItem(player, state, world, pos, stack);
+                // Paper start - handle cancelled events
+                if (iblockdata1 == null) {
+                    return ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION;
+                }
+                // Paper end
 
                 world.levelEvent(1500, pos, state != iblockdata1 ? 1 : 0);
                 player.awardStat(Stats.ITEM_USED.get(stack.getItem()));
@@ -269,11 +274,16 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder {
         if (i < 7 && ComposterBlock.COMPOSTABLES.containsKey(stack.getItem())) {
             // CraftBukkit start
             double rand = world.getRandom().nextDouble();
-            BlockState iblockdata1 = ComposterBlock.addItem(user, state, DummyGeneratorAccess.INSTANCE, pos, stack, rand);
-            if (state == iblockdata1 || !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(user, pos, iblockdata1)) {
+            BlockState iblockdata1 = null; // Paper
+            if (false && (state == iblockdata1 || !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(user, pos, iblockdata1))) { // Paper - move event call into addItem
                 return state;
             }
             iblockdata1 = ComposterBlock.addItem(user, state, world, pos, stack, rand);
+            // Paper start - handle cancelled events
+            if (iblockdata1 == null) {
+                return state;
+            }
+            // Paper end
             // CraftBukkit end
 
             stack.shrink(1);
@@ -314,11 +324,13 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder {
         return iblockdata1;
     }
 
+    @Nullable // Paper
     static BlockState addItem(@Nullable Entity user, BlockState state, LevelAccessor world, BlockPos pos, ItemStack stack) {
         // CraftBukkit start
         return ComposterBlock.addItem(user, state, world, pos, stack, world.getRandom().nextDouble());
     }
 
+    @Nullable // Paper - make it nullable
     static BlockState addItem(@Nullable Entity entity, BlockState iblockdata, LevelAccessor generatoraccess, BlockPos blockposition, ItemStack itemstack, double rand) {
         // CraftBukkit end
         int i = (Integer) iblockdata.getValue(ComposterBlock.LEVEL);
@@ -329,6 +341,11 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder {
         } else {
             int j = i + 1;
             BlockState iblockdata1 = (BlockState) iblockdata.setValue(ComposterBlock.LEVEL, j);
+            // Paper start - move the EntityChangeBlockEvent here to avoid conflict later for the compost events
+            if (entity != null && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, blockposition, iblockdata1)) {
+                return null;
+            }
+            // Paper end
 
             generatoraccess.setBlock(blockposition, iblockdata1, 3);
             generatoraccess.gameEvent((Holder) GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(entity, iblockdata1));
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
index b18494d2a83473e9bc4197f86ff599de59043217..6fb7ec36f6f7a3021fac4b9e31fd333dfd5ea5e5 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
@@ -259,7 +259,13 @@ public class BeehiveBlockEntity extends BlockEntity {
                                         --j;
                                     }
 
-                                    world.setBlockAndUpdate(blockposition, (BlockState) iblockdata.setValue(BeehiveBlock.HONEY_LEVEL, i + j));
+                                    // Paper start - Fire EntityChangeBlockEvent in more places
+                                    BlockState newBlockState = iblockdata.setValue(BeehiveBlock.HONEY_LEVEL, i + j);
+
+                                    if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entitybee, blockposition, newBlockState)) {
+                                        world.setBlockAndUpdate(blockposition, newBlockState);
+                                    }
+                                    // Paper end - Fire EntityChangeBlockEvent in more places
                                 }
                             }
                         }
diff --git a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java
index daf3c26fce7569761951bfd5594c6726d854a9ff..e8a73d34dbb372581b03018aade170a31c266099 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java
@@ -120,7 +120,7 @@ public class DummyGeneratorAccess implements WorldGenLevel {
 
     @Override
     public void gameEvent(Holder<GameEvent> event, Vec3 emitterPos, GameEvent.Context emitter) {
-        // Used by BlockComposter
+        // Used by ComposterBlock
     }
 
     @Override