diff --git a/paper-server/patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch new file mode 100644 index 0000000000..146db06871 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch @@ -0,0 +1,376 @@ +--- a/net/minecraft/world/entity/decoration/ArmorStand.java ++++ b/net/minecraft/world/entity/decoration/ArmorStand.java +@@ -86,9 +_,17 @@ + public Rotations rightArmPose = DEFAULT_RIGHT_ARM_POSE; + public Rotations leftLegPose = DEFAULT_LEFT_LEG_POSE; + public Rotations rightLegPose = DEFAULT_RIGHT_LEG_POSE; ++ public boolean canMove = true; // Paper ++ // Paper start - Allow ArmorStands not to tick ++ public boolean canTick = true; ++ public boolean canTickSetByAPI = false; ++ private boolean noTickPoseDirty = false; ++ private boolean noTickEquipmentDirty = false; ++ // Paper end - Allow ArmorStands not to tick + + public ArmorStand(EntityType entityType, Level level) { + super(entityType, level); ++ if (level != null) this.canTick = level.paperConfig().entities.armorStands.tick; // Paper - Allow ArmorStands not to tick + } + + public ArmorStand(Level level, double x, double y, double z) { +@@ -100,6 +_,13 @@ + return createLivingAttributes().add(Attributes.STEP_HEIGHT, 0.0); + } + ++ // CraftBukkit start - SPIGOT-3607, SPIGOT-3637 ++ @Override ++ public float getBukkitYaw() { ++ return this.getYRot(); ++ } ++ // CraftBukkit end ++ + @Override + public void refreshDimensions() { + double x = this.getX(); +@@ -159,14 +_,22 @@ + + @Override + public void setItemSlot(EquipmentSlot slot, ItemStack stack) { ++ // CraftBukkit start ++ this.setItemSlot(slot, stack, false); ++ } ++ ++ @Override ++ public void setItemSlot(net.minecraft.world.entity.EquipmentSlot slot, ItemStack stack, boolean silent) { ++ // CraftBukkit end + this.verifyEquippedItem(stack); + switch (slot.getType()) { + case HAND: +- this.onEquipItem(slot, this.handItems.set(slot.getIndex(), stack), stack); ++ this.onEquipItem(slot, this.handItems.set(slot.getIndex(), stack), stack, silent); // CraftBukkit + break; + case HUMANOID_ARMOR: +- this.onEquipItem(slot, this.armorItems.set(slot.getIndex(), stack), stack); ++ this.onEquipItem(slot, this.armorItems.set(slot.getIndex(), stack), stack, silent); // CraftBukkit + } ++ this.noTickEquipmentDirty = true; // Paper - Allow ArmorStands not to tick; Still update equipment + } + + @Override +@@ -196,6 +_,7 @@ + } + + compound.put("Pose", this.writePose()); ++ if (this.canTickSetByAPI) compound.putBoolean("Paper.CanTickOverride", this.canTick); // Paper - Allow ArmorStands not to tick + } + + @Override +@@ -226,6 +_,12 @@ + this.setNoBasePlate(compound.getBoolean("NoBasePlate")); + this.setMarker(compound.getBoolean("Marker")); + this.noPhysics = !this.hasPhysics(); ++ // Paper start - Allow ArmorStands not to tick ++ if (compound.contains("Paper.CanTickOverride")) { ++ this.canTick = compound.getBoolean("Paper.CanTickOverride"); ++ this.canTickSetByAPI = true; ++ } ++ // Paper end - Allow ArmorStands not to tick + CompoundTag compound2 = compound.getCompound("Pose"); + this.readPose(compound2); + } +@@ -275,7 +_,7 @@ + } + + @Override +- public boolean isPushable() { ++ public boolean isCollidable(boolean ignoreClimbing) { // Paper - Climbing should not bypass cramming gamerule + return false; + } + +@@ -285,6 +_,7 @@ + + @Override + protected void pushEntities() { ++ if (!this.level().paperConfig().entities.armorStands.doCollisionEntityLookups) return; // Paper - Option to prevent armor stands from doing entity lookups + for (Entity entity : this.level().getEntities(this, this.getBoundingBox(), RIDABLE_MINECARTS)) { + if (this.distanceToSqr(entity) <= 0.2) { + entity.push(this); +@@ -357,7 +_,25 @@ + return false; + } else if (itemBySlot.isEmpty() && (this.disabledSlots & 1 << slot.getFilterBit(16)) != 0) { + return false; +- } else if (player.hasInfiniteMaterials() && itemBySlot.isEmpty() && !stack.isEmpty()) { ++ // CraftBukkit start ++ } else { ++ org.bukkit.inventory.ItemStack armorStandItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemBySlot); ++ org.bukkit.inventory.ItemStack playerHeldItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack); ++ ++ org.bukkit.entity.Player player1 = (org.bukkit.entity.Player) player.getBukkitEntity(); ++ org.bukkit.entity.ArmorStand self = (org.bukkit.entity.ArmorStand) this.getBukkitEntity(); ++ ++ org.bukkit.inventory.EquipmentSlot slot1 = org.bukkit.craftbukkit.CraftEquipmentSlot.getSlot(slot); ++ org.bukkit.inventory.EquipmentSlot hand1 = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand); ++ org.bukkit.event.player.PlayerArmorStandManipulateEvent armorStandManipulateEvent = new org.bukkit.event.player.PlayerArmorStandManipulateEvent(player1, self, playerHeldItem, armorStandItem, slot1, hand1); ++ this.level().getCraftServer().getPluginManager().callEvent(armorStandManipulateEvent); ++ ++ if (armorStandManipulateEvent.isCancelled()) { ++ return true; ++ } ++ ++ if (player.hasInfiniteMaterials() && itemBySlot.isEmpty() && !stack.isEmpty()) { ++ // CraftBukkit end + this.setItemSlot(slot, stack.copyWithCount(1)); + return true; + } else if (stack.isEmpty() || stack.getCount() <= 1) { +@@ -370,6 +_,7 @@ + this.setItemSlot(slot, stack.split(1)); + return true; + } ++ } // CraftBukkit + } + + @Override +@@ -379,15 +_,32 @@ + } else if (!level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && damageSource.getEntity() instanceof Mob) { + return false; + } else if (damageSource.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) { +- this.kill(level); ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damageSource, amount)) { ++ return false; ++ } ++ this.kill(level, damageSource); // CraftBukkit ++ // CraftBukkit end + return false; +- } else if (this.isInvulnerableTo(level, damageSource) || this.invisible || this.isMarker()) { ++ } else if (this.isInvulnerableTo(level, damageSource) /*|| this.invisible*/ || this.isMarker()) { // CraftBukkit + return false; + } else if (damageSource.is(DamageTypeTags.IS_EXPLOSION)) { +- this.brokenByAnything(level, damageSource); +- this.kill(level); ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damageSource, amount, true, this.invisible)) { ++ return false; ++ } ++ // CraftBukkit end ++ // Paper start - avoid duplicate event call ++ org.bukkit.event.entity.EntityDeathEvent event = this.brokenByAnything(level, damageSource); ++ if (!event.isCancelled()) this.kill(damageSource, false); // CraftBukkit ++ // Paper end + return false; + } else if (damageSource.is(DamageTypeTags.IGNITES_ARMOR_STANDS)) { ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damageSource, amount, true, this.invisible)) { ++ return false; ++ } ++ // CraftBukkit end + if (this.isOnFire()) { + this.causeDamage(level, damageSource, 0.15F); + } else { +@@ -396,9 +_,19 @@ + + return false; + } else if (damageSource.is(DamageTypeTags.BURNS_ARMOR_STANDS) && this.getHealth() > 0.5F) { ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damageSource, amount, true, this.invisible)) { ++ return false; ++ } ++ // CraftBukkit end + this.causeDamage(level, damageSource, 4.0F); + return false; + } else { ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damageSource, amount, true, this.invisible)) { ++ return false; ++ } ++ // CraftBukkit end + boolean isCanBreakArmorStand = damageSource.is(DamageTypeTags.CAN_BREAK_ARMOR_STAND); + boolean isAlwaysKillsArmorStands = damageSource.is(DamageTypeTags.ALWAYS_KILLS_ARMOR_STANDS); + if (!isCanBreakArmorStand && !isAlwaysKillsArmorStands) { +@@ -408,7 +_,7 @@ + } else if (damageSource.isCreativePlayer()) { + this.playBrokenSound(); + this.showBreakingParticles(); +- this.kill(level); ++ this.kill(level, damageSource); // CraftBukkit + return true; + } else { + long gameTime = level.getGameTime(); +@@ -417,9 +_,9 @@ + this.gameEvent(GameEvent.ENTITY_DAMAGE, damageSource.getEntity()); + this.lastHit = gameTime; + } else { +- this.brokenByPlayer(level, damageSource); ++ org.bukkit.event.entity.EntityDeathEvent event = this.brokenByPlayer(level, damageSource); // Paper + this.showBreakingParticles(); +- this.kill(level); ++ if (!event.isCancelled()) this.kill(damageSource, false); // Paper - we still need to kill to follow vanilla logic (emit the game event etc...) + } + + return true; +@@ -472,28 +_,31 @@ + health -= damageAmount; + if (health <= 0.5F) { + this.brokenByAnything(level, damageSource); +- this.kill(level); ++ // Paper start - avoid duplicate event call ++ org.bukkit.event.entity.EntityDeathEvent event = this.brokenByAnything(level, damageSource); ++ if (!event.isCancelled()) this.kill(damageSource, false); // CraftBukkit ++ // Paper end + } else { + this.setHealth(health); + this.gameEvent(GameEvent.ENTITY_DAMAGE, damageSource.getEntity()); + } + } + +- private void brokenByPlayer(ServerLevel level, DamageSource damageSource) { ++ private org.bukkit.event.entity.EntityDeathEvent brokenByPlayer(ServerLevel level, DamageSource damageSource) { // Paper + ItemStack itemStack = new ItemStack(Items.ARMOR_STAND); + itemStack.set(DataComponents.CUSTOM_NAME, this.getCustomName()); +- Block.popResource(this.level(), this.blockPosition(), itemStack); +- this.brokenByAnything(level, damageSource); ++ this.drops.add(new DefaultDrop(itemStack, stack -> Block.popResource(this.level(), this.blockPosition(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior ++ return this.brokenByAnything(level, damageSource); // Paper + } + +- private void brokenByAnything(ServerLevel level, DamageSource damageSource) { ++ private org.bukkit.event.entity.EntityDeathEvent brokenByAnything(ServerLevel level, DamageSource damageSource) { // Paper + this.playBrokenSound(); +- this.dropAllDeathLoot(level, damageSource); ++ // this.dropAllDeathLoot(level, damageSource); // CraftBukkit - moved down + + for (int i = 0; i < this.handItems.size(); i++) { + ItemStack itemStack = this.handItems.get(i); + if (!itemStack.isEmpty()) { +- Block.popResource(this.level(), this.blockPosition().above(), itemStack); ++ this.drops.add(new DefaultDrop(itemStack, stack -> Block.popResource(this.level(), this.blockPosition().above(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior; mirror so we can destroy it later - though this call site was safe & spawn drops correctly + this.handItems.set(i, ItemStack.EMPTY); + } + } +@@ -501,10 +_,11 @@ + for (int ix = 0; ix < this.armorItems.size(); ix++) { + ItemStack itemStack = this.armorItems.get(ix); + if (!itemStack.isEmpty()) { +- Block.popResource(this.level(), this.blockPosition().above(), itemStack); ++ this.drops.add(new DefaultDrop(itemStack, stack -> Block.popResource(this.level(), this.blockPosition().above(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior; mirror so we can destroy it later - though this call site was safe & spawn drops correctly + this.armorItems.set(ix, ItemStack.EMPTY); + } + } ++ return this.dropAllDeathLoot(level, damageSource); // CraftBukkit - moved from above // Paper + } + + private void playBrokenSound() { +@@ -539,7 +_,28 @@ + + @Override + public void tick() { ++ // Paper start - Allow ArmorStands not to tick ++ if (!this.canTick) { ++ if (this.noTickPoseDirty) { ++ this.noTickPoseDirty = false; ++ this.updatePose(); ++ } ++ ++ if (this.noTickEquipmentDirty) { ++ this.noTickEquipmentDirty = false; ++ this.detectEquipmentUpdatesPublic(); ++ } ++ ++ return; ++ } ++ // Paper end - Allow ArmorStands not to tick + super.tick(); ++ // Paper start - Allow ArmorStands not to tick ++ this.updatePose(); ++ } ++ ++ public void updatePose() { ++ // Paper end - Allow ArmorStands not to tick + Rotations rotations = this.entityData.get(DATA_HEAD_POSE); + if (!this.headPose.equals(rotations)) { + this.setHeadPose(rotations); +@@ -587,9 +_,31 @@ + return this.isSmall(); + } + ++ // CraftBukkit start ++ @Override ++ public boolean shouldDropExperience() { ++ return true; // MC-157395, SPIGOT-5193 even baby (small) armor stands should drop ++ } ++ // CraftBukkit end ++ + @Override + public void kill(ServerLevel level) { +- this.remove(Entity.RemovalReason.KILLED); ++ // CraftBukkit start - pass DamageSource for kill ++ this.kill(level, null); ++ } ++ ++ public void kill(ServerLevel level, @Nullable DamageSource damageSource) { ++ // Paper start - make cancellable ++ this.kill(damageSource, true); ++ } ++ public void kill(@Nullable DamageSource damageSource, boolean callEvent) { ++ if (callEvent) { ++ org.bukkit.event.entity.EntityDeathEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, (damageSource == null ? this.damageSources().genericKill() : damageSource), this.drops); // CraftBukkit - call event ++ if (event.isCancelled()) return; ++ } ++ // Paper end ++ this.remove(Entity.RemovalReason.KILLED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause ++ // CraftBukkit end + this.gameEvent(GameEvent.ENTITY_DIE); + } + +@@ -653,31 +_,37 @@ + public void setHeadPose(Rotations headPose) { + this.headPose = headPose; + this.entityData.set(DATA_HEAD_POSE, headPose); ++ this.noTickPoseDirty = true; // Paper - Allow updates when not ticking + } + + public void setBodyPose(Rotations bodyPose) { + this.bodyPose = bodyPose; + this.entityData.set(DATA_BODY_POSE, bodyPose); ++ this.noTickPoseDirty = true; // Paper - Allow updates when not ticking + } + + public void setLeftArmPose(Rotations leftArmPose) { + this.leftArmPose = leftArmPose; + this.entityData.set(DATA_LEFT_ARM_POSE, leftArmPose); ++ this.noTickPoseDirty = true; // Paper - Allow updates when not ticking + } + + public void setRightArmPose(Rotations rightArmPose) { + this.rightArmPose = rightArmPose; + this.entityData.set(DATA_RIGHT_ARM_POSE, rightArmPose); ++ this.noTickPoseDirty = true; // Paper - Allow updates when not ticking + } + + public void setLeftLegPose(Rotations leftLegPose) { + this.leftLegPose = leftLegPose; + this.entityData.set(DATA_LEFT_LEG_POSE, leftLegPose); ++ this.noTickPoseDirty = true; // Paper - Allow updates when not ticking + } + + public void setRightLegPose(Rotations rightLegPose) { + this.rightLegPose = rightLegPose; + this.entityData.set(DATA_RIGHT_LEG_POSE, rightLegPose); ++ this.noTickPoseDirty = true; // Paper - Allow updates when not ticking + } + + public Rotations getHeadPose() { +@@ -809,4 +_,13 @@ + public boolean canBeSeenByAnyone() { + return !this.isInvisible() && !this.isMarker(); + } ++ ++ // Paper start ++ @Override ++ public void move(net.minecraft.world.entity.MoverType type, Vec3 movement) { ++ if (this.canMove) { ++ super.move(type, movement); ++ } ++ } ++ // Paper end + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/decoration/BlockAttachedEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/decoration/BlockAttachedEntity.java.patch new file mode 100644 index 0000000000..a5583937ae --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/decoration/BlockAttachedEntity.java.patch @@ -0,0 +1,114 @@ +--- a/net/minecraft/world/entity/decoration/BlockAttachedEntity.java ++++ b/net/minecraft/world/entity/decoration/BlockAttachedEntity.java +@@ -20,7 +_,7 @@ + + public abstract class BlockAttachedEntity extends Entity { + private static final Logger LOGGER = LogUtils.getLogger(); +- private int checkInterval; ++ private int checkInterval; { this.checkInterval = this.getId() % this.level().spigotConfig.hangingTickFrequency; } // Paper - Perf: offset item frame ticking + protected BlockPos pos; + + protected BlockAttachedEntity(EntityType entityType, Level level) { +@@ -38,10 +_,29 @@ + public void tick() { + if (this.level() instanceof ServerLevel serverLevel) { + this.checkBelowWorld(); +- if (this.checkInterval++ == 100) { ++ if (this.checkInterval++ == this.level().spigotConfig.hangingTickFrequency) { // Spigot + this.checkInterval = 0; + if (!this.isRemoved() && !this.survives()) { +- this.discard(); ++ // this.discard(); ++ // CraftBukkit start - fire break events ++ net.minecraft.world.level.block.state.BlockState material = this.level().getBlockState(this.blockPosition()); ++ org.bukkit.event.hanging.HangingBreakEvent.RemoveCause cause; ++ ++ if (!material.isAir()) { ++ // TODO: This feels insufficient to catch 100% of suffocation cases ++ cause = org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.OBSTRUCTION; ++ } else { ++ cause = org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.PHYSICS; ++ } ++ ++ org.bukkit.event.hanging.HangingBreakEvent event = new org.bukkit.event.hanging.HangingBreakEvent((org.bukkit.entity.Hanging) this.getBukkitEntity(), cause); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (this.isRemoved() || event.isCancelled()) { ++ return; ++ } ++ // CraftBukkit end ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DROP); // CraftBukkit - add Bukkit remove cause + this.dropItem(serverLevel, null); + } + } +@@ -74,6 +_,21 @@ + return false; + } else { + if (!this.isRemoved()) { ++ // CraftBukkit start - fire break events ++ Entity damager = (!damageSource.isDirect() && damageSource.getEntity() != null) ? damageSource.getEntity() : damageSource.getDirectEntity(); // Paper - fix DamageSource API ++ org.bukkit.event.hanging.HangingBreakEvent event; ++ if (damager != null) { ++ event = new org.bukkit.event.hanging.HangingBreakByEntityEvent((org.bukkit.entity.Hanging) this.getBukkitEntity(), damager.getBukkitEntity(), damageSource.is(net.minecraft.tags.DamageTypeTags.IS_EXPLOSION) ? org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.EXPLOSION : org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.ENTITY); ++ } else { ++ event = new org.bukkit.event.hanging.HangingBreakEvent((org.bukkit.entity.Hanging) this.getBukkitEntity(), damageSource.is(net.minecraft.tags.DamageTypeTags.IS_EXPLOSION) ? org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.EXPLOSION : org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.DEFAULT); ++ } ++ ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (this.isRemoved() || event.isCancelled()) { ++ return true; ++ } ++ // CraftBukkit end + this.kill(level); + this.markHurt(); + this.dropItem(level, damageSource.getEntity()); +@@ -91,18 +_,36 @@ + @Override + public void move(MoverType type, Vec3 movement) { + if (this.level() instanceof ServerLevel serverLevel && !this.isRemoved() && movement.lengthSqr() > 0.0) { +- this.kill(serverLevel); +- this.dropItem(serverLevel, null); +- } +- } +- +- @Override +- public void push(double x, double y, double z) { +- if (this.level() instanceof ServerLevel serverLevel && !this.isRemoved() && x * x + y * y + z * z > 0.0) { +- this.kill(serverLevel); +- this.dropItem(serverLevel, null); +- } +- } ++ // CraftBukkit start - fire break events ++ // TODO - Does this need its own cause? Seems to only be triggered by pistons ++ org.bukkit.event.hanging.HangingBreakEvent event = new org.bukkit.event.hanging.HangingBreakEvent((org.bukkit.entity.Hanging) this.getBukkitEntity(), org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.PHYSICS); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (this.isRemoved() || event.isCancelled()) { ++ return; ++ } ++ // CraftBukkit end ++ this.kill(serverLevel); ++ this.dropItem(serverLevel, null); ++ } ++ } ++ ++ @Override ++ public void push(double x, double y, double z, @Nullable Entity pushingEntity) { // Paper - override correct overload ++ if (false && this.level() instanceof ServerLevel serverLevel && !this.isRemoved() && x * x + y * y + z * z > 0.0) { // CraftBukkit - not needed ++ this.kill(serverLevel); ++ this.dropItem(serverLevel, null); ++ } ++ } ++ ++ // CraftBukkit start - selectively save tile position ++ @Override ++ public void addAdditionalSaveData(CompoundTag nbt, boolean includeAll) { ++ if (includeAll) { ++ this.addAdditionalSaveData(nbt); ++ } ++ } ++ // CraftBukkit end + + @Override + public void addAdditionalSaveData(CompoundTag tag) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/decoration/ItemFrame.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/decoration/ItemFrame.java.patch new file mode 100644 index 0000000000..f6480c2be0 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/decoration/ItemFrame.java.patch @@ -0,0 +1,127 @@ +--- a/net/minecraft/world/entity/decoration/ItemFrame.java ++++ b/net/minecraft/world/entity/decoration/ItemFrame.java +@@ -49,6 +_,7 @@ + private static final float HEIGHT = 0.75F; + public float dropChance = 1.0F; + public boolean fixed; ++ public @Nullable MapId cachedMapId; // Paper - Perf: Cache map ids on item frames + + public ItemFrame(EntityType entityType, Level level) { + super(entityType, level); +@@ -88,6 +_,12 @@ + + @Override + protected AABB calculateBoundingBox(BlockPos pos, Direction direction) { ++ // CraftBukkit start - break out BB calc into own method ++ return ItemFrame.calculateBoundingBoxStatic(pos, direction); ++ } ++ ++ public static AABB calculateBoundingBoxStatic(BlockPos pos, Direction direction) { ++ // CraftBukkit end + float f = 0.46875F; + Vec3 vec3 = Vec3.atCenterOf(pos).relative(direction, -0.46875); + Direction.Axis axis = direction.getAxis(); +@@ -118,9 +_,9 @@ + } + + @Override +- public void push(double x, double y, double z) { ++ public void push(double x, double y, double z, @Nullable Entity pushingEntity) { // Paper - add push source entity param + if (!this.fixed) { +- super.push(x, y, z); ++ super.push(x, y, z, pushingEntity); // Paper - add push source entity param + } + } + +@@ -149,6 +_,18 @@ + if (this.isInvulnerableToBase(damageSource)) { + return false; + } else if (this.shouldDamageDropItem(damageSource)) { ++ // CraftBukkit start - fire EntityDamageEvent ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damageSource, amount, false) || this.isRemoved()) { ++ return true; ++ } ++ // CraftBukkit end ++ // Paper start - Add PlayerItemFrameChangeEvent ++ if (damageSource.getEntity() instanceof Player player) { ++ var event = new io.papermc.paper.event.player.PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), this.getItem().asBukkitCopy(), io.papermc.paper.event.player.PlayerItemFrameChangeEvent.ItemFrameChangeAction.REMOVE); ++ if (!event.callEvent()) return true; // return true here because you aren't cancelling the damage, just the change ++ this.setItem(ItemStack.fromBukkitCopy(event.getItemStack()), false); ++ } ++ // Paper end - Add PlayerItemFrameChangeEvent + this.dropItem(level, damageSource.getEntity(), false); + this.gameEvent(GameEvent.BLOCK_CHANGE, damageSource.getEntity()); + this.playSound(this.getRemoveItemSound(), 1.0F, 1.0F); +@@ -234,6 +_,14 @@ + return this.getEntityData().get(DATA_ITEM); + } + ++ // Paper start - Fix MC-123848 (spawn item frame drops above block) ++ @Nullable ++ @Override ++ public net.minecraft.world.entity.item.ItemEntity spawnAtLocation(ServerLevel serverLevel, ItemStack stack) { ++ return this.spawnAtLocation(serverLevel, stack, this.getDirection() == Direction.DOWN ? -0.6F : 0.0F); ++ } ++ // Paper end ++ + @Nullable + public MapId getFramedMapId(ItemStack stack) { + return stack.get(DataComponents.MAP_ID); +@@ -248,13 +_,19 @@ + } + + public void setItem(ItemStack stack, boolean updateNeighbours) { ++ // CraftBukkit start ++ this.setItem(stack, updateNeighbours, true); ++ } ++ ++ public void setItem(ItemStack stack, boolean updateNeighbours, boolean playSound) { ++ // CraftBukkit end + if (!stack.isEmpty()) { + stack = stack.copyWithCount(1); + } + + this.onItemChanged(stack); + this.getEntityData().set(DATA_ITEM, stack); +- if (!stack.isEmpty()) { ++ if (!stack.isEmpty() && updateNeighbours && playSound) { // CraftBukkit // Paper - only play sound when update flag is set + this.playSound(this.getAddItemSound(), 1.0F, 1.0F); + } + +@@ -280,6 +_,7 @@ + } + + private void onItemChanged(ItemStack item) { ++ this.cachedMapId = item.getComponents().get(net.minecraft.core.component.DataComponents.MAP_ID); // Paper - Perf: Cache map ids on item frames + if (!item.isEmpty() && item.getFrame() != this) { + item.setEntityRepresentation(this); + } +@@ -359,7 +_,13 @@ + if (savedData != null && savedData.isTrackedCountOverLimit(256)) { + return InteractionResult.FAIL; + } else { +- this.setItem(itemInHand); ++ // Paper start - Add PlayerItemFrameChangeEvent ++ io.papermc.paper.event.player.PlayerItemFrameChangeEvent event = new io.papermc.paper.event.player.PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), itemInHand.asBukkitCopy(), io.papermc.paper.event.player.PlayerItemFrameChangeEvent.ItemFrameChangeAction.PLACE); ++ if (!event.callEvent()) { ++ return InteractionResult.FAIL; ++ } ++ this.setItem(ItemStack.fromBukkitCopy(event.getItemStack())); ++ // Paper end - Add PlayerItemFrameChangeEvent + this.gameEvent(GameEvent.BLOCK_CHANGE, player); + itemInHand.consume(1, player); + return InteractionResult.SUCCESS; +@@ -368,6 +_,13 @@ + return InteractionResult.PASS; + } + } else { ++ // Paper start - Add PlayerItemFrameChangeEvent ++ io.papermc.paper.event.player.PlayerItemFrameChangeEvent event = new io.papermc.paper.event.player.PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), this.getItem().asBukkitCopy(), io.papermc.paper.event.player.PlayerItemFrameChangeEvent.ItemFrameChangeAction.ROTATE); ++ if (!event.callEvent()) { ++ return InteractionResult.FAIL; ++ } ++ setItem(ItemStack.fromBukkitCopy(event.getItemStack()), false, false); ++ // Paper end - Add PlayerItemFrameChangeEvent + this.playSound(this.getRotateItemSound(), 1.0F, 1.0F); + this.setRotation(this.getRotation() + 1); + this.gameEvent(GameEvent.BLOCK_CHANGE, player); diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch similarity index 59% rename from paper-server/patches/unapplied/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch index c569c75fde..56d3dea16c 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch @@ -1,35 +1,13 @@ --- a/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java +++ b/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java -@@ -8,9 +8,11 @@ - import net.minecraft.network.protocol.Packet; - import net.minecraft.network.protocol.game.ClientGamePacketListener; - import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; -+import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket; - import net.minecraft.network.syncher.SynchedEntityData; - import net.minecraft.server.level.ServerEntity; - import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; - import net.minecraft.sounds.SoundEvents; - import net.minecraft.tags.BlockTags; - import net.minecraft.world.InteractionHand; -@@ -26,6 +28,9 @@ - import net.minecraft.world.level.gameevent.GameEvent; - import net.minecraft.world.phys.AABB; - import net.minecraft.world.phys.Vec3; -+import org.bukkit.craftbukkit.event.CraftEventFactory; -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public class LeashFenceKnotEntity extends BlockAttachedEntity { - -@@ -85,6 +90,15 @@ - Leashable leashable = (Leashable) iterator.next(); +@@ -81,6 +_,15 @@ + for (Leashable leashable : list) { if (leashable.getLeashHolder() == player) { + // CraftBukkit start + if (leashable instanceof Entity leashed) { -+ if (CraftEventFactory.callPlayerLeashEntityEvent(leashed, this, player, hand).isCancelled()) { -+ ((ServerPlayer) player).connection.send(new ClientboundSetEntityLinkPacket(leashed, leashable.getLeashHolder())); ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerLeashEntityEvent(leashed, this, player, hand).isCancelled()) { ++ ((net.minecraft.server.level.ServerPlayer) player).connection.send(new net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket(leashed, leashable.getLeashHolder())); + flag = true; // Also set true when the event is cancelled otherwise it tries to unleash the entities + continue; + } @@ -38,9 +16,9 @@ leashable.setLeashedTo(this, true); flag = true; } -@@ -93,18 +107,43 @@ - boolean flag1 = false; +@@ -88,14 +_,39 @@ + boolean flag1 = false; if (!flag) { - this.discard(); - if (player.getAbilities().instabuild) { @@ -49,18 +27,14 @@ + boolean die = true; + // CraftBukkit end + if (true || player.getAbilities().instabuild) { // CraftBukkit - Process for non-creative as well - Iterator iterator1 = list.iterator(); - - while (iterator1.hasNext()) { - Leashable leashable1 = (Leashable) iterator1.next(); - + for (Leashable leashable1 : list) { if (leashable1.isLeashed() && leashable1.getLeashHolder() == this) { - leashable1.removeLeash(); + // CraftBukkit start + boolean dropLeash = !player.hasInfiniteMaterials(); + if (leashable1 instanceof Entity leashed) { + // Paper start - Expand EntityUnleashEvent -+ org.bukkit.event.player.PlayerUnleashEntityEvent event = CraftEventFactory.callPlayerUnleashEntityEvent(leashed, player, hand, dropLeash); ++ org.bukkit.event.player.PlayerUnleashEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerUnleashEntityEvent(leashed, player, hand, dropLeash); + dropLeash = event.isDropLeash(); + if (event.isCancelled()) { + // Paper end - Expand EntityUnleashEvent @@ -79,7 +53,7 @@ } + // CraftBukkit start + if (die) { -+ this.discard(EntityRemoveEvent.Cause.DROP); // CraftBukkit - add Bukkit remove cause ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DROP); // CraftBukkit - add Bukkit remove cause + } + // CraftBukkit end } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/decoration/Painting.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/decoration/Painting.java.patch new file mode 100644 index 0000000000..97a17e6cd7 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/decoration/Painting.java.patch @@ -0,0 +1,41 @@ +--- a/net/minecraft/world/entity/decoration/Painting.java ++++ b/net/minecraft/world/entity/decoration/Painting.java +@@ -129,21 +_,31 @@ + + @Override + protected AABB calculateBoundingBox(BlockPos pos, Direction direction) { ++ // CraftBukkit start ++ PaintingVariant variant = (PaintingVariant) this.getVariant().value(); ++ return Painting.calculateBoundingBoxStatic(pos, direction, variant.width(), variant.height()); ++ } ++ ++ public static AABB calculateBoundingBoxStatic(BlockPos pos, Direction direction, int width, int height) { ++ // CraftBukkit end + float f = 0.46875F; + Vec3 vec3 = Vec3.atCenterOf(pos).relative(direction, -0.46875); +- PaintingVariant paintingVariant = this.getVariant().value(); +- double d = this.offsetForPaintingSize(paintingVariant.width()); +- double d1 = this.offsetForPaintingSize(paintingVariant.height()); ++ // CraftBukkit start ++ double d = Painting.offsetForPaintingSize(width); ++ double d1 = Painting.offsetForPaintingSize(height); ++ // CraftBukkit end + Direction counterClockWise = direction.getCounterClockWise(); + Vec3 vec31 = vec3.relative(counterClockWise, d).relative(Direction.UP, d1); + Direction.Axis axis = direction.getAxis(); +- double d2 = axis == Direction.Axis.X ? 0.0625 : paintingVariant.width(); +- double d3 = paintingVariant.height(); +- double d4 = axis == Direction.Axis.Z ? 0.0625 : paintingVariant.width(); ++ // CraftBukkit start ++ double d2 = axis == Direction.Axis.X ? 0.0625 : width; ++ double d3 = height; ++ double d4 = axis == Direction.Axis.Z ? 0.0625 : width; ++ // CraftBukkit end + return AABB.ofSize(vec31, d2, d3, d4); + } + +- private double offsetForPaintingSize(int size) { ++ private static double offsetForPaintingSize(int size) { // CraftBukkit - static + return size % 2 == 0 ? 0.5 : 0.0; + } + diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/decoration/ArmorStand.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/decoration/ArmorStand.java.patch deleted file mode 100644 index edb69ea66e..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/decoration/ArmorStand.java.patch +++ /dev/null @@ -1,513 +0,0 @@ ---- a/net/minecraft/world/entity/decoration/ArmorStand.java -+++ b/net/minecraft/world/entity/decoration/ArmorStand.java -@@ -25,7 +25,6 @@ - import net.minecraft.world.entity.Entity; - import net.minecraft.world.entity.EntityDimensions; - import net.minecraft.world.entity.EntityType; --import net.minecraft.world.entity.EquipmentSlot; - import net.minecraft.world.entity.HumanoidArm; - import net.minecraft.world.entity.LightningBolt; - import net.minecraft.world.entity.LivingEntity; -@@ -33,7 +32,6 @@ - import net.minecraft.world.entity.Pose; - import net.minecraft.world.entity.ai.attributes.AttributeSupplier; - import net.minecraft.world.entity.ai.attributes.Attributes; --import net.minecraft.world.entity.player.Player; - import net.minecraft.world.entity.vehicle.AbstractMinecart; - import net.minecraft.world.item.ItemStack; - import net.minecraft.world.item.Items; -@@ -47,6 +45,14 @@ - import net.minecraft.world.level.material.PushReaction; - import net.minecraft.world.phys.AABB; - import net.minecraft.world.phys.Vec3; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityRemoveEvent; -+import org.bukkit.inventory.EquipmentSlot; -+import org.bukkit.craftbukkit.CraftEquipmentSlot; -+import org.bukkit.craftbukkit.inventory.CraftItemStack; -+import org.bukkit.entity.Player; -+import org.bukkit.event.player.PlayerArmorStandManipulateEvent; -+// CraftBukkit end - - public class ArmorStand extends LivingEntity { - -@@ -101,9 +107,17 @@ - public Rotations rightArmPose; - public Rotations leftLegPose; - public Rotations rightLegPose; -+ public boolean canMove = true; // Paper -+ // Paper start - Allow ArmorStands not to tick -+ public boolean canTick = true; -+ public boolean canTickSetByAPI = false; -+ private boolean noTickPoseDirty = false; -+ private boolean noTickEquipmentDirty = false; -+ // Paper end - Allow ArmorStands not to tick - - public ArmorStand(EntityType type, Level world) { - super(type, world); -+ if (world != null) this.canTick = world.paperConfig().entities.armorStands.tick; // Paper - Allow ArmorStands not to tick - this.handItems = NonNullList.withSize(2, ItemStack.EMPTY); - this.armorItems = NonNullList.withSize(4, ItemStack.EMPTY); - this.headPose = ArmorStand.DEFAULT_HEAD_POSE; -@@ -123,7 +137,14 @@ - return createLivingAttributes().add(Attributes.STEP_HEIGHT, 0.0D); - } - -+ // CraftBukkit start - SPIGOT-3607, SPIGOT-3637 - @Override -+ public float getBukkitYaw() { -+ return this.getYRot(); -+ } -+ // CraftBukkit end -+ -+ @Override - public void refreshDimensions() { - double d0 = this.getX(); - double d1 = this.getY(); -@@ -165,7 +186,7 @@ - } - - @Override -- public ItemStack getItemBySlot(EquipmentSlot slot) { -+ public ItemStack getItemBySlot(net.minecraft.world.entity.EquipmentSlot slot) { - switch (slot.getType()) { - case HAND: - return (ItemStack) this.handItems.get(slot.getIndex()); -@@ -177,21 +198,29 @@ - } - - @Override -- public boolean canUseSlot(EquipmentSlot slot) { -- return slot != EquipmentSlot.BODY && !this.isDisabled(slot); -+ public boolean canUseSlot(net.minecraft.world.entity.EquipmentSlot slot) { -+ return slot != net.minecraft.world.entity.EquipmentSlot.BODY && !this.isDisabled(slot); -+ } -+ -+ @Override -+ public void setItemSlot(net.minecraft.world.entity.EquipmentSlot slot, ItemStack stack) { -+ // CraftBukkit start -+ this.setItemSlot(slot, stack, false); - } - - @Override -- public void setItemSlot(EquipmentSlot slot, ItemStack stack) { -- this.verifyEquippedItem(stack); -- switch (slot.getType()) { -+ public void setItemSlot(net.minecraft.world.entity.EquipmentSlot enumitemslot, ItemStack itemstack, boolean silent) { -+ // CraftBukkit end -+ this.verifyEquippedItem(itemstack); -+ switch (enumitemslot.getType()) { - case HAND: -- this.onEquipItem(slot, (ItemStack) this.handItems.set(slot.getIndex(), stack), stack); -+ this.onEquipItem(enumitemslot, (ItemStack) this.handItems.set(enumitemslot.getIndex(), itemstack), itemstack, silent); // CraftBukkit - break; - case HUMANOID_ARMOR: -- this.onEquipItem(slot, (ItemStack) this.armorItems.set(slot.getIndex(), stack), stack); -+ this.onEquipItem(enumitemslot, (ItemStack) this.armorItems.set(enumitemslot.getIndex(), itemstack), itemstack, silent); // CraftBukkit - } - -+ this.noTickEquipmentDirty = true; // Paper - Allow ArmorStands not to tick; Still update equipment - } - - @Override -@@ -227,6 +256,7 @@ - } - - nbt.put("Pose", this.writePose()); -+ if (this.canTickSetByAPI) nbt.putBoolean("Paper.CanTickOverride", this.canTick); // Paper - Allow ArmorStands not to tick - } - - @Override -@@ -261,6 +291,12 @@ - this.setNoBasePlate(nbt.getBoolean("NoBasePlate")); - this.setMarker(nbt.getBoolean("Marker")); - this.noPhysics = !this.hasPhysics(); -+ // Paper start - Allow ArmorStands not to tick -+ if (nbt.contains("Paper.CanTickOverride")) { -+ this.canTick = nbt.getBoolean("Paper.CanTickOverride"); -+ this.canTickSetByAPI = true; -+ } -+ // Paper end - Allow ArmorStands not to tick - CompoundTag nbttagcompound2 = nbt.getCompound("Pose"); - - this.readPose(nbttagcompound2); -@@ -318,7 +354,7 @@ - } - - @Override -- public boolean isPushable() { -+ public boolean isCollidable(boolean ignoreClimbing) { // Paper - Climbing should not bypass cramming gamerule - return false; - } - -@@ -327,6 +363,7 @@ - - @Override - protected void pushEntities() { -+ if (!this.level().paperConfig().entities.armorStands.doCollisionEntityLookups) return; // Paper - Option to prevent armor stands from doing entity lookups - List list = this.level().getEntities((Entity) this, this.getBoundingBox(), ArmorStand.RIDABLE_MINECARTS); - Iterator iterator = list.iterator(); - -@@ -341,7 +378,7 @@ - } - - @Override -- public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { -+ public InteractionResult interactAt(net.minecraft.world.entity.player.Player player, Vec3 hitPos, InteractionHand hand) { - ItemStack itemstack = player.getItemInHand(hand); - - if (!this.isMarker() && !itemstack.is(Items.NAME_TAG)) { -@@ -350,11 +387,11 @@ - } else if (player.level().isClientSide) { - return InteractionResult.SUCCESS_SERVER; - } else { -- EquipmentSlot enumitemslot = this.getEquipmentSlotForItem(itemstack); -+ net.minecraft.world.entity.EquipmentSlot enumitemslot = this.getEquipmentSlotForItem(itemstack); - - if (itemstack.isEmpty()) { -- EquipmentSlot enumitemslot1 = this.getClickedSlot(hitPos); -- EquipmentSlot enumitemslot2 = this.isDisabled(enumitemslot1) ? enumitemslot : enumitemslot1; -+ net.minecraft.world.entity.EquipmentSlot enumitemslot1 = this.getClickedSlot(hitPos); -+ net.minecraft.world.entity.EquipmentSlot enumitemslot2 = this.isDisabled(enumitemslot1) ? enumitemslot : enumitemslot1; - - if (this.hasItemInSlot(enumitemslot2) && this.swapItem(player, enumitemslot2, itemstack, hand)) { - return InteractionResult.SUCCESS_SERVER; -@@ -364,7 +401,7 @@ - return InteractionResult.FAIL; - } - -- if (enumitemslot.getType() == EquipmentSlot.Type.HAND && !this.showArms()) { -+ if (enumitemslot.getType() == net.minecraft.world.entity.EquipmentSlot.Type.HAND && !this.showArms()) { - return InteractionResult.FAIL; - } - -@@ -380,39 +417,57 @@ - } - } - -- private EquipmentSlot getClickedSlot(Vec3 hitPos) { -- EquipmentSlot enumitemslot = EquipmentSlot.MAINHAND; -+ private net.minecraft.world.entity.EquipmentSlot getClickedSlot(Vec3 hitPos) { -+ net.minecraft.world.entity.EquipmentSlot enumitemslot = net.minecraft.world.entity.EquipmentSlot.MAINHAND; - boolean flag = this.isSmall(); - double d0 = hitPos.y / (double) (this.getScale() * this.getAgeScale()); -- EquipmentSlot enumitemslot1 = EquipmentSlot.FEET; -+ net.minecraft.world.entity.EquipmentSlot enumitemslot1 = net.minecraft.world.entity.EquipmentSlot.FEET; - - if (d0 >= 0.1D && d0 < 0.1D + (flag ? 0.8D : 0.45D) && this.hasItemInSlot(enumitemslot1)) { -- enumitemslot = EquipmentSlot.FEET; -- } else if (d0 >= 0.9D + (flag ? 0.3D : 0.0D) && d0 < 0.9D + (flag ? 1.0D : 0.7D) && this.hasItemInSlot(EquipmentSlot.CHEST)) { -- enumitemslot = EquipmentSlot.CHEST; -- } else if (d0 >= 0.4D && d0 < 0.4D + (flag ? 1.0D : 0.8D) && this.hasItemInSlot(EquipmentSlot.LEGS)) { -- enumitemslot = EquipmentSlot.LEGS; -- } else if (d0 >= 1.6D && this.hasItemInSlot(EquipmentSlot.HEAD)) { -- enumitemslot = EquipmentSlot.HEAD; -- } else if (!this.hasItemInSlot(EquipmentSlot.MAINHAND) && this.hasItemInSlot(EquipmentSlot.OFFHAND)) { -- enumitemslot = EquipmentSlot.OFFHAND; -+ enumitemslot = net.minecraft.world.entity.EquipmentSlot.FEET; -+ } else if (d0 >= 0.9D + (flag ? 0.3D : 0.0D) && d0 < 0.9D + (flag ? 1.0D : 0.7D) && this.hasItemInSlot(net.minecraft.world.entity.EquipmentSlot.CHEST)) { -+ enumitemslot = net.minecraft.world.entity.EquipmentSlot.CHEST; -+ } else if (d0 >= 0.4D && d0 < 0.4D + (flag ? 1.0D : 0.8D) && this.hasItemInSlot(net.minecraft.world.entity.EquipmentSlot.LEGS)) { -+ enumitemslot = net.minecraft.world.entity.EquipmentSlot.LEGS; -+ } else if (d0 >= 1.6D && this.hasItemInSlot(net.minecraft.world.entity.EquipmentSlot.HEAD)) { -+ enumitemslot = net.minecraft.world.entity.EquipmentSlot.HEAD; -+ } else if (!this.hasItemInSlot(net.minecraft.world.entity.EquipmentSlot.MAINHAND) && this.hasItemInSlot(net.minecraft.world.entity.EquipmentSlot.OFFHAND)) { -+ enumitemslot = net.minecraft.world.entity.EquipmentSlot.OFFHAND; - } - - return enumitemslot; - } - -- public boolean isDisabled(EquipmentSlot slot) { -- return (this.disabledSlots & 1 << slot.getFilterBit(0)) != 0 || slot.getType() == EquipmentSlot.Type.HAND && !this.showArms(); -+ public boolean isDisabled(net.minecraft.world.entity.EquipmentSlot slot) { -+ return (this.disabledSlots & 1 << slot.getFilterBit(0)) != 0 || slot.getType() == net.minecraft.world.entity.EquipmentSlot.Type.HAND && !this.showArms(); - } - -- private boolean swapItem(Player player, EquipmentSlot slot, ItemStack stack, InteractionHand hand) { -+ private boolean swapItem(net.minecraft.world.entity.player.Player player, net.minecraft.world.entity.EquipmentSlot slot, ItemStack stack, InteractionHand hand) { - ItemStack itemstack1 = this.getItemBySlot(slot); - - if (!itemstack1.isEmpty() && (this.disabledSlots & 1 << slot.getFilterBit(8)) != 0) { - return false; - } else if (itemstack1.isEmpty() && (this.disabledSlots & 1 << slot.getFilterBit(16)) != 0) { - return false; -- } else if (player.hasInfiniteMaterials() && itemstack1.isEmpty() && !stack.isEmpty()) { -+ // CraftBukkit start -+ } else { -+ org.bukkit.inventory.ItemStack armorStandItem = CraftItemStack.asCraftMirror(itemstack1); -+ org.bukkit.inventory.ItemStack playerHeldItem = CraftItemStack.asCraftMirror(stack); -+ -+ Player player1 = (Player) player.getBukkitEntity(); -+ org.bukkit.entity.ArmorStand self = (org.bukkit.entity.ArmorStand) this.getBukkitEntity(); -+ -+ EquipmentSlot slot1 = CraftEquipmentSlot.getSlot(slot); -+ EquipmentSlot hand1 = CraftEquipmentSlot.getHand(hand); -+ PlayerArmorStandManipulateEvent armorStandManipulateEvent = new PlayerArmorStandManipulateEvent(player1, self, playerHeldItem, armorStandItem, slot1, hand1); -+ this.level().getCraftServer().getPluginManager().callEvent(armorStandManipulateEvent); -+ -+ if (armorStandManipulateEvent.isCancelled()) { -+ return true; -+ } -+ -+ if (player.hasInfiniteMaterials() && itemstack1.isEmpty() && !stack.isEmpty()) { -+ // CraftBukkit end - this.setItemSlot(slot, stack.copyWithCount(1)); - return true; - } else if (!stack.isEmpty() && stack.getCount() > 1) { -@@ -427,6 +482,7 @@ - player.setItemInHand(hand, itemstack1); - return true; - } -+ } // CraftBukkit - } - - @Override -@@ -436,12 +492,24 @@ - } else if (!world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && source.getEntity() instanceof Mob) { - return false; - } else if (source.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) { -- this.kill(world); -+ // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, amount)) { -+ return false; -+ } -+ this.kill(world, source); // CraftBukkit -+ // CraftBukkit end - return false; -- } else if (!this.isInvulnerableTo(world, source) && !this.invisible && !this.isMarker()) { -+ } else if (!this.isInvulnerableTo(world, source) && (true || !this.invisible) && !this.isMarker()) { // CraftBukkit -+ // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, amount, true, this.invisible)) { -+ return false; -+ } -+ // CraftBukkit end - if (source.is(DamageTypeTags.IS_EXPLOSION)) { -- this.brokenByAnything(world, source); -- this.kill(world); -+ // Paper start - avoid duplicate event call -+ org.bukkit.event.entity.EntityDeathEvent event = this.brokenByAnything(world, source); -+ if (!event.isCancelled()) this.kill(source, false); // CraftBukkit -+ // Paper end - return false; - } else if (source.is(DamageTypeTags.IGNITES_ARMOR_STANDS)) { - if (this.isOnFire()) { -@@ -463,8 +531,8 @@ - } else { - Entity entity = source.getEntity(); - -- if (entity instanceof Player) { -- Player entityhuman = (Player) entity; -+ if (entity instanceof net.minecraft.world.entity.player.Player) { -+ net.minecraft.world.entity.player.Player entityhuman = (net.minecraft.world.entity.player.Player) entity; - - if (!entityhuman.getAbilities().mayBuild) { - return false; -@@ -474,7 +542,7 @@ - if (source.isCreativePlayer()) { - this.playBrokenSound(); - this.showBreakingParticles(); -- this.kill(world); -+ this.kill(world, source); // CraftBukkit - return true; - } else { - long i = world.getGameTime(); -@@ -484,9 +552,9 @@ - this.gameEvent(GameEvent.ENTITY_DAMAGE, source.getEntity()); - this.lastHit = i; - } else { -- this.brokenByPlayer(world, source); -+ org.bukkit.event.entity.EntityDeathEvent event = this.brokenByPlayer(world, source); // Paper - this.showBreakingParticles(); -- this.kill(world); -+ if (!event.isCancelled()) this.kill(source, false); // Paper - we still need to kill to follow vanilla logic (emit the game event etc...) - } - - return true; -@@ -536,7 +604,10 @@ - f1 -= amount; - if (f1 <= 0.5F) { - this.brokenByAnything(world, damageSource); -- this.kill(world); -+ // Paper start - avoid duplicate event call -+ org.bukkit.event.entity.EntityDeathEvent event = this.brokenByAnything(world, damageSource); -+ if (!event.isCancelled()) this.kill(damageSource, false); // CraftBukkit -+ // Paper end - } else { - this.setHealth(f1); - this.gameEvent(GameEvent.ENTITY_DAMAGE, damageSource.getEntity()); -@@ -544,17 +615,17 @@ - - } - -- private void brokenByPlayer(ServerLevel world, DamageSource damageSource) { -+ private org.bukkit.event.entity.EntityDeathEvent brokenByPlayer(ServerLevel world, DamageSource damageSource) { // Paper - ItemStack itemstack = new ItemStack(Items.ARMOR_STAND); - - itemstack.set(DataComponents.CUSTOM_NAME, this.getCustomName()); -- Block.popResource(this.level(), this.blockPosition(), itemstack); -- this.brokenByAnything(world, damageSource); -+ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior -+ return this.brokenByAnything(world, damageSource); // Paper - } - -- private void brokenByAnything(ServerLevel world, DamageSource damageSource) { -+ private org.bukkit.event.entity.EntityDeathEvent brokenByAnything(ServerLevel world, DamageSource damageSource) { // Paper - this.playBrokenSound(); -- this.dropAllDeathLoot(world, damageSource); -+ // this.dropAllDeathLoot(worldserver, damagesource); // CraftBukkit - moved down - - ItemStack itemstack; - int i; -@@ -562,7 +633,7 @@ - for (i = 0; i < this.handItems.size(); ++i) { - itemstack = (ItemStack) this.handItems.get(i); - if (!itemstack.isEmpty()) { -- Block.popResource(this.level(), this.blockPosition().above(), itemstack); -+ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition().above(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior; mirror so we can destroy it later - though this call site was safe & spawn drops correctly - this.handItems.set(i, ItemStack.EMPTY); - } - } -@@ -570,15 +641,16 @@ - for (i = 0; i < this.armorItems.size(); ++i) { - itemstack = (ItemStack) this.armorItems.get(i); - if (!itemstack.isEmpty()) { -- Block.popResource(this.level(), this.blockPosition().above(), itemstack); -+ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition().above(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior; mirror so we can destroy it later - though this call site was safe & spawn drops correctly - this.armorItems.set(i, ItemStack.EMPTY); - } - } -+ return this.dropAllDeathLoot(world, damageSource); // CraftBukkit - moved from above // Paper - - } - - private void playBrokenSound() { -- this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.ARMOR_STAND_BREAK, this.getSoundSource(), 1.0F, 1.0F); -+ this.level().playSound((net.minecraft.world.entity.player.Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.ARMOR_STAND_BREAK, this.getSoundSource(), 1.0F, 1.0F); - } - - @Override -@@ -609,7 +681,29 @@ - - @Override - public void tick() { -+ // Paper start - Allow ArmorStands not to tick -+ if (!this.canTick) { -+ if (this.noTickPoseDirty) { -+ this.noTickPoseDirty = false; -+ this.updatePose(); -+ } -+ -+ if (this.noTickEquipmentDirty) { -+ this.noTickEquipmentDirty = false; -+ this.detectEquipmentUpdatesPublic(); -+ } -+ -+ return; -+ } -+ // Paper end - Allow ArmorStands not to tick -+ - super.tick(); -+ // Paper start - Allow ArmorStands not to tick -+ updatePose(); -+ } -+ -+ public void updatePose() { -+ // Paper end - Allow ArmorStands not to tick - Rotations vector3f = (Rotations) this.entityData.get(ArmorStand.DATA_HEAD_POSE); - - if (!this.headPose.equals(vector3f)) { -@@ -664,9 +758,31 @@ - return this.isSmall(); - } - -+ // CraftBukkit start - @Override -+ public boolean shouldDropExperience() { -+ return true; // MC-157395, SPIGOT-5193 even baby (small) armor stands should drop -+ } -+ // CraftBukkit end -+ -+ @Override - public void kill(ServerLevel world) { -- this.remove(Entity.RemovalReason.KILLED); -+ // CraftBukkit start - pass DamageSource for kill -+ this.kill(world, null); -+ } -+ -+ public void kill(ServerLevel worldserver, DamageSource damageSource) { -+ // Paper start - make cancellable -+ this.kill(damageSource, true); -+ } -+ public void kill(DamageSource damageSource, boolean callEvent) { -+ if (callEvent) { -+ org.bukkit.event.entity.EntityDeathEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, (damageSource == null ? this.damageSources().genericKill() : damageSource), this.drops); // CraftBukkit - call event -+ if (event.isCancelled()) return; -+ } -+ // Paper end -+ this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause -+ // CraftBukkit end - this.gameEvent(GameEvent.ENTITY_DIE); - } - -@@ -730,31 +846,37 @@ - public void setHeadPose(Rotations angle) { - this.headPose = angle; - this.entityData.set(ArmorStand.DATA_HEAD_POSE, angle); -+ this.noTickPoseDirty = true; // Paper - Allow updates when not ticking - } - - public void setBodyPose(Rotations angle) { - this.bodyPose = angle; - this.entityData.set(ArmorStand.DATA_BODY_POSE, angle); -+ this.noTickPoseDirty = true; // Paper - Allow updates when not ticking - } - - public void setLeftArmPose(Rotations angle) { - this.leftArmPose = angle; - this.entityData.set(ArmorStand.DATA_LEFT_ARM_POSE, angle); -+ this.noTickPoseDirty = true; // Paper - Allow updates when not ticking - } - - public void setRightArmPose(Rotations angle) { - this.rightArmPose = angle; - this.entityData.set(ArmorStand.DATA_RIGHT_ARM_POSE, angle); -+ this.noTickPoseDirty = true; // Paper - Allow updates when not ticking - } - - public void setLeftLegPose(Rotations angle) { - this.leftLegPose = angle; - this.entityData.set(ArmorStand.DATA_LEFT_LEG_POSE, angle); -+ this.noTickPoseDirty = true; // Paper - Allow updates when not ticking - } - - public void setRightLegPose(Rotations angle) { - this.rightLegPose = angle; - this.entityData.set(ArmorStand.DATA_RIGHT_LEG_POSE, angle); -+ this.noTickPoseDirty = true; // Paper - Allow updates when not ticking - } - - public Rotations getHeadPose() { -@@ -788,7 +910,7 @@ - - @Override - public boolean skipAttackInteraction(Entity attacker) { -- return attacker instanceof Player && !this.level().mayInteract((Player) attacker, this.blockPosition()); -+ return attacker instanceof net.minecraft.world.entity.player.Player && !this.level().mayInteract((net.minecraft.world.entity.player.Player) attacker, this.blockPosition()); - } - - @Override -@@ -882,4 +1004,13 @@ - public boolean canBeSeenByAnyone() { - return !this.isInvisible() && !this.isMarker(); - } -+ -+ // Paper start -+ @Override -+ public void move(net.minecraft.world.entity.MoverType type, Vec3 movement) { -+ if (this.canMove) { -+ super.move(type, movement); -+ } -+ } -+ // Paper end - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/decoration/BlockAttachedEntity.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/decoration/BlockAttachedEntity.java.patch deleted file mode 100644 index 2f102c86b9..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/decoration/BlockAttachedEntity.java.patch +++ /dev/null @@ -1,140 +0,0 @@ ---- a/net/minecraft/world/entity/decoration/BlockAttachedEntity.java -+++ b/net/minecraft/world/entity/decoration/BlockAttachedEntity.java -@@ -2,9 +2,6 @@ - - import com.mojang.logging.LogUtils; - import javax.annotation.Nullable; --import net.minecraft.core.BlockPos; --import net.minecraft.nbt.CompoundTag; --import net.minecraft.server.level.ServerLevel; - import net.minecraft.world.damagesource.DamageSource; - import net.minecraft.world.entity.Entity; - import net.minecraft.world.entity.EntityType; -@@ -15,13 +12,24 @@ - import net.minecraft.world.level.Explosion; - import net.minecraft.world.level.GameRules; - import net.minecraft.world.level.Level; -+import net.minecraft.world.level.block.state.BlockState; - import net.minecraft.world.phys.Vec3; - import org.slf4j.Logger; -+import net.minecraft.core.BlockPos; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.server.level.ServerLevel; -+// CraftBukkit start -+import net.minecraft.tags.DamageTypeTags; -+import org.bukkit.entity.Hanging; -+import org.bukkit.event.entity.EntityRemoveEvent; -+import org.bukkit.event.hanging.HangingBreakByEntityEvent; -+import org.bukkit.event.hanging.HangingBreakEvent; -+// CraftBukkit end - - public abstract class BlockAttachedEntity extends Entity { - - private static final Logger LOGGER = LogUtils.getLogger(); -- private int checkInterval; -+ private int checkInterval; { this.checkInterval = this.getId() % this.level().spigotConfig.hangingTickFrequency; } // Paper - Perf: offset item frame ticking - protected BlockPos pos; - - protected BlockAttachedEntity(EntityType type, Level world) { -@@ -41,10 +49,28 @@ - - if (world instanceof ServerLevel worldserver) { - this.checkBelowWorld(); -- if (this.checkInterval++ == 100) { -+ if (this.checkInterval++ == this.level().spigotConfig.hangingTickFrequency) { // Spigot - this.checkInterval = 0; - if (!this.isRemoved() && !this.survives()) { -- this.discard(); -+ // CraftBukkit start - fire break events -+ BlockState material = this.level().getBlockState(this.blockPosition()); -+ HangingBreakEvent.RemoveCause cause; -+ -+ if (!material.isAir()) { -+ // TODO: This feels insufficient to catch 100% of suffocation cases -+ cause = HangingBreakEvent.RemoveCause.OBSTRUCTION; -+ } else { -+ cause = HangingBreakEvent.RemoveCause.PHYSICS; -+ } -+ -+ HangingBreakEvent event = new HangingBreakEvent((Hanging) this.getBukkitEntity(), cause); -+ this.level().getCraftServer().getPluginManager().callEvent(event); -+ -+ if (this.isRemoved() || event.isCancelled()) { -+ return; -+ } -+ // CraftBukkit end -+ this.discard(EntityRemoveEvent.Cause.DROP); // CraftBukkit - add Bukkit remove cause - this.dropItem(worldserver, (Entity) null); - } - } -@@ -81,6 +107,22 @@ - return false; - } else { - if (!this.isRemoved()) { -+ // CraftBukkit start - fire break events -+ Entity damager = (!source.isDirect() && source.getEntity() != null) ? source.getEntity() : source.getDirectEntity(); // Paper - fix DamageSource API -+ HangingBreakEvent event; -+ if (damager != null) { -+ event = new HangingBreakByEntityEvent((Hanging) this.getBukkitEntity(), damager.getBukkitEntity(), source.is(DamageTypeTags.IS_EXPLOSION) ? HangingBreakEvent.RemoveCause.EXPLOSION : HangingBreakEvent.RemoveCause.ENTITY); -+ } else { -+ event = new HangingBreakEvent((Hanging) this.getBukkitEntity(), source.is(DamageTypeTags.IS_EXPLOSION) ? HangingBreakEvent.RemoveCause.EXPLOSION : HangingBreakEvent.RemoveCause.DEFAULT); -+ } -+ -+ this.level().getCraftServer().getPluginManager().callEvent(event); -+ -+ if (this.isRemoved() || event.isCancelled()) { -+ return true; -+ } -+ // CraftBukkit end -+ - this.kill(world); - this.markHurt(); - this.dropItem(world, source.getEntity()); -@@ -101,6 +143,16 @@ - - if (world instanceof ServerLevel worldserver) { - if (!this.isRemoved() && movement.lengthSqr() > 0.0D) { -+ // CraftBukkit start - fire break events -+ // TODO - Does this need its own cause? Seems to only be triggered by pistons -+ HangingBreakEvent event = new HangingBreakEvent((Hanging) this.getBukkitEntity(), HangingBreakEvent.RemoveCause.PHYSICS); -+ this.level().getCraftServer().getPluginManager().callEvent(event); -+ -+ if (this.isRemoved() || event.isCancelled()) { -+ return; -+ } -+ // CraftBukkit end -+ - this.kill(worldserver); - this.dropItem(worldserver, (Entity) null); - } -@@ -109,11 +161,11 @@ - } - - @Override -- public void push(double deltaX, double deltaY, double deltaZ) { -+ public void push(double deltaX, double deltaY, double deltaZ, @Nullable Entity pushingEntity) { // Paper - override correct overload - Level world = this.level(); - - if (world instanceof ServerLevel worldserver) { -- if (!this.isRemoved() && deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ > 0.0D) { -+ if (false && !this.isRemoved() && deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ > 0.0D) { // CraftBukkit - not needed - this.kill(worldserver); - this.dropItem(worldserver, (Entity) null); - } -@@ -121,7 +173,16 @@ - - } - -+ // CraftBukkit start - selectively save tile position - @Override -+ public void addAdditionalSaveData(CompoundTag nbttagcompound, boolean includeAll) { -+ if (includeAll) { -+ this.addAdditionalSaveData(nbttagcompound); -+ } -+ } -+ // CraftBukkit end -+ -+ @Override - public void addAdditionalSaveData(CompoundTag nbt) { - BlockPos blockposition = this.getPos(); - diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/decoration/ItemFrame.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/decoration/ItemFrame.java.patch deleted file mode 100644 index f6d7c47bb4..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/decoration/ItemFrame.java.patch +++ /dev/null @@ -1,150 +0,0 @@ ---- a/net/minecraft/world/entity/decoration/ItemFrame.java -+++ b/net/minecraft/world/entity/decoration/ItemFrame.java -@@ -1,6 +1,7 @@ - package net.minecraft.world.entity.decoration; - - import javax.annotation.Nullable; -+import io.papermc.paper.event.player.PlayerItemFrameChangeEvent; // Paper - Add PlayerItemFrameChangeEvent - import net.minecraft.core.BlockPos; - import net.minecraft.core.Direction; - import net.minecraft.core.component.DataComponents; -@@ -50,6 +51,7 @@ - private static final float HEIGHT = 0.75F; - public float dropChance; - public boolean fixed; -+ public @Nullable MapId cachedMapId; // Paper - Perf: Cache map ids on item frames - - public ItemFrame(EntityType type, Level world) { - super(type, world); -@@ -91,9 +93,15 @@ - - @Override - protected AABB calculateBoundingBox(BlockPos pos, Direction side) { -+ // CraftBukkit start - break out BB calc into own method -+ return ItemFrame.calculateBoundingBoxStatic(pos, side); -+ } -+ -+ public static AABB calculateBoundingBoxStatic(BlockPos blockposition, Direction enumdirection) { -+ // CraftBukkit end - float f = 0.46875F; -- Vec3 vec3d = Vec3.atCenterOf(pos).relative(side, -0.46875D); -- Direction.Axis enumdirection_enumaxis = side.getAxis(); -+ Vec3 vec3d = Vec3.atCenterOf(blockposition).relative(enumdirection, -0.46875D); -+ Direction.Axis enumdirection_enumaxis = enumdirection.getAxis(); - double d0 = enumdirection_enumaxis == Direction.Axis.X ? 0.0625D : 0.75D; - double d1 = enumdirection_enumaxis == Direction.Axis.Y ? 0.0625D : 0.75D; - double d2 = enumdirection_enumaxis == Direction.Axis.Z ? 0.0625D : 0.75D; -@@ -123,9 +131,9 @@ - } - - @Override -- public void push(double deltaX, double deltaY, double deltaZ) { -+ public void push(double deltaX, double deltaY, double deltaZ, @Nullable Entity pushingEntity) { // Paper - add push source entity param - if (!this.fixed) { -- super.push(deltaX, deltaY, deltaZ); -+ super.push(deltaX, deltaY, deltaZ, pushingEntity); // Paper - add push source entity param - } - - } -@@ -155,6 +163,18 @@ - if (this.isInvulnerableToBase(source)) { - return false; - } else if (this.shouldDamageDropItem(source)) { -+ // CraftBukkit start - fire EntityDamageEvent -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, amount, false) || this.isRemoved()) { -+ return true; -+ } -+ // CraftBukkit end -+ // Paper start - Add PlayerItemFrameChangeEvent -+ if (source.getEntity() instanceof Player player) { -+ var event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), this.getItem().asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.REMOVE); -+ if (!event.callEvent()) return true; // return true here because you aren't cancelling the damage, just the change -+ this.setItem(ItemStack.fromBukkitCopy(event.getItemStack()), false); -+ } -+ // Paper end - Add PlayerItemFrameChangeEvent - this.dropItem(world, source.getEntity(), false); - this.gameEvent(GameEvent.BLOCK_CHANGE, source.getEntity()); - this.playSound(this.getRemoveItemSound(), 1.0F, 1.0F); -@@ -251,7 +271,15 @@ - - public ItemStack getItem() { - return (ItemStack) this.getEntityData().get(ItemFrame.DATA_ITEM); -+ } -+ -+ // Paper start - Fix MC-123848 (spawn item frame drops above block) -+ @Nullable -+ @Override -+ public net.minecraft.world.entity.item.ItemEntity spawnAtLocation(ServerLevel serverLevel, ItemStack stack) { -+ return this.spawnAtLocation(serverLevel, stack, this.getDirection() == Direction.DOWN ? -0.6F : 0.0F); - } -+ // Paper end - - @Nullable - public MapId getFramedMapId(ItemStack stack) { -@@ -267,17 +295,23 @@ - } - - public void setItem(ItemStack value, boolean update) { -- if (!value.isEmpty()) { -- value = value.copyWithCount(1); -+ // CraftBukkit start -+ this.setItem(value, update, true); -+ } -+ -+ public void setItem(ItemStack itemstack, boolean flag, boolean playSound) { -+ // CraftBukkit end -+ if (!itemstack.isEmpty()) { -+ itemstack = itemstack.copyWithCount(1); - } - -- this.onItemChanged(value); -- this.getEntityData().set(ItemFrame.DATA_ITEM, value); -- if (!value.isEmpty()) { -+ this.onItemChanged(itemstack); -+ this.getEntityData().set(ItemFrame.DATA_ITEM, itemstack); -+ if (!itemstack.isEmpty() && flag && playSound) { // CraftBukkit // Paper - only play sound when update flag is set - this.playSound(this.getAddItemSound(), 1.0F, 1.0F); - } - -- if (update && this.pos != null) { -+ if (flag && this.pos != null) { - this.level().updateNeighbourForOutputSignal(this.pos, Blocks.AIR); - } - -@@ -301,6 +335,7 @@ - } - - private void onItemChanged(ItemStack stack) { -+ this.cachedMapId = stack.getComponents().get(net.minecraft.core.component.DataComponents.MAP_ID); // Paper - Perf: Cache map ids on item frames - if (!stack.isEmpty() && stack.getFrame() != this) { - stack.setEntityRepresentation(this); - } -@@ -386,7 +421,13 @@ - if (worldmap != null && worldmap.isTrackedCountOverLimit(256)) { - return InteractionResult.FAIL; - } else { -- this.setItem(itemstack); -+ // Paper start - Add PlayerItemFrameChangeEvent -+ PlayerItemFrameChangeEvent event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), itemstack.asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.PLACE); -+ if (!event.callEvent()) { -+ return InteractionResult.FAIL; -+ } -+ this.setItem(ItemStack.fromBukkitCopy(event.getItemStack())); -+ // Paper end - Add PlayerItemFrameChangeEvent - this.gameEvent(GameEvent.BLOCK_CHANGE, player); - itemstack.consume(1, player); - return InteractionResult.SUCCESS; -@@ -395,6 +436,13 @@ - return InteractionResult.PASS; - } - } else { -+ // Paper start - Add PlayerItemFrameChangeEvent -+ PlayerItemFrameChangeEvent event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), this.getItem().asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.ROTATE); -+ if (!event.callEvent()) { -+ return InteractionResult.FAIL; -+ } -+ setItem(ItemStack.fromBukkitCopy(event.getItemStack()), false, false); -+ // Paper end - Add PlayerItemFrameChangeEvent - this.playSound(this.getRotateItemSound(), 1.0F, 1.0F); - this.setRotation(this.getRotation() + 1); - this.gameEvent(GameEvent.BLOCK_CHANGE, player); diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/decoration/Painting.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/decoration/Painting.java.patch deleted file mode 100644 index 122466b765..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/decoration/Painting.java.patch +++ /dev/null @@ -1,54 +0,0 @@ ---- a/net/minecraft/world/entity/decoration/Painting.java -+++ b/net/minecraft/world/entity/decoration/Painting.java -@@ -72,7 +72,7 @@ - public static Optional create(Level world, BlockPos pos, Direction facing) { - Painting entitypainting = new Painting(world, pos); - List> list = new ArrayList(); -- Iterable iterable = world.registryAccess().lookupOrThrow(Registries.PAINTING_VARIANT).getTagOrEmpty(PaintingVariantTags.PLACEABLE); -+ Iterable> iterable = world.registryAccess().lookupOrThrow(Registries.PAINTING_VARIANT).getTagOrEmpty(PaintingVariantTags.PLACEABLE); // CraftBukkit - decompile error - - Objects.requireNonNull(list); - iterable.forEach(list::add); -@@ -138,22 +138,32 @@ - - @Override - protected AABB calculateBoundingBox(BlockPos pos, Direction side) { -- float f = 0.46875F; -- Vec3 vec3d = Vec3.atCenterOf(pos).relative(side, -0.46875D); -+ // CraftBukkit start - PaintingVariant paintingvariant = (PaintingVariant) this.getVariant().value(); -- double d0 = this.offsetForPaintingSize(paintingvariant.width()); -- double d1 = this.offsetForPaintingSize(paintingvariant.height()); -- Direction enumdirection1 = side.getCounterClockWise(); -+ return Painting.calculateBoundingBoxStatic(pos, side, paintingvariant.width(), paintingvariant.height()); -+ } -+ -+ public static AABB calculateBoundingBoxStatic(BlockPos blockposition, Direction enumdirection, int width, int height) { -+ // CraftBukkit end -+ float f = 0.46875F; -+ Vec3 vec3d = Vec3.atCenterOf(blockposition).relative(enumdirection, -0.46875D); -+ // CraftBukkit start -+ double d0 = Painting.offsetForPaintingSize(width); -+ double d1 = Painting.offsetForPaintingSize(height); -+ // CraftBukkit end -+ Direction enumdirection1 = enumdirection.getCounterClockWise(); - Vec3 vec3d1 = vec3d.relative(enumdirection1, d0).relative(Direction.UP, d1); -- Direction.Axis enumdirection_enumaxis = side.getAxis(); -- double d2 = enumdirection_enumaxis == Direction.Axis.X ? 0.0625D : (double) paintingvariant.width(); -- double d3 = (double) paintingvariant.height(); -- double d4 = enumdirection_enumaxis == Direction.Axis.Z ? 0.0625D : (double) paintingvariant.width(); -+ Direction.Axis enumdirection_enumaxis = enumdirection.getAxis(); -+ // CraftBukkit start -+ double d2 = enumdirection_enumaxis == Direction.Axis.X ? 0.0625D : (double) width; -+ double d3 = (double) height; -+ double d4 = enumdirection_enumaxis == Direction.Axis.Z ? 0.0625D : (double) width; -+ // CraftBukkit end - - return AABB.ofSize(vec3d1, d2, d3, d4); - } - -- private double offsetForPaintingSize(int length) { -+ private static double offsetForPaintingSize(int length) { // CraftBukkit - static - return length % 2 == 0 ? 0.5D : 0.0D; - } -