From 110bcadcdf12a83eefc9a00250753773bc123125 Mon Sep 17 00:00:00 2001 From: Aikar Date: Tue, 19 Dec 2017 16:31:46 -0500 Subject: [PATCH] ExperienceOrbs API for Reason/Source/Triggering player Adds lots of information about why this orb exists. Replaces isFromBottle() with logic that persists entity reloads too. --- .../level/ServerPlayerGameMode.java.patch | 2 +- .../world/entity/ExperienceOrb.java.patch | 117 ++++++++++++++++-- .../world/entity/LivingEntity.java.patch | 2 +- .../world/entity/animal/Animal.java.patch | 19 +-- .../world/entity/animal/Fox.java.patch | 2 +- .../world/entity/animal/Turtle.java.patch | 9 ++ .../boss/enderdragon/EnderDragon.java.patch | 10 +- .../world/entity/npc/Villager.java.patch | 27 ++-- .../entity/npc/WanderingTrader.java.patch | 9 ++ .../entity/projectile/FishingHook.java.patch | 2 +- .../ThrownExperienceBottle.java.patch | 5 +- .../world/inventory/GrindstoneMenu.java.patch | 8 +- .../world/level/block/Block.java.patch | 19 ++- .../AbstractFurnaceBlockEntity.java.patch | 2 +- .../craftbukkit/entity/CraftEntityTypes.java | 2 +- .../entity/CraftExperienceOrb.java | 12 ++ 16 files changed, 207 insertions(+), 40 deletions(-) diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch index 5352294fce..86c8cf6309 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch @@ -283,7 +283,7 @@ + + // Drop event experience + if (flag && event != null) { -+ iblockdata.getBlock().popExperience(this.level, pos, event.getExpToDrop()); ++ iblockdata.getBlock().popExperience(this.level, pos, event.getExpToDrop(), this.player); // Paper + } + + return true; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch index b2160b88e9..ca8ddf1960 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch @@ -14,7 +14,71 @@ public class ExperienceOrb extends Entity { -@@ -68,6 +75,7 @@ +@@ -37,9 +44,63 @@ + public int value; + public int count; + private Player followingPlayer; ++ // Paper start ++ @javax.annotation.Nullable ++ public java.util.UUID sourceEntityId; ++ @javax.annotation.Nullable ++ public java.util.UUID triggerEntityId; ++ public org.bukkit.entity.ExperienceOrb.SpawnReason spawnReason = org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN; + ++ private void loadPaperNBT(CompoundTag tag) { ++ if (!tag.contains("Paper.ExpData", net.minecraft.nbt.Tag.TAG_COMPOUND)) { ++ return; ++ } ++ CompoundTag comp = tag.getCompound("Paper.ExpData"); ++ if (comp.hasUUID("source")) { ++ this.sourceEntityId = comp.getUUID("source"); ++ } ++ if (comp.hasUUID("trigger")) { ++ this.triggerEntityId = comp.getUUID("trigger"); ++ } ++ if (comp.contains("reason")) { ++ String reason = comp.getString("reason"); ++ try { ++ this.spawnReason = org.bukkit.entity.ExperienceOrb.SpawnReason.valueOf(reason); ++ } catch (Exception e) { ++ this.level().getCraftServer().getLogger().warning("Invalid spawnReason set for experience orb: " + e.getMessage() + " - " + reason); ++ } ++ } ++ } ++ private void savePaperNBT(CompoundTag tag) { ++ CompoundTag comp = new CompoundTag(); ++ if (this.sourceEntityId != null) { ++ comp.putUUID("source", this.sourceEntityId); ++ } ++ if (this.triggerEntityId != null) { ++ comp.putUUID("trigger", triggerEntityId); ++ } ++ if (this.spawnReason != null && this.spawnReason != org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN) { ++ comp.putString("reason", this.spawnReason.name()); ++ } ++ tag.put("Paper.ExpData", comp); ++ } ++ ++ @io.papermc.paper.annotation.DoNotUse ++ @Deprecated + public ExperienceOrb(Level world, double x, double y, double z, int amount) { ++ this(world, x, y, z, amount, null, null); ++ } ++ ++ public ExperienceOrb(Level world, double x, double y, double z, int amount, @javax.annotation.Nullable org.bukkit.entity.ExperienceOrb.SpawnReason reason, @javax.annotation.Nullable Entity triggerId) { ++ this(world, x, y, z, amount, reason, triggerId, null); ++ } ++ ++ public ExperienceOrb(Level world, double x, double y, double z, int amount, @javax.annotation.Nullable org.bukkit.entity.ExperienceOrb.SpawnReason reason, @javax.annotation.Nullable Entity triggerId, @javax.annotation.Nullable Entity sourceId) { + this(EntityType.EXPERIENCE_ORB, world); ++ this.sourceEntityId = sourceId != null ? sourceId.getUUID() : null; ++ this.triggerEntityId = triggerId != null ? triggerId.getUUID() : null; ++ this.spawnReason = reason != null ? reason : org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN; ++ // Paper end + this.setPos(x, y, z); + this.setYRot((float) (this.random.nextDouble() * 360.0D)); + this.setDeltaMovement((this.random.nextDouble() * 0.20000000298023224D - 0.10000000149011612D) * 2.0D, this.random.nextDouble() * 0.2D * 2.0D, (this.random.nextDouble() * 0.20000000298023224D - 0.10000000149011612D) * 2.0D); +@@ -68,6 +129,7 @@ @Override public void tick() { super.tick(); @@ -22,7 +86,7 @@ this.xo = this.getX(); this.yo = this.getY(); this.zo = this.getZ(); -@@ -93,7 +101,22 @@ +@@ -93,7 +155,22 @@ this.followingPlayer = null; } @@ -46,7 +110,7 @@ Vec3 vec3d = new Vec3(this.followingPlayer.getX() - this.getX(), this.followingPlayer.getY() + (double) this.followingPlayer.getEyeHeight() / 2.0D - this.getY(), this.followingPlayer.getZ() - this.getZ()); double d0 = vec3d.lengthSqr(); -@@ -121,7 +144,7 @@ +@@ -121,7 +198,7 @@ ++this.age; if (this.age >= 6000) { @@ -55,7 +119,29 @@ } } -@@ -190,7 +213,7 @@ +@@ -150,12 +227,20 @@ + } + + public static void award(ServerLevel world, Vec3 pos, int amount) { ++ // Paper start - add reasons for orbs ++ award(world, pos, amount, null, null, null); ++ } ++ public static void award(ServerLevel world, Vec3 pos, int amount, org.bukkit.entity.ExperienceOrb.SpawnReason reason, Entity triggerId) { ++ award(world, pos, amount, reason, triggerId, null); ++ } ++ public static void award(ServerLevel world, Vec3 pos, int amount, org.bukkit.entity.ExperienceOrb.SpawnReason reason, Entity triggerId, Entity sourceId) { ++ // Paper end - add reasons for orbs + while (amount > 0) { + int j = ExperienceOrb.getExperienceValue(amount); + + amount -= j; + if (!ExperienceOrb.tryMergeToExisting(world, pos, j)) { +- world.addFreshEntity(new ExperienceOrb(world, pos.x(), pos.y(), pos.z(), j)); ++ world.addFreshEntity(new ExperienceOrb(world, pos.x(), pos.y(), pos.z(), j, reason, triggerId, sourceId)); // Paper - add reason + } + } + +@@ -190,7 +275,7 @@ private void merge(ExperienceOrb other) { this.count += other.count; this.age = Math.min(this.age, other.age); @@ -64,7 +150,7 @@ } private void setUnderwaterMovement() { -@@ -215,7 +238,7 @@ +@@ -215,7 +300,7 @@ this.markHurt(); this.health = (int) ((float) this.health - amount); if (this.health <= 0) { @@ -73,7 +159,22 @@ } return true; -@@ -242,17 +265,17 @@ +@@ -228,6 +313,7 @@ + nbt.putShort("Age", (short) this.age); + nbt.putShort("Value", (short) this.value); + nbt.putInt("Count", this.count); ++ this.savePaperNBT(nbt); // Paper + } + + @Override +@@ -236,23 +322,24 @@ + this.age = nbt.getShort("Age"); + this.value = nbt.getShort("Value"); + this.count = Math.max(nbt.getInt("Count"), 1); ++ this.loadPaperNBT(nbt); // Paper + } + + @Override public void playerTouch(Player player) { if (player instanceof ServerPlayer entityplayer) { if (player.takeXpDelay == 0) { @@ -94,7 +195,7 @@ } } -@@ -266,12 +289,20 @@ +@@ -266,12 +353,20 @@ ItemStack itemstack = ((EnchantedItemInUse) optional.get()).itemStack(); int j = EnchantmentHelper.modifyDurabilityToRepairFromXp(player.serverLevel(), itemstack, amount); int k = Math.min(j, itemstack.getDamageValue()); @@ -115,7 +216,7 @@ return this.repairPlayerItems(player, l); } } -@@ -291,6 +322,24 @@ +@@ -291,6 +386,24 @@ } public static int getExperienceValue(int value) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch index d3b9205626..ad8607374a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch @@ -805,7 +805,7 @@ + protected void dropExperience(ServerLevel world, @Nullable Entity attacker) { + // CraftBukkit start - Update getExpReward() above if the removed if() changes! + if (!(this instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon)) { // CraftBukkit - SPIGOT-2420: Special case ender dragon will drop the xp over time -+ ExperienceOrb.award(world, this.position(), this.expToDrop); ++ ExperienceOrb.award(world, this.position(), this.expToDrop, this instanceof ServerPlayer ? org.bukkit.entity.ExperienceOrb.SpawnReason.PLAYER_DEATH : org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, attacker, this); // Paper + this.expToDrop = 0; + } + // CraftBukkit end diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/Animal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/Animal.java.patch index 9fcf8b12c3..79a03f7409 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/Animal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/Animal.java.patch @@ -58,7 +58,7 @@ this.level().broadcastEntityEvent(this, (byte) 18); } -@@ -233,25 +254,46 @@ +@@ -233,25 +254,48 @@ if (entityageable != null) { entityageable.setBaby(true); entityageable.moveTo(this.getX(), this.getY(), this.getZ(), 0.0F, 0.0F); @@ -81,20 +81,25 @@ } public void finalizeSpawnChildFromBreeding(ServerLevel world, Animal other, @Nullable AgeableMob baby) { +- Optional.ofNullable(this.getLoveCause()).or(() -> { +- return Optional.ofNullable(other.getLoveCause()); +- }).ifPresent((entityplayer) -> { + // CraftBukkit start + this.finalizeSpawnChildFromBreeding(world, other, baby, this.getRandom().nextInt(7) + 1); + } + + public void finalizeSpawnChildFromBreeding(ServerLevel worldserver, Animal entityanimal, @Nullable AgeableMob entityageable, int experience) { + // CraftBukkit end - Optional.ofNullable(this.getLoveCause()).or(() -> { -- return Optional.ofNullable(other.getLoveCause()); -+ return Optional.ofNullable(entityanimal.getLoveCause()); - }).ifPresent((entityplayer) -> { ++ // Paper start ++ ServerPlayer entityplayer = this.getLoveCause(); ++ if (entityplayer == null) entityplayer = entityanimal.getLoveCause(); ++ if (entityplayer != null) { ++ // Paper end entityplayer.awardStat(Stats.ANIMALS_BRED); - CriteriaTriggers.BRED_ANIMALS.trigger(entityplayer, this, other, baby); +- }); + CriteriaTriggers.BRED_ANIMALS.trigger(entityplayer, this, entityanimal, entityageable); - }); ++ } // Paper this.setAge(6000); - other.setAge(6000); + entityanimal.setAge(6000); @@ -108,7 +113,7 @@ + if (worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { + // CraftBukkit start - use event experience + if (experience > 0) { -+ worldserver.addFreshEntity(new ExperienceOrb(worldserver, this.getX(), this.getY(), this.getZ(), experience)); ++ worldserver.addFreshEntity(new ExperienceOrb(worldserver, this.getX(), this.getY(), this.getZ(), experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer, entityageable)); // Paper + } + // CraftBukkit end } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/Fox.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/Fox.java.patch index 832793d2cc..aecbab30cf 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/Fox.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/Fox.java.patch @@ -60,7 +60,7 @@ - this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), this.animal.getRandom().nextInt(7) + 1)); + // CraftBukkit start - use event experience + if (experience > 0) { -+ this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), experience)); ++ this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer, entityfox)); // Paper + } + // CraftBukkit end } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/Turtle.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/Turtle.java.patch index 5a6ee3ed21..47fc233191 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/Turtle.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/Turtle.java.patch @@ -19,6 +19,15 @@ } @Override +@@ -460,7 +462,7 @@ + RandomSource randomsource = this.animal.getRandom(); + + if (getServerLevel((Level) this.level).getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { +- this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), randomsource.nextInt(7) + 1)); ++ this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), randomsource.nextInt(7) + 1, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer)); // Paper; + } + + } @@ -496,12 +498,14 @@ } else if (this.turtle.layEggCounter > this.adjustedTickDelay(200)) { Level world = this.turtle.level(); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch index 3d5359b4b7..ad7f4d3b7a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch @@ -205,8 +205,9 @@ if (world instanceof ServerLevel worldserver) { - if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0 && worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { +- ExperienceOrb.award(worldserver, this.position(), Mth.floor((float) short0 * 0.08F)); + if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0 && true) { // CraftBukkit - SPIGOT-2420: Already checked for the game rule when calculating the xp - ExperienceOrb.award(worldserver, this.position(), Mth.floor((float) short0 * 0.08F)); ++ ExperienceOrb.award(worldserver, this.position(), Mth.floor((float) short0 * 0.08F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, this.lastHurtByPlayer, this); // Paper } if (this.dragonDeathTime == 1 && !this.isSilent()) { @@ -233,16 +234,17 @@ } } -@@ -592,7 +704,7 @@ +@@ -592,15 +704,15 @@ if (world1 instanceof ServerLevel) { ServerLevel worldserver1 = (ServerLevel) world1; - if (worldserver1.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { +- ExperienceOrb.award(worldserver1, this.position(), Mth.floor((float) short0 * 0.2F)); + if (true) { // CraftBukkit - SPIGOT-2420: Already checked for the game rule when calculating the xp - ExperienceOrb.award(worldserver1, this.position(), Mth.floor((float) short0 * 0.2F)); ++ ExperienceOrb.award(worldserver1, this.position(), Mth.floor((float) short0 * 0.2F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, this.lastHurtByPlayer, this); // Paper } -@@ -600,7 +712,7 @@ + if (this.dragonFight != null) { this.dragonFight.setDragonKilled(this); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/npc/Villager.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/npc/Villager.java.patch index 50d1a6008e..d28a09255d 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/npc/Villager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/npc/Villager.java.patch @@ -24,25 +24,25 @@ } @Override -@@ -214,7 +222,18 @@ - - public boolean assignProfessionWhenSpawned() { +@@ -216,7 +224,18 @@ return this.assignProfessionWhenSpawned; -+ } -+ + } + + // Spigot Start -+ @Override + @Override + public void inactiveTick() { + // SPIGOT-3874, SPIGOT-3894, SPIGOT-3846, SPIGOT-5286 :( + if (this.level().spigotConfig.tickInactiveVillagers && this.isEffectiveAi()) { + this.customServerAiStep((ServerLevel) this.level()); + } + super.inactiveTick(); - } ++ } + // Spigot End - - @Override ++ ++ @Override protected void customServerAiStep(ServerLevel world) { + ProfilerFiller gameprofilerfiller = Profiler.get(); + @@ -235,7 +254,7 @@ this.increaseProfessionLevelOnUpdate = false; } @@ -100,6 +100,15 @@ Logger logger = Villager.LOGGER; Objects.requireNonNull(logger); +@@ -599,7 +630,7 @@ + } + + if (offer.shouldRewardExp()) { +- this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5D, this.getZ(), i)); ++ this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5D, this.getZ(), i, org.bukkit.entity.ExperienceOrb.SpawnReason.VILLAGER_TRADE, this.getTradingPlayer(), this)); // Paper + } + + } @@ -618,7 +649,7 @@ @Override diff --git a/paper-server/patches/sources/net/minecraft/world/entity/npc/WanderingTrader.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/npc/WanderingTrader.java.patch index 8b6cac6fae..4e58fee721 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/npc/WanderingTrader.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/npc/WanderingTrader.java.patch @@ -44,6 +44,15 @@ } } +@@ -190,7 +208,7 @@ + if (offer.shouldRewardExp()) { + int i = 3 + this.random.nextInt(4); + +- this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5D, this.getZ(), i)); ++ this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5D, this.getZ(), i, org.bukkit.entity.ExperienceOrb.SpawnReason.VILLAGER_TRADE, this.getTradingPlayer(), this)); // Paper + } + + } @@ -244,7 +262,7 @@ private void maybeDespawn() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/FishingHook.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/FishingHook.java.patch index c5b22d1a8a..d6a87cac69 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/FishingHook.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/FishingHook.java.patch @@ -211,7 +211,7 @@ - entityhuman.level().addFreshEntity(new ExperienceOrb(entityhuman.level(), entityhuman.getX(), entityhuman.getY() + 0.5D, entityhuman.getZ() + 0.5D, this.random.nextInt(6) + 1)); + // CraftBukkit start - this.random.nextInt(6) + 1 -> playerFishEvent.getExpToDrop() + if (playerFishEvent.getExpToDrop() > 0) { -+ entityhuman.level().addFreshEntity(new ExperienceOrb(entityhuman.level(), entityhuman.getX(), entityhuman.getY() + 0.5D, entityhuman.getZ() + 0.5D, playerFishEvent.getExpToDrop())); ++ entityhuman.level().addFreshEntity(new ExperienceOrb(entityhuman.level(), entityhuman.getX(), entityhuman.getY() + 0.5D, entityhuman.getZ() + 0.5D, playerFishEvent.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.FISHING, this.getPlayerOwner(), this)); // Paper + } + // CraftBukkit end if (itemstack1.is(ItemTags.FISHES)) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java.patch index 9818d0cce1..40cd201036 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java.patch @@ -19,6 +19,8 @@ + // this.level().levelEvent(2002, this.blockPosition(), -13083194); int i = 3 + this.level().random.nextInt(5) + this.level().random.nextInt(5); +- ExperienceOrb.award((ServerLevel) this.level(), this.position(), i); +- this.discard(); + // CraftBukkit start + org.bukkit.event.entity.ExpBottleEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExpBottleEvent(this, hitResult, i); + i = event.getExperience(); @@ -27,8 +29,7 @@ + } + // CraftBukkit end + - ExperienceOrb.award((ServerLevel) this.level(), this.position(), i); -- this.discard(); ++ ExperienceOrb.award((ServerLevel) this.level(), this.position(), i, org.bukkit.entity.ExperienceOrb.SpawnReason.EXP_BOTTLE, this.getOwner(), this); // Paper + this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/GrindstoneMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/GrindstoneMenu.java.patch index 50d59c0ca8..6cfdacc06e 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/GrindstoneMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/GrindstoneMenu.java.patch @@ -65,7 +65,7 @@ @Override public boolean mayPlace(ItemStack stack) { return stack.isDamageableItem() || EnchantmentHelper.hasAnyEnchantments(stack); -@@ -68,7 +95,7 @@ +@@ -68,10 +95,10 @@ } @Override @@ -73,7 +73,11 @@ + public void onTake(net.minecraft.world.entity.player.Player player, ItemStack stack) { context.execute((world, blockposition) -> { if (world instanceof ServerLevel) { - ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), this.getExperienceAmount(world)); +- ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), this.getExperienceAmount(world)); ++ ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), this.getExperienceAmount(world), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player); // Paper + } + + world.levelEvent(1042, blockposition, 0); @@ -113,6 +140,7 @@ } }); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/Block.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/Block.java.patch index c401e3135b..0632aa2c1d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/Block.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/Block.java.patch @@ -15,7 +15,22 @@ return; } } -@@ -369,7 +375,7 @@ +@@ -348,8 +354,13 @@ + } + + public void popExperience(ServerLevel world, BlockPos pos, int size) { ++ // Paper start - add entity parameter ++ popExperience(world, pos, size, null); ++ } ++ public void popExperience(ServerLevel world, BlockPos pos, int size, net.minecraft.world.entity.Entity entity) { ++ // Paper end - add entity parameter + if (world.getGameRules().getBoolean(GameRules.RULE_DOBLOCKDROPS)) { +- ExperienceOrb.award(world, Vec3.atCenterOf(pos), size); ++ ExperienceOrb.award(world, Vec3.atCenterOf(pos), size, org.bukkit.entity.ExperienceOrb.SpawnReason.BLOCK_BREAK, entity); // Paper + } + + } +@@ -369,7 +380,7 @@ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) { player.awardStat(Stats.BLOCK_MINED.get(this)); @@ -24,7 +39,7 @@ Block.dropResources(state, world, pos, blockEntity, player, tool); } -@@ -490,15 +496,35 @@ +@@ -490,15 +501,35 @@ return this.builtInRegistryHolder; } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch index ea190773fc..eb9a50bc6a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch @@ -266,7 +266,7 @@ + j = event.getExpToDrop(); + // CraftBukkit end + -+ ExperienceOrb.award(worldserver, vec3d, j); ++ ExperienceOrb.award(worldserver, vec3d, j, org.bukkit.entity.ExperienceOrb.SpawnReason.FURNACE, entityhuman); // Paper } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java index 807e4a7a83..0ebcf7ed1c 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java @@ -424,7 +424,7 @@ public final class CraftEntityTypes { return item; })); register(new EntityTypeData<>(EntityType.EXPERIENCE_ORB, ExperienceOrb.class, CraftExperienceOrb::new, - spawnData -> new net.minecraft.world.entity.ExperienceOrb(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), 0) + spawnData -> new net.minecraft.world.entity.ExperienceOrb(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), 0, org.bukkit.entity.ExperienceOrb.SpawnReason.CUSTOM, null, null) // Paper )); register(new EntityTypeData<>(EntityType.AREA_EFFECT_CLOUD, AreaEffectCloud.class, CraftAreaEffectCloud::new, spawnData -> new net.minecraft.world.entity.AreaEffectCloud(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z()))); register(new EntityTypeData<>(EntityType.EGG, Egg.class, CraftEgg::new, spawnData -> new ThrownEgg(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), new net.minecraft.world.item.ItemStack(Items.EGG)))); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java index 9231511af4..5a7d314ec0 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java @@ -18,6 +18,18 @@ public class CraftExperienceOrb extends CraftEntity implements ExperienceOrb { this.getHandle().value = value; } + // Paper start + public java.util.UUID getTriggerEntityId() { + return getHandle().triggerEntityId; + } + public java.util.UUID getSourceEntityId() { + return getHandle().sourceEntityId; + } + public SpawnReason getSpawnReason() { + return getHandle().spawnReason; + } + // Paper end + @Override public net.minecraft.world.entity.ExperienceOrb getHandle() { return (net.minecraft.world.entity.ExperienceOrb) this.entity;