Co-authored-by: Bjarne Koll <git@lynxplay.dev>
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com>
Co-authored-by: MiniDigger | Martin <admin@minidigger.dev>
Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
Co-authored-by: Noah van der Aa <ndvdaa@gmail.com>
Co-authored-by: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Co-authored-by: Shane Freeder <theboyetronic@gmail.com>
Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
Co-authored-by: Tamion <70228790+notTamion@users.noreply.github.com>
Co-authored-by: Warrior <50800980+Warriorrrr@users.noreply.github.com>
This commit is contained in:
Nassim Jahnke
2025-04-12 17:26:44 +02:00
parent 0767902699
commit f00727c57e
2092 changed files with 50551 additions and 48729 deletions

View File

@@ -1,6 +1,6 @@
--- a/net/minecraft/core/Direction.java
+++ b/net/minecraft/core/Direction.java
@@ -57,6 +_,12 @@
@@ -62,6 +_,12 @@
.sorted(Comparator.comparingInt(direction -> direction.data2d))
.toArray(Direction[]::new);
@@ -13,10 +13,10 @@
private Direction(
final int data3d,
final int oppositeIndex,
@@ -74,6 +_,11 @@
this.axisDirection = axisDirection;
@@ -80,6 +_,11 @@
this.normal = normal;
this.normalVec3 = Vec3.atLowerCornerOf(normal);
this.normalVec3f = new Vector3f(normal.getX(), normal.getY(), normal.getZ());
+ // Paper start - Perf: Inline shift direction fields
+ this.adjX = normal.getX();
+ this.adjY = normal.getY();
@@ -25,7 +25,7 @@
}
public static Direction[] orderedByNearest(Entity entity) {
@@ -247,15 +_,15 @@
@@ -252,15 +_,15 @@
}
public int getStepX() {

View File

@@ -1,6 +1,6 @@
--- a/net/minecraft/core/MappedRegistry.java
+++ b/net/minecraft/core/MappedRegistry.java
@@ -33,17 +_,18 @@
@@ -32,17 +_,18 @@
public class MappedRegistry<T> implements WritableRegistry<T> {
private final ResourceKey<? extends Registry<T>> key;
private final ObjectList<Holder.Reference<T>> byId = new ObjectArrayList<>(256);
@@ -24,7 +24,7 @@
@Override
public Stream<HolderSet.Named<T>> listTags() {
@@ -114,6 +_,7 @@
@@ -113,6 +_,7 @@
this.toId.put(value, size);
this.registrationInfos.put(key, registrationInfo);
this.registryLifecycle = this.registryLifecycle.add(registrationInfo.lifecycle());
@@ -32,7 +32,7 @@
return reference;
}
}
@@ -275,6 +_,7 @@
@@ -274,6 +_,7 @@
return this;
} else {
this.frozen = true;
@@ -40,7 +40,7 @@
this.byValue.forEach((object, reference) -> reference.bindValue((T)object));
List<ResourceLocation> list = this.byKey
.entrySet()
@@ -509,4 +_,13 @@
@@ -508,4 +_,13 @@
Stream<HolderSet.Named<T>> getTags();
}

View File

@@ -1,21 +1,25 @@
--- a/net/minecraft/core/Rotations.java
+++ b/net/minecraft/core/Rotations.java
@@ -34,6 +_,18 @@
this(tag.getFloat(0), tag.getFloat(1), tag.getFloat(2));
}
+ // Paper start - faster alternative constructor
+ private Rotations(float x, float y, float z, Void dummy_var) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
@@ -26,11 +_,22 @@
buffer.writeFloat(value.z);
}
};
+ // Paper start - add internal method for skipping validation for plugins
+ private static boolean SKIP_VALIDATION = false;
+ public static Rotations createWithoutValidityChecks(float x, float y, float z) {
+ return new Rotations(x, y, z, null);
+ SKIP_VALIDATION = true;
+ Rotations rotations = new Rotations(x, y, z);
+ SKIP_VALIDATION = false;
+ return rotations;
+ }
+ // Paper end - faster alternative constructor
+
public ListTag save() {
ListTag listTag = new ListTag();
listTag.add(FloatTag.valueOf(this.x));
+ // Paper end - add internal method for skipping validation for plugins
public Rotations(float x, float y, float z) {
+ if (SKIP_VALIDATION) { // Paper - add internal method for skipping validation for plugins
x = !Float.isInfinite(x) && !Float.isNaN(x) ? x % 360.0F : 0.0F;
y = !Float.isInfinite(y) && !Float.isNaN(y) ? y % 360.0F : 0.0F;
z = !Float.isInfinite(z) && !Float.isNaN(z) ? z % 360.0F : 0.0F;
+ } // Paper - add internal method for skipping validation for plugins
this.x = x;
this.y = y;
this.z = z;

View File

@@ -1,8 +1,8 @@
--- a/net/minecraft/core/Vec3i.java
+++ b/net/minecraft/core/Vec3i.java
@@ -16,9 +_,9 @@
vec3i -> IntStream.of(vec3i.getX(), vec3i.getY(), vec3i.getZ())
);
@@ -22,9 +_,9 @@
ByteBufCodecs.VAR_INT, Vec3i::getX, ByteBufCodecs.VAR_INT, Vec3i::getY, ByteBufCodecs.VAR_INT, Vec3i::getZ, Vec3i::new
);
public static final Vec3i ZERO = new Vec3i(0, 0, 0);
- private int x;
- private int y;
@@ -13,7 +13,7 @@
public static Codec<Vec3i> offsetCodec(int maxOffset) {
return CODEC.validate(
@@ -35,12 +_,12 @@
@@ -41,12 +_,12 @@
}
@Override
@@ -28,7 +28,7 @@
return (this.getY() + this.getZ() * 31) * 31 + this.getX();
}
@@ -53,15 +_,15 @@
@@ -59,15 +_,15 @@
}
}
@@ -47,7 +47,7 @@
return this.z;
}
@@ -235,4 +_,10 @@
@@ -241,4 +_,10 @@
public String toShortString() {
return this.getX() + ", " + this.getY() + ", " + this.getZ();
}

View File

