279
This commit is contained in:
		
					parent
					
						
							
								9120ce5d4b
							
						
					
				
			
			
				commit
				
					
						e07671b7df
					
				
			
		
					 86 changed files with 231 additions and 248 deletions
				
			
		| 
						 | 
				
			
			@ -42,7 +42,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
--- a/src/main/java/net/minecraft/network/Connection.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/network/Connection.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
 | 
			
		||||
                     packetlistener1.onDisconnect(ichatbasecomponent);
 | 
			
		||||
                     packetlistener1.onDisconnect(disconnectiondetails);
 | 
			
		||||
                 }
 | 
			
		||||
                 this.pendingActions.clear(); // Free up packet queue.
 | 
			
		||||
+                // Paper start - Add PlayerConnectionCloseEvent
 | 
			
		||||
| 
						 | 
				
			
			@ -15,12 +15,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    public void push(double deltaX, double deltaY, double deltaZ) {
 | 
			
		||||
-        this.setDeltaMovement(this.getDeltaMovement().add(deltaX, deltaY, deltaZ));
 | 
			
		||||
+    public final void push(double deltaX, double deltaY, double deltaZ) { // Paper - override the added overload below
 | 
			
		||||
     public void push(double deltaX, double deltaY, double deltaZ) {
 | 
			
		||||
+        // Paper start - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent
 | 
			
		||||
+        this.push(deltaX, deltaY, deltaZ, null);
 | 
			
		||||
+    }
 | 
			
		||||
| 
						 | 
				
			
			@ -36,15 +33,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
+        }
 | 
			
		||||
+        this.setDeltaMovement(this.getDeltaMovement().add(delta.getX(), delta.getY(), delta.getZ()));
 | 
			
		||||
+        // Paper end - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent
 | 
			
		||||
         this.setDeltaMovement(this.getDeltaMovement().add(deltaX, deltaY, deltaZ));
 | 
			
		||||
         this.hasImpulse = true;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
 | 
			
		||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
 | 
			
		||||
                         d0 = (Math.random() - Math.random()) * 0.01D;
 | 
			
		||||
                         d1 = source.getSourcePosition().z() - this.getZ();
 | 
			
		||||
                     }
 | 
			
		||||
 
 | 
			
		||||
-                    this.knockback(0.4000000059604645D, d0, d1, entity1, entity1 == null ? EntityKnockbackEvent.KnockbackCause.DAMAGE : EntityKnockbackEvent.KnockbackCause.ENTITY_ATTACK); // CraftBukkit
 | 
			
		||||
