net.minecraft.world.entity.decoration

This commit is contained in:
Jake Potrebic
2024-12-14 15:38:34 -08:00
parent 363d5bcf57
commit 5deb3e9671
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

@@ -0,0 +1,61 @@
--- a/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java
+++ b/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java
@@ -81,6 +_,15 @@
for (Leashable leashable : list) {
if (leashable.getLeashHolder() == player) {
+ // CraftBukkit start
+ if (leashable instanceof Entity leashed) {
+ 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;
+ }
+ }
+ // CraftBukkit end
leashable.setLeashedTo(this, true);
flag = true;
}
@@ -88,14 +_,39 @@
boolean flag1 = false;
if (!flag) {
- this.discard();
- if (player.getAbilities().instabuild) {
+ // CraftBukkit start - Move below
+ // this.discard();
+ boolean die = true;
+ // CraftBukkit end
+ if (true || player.getAbilities().instabuild) { // CraftBukkit - Process for non-creative as well
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 = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerUnleashEntityEvent(leashed, player, hand, dropLeash);
+ dropLeash = event.isDropLeash();
+ if (event.isCancelled()) {
+ // Paper end - Expand EntityUnleashEvent
+ die = false;
+ continue;
+ }
+ }
+ if (!dropLeash) { // Paper - Expand EntityUnleashEvent
+ leashable1.removeLeash();
+ } else {
+ leashable1.dropLeash();
+ }
+ // CraftBukkit end
flag1 = true;
}
}
+ // CraftBukkit start
+ if (die) {
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DROP); // CraftBukkit - add Bukkit remove cause
+ }
+ // 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;
}