@@ -122,13 +122,14 @@
)
);
addDefaultInteractions(map3);
@@ -202,15 +_,34 @@
@@ -202,15 +_,35 @@
Predicate<BlockState> statePredicate,
SoundEvent fillSound
) {
+ // Paper start - add hitDirection
+ return fillBucket(state, level, pos, player, hand, emptyStack, filledStack, statePredicate, fillSound, null); // Paper - add hitDirection
+ }
+
+ static InteractionResult fillBucket(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack emptyStack, ItemStack filledStack, Predicate<BlockState> statePredicate, SoundEvent fillSound, @javax.annotation.Nullable net.minecraft.core.Direction hitDirection) {
+ // Paper end - add hitDirection
if (!statePredicate.test(state)) {
@@ -137,7 +138,7 @@
if (!level.isClientSide) {
+ // Paper start - fire PlayerBucketFillEvent
+ if (hitDirection != null) {
+ org.bukkit.event.player.PlayerBucketEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent((net.minecraft.server.level.ServerLevel) level, player, pos, pos, hitDirection, emptyStack, filledStack.getItem(), hand);
+ org.bukkit.event.player.PlayerBucketEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent(level, player, pos, pos, hitDirection, emptyStack, filledStack.getItem(), hand);
+ if (event.isCancelled()) {
+ return InteractionResult.PASS;
+ }
@@ -158,20 +159,21 @@
level.playSound(null, pos, fillSound, SoundSource.BLOCKS, 1.0F, 1.0F);
level.gameEvent(null, GameEvent.FLUID_PICKUP, pos);
}
@@ -222,12 +_,32 @@
@@ -222,12 +_,33 @@
static InteractionResult emptyBucket(
Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack filledStackl, BlockState state, SoundEvent emptySound
) {
+ // Paper start - add hitDirection
+ return emptyBucket(level, pos, player, hand, filledStackl, state, emptySound, null);
+ }
+
+ static InteractionResult emptyBucket(Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack filledStackl, BlockState state, SoundEvent emptySound, @javax.annotation.Nullable net.minecraft.core.Direction hitDirection) {
+ // Paper end - add hitDirection
if (!level.isClientSide) {
+ // Paper start - fire PlayerBucketEmptyEvent
+ ItemStack output = new ItemStack(Items.BUCKET);
+ if (hitDirection != null) {
+ org.bukkit.event.player.PlayerBucketEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketEmptyEvent((net.minecraft.server.level.ServerLevel) level, player, pos, pos, hitDirection, filledStackl, hand);
+ org.bukkit.event.player.PlayerBucketEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketEmptyEvent(level, player, pos, pos, hitDirection, filledStackl, hand);
+ if (event.isCancelled()) {
+ return InteractionResult.PASS;
+ }
@@ -193,7 +195,7 @@
level.playSound(null, pos, emptySound, SoundSource.BLOCKS, 1.0F, 1.0F);
level.gameEvent(null, GameEvent.FLUID_PLACE, pos);
}
@@ -236,7 +_,7 @@
@@ -236,23 +_,23 @@
}
private static InteractionResult fillWaterInteraction(
@@ -201,13 +203,8 @@
+ BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack filledStack, final net.minecraft.core.Direction hitDirection // Paper - add hitDirection
) {
return emptyBucket(
level,
@@ -245,20 +_,20 @@
hand,
filledStack,
Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, Integer.valueOf(3)),
- SoundEvents.BUCKET_EMPTY
+ SoundEvents.BUCKET_EMPTY, hitDirection // Paper - add hitDirection
- level, pos, player, hand, filledStack, Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), SoundEvents.BUCKET_EMPTY
+ level, pos, player, hand, filledStack, Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), SoundEvents.BUCKET_EMPTY, hitDirection // Paper - add hitDirection
);
}
@@ -227,10 +224,10 @@
) {
return (InteractionResult)(isUnderWater(level, pos)
? InteractionResult.CONSUME
@@ -269,53 +_,68 @@
@@ -263,53 +_,68 @@
hand,
filledStack,
Blocks.POWDER_SNOW_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, Integer.valueOf(3)),
Blocks.POWDER_SNOW_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3),
- SoundEvents.BUCKET_EMPTY_POWDER_SNOW
+ SoundEvents.BUCKET_EMPTY_POWDER_SNOW, hitDirection // Paper - add hitDirection
));

View File

@@ -1,50 +1,50 @@
--- a/net/minecraft/core/component/DataComponentPatch.java
+++ b/net/minecraft/core/component/DataComponentPatch.java
@@ -86,6 +_,11 @@
buffer.writeVarInt(0);
buffer.writeVarInt(0);
} else {
+ // Paper start - data sanitization for items
+ final io.papermc.paper.util.ItemObfuscationSession itemObfuscationSession = value.map.isEmpty()
+ ? null // Avoid thread local lookup of current session if it won't be needed anyway.
+ : io.papermc.paper.util.ItemObfuscationSession.currentSession();
+ // Paper end - data sanitization for items
int i = 0;
int i1 = 0;
@@ -106,6 +_,11 @@
buffer.writeVarInt(0);
buffer.writeVarInt(0);
} else {
+ // Paper start - data sanitization for items
+ final io.papermc.paper.util.sanitizer.ItemObfuscationSession itemObfuscationSession = value.map.isEmpty()
+ ? null // Avoid thread local lookup of current session if it won't be needed anyway.
+ : io.papermc.paper.util.sanitizer.ItemObfuscationSession.currentSession();
+ // Paper end - data sanitization for items
int i = 0;
int i1 = 0;
@@ -93,7 +_,7 @@
value.map
)) {
if (entry.getValue().isPresent()) {
- i++;
+ if (!io.papermc.paper.util.ItemComponentSanitizer.shouldDrop(itemObfuscationSession, entry.getKey())) i++; // Paper - data sanitization for items
} else {
i1++;
}
@@ -106,6 +_,7 @@
value.map
)) {
Optional<?> optional = entryx.getValue();
+ optional = io.papermc.paper.util.ItemComponentSanitizer.override(itemObfuscationSession, entryx.getKey(), entryx.getValue()); // Paper - data sanitization for items
if (optional.isPresent()) {
DataComponentType<?> dataComponentType = entryx.getKey();
DataComponentType.STREAM_CODEC.encode(buffer, dataComponentType);
@@ -125,7 +_,13 @@
}
@@ -113,7 +_,7 @@
value.map
)) {
if (entry.getValue().isPresent()) {
- i++;
+ if (!io.papermc.paper.util.sanitizer.ItemComponentSanitizer.shouldDrop(itemObfuscationSession, entry.getKey())) i++; // Paper - data sanitization for items
} else {
i1++;
}
@@ -126,6 +_,7 @@
value.map
)) {
Optional<?> optional = entryx.getValue();
+ optional = io.papermc.paper.util.sanitizer.ItemComponentSanitizer.override(itemObfuscationSession, entryx.getKey(), entryx.getValue()); // Paper - data sanitization for items
if (optional.isPresent()) {
DataComponentType<?> dataComponentType = entryx.getKey();
DataComponentType.STREAM_CODEC.encode(buffer, dataComponentType);
@@ -145,7 +_,13 @@
}
private static <T> void encodeComponent(RegistryFriendlyByteBuf buffer, DataComponentType<T> component, Object value) {
- component.streamCodec().encode(buffer, (T)value);
+ // Paper start - codec errors of random anonymous classes are useless
+ try {
+ component.streamCodec().encode(buffer, (T)value);
+ } catch (final Exception e) {
+ throw new RuntimeException("Error encoding component " + component, e);
+ }
+ // Paper end - codec errors of random anonymous classes are useless
}
};
private static final String REMOVED_PREFIX = "!";
@@ -230,6 +_,42 @@
private <T> void encodeComponent(RegistryFriendlyByteBuf buffer, DataComponentType<T> component, Object value) {
- codecGetter.apply(component).encode(buffer, (T)value);
+ // Paper start - codec errors of random anonymous classes are useless
+ try {
+ codecGetter.apply(component).encode(buffer, (T)value);
+ } catch (final Exception e) {
+ throw new RuntimeException("Error encoding component " + component, e);
+ }
+ // Paper end - codec errors of random anonymous classes are useless
}
};
}
@@ -249,6 +_,42 @@
Builder() {
}

View File