| 
						 | 
				
			
			@ -74,7 +71,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
         d0 *= 1.0D - this.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE);
 | 
			
		||||
         if (true || d0 > 0.0D) { // CraftBukkit - Call event even when force is 0
 | 
			
		||||
             //this.hasImpulse = true; // CraftBukkit - Move down
 | 
			
		||||
             Vec3 vec3d = this.getDeltaMovement();
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
 | 
			
		||||
 
 | 
			
		||||
             Vec3 vec3d1 = (new Vec3(d1, 0.0D, d2)).normalize().scale(d0);
 | 
			
		||||
 
 | 
			
		||||
-            EntityKnockbackEvent event = CraftEventFactory.callEntityKnockbackEvent((org.bukkit.craftbukkit.entity.CraftLivingEntity) this.getBukkitEntity(), attacker, cause, d0, vec3d1, vec3d.x / 2.0D - vec3d1.x, this.onGround() ? Math.min(0.4D, vec3d.y / 2.0D + d0) : vec3d.y, vec3d.z / 2.0D - vec3d1.z);
 | 
			
		||||
| 
						 | 
				
			
			@ -97,12 +95,12 @@ diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/n
 | 
			
		|||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/world/entity/Mob.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti
 | 
			
		||||
 
 | 
			
		||||
         if (flag) {
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
 | 
			
		||||
             if (f1 > 0.0F && target instanceof LivingEntity) {
 | 
			
		||||
-                ((LivingEntity) target).knockback((double) (f1 * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot())) * 0.017453292F, this, org.bukkit.event.entity.EntityKnockbackEvent.KnockbackCause.ENTITY_ATTACK); // CraftBukkit
 | 
			
		||||
+                ((LivingEntity) target).knockback((double) (f1 * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot())) * 0.017453292F, this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events
 | 
			
		||||
                 LivingEntity entityliving = (LivingEntity) target;
 | 
			
		||||
 
 | 
			
		||||
-                entityliving.knockback((double) (f1 * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, org.bukkit.event.entity.EntityKnockbackEvent.KnockbackCause.ENTITY_ATTACK); // CraftBukkit
 | 
			
		||||
+                entityliving.knockback((double) (f1 * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events
 | 
			
		||||
                 this.setDeltaMovement(this.getDeltaMovement().multiply(0.6D, 1.0D, 0.6D));
 | 
			
		||||
             }
 | 
			
		||||
 
 | 
			
		||||
| 
						 | 
				
			
			@ -142,19 +140,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
 
 | 
			
		||||
-                entity.push(d2 / d4 * 4.0D, 0.20000000298023224D, d3 / d4 * 4.0D);
 | 
			
		||||
+                entity.push(d2 / d4 * 4.0D, 0.20000000298023224D, d3 / d4 * 4.0D, this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent
 | 
			
		||||
                 if (!this.phaseManager.getCurrentPhase().isSitting() && ((LivingEntity) entity).getLastHurtByMobTimestamp() < entity.tickCount - 2) {
 | 
			
		||||
                     entity.hurt(this.damageSources().mobAttack(this), 5.0F);
 | 
			
		||||
                     this.doEnchantDamageEffects(this, entity);
 | 
			
		||||
diff --git a/src/main/java/net/minecraft/world/entity/decoration/HangingEntity.java b/src/main/java/net/minecraft/world/entity/decoration/HangingEntity.java
 | 
			
		||||
                 if (!this.phaseManager.getCurrentPhase().isSitting() && entityliving.getLastHurtByMobTimestamp() < entity.tickCount - 2) {
 | 
			
		||||
                     DamageSource damagesource = this.damageSources().mobAttack(this);
 | 
			
		||||
 
 | 
			
		||||
diff --git a/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java b/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java
 | 
			
		||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/world/entity/decoration/HangingEntity.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/HangingEntity.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class HangingEntity extends Entity {
 | 
			
		||||
--- a/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/BlockAttachedEntity.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class BlockAttachedEntity extends Entity {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     @Override
 | 
			
		||||
-    public void push(double deltaX, double deltaY, double deltaZ) {
 | 
			
		||||
+    public void push(double deltaX, double deltaY, double deltaZ, @org.jetbrains.annotations.Nullable Entity pushingEntity) { // Paper - add push source entity param
 | 
			
		||||
+    public void push(double deltaX, double deltaY, double deltaZ, @Nullable Entity pushingEntity) { // Paper - override correct overload
 | 
			
		||||
         if (false && !this.level().isClientSide && !this.isRemoved() && deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ > 0.0D) { // CraftBukkit - not needed
 | 
			
		||||
             this.kill();
 | 
			
		||||
             this.dropItem((Entity) null);
 | 
			
		||||
| 
						 | 
				
			
			@ -205,38 +203,38 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class Player extends LivingEntity {
 | 
			
		||||
                         if (flag5) {
 | 
			
		||||
                             if (i > 0) {
 | 
			
		||||
                                 if (target instanceof LivingEntity) {
 | 
			
		||||
-                                    ((LivingEntity) target).knockback((double) ((float) i * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, EntityKnockbackEvent.KnockbackCause.ENTITY_ATTACK); // CraftBukkit
 | 
			
		||||
+                                    ((LivingEntity) target).knockback((double) ((float) i * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events
 | 
			
		||||
                                 } else {
 | 
			
		||||
-                                    target.push((double) (-Mth.sin(this.getYRot() * 0.017453292F) * (float) i * 0.5F), 0.1D, (double) (Mth.cos(this.getYRot() * 0.017453292F) * (float) i * 0.5F));
 | 
			
		||||
+                                    target.push((double) (-Mth.sin(this.getYRot() * 0.017453292F) * (float) i * 0.5F), 0.1D, (double) (Mth.cos(this.getYRot() * 0.017453292F) * (float) i * 0.5F), this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent
 | 
			
		||||
                                 }
 | 
			
		||||
                             if (target instanceof LivingEntity) {
 | 
			
		||||
                                 LivingEntity entityliving1 = (LivingEntity) target;
 | 
			
		||||
 
 | 
			
		||||
                                 this.setDeltaMovement(this.getDeltaMovement().multiply(0.6D, 1.0D, 0.6D));
 | 
			
		||||
-                                entityliving1.knockback((double) (f5 * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)));
 | 
			
		||||
+                                entityliving1.knockback((double) (f5 * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // Paper - knockback events
 | 
			
		||||
                             } else {
 | 
			
		||||
-                                target.push((double) (-Mth.sin(this.getYRot() * 0.017453292F) * f5 * 0.5F), 0.1D, (double) (Mth.cos(this.getYRot() * 0.017453292F) * f5 * 0.5F));
 | 
			
		||||
+                                target.push((double) (-Mth.sin(this.getYRot() * 0.017453292F) * f5 * 0.5F), 0.1D, (double) (Mth.cos(this.getYRot() * 0.017453292F) * f5 * 0.5F), this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent
 | 
			
		||||
                             }
 | 
			
		||||
 
 | 
			
		||||
                             this.setDeltaMovement(this.getDeltaMovement().multiply(0.6D, 1.0D, 0.6D));
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class Player extends LivingEntity {
 | 
			
		||||
                                     if (entityliving != this && entityliving != target && !this.isAlliedTo((Entity) entityliving) && (!(entityliving instanceof ArmorStand) || !((ArmorStand) entityliving).isMarker()) && this.distanceToSqr((Entity) entityliving) < 9.0D) {
 | 
			
		||||
                                         // CraftBukkit start - Only apply knockback if the damage hits
 | 
			
		||||
                                         if (entityliving.hurt(this.damageSources().playerAttack(this).sweep(), f4)) {
 | 
			
		||||
-                                            entityliving.knockback(0.4000000059604645D, (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, EntityKnockbackEvent.KnockbackCause.SWEEP_ATTACK); // CraftBukkit
 | 
			
		||||
+                                            entityliving.knockback(0.4000000059604645D, (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.SWEEP_ATTACK); // CraftBukkit // Paper - knockback events
 | 
			
		||||
                                         }
 | 
			
		||||
                                         // CraftBukkit end
 | 
			
		||||
 
 | 
			
		||||
                                     // CraftBukkit start - Only apply knockback if the damage hits
 | 
			
		||||
                                     if (entityliving2.hurt(this.damageSources().playerAttack(this).sweep(), f7)) {
 | 
			
		||||
-                                        entityliving2.knockback(0.4000000059604645D, (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, EntityKnockbackEvent.KnockbackCause.SWEEP_ATTACK); // CraftBukkit
 | 
			
		||||
+                                        entityliving2.knockback(0.4000000059604645D, (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.SWEEP_ATTACK); // CraftBukkit // Paper - knockback events
 | 
			
		||||
                                     }
 | 
			
		||||
                                     // CraftBukkit end
 | 
			
		||||
                                     Level world = this.level();
 | 
			
		||||
diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
 | 
			
		||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class AbstractArrow extends Projectile {
 | 
			
		||||
                     Vec3 vec3d = this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D).normalize().scale((double) this.knockback * 0.6D * d0);
 | 
			
		||||
             Vec3 vec3d = this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D).normalize().scale(d0 * 0.6D * d1);
 | 
			
		||||
 
 | 
			
		||||
                     if (vec3d.lengthSqr() > 0.0D) {
 | 
			
		||||
-                        entityliving.push(vec3d.x, 0.1D, vec3d.z);
 | 
			
		||||
+                        entityliving.push(vec3d.x, 0.1D, vec3d.z, this); // Paper - pass causing entity for knockback events
 | 
			
		||||
                     }
 | 
			
		||||
                 }
 | 
			
		||||
             if (vec3d.lengthSqr() > 0.0D) {
 | 
			
		||||
-                target.push(vec3d.x, 0.1D, vec3d.z);
 | 
			
		||||
+                target.push(vec3d.x, 0.1D, vec3d.z, this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
diff --git a/src/main/java/net/minecraft/world/entity/projectile/windcharge/AbstractWindCharge.java b/src/main/java/net/minecraft/world/entity/projectile/windcharge/AbstractWindCharge.java
 | 
			
		||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
| 
						 | 
				
			
			@ -249,7 +247,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
-    public void push(double deltaX, double deltaY, double deltaZ) {}
 | 
			
		||||
+    public void push(double deltaX, double deltaY, double deltaZ, @org.jetbrains.annotations.Nullable Entity pushingEntity) {} // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent
 | 
			
		||||
 
 | 
			
		||||
     public abstract void explode();
 | 
			
		||||
     public abstract void explode(Vec3 pos);
 | 
			
		||||
 
 | 
			
		||||
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
 | 
			
		||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
-                    potion = org.bukkit.craftbukkit.event.CraftEventFactory.handleWitchReadyPotionEvent(this, potion);
 | 
			
		||||
-                    this.setItemSlot(EquipmentSlot.MAINHAND, potion);
 | 
			
		||||
-                    // Paper end
 | 
			
		||||
-                    this.usingTime = this.getMainHandItem().getUseDuration();
 | 
			
		||||
-                    this.usingTime = this.getMainHandItem().getUseDuration(this);
 | 
			
		||||
-                    this.setUsingItem(true);
 | 
			
		||||
-                    if (!this.isSilent()) {
 | 
			
		||||
-                        this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.WITCH_DRINK, this.getSoundSource(), 1.0F, 0.8F + this.random.nextFloat() * 0.4F);
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
-
 | 
			
		||||
-                    AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED);
 | 
			
		||||
-
 | 
			
		||||
-                    attributemodifiable.removeModifier(Witch.SPEED_MODIFIER_DRINKING.id());
 | 
			
		||||
-                    attributemodifiable.removeModifier(Witch.SPEED_MODIFIER_DRINKING_ID);
 | 
			
		||||
-                    attributemodifiable.addTransientModifier(Witch.SPEED_MODIFIER_DRINKING);
 | 
			
		||||
+                    this.setDrinkingPotion(PotionContents.createItemStack(Items.POTION, holder)); // Paper - logic moved into setDrinkingPotion, copy exact impl into the method and then comment out
 | 
			
		||||
                 }
 | 
			
		||||
| 
						 | 
				
			
			@ -41,7 +41,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
+    public void setDrinkingPotion(ItemStack potion) {
 | 
			
		||||
+        potion = org.bukkit.craftbukkit.event.CraftEventFactory.handleWitchReadyPotionEvent(this, potion);
 | 
			
		||||
+        this.setItemSlot(EquipmentSlot.MAINHAND, potion);
 | 
			
		||||
+        this.usingTime = this.getMainHandItem().getUseDuration();
 | 
			
		||||
+        this.usingTime = this.getMainHandItem().getUseDuration(this);
 | 
			
		||||
+        this.setUsingItem(true);
 | 
			
		||||
+        if (!this.isSilent()) {
 | 
			
		||||
+            this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.WITCH_DRINK, this.getSoundSource(), 1.0F, 0.8F + this.random.nextFloat() * 0.4F);
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +49,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
+
 | 
			
		||||
+        AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED);
 | 
			
		||||
+
 | 
			
		||||
+        attributemodifiable.removeModifier(Witch.SPEED_MODIFIER_DRINKING.id());
 | 
			
		||||
+        attributemodifiable.removeModifier(Witch.SPEED_MODIFIER_DRINKING_ID);
 | 
			
		||||
+        attributemodifiable.addTransientModifier(Witch.SPEED_MODIFIER_DRINKING);
 | 
			
		||||
+    }
 | 
			
		||||
+    // Paper end
 | 
			
		||||
| 
						 | 
				
			
			@ -40,9 +40,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
                 // CraftBukkit end
 | 
			
		||||
                     ServerGamePacketListenerImpl.LOGGER.warn("{} (vehicle of {}) moved too quickly! {},{},{}", new Object[]{entity.getName().getString(), this.player.getName().getString(), d6, d7, d8});
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
 | 
			
		||||
                 }
 | 
			
		||||
 
 | 
			
		||||
                 } else {
 | 
			
		||||
                     this.awaitingTeleportTime = this.tickCount;
 | 
			
		||||
                 if (!this.updateAwaitingTeleport()) {
 | 
			
		||||
-                    double d0 = ServerGamePacketListenerImpl.clampHorizontal(packet.getX(this.player.getX()));
 | 
			
		||||
-                    double d1 = ServerGamePacketListenerImpl.clampVertical(packet.getY(this.player.getY()));
 | 
			
		||||
-                    double d2 = ServerGamePacketListenerImpl.clampHorizontal(packet.getZ(this.player.getZ()));
 | 
			
		||||
| 
						 | 
				
			
			@ -54,4 +54,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
+        // Paper end - Book size limits
 | 
			
		||||
         // CraftBukkit start
 | 
			
		||||
         if (this.lastBookTick + 20 > MinecraftServer.currentTick) {
 | 
			
		||||
             this.disconnect("Book edited too quickly!");
 | 
			
		||||
             this.disconnect(Component.literal("Book edited too quickly!"));
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/ma
 | 
			
		|||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
 | 
			
		||||
 
 | 
			
		||||
         this.camera = (Entity) (entity == null ? this : entity);
 | 
			
		||||
         if (entity1 != this.camera) {
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonStrafePlayerPhase.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public class DragonStrafePlayerPhase extends AbstractDragonPhaseInstance {
 | 
			
		||||
 
 | 
			
		||||
                         DragonFireball dragonFireball = new DragonFireball(this.dragon.level(), this.dragon, r, s, t);
 | 
			
		||||
                         DragonFireball dragonFireball = new DragonFireball(this.dragon.level(), this.dragon, vec34.normalize());
 | 
			
		||||
                         dragonFireball.moveTo(o, p, q, 0.0F, 0.0F);
 | 
			
		||||
+                        if (new com.destroystokyo.paper.event.entity.EnderDragonShootFireballEvent((org.bukkit.entity.EnderDragon) dragon.getBukkitEntity(), (org.bukkit.entity.DragonFireball) dragonFireball.getBukkitEntity()).callEvent()) // Paper - EnderDragon Events
 | 
			
		||||
                         this.dragon.level().addFreshEntity(dragonFireball);
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
@@ -0,0 +0,0 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
 | 
			
		||||
     protected final ContainerData dataAccess;
 | 
			
		||||
     public final Object2IntOpenHashMap<ResourceLocation> recipesUsed;
 | 
			
		||||
     private final RecipeManager.CachedCheck<Container, ? extends AbstractCookingRecipe> quickCheck;
 | 
			
		||||
     private final RecipeManager.CachedCheck<SingleRecipeInput, ? extends AbstractCookingRecipe> quickCheck;
 | 
			
		||||
+    public final RecipeType<? extends AbstractCookingRecipe> recipeType; // Paper - cook speed multiplier API
 | 
			
		||||
 
 | 
			
		||||
     protected AbstractFurnaceBlockEntity(BlockEntityType<?> blockEntityType, BlockPos pos, BlockState state, RecipeType<? extends AbstractCookingRecipe> recipeType) {
 | 
			
		||||
| 
						 | 
				
			
			@ -37,7 +37,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
 
 | 
			
		||||
     public static void invalidateCache() {
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
 | 
			
		||||
             this.recipesUsed.put(new ResourceLocation(s), nbttagcompound1.getInt(s));
 | 
			
		||||
             this.recipesUsed.put(ResourceLocation.parse(s), nbttagcompound1.getInt(s));
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
+        // Paper start - cook speed multiplier API
 | 
			
		||||
| 
						 | 
				
			
			@ -83,13 +83,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
 
 | 
			
		||||
-    private static int getTotalCookTime(Level world, AbstractFurnaceBlockEntity furnace) {
 | 
			
		||||
-        if (world == null) return 200; // CraftBukkit - SPIGOT-4302
 | 
			
		||||
-        return (Integer) furnace.quickCheck.getRecipeFor(furnace, world).map((recipeholder) -> {
 | 
			
		||||
+    private static int getTotalCookTime(@Nullable Level world, RecipeType<? extends AbstractCookingRecipe> recipeType, AbstractFurnaceBlockEntity furnace, double cookSpeedMultiplier) { // Paper - cook speed multiplier API
 | 
			
		||||
         SingleRecipeInput singlerecipeinput = new SingleRecipeInput(furnace.getItem(0));
 | 
			
		||||
 
 | 
			
		||||
-        return (Integer) furnace.quickCheck.getRecipeFor(singlerecipeinput, world).map((recipeholder) -> {
 | 
			
		||||
-            return ((AbstractCookingRecipe) recipeholder.value()).getCookingTime();
 | 
			
		||||
-        }).orElse(200);
 | 
			
		||||
+    // Paper start - cook speed multiplier API
 | 
			
		||||
+    public static int getTotalCookTime(@Nullable Level world, RecipeType<? extends AbstractCookingRecipe> recipeType, AbstractFurnaceBlockEntity furnace, double cookSpeedMultiplier) {
 | 
			
		||||
+        // Paper start - cook speed multiplier API
 | 
			
		||||
+        /* Scale the recipe's cooking time to the current cookSpeedMultiplier */
 | 
			
		||||
+        int cookTime = world != null ? furnace.quickCheck.getRecipeFor(furnace, world).map(holder -> holder.value().getCookingTime()).orElse(200) : (net.minecraft.server.MinecraftServer.getServer().getRecipeManager().getRecipeFor(recipeType, furnace, world /* passing a null level here is safe. world is only used for map extending recipes which won't happen here */).map(holder -> holder.value().getCookingTime()).orElse(200));
 | 
			
		||||
+        int cookTime = world != null ? furnace.quickCheck.getRecipeFor(singlerecipeinput, world).map(holder -> holder.value().getCookingTime()).orElse(200) : (net.minecraft.server.MinecraftServer.getServer().getRecipeManager().getRecipeFor(recipeType, singlerecipeinput, world /* passing a null level here is safe. world is only used for map extending recipes which won't happen here */).map(holder -> holder.value().getCookingTime()).orElse(200));
 | 
			
		||||
+        return (int) Math.ceil (cookTime / cookSpeedMultiplier);
 | 
			
		||||
+        // Paper end - cook speed multiplier API
 | 
			
		||||
     }
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/ma
 | 
			
		|||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
 | 
			
		||||
     private int containerCounter;
 | 
			
		||||
     public boolean wonGame;
 | 
			
		||||
     private int containerUpdateDelay; // Paper - Configurable container update tick rate
 | 
			
		||||
| 
						 | 
				
			
			@ -33,7 +33,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
 
 | 
			
		||||
     // CraftBukkit start
 | 
			
		||||
     public CraftPlayer.TransferCookieConnection transferCookieConnection;
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
 | 
			
		||||
 
 | 
			
		||||
     @Override
 | 
			
		||||
     public void die(DamageSource damageSource) {
 | 
			
		||||
| 
						 | 
				
			
			@ -42,7 +42,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
         boolean flag = this.level().getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES);
 | 
			
		||||
         // CraftBukkit start - fire PlayerDeathEvent
 | 
			
		||||
         if (this.isRemoved()) {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
 | 
			
		||||
         String deathmessage = defaultMessage.getString();
 | 
			
		||||
         this.keepLevel = keepInventory; // SPIGOT-2222: pre-set keepLevel
 | 
			
		||||
         org.bukkit.event.entity.PlayerDeathEvent event = CraftEventFactory.callPlayerDeathEvent(this, damageSource, loot, PaperAdventure.asAdventure(defaultMessage), keepInventory); // Paper - Adventure
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +59,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
 
 | 
			
		||||
         // SPIGOT-943 - only call if they have an inventory open
 | 
			
		||||
         if (this.containerMenu != this.inventoryMenu) {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
 | 
			
		||||
                         }
 | 
			
		||||
                     }
 | 
			
		||||
                 }
 | 
			
		||||
| 
						 | 
				
			
			@ -131,7 +131,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
+                // Paper - move below into if for onKill
 | 
			
		||||
+
 | 
			
		||||
+                // Paper start
 | 
			
		||||
+                org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(damageSource);
 | 
			
		||||
+                org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(worldserver, damageSource);
 | 
			
		||||
+                if (deathEvent == null || !deathEvent.isCancelled()) {
 | 
			
		||||
+                    if (this.deathScore >= 0 && entityliving != null) {
 | 
			
		||||
+                        entityliving.awardKillScore(this, this.deathScore, damageSource);
 | 
			
		||||
| 
						 | 
				
			
			@ -148,32 +148,31 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
+                    if (this.isSleeping()) {
 | 
			
		||||
+                        this.stopSleeping();
 | 
			
		||||
+                    }
 | 
			
		||||
+
 | 
			
		||||
 
 | 
			
		||||
-                if (entity == null || entity.killedEntity(worldserver, this)) {
 | 
			
		||||
+                    if (!this.level().isClientSide && this.hasCustomName()) {
 | 
			
		||||
+                        if (org.spigotmc.SpigotConfig.logNamedDeaths) LivingEntity.LOGGER.info("Named entity {} died: {}", this, this.getCombatTracker().getDeathMessage().getString()); // Spigot
 | 
			
		||||
+                    }
 | 
			
		||||
 
 | 
			
		||||
-                if (entity == null || entity.killedEntity(worldserver, this)) {
 | 
			
		||||
+
 | 
			
		||||
+                    this.getCombatTracker().recheckStatus();
 | 
			
		||||
+                    if (entity != null) {
 | 
			
		||||
+                        entity.killedEntity((ServerLevel) this.level(), this);
 | 
			
		||||
+                    }
 | 
			
		||||
                     this.gameEvent(GameEvent.ENTITY_DIE);
 | 
			
		||||
-                    this.dropAllDeathLoot(damageSource);
 | 
			
		||||
-                    this.createWitherRose(entityliving);
 | 
			
		||||
-                    this.dropAllDeathLoot(worldserver, damageSource);
 | 
			
		||||
+                } else {
 | 
			
		||||
+                    this.dead = false;
 | 
			
		||||
+                    this.setHealth((float) deathEvent.getReviveHealth());
 | 
			
		||||
                 }
 | 
			
		||||
 
 | 
			
		||||
-                this.level().broadcastEntityEvent(this, (byte) 3);
 | 
			
		||||
+                }
 | 
			
		||||
+                // Paper end
 | 
			
		||||
+                this.createWitherRose(entityliving);
 | 
			
		||||
             }
 | 
			
		||||
                     this.createWitherRose(entityliving);
 | 
			
		||||
                 }
 | 
			
		||||
 
 | 
			
		||||
+            // Paper start
 | 
			
		||||
+            if (this.dead) { // Paper
 | 
			
		||||
+                this.level().broadcastEntityEvent(this, (byte) 3);
 | 
			
		||||
                 this.level().broadcastEntityEvent(this, (byte) 3);
 | 
			
		||||
-            }
 | 
			
		||||
 
 | 
			
		||||
             this.setPose(Pose.DYING);
 | 
			
		||||
+            }
 | 
			
		||||
+            // Paper end
 | 
			
		||||
| 
						 | 
				
			
			@ -193,49 +192,47 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
         }
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    protected void dropAllDeathLoot(DamageSource source) {
 | 
			
		||||
-    protected void dropAllDeathLoot(ServerLevel world, DamageSource damageSource) {
 | 
			
		||||
+    // Paper start
 | 
			
		||||
+    protected boolean clearEquipmentSlots = true;
 | 
			
		||||
+    protected Set<EquipmentSlot> clearedEquipmentSlots = new java.util.HashSet<>();
 | 
			
		||||
+    protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(DamageSource source) {
 | 
			
		||||
+    // Paper end
 | 
			
		||||
         Entity entity = source.getEntity();
 | 
			
		||||
         int i;
 | 
			
		||||
+    protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(ServerLevel world, DamageSource damageSource) {
 | 
			
		||||
+        // Paper end
 | 
			
		||||
         boolean flag = this.lastHurtByPlayerTime > 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
 | 
			
		||||
         this.dropEquipment(); // CraftBukkit - from below
 | 
			
		||||
         if (this.shouldDropLoot() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
 | 
			
		||||
             this.dropFromLootTable(source, flag);
 | 
			
		||||
         if (this.shouldDropLoot() && world.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
 | 
			
		||||
             this.dropFromLootTable(damageSource, flag);
 | 
			
		||||
+            // Paper start
 | 
			
		||||
+            final boolean prev = this.clearEquipmentSlots;
 | 
			
		||||
+            this.clearEquipmentSlots = false;
 | 
			
		||||
+            this.clearedEquipmentSlots.clear();
 | 
			
		||||
+            // Paper end
 | 
			
		||||
             this.dropCustomDeathLoot(source, i, flag);
 | 
			
		||||
             this.dropCustomDeathLoot(world, damageSource, flag);
 | 
			
		||||
+            this.clearEquipmentSlots = prev; // Paper
 | 
			
		||||
         }
 | 
			
		||||
         // CraftBukkit start - Call death event
 | 
			
		||||
-        CraftEventFactory.callEntityDeathEvent(this, source, this.drops);
 | 
			
		||||
+        org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, source, this.drops); // Paper
 | 
			
		||||
-        CraftEventFactory.callEntityDeathEvent(this, damageSource, this.drops);
 | 
			
		||||
+        org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, damageSource, this.drops); // Paper
 | 
			
		||||
+        this.postDeathDropItems(deathEvent); // Paper
 | 
			
		||||
         this.drops = new ArrayList<>();
 | 
			
		||||
         // CraftBukkit end
 | 
			
		||||
 
 | 
			
		||||
         // this.dropInventory();// CraftBukkit - moved up
 | 
			
		||||
         this.dropExperience();
 | 
			
		||||
         // this.dropEquipment();// CraftBukkit - moved up
 | 
			
		||||
         this.dropExperience(damageSource.getEntity());
 | 
			
		||||
+        return deathEvent; // Paper
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     protected void dropEquipment() {}
 | 
			
		||||
+    protected void postDeathDropItems(org.bukkit.event.entity.EntityDeathEvent event) {} // Paper - method for post death logic that cannot be ran before the event is potentially cancelled
 | 
			
		||||
 
 | 
			
		||||
     // CraftBukkit start
 | 
			
		||||
     public int getExpReward() {
 | 
			
		||||
     public int getExpReward(@Nullable Entity entity) { // CraftBukkit
 | 
			
		||||
         Level world = this.level();
 | 
			
		||||
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
 | 
			
		||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/world/entity/Mob.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
 | 
			
		||||
 
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
| 
						 | 
				
			
			@ -246,30 +243,30 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
+    // Paper end
 | 
			
		||||
+
 | 
			
		||||
     @Override
 | 
			
		||||
     protected void dropCustomDeathLoot(DamageSource source, int lootingMultiplier, boolean allowDrops) {
 | 
			
		||||
         super.dropCustomDeathLoot(source, lootingMultiplier, allowDrops);
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti
 | 
			
		||||
     protected void dropCustomDeathLoot(ServerLevel world, DamageSource source, boolean causedByPlayer) {
 | 
			
		||||
         super.dropCustomDeathLoot(world, source, causedByPlayer);
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
 | 
			
		||||
 
 | 
			
		||||
         for (int k = 0; k < j; ++k) {
 | 
			
		||||
             EquipmentSlot enumitemslot = aenumitemslot[k];
 | 
			
		||||
         for (int j = 0; j < i; ++j) {
 | 
			
		||||
             EquipmentSlot enumitemslot = aenumitemslot[j];
 | 
			
		||||
+            if (this.shouldSkipLoot(enumitemslot)) continue; // Paper
 | 
			
		||||
             ItemStack itemstack = this.getItemBySlot(enumitemslot);
 | 
			
		||||
             float f = this.getEquipmentDropChance(enumitemslot);
 | 
			
		||||
             boolean flag1 = f > 1.0F;
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti
 | 
			
		||||
                 }
 | 
			
		||||
 
 | 
			
		||||
                 this.spawnAtLocation(itemstack);
 | 
			
		||||
+                if (this.clearEquipmentSlots) { // Paper
 | 
			
		||||
                 this.setItemSlot(enumitemslot, ItemStack.EMPTY);
 | 
			
		||||
+                // Paper start
 | 
			
		||||
+                } else {
 | 
			
		||||
+                    this.clearedEquipmentSlots.add(enumitemslot);
 | 
			
		||||
+                }
 | 
			
		||||
+                // Paper end
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
 | 
			
		||||
                     }
 | 
			
		||||
 
 | 
			
		||||
                     this.spawnAtLocation(itemstack);
 | 
			
		||||
+                    if (this.clearEquipmentSlots) { // Paper
 | 
			
		||||
                     this.setItemSlot(enumitemslot, ItemStack.EMPTY);
 | 
			
		||||
+                    // Paper start
 | 
			
		||||
+                    } else {
 | 
			
		||||
+                        this.clearedEquipmentSlots.add(enumitemslot);
 | 
			
		||||
+                    }
 | 
			
		||||
+                    // Paper end
 | 
			
		||||
                 }
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java
 | 
			
		||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/world/entity/animal/Fox.java
 | 
			
		||||
| 
						 | 
				
			
			@ -280,7 +277,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
 
 | 
			
		||||
+    // Paper start - handle the bitten item separately like vanilla
 | 
			
		||||
     @Override
 | 
			
		||||
-    protected void dropAllDeathLoot(DamageSource source) {
 | 
			
		||||
-    protected void dropAllDeathLoot(ServerLevel world, DamageSource damageSource) {
 | 
			
		||||
+    protected boolean shouldSkipLoot(EquipmentSlot slot) {
 | 
			
		||||
+        return slot == EquipmentSlot.MAINHAND;
 | 
			
		||||
+    }
 | 
			
		||||
| 
						 | 
				
			
			@ -288,7 +285,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
+
 | 
			
		||||
+    @Override
 | 
			
		||||
+    // Paper start - Cancellable death event
 | 
			
		||||
+    protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(DamageSource source) {
 | 
			
		||||
+    protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(ServerLevel world, DamageSource damageSource) {
 | 
			
		||||
         ItemStack itemstack = this.getItemBySlot(EquipmentSlot.MAINHAND);
 | 
			
		||||
 
 | 
			
		||||
-        if (!itemstack.isEmpty()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -298,7 +295,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
+            releaseMouth = true;
 | 
			
		||||
+        }
 | 
			
		||||
+
 | 
			
		||||
+        org.bukkit.event.entity.EntityDeathEvent deathEvent = super.dropAllDeathLoot(source);
 | 
			
		||||
+        org.bukkit.event.entity.EntityDeathEvent deathEvent = super.dropAllDeathLoot(world, damageSource);
 | 
			
		||||
+
 | 
			
		||||
+        // Below is code to drop
 | 
			
		||||
+
 | 
			
		||||
| 
						 | 
				
			
			@ -311,7 +308,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
             this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY);
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
-        super.dropAllDeathLoot(source);
 | 
			
		||||
-        super.dropAllDeathLoot(world, damageSource);
 | 
			
		||||
+        return deathEvent; // Paper - Cancellable death event
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
| 
						 | 
				
			
			@ -343,38 +340,38 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ArmorStand extends LivingEntity {
 | 
			
		||||
                 }
 | 
			
		||||
                 // CraftBukkit end
 | 
			
		||||
                 if (source.is(DamageTypeTags.IS_EXPLOSION)) {
 | 
			
		||||
-                    this.brokenByAnything(source);
 | 
			
		||||
-                    this.kill(source); // CraftBukkit
 | 
			
		||||
+                    // Paper start - avoid duplicate event call
 | 
			
		||||
+                    org.bukkit.event.entity.EntityDeathEvent event = this.brokenByAnything(source);
 | 
			
		||||
+                    if (!event.isCancelled()) this.kill(source, false); // CraftBukkit
 | 
			
		||||
+                    // Paper end
 | 
			
		||||
                     return false;
 | 
			
		||||
                 } else if (source.is(DamageTypeTags.IGNITES_ARMOR_STANDS)) {
 | 
			
		||||
                     if (this.isOnFire()) {
 | 
			
		||||
                     }
 | 
			
		||||
                     // CraftBukkit end
 | 
			
		||||
                     if (source.is(DamageTypeTags.IS_EXPLOSION)) {
 | 
			
		||||
-                        this.brokenByAnything(worldserver, source);
 | 
			
		||||
-                        this.kill(source); // CraftBukkit
 | 
			
		||||
+                        // Paper start - avoid duplicate event call
 | 
			
		||||
+                        org.bukkit.event.entity.EntityDeathEvent event = this.brokenByAnything(worldserver, source);
 | 
			
		||||
+                        if (!event.isCancelled()) this.kill(source, false); // CraftBukkit
 | 
			
		||||
+                        // Paper end
 | 
			
		||||
                         return false;
 | 
			
		||||
                     } else if (source.is(DamageTypeTags.IGNITES_ARMOR_STANDS)) {
 | 
			
		||||
                         if (this.isOnFire()) {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ArmorStand extends LivingEntity {
 | 
			
		||||
                                 this.gameEvent(GameEvent.ENTITY_DAMAGE, source.getEntity());
 | 
			
		||||
                                 this.lastHit = i;
 | 
			
		||||
                             } else {
 | 
			
		||||
-                                this.brokenByPlayer(source);
 | 
			
		||||
+                                org.bukkit.event.entity.EntityDeathEvent event = this.brokenByPlayer(source); // Paper
 | 
			
		||||
                                 this.showBreakingParticles();
 | 
			
		||||
-                                this.discard(EntityRemoveEvent.Cause.DEATH); // CraftBukkit - SPIGOT-4890: remain as this.discard() since above damagesource method will call death event
 | 
			
		||||
+                                if (!event.isCancelled()) this.kill(source, false); // Paper - we still need to kill to follow vanilla logic (emit the game event etc...)
 | 
			
		||||
                             }
 | 
			
		||||
                                     this.gameEvent(GameEvent.ENTITY_DAMAGE, source.getEntity());
 | 
			
		||||
                                     this.lastHit = i;
 | 
			
		||||
                                 } else {
 | 
			
		||||
-                                    this.brokenByPlayer(worldserver, source);
 | 
			
		||||
+                                    org.bukkit.event.entity.EntityDeathEvent event = this.brokenByPlayer(worldserver, source); // Paper
 | 
			
		||||
                                     this.showBreakingParticles();
 | 
			
		||||
-                                    this.discard(EntityRemoveEvent.Cause.DEATH); // CraftBukkit - SPIGOT-4890: remain as this.discard() since above damagesource method will call death event
 | 
			
		||||
+                                    if (!event.isCancelled()) this.kill(source, false); // Paper - we still need to kill to follow vanilla logic (emit the game event etc...)
 | 
			
		||||
                                 }
 | 
			
		||||
 
 | 
			
		||||
                             return true;
 | 
			
		||||
                                 return true;
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ArmorStand extends LivingEntity {
 | 
			
		||||
 
 | 
			
		||||
         f1 -= amount;
 | 
			
		||||
         if (f1 <= 0.5F) {
 | 
			
		||||
-            this.brokenByAnything(damageSource);
 | 
			
		||||
-            this.brokenByAnything(world, damageSource);
 | 
			
		||||
-            this.kill(damageSource); // CraftBukkit
 | 
			
		||||
+            // Paper start - avoid duplicate event call
 | 
			
		||||
+            org.bukkit.event.entity.EntityDeathEvent event = this.brokenByAnything(damageSource);
 | 
			
		||||
+            org.bukkit.event.entity.EntityDeathEvent event = this.brokenByAnything(world, damageSource);
 | 
			
		||||
+            if (!event.isCancelled()) this.kill(damageSource, false); // CraftBukkit
 | 
			
		||||
+            // Paper end
 | 
			
		||||
         } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -384,27 +381,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
 
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private void brokenByPlayer(DamageSource damageSource) {
 | 
			
		||||
+    private org.bukkit.event.entity.EntityDeathEvent brokenByPlayer(DamageSource damageSource) { // Paper
 | 
			
		||||
-    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());
 | 
			
		||||
         this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops
 | 
			
		||||
-        this.brokenByAnything(damageSource);
 | 
			
		||||
+        return this.brokenByAnything(damageSource); // Paper
 | 
			
		||||
-        this.brokenByAnything(world, damageSource);
 | 
			
		||||
+        return this.brokenByAnything(world, damageSource); // Paper
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
-    private void brokenByAnything(DamageSource damageSource) {
 | 
			
		||||
+    private org.bukkit.event.entity.EntityDeathEvent brokenByAnything(DamageSource 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(damagesource); // CraftBukkit - moved down
 | 
			
		||||
         // this.dropAllDeathLoot(worldserver, damagesource); // CraftBukkit - moved down
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ArmorStand extends LivingEntity {
 | 
			
		||||
                 this.armorItems.set(i, ItemStack.EMPTY);
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
-        this.dropAllDeathLoot(damageSource); // CraftBukkit - moved from above
 | 
			
		||||
+        return this.dropAllDeathLoot(damageSource); // CraftBukkit - moved from above // Paper
 | 
			
		||||
-        this.dropAllDeathLoot(world, damageSource); // CraftBukkit - moved from above
 | 
			
		||||
+        return this.dropAllDeathLoot(world, damageSource); // CraftBukkit - moved from above // Paper
 | 
			
		||||
 
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
| 
						 | 
				
			
			@ -452,7 +449,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
@@ -0,0 +0,0 @@ public class CraftEventFactory {
 | 
			
		||||
         CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity();
 | 
			
		||||
         CraftDamageSource bukkitDamageSource = new CraftDamageSource(damageSource);
 | 
			
		||||
         EntityDeathEvent event = new EntityDeathEvent(entity, bukkitDamageSource, drops, victim.getExpReward());
 | 
			
		||||
         EntityDeathEvent event = new EntityDeathEvent(entity, bukkitDamageSource, drops, victim.getExpReward(damageSource.getEntity()));
 | 
			
		||||
+        populateFields(victim, event); // Paper - make cancellable
 | 
			
		||||
         CraftWorld world = (CraftWorld) entity.getWorld();
 | 
			
		||||
         Bukkit.getServer().getPluginManager().callEvent(event);
 | 
			
		||||
| 
						 | 
				
			
			@ -467,7 +464,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
 
 | 
			
		||||
         for (org.bukkit.inventory.ItemStack stack : event.getDrops()) {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class CraftEventFactory {
 | 
			
		||||
         PlayerDeathEvent event = new PlayerDeathEvent(entity, bukkitDamageSource, drops, victim.getExpReward(), 0, deathMessage);
 | 
			
		||||
         PlayerDeathEvent event = new PlayerDeathEvent(entity, bukkitDamageSource, drops, victim.getExpReward(damageSource.getEntity()), 0, deathMessage);
 | 
			
		||||
         event.setKeepInventory(keepInventory);
 | 
			
		||||
         event.setKeepLevel(victim.keepLevel); // SPIGOT-2222: pre-set keepLevel
 | 
			
		||||
+        populateFields(victim, event); // Paper - make cancellable
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
+import net.minecraft.world.item.crafting.Ingredient;
 | 
			
		||||
+import net.minecraft.world.item.crafting.Recipe;
 | 
			
		||||
+
 | 
			
		||||
+public abstract class RecipeBookExactChoiceRecipe<C extends Container> implements Recipe<C> {
 | 
			
		||||
+public abstract class RecipeBookExactChoiceRecipe<C extends net.minecraft.world.item.crafting.RecipeInput> implements Recipe<C> {
 | 
			
		||||
+
 | 
			
		||||
+    private boolean hasExactIngredients;
 | 
			
		||||
+
 | 
			
		||||
| 
						 | 
				
			
			@ -146,15 +146,15 @@ diff --git a/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java b/src
 | 
			
		|||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlaceRecipe<C extends Container> implements PlaceRecipe<Integ
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlaceRecipe<I extends RecipeInput, R extends Recipe<I>> imple
 | 
			
		||||
             this.inventory = entity.getInventory();
 | 
			
		||||
             if (this.testClearGrid() || entity.isCreative()) {
 | 
			
		||||
                 this.stackedContents.clear();
 | 
			
		||||
+                this.stackedContents.initialize(recipe.value()); // Paper - Improve exact choice recipe ingredients
 | 
			
		||||
                 entity.getInventory().fillStackedContents(this.stackedContents);
 | 
			
		||||
                 this.menu.fillCraftSlotsStackedContents(this.stackedContents);
 | 
			
		||||
                 if (this.stackedContents.canCraft((Recipe<?>)recipe.value(), null)) {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlaceRecipe<C extends Container> implements PlaceRecipe<Integ
 | 
			
		||||
                 if (this.stackedContents.canCraft(recipe.value(), null)) {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlaceRecipe<I extends RecipeInput, R extends Recipe<I>> imple
 | 
			
		||||
             int l = k;
 | 
			
		||||
 
 | 
			
		||||
             for (int m : intList) {
 | 
			
		||||
| 
						 | 
				
			
			@ -163,46 +163,48 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
                 if (!itemStack2.isEmpty()) {
 | 
			
		||||
                     int n = itemStack2.getMaxStackSize();
 | 
			
		||||
                     if (n < l) {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlaceRecipe<C extends Container> implements PlaceRecipe<Integ
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlaceRecipe<I extends RecipeInput, R extends Recipe<I>> imple
 | 
			
		||||
     @Override
 | 
			
		||||
     public void addItemToSlot(Iterator<Integer> inputs, int slot, int amount, int gridX, int gridY) {
 | 
			
		||||
     public void addItemToSlot(Integer input, int slot, int amount, int gridX, int gridY) {
 | 
			
		||||
         Slot slot2 = this.menu.getSlot(slot);
 | 
			
		||||
-        ItemStack itemStack = StackedContents.fromStackingIndex(inputs.next());
 | 
			
		||||
-        ItemStack itemStack = StackedContents.fromStackingIndex(input);
 | 
			
		||||
+        // Paper start - Improve exact choice recipe ingredients
 | 
			
		||||
+        final int itemId = inputs.next();
 | 
			
		||||
+        ItemStack itemStack = null;
 | 
			
		||||
+        boolean isExact = false;
 | 
			
		||||
+        if (this.stackedContents.extrasMap != null && itemId >= net.minecraft.core.registries.BuiltInRegistries.ITEM.size()) {
 | 
			
		||||
+            itemStack = StackedContents.fromStackingIndexExtras(itemId, this.stackedContents.extrasMap).copy();
 | 
			
		||||
+        if (this.stackedContents.extrasMap != null && input >= net.minecraft.core.registries.BuiltInRegistries.ITEM.size()) {
 | 
			
		||||
+            itemStack = StackedContents.fromStackingIndexExtras(input, this.stackedContents.extrasMap).copy();
 | 
			
		||||
+            isExact = true;
 | 
			
		||||
+        }
 | 
			
		||||
+        if (itemStack == null) {
 | 
			
		||||
+            itemStack = StackedContents.fromStackingIndex(itemId);
 | 
			
		||||
+            itemStack = StackedContents.fromStackingIndex(input);
 | 
			
		||||
+        }
 | 
			
		||||
+        // Paper end - Improve exact choice recipe ingredients
 | 
			
		||||
         if (!itemStack.isEmpty()) {
 | 
			
		||||
             for (int i = 0; i < amount; i++) {
 | 
			
		||||
-                this.moveItemToGrid(slot2, itemStack);
 | 
			
		||||
+                this.moveItemToGrid(slot2, itemStack, isExact); // Paper - Improve exact choice recipe ingredients
 | 
			
		||||
             }
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlaceRecipe<C extends Container> implements PlaceRecipe<Integ
 | 
			
		||||
             int i = amount;
 | 
			
		||||
 
 | 
			
		||||
             while (i > 0) {
 | 
			
		||||
-                i = this.moveItemToGrid(slot2, itemStack, i);
 | 
			
		||||
+                i = this.moveItemToGrid(slot2, itemStack, i, isExact); // Paper - Improve exact choice recipe ingredients
 | 
			
		||||
                 if (i == -1) {
 | 
			
		||||
                     return;
 | 
			
		||||
                 }
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlaceRecipe<I extends RecipeInput, R extends Recipe<I>> imple
 | 
			
		||||
         return i;
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
+    @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Improve exact choice recipe ingredients
 | 
			
		||||
     protected void moveItemToGrid(Slot slot, ItemStack stack) {
 | 
			
		||||
-        int i = this.inventory.findSlotMatchingUnusedItem(stack);
 | 
			
		||||
+
 | 
			
		||||
     protected int moveItemToGrid(Slot slot, ItemStack stack, int i) {
 | 
			
		||||
-        int j = this.inventory.findSlotMatchingUnusedItem(stack);
 | 
			
		||||
+        // Paper start - Improve exact choice recipe ingredients
 | 
			
		||||
+        this.moveItemToGrid(slot, stack, false);
 | 
			
		||||
+        return this.moveItemToGrid(slot, stack, i, false);
 | 
			
		||||
+    }
 | 
			
		||||
+    protected void moveItemToGrid(Slot slot, ItemStack stack, final boolean isExact) {
 | 
			
		||||
+        int i = isExact ? this.inventory.findSlotMatchingItem(stack) : this.inventory.findSlotMatchingUnusedItem(stack);
 | 
			
		||||
+    protected int moveItemToGrid(Slot slot, ItemStack stack, int i, final boolean isExact) {
 | 
			
		||||
+        int j = isExact ? this.inventory.findSlotMatchingItem(stack) : this.inventory.findSlotMatchingUnusedItem(stack);
 | 
			
		||||
+        // Paper end - Improve exact choice recipe ingredients
 | 
			
		||||
         if (i != -1) {
 | 
			
		||||
             ItemStack itemStack = this.inventory.getItem(i);
 | 
			
		||||
             if (!itemStack.isEmpty()) {
 | 
			
		||||
         if (j == -1) {
 | 
			
		||||
             return -1;
 | 
			
		||||
         } else {
 | 
			
		||||
diff --git a/src/main/java/net/minecraft/world/entity/player/StackedContents.java b/src/main/java/net/minecraft/world/entity/player/StackedContents.java
 | 
			
		||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/world/entity/player/StackedContents.java
 | 
			
		||||
| 
						 | 
				
			
			@ -299,16 +301,16 @@ diff --git a/src/main/java/net/minecraft/world/item/crafting/AbstractCookingReci
 | 
			
		|||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/world/item/crafting/AbstractCookingRecipe.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/world/item/crafting/AbstractCookingRecipe.java
 | 
			
		||||
@@ -0,0 +0,0 @@ import net.minecraft.world.Container;
 | 
			
		||||
@@ -0,0 +0,0 @@ import net.minecraft.core.NonNullList;
 | 
			
		||||
 import net.minecraft.world.item.ItemStack;
 | 
			
		||||
 import net.minecraft.world.level.Level;
 | 
			
		||||
 
 | 
			
		||||
-public abstract class AbstractCookingRecipe implements Recipe<Container> {
 | 
			
		||||
+public abstract class AbstractCookingRecipe extends io.papermc.paper.inventory.recipe.RecipeBookExactChoiceRecipe<Container> implements Recipe<Container> { // Paper - improve exact recipe choices
 | 
			
		||||
-public abstract class AbstractCookingRecipe implements Recipe<SingleRecipeInput> {
 | 
			
		||||
+public abstract class AbstractCookingRecipe extends io.papermc.paper.inventory.recipe.RecipeBookExactChoiceRecipe<SingleRecipeInput> implements Recipe<SingleRecipeInput> { // Paper - improve exact recipe choices
 | 
			
		||||
     protected final RecipeType<?> type;
 | 
			
		||||
     protected final CookingBookCategory category;
 | 
			
		||||
     protected final String group;
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class AbstractCookingRecipe implements Recipe<Container> {
 | 
			
		||||
@@ -0,0 +0,0 @@ public abstract class AbstractCookingRecipe implements Recipe<SingleRecipeInput>
 | 
			
		||||
         this.result = result;
 | 
			
		||||
         this.experience = experience;
 | 
			
		||||
         this.cookingTime = cookingTime;
 | 
			
		||||
| 
						 | 
				
			
			@ -320,7 +322,7 @@ diff --git a/src/main/java/net/minecraft/world/item/crafting/Recipe.java b/src/m
 | 
			
		|||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/world/item/crafting/Recipe.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/world/item/crafting/Recipe.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public interface Recipe<C extends Container> {
 | 
			
		||||
@@ -0,0 +0,0 @@ public interface Recipe<T extends RecipeInput> {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id); // CraftBukkit
 | 
			
		||||
| 
						 | 
				
			
			@ -340,7 +342,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
 // CraftBukkit end
 | 
			
		||||
 
 | 
			
		||||
-public class ShapedRecipe implements CraftingRecipe {
 | 
			
		||||
+public class ShapedRecipe extends io.papermc.paper.inventory.recipe.RecipeBookExactChoiceRecipe<CraftingContainer> implements CraftingRecipe { // Paper - improve exact recipe choices
 | 
			
		||||
+public class ShapedRecipe extends io.papermc.paper.inventory.recipe.RecipeBookExactChoiceRecipe<CraftingInput> implements CraftingRecipe { // Paper - improve exact recipe choices
 | 
			
		||||
 
 | 
			
		||||
     final ShapedRecipePattern pattern;
 | 
			
		||||
     final ItemStack result;
 | 
			
		||||
| 
						 | 
				
			
			@ -361,7 +363,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
 // CraftBukkit end
 | 
			
		||||
 
 | 
			
		||||
-public class ShapelessRecipe implements CraftingRecipe {
 | 
			
		||||
+public class ShapelessRecipe extends io.papermc.paper.inventory.recipe.RecipeBookExactChoiceRecipe<CraftingContainer> implements CraftingRecipe { // Paper - improve exact recipe choices
 | 
			
		||||
+public class ShapelessRecipe extends io.papermc.paper.inventory.recipe.RecipeBookExactChoiceRecipe<CraftingInput> implements CraftingRecipe { // Paper - improve exact recipe choices
 | 
			
		||||
 
 | 
			
		||||
     final String group;
 | 
			
		||||
     final CraftingBookCategory category;
 | 
			
		||||
| 
						 | 
				
			
			@ -374,10 +376,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
 
 | 
			
		||||
     // CraftBukkit start
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ShapelessRecipe implements CraftingRecipe {
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
     public boolean matches(CraftingContainer inventory, Level world) {
 | 
			
		||||
         StackedContents autorecipestackmanager = new StackedContents();
 | 
			
		||||
+        autorecipestackmanager.initialize(this); // Paper - better exact choice recipes
 | 
			
		||||
         int i = 0;
 | 
			
		||||
     public boolean matches(CraftingInput input, Level world) {
 | 
			
		||||
-        return input.ingredientCount() != this.ingredients.size() ? false : (input.size() == 1 && this.ingredients.size() == 1 ? ((Ingredient) this.ingredients.getFirst()).test(input.getItem(0)) : input.stackedContents().canCraft(this, (IntList) null));
 | 
			
		||||
+        // Paper start - unwrap ternary & better exact choice recipes
 | 
			
		||||
+        if (input.ingredientCount() != this.ingredients.size()) {
 | 
			
		||||
+            return false;
 | 
			
		||||
+        }
 | 
			
		||||
+        if (input.size() == 1 && this.ingredients.size() == 1) {
 | 
			
		||||
+            return this.ingredients.getFirst().test(input.getItem(0));
 | 
			
		||||
+        }
 | 
			
		||||
+        input.stackedContents().initialize(this); // setup stacked contents for this recipe
 | 
			
		||||
+        return input.stackedContents().canCraft(this, null);
 | 
			
		||||
+        // Paper end - unwrap ternary & better exact choice recipes
 | 
			
		||||
     }
 | 
			
		||||
 
 | 
			
		||||
         for (int j = 0; j < inventory.getContainerSize(); ++j) {
 | 
			
		||||
     public ItemStack assemble(CraftingInput input, HolderLookup.Provider lookup) {
 | 
			
		||||
| 
						 | 
				
			
			@ -32,7 +32,7 @@ diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/ma
 | 
			
		|||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
 | 
			
		||||
         }
 | 
			
		||||
         // Paper end - Configurable container update tick rate
 | 
			
		||||
         if (!this.level().isClientSide && !this.containerMenu.stillValid(this)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -41,7 +41,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
             this.containerMenu = this.inventoryMenu;
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
 | 
			
		||||
 
 | 
			
		||||
         // SPIGOT-943 - only call if they have an inventory open
 | 
			
		||||
         if (this.containerMenu != this.inventoryMenu) {
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +50,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
         }
 | 
			
		||||
 
 | 
			
		||||
         net.kyori.adventure.text.Component deathMessage = event.deathMessage() != null ? event.deathMessage() : net.kyori.adventure.text.Component.empty(); // Paper - Adventure
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
 | 
			
		||||
         }
 | 
			
		||||
         // CraftBukkit end
 | 
			
		||||
         if (this.containerMenu != this.inventoryMenu) {
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +59,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
         }
 | 
			
		||||
 
 | 
			
		||||
         // this.nextContainerCounter(); // CraftBukkit - moved up
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
 | 
			
		||||
 
 | 
			
		||||
     @Override
 | 
			
		||||
     public void closeContainer() {
 | 
			
		||||
| 
						 | 
				
			
			@ -12,8 +12,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
         if (this.isUsingItem() && !this.useItem.isEmpty()) {
 | 
			
		||||
             Item item = this.useItem.getItem();
 | 
			
		||||
 
 | 
			
		||||
-            return item.getUseAnimation(this.useItem) != UseAnim.BLOCK ? false : item.getUseDuration(this.useItem) - this.useItemRemaining >= 5;
 | 
			
		||||
+            return item.getUseAnimation(this.useItem) != UseAnim.BLOCK ? false : item.getUseDuration(this.useItem) - this.useItemRemaining >= getShieldBlockingDelay(); // Paper - Make shield blocking delay configurable
 | 
			
		||||
-            return item.getUseAnimation(this.useItem) != UseAnim.BLOCK ? false : item.getUseDuration(this.useItem, this) - this.useItemRemaining >= 5;
 | 
			
		||||
+            return item.getUseAnimation(this.useItem) != UseAnim.BLOCK ? false : item.getUseDuration(this.useItem, this) - this.useItemRemaining >= getShieldBlockingDelay(); // Paper - Make shield blocking delay configurable
 | 
			
		||||
         } else {
 | 
			
		||||
             return false;
 | 
			
		||||
         }
 | 
			
		||||
| 
						 | 
				
			
			@ -291,29 +291,29 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
--- a/src/main/java/net/minecraft/world/item/TridentItem.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/world/item/TridentItem.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public class TridentItem extends Item implements ProjectileItem {
 | 
			
		||||
                             }
 | 
			
		||||
 
 | 
			
		||||
                             // CraftBukkit start
 | 
			
		||||
-                            if (!world.addFreshEntity(entitythrowntrident)) {
 | 
			
		||||
+                            // Paper start - PlayerLaunchProjectileEvent
 | 
			
		||||
+                            com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), (org.bukkit.entity.Projectile) entitythrowntrident.getBukkitEntity());
 | 
			
		||||
+                            if (!event.callEvent() || !world.addFreshEntity(entitythrowntrident)) {
 | 
			
		||||
+                                // Paper end - PlayerLaunchProjectileEvent
 | 
			
		||||
                                 if (entityhuman instanceof net.minecraft.server.level.ServerPlayer) {
 | 
			
		||||
                                     ((net.minecraft.server.level.ServerPlayer) entityhuman).getBukkitEntity().updateInventory();
 | 
			
		||||
                                 }
 | 
			
		||||
                                 return;
 | 
			
		||||
                             }
 | 
			
		||||
 
 | 
			
		||||
+                            if (event.shouldConsume()) { // Paper - PlayerLaunchProjectileEvent
 | 
			
		||||
                             stack.hurtAndBreak(1, entityhuman, LivingEntity.getSlotForHand(user.getUsedItemHand()));
 | 
			
		||||
+                            } // Paper - PlayerLaunchProjectileEvent
 | 
			
		||||
                             entitythrowntrident.pickupItemStack = stack.copy(); // SPIGOT-4511 update since damage call moved
 | 
			
		||||
                             // CraftBukkit end
 | 
			
		||||
                                 // CraftBukkit start
 | 
			
		||||
-                                if (!world.addFreshEntity(entitythrowntrident)) {
 | 
			
		||||
+                                // Paper start - PlayerLaunchProjectileEvent
 | 
			
		||||
+                                com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), (org.bukkit.entity.Projectile) entitythrowntrident.getBukkitEntity());
 | 
			
		||||
+                                if (!event.callEvent() || !world.addFreshEntity(entitythrowntrident)) {
 | 
			
		||||
+                                    // Paper end - PlayerLaunchProjectileEvent
 | 
			
		||||
                                     if (entityhuman instanceof net.minecraft.server.level.ServerPlayer) {
 | 
			
		||||
                                         ((net.minecraft.server.level.ServerPlayer) entityhuman).getBukkitEntity().updateInventory();
 | 
			
		||||
                                     }
 | 
			
		||||
                                     return;
 | 
			
		||||
                                 }
 | 
			
		||||
 
 | 
			
		||||
                             world.playSound((Player) null, (Entity) entitythrowntrident, SoundEvents.TRIDENT_THROW, SoundSource.PLAYERS, 1.0F, 1.0F);
 | 
			
		||||
-                            if (!entityhuman.hasInfiniteMaterials()) {
 | 
			
		||||
+                            if (event.shouldConsume() && !entityhuman.hasInfiniteMaterials()) {
 | 
			
		||||
                                 entityhuman.getInventory().removeItem(stack);
 | 
			
		||||
                             }
 | 
			
		||||
                             // CraftBukkit start - SPIGOT-5458 also need in this branch :(
 | 
			
		||||
+                                if (event.shouldConsume()) { // Paper - PlayerLaunchProjectileEvent
 | 
			
		||||
                                 stack.hurtAndBreak(1, entityhuman, LivingEntity.getSlotForHand(user.getUsedItemHand()));
 | 
			
		||||
+                                } // Paper - PlayerLaunchProjectileEvent
 | 
			
		||||
                                 entitythrowntrident.pickupItemStack = stack.copy(); // SPIGOT-4511 update since damage call moved
 | 
			
		||||
                                 // CraftBukkit end
 | 
			
		||||
 
 | 
			
		||||
                                 world.playSound((Player) null, (Entity) entitythrowntrident, (SoundEvent) holder.value(), SoundSource.PLAYERS, 1.0F, 1.0F);
 | 
			
		||||
-                                if (!entityhuman.hasInfiniteMaterials()) {
 | 
			
		||||
+                                if (event.shouldConsume() && !entityhuman.hasInfiniteMaterials()) { // Paper - PlayerLaunchProjectileEvent
 | 
			
		||||
                                     entityhuman.getInventory().removeItem(stack);
 | 
			
		||||
                                 }
 | 
			
		||||
                                 // CraftBukkit start - SPIGOT-5458 also need in this branch :(
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/ma
 | 
			
		|||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
 | 
			
		||||
     private int containerCounter;
 | 
			
		||||
     public boolean wonGame;
 | 
			
		||||
     private int containerUpdateDelay; // Paper - Configurable container update tick rate
 | 
			
		||||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/ma
 | 
			
		|||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
 | 
			
		||||
 
 | 
			
		||||
         this.setHealth(this.getMaxHealth());
 | 
			
		||||
         this.stopUsingItem(); // CraftBukkit - SPIGOT-6682: Clear active item on reset
 | 
			
		||||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonTrapG
 | 
			
		|||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonTrapGoal.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/world/entity/animal/horse/SkeletonTrapGoal.java
 | 
			
		||||
@@ -0,0 +0,0 @@ import net.minecraft.world.item.enchantment.ItemEnchantments;
 | 
			
		||||
@@ -0,0 +0,0 @@ import net.minecraft.world.item.enchantment.providers.VanillaEnchantmentProvider
 | 
			
		||||
 public class SkeletonTrapGoal extends Goal {
 | 
			
		||||
 
 | 
			
		||||
     private final SkeletonHorse horse;
 | 
			
		||||
| 
						 | 
				
			
			@ -12,14 +12,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 | 
			
		|||
                 }
 | 
			
		||||
 
 | 
			
		||||
                 if (holder != null) {
 | 
			
		||||
-                    this.setItemSlot(EquipmentSlot.MAINHAND, PotionContents.createItemStack(Items.POTION, holder));
 | 
			
		||||
+                    // Paper start
 | 
			
		||||
+                    ItemStack potion = PotionContents.createItemStack(Items.POTION, holder);
 | 
			
		||||
+                    potion = org.bukkit.craftbukkit.event.CraftEventFactory.handleWitchReadyPotionEvent(this, potion);
 | 
			
		||||
+                    this.setItemSlot(EquipmentSlot.MAINHAND, potion);
 | 
			
		||||
+                    // Paper end
 | 
			
		||||
                     this.setItemSlot(EquipmentSlot.MAINHAND, PotionContents.createItemStack(Items.POTION, holder));
 | 
			
		||||
                     this.usingTime = this.getMainHandItem().getUseDuration(this);
 | 
			
		||||
                     this.setUsingItem(true);
 | 
			
		||||
                     if (!this.isSilent()) {
 | 
			
		||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
 | 
			
		||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/ma
 | 
			
		|||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
 | 
			
		||||
     public void disconnect() {
 | 
			
		||||
         this.disconnected = true;
 | 
			
		||||
         this.ejectPassengers();
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/ma
 | 
			
		|||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
 | 
			
		||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
 | 
			
		||||
 
 | 
			
		||||
     @Override
 | 
			
		||||
     public void stopRiding() {
 | 
			
		||||
| 
						 | 
				
			
			@ -1,27 +0,0 @@
 | 
			
		|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Noah van der Aa <ndvdaa@gmail.com>
 | 
			
		||||
Date: Mon, 29 Apr 2024 23:12:33 +0200
 | 
			
		||||
Subject: [PATCH] Catch JsonParseException in block entity names
 | 
			
		||||
 | 
			
		||||
As a result, data that no longer parses correctly will not crash the server
 | 
			
		||||
instead just logging the exception and continuing (and in most cases should
 | 
			
		||||
fix the data)
 | 
			
		||||
 | 
			
		||||
Player data is fixed pretty much immediately but some block data (like
 | 
			
		||||
Shulkers) may need to be changed in order for it to re-save properly
 | 
			
		||||
 | 
			
		||||
No more crashing though.
 | 
			
		||||
 | 
			
		||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java
 | 
			
		||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
			
		||||
--- a/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java
 | 
			
		||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java
 | 
			
		||||
@@ -0,0 +0,0 @@ public class SkullBlockEntity extends BlockEntity {
 | 
			
		||||
         }
 | 
			
		||||
 
 | 
			
		||||
         if (nbt.contains("custom_name", 8)) {
 | 
			
		||||
-            this.customName = Component.Serializer.fromJson(nbt.getString("custom_name"), registryLookup);
 | 
			
		||||
+            this.customName = BlockEntity.parseCustomNameSafe(nbt.getString("custom_name"), registryLookup); // Paper
 | 
			
		||||
         } else {
 | 
			
		||||
             this.customName = null;
 | 
			
		||||
         }
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue