PaperMC/patches/server/ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch
Nassim Jahnke aa7c3b02e8 Updated Upstream (Bukkit/CraftBukkit/Spigot)
Upstream has released updates that appear to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing

Bukkit Changes:
2d009e64 Update SnakeYAML javadoc link
b4fd213c Switch Player#updateInventory deprecation for internal API annotation

CraftBukkit Changes:
f3b2b2210 SPIGOT-7376: Exception with getBlockData when hasBlockData is false
725545630 SPIGOT-7375: Fix crash breeding certain entities
b9873b0d4 Update Brigadier version with fix
68b320562 SPIGOT-7266: Found typo in CraftBukkit package
98b4d2ff8 SPIGOT-7372, SPIGOT-7373: Signs can't be edited, issues with SignChangeEvent
5f7bd4d78 SPIGOT-7371: Sign does not open edit text on placement
b4cf99d24 SPIGOT-7371: Fix editing signs with API
a2b6c2744 PR-1200: Implement open sign by side
a345bb940 SPIGOT-7368: Downgrade SpecialSource version

Spigot Changes:
723951c3 Rebuild patches
b655c57d Drop old collision API deprecated since 1.9.4
55b0fed4 Rebuild patches
2023-06-08 15:25:35 +02:00

340 lines
21 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
@@ -0,0 +0,0 @@ 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.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());
+ }
+ nbttagcompound.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 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) {
@@ -0,0 +0,0 @@ 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
}
}
@@ -0,0 +0,0 @@ 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
@@ -0,0 +0,0 @@ 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 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 {
protected void dropExperience() {
// CraftBukkit start - Update getExpReward() above if the removed if() changes!
if (true && !(this instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon)) { // CraftBukkit - SPIGOT-2420: Special case ender dragon will drop the xp over time
- 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Animal.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Animal.java
@@ -0,0 +0,0 @@ public abstract class Animal extends AgeableMob {
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, null)); // Paper //TODO trigger
}
// 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Fox.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java
@@ -0,0 +0,0 @@ public class Fox extends Animal implements VariantHolder<Fox.Type> {
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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
@@ -0,0 +0,0 @@ public class Turtle extends Animal {
RandomSource randomsource = 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(), 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;
}
}
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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 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
@@ -0,0 +0,0 @@ public class EnderDragon extends Mob implements Enemy {
if (this.level() instanceof ServerLevel) {
if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0 && true) { // CraftBukkit - SPIGOT-2420: Already checked for the game rule when calculating the xp
- 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()) {
@@ -0,0 +0,0 @@ public class EnderDragon extends Mob implements Enemy {
this.move(MoverType.SELF, new Vec3(0.0D, 0.10000000149011612D, 0.0D));
if (this.dragonDeathTime == 200 && this.level() instanceof ServerLevel) {
if (true) { // CraftBukkit - SPIGOT-2420: Already checked for the game rule when calculating the xp
- 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
@@ -0,0 +0,0 @@ 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(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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java
@@ -0,0 +0,0 @@ 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/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
@@ -0,0 +0,0 @@ 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(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);
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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/block/Block.java
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
@@ -0,0 +0,0 @@ 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(pos), size);
+ ExperienceOrb.award(world, Vec3.atCenterOf(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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 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
@@ -0,0 +0,0 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
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/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
@@ -0,0 +0,0 @@ public abstract class CraftRegionAccessor implements RegionAccessor {
} else if (TNTPrimed.class.isAssignableFrom(clazz)) {
entity = new PrimedTnt(world, x, y, z, null);
} else if (ExperienceOrb.class.isAssignableFrom(clazz)) {
- entity = new net.minecraft.world.entity.ExperienceOrb(world, x, y, z, 0);
+ entity = new net.minecraft.world.entity.ExperienceOrb(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);
entity.moveTo(location.getX(), location.getY(), location.getZ());
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java
@@ -0,0 +0,0 @@ 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;