@@ -1,24 +1,24 @@
--- a/net/minecraft/core/component/DataComponents.java
+++ b/net/minecraft/core/component/DataComponents.java
@@ -180,10 +_,10 @@
@@ -203,10 +_,10 @@
"map_post_processing", builder -> builder.networkSynchronized(MapPostProcessing.STREAM_CODEC)
);
public static final DataComponentType<ChargedProjectiles> CHARGED_PROJECTILES = register(
- "charged_projectiles", builder -> builder.persistent(ChargedProjectiles.CODEC).networkSynchronized(ChargedProjectiles.STREAM_CODEC).cacheEncoding()
+ "charged_projectiles", builder -> builder.persistent(ChargedProjectiles.CODEC).networkSynchronized(io.papermc.paper.util.OversizedItemComponentSanitizer.CHARGED_PROJECTILES).cacheEncoding() // Paper - sanitize charged projectiles
+ "charged_projectiles", builder -> builder.persistent(ChargedProjectiles.CODEC).networkSynchronized(io.papermc.paper.util.sanitizer.OversizedItemComponentSanitizer.CHARGED_PROJECTILES).cacheEncoding() // Paper - sanitize charged projectiles
);
public static final DataComponentType<BundleContents> BUNDLE_CONTENTS = register(
- "bundle_contents", builder -> builder.persistent(BundleContents.CODEC).networkSynchronized(BundleContents.STREAM_CODEC).cacheEncoding()
+ "bundle_contents", builder -> builder.persistent(BundleContents.CODEC).networkSynchronized(io.papermc.paper.util.OversizedItemComponentSanitizer.BUNDLE_CONTENTS).cacheEncoding() // Paper - sanitize bundle contents
+ "bundle_contents", builder -> builder.persistent(BundleContents.CODEC).networkSynchronized(io.papermc.paper.util.sanitizer.OversizedItemComponentSanitizer.BUNDLE_CONTENTS).cacheEncoding() // Paper - sanitize bundle contents
);
public static final DataComponentType<PotionContents> POTION_CONTENTS = register(
"potion_contents", builder -> builder.persistent(PotionContents.CODEC).networkSynchronized(PotionContents.STREAM_CODEC).cacheEncoding()
@@ -250,7 +_,7 @@
@@ -286,7 +_,7 @@
"pot_decorations", builder -> builder.persistent(PotDecorations.CODEC).networkSynchronized(PotDecorations.STREAM_CODEC).cacheEncoding()
);
public static final DataComponentType<ItemContainerContents> CONTAINER = register(
- "container", builder -> builder.persistent(ItemContainerContents.CODEC).networkSynchronized(ItemContainerContents.STREAM_CODEC).cacheEncoding()
+ "container", builder -> builder.persistent(ItemContainerContents.CODEC).networkSynchronized(io.papermc.paper.util.OversizedItemComponentSanitizer.CONTAINER).cacheEncoding() // Paper - sanitize container contents
+ "container", builder -> builder.persistent(ItemContainerContents.CODEC).networkSynchronized(io.papermc.paper.util.sanitizer.OversizedItemComponentSanitizer.CONTAINER).cacheEncoding() // Paper - sanitize container contents
);
public static final DataComponentType<BlockItemStateProperties> BLOCK_STATE = register(
"block_state", builder -> builder.persistent(BlockItemStateProperties.CODEC).networkSynchronized(BlockItemStateProperties.STREAM_CODEC).cacheEncoding()

View File

@@ -1,30 +1,27 @@
--- a/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
@@ -40,13 +_,39 @@
@@ -40,13 +_,36 @@
d4 = 0.0;
}
+ // CraftBukkit start
+ ItemStack singleItemStack = item.copyWithCount(1); // Paper - shrink at end and single item in event
+ ItemStack singleItemStack = item.copyWithCount(1);
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
+
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d1, d2 + d4, d3));
+ if (!DispenserBlock.eventFired) {
+ serverLevel.getCraftServer().getPluginManager().callEvent(event);
+ }
+ serverLevel.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ // stack.grow(1); // Paper - shrink below
+ return item;
+ }
+
+ boolean shrink = true; // Paper
+ boolean shrink = true;
+ if (!event.getItem().equals(craftItem)) {
+ shrink = false; // Paper - shrink below
+ shrink = false;
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack);
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+ dispenseBehavior.dispense(blockSource, eventStack);
+ return item;

View File

@@ -1,20 +1,11 @@
--- a/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java
@@ -10,23 +_,46 @@
@@ -9,24 +_,37 @@
public class DefaultDispenseItemBehavior implements DispenseItemBehavior {
private static final int DEFAULT_ACCURACY = 6;
+ // CraftBukkit start
+ private Direction direction; // Paper - cache facing direction
+ private boolean dropper;
+
+ public DefaultDispenseItemBehavior(boolean dropper) {
+ this.dropper = dropper;
+ }
+
+ public DefaultDispenseItemBehavior() {}
+ // CraftBukkit end
+
@Override
public final ItemStack dispense(BlockSource blockSource, ItemStack item) {
+ this.direction = blockSource.state().getValue(DispenserBlock.FACING); // Paper - cache facing direction
@@ -32,7 +23,7 @@
ItemStack itemStack = item.split(1);
- spawnItem(blockSource.level(), itemStack, 6, direction, dispensePosition);
+ // CraftBukkit start
+ if (!DefaultDispenseItemBehavior.spawnItem(blockSource.level(), itemStack, 6, this.direction, dispensePosition, blockSource, this.dropper)) {
+ if (!DefaultDispenseItemBehavior.spawnItem(blockSource.level(), itemStack, 6, this.direction, dispensePosition, blockSource)) {
+ item.grow(1);
+ }
+ // CraftBukkit end
@@ -50,37 +41,35 @@
double d = position.x();
double d1 = position.y();
double d2 = position.z();
@@ -43,7 +_,45 @@
@@ -43,7 +_,43 @@
level.random.triangle(0.2, 0.0172275 * speed),
level.random.triangle(facing.getStepZ() * d3, 0.0172275 * speed)
);
+ return itemEntity; // CraftBukkit
+ }
+
+ // CraftBukkit - void -> boolean return, IPosition -> ISourceBlock last argument, dropper
+ public static boolean spawnItem(Level level, ItemStack stack, int speed, Direction facing, Position dispensePosition, BlockSource blockSource, boolean dropper) {
+ // CraftBukkit start - void -> boolean return
+ public static boolean spawnItem(Level level, ItemStack stack, int speed, Direction facing, Position position, BlockSource blockSource) {
+ if (stack.isEmpty()) return true;
+ ItemEntity itemEntity = DefaultDispenseItemBehavior.prepareItem(level, stack, speed, facing, dispensePosition);
+ ItemEntity itemEntity = DefaultDispenseItemBehavior.prepareItem(level, stack, speed, facing, position);
+
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack);
+
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(itemEntity.getDeltaMovement()));
+ if (!DispenserBlock.eventFired) {
+ level.getCraftServer().getPluginManager().callEvent(event);
+ }
+ level.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ return false;
+ }
+
+ itemEntity.setItem(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()));
+ itemEntity.setDeltaMovement(org.bukkit.craftbukkit.util.CraftVector.toNMS(event.getVelocity()));
+ itemEntity.setDeltaMovement(org.bukkit.craftbukkit.util.CraftVector.toVec3(event.getVelocity()));
+
+ if (!dropper && !event.getItem().getType().equals(craftItem.getType())) {
+ if (blockSource.state().is(net.minecraft.world.level.block.Blocks.DISPENSER) && !event.getItem().getType().equals(craftItem.getType())) {
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack);
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior.getClass() != DefaultDispenseItemBehavior.class) {
+ dispenseBehavior.dispense(blockSource, eventStack);
+ } else {

View File

@@ -1,31 +1,28 @@
--- a/net/minecraft/core/dispenser/DispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/DispenseItemBehavior.java
@@ -82,16 +_,48 @@
@@ -83,16 +_,45 @@
Direction direction = blockSource.state().getValue(DispenserBlock.FACING);
EntityType<?> type = ((SpawnEggItem)item.getItem()).getType(blockSource.level().registryAccess(), item);
+ // CraftBukkit start
+ ServerLevel serverLevel = blockSource.level();
+ ItemStack singleItemStack = item.copyWithCount(1); // Paper - shrink below and single item in event
+ ItemStack singleItemStack = item.copyWithCount(1);
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
+
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
+ if (!DispenserBlock.eventFired) {
+ serverLevel.getCraftServer().getPluginManager().callEvent(event);
+ }
+ serverLevel.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ // item.grow(1); // Paper - shrink below
+ return item;
+ }
+
+ boolean shrink = true; // Paper
+ boolean shrink = true;
+ if (!event.getItem().equals(craftItem)) {
+ shrink = false; // Paper - shrink below
+ shrink = false;
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack);
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+ dispenseBehavior.dispense(blockSource, eventStack);
+ return item;
@@ -46,42 +43,40 @@
}
- item.shrink(1);
+ if (shrink) item.shrink(1); // Paper - actually handle here
+ if (shrink) item.shrink(1);
+ // CraftBukkit end
blockSource.level().gameEvent(null, GameEvent.ENTITY_PLACE, blockSource.pos());
return item;
}
@@ -109,12 +_,40 @@
@@ -110,12 +_,38 @@
Direction direction = blockSource.state().getValue(DispenserBlock.FACING);
BlockPos blockPos = blockSource.pos().relative(direction);
ServerLevel serverLevel = blockSource.level();
+ // CraftBukkit start
+ ItemStack singleItemStack = item.copyWithCount(1); // Paper - shrink below and single item in event
+ ItemStack singleItemStack = item.copyWithCount(1);
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
+
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
+ if (!DispenserBlock.eventFired) {
+ serverLevel.getCraftServer().getPluginManager().callEvent(event);
+ }
+ serverLevel.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ // item.grow(1); // Paper - shrink below
+ return item;
+ }
+
+ boolean shrink = true; // Paper
+ boolean shrink = true;
+ if (!event.getItem().equals(craftItem)) {
+ shrink = false; // Paper - shrink below
+ shrink = false;
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack);
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+ dispenseBehavior.dispense(blockSource, eventStack);
+ return item;
+ }
+ }
+ // CraftBukkit end
+
+ final ItemStack newStack = org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getItem()); // Paper - use event itemstack (unwrap is fine here because the stack won't be modified)
Consumer<ArmorStand> consumer = EntityType.appendDefaultStackConfig(
- armorStand1 -> armorStand1.setYRot(direction.toYRot()), serverLevel, item, null
@@ -90,76 +85,37 @@
ArmorStand armorStand = EntityType.ARMOR_STAND.spawn(serverLevel, consumer, blockPos, EntitySpawnReason.DISPENSER, false, false);
if (armorStand != null) {
- item.shrink(1);
+ if (shrink) item.shrink(1); // Paper - actually handle here
+ if (shrink) item.shrink(1); // Paper
}
return item;
@@ -134,7 +_,36 @@
livingEntity -> livingEntity instanceof Saddleable saddleable && !saddleable.isSaddled() && saddleable.isSaddleable()
);
if (!entitiesOfClass.isEmpty()) {
- ((Saddleable)entitiesOfClass.get(0)).equipSaddle(item.split(1), SoundSource.BLOCKS);
+ // CraftBukkit start
+ ItemStack singleItemStack = item.copyWithCount(1); // Paper - shrink below and single item in event
+ ServerLevel world = blockSource.level();
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
+
+ org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), entitiesOfClass.get(0).getBukkitLivingEntity());
+ if (!DispenserBlock.eventFired) {
+ world.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ // item.grow(1); // Paper - shrink below
+ return item;
+ }
+
+ boolean shrink = true; // Paper
+ if (!event.getItem().equals(craftItem)) {
+ shrink = false; // Paper - shrink below
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { // Paper - fix possible StackOverflowError
+ dispenseBehavior.dispense(blockSource, eventStack);
+ return item;
+ }
+ }
+ ((Saddleable) entitiesOfClass.get(0)).equipSaddle(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), SoundSource.BLOCKS); // Paper - track changed items in dispense event
+ // CraftBukkit end
+ if (shrink) item.shrink(1); // Paper - actually handle here
this.setSuccess(true);
return item;
} else {
@@ -156,8 +_,36 @@
@@ -135,8 +_,35 @@
new AABB(blockPos),
abstractChestedHorse1 -> abstractChestedHorse1.isAlive() && !abstractChestedHorse1.hasChest()
)) {
- if (abstractChestedHorse.isTamed() && abstractChestedHorse.getSlot(499).set(item)) {
- item.shrink(1);
+ if (abstractChestedHorse.isTamed()/* && abstractChestedHorse.getSlot(499).set(item)*/) {
+ ItemStack singleCopy = item.copyWithCount(1); // Paper - shrink below
+ // CraftBukkit start
+ ItemStack singleCopy = item.copyWithCount(1);
+ ServerLevel world = blockSource.level();
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleCopy);
+ org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), abstractChestedHorse.getBukkitLivingEntity());
+ if (!DispenserBlock.eventFired) {
+ world.getCraftServer().getPluginManager().callEvent(event);
+ }
+ world.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ // stack.grow(1); // Paper - shrink below (this was actually missing and should be here, added it commented out to be consistent)
+ this.setSuccess(false);
+ return item;
+ }
+
+ boolean shrink = true; // Paper
+ boolean shrink = true;
+ if (!event.getItem().equals(craftItem)) {
+ shrink = false; // Paper - shrink below
+ shrink = false;
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { // Paper - fix possible StackOverflowError
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack);
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+ dispenseBehavior.dispense(blockSource, eventStack);
+ return item;
+ }
@@ -171,30 +127,25 @@
this.setSuccess(true);
return item;
}
@@ -195,8 +_,50 @@
@@ -174,8 +_,45 @@
DispensibleContainerItem dispensibleContainerItem = (DispensibleContainerItem)item.getItem();
BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING));
Level level = blockSource.level();
+ // CraftBukkit start
+ int x = blockPos.getX();
+ int y = blockPos.getY();
+ int z = blockPos.getZ();
+ BlockState iblockdata = level.getBlockState(blockPos);
+ BlockState state = level.getBlockState(blockPos);
+ ItemStack dispensedItem = item; // Paper - track changed item from the dispense event
+ // Paper start - correctly check if the bucket place will succeed
+ /* Taken from SolidBucketItem#emptyContents */
+ boolean willEmptyContentsSolidBucketItem = dispensibleContainerItem instanceof net.minecraft.world.item.SolidBucketItem && level.isInWorldBounds(blockPos) && iblockdata.isAir();
+ boolean willEmptyContentsSolidBucketItem = dispensibleContainerItem instanceof net.minecraft.world.item.SolidBucketItem && level.isInWorldBounds(blockPos) && state.isAir();
+ /* Taken from BucketItem#emptyContents */
+ boolean willEmptyBucketItem = dispensibleContainerItem instanceof final net.minecraft.world.item.BucketItem bucketItem && bucketItem.content instanceof net.minecraft.world.level.material.FlowingFluid && (iblockdata.isAir() || iblockdata.canBeReplaced(bucketItem.content) || (iblockdata.getBlock() instanceof net.minecraft.world.level.block.LiquidBlockContainer liquidBlockContainer && liquidBlockContainer.canPlaceLiquid(null, level, blockPos, iblockdata, bucketItem.content)));
+ boolean willEmptyBucketItem = dispensibleContainerItem instanceof final net.minecraft.world.item.BucketItem bucketItem && bucketItem.content instanceof net.minecraft.world.level.material.FlowingFluid && (state.isAir() || state.canBeReplaced(bucketItem.content) || (state.getBlock() instanceof net.minecraft.world.level.block.LiquidBlockContainer liquidBlockContainer && liquidBlockContainer.canPlaceLiquid(null, level, blockPos, state, bucketItem.content)));
+ if (willEmptyContentsSolidBucketItem || willEmptyBucketItem) {
+ // Paper end - correctly check if the bucket place will succeed
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
+
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(x, y, z));
+ if (!DispenserBlock.eventFired) {
+ level.getCraftServer().getPluginManager().callEvent(event);
+ }
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos));
+ level.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ return item;
@@ -203,7 +154,7 @@
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack);
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+ dispenseBehavior.dispense(blockSource, eventStack);
+ return item;
@@ -223,7 +174,7 @@
return this.consumeWithRemainder(blockSource, item, new ItemStack(Items.BUCKET));
} else {
return this.defaultDispenseItemBehavior.dispense(blockSource, item);
@@ -219,12 +_,37 @@
@@ -198,12 +_,19 @@
BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING));
BlockState blockState = levelAccessor.getBlockState(blockPos);
if (blockState.getBlock() instanceof BucketPickup bucketPickup) {
@@ -234,64 +185,27 @@
} else {
levelAccessor.gameEvent(null, GameEvent.FLUID_PICKUP, blockPos);
Item item1 = itemStack.getItem();
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(levelAccessor, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
+
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos));
+ if (!DispenserBlock.eventFired) {
+ levelAccessor.getMinecraftWorld().getCraftServer().getPluginManager().callEvent(event);
+ // Paper start - Call BlockDispenseEvent
+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos, item, this);
+ if (result != null) {
+ return result;
+ }
+
+ if (event.isCancelled()) {
+ return item;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+ dispenseBehavior.dispense(blockSource, eventStack);
+ return item;
+ }
+ }
+
+ itemStack = bucketPickup.pickupBlock(null, levelAccessor, blockPos, blockState); // From above
+ // CraftBukkit end
+ // Paper end - Call BlockDispenseEvent
+ itemStack = bucketPickup.pickupBlock(null, levelAccessor, blockPos, blockState); // CraftBukkit - from above
return this.consumeWithRemainder(blockSource, item, new ItemStack(item1));
}
} else {
@@ -236,17 +_,44 @@
@Override
protected ItemStack execute(BlockSource blockSource, ItemStack item) {
ServerLevel serverLevel = blockSource.level();
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item); // Paper - ignore stack size on damageable items
+
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
+ if (!DispenserBlock.eventFired) {
+ serverLevel.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ return item;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+ dispenseBehavior.dispense(blockSource, eventStack);
+ return item;
+ }
+ }
+ // CraftBukkit end
@@ -218,15 +_,26 @@
this.setSuccess(true);
Direction direction = blockSource.state().getValue(DispenserBlock.FACING);
BlockPos blockPos = blockSource.pos().relative(direction);
+ // Paper start - Call BlockDispenseEvent
+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos, item, this);
+ if (result != null) {
+ this.setSuccess(false);
+ return result;
+ }
+ // Paper end - Call BlockDispenseEvent
BlockState blockState = serverLevel.getBlockState(blockPos);
if (BaseFireBlock.canBePlacedAt(serverLevel, blockPos, direction)) {
- serverLevel.setBlockAndUpdate(blockPos, BaseFireBlock.getState(serverLevel, blockPos));
@@ -303,42 +217,26 @@
+ }
+ // CraftBukkit end
} else if (CampfireBlock.canLight(blockState) || CandleBlock.canLight(blockState) || CandleCakeBlock.canLight(blockState)) {
serverLevel.setBlockAndUpdate(blockPos, blockState.setValue(BlockStateProperties.LIT, Boolean.valueOf(true)));
serverLevel.setBlockAndUpdate(blockPos, blockState.setValue(BlockStateProperties.LIT, true));
serverLevel.gameEvent(null, GameEvent.BLOCK_CHANGE, blockPos);
- } else if (blockState.getBlock() instanceof TntBlock) {
+ } else if (blockState.getBlock() instanceof TntBlock && org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(serverLevel, blockPos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.DISPENSER, null, blockSource.pos())) { // CraftBukkit - TNTPrimeEvent
TntBlock.explode(serverLevel, blockPos);
serverLevel.removeBlock(blockPos, false);
} else {
@@ -266,11 +_,62 @@
} else if (blockState.getBlock() instanceof TntBlock) {
- if (TntBlock.prime(serverLevel, blockPos)) {
+ if (TntBlock.prime(serverLevel, blockPos, () -> org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(serverLevel, blockPos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.DISPENSER, null, blockSource.pos()))) { // CraftBukkit - TNTPrimeEvent
serverLevel.removeBlock(blockPos, false);
} else {
this.setSuccess(false);
@@ -248,11 +_,46 @@
this.setSuccess(true);
Level level = blockSource.level();
BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING));
+ // CraftBukkit start
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
+
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
+ if (!DispenserBlock.eventFired) {
+ level.getCraftServer().getPluginManager().callEvent(event);
+ // Paper start - Call BlockDispenseEvent
+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos, item, this);
+ if (result != null) {
+ this.setSuccess(false);
+ return result;
+ }
+
+ if (event.isCancelled()) {
+ return item;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+ dispenseBehavior.dispense(blockSource, eventStack);
+ return item;
+ }
+ }
+
+ level.captureTreeGeneration = true;
+ // CraftBukkit end
+ // Paper end - Call BlockDispenseEvent
+ level.captureTreeGeneration = true; // CraftBukkit
if (!BoneMealItem.growCrop(item, level, blockPos) && !BoneMealItem.growWaterPlant(item, level, blockPos, null)) {
this.setSuccess(false);
} else if (!level.isClientSide) {
@@ -346,26 +244,27 @@
}
+ // CraftBukkit start
+ level.captureTreeGeneration = false;
+ if (level.capturedBlockStates.size() > 0) {
+ if (!level.capturedBlockStates.isEmpty()) {
+ org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeType;
+ net.minecraft.world.level.block.SaplingBlock.treeType = null;
+ org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(blockPos, level.getWorld());
+ List<org.bukkit.block.BlockState> blocks = new java.util.ArrayList<>(level.capturedBlockStates.values());
+ List<org.bukkit.block.BlockState> states = new java.util.ArrayList<>(level.capturedBlockStates.values());
+ level.capturedBlockStates.clear();
+ org.bukkit.event.world.StructureGrowEvent structureEvent = null;
+ if (treeType != null) {
+ structureEvent = new org.bukkit.event.world.StructureGrowEvent(location, treeType, false, null, blocks);
+ structureEvent = new org.bukkit.event.world.StructureGrowEvent(location, treeType, false, null, states);
+ org.bukkit.Bukkit.getPluginManager().callEvent(structureEvent);
+ }
+
+ org.bukkit.event.block.BlockFertilizeEvent fertilizeEvent = new org.bukkit.event.block.BlockFertilizeEvent(location.getBlock(), null, blocks);
+ org.bukkit.event.block.BlockFertilizeEvent fertilizeEvent = new org.bukkit.event.block.BlockFertilizeEvent(location.getBlock(), null, states);
+ fertilizeEvent.setCancelled(structureEvent != null && structureEvent.isCancelled());
+ org.bukkit.Bukkit.getPluginManager().callEvent(fertilizeEvent);
+
+ if (!fertilizeEvent.isCancelled()) {
+ for (org.bukkit.block.BlockState blockstate : blocks) {
+ blockstate.update(true);
+ blockSource.level().checkCapturedTreeStateForObserverNotify(blockPos, (org.bukkit.craftbukkit.block.CraftBlockState) blockstate); // Paper - notify observers even if grow failed
+ for (org.bukkit.block.BlockState state : states) {
+ org.bukkit.craftbukkit.block.CraftBlockState craftBlockState = (org.bukkit.craftbukkit.block.CraftBlockState) state;
+ craftBlockState.place(craftBlockState.getFlags());
+ blockSource.level().checkCapturedTreeStateForObserverNotify(blockPos, craftBlockState); // Paper - notify observers even if grow failed
+ }
+ }
+ }
@@ -373,79 +272,61 @@
return item;
}
@@ -280,11 +_,39 @@
protected ItemStack execute(BlockSource blockSource, ItemStack item) {
Level level = blockSource.level();
BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING));
- PrimedTnt primedTnt = new PrimedTnt(level, blockPos.getX() + 0.5, blockPos.getY(), blockPos.getZ() + 0.5, null);
+ // CraftBukkit start
+ ItemStack singleItemStack = item.copyWithCount(1); // Paper - shrink at end and single item in event
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
+
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) blockPos.getX() + 0.5D, (double) blockPos.getY(), (double) blockPos.getZ() + 0.5D));
+ if (!DispenserBlock.eventFired) {
+ level.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ // item.grow(1); // Paper - shrink below
+ return item;
+ }
+
+ boolean shrink = true; // Paper
+ if (!event.getItem().equals(craftItem)) {
+ shrink = false; // Paper - shrink below
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+ dispenseBehavior.dispense(blockSource, eventStack);
+ return item;
+ }
+ }
+
+ PrimedTnt primedTnt = new PrimedTnt(level, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), null);
+ // CraftBukkit end
level.addFreshEntity(primedTnt);
level.playSound(null, primedTnt.getX(), primedTnt.getY(), primedTnt.getZ(), SoundEvents.TNT_PRIMED, SoundSource.BLOCKS, 1.0F, 1.0F);
level.gameEvent(null, GameEvent.ENTITY_PLACE, blockPos);
- item.shrink(1);
+ if (shrink) item.shrink(1); // Paper - actually handle here
return item;
}
});
@@ -296,6 +_,29 @@
Level level = blockSource.level();
Direction direction = blockSource.state().getValue(DispenserBlock.FACING);
BlockPos blockPos = blockSource.pos().relative(direction);
@@ -266,11 +_,36 @@
return item;
} else {
BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING));
- PrimedTnt primedTnt = new PrimedTnt(serverLevel, blockPos.getX() + 0.5, blockPos.getY(), blockPos.getZ() + 0.5, null);
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
+ ItemStack singleItemStack = item.copyWithCount(1); // Paper - shrink at end and single item in event
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
+
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos));
+ if (!DispenserBlock.eventFired) {
+ level.getCraftServer().getPluginManager().callEvent(event);
+ }
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) blockPos.getX() + 0.5D, (double) blockPos.getY(), (double) blockPos.getZ() + 0.5D));
+ serverLevel.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ return item;
+ }
+
+ boolean shrink = true;
+ if (!event.getItem().equals(craftItem)) {
+ shrink = false;
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack);
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+ dispenseBehavior.dispense(blockSource, eventStack);
+ return item;
+ }
+ }
+
+ PrimedTnt primedTnt = new PrimedTnt(serverLevel, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), null);
+ // CraftBukkit end
serverLevel.addFreshEntity(primedTnt);
serverLevel.playSound(null, primedTnt.getX(), primedTnt.getY(), primedTnt.getZ(), SoundEvents.TNT_PRIMED, SoundSource.BLOCKS, 1.0F, 1.0F);
- serverLevel.gameEvent(null, GameEvent.ENTITY_PLACE, blockPos);
- item.shrink(1);
+ serverLevel.gameEvent(null, GameEvent.ENTITY_PLACE, org.bukkit.craftbukkit.util.CraftVector.toBlockPos(event.getVelocity())); // Paper - update game event position
+ if (shrink) item.shrink(1); // Paper
this.setSuccess(true);
return item;
}
@@ -284,6 +_,13 @@
Level level = blockSource.level();
Direction direction = blockSource.state().getValue(DispenserBlock.FACING);
BlockPos blockPos = blockSource.pos().relative(direction);
+ // Paper start - Call BlockDispenseEvent
+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos, item, this);
+ if (result != null) {
+ this.setSuccess(false);
+ return result;
+ }
+ // Paper end - Call BlockDispenseEvent
if (level.isEmptyBlock(blockPos) && WitherSkullBlock.canSpawnMob(level, blockPos, item)) {
level.setBlock(
blockPos,
@@ -313,7 +_,7 @@
@@ -299,7 +_,7 @@
item.shrink(1);
this.setSuccess(true);
} else {
@@ -454,37 +335,21 @@
}
return item;
@@ -326,6 +_,29 @@
@@ -312,6 +_,13 @@
Level level = blockSource.level();
BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING));
CarvedPumpkinBlock carvedPumpkinBlock = (CarvedPumpkinBlock)Blocks.CARVED_PUMPKIN;
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
+
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos));
+ if (!DispenserBlock.eventFired) {
+ level.getCraftServer().getPluginManager().callEvent(event);
+ // Paper start - Call BlockDispenseEvent
+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos, item, this);
+ if (result != null) {
+ this.setSuccess(false);
+ return result;
+ }
+
+ if (event.isCancelled()) {
+ return item;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+ dispenseBehavior.dispense(blockSource, eventStack);
+ return item;
+ }
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockDispenseEvent
if (level.isEmptyBlock(blockPos) && carvedPumpkinBlock.canSpawnGolem(level, blockPos)) {
if (!level.isClientSide) {
level.setBlock(blockPos, carvedPumpkinBlock.defaultBlockState(), 3);
@@ -335,7 +_,7 @@
@@ -321,7 +_,7 @@
item.shrink(1);
this.setSuccess(true);
} else {
@@ -493,51 +358,34 @@
}
return item;
@@ -361,6 +_,29 @@
@@ -347,6 +_,12 @@
ServerLevel serverLevel = blockSource.level();
BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING));
BlockState blockState = serverLevel.getBlockState(blockPos);
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - only single item in event
+
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos));
+ if (!DispenserBlock.eventFired) {
+ serverLevel.getCraftServer().getPluginManager().callEvent(event);
+ // Paper start - Call BlockDispenseEvent
+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos, item, this);
+ if (result != null) {
+ return result;
+ }
+
+ if (event.isCancelled()) {
+ return item;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+ dispenseBehavior.dispense(blockSource, eventStack);
+ return item;
+ }
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockDispenseEvent
if (blockState.is(
BlockTags.BEEHIVES,
blockStateBase -> blockStateBase.hasProperty(BeehiveBlock.HONEY_LEVEL) && blockStateBase.getBlock() instanceof BeehiveBlock
@@ -389,6 +_,13 @@
@@ -375,6 +_,13 @@
this.setSuccess(true);
if (blockState.is(Blocks.RESPAWN_ANCHOR)) {
if (blockState.getValue(RespawnAnchorBlock.CHARGE) != 4) {
+ // Paper start - Call missing BlockDispenseEvent
+ // Paper start - Call BlockDispenseEvent
+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos, item, this);
+ if (result != null) {
+ this.setSuccess(false);
+ return result;
+ }
+ // Paper end - Call missing BlockDispenseEvent
+ // Paper end - Call BlockDispenseEvent
RespawnAnchorBlock.charge(null, level, blockPos, blockState);
item.shrink(1);
} else {
@@ -412,6 +_,29 @@
@@ -398,6 +_,28 @@
this.setSuccess(false);
return item;
} else {
@@ -546,19 +394,18 @@
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item); // Paper - ignore stack size on damageable items
+
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), entitiesOfClass.get(0).getBukkitLivingEntity());
+ if (!DispenserBlock.eventFired) {
+ serverLevel.getCraftServer().getPluginManager().callEvent(event);
+ }
+ serverLevel.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ this.setSuccess(false);
+ return item;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { // Paper - fix possible StackOverflowError
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack);
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+ dispenseBehavior.dispense(blockSource, eventStack);
+ return item;
+ }
@@ -567,30 +414,30 @@
for (Armadillo armadillo : entitiesOfClass) {
if (armadillo.brushOffScute()) {
item.hurtAndBreak(16, serverLevel, null, item1 -> {});
@@ -432,6 +_,13 @@
@@ -418,6 +_,13 @@
BlockState blockState = level.getBlockState(blockPos);
Optional<BlockState> waxed = HoneycombItem.getWaxed(blockState);
if (waxed.isPresent()) {
+ // Paper start - Call missing BlockDispenseEvent
+ // Paper start - Call BlockDispenseEvent
+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos, item, this);
+ if (result != null) {
+ this.setSuccess(false);
+ return result;
+ }
+ // Paper end - Call missing BlockDispenseEvent
+ // Paper end - Call BlockDispenseEvent
level.setBlockAndUpdate(blockPos, waxed.get());
level.levelEvent(3003, blockPos, 0);
item.shrink(1);
@@ -459,6 +_,12 @@
@@ -445,6 +_,12 @@
if (!serverLevel.getBlockState(blockPos1).is(BlockTags.CONVERTABLE_TO_MUD)) {
return this.defaultDispenseItemBehavior.dispense(blockSource, item);
} else {
+ // Paper start - Call missing BlockDispenseEvent
+ // Paper start - Call BlockDispenseEvent
+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(blockSource, blockPos1, item, this);
+ if (result != null) {
+ return result;
+ }
+ // Paper end - Call missing BlockDispenseEvent
+ // Paper end - Call BlockDispenseEvent
if (!serverLevel.isClientSide) {
for (int i = 0; i < 5; i++) {
serverLevel.sendParticles(

View File

@@ -1,6 +1,6 @@
--- a/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
@@ -14,10 +_,16 @@
@@ -14,10 +_,17 @@
@Override
protected ItemStack execute(BlockSource blockSource, ItemStack item) {
@@ -13,12 +13,13 @@
+ // Paper start
+ return dispenseEquipment(blockSource, item, null);
+ }
+
+ public static boolean dispenseEquipment(BlockSource blockSource, ItemStack item, @javax.annotation.Nullable DispenseItemBehavior currentBehavior) {
+ // Paper end
BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING));
List<LivingEntity> entitiesOfClass = blockSource.level()
.getEntitiesOfClass(LivingEntity.class, new AABB(blockPos), entity -> entity.canEquipWithDispenser(item));
@@ -26,13 +_,42 @@
@@ -26,13 +_,39 @@
} else {
LivingEntity livingEntity = entitiesOfClass.getFirst();
EquipmentSlot equipmentSlotForItem = livingEntity.getEquipmentSlotForItem(item);
@@ -31,22 +32,19 @@
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack);
+
+ org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) livingEntity.getBukkitEntity());
+ if (!DispenserBlock.eventFired) {
+ world.getCraftServer().getPluginManager().callEvent(event);
+ }
+ world.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ // stack.grow(1); // Paper - shrink below
+ return false;
+ }
+
+ boolean shrink = true; // Paper
+ boolean shrink = true;
+ if (!event.getItem().equals(craftItem)) {
+ shrink = false; // Paper - shrink below
+ shrink = false;
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseItemBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (dispenseItemBehavior != DispenseItemBehavior.NOOP && (currentBehavior == null || dispenseItemBehavior != currentBehavior)) { // Paper - fix possible StackOverflowError
+ DispenseItemBehavior dispenseItemBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack);
+ if (dispenseItemBehavior != DispenseItemBehavior.NOOP && (currentBehavior == null || dispenseItemBehavior != currentBehavior)) {
+ dispenseItemBehavior.dispense(blockSource, eventStack);
+ return true;
+ }
@@ -55,7 +53,7 @@
+ livingEntity.setItemSlot(equipmentSlotForItem, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()));
+ // CraftBukkit end
if (livingEntity instanceof Mob mob) {
mob.setDropChance(equipmentSlotForItem, 2.0F);
mob.setGuaranteedDrop(equipmentSlotForItem);
mob.setPersistenceRequired();
}

View File

@@ -1,6 +1,6 @@
--- a/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java
@@ -57,12 +_,38 @@
@@ -57,12 +_,35 @@
}
Vec3 vec31 = new Vec3(d, d1 + d3, d2);
@@ -11,22 +11,19 @@
+ org.bukkit.block.Block block2 = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack1);
+
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block2, craftItem.clone(), new org.bukkit.util.Vector(vec31.x, vec31.y, vec31.z));
+ if (!DispenserBlock.eventFired) {
+ serverLevel.getCraftServer().getPluginManager().callEvent(event);
+ }
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block2, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(vec31));
+ serverLevel.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ // stack.grow(1); // Paper - shrink below
+ return item;
+ }
+
+ boolean shrink = true; // Paper
+ boolean shrink = true;
+ if (!event.getItem().equals(craftItem)) {
+ shrink = false; // Paper - shrink below
+ shrink = false;
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseItemBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ DispenseItemBehavior dispenseItemBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack);
+ if (dispenseItemBehavior != DispenseItemBehavior.NOOP && dispenseItemBehavior != this) {
+ dispenseItemBehavior.dispense(blockSource, eventStack);
+ return item;

View File

@@ -1,6 +1,6 @@
--- a/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
+++ b/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
@@ -27,17 +_,39 @@
@@ -27,17 +_,36 @@
ServerLevel serverLevel = blockSource.level();
Direction direction = blockSource.state().getValue(DispenserBlock.FACING);
Position dispensePosition = this.dispenseConfig.positionFunction().getDispensePosition(blockSource, direction);
@@ -15,38 +15,35 @@
- this.dispenseConfig.uncertainty()
- );
- item.shrink(1);
+ ItemStack itemstack1 = item.copyWithCount(1); // Paper - shrink below and single item in event
+ ItemStack singleItemStack = item.copyWithCount(1); // Paper - shrink below and single item in event
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack1);
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
+
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) direction.getStepX(), (double) direction.getStepY(), (double) direction.getStepZ()));
+ if (!DispenserBlock.eventFired) {
+ serverLevel.getCraftServer().getPluginManager().callEvent(event);
+ }
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(direction.getStepX(), direction.getStepY(), direction.getStepZ()));
+ serverLevel.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ // item.grow(1); // Paper - shrink below
+ return item;
+ }
+
+ boolean shrink = true; // Paper
+ boolean shrink = true;
+ if (!event.getItem().equals(craftItem)) {
+ shrink = false; // Paper - shrink below
+ shrink = false;
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(blockSource, eventStack);
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack);
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+ dispenseBehavior.dispense(blockSource, eventStack);
+ return item;
+ }
+ }
+
+ // SPIGOT-7923: Avoid create projectiles with empty item
+ if (!itemstack1.isEmpty()) {
+ Projectile iprojectile = Projectile.spawnProjectileUsingShoot(this.projectileItem.asProjectile(serverLevel, dispensePosition, org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getItem()), direction), serverLevel, itemstack1, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.dispenseConfig.power(), this.dispenseConfig.uncertainty()); // Paper - track changed items in the dispense event; unwrap is safe here because all uses of the stack make their own copies
+ iprojectile.projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource(blockSource.blockEntity());
+ if (!singleItemStack.isEmpty()) {
+ Projectile projectile = Projectile.spawnProjectileUsingShoot(this.projectileItem.asProjectile(serverLevel, dispensePosition, org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getItem()), direction), serverLevel, singleItemStack, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.dispenseConfig.power(), this.dispenseConfig.uncertainty()); // Paper - track changed items in the dispense event; unwrap is safe here because all uses of the stack make their own copies
+ projectile.projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource(blockSource.blockEntity());
+ }
+ if (shrink) item.shrink(1); // Paper - actually handle here
+ if (shrink) item.shrink(1);
+ // CraftBukkit end
return item;
}

