Paper/patches/server/0128-ExperienceOrbs-API-for...

352 lines
22 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
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/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
index f772924217c0531b09662a145d8ee5d22dd5ca51..ecfb88b4d9727ad20a2c33475cc6b1ec88821a19 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -415,7 +415,7 @@ public class ServerPlayerGameMode {
// 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/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
index 919fbe73f46238a1846c969bf64c309f3b9ad9d6..9662104a85faff2cdafd8cf001a8222182b56073 100644
--- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
@@ -38,13 +38,63 @@ public class ExperienceOrb extends Entity {
public int value;
private int count;
private Player followingPlayer;
+ // 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(CompoundTag nbttagcompound) {
+ if (!nbttagcompound.contains("Paper.ExpData", 10)) { // 10 = compound
+ return;
+ }
+ CompoundTag 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.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 nbttagcompound) {
+ CompoundTag comp = new CompoundTag();
+ if (this.sourceEntityId != null) {
+ comp.setUUID("source", this.sourceEntityId);
+ }
+ if (this.triggerEntityId != null) {
+ comp.setUUID("trigger", triggerEntityId);
+ }
+ if (this.spawnReason != null && this.spawnReason != org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN) {
+ comp.putString("reason", this.spawnReason.name());
+ }
+ nbttagcompound.put("Paper.ExpData", comp);
+ }
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 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 ExperienceOrb(Level world, double d0, double d1, double d2, int i, org.bukkit.entity.ExperienceOrb.SpawnReason reason, Entity triggerId, Entity sourceId) {
this(EntityType.EXPERIENCE_ORB, world);
- this.setPos(x, y, z);
+ 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(d0, d1, d2);
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);
- this.value = amount;
+ this.value = i;
}
public ExperienceOrb(EntityType<? extends ExperienceOrb> type, Level world) {
@@ -154,12 +204,20 @@ public class ExperienceOrb extends Entity {
}
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
}
}
@@ -227,6 +285,7 @@ public class ExperienceOrb extends Entity {
nbt.putShort("Age", (short) this.age);
nbt.putShort("Value", (short) this.value);
nbt.putInt("Count", this.count);
+ this.savePaperNBT(nbt); // Paper
}
@Override
@@ -235,6 +294,7 @@ public class ExperienceOrb extends Entity {
this.age = nbt.getShort("Age");
this.value = nbt.getShort("Value");
this.count = Math.max(nbt.getInt("Count"), 1);
+ this.loadPaperNBT(nbt); // Paper
}
@Override
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 041a61e037e7f6fddd94567f2954be600c737811..971e4c6d742e0c63b3c5dfa6d87b2468f8ce5010 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -1699,7 +1699,8 @@ public abstract class LivingEntity extends Entity {
protected void dropExperience() {
// CraftBukkit start - Update getExpReward() above if the removed if() changes!
if (true) {
- ExperienceOrb.award((ServerLevel) this.level, this.position(), this.expToDrop);
+ LivingEntity attacker = this.lastHurtByPlayer != null ? this.lastHurtByPlayer : this.lastHurtByMob; // Paper
+ ExperienceOrb.award((ServerLevel) this.level, 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/src/main/java/net/minecraft/world/entity/animal/Animal.java b/src/main/java/net/minecraft/world/entity/animal/Animal.java
index b8163a04f5aad326e78416b270dc64ffc913ccc5..5a503a255b4e7e684a8f42d8190430397ca81683 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Animal.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Animal.java
@@ -264,7 +264,7 @@ public abstract class Animal extends AgeableMob {
if (world.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
// CraftBukkit start - use event experience
if (experience > 0) {
- world.addFreshEntity(new ExperienceOrb(world, this.getX(), this.getY(), this.getZ(), experience));
+ world.addFreshEntity(new ExperienceOrb(world, this.getX(), this.getY(), this.getZ(), experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer, entityageable)); // Paper
}
// CraftBukkit 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 0fd1dfacca88cd5399e05cb7ebc0150491e8f59c..c1cdb1905536bda76f34ad3fc796996443839767 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Fox.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java
@@ -883,7 +883,7 @@ public class Fox extends Animal {
if (this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
// 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/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
index 593442f0f2d58e2e0a0a86d6f16aea90cc36d184..b782d278463a72b8514719e9b14986f268828772 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
@@ -455,7 +455,7 @@ public class Turtle extends Animal {
Random random = this.animal.getRandom();
if (this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
- this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), random.nextInt(7) + 1));
+ this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), random.nextInt(7) + 1, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer)); // Paper;
}
}
diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
index 9d6d8bf5f38ec11f26665ae676c46e4ef089670b..e286d4ed03eba05b862741cb98db8a031224cd98 100644
--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
@@ -634,7 +634,7 @@ public class EnderDragon extends Mob implements Enemy {
if (this.level instanceof ServerLevel) {
if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0 && flag) {
- ExperienceOrb.award((ServerLevel) this.level, this.position(), Mth.floor((float) short0 * 0.08F));
+ ExperienceOrb.award((ServerLevel) this.level, 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()) {
@@ -665,7 +665,7 @@ public class EnderDragon extends Mob implements Enemy {
this.yBodyRot = this.getYRot();
if (this.dragonDeathTime == 200 && this.level instanceof ServerLevel) {
if (flag) {
- ExperienceOrb.award((ServerLevel) this.level, this.position(), Mth.floor((float) short0 * 0.2F));
+ ExperienceOrb.award((ServerLevel) this.level, this.position(), Mth.floor((float) short0 * 0.2F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, this.lastHurtByPlayer, this); // Paper
}
if (this.dragonFight != null) {
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
index 731aea63eedb8cb37291bb2238ff8ab2e3a5f6eb..6a9e2105b2d9a4ee83c0a2516d5ef26dc3b99053 100644
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
@@ -616,7 +616,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
}
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
}
}
diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
index 892603dabb17e77ac0b038617f00f2d3d1c728ac..59c4ab697ef0a336ffce19d215952f3a8ff0852b 100644
--- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
@@ -187,7 +187,7 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill
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
}
}
diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
index d25fe9cb2cf755f3e34a79ce87ed38c1ffada53f..0258d0699afe7ceec19154c669b10298e6e1bf95 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
@@ -516,7 +516,7 @@ public class FishingHook extends Projectile {
this.level.addFreshEntity(entityitem);
// 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((Tag) ItemTags.FISHES)) {
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java
index 467f9814e0991d31bff7259f266262c81328f05f..11d1db5ef709dfb6fa596ebc4f5fff1415ad4f6d 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java
@@ -51,7 +51,7 @@ public class ThrownExperienceBottle extends ThrowableItemProjectile {
}
// CraftBukkit end
- ExperienceOrb.award((ServerLevel) this.level, this.position(), i);
+ ExperienceOrb.award((ServerLevel) this.level, this.position(), i, org.bukkit.entity.ExperienceOrb.SpawnReason.EXP_BOTTLE, this.getOwner(), this); // Paper
this.discard();
}
diff --git a/src/main/java/net/minecraft/world/inventory/FurnaceResultSlot.java b/src/main/java/net/minecraft/world/inventory/FurnaceResultSlot.java
index d486b8d7d80bc79c5af6106de56a3ba49021258e..6f26688347ff2c206ab0b3ccae30b95ee7475fa2 100644
--- a/src/main/java/net/minecraft/world/inventory/FurnaceResultSlot.java
+++ b/src/main/java/net/minecraft/world/inventory/FurnaceResultSlot.java
@@ -8,7 +8,7 @@ import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity;
public class FurnaceResultSlot extends Slot {
- private final Player player;
+ private final Player player; public final Player getPlayer() { return this.player; } // Paper OBFHELPER
private int removeCount;
public FurnaceResultSlot(Player player, Container inventory, int index, int x, int y) {
diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
index 473e17d87637cd1a85880e2956f83de0b510b488..34574f3945d2a7b4ab6a71adb2408b9811a3cb0d 100644
--- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
@@ -98,7 +98,7 @@ public class GrindstoneMenu extends AbstractContainerMenu {
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((Vec3i) blockposition), this.getExperienceAmount(world));
+ ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf((Vec3i) blockposition), this.getExperienceAmount(world), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player); // Paper
}
world.levelEvent(1042, blockposition, 0);
diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
index c27e755f93a2b2e203b305e0cae2c782a34e38cc..27016f964d2f6458298a9052d031a44b3d9f5f4b 100644
--- a/src/main/java/net/minecraft/world/level/block/Block.java
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
@@ -374,8 +374,13 @@ public class Block extends BlockBehaviour implements ItemLike {
}
public void popExperience(ServerLevel world, BlockPos pos, int size) {
+ // Paper start - add player parameter
+ popExperience(world, pos, size, null);
+ }
+ public void popExperience(ServerLevel world, BlockPos pos, int size, net.minecraft.server.level.ServerPlayer player) {
+ // Paper end - add player parameter
if (world.getGameRules().getBoolean(GameRules.RULE_DOBLOCKDROPS)) {
- ExperienceOrb.award(world, Vec3.atCenterOf((Vec3i) pos), size);
+ ExperienceOrb.award(world, Vec3.atCenterOf((Vec3i) pos), size, org.bukkit.entity.ExperienceOrb.SpawnReason.BLOCK_BREAK, player); // Paper
}
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
index 11ed01b3ebe4c71e3d3c767887a5dca6033fdf3c..52b2b27f8f8b542a930d649ed6904b4bf808906c 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
@@ -606,7 +606,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
}
// CraftBukkit end
- ExperienceOrb.award(worldserver, vec3d, j);
+ ExperienceOrb.award(worldserver, vec3d, j, org.bukkit.entity.ExperienceOrb.SpawnReason.FURNACE, entityhuman); // Paper
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 7b1f853913a3d858718a6067b3927946c7e50114..efff3e9590e3fd66d9ab56173c986f5b51bbe559 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -1838,7 +1838,7 @@ public class CraftWorld implements World {
} else if (TNTPrimed.class.isAssignableFrom(clazz)) {
entity = new PrimedTnt(this.world, x, y, z, null);
} else if (ExperienceOrb.class.isAssignableFrom(clazz)) {
- entity = new net.minecraft.world.entity.ExperienceOrb(this.world, x, y, z, 0);
+ entity = new net.minecraft.world.entity.ExperienceOrb(this.world, x, y, z, 0, org.bukkit.entity.ExperienceOrb.SpawnReason.CUSTOM, null, null); // Paper
} else if (LightningStrike.class.isAssignableFrom(clazz)) {
entity = net.minecraft.world.entity.EntityType.LIGHTNING_BOLT.create(world);
} else if (AreaEffectCloud.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 40713228b149b4532fcee3a54bbe63e161318258..84899284703baeb04bfc79251941265d52ac07e8 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java
@@ -19,6 +19,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) entity;