diff --git a/paper-server/patches/features/0005-Optimize-Connection-and-add-advanced-packet-support.patch b/paper-server/patches/features/0005-Optimize-Connection-and-add-advanced-packet-support.patch index 93e21352e385..2bf866a288af 100644 --- a/paper-server/patches/features/0005-Optimize-Connection-and-add-advanced-packet-support.patch +++ b/paper-server/patches/features/0005-Optimize-Connection-and-add-advanced-packet-support.patch @@ -28,7 +28,7 @@ and then catch exceptions and close if they fire. Part of this commit was authored by: Spottedleaf, sandtechnology diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java -index f7814801138d9547e693ad51ba83cb2cb4ef750e..e6a674eb859af1e98fe25b644c1c5f70728128d0 100644 +index 91c1ff8b8234900fbe044bbe0c3c10122c27a91b..e226a4b3ae089c3685ea7e5ae052d7a7e96c8d52 100644 --- a/net/minecraft/network/Connection.java +++ b/net/minecraft/network/Connection.java @@ -64,7 +64,7 @@ public class Connection extends SimpleChannelInboundHandler> { diff --git a/paper-server/patches/features/0008-Use-Velocity-compression-and-cipher-natives.patch b/paper-server/patches/features/0008-Use-Velocity-compression-and-cipher-natives.patch index f0cb109c32cd..883085178c76 100644 --- a/paper-server/patches/features/0008-Use-Velocity-compression-and-cipher-natives.patch +++ b/paper-server/patches/features/0008-Use-Velocity-compression-and-cipher-natives.patch @@ -267,7 +267,7 @@ index 595db570b0ade9cad7de77d2ab7b10d9e68699df..ac095f59d9f17d8239d6493d1c1e3942 + // Paper end - Use Velocity cipher } diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java -index e6a674eb859af1e98fe25b644c1c5f70728128d0..936200d7620e1fe83eb45ddbcff86b6b6ecaab8f 100644 +index e226a4b3ae089c3685ea7e5ae052d7a7e96c8d52..76596e87945f0b95af8032338a64817a8faed4d0 100644 --- a/net/minecraft/network/Connection.java +++ b/net/minecraft/network/Connection.java @@ -796,10 +796,24 @@ public class Connection extends SimpleChannelInboundHandler> { @@ -320,7 +320,7 @@ index e6a674eb859af1e98fe25b644c1c5f70728128d0..936200d7620e1fe83eb45ddbcff86b6b this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_THRESHOLD_SET); // Paper - Add Channel initialization listeners } else { diff --git a/net/minecraft/server/network/ServerConnectionListener.java b/net/minecraft/server/network/ServerConnectionListener.java -index c2b09a693daf8b4d3d274c07b3be37ba4fc1a483..2f3b58491ef7be8cd2e081f2c44869cd1e50e6a6 100644 +index 100e7a2483f63497a1b757c77377262de7248996..42408dede2808447281b49f4006c1d8b03c10bf4 100644 --- a/net/minecraft/server/network/ServerConnectionListener.java +++ b/net/minecraft/server/network/ServerConnectionListener.java @@ -71,6 +71,10 @@ public class ServerConnectionListener { @@ -335,7 +335,7 @@ index c2b09a693daf8b4d3d274c07b3be37ba4fc1a483..2f3b58491ef7be8cd2e081f2c44869cd .add( new ServerBootstrap() diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index dd2c5b7bd16ca17e253501fbc49cc21c8a06d603..a1855a257c3ac801bbd371ca4508af755550d737 100644 +index ab21339beb36388bffabb289546bbfe5732df855..eea7dd596eb9ac75dee29d843d786493d44034f3 100644 --- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java @@ -256,9 +256,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, diff --git a/paper-server/patches/features/0013-Add-Alternate-Current-redstone-implementation.patch b/paper-server/patches/features/0013-Add-Alternate-Current-redstone-implementation.patch index a18393230d56..fddcfa3d79be 100644 --- a/paper-server/patches/features/0013-Add-Alternate-Current-redstone-implementation.patch +++ b/paper-server/patches/features/0013-Add-Alternate-Current-redstone-implementation.patch @@ -2321,7 +2321,7 @@ index 0000000000000000000000000000000000000000..505b5e39d0b4cf2a56c1c720f0c9ab01 + } +} diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index bc2bacabb588bd6a644ac5226720c7451ac0e475..e4d38cfdac2b926afae3b1b96679b6ce45ea256a 100644 +index a4e6225add32df93b0d6009d98ee322941b69938..e197ac0ee5e49d7768a9de889c972b3d590f7951 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java @@ -238,6 +238,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet @@ -2347,7 +2347,7 @@ index bc2bacabb588bd6a644ac5226720c7451ac0e475..e4d38cfdac2b926afae3b1b96679b6ce return toLevel.dimension() != Level.NETHER || this.getGameRules().get(GameRules.ALLOW_ENTERING_NETHER_USING_PORTALS); } diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index efcf399ced67201525ea6e6b3bd46b93b7e1823d..a1da101177a5a4fb2b4ba5e34be165daf4d147fb 100644 +index 2f5ec35bf7f104e259f85d15b17c8064daa05a5e..7cbf8592ec5792e458fa07987cf258c51f9e1e8a 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -2169,6 +2169,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl diff --git a/paper-server/patches/features/0033-Pre-load-data-off-main-during-startup.patch b/paper-server/patches/features/0033-Pre-load-data-off-main-during-startup.patch index 18083b4d6857..8ae1363f39e9 100644 --- a/paper-server/patches/features/0033-Pre-load-data-off-main-during-startup.patch +++ b/paper-server/patches/features/0033-Pre-load-data-off-main-during-startup.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Pre-load data off-main during startup diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java -index b515d8be0e2f0639f7fc843d6ce074b0a583c673..984cf7143e3809507c557e0e70ab271b753db235 100644 +index c22cc4387e7cc5da7d38ee14ed7f187b5d9507f4..aa7f2ba4d931f98ce15c52dc2b99f07504149582 100644 --- a/net/minecraft/server/Main.java +++ b/net/minecraft/server/Main.java @@ -102,7 +102,10 @@ public class Main { diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java.patch index 4fe61735fd7f..4273963c4a37 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java.patch @@ -66,7 +66,7 @@ + itemEntity.setItem(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem())); + itemEntity.setDeltaMovement(org.bukkit.craftbukkit.util.CraftVector.toVec3(event.getVelocity())); + -+ if (source.state().is(net.minecraft.world.level.block.Blocks.DISPENSER) && !event.getItem().getType().equals(craftItem.getType())) { ++ if (source.state().is(net.minecraft.world.level.block.Blocks.DISPENSER) && event.getItem().getType() != craftItem.getType()) { + // Chain to handler for new item + ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); + DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch index ff7c9a136eb1..587a3783b0e8 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch @@ -134,14 +134,14 @@ return super.execute(source, dispensed); } - level.gameEvent(null, GameEvent.FLUID_PICKUP, target); - Item targetType = pickup.getItem(); + // Paper start - Call BlockDispenseEvent + ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); + if (result != null) { + return result; + } + // Paper end - Call BlockDispenseEvent + level.gameEvent(null, GameEvent.FLUID_PICKUP, target); + Item targetType = pickup.getItem(); + pickup = bucket.pickupBlock(null, level, target, blockState); // CraftBukkit - from above return this.consumeWithRemainder(source, dispensed, new ItemStack(targetType)); } else { @@ -250,20 +250,20 @@ this.setSuccess(true); return dispensed; } -@@ -230,6 +_,13 @@ - Level level = source.level(); +@@ -231,6 +_,13 @@ Direction direction = source.state().getValue(DispenserBlock.FACING); BlockPos target = source.pos().relative(direction); -+ // Paper start - Call BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); -+ if (result != null) { -+ this.setSuccess(false); -+ return result; -+ } -+ // Paper end - Call BlockDispenseEvent if (level.isEmptyBlock(target) && WitherSkullBlock.canSpawnMob(level, target, dispensed)) { ++ // Paper start - Call BlockDispenseEvent ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); ++ if (result != null) { ++ this.setSuccess(false); ++ return result; ++ } ++ // Paper end - Call BlockDispenseEvent level.setBlockAndUpdate( target, Blocks.WITHER_SKELETON_SKULL.defaultBlockState().setValue(SkullBlock.ROTATION, RotationSegment.convertToSegment(direction)) + ); @@ -242,7 +_,7 @@ dispensed.shrink(1); this.setSuccess(true); @@ -273,20 +273,20 @@ } return dispensed; -@@ -255,6 +_,13 @@ - Level level = source.level(); +@@ -256,6 +_,13 @@ BlockPos target = source.pos().relative(source.state().getValue(DispenserBlock.FACING)); CarvedPumpkinBlock pumpkinBlock = (CarvedPumpkinBlock)Blocks.CARVED_PUMPKIN; -+ // Paper start - Call BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); -+ if (result != null) { -+ this.setSuccess(false); -+ return result; -+ } -+ // Paper end - Call BlockDispenseEvent if (level.isEmptyBlock(target) && pumpkinBlock.canSpawnGolem(level, target)) { ++ // Paper start - Call BlockDispenseEvent ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); ++ if (result != null) { ++ this.setSuccess(false); ++ return result; ++ } ++ // Paper end - Call BlockDispenseEvent if (!level.isClientSide()) { level.setBlockAndUpdate(target, pumpkinBlock.defaultBlockState()); + level.gameEvent(null, GameEvent.BLOCK_PLACE, target); @@ -264,7 +_,7 @@ dispensed.shrink(1); this.setSuccess(true); @@ -296,19 +296,30 @@ } return dispensed; -@@ -287,6 +_,12 @@ - ServerLevel level = source.level(); - BlockPos target = source.pos().relative(source.state().getValue(DispenserBlock.FACING)); +@@ -289,11 +_,23 @@ BlockState state = level.getBlockState(target); -+ // Paper start - Call BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); -+ if (result != null) { -+ return result; -+ } -+ // Paper end - Call BlockDispenseEvent if (state.is(BlockTags.BEEHIVES, s -> s.hasProperty(BeehiveBlock.HONEY_LEVEL) && s.getBlock() instanceof BeehiveBlock) && state.getValue(BeehiveBlock.HONEY_LEVEL) >= 5) { ++ // Paper start - Call BlockDispenseEvent ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); ++ if (result != null) { ++ return result; ++ } ++ // Paper end - Call BlockDispenseEvent ((BeehiveBlock)state.getBlock()) + .releaseBeesAndResetHoneyLevel(level, state, target, null, BeehiveBlockEntity.BeeReleaseStatus.BEE_RELEASED); + this.setSuccess(true); + return this.takeLiquid(source, dispensed, new ItemStack(Items.HONEY_BOTTLE)); + } else if (level.getFluidState(target).is(FluidTags.WATER)) { ++ // Paper start - Call BlockDispenseEvent ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); ++ if (result != null) { ++ return result; ++ } ++ // Paper end - Call BlockDispenseEvent + this.setSuccess(true); + return this.takeLiquid(source, dispensed, PotionContents.createItemStack(Items.POTION, Potions.WATER)); + } else { @@ -312,6 +_,13 @@ this.setSuccess(true); if (blockState.is(Blocks.RESPAWN_ANCHOR)) { diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/FlintAndSteelDispenseItemBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/FlintAndSteelDispenseItemBehavior.java.patch index e52da0e4677f..dd0d87a7eb1f 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/FlintAndSteelDispenseItemBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/FlintAndSteelDispenseItemBehavior.java.patch @@ -1,19 +1,24 @@ --- a/net/minecraft/core/dispenser/FlintAndSteelDispenseItemBehavior.java +++ b/net/minecraft/core/dispenser/FlintAndSteelDispenseItemBehavior.java -@@ -24,16 +_,27 @@ - this.setSuccess(true); +@@ -25,21 +_,55 @@ Direction facing = source.state().getValue(DispenserBlock.FACING); BlockPos targetPos = source.pos().relative(facing); + BlockState target = level.getBlockState(targetPos); +- if (!tryIgniteExplosiveEntities(level, targetPos)) { + // Paper start - Call BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, targetPos, dispensed, this); -+ if (result != null) { -+ this.setSuccess(false); -+ return result; -+ } ++ final @org.jspecify.annotations.Nullable ItemStack[] blockDispenseEventResult = new ItemStack[1]; ++ if (!tryIgniteExplosiveEntities(level, targetPos, () -> ++ (blockDispenseEventResult[0] = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, targetPos, dispensed, this)) == null) ++ ) { + // Paper end - Call BlockDispenseEvent - BlockState target = level.getBlockState(targetPos); - if (!tryIgniteExplosiveEntities(level, targetPos)) { if (BaseFireBlock.canBePlacedAt(level, targetPos, facing)) { ++ // Paper start - Call BlockDispenseEvent ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, targetPos, dispensed, this); ++ if (result != null) { ++ this.setSuccess(false); ++ return result; ++ } ++ // Paper end - Call BlockDispenseEvent + // CraftBukkit start - Ignition by dispensing flint and steel + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(level, targetPos, source.pos()).isCancelled()) { level.setBlockAndUpdate(targetPos, BaseFireBlock.getState(level, targetPos)); @@ -21,11 +26,55 @@ + } + // CraftBukkit end } else if (CampfireBlock.canLight(target) || CandleBlock.canLight(target) || CandleCakeBlock.canLight(target)) { ++ // Paper start - Call BlockDispenseEvent ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, targetPos, dispensed, this); ++ if (result != null) { ++ this.setSuccess(false); ++ return result; ++ } ++ // Paper end - Call BlockDispenseEvent level.setBlockAndUpdate(targetPos, target.setValue(BlockStateProperties.LIT, true)); level.gameEvent(null, GameEvent.BLOCK_CHANGE, targetPos); } else if (target.getBlock() instanceof TntBlock) { - if (TntBlock.prime(level, targetPos, null, dispensed)) { -+ if (TntBlock.prime(level, targetPos, null, dispensed, () -> org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(level, targetPos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.DISPENSER, null, source.pos()))) { // CraftBukkit - TNTPrimeEvent ++ // Paper start - Call BlockDispenseEvent / TNTPrimeEvent ++ final java.util.function.BooleanSupplier tntPrimedEvents = () -> ( ++ blockDispenseEventResult[0] = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, targetPos, dispensed, this)) == null ++ && org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(level, targetPos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.DISPENSER, null, source.pos()); ++ if (TntBlock.prime(level, targetPos, null, dispensed, tntPrimedEvents)) { ++ // Paper end - Call BlockDispenseEvent / TNTPrimeEvent level.removeBlock(targetPos, false); } else { this.setSuccess(false); + } + } + } ++ // Paper start - Call BlockDispenseEvent - yield back possibly changed result stack from sulfur or tnt dispesne events ++ if (blockDispenseEventResult[0] != null) { ++ this.setSuccess(false); ++ return blockDispenseEventResult[0]; ++ } ++ // Paper end - Call BlockDispenseEvent - yield back possibly changed result stack from sulfur or tnt dispesne events + + if (this.isSuccess()) { + dispensed.hurtAndBreak(1, level, null, item -> {}); +@@ -48,11 +_,18 @@ + return dispensed; + } + +- private static boolean tryIgniteExplosiveEntities(final ServerLevel level, final BlockPos pos) { ++ private static boolean tryIgniteExplosiveEntities(final ServerLevel level, final BlockPos pos, final java.util.function.BooleanSupplier eventSupplier) { // Paper - call BlockDispenseEvent + List entities = level.getEntitiesOfClass(SulfurCube.class, new AABB(pos), SulfurCube::canExplode); + if (entities.isEmpty()) { + return false; + } ++ ++ // Paper start - call BlockDispenseEvent ++ // If the event was canceled, we return true and stop further event calls. ++ // Vanilla would only consider other flint and steel dispense behaviors if no sulfur cube was in the AABB ++ // that could explode, which was not the case. ++ if (!eventSupplier.getAsBoolean()) return true; ++ // Paper end - call BlockDispenseEvent + + entities.getFirst().primeTime(false); + return true; diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/SulfurCubeBlockDispenseItemBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/SulfurCubeBlockDispenseItemBehavior.java.patch index 1d8957d7b7ce..9ac3d266827f 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/SulfurCubeBlockDispenseItemBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/SulfurCubeBlockDispenseItemBehavior.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/core/dispenser/SulfurCubeBlockDispenseItemBehavior.java +++ b/net/minecraft/core/dispenser/SulfurCubeBlockDispenseItemBehavior.java -@@ -12,12 +_,19 @@ +@@ -12,14 +_,19 @@ @Override protected ItemStack execute(final BlockSource source, final ItemStack dispensed) { @@ -11,14 +11,15 @@ } - public static boolean dispenseBlock(final ServerLevel level, final BlockPos pos, final ItemStack dispensed) { -+ // Paper start - Call BlockDispenseEvent -+ public static boolean dispenseBlock(final ServerLevel level, final BlockPos pos, final ItemStack dispensed, final BlockSource source, final @org.jspecify.annotations.Nullable DispenseItemBehavior currentBehavior) { -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, pos, dispensed, currentBehavior); -+ if (result != null) { // todo - snapshot - setItem should probably override the equipped item + possible event in the for loop -+ return false; -+ } -+ // Paper end - Call BlockDispenseEvent -+ ++ public static boolean dispenseBlock(final ServerLevel level, final BlockPos pos, final ItemStack dispensed, final BlockSource source, final @org.jspecify.annotations.Nullable DispenseItemBehavior currentBehavior) { // Paper - Call BlockDispenseEvent for (SulfurCube entity : level.getEntitiesOfClass(SulfurCube.class, new AABB(pos))) { - if (entity.equipItem(dispensed)) { +- if (entity.equipItem(dispensed)) { ++ // Paper start - Call BlockDispenseEvent ++ if (entity.canEquipItem(dispensed)) { ++ final org.bukkit.craftbukkit.event.CraftEventFactory.PaperBlockDispenseEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEventInspectable(source, pos, dispensed, currentBehavior); ++ if (event.result.preventBehaviour()) return true; // Pretend that we succeeded this so we do not call the normal flow. ++ entity.equipItem(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem())); ++ // Paper end - Call BlockDispenseEvent dispensed.shrink(1); + return true; + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/cubemob/SulfurCube.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/cubemob/SulfurCube.java.patch index 948f86fc26d5..05424e866896 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/cubemob/SulfurCube.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/cubemob/SulfurCube.java.patch @@ -128,6 +128,36 @@ return itWorked ? InteractionResult.SUCCESS_SERVER : InteractionResult.PASS; } else { return Bucketable.bucketMobPickup(player, hand, this).orElse(super.mobInteract(player, hand)); +@@ -490,16 +_,22 @@ + } + } + ++ // Paper start - move out equip item checks ++ public boolean canEquipItem(final ItemStack heldItem) { ++ if (this.isBaby()) return false; ++ ++ final Item swallowedItem = this.getItemBySlot(EquipmentSlot.BODY).getItem(); ++ if (heldItem.is(swallowedItem)) return false; ++ ++ return true; ++ } ++ // Paper end - move out equip item checks ++ + public boolean equipItem(final ItemStack heldItem) { +- if (this.isBaby()) { +- return false; +- } ++ if (!canEquipItem(heldItem)) return false; // Paper - move out equip item checks + + if (this.hasBodyItem()) { +- Item swallowedItem = this.getItemBySlot(EquipmentSlot.BODY).getItem(); +- if (heldItem.is(swallowedItem)) { +- return false; +- } ++ // Paper - move out equip item checks + + Vec3 equipmentSpawnOffset = this.getAttachments().getAverage(EntityAttachment.PASSENGER); + if (this.level() instanceof ServerLevel serverLevel) { @@ -525,7 +_,7 @@ if (this.level() instanceof ServerLevel serverLevel) { for (SulfurCubeArchetype.ContactDamage damage : this.contactDamages) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index fc04dc08b263..cf7f78f5f5fe 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -30,6 +30,8 @@ import net.minecraft.commands.CommandSourceStack; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.dispenser.BlockSource; +import net.minecraft.core.dispenser.DispenseItemBehavior; import net.minecraft.network.Connection; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ServerboundContainerClosePacket; @@ -155,6 +157,7 @@ import org.bukkit.event.block.BellRingEvent; import org.bukkit.event.block.BlockDamageAbortEvent; import org.bukkit.event.block.BlockDamageEvent; +import org.bukkit.event.block.BlockDispenseEvent; import org.bukkit.event.block.BlockDispenseLootEvent; import org.bukkit.event.block.BlockDropItemEvent; import org.bukkit.event.block.BlockExplodeEvent; @@ -2304,25 +2307,62 @@ public static boolean handleBlockPreDispenseEvent(ServerLevel level, BlockPos po return event.callEvent(); } - public static @Nullable ItemStack handleBlockDispenseEvent(net.minecraft.core.dispenser.BlockSource pointer, BlockPos to, ItemStack dispensed, net.minecraft.core.dispenser.DispenseItemBehavior instance) { - org.bukkit.block.Block bukkitBlock = CraftBlock.at(pointer.level(), pointer.pos()); - org.bukkit.inventory.ItemStack craftItem = CraftItemStack.asBukkitMirror(dispensed.isDamageableItem() ? dispensed : dispensed.copyWithCount(1)); + public static class PaperBlockDispenseEvent extends BlockDispenseEvent { - org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), CraftVector.toBukkit(to)); + public enum Result { + CANCELLED, + ITEM_CHANGE_REROUTED, + ITEM_CHANGE_NO_REROUTE, + NO_REROUTED, + ; + + public boolean preventBehaviour() { + return switch (this) { + case CANCELLED, ITEM_CHANGE_REROUTED -> true; + case ITEM_CHANGE_NO_REROUTE, NO_REROUTED -> false; + }; + } + } + + public Result result = Result.NO_REROUTED; + + public PaperBlockDispenseEvent(final @NotNull Block block, final org.bukkit.inventory.@NotNull ItemStack item, final @NotNull Vector velocity) { + super(block, item, velocity); + } + + public PaperBlockDispenseEvent withResult(final Result result) { + this.result = result; + return this; + } + } + + public static @Nullable ItemStack handleBlockDispenseEvent(final BlockSource pointer, final BlockPos to, final ItemStack dispensed, final DispenseItemBehavior instance) { + return switch (handleBlockDispenseEventInspectable(pointer, to, dispensed, instance).result) { + case CANCELLED, ITEM_CHANGE_REROUTED -> dispensed; + case NO_REROUTED, ITEM_CHANGE_NO_REROUTE -> null; + }; + } + + public static PaperBlockDispenseEvent handleBlockDispenseEventInspectable(final BlockSource pointer, final BlockPos to, final ItemStack dispensed, final DispenseItemBehavior instance) { + final org.bukkit.block.Block bukkitBlock = CraftBlock.at(pointer.level(), pointer.pos()); + final org.bukkit.inventory.ItemStack craftItem = CraftItemStack.asBukkitMirror(dispensed.isDamageableItem() ? dispensed : dispensed.copyWithCount(1)); + + final PaperBlockDispenseEvent event = new PaperBlockDispenseEvent(bukkitBlock, craftItem.clone(), CraftVector.toBukkit(to)); if (!event.callEvent()) { - return dispensed; + return event.withResult(PaperBlockDispenseEvent.Result.CANCELLED); } if (!event.getItem().equals(craftItem)) { // Chain to handler for new item - ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); - net.minecraft.core.dispenser.DispenseItemBehavior itemBehavior = net.minecraft.world.level.block.DispenserBlock.getDispenseBehavior(pointer, eventStack); - if (itemBehavior != net.minecraft.core.dispenser.DispenseItemBehavior.NOOP && itemBehavior != instance) { + final ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); + final DispenseItemBehavior itemBehavior = net.minecraft.world.level.block.DispenserBlock.getDispenseBehavior(pointer, eventStack); + if (itemBehavior != DispenseItemBehavior.NOOP && itemBehavior != instance) { itemBehavior.dispense(pointer, eventStack); - return dispensed; + return event.withResult(PaperBlockDispenseEvent.Result.ITEM_CHANGE_REROUTED); } + return event.withResult(PaperBlockDispenseEvent.Result.ITEM_CHANGE_NO_REROUTE); } - return null; + return event.withResult(PaperBlockDispenseEvent.Result.NO_REROUTED); } /**