View File

@@ -1,26 +1,24 @@
--- a/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java
@@ -20,9 +_,32 @@
@@ -20,9 +_,30 @@
@Override
protected ItemStack execute(BlockSource blockSource, ItemStack item) {
ServerLevel serverLevel = blockSource.level();
+
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item); // Paper - ignore stack size on damageable items
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
+ if (!DispenserBlock.eventFired) {
+ serverLevel.getCraftServer().getPluginManager().callEvent(event);
+ }
+ serverLevel.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ this.setSuccess(false);
+ return item;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack);
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+ dispenseBehavior.dispense(blockSource, eventStack);
+ return item;

View File

@@ -1,17 +1,15 @@
--- a/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
+++ b/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
@@ -22,10 +_,38 @@
@@ -22,10 +_,36 @@
BlockPos blockPos = blockSource.pos().relative(direction);
Direction direction1 = blockSource.level().isEmptyBlock(blockPos.below()) ? direction : Direction.UP;
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(blockSource.level(), blockSource.pos());
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1));
+
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockPos.getX(), blockPos.getY(), blockPos.getZ()));
+ if (!DispenserBlock.eventFired) {
+ blockSource.level().getCraftServer().getPluginManager().callEvent(event);
+ }
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos));
+ blockSource.level().getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ return item;
@@ -20,7 +18,7 @@
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack); // Paper - Fix NPE with equippable and items without behavior
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack);
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+ dispenseBehavior.dispense(blockSource, eventStack);
+ return item;

