Paper/patches/server/0278-Fixes-and-additions-to-the-spawn-reason-API.patch
Jason Penilla 580a610550
Allow using old ender pearl behavior & apply ender pearl exploit patch (#11524)
When enabled, ender pearls will not load chunks and will save to the world instead of the player.

Also changes the exploit config to be default false, as it only makes sense when legacy behavior is enabled.
2024-10-30 18:09:05 +01:00

290 lines
19 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 24 Mar 2019 00:24:52 -0400
Subject: [PATCH] Fixes and additions to the spawn reason API
Expose an entities spawn reason on the entity.
Pre existing entities will return NATURAL if it was a non
persistenting Living Entity, SPAWNER for spawners,
or DEFAULT since data was not stored.
Additionally, add missing spawn reasons.
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
Co-authored-by: Doc <nachito94@msn.com>
diff --git a/src/main/java/net/minecraft/server/commands/SummonCommand.java b/src/main/java/net/minecraft/server/commands/SummonCommand.java
index f55832ce841621daab4d3a910650ab6562cefcda..f635da34335cd2901adf975fcd74c5c6f9785836 100644
--- a/src/main/java/net/minecraft/server/commands/SummonCommand.java
+++ b/src/main/java/net/minecraft/server/commands/SummonCommand.java
@@ -57,6 +57,7 @@ public class SummonCommand {
ServerLevel worldserver = source.getLevel();
Entity entity = EntityType.loadEntityRecursive(nbttagcompound1, worldserver, EntitySpawnReason.COMMAND, (entity1) -> {
entity1.moveTo(pos.x, pos.y, pos.z, entity1.getYRot(), entity1.getXRot());
+ entity1.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.COMMAND; // Paper - Entity#getEntitySpawnReason
return entity1;
});
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 0635e7ed67d45abb7c419cf4ebda0e64718b630e..91e462544b82e0fe41851fa0fa3f6d6f08ac490d 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1172,6 +1172,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
return true;
}
// Paper end - extra debug info
+ if (entity.spawnReason == null) entity.spawnReason = spawnReason; // Paper - Entity#getEntitySpawnReason
if (entity.isRemoved()) {
// WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getKey(entity.getType())); // CraftBukkit
return false;
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 9cfd0b457f6c462921667b9439a7b3e32d019758..62412b37d4f7d37b3fec0966ab700c2ae4d8cada 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -716,7 +716,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
ServerLevel worldserver = (ServerLevel) world;
CompoundTag nbttagcompound = ((CompoundTag) nbt.get()).getCompound("RootVehicle");
Entity entity = EntityType.loadEntityRecursive(nbttagcompound.getCompound("Entity"), worldserver, EntitySpawnReason.LOAD, (entity1) -> {
- return !worldserver.addWithUUID(entity1) ? null : entity1;
+ return !worldserver.addWithUUID(entity1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.MOUNT) ? null : entity1; // CraftBukkit - decompile error // Paper - Entity#getEntitySpawnReason
});
if (entity == null) {
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index c75bc7427bd818e9d23ca0af2b08cb160f3c432e..fd1fe9a72a1d4e87b97a34fc79ab1429d31207e5 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -223,6 +223,11 @@ public abstract class PlayerList {
worldserver1 = worldserver;
}
+ // Paper start - Entity#getEntitySpawnReason
+ if (optional.isEmpty()) {
+ player.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT; // set Player SpawnReason to DEFAULT on first login
+ }
+ // Paper end - Entity#getEntitySpawnReason
player.setServerLevel(worldserver1);
String s1 = connection.getLoggableAddress(this.server.logIPs());
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 5d551a50e1043e369ebf3ddfe181be1e24cfd068..463d34e7b54efd503c4879d1386b2439474863dd 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -255,6 +255,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
}
// Paper end - Share random for entities to make them more random
+ public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper - Entity#getEntitySpawnReason
private CraftEntity bukkitEntity;
@@ -2390,6 +2391,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
nbttagcompound.put("Paper.Origin", this.newDoubleList(origin.getX(), origin.getY(), origin.getZ()));
}
+ if (spawnReason != null) {
+ nbttagcompound.putString("Paper.SpawnReason", spawnReason.name());
+ }
// Save entity's from mob spawner status
if (spawnedViaMobSpawner) {
nbttagcompound.putBoolean("Paper.FromMobSpawner", true);
@@ -2537,6 +2541,26 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
spawnedViaMobSpawner = nbt.getBoolean("Paper.FromMobSpawner"); // Restore entity's from mob spawner status
+ if (nbt.contains("Paper.SpawnReason")) {
+ String spawnReasonName = nbt.getString("Paper.SpawnReason");
+ try {
+ spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.valueOf(spawnReasonName);
+ } catch (Exception ignored) {
+ LOGGER.error("Unknown SpawnReason " + spawnReasonName + " for " + this);
+ }
+ }
+ if (spawnReason == null) {
+ if (spawnedViaMobSpawner) {
+ spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER;
+ } else if (this instanceof Mob && (this instanceof net.minecraft.world.entity.animal.Animal || this instanceof net.minecraft.world.entity.animal.AbstractFish) && !((Mob) this).removeWhenFarAway(0.0)) {
+ if (!nbt.getBoolean("PersistenceRequired")) {
+ spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL;
+ }
+ }
+ }
+ if (spawnReason == null) {
+ spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT;
+ }
// Paper end
} catch (Throwable throwable) {
diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java
index 8f4ec4f0ea7ff2f9a952120785aea65f6559f897..989b766bc166141a391e0a7c1a5eb815e20acfac 100644
--- a/src/main/java/net/minecraft/world/entity/EntityType.java
+++ b/src/main/java/net/minecraft/world/entity/EntityType.java
@@ -433,7 +433,7 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT
@Nullable
public T spawn(ServerLevel world, @Nullable ItemStack stack, @Nullable Player player, BlockPos pos, EntitySpawnReason spawnReason, boolean alignPosition, boolean invertY) {
// CraftBukkit start
- return this.spawn(world, stack, player, pos, spawnReason, alignPosition, invertY, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG);
+ return this.spawn(world, stack, player, pos, spawnReason, alignPosition, invertY, spawnReason == EntitySpawnReason.DISPENSER ? org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DISPENSE_EGG : org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG); // Paper - use correct spawn reason for dispenser spawn eggs
}
@Nullable
diff --git a/src/main/java/net/minecraft/world/entity/OminousItemSpawner.java b/src/main/java/net/minecraft/world/entity/OminousItemSpawner.java
index 1fc9f883305e150f4bdf478bf0f43e301460cbf2..7b75dbb79e0d2a92cc10838a6e4da973e69125fb 100644
--- a/src/main/java/net/minecraft/world/entity/OminousItemSpawner.java
+++ b/src/main/java/net/minecraft/world/entity/OminousItemSpawner.java
@@ -76,7 +76,7 @@ public class OminousItemSpawner extends Entity {
entity = this.spawnProjectile(serverLevel, projectileItem, itemStack);
} else {
entity = new ItemEntity(serverLevel, this.getX(), this.getY(), this.getZ(), itemStack);
- serverLevel.addFreshEntity(entity);
+ serverLevel.addFreshEntity(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.OMINOUS_ITEM_SPAWNER); // Paper - fixes and addition to spawn reason API
}
serverLevel.levelEvent(3021, this.blockPosition(), 1);
@@ -90,7 +90,7 @@ public class OminousItemSpawner extends Entity {
ProjectileItem.DispenseConfig dispenseConfig = item.createDispenseConfig();
dispenseConfig.overrideDispenseEvent().ifPresent(dispenseEvent -> world.levelEvent(dispenseEvent, this.blockPosition(), 0));
Direction direction = Direction.DOWN;
- Projectile projectile = Projectile.spawnProjectileUsingShoot(
+ Projectile projectile = Projectile.spawnProjectileUsingShootDelayed( // Paper - fixes and addition to spawn reason API
item.asProjectile(world, this.position(), stack, direction),
world,
stack,
@@ -99,7 +99,7 @@ public class OminousItemSpawner extends Entity {
(double)direction.getStepZ(),
dispenseConfig.power(),
dispenseConfig.uncertainty()
- );
+ ).spawn(org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.OMINOUS_ITEM_SPAWNER); // Paper - fixes and addition to spawn reason API
projectile.setOwner(this);
return projectile;
}
diff --git a/src/main/java/net/minecraft/world/entity/projectile/DragonFireball.java b/src/main/java/net/minecraft/world/entity/projectile/DragonFireball.java
index 2eecdcbea3d51b1fb6e0c3db0667464a699ca0df..c68ddccd5fbe27f6a62cedbdc2337f1b6e4d3273 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/DragonFireball.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/DragonFireball.java
@@ -64,7 +64,7 @@ public class DragonFireball extends AbstractHurtingProjectile {
if (new com.destroystokyo.paper.event.entity.EnderDragonFireballHitEvent((org.bukkit.entity.DragonFireball) this.getBukkitEntity(), list.stream().map(LivingEntity::getBukkitLivingEntity).collect(java.util.stream.Collectors.toList()), (org.bukkit.entity.AreaEffectCloud) entityareaeffectcloud.getBukkitEntity()).callEvent()) { // Paper - EnderDragon Events
this.level().levelEvent(2006, this.blockPosition(), this.isSilent() ? -1 : 1);
- this.level().addFreshEntity(entityareaeffectcloud);
+ this.level().addFreshEntity(entityareaeffectcloud, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EXPLOSION); // Paper - use correct spawn reason
} else entityareaeffectcloud.discard(null); // Paper - EnderDragon Events
this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause
}
diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
index 6c7f644738548da30908a08dcfde8142b597c0b7..80637835a35dbfd7c7458b246ddee9d836e5101a 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
@@ -214,7 +214,12 @@ public abstract class Projectile extends Entity implements TraceableEntity {
}
public static <T extends Projectile> T spawnProjectileUsingShoot(T projectile, ServerLevel world, ItemStack projectileStack, double velocityX, double velocityY, double velocityZ, float power, float divergence) {
- return Projectile.spawnProjectile(projectile, world, projectileStack, (iprojectile) -> {
+ // Paper start - fixes and addition to spawn reason API
+ return spawnProjectileUsingShootDelayed(projectile, world, projectileStack, velocityX, velocityY, velocityZ, power, divergence).spawn();
+ }
+ public static <T extends Projectile> Delayed<T> spawnProjectileUsingShootDelayed(T projectile, ServerLevel world, ItemStack projectileStack, double velocityX, double velocityY, double velocityZ, float power, float divergence) {
+ return Projectile.spawnProjectileDelayed(projectile, world, projectileStack, (iprojectile) -> {
+ // Paper end - fixes and addition to spawn reason API
projectile.shoot(velocityX, velocityY, velocityZ, power, divergence);
});
}
@@ -241,6 +246,17 @@ public abstract class Projectile extends Entity implements TraceableEntity {
this.attemptSpawn();
return projectile();
}
+
+ public boolean attemptSpawn(final org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) {
+ if (!world.addFreshEntity(projectile, reason)) return false;
+ projectile.applyOnProjectileSpawned(this.world, this.projectileStack);
+ return true;
+ }
+
+ public T spawn(final org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) {
+ this.attemptSpawn(reason);
+ return projectile();
+ }
}
// Paper end - delayed projectile spawning
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
index 261de9ea37d22023da6a306b58b1b62a54dc03da..299137519dba07c8b2cb35437742b5d40eb9e5d2 100644
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
@@ -191,6 +191,7 @@ public abstract class BaseSpawner {
}
entity.spawnedViaMobSpawner = true; // Paper
+ entity.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER; // Paper - Entity#getEntitySpawnReason
flag = true; // Paper
// CraftBukkit start
if (org.bukkit.craftbukkit.event.CraftEventFactory.callSpawnerSpawnEvent(entity, pos).isCancelled()) {
diff --git a/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java b/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java
index 524f94a00f7b76a3847b68f0ab0cf82cc524b01e..aee71779f31def5f1ef7438cf06219d1de7092ec 100644
--- a/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java
@@ -121,7 +121,7 @@ public class FrogspawnBlock extends Block {
int k = random.nextInt(1, 361);
tadpole.moveTo(d, (double)pos.getY() - 0.5, e, (float)k, 0.0F);
tadpole.setPersistenceRequired();
- world.addFreshEntity(tadpole);
+ world.addFreshEntity(tadpole, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EGG); // Paper - use correct spawn reason
}
}
}
diff --git a/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java b/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java
index fc26713a869d0c1fad1634ef4a6c6282fef5aa31..4f8224841865f956aaa969ab7f543c80b3c24319 100644
--- a/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java
@@ -74,7 +74,7 @@ public class SnifferEggBlock extends Block {
Vec3 vec3 = pos.getCenter();
sniffer.setBaby(true);
sniffer.moveTo(vec3.x(), vec3.y(), vec3.z(), Mth.wrapDegrees(world.random.nextFloat() * 360.0F), 0.0F);
- world.addFreshEntity(sniffer);
+ world.addFreshEntity(sniffer, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EGG); // Paper - use correct spawn reason
}
}
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java
index dc6b18527222d23e9719e2210b684a1aa797c70d..ea53c25c350c0cf8e0360ea409cd1f69a62054a8 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java
@@ -189,7 +189,7 @@ public class SculkShriekerBlockEntity extends BlockEntity implements GameEventLi
private boolean trySummonWarden(ServerLevel world) {
return this.warningLevel >= 4
- && SpawnUtil.trySpawnMob(EntityType.WARDEN, EntitySpawnReason.TRIGGERED, world, this.getBlockPos(), 20, 5, 6, SpawnUtil.Strategy.ON_TOP_OF_COLLIDER)
+ && SpawnUtil.trySpawnMob(EntityType.WARDEN, EntitySpawnReason.TRIGGERED, world, this.getBlockPos(), 20, 5, 6, SpawnUtil.Strategy.ON_TOP_OF_COLLIDER, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL, null) // Paper - Entity#getEntitySpawnReason
.isPresent();
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java b/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java
index f0163b7fa8b27823db9df5b8d2b6adcb63023164..de9d00ec932c8d07b28dd68ac9b8e6d5b94f7a8d 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java
@@ -231,6 +231,7 @@ public final class TrialSpawner {
}
entity.spawnedViaMobSpawner = true; // Paper
+ entity.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.TRIAL_SPAWNER; // Paper - Entity#getEntitySpawnReason
// CraftBukkit start
if (org.bukkit.craftbukkit.event.CraftEventFactory.callTrialSpawnerSpawnEvent(entity, pos).isCancelled()) {
return Optional.empty();
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 0e5cc680ee2418ec2af5fc3e215618ad4e768ed0..7fb04535b8c0744d0fa4b0c0a933234134486956 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -1019,4 +1019,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
return this.getHandle().spawnedViaMobSpawner;
}
// Paper end - Entity#fromMobSpawner
+
+ // Paper start - entity spawn reason API
+ @Override
+ public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason getEntitySpawnReason() {
+ return getHandle().spawnReason;
+ }
+ // Paper end - entity spawn reason API
}