net.minecraft.world.entity.decoration

This commit is contained in:
Jake Potrebic 2024-12-14 15:38:34 -08:00
parent 363d5bcf57
commit 5deb3e9671
No known key found for this signature in database
GPG key ID: ECE0B3C133C016C5
9 changed files with 667 additions and 892 deletions

View file

@ -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<? extends ArmorStand> 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
}

View file

@ -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<? extends BlockAttachedEntity> 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) {

View file

@ -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<? extends ItemFrame> 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);

View file

@ -1,35 +1,13 @@
--- a/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java --- a/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java
+++ b/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java +++ b/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java
@@ -8,9 +8,11 @@ @@ -81,6 +_,15 @@
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();
for (Leashable leashable : list) {
if (leashable.getLeashHolder() == player) { if (leashable.getLeashHolder() == player) {
+ // CraftBukkit start + // CraftBukkit start
+ if (leashable instanceof Entity leashed) { + if (leashable instanceof Entity leashed) {
+ if (CraftEventFactory.callPlayerLeashEntityEvent(leashed, this, player, hand).isCancelled()) { + if (org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerLeashEntityEvent(leashed, this, player, hand).isCancelled()) {
+ ((ServerPlayer) player).connection.send(new ClientboundSetEntityLinkPacket(leashed, leashable.getLeashHolder())); + ((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 + flag = true; // Also set true when the event is cancelled otherwise it tries to unleash the entities
+ continue; + continue;
+ } + }
@ -38,9 +16,9 @@
leashable.setLeashedTo(this, true); leashable.setLeashedTo(this, true);
flag = true; flag = true;
} }
@@ -93,18 +107,43 @@ @@ -88,14 +_,39 @@
boolean flag1 = false;
boolean flag1 = false;
if (!flag) { if (!flag) {
- this.discard(); - this.discard();
- if (player.getAbilities().instabuild) { - if (player.getAbilities().instabuild) {
@ -49,18 +27,14 @@
+ boolean die = true; + boolean die = true;
+ // CraftBukkit end + // CraftBukkit end
+ if (true || player.getAbilities().instabuild) { // CraftBukkit - Process for non-creative as well + if (true || player.getAbilities().instabuild) { // CraftBukkit - Process for non-creative as well
Iterator iterator1 = list.iterator(); for (Leashable leashable1 : list) {
while (iterator1.hasNext()) {
Leashable leashable1 = (Leashable) iterator1.next();
if (leashable1.isLeashed() && leashable1.getLeashHolder() == this) { if (leashable1.isLeashed() && leashable1.getLeashHolder() == this) {
- leashable1.removeLeash(); - leashable1.removeLeash();
+ // CraftBukkit start + // CraftBukkit start
+ boolean dropLeash = !player.hasInfiniteMaterials(); + boolean dropLeash = !player.hasInfiniteMaterials();
+ if (leashable1 instanceof Entity leashed) { + if (leashable1 instanceof Entity leashed) {
+ // Paper start - Expand EntityUnleashEvent + // 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(); + dropLeash = event.isDropLeash();
+ if (event.isCancelled()) { + if (event.isCancelled()) {
+ // Paper end - Expand EntityUnleashEvent + // Paper end - Expand EntityUnleashEvent
@ -79,7 +53,7 @@
} }
+ // CraftBukkit start + // CraftBukkit start
+ if (die) { + 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 + // CraftBukkit end
} }

View file

@ -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;
}

View file

@ -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<? extends ArmorStand> 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<Entity> 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
}

View file

@ -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<? extends BlockAttachedEntity> 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();

View file

@ -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<? extends ItemFrame> 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);

View file

@ -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<Painting> create(Level world, BlockPos pos, Direction facing) {
Painting entitypainting = new Painting(world, pos);
List<Holder<PaintingVariant>> list = new ArrayList();
- Iterable iterable = world.registryAccess().lookupOrThrow(Registries.PAINTING_VARIANT).getTagOrEmpty(PaintingVariantTags.PLACEABLE);
+ Iterable<Holder<PaintingVariant>> 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;
}