View File

@@ -1,8 +1,8 @@
--- a/net/minecraft/core/registries/BuiltInRegistries.java
+++ b/net/minecraft/core/registries/BuiltInRegistries.java
@@ -296,6 +_,17 @@
public static final Registry<SlotDisplay.Type<?>> SLOT_DISPLAY = registerSimple(Registries.SLOT_DISPLAY, SlotDisplays::bootstrap);
public static final Registry<RecipeBookCategory> RECIPE_BOOK_CATEGORY = registerSimple(Registries.RECIPE_BOOK_CATEGORY, RecipeBookCategories::bootstrap);
@@ -311,6 +_,17 @@
);
public static final Registry<Consumer<GameTestHelper>> TEST_FUNCTION = registerSimple(Registries.TEST_FUNCTION, BuiltinTestFunctions::bootstrap);
public static final Registry<? extends Registry<?>> REGISTRY = WRITABLE_REGISTRY;
+ // Paper start - add built-in registry conversions
+ public static final io.papermc.paper.registry.data.util.Conversions BUILT_IN_CONVERSIONS = new io.papermc.paper.registry.data.util.Conversions(new net.minecraft.resources.RegistryOps.RegistryInfoLookup() {
@@ -18,7 +18,7 @@
private static <T> Registry<T> registerSimple(ResourceKey<? extends Registry<T>> key, BuiltInRegistries.RegistryBootstrap<T> bootstrap) {
return internalRegister(key, new MappedRegistry<>(key, Lifecycle.stable(), false), bootstrap);
@@ -321,6 +_,7 @@
@@ -336,6 +_,7 @@
ResourceKey<? extends Registry<T>> key, R registry, BuiltInRegistries.RegistryBootstrap<T> bootstrap
) {
Bootstrap.checkBootstrapCalled(() -> "registry " + key.location());
@@ -26,7 +26,7 @@
ResourceLocation resourceLocation = key.location();
LOADERS.put(resourceLocation, () -> bootstrap.run(registry));
WRITABLE_REGISTRY.register((ResourceKey)key, registry, RegistrationInfo.BUILT_IN);
@@ -328,16 +_,34 @@
@@ -343,16 +_,34 @@
}
public static void bootStrap() {
@@ -61,7 +61,7 @@
});
}
@@ -346,6 +_,7 @@
@@ -361,6 +_,7 @@
for (Registry<?> registry : REGISTRY) {
bindBootstrappedTagsToEmpty(registry);