From 2aca511c4110fde82bf8492a8ae4d9f82cd78c58 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. diff --git a/src/main/java/net/minecraft/server/Block.java b/src/main/java/net/minecraft/server/Block.java index dbf1089ba..66643be2b 100644 --- a/src/main/java/net/minecraft/server/Block.java +++ b/src/main/java/net/minecraft/server/Block.java @@ -450,13 +450,13 @@ public class Block implements IMaterial { } } - protected void dropExperience(World world, BlockPosition blockposition, int i) { + protected void dropExperience(World world, BlockPosition blockposition, int i, EntityPlayer player) { // Paper if (!world.isClientSide && world.getGameRules().getBoolean("doTileDrops")) { while (i > 0) { int j = EntityExperienceOrb.getOrbValue(i); i -= j; - world.addEntity(new EntityExperienceOrb(world, (double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, j)); + world.addEntity(new EntityExperienceOrb(world, (double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, j, org.bukkit.entity.ExperienceOrb.SpawnReason.BLOCK_BREAK, player)); // Paper } } diff --git a/src/main/java/net/minecraft/server/EntityEnderDragon.java b/src/main/java/net/minecraft/server/EntityEnderDragon.java index b3fbc8249..79d8be8d4 100644 --- a/src/main/java/net/minecraft/server/EntityEnderDragon.java +++ b/src/main/java/net/minecraft/server/EntityEnderDragon.java @@ -618,7 +618,7 @@ public class EntityEnderDragon extends EntityInsentient implements IComplex, IMo int j = EntityExperienceOrb.getOrbValue(i); i -= j; - this.world.addEntity(new EntityExperienceOrb(this.world, this.locX, this.locY, this.locZ, j)); + this.world.addEntity(new EntityExperienceOrb(this.world, this.locX, this.locY, this.locZ, j, org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, this.killer, this)); // Paper } } diff --git a/src/main/java/net/minecraft/server/EntityExperienceOrb.java b/src/main/java/net/minecraft/server/EntityExperienceOrb.java index 3030dd9c3..404a222b4 100644 --- a/src/main/java/net/minecraft/server/EntityExperienceOrb.java +++ b/src/main/java/net/minecraft/server/EntityExperienceOrb.java @@ -15,9 +15,59 @@ public class EntityExperienceOrb extends Entity { public int value; private EntityHuman targetPlayer; private int targetTime; + // Paper start + public java.util.UUID sourceEntityId; + public java.util.UUID triggerEntityId; + public org.bukkit.entity.ExperienceOrb.SpawnReason spawnReason = org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN; + + private void loadPaperNBT(NBTTagCompound nbttagcompound) { + if (!nbttagcompound.hasKeyOfType("Paper.ExpData", 10)) { // 10 = compound + return; + } + NBTTagCompound comp = nbttagcompound.getCompound("Paper.ExpData"); + if (comp.hasUUID("source")) { + this.sourceEntityId = comp.getUUID("source"); + } + if (comp.hasUUID("trigger")) { + this.triggerEntityId = comp.getUUID("trigger"); + } + if (comp.hasKey("reason")) { + String reason = comp.getString("reason"); + try { + spawnReason = org.bukkit.entity.ExperienceOrb.SpawnReason.valueOf(reason); + } catch (Exception e) { + this.world.getServer().getLogger().warning("Invalid spawnReason set for experience orb: " + e.getMessage() + " - " + reason); + } + } + } + private void savePaperNBT(NBTTagCompound nbttagcompound) { + NBTTagCompound comp = new NBTTagCompound(); + if (sourceEntityId != null) { + comp.setUUID("source", sourceEntityId); + } + if (triggerEntityId != null) { + comp.setUUID("trigger", triggerEntityId); + } + if (spawnReason != null && spawnReason != org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN) { + comp.setString("reason", spawnReason.name()); + } + nbttagcompound.set("Paper.ExpData", comp); + } public EntityExperienceOrb(World world, double d0, double d1, double d2, int i) { + this(world, d0, d1, d2, i, null, null); + } + + public EntityExperienceOrb(World world, double d0, double d1, double d2, int i, org.bukkit.entity.ExperienceOrb.SpawnReason reason, Entity triggerId) { + this(world, d0, d1, d2, i, reason, triggerId, null); + } + + public EntityExperienceOrb(World world, double d0, double d1, double d2, int i, org.bukkit.entity.ExperienceOrb.SpawnReason reason, Entity triggerId, Entity sourceId) { super(EntityTypes.EXPERIENCE_ORB, world); + this.sourceEntityId = sourceId != null ? sourceId.getUniqueID() : null; + this.triggerEntityId = triggerId != null ? triggerId.getUniqueID() : null; + this.spawnReason = reason != null ? reason : org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN; + // Paper end this.setSize(0.5F, 0.5F); this.setPosition(d0, d1, d2); this.yaw = (float) (Math.random() * 360.0D); @@ -156,12 +206,14 @@ public class EntityExperienceOrb extends Entity { nbttagcompound.setShort("Health", (short) this.d); nbttagcompound.setShort("Age", (short) this.b); nbttagcompound.setShort("Value", (short) this.value); + savePaperNBT(nbttagcompound); // Paper } public void a(NBTTagCompound nbttagcompound) { this.d = nbttagcompound.getShort("Health"); this.b = nbttagcompound.getShort("Age"); this.value = nbttagcompound.getShort("Value"); + loadPaperNBT(nbttagcompound); // Paper } public void d(EntityHuman entityhuman) { diff --git a/src/main/java/net/minecraft/server/EntityFishingHook.java b/src/main/java/net/minecraft/server/EntityFishingHook.java index 23f7d36b5..e1c685eed 100644 --- a/src/main/java/net/minecraft/server/EntityFishingHook.java +++ b/src/main/java/net/minecraft/server/EntityFishingHook.java @@ -467,7 +467,7 @@ public class EntityFishingHook extends Entity { this.world.addEntity(entityitem); // CraftBukkit start - this.random.nextInt(6) + 1 -> playerFishEvent.getExpToDrop() if (playerFishEvent.getExpToDrop() > 0) { - this.owner.world.addEntity(new EntityExperienceOrb(this.owner.world, this.owner.locX, this.owner.locY + 0.5D, this.owner.locZ + 0.5D, playerFishEvent.getExpToDrop())); + this.owner.world.addEntity(new EntityExperienceOrb(this.owner.world, this.owner.locX, this.owner.locY + 0.5D, this.owner.locZ + 0.5D, playerFishEvent.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.FISHING, this.owner, this)); // Paper } // CraftBukkit end if (itemstack1.getItem().a(TagsItem.FISHES)) { diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java index f58ebe3c2..f2e38b9f3 100644 --- a/src/main/java/net/minecraft/server/EntityLiving.java +++ b/src/main/java/net/minecraft/server/EntityLiving.java @@ -354,7 +354,8 @@ public abstract class EntityLiving extends Entity { int j = EntityExperienceOrb.getOrbValue(i); i -= j; - this.world.addEntity(new EntityExperienceOrb(this.world, this.locX, this.locY, this.locZ, j)); + EntityLiving attacker = killer != null ? killer : lastDamager; // Paper + this.world.addEntity(new EntityExperienceOrb(this.world, this.locX, this.locY, this.locZ, j, this instanceof EntityPlayer ? 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/src/main/java/net/minecraft/server/EntityThrownExpBottle.java b/src/main/java/net/minecraft/server/EntityThrownExpBottle.java index a5e1939e0..e73dba09a 100644 --- a/src/main/java/net/minecraft/server/EntityThrownExpBottle.java +++ b/src/main/java/net/minecraft/server/EntityThrownExpBottle.java @@ -36,7 +36,7 @@ public class EntityThrownExpBottle extends EntityProjectile { int j = EntityExperienceOrb.getOrbValue(i); i -= j; - this.world.addEntity(new EntityExperienceOrb(this.world, this.locX, this.locY, this.locZ, j)); + this.world.addEntity(new EntityExperienceOrb(this.world, this.locX, this.locY, this.locZ, j, org.bukkit.entity.ExperienceOrb.SpawnReason.EXP_BOTTLE, getShooter(), this)); // Paper } this.die(); diff --git a/src/main/java/net/minecraft/server/EntityVillager.java b/src/main/java/net/minecraft/server/EntityVillager.java index ebe397b15..78acac4ca 100644 --- a/src/main/java/net/minecraft/server/EntityVillager.java +++ b/src/main/java/net/minecraft/server/EntityVillager.java @@ -412,7 +412,7 @@ public class EntityVillager extends EntityAgeable implements NPC, IMerchant { } if (merchantrecipe.j()) { - this.world.addEntity(new EntityExperienceOrb(this.world, this.locX, this.locY + 0.5D, this.locZ, i)); + this.world.addEntity(new EntityExperienceOrb(this.world, this.locX, this.locY + 0.5D, this.locZ, i, org.bukkit.entity.ExperienceOrb.SpawnReason.VILLAGER_TRADE, tradingPlayer, this)); // Paper } if (this.tradingPlayer instanceof EntityPlayer) { diff --git a/src/main/java/net/minecraft/server/PathfinderGoalBreed.java b/src/main/java/net/minecraft/server/PathfinderGoalBreed.java index bf061cf06..55f978768 100644 --- a/src/main/java/net/minecraft/server/PathfinderGoalBreed.java +++ b/src/main/java/net/minecraft/server/PathfinderGoalBreed.java @@ -122,7 +122,7 @@ public class PathfinderGoalBreed extends PathfinderGoal { if (this.b.getGameRules().getBoolean("doMobLoot")) { // CraftBukkit start - use event experience if (experience > 0) { - this.b.addEntity(new EntityExperienceOrb(this.b, this.animal.locX, this.animal.locY, this.animal.locZ, experience)); + this.b.addEntity(new EntityExperienceOrb(this.b, this.animal.locX, this.animal.locY, this.animal.locZ, experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer, entityageable)); // Paper } // CraftBukkit end } diff --git a/src/main/java/net/minecraft/server/PlayerInteractManager.java b/src/main/java/net/minecraft/server/PlayerInteractManager.java index a165378ac..50a1239c2 100644 --- a/src/main/java/net/minecraft/server/PlayerInteractManager.java +++ b/src/main/java/net/minecraft/server/PlayerInteractManager.java @@ -399,7 +399,7 @@ public class PlayerInteractManager { // CraftBukkit start - Drop event experience if (flag && event != null) { - iblockdata.getBlock().dropExperience(this.world, blockposition, event.getExpToDrop()); + iblockdata.getBlock().dropExperience(this.world, blockposition, event.getExpToDrop(), this.player); // Paper } // CraftBukkit end diff --git a/src/main/java/net/minecraft/server/SlotFurnaceResult.java b/src/main/java/net/minecraft/server/SlotFurnaceResult.java index 5ac554d65..d70c4dda5 100644 --- a/src/main/java/net/minecraft/server/SlotFurnaceResult.java +++ b/src/main/java/net/minecraft/server/SlotFurnaceResult.java @@ -9,7 +9,7 @@ import org.bukkit.event.inventory.FurnaceExtractEvent; public class SlotFurnaceResult extends Slot { - private final EntityHuman a; + private final EntityHuman a;public EntityHuman getPlayer() { return a; } // Paper OBFHELPER private int b; public SlotFurnaceResult(EntityHuman entityhuman, IInventory iinventory, int i, int j, int k) { @@ -85,7 +85,7 @@ public class SlotFurnaceResult extends Slot { while (i > 0) { j = EntityExperienceOrb.getOrbValue(i); i -= j; - this.a.world.addEntity(new EntityExperienceOrb(this.a.world, this.a.locX, this.a.locY + 0.5D, this.a.locZ + 0.5D, j)); + this.a.world.addEntity(new EntityExperienceOrb(this.a.world, this.a.locX, this.a.locY + 0.5D, this.a.locZ + 0.5D, j, org.bukkit.entity.ExperienceOrb.SpawnReason.FURNACE, getPlayer())); // Paper } } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 0f3bf13ef..36d27c2a3 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -1354,7 +1354,7 @@ public class CraftWorld implements World { } else if (TNTPrimed.class.isAssignableFrom(clazz)) { entity = new EntityTNTPrimed(world, x, y, z, null); } else if (ExperienceOrb.class.isAssignableFrom(clazz)) { - entity = new EntityExperienceOrb(world, x, y, z, 0); + entity = new EntityExperienceOrb(world, x, y, z, 0, org.bukkit.entity.ExperienceOrb.SpawnReason.CUSTOM, null, null); // Paper } else if (Weather.class.isAssignableFrom(clazz)) { // not sure what this can do if (LightningStrike.class.isAssignableFrom(clazz)) { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java index 3a09cab3d..3302af0e4 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java @@ -18,6 +18,18 @@ public class CraftExperienceOrb extends CraftEntity implements ExperienceOrb { 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 EntityExperienceOrb getHandle() { return (EntityExperienceOrb) entity; -- 2.20.1