diff --git a/build-data/paper.at b/build-data/paper.at index f7bc3ced1c..13f5525a66 100644 --- a/build-data/paper.at +++ b/build-data/paper.at @@ -474,6 +474,7 @@ public net.minecraft.world.entity.projectile.LargeFireball explosionPower public net.minecraft.world.entity.projectile.Projectile cachedOwner public net.minecraft.world.entity.projectile.Projectile hasBeenShot public net.minecraft.world.entity.projectile.Projectile leftOwner +public net.minecraft.world.entity.projectile.Projectile owner public net.minecraft.world.entity.projectile.Projectile ownerUUID public net.minecraft.world.entity.projectile.ShulkerBullet currentMoveDirection public net.minecraft.world.entity.projectile.ShulkerBullet flightSteps diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch index c1c8ee04d7..d4e161bb5f 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch @@ -630,8 +630,8 @@ + org.bukkit.Location exit = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(absolutePosition.position(), level.getWorld(), absolutePosition.yRot(), absolutePosition.xRot()); + org.bukkit.event.player.PlayerTeleportEvent tpEvent = new org.bukkit.event.player.PlayerTeleportEvent(this.getBukkitEntity(), enter, exit.clone(), teleportTransition.cause()); + // Paper start - gateway-specific teleport event -+ if (this.portalProcess != null && this.portalProcess.isSamePortal(((net.minecraft.world.level.block.EndGatewayBlock) net.minecraft.world.level.block.Blocks.END_GATEWAY)) && this.serverLevel().getBlockEntity(this.portalProcess.getEntryPosition()) instanceof net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity theEndGatewayBlockEntity) { -+ tpEvent = new com.destroystokyo.paper.event.player.PlayerTeleportEndGatewayEvent(this.getBukkitEntity(), enter, exit.clone(), new org.bukkit.craftbukkit.block.CraftEndGateway(this.serverLevel().getWorld(), theEndGatewayBlockEntity)); ++ if (this.portalProcess != null && this.portalProcess.isSamePortal(((net.minecraft.world.level.block.EndGatewayBlock) net.minecraft.world.level.block.Blocks.END_GATEWAY)) && this.level().getBlockEntity(this.portalProcess.getEntryPosition()) instanceof net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity theEndGatewayBlockEntity) { ++ tpEvent = new com.destroystokyo.paper.event.player.PlayerTeleportEndGatewayEvent(this.getBukkitEntity(), enter, exit.clone(), new org.bukkit.craftbukkit.block.CraftEndGateway(this.level().getWorld(), theEndGatewayBlockEntity)); + } + // Paper end - gateway-specific teleport event + org.bukkit.Bukkit.getServer().getPluginManager().callEvent(tpEvent); diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index d454ab81fc..b0b837591b 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -208,6 +_,39 @@ +@@ -208,6 +_,38 @@ import net.minecraft.world.phys.shapes.VoxelShape; import org.slf4j.Logger; @@ -33,7 +33,6 @@ +import org.bukkit.event.player.PlayerSwapHandItemsEvent; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.event.player.PlayerToggleFlightEvent; -+import org.bukkit.event.player.PlayerToggleSneakEvent; +import org.bukkit.event.player.PlayerToggleSprintEvent; +// CraftBukkit end + @@ -141,7 +140,7 @@ } private int getMaximumFlyingTicks(Entity entity) { -@@ -388,11 +_,22 @@ +@@ -388,11 +_,37 @@ @Override public void handlePlayerInput(ServerboundPlayerInputPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); @@ -151,16 +150,33 @@ + this.cserver.getPluginManager().callEvent(event); + } + // CraftBukkit end ++ // Paper ++ net.minecraft.world.entity.player.Input lastInput = this.player.getLastClientInput(); ++ boolean shiftKeyDown =packet.input().shift(); ++ if (lastInput.shift() != packet.input().shift()) { ++ // Has sneak changed ++ org.bukkit.event.player.PlayerToggleSneakEvent event = new org.bukkit.event.player.PlayerToggleSneakEvent(this.getCraftPlayer(), packet.input().shift()); ++ this.cserver.getPluginManager().callEvent(event); ++ ++ // Technically the player input and the flag is desynced, but this is previous behavior.. so should be fine? ++ if (event.isCancelled()) { ++ shiftKeyDown = this.player.isShiftKeyDown(); ++ } ++ } ++ // Paper end this.player.setLastClientInput(packet.input()); if (this.player.hasClientLoaded()) { this.player.resetLastActionTime(); - this.player.setShiftKeyDown(packet.input().shift()); - } +- this.player.setShiftKeyDown(packet.input().shift()); +- } ++ this.player.setShiftKeyDown(shiftKeyDown); // Paper ++ } + // Paper start - Add option to make parrots stay + if (packet.input().shift() && this.player.level().paperConfig().entities.behavior.parrotsAreUnaffectedByPlayerMovement) { + this.player.removeEntitiesOnShoulder(); + } + // Paper end - Add option to make parrots stay ++ } private static boolean containsInvalidValues(double x, double y, double z, float yRot, float xRot) { @@ -351,7 +367,7 @@ this.lastGoodZ = this.awaitingPositionFromClient.z; this.player.hasChangedDimension(); this.awaitingPositionFromClient = null; -+ this.player.serverLevel().getChunkSource().move(this.player); // CraftBukkit ++ this.player.level().getChunkSource().move(this.player); // CraftBukkit } } @@ -1702,23 +1718,13 @@ this.player.swing(packet.getHand()); } -@@ -1598,6 +_,32 @@ +@@ -1598,6 +_,22 @@ public void handlePlayerCommand(ServerboundPlayerCommandPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); if (this.player.hasClientLoaded()) { + // CraftBukkit start + if (this.player.isRemoved()) return; + switch (packet.getAction()) { -+ case PRESS_SHIFT_KEY: -+ case RELEASE_SHIFT_KEY: { -+ PlayerToggleSneakEvent event = new PlayerToggleSneakEvent(this.getCraftPlayer(), packet.getAction() == ServerboundPlayerCommandPacket.Action.PRESS_SHIFT_KEY); -+ this.cserver.getPluginManager().callEvent(event); -+ -+ if (event.isCancelled()) { -+ return; -+ } -+ break; -+ } + case START_SPRINTING: + case STOP_SPRINTING: { + PlayerToggleSprintEvent event = new PlayerToggleSprintEvent(this.getCraftPlayer(), packet.getAction() == ServerboundPlayerCommandPacket.Action.START_SPRINTING); @@ -1948,7 +1954,7 @@ - this.player.setGameMode(GameType.SPECTATOR); - this.player.level().getGameRules().getRule(GameRules.RULE_SPECTATORSGENERATECHUNKS).set(false, this.server); + this.player.setGameMode(GameType.SPECTATOR, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.HARDCORE_DEATH, null); // Paper - Expand PlayerGameModeChangeEvent -+ this.player.level().getGameRules().getRule(GameRules.RULE_SPECTATORSGENERATECHUNKS).set(false, this.player.serverLevel()); // CraftBukkit - per-world ++ this.player.level().getGameRules().getRule(GameRules.RULE_SPECTATORSGENERATECHUNKS).set(false, this.player.level()); // CraftBukkit - per-world } } break; 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 59bb381b16..eee7778a78 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 @@ -207,7 +207,7 @@ } + // CraftBukkit start -+ input.getDouble("Bukkit.MaxHealth").ifPresent(maxHealth -> { ++ input.read("Bukkit.MaxHealth", com.mojang.serialization.Codec.DOUBLE).ifPresent(maxHealth -> { + this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(maxHealth); + }); + // CraftBukkit end @@ -944,7 +944,7 @@ + protected void dropExperience(ServerLevel level, @Nullable Entity entity) { + // 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(level, this.position(), this.expToDrop, this instanceof ServerPlayer ? org.bukkit.entity.ExperienceOrb.SpawnReason.PLAYER_DEATH : org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, entity, this); // Paper ++ ExperienceOrb.awardWithDirection(level, this.position(), net.minecraft.world.phys.Vec3.ZERO, this.expToDrop, this instanceof ServerPlayer ? org.bukkit.entity.ExperienceOrb.SpawnReason.PLAYER_DEATH : org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, entity, this); // Paper + this.expToDrop = 0; + } + // CraftBukkit end @@ -1564,7 +1564,7 @@ public void onItemPickup(ItemEntity itemEntity) { - Entity owner = itemEntity.getOwner(); -+ Entity owner = itemEntity.thrower != null ? this.level().getGlobalPlayerByUUID(itemEntity.thrower) : null; // Paper - check global player list where appropriate ++ Entity owner = itemEntity.thrower != null ? itemEntity.thrower.getEntity(this.level()::getGlobalPlayerByUUID, Entity.class) : null; // Paper - check global player list where appropriate if (owner instanceof ServerPlayer) { CriteriaTriggers.THROWN_ITEM_PICKED_UP_BY_ENTITY.trigger((ServerPlayer)owner, itemEntity.getItem(), this); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/TemptGoal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/TemptGoal.java.patch index 72d4a62d17..cd8fcb0799 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/TemptGoal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/TemptGoal.java.patch @@ -25,3 +25,21 @@ return this.player != null; } } +@@ -123,7 +_,7 @@ + this.mob.getNavigation().stop(); + } + +- protected void navigateTowards(Player player) { ++ protected void navigateTowards(LivingEntity player) { // Paper + this.mob.getNavigation().moveTo(player, this.speedModifier); + } + +@@ -142,7 +_,7 @@ + } + + @Override +- protected void navigateTowards(Player player) { ++ protected void navigateTowards(LivingEntity player) { // Paper + Vec3 vec3 = player.getEyePosition().subtract(this.mob.position()).scale(this.mob.getRandom().nextDouble()).add(this.mob.position()); + this.mob.getMoveControl().setWantedPosition(vec3.x, vec3.y, vec3.z, this.speedModifier); + } 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 016a9af2e0..91eccbe3ea 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 @@ -108,7 +108,7 @@ - if (level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { - level.addFreshEntity(new ExperienceOrb(level, this.getX(), this.getY(), this.getZ(), this.getRandom().nextInt(7) + 1)); + if (experience > 0 && level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { // Paper - Call EntityBreedEvent -+ level.addFreshEntity(new ExperienceOrb(level, this.getX(), this.getY(), this.getZ(), experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, player, baby)); // Paper - Call EntityBreedEvent, add spawn context ++ level.addFreshEntity(new ExperienceOrb(level, this.position(), net.minecraft.world.phys.Vec3.ZERO, experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, player, baby)); // Paper - Call EntityBreedEvent, add spawn context } } 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 aefa549f0a..9966eed6ef 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 @@ -142,7 +142,7 @@ this.level .addFreshEntity( - new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), this.animal.getRandom().nextInt(7) + 1) -+ new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, loveCause, fox) // Paper - call EntityBreedEvent, add spawn context ++ new ExperienceOrb(this.level, this.animal.position(), net.minecraft.world.phys.Vec3.ZERO, experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, loveCause, fox) // Paper - call EntityBreedEvent, add spawn context ); } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/HappyGhast.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/HappyGhast.java.patch new file mode 100644 index 0000000000..ec9a0957a0 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/HappyGhast.java.patch @@ -0,0 +1,25 @@ +--- a/net/minecraft/world/entity/animal/HappyGhast.java ++++ b/net/minecraft/world/entity/animal/HappyGhast.java +@@ -296,8 +_,12 @@ + } + + @Override +- protected void removePassenger(Entity passenger) { +- super.removePassenger(passenger); ++ // Paper start - cancellable passengers ++ protected boolean removePassenger(Entity passenger) { ++ if (!super.removePassenger(passenger)) { ++ return false; ++ } ++ // Paper end - cancellable passengers + if (!this.level().isClientSide) { + this.setServerStillTimeout(this.getPassengers().isEmpty() ? 40 : 10); + } +@@ -306,6 +_,7 @@ + this.clearHome(); + this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.HARNESS_GOGGLES_UP, this.getSoundSource(), 1.0F, 1.0F); + } ++ return true; // Paper - cancellable passengers + } + + @Override 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 00cd38d78f..6f29caadf8 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 @@ -35,7 +35,7 @@ RandomSource random = this.animal.getRandom(); if (getServerLevel(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)); -+ if (event.getExperience() > 0) this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), event.getExperience(), org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, loveCause)); // Paper - Add EntityFertilizeEggEvent event ++ if (event.getExperience() > 0) this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.position(), Vec3.ZERO, event.getExperience(), org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, loveCause, this.turtle)); // Paper - Add EntityFertilizeEggEvent event } } } 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 fa85b29fdb..57b67674cb 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 @@ -186,7 +186,7 @@ - if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0 && serverLevel.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { - ExperienceOrb.award(serverLevel, this.position(), Mth.floor(i * 0.08F)); + if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0) { // CraftBukkit - SPIGOT-2420: Already checked for the game rule when calculating the xp -+ ExperienceOrb.award(serverLevel, this.position(), Mth.floor(i * 0.08F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, net.minecraft.Optionull.map(this.lastHurtByPlayer, lastHurtByPlayer -> lastHurtByPlayer.getEntity(this.level(), Player.class)), this); // Paper ++ ExperienceOrb.awardWithDirection(serverLevel, this.position(), net.minecraft.world.phys.Vec3.ZERO, Mth.floor(i * 0.08F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, net.minecraft.Optionull.map(this.lastHurtByPlayer, lastHurtByPlayer -> lastHurtByPlayer.getEntity(this.level(), Player.class)), this); // Paper } if (this.dragonDeathTime == 1 && !this.isSilent()) { @@ -220,7 +220,7 @@ - if (serverLevel1.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { - ExperienceOrb.award(serverLevel1, this.position(), Mth.floor(i * 0.2F)); + if (true) { // Paper - SPIGOT-2420: Already checked for the game rule when calculating the xp -+ ExperienceOrb.award(serverLevel1, this.position(), Mth.floor(i * 0.2F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, net.minecraft.Optionull.map(this.lastHurtByPlayer, lastHurtByPlayer -> lastHurtByPlayer.getEntity(this.level(), Player.class)), this); // Paper ++ ExperienceOrb.awardWithDirection(serverLevel1, this.position(), net.minecraft.world.phys.Vec3.ZERO, Mth.floor(i * 0.2F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, net.minecraft.Optionull.map(this.lastHurtByPlayer, lastHurtByPlayer -> lastHurtByPlayer.getEntity(this.level(), Player.class)), this); // Paper } if (this.dragonFight != null) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch index 75b9fb6401..1a07996263 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch @@ -86,7 +86,7 @@ protected void dropCustomDeathLoot(ServerLevel level, DamageSource damageSource, boolean recentlyHit) { super.dropCustomDeathLoot(level, damageSource, recentlyHit); - ItemEntity itemEntity = this.spawnAtLocation(level, Items.NETHER_STAR); -+ ItemEntity itemEntity = this.spawnAtLocation(level, new net.minecraft.world.item.ItemStack(Items.NETHER_STAR), 0, ItemEntity::setExtendedLifetime); // Paper - Restore vanilla drops behavior; spawnAtLocation returns null so modify the item entity with a consumer ++ ItemEntity itemEntity = this.spawnAtLocation(level, new net.minecraft.world.item.ItemStack(Items.NETHER_STAR), net.minecraft.world.phys.Vec3.ZERO, ItemEntity::setExtendedLifetime); // Paper - Restore vanilla drops behavior; spawnAtLocation returns null so modify the item entity with a consumer if (itemEntity != null) { - itemEntity.setExtendedLifetime(); + itemEntity.setExtendedLifetime(); // Paper - diff on change 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 a66203b64b..81cd2f4684 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 @@ -215,7 +215,7 @@ + playerOwner.level() + .addFreshEntity( + new ExperienceOrb( -+ playerOwner.level(), playerOwner.getX(), playerOwner.getY() + 0.5, playerOwner.getZ() + 0.5, playerFishEvent.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.FISHING, this.getPlayerOwner(), this // Paper ++ playerOwner.level(), new net.minecraft.world.phys.Vec3(playerOwner.getX(), playerOwner.getY() + 0.5, playerOwner.getZ() + 0.5), net.minecraft.world.phys.Vec3.ZERO, playerFishEvent.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.FISHING, this.getPlayerOwner(), this // Paper + ) + ); + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch index b16a8c78af..4be838d664 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch @@ -1,6 +1,12 @@ --- a/net/minecraft/world/entity/projectile/Projectile.java +++ b/net/minecraft/world/entity/projectile/Projectile.java -@@ -44,6 +_,7 @@ +@@ -39,11 +_,12 @@ + private static final boolean DEFAULT_LEFT_OWNER = false; + private static final boolean DEFAULT_HAS_BEEN_SHOT = false; + @Nullable +- public EntityReference owner; ++ protected EntityReference owner; + public boolean leftOwner = false; public boolean hasBeenShot = false; @Nullable private Entity lastDeflectedBy; 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 ec3ca35574..39b09b925f 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 @@ -70,7 +70,7 @@ + // Paper start - Fire BlockExpEvent on grindstone use + org.bukkit.event.block.BlockExpEvent event = new org.bukkit.event.block.BlockExpEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPos), this.getExperienceAmount(level)); + event.callEvent(); -+ ExperienceOrb.award((ServerLevel) level, Vec3.atCenterOf(blockPos), event.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player); ++ ExperienceOrb.awardWithDirection((ServerLevel) level, Vec3.atCenterOf(blockPos), Vec3.ZERO, event.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player, null); + // Paper end - Fire BlockExpEvent on grindstone use } diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/Consumable.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/Consumable.java.patch index d39f21455d..fff05a6ec0 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/Consumable.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/Consumable.java.patch @@ -30,7 +30,7 @@ + stack.getAllOfType(ConsumableListener.class).forEach(listener -> { + listener.cancelUsingItem(player, stack, packets); // Paper - properly resend entities - collect packets for bundle + }); -+ player.server.getPlayerList().sendActiveEffects(player, packets::add); // Paper - properly resend entities - collect packets for bundle ++ player.getServer().getPlayerList().sendActiveEffects(player, packets::add); // Paper - properly resend entities - collect packets for bundle + player.connection.send(new net.minecraft.network.protocol.game.ClientboundBundlePacket(packets)); + } + // CraftBukkit end 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 557a1c5cf8..cfcc81eb86 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 @@ -90,7 +90,7 @@ + // Paper end - add entity parameter if (level.getGameRules().getBoolean(GameRules.RULE_DOBLOCKDROPS)) { - ExperienceOrb.award(level, Vec3.atCenterOf(pos), amount); -+ ExperienceOrb.award(level, Vec3.atCenterOf(pos), amount, org.bukkit.entity.ExperienceOrb.SpawnReason.BLOCK_BREAK, entity); // Paper ++ ExperienceOrb.awardWithDirection(level, Vec3.atCenterOf(pos), net.minecraft.world.phys.Vec3.ZERO, amount, org.bukkit.entity.ExperienceOrb.SpawnReason.BLOCK_BREAK, entity, null); // Paper } } 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 878fe95a72..6145f471fc 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 @@ -268,7 +268,7 @@ + floor = event.getExpToDrop(); + // CraftBukkit end + -+ ExperienceOrb.award(level, popVec, floor, org.bukkit.entity.ExperienceOrb.SpawnReason.FURNACE, serverPlayer); // Paper ++ ExperienceOrb.awardWithDirection(level, popVec, net.minecraft.world.phys.Vec3.ZERO, floor, org.bukkit.entity.ExperienceOrb.SpawnReason.FURNACE, serverPlayer, null); // Paper } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch index 2c9a995f99..cace6fd267 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch @@ -26,7 +26,7 @@ + // Paper end - guard against serializing mismatching coordinates + + // Paper start - Do not let the server load chunks from newer versions -+ private static final int CURRENT_DATA_VERSION = net.minecraft.SharedConstants.getCurrentVersion().getDataVersion().getVersion(); ++ private static final int CURRENT_DATA_VERSION = net.minecraft.SharedConstants.getCurrentVersion().dataVersion().getVersion(); + private static final boolean JUST_CORRUPT_IT = Boolean.getBoolean("Paper.ignoreWorldDataVersion"); + // Paper end - Do not let the server load chunks from newer versions + diff --git a/paper-server/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/paper-server/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java index 790bad0494..74ffdc823e 100644 --- a/paper-server/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java +++ b/paper-server/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java @@ -45,8 +45,8 @@ public record ServerBuildInfoImpl( .orElse(BRAND_PAPER_ID), getManifestAttribute(manifest, ATTRIBUTE_BRAND_NAME) .orElse(BRAND_PAPER_NAME), - SharedConstants.getCurrentVersion().getId(), - SharedConstants.getCurrentVersion().getName(), + SharedConstants.getCurrentVersion().id(), + SharedConstants.getCurrentVersion().name(), getManifestAttribute(manifest, ATTRIBUTE_BUILD_NUMBER) .map(Integer::parseInt) .map(OptionalInt::of) diff --git a/paper-server/src/main/java/io/papermc/paper/command/subcommands/MobcapsCommand.java b/paper-server/src/main/java/io/papermc/paper/command/subcommands/MobcapsCommand.java index d3b39d88a7..950e709a7b 100644 --- a/paper-server/src/main/java/io/papermc/paper/command/subcommands/MobcapsCommand.java +++ b/paper-server/src/main/java/io/papermc/paper/command/subcommands/MobcapsCommand.java @@ -162,7 +162,7 @@ public final class MobcapsCommand implements PaperSubcommand { } final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - final ServerLevel level = serverPlayer.serverLevel(); + final ServerLevel level = serverPlayer.level(); if (!level.paperConfig().entities.spawning.perPlayerMobSpawns) { sender.sendMessage(Component.text("Use '/paper mobcaps' for worlds where per-player mob spawning is disabled.", NamedTextColor.RED)); diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperEquippable.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperEquippable.java index 2f4d593e9d..b0e2b9a1e6 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperEquippable.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperEquippable.java @@ -177,7 +177,9 @@ public record PaperEquippable( this.dispensable, this.swappable, this.damageOnHurt, - this.equipOnInteract + this.equipOnInteract, + false, // TODO + Holder.direct(SoundEvents.GOAT_SCREAMING_DEATH) // TODO ) ); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java index 43ae147ae1..54ab8a0b50 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java @@ -10,11 +10,14 @@ import java.util.Map; import java.util.UUID; import net.minecraft.core.GlobalPos; import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.game.ClientboundTagQueryPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.players.UserWhiteListEntry; import net.minecraft.stats.ServerStatsCounter; +import net.minecraft.util.ProblemReporter; import net.minecraft.world.level.storage.PlayerDataStorage; +import net.minecraft.world.level.storage.TagValueOutput; import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; import org.bukkit.BanEntry; @@ -196,7 +199,8 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa } private CompoundTag getData() { - return this.storage.load(this.profile.getName(), this.profile.getId().toString()).orElse(null); + // This method does not use the problem reporter + return this.storage.load(this.profile.getName(), this.profile.getId().toString(), ProblemReporter.DISCARDING).orElse(null); } private CompoundTag getBukkitData() { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java index 7f1b758e50..9f20a8543b 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java @@ -8,8 +8,10 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; +import net.minecraft.core.RegistryAccess; import net.minecraft.nbt.CompoundTag; import net.minecraft.util.InclusiveRange; +import net.minecraft.util.ProblemReporter; import net.minecraft.util.RandomSource; import net.minecraft.util.random.Weighted; import net.minecraft.util.random.WeightedList; @@ -17,6 +19,8 @@ import net.minecraft.world.entity.EquipmentTable; import net.minecraft.world.level.BaseSpawner; import net.minecraft.world.level.SpawnData; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; +import net.minecraft.world.level.storage.TagValueInput; +import net.minecraft.world.level.storage.ValueInput; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreatureSpawner; @@ -46,8 +50,11 @@ public class CraftCreatureSpawner extends CraftBlockEntityState> type = net.minecraft.world.entity.EntityType.by(spawnData.getEntityToSpawn()); - return type.map(CraftEntityType::minecraftToBukkit).orElse(null); + try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(() -> "spawner@" + getLocation(), LOGGER)) { + ValueInput valueInput = TagValueInput.create(scopedCollector, this.getInternalWorld().registryAccess(), spawnData.entityToSpawn()); + Optional> type = net.minecraft.world.entity.EntityType.by(valueInput); + return type.map(CraftEntityType::minecraftToBukkit).orElse(null); + } } @Override @@ -175,9 +182,12 @@ public class CraftCreatureSpawner extends CraftBlockEntityState "spawner@" + getLocation(), LOGGER)) { + ValueInput valueInput = TagValueInput.create(scopedCollector, this.getInternalWorld().registryAccess(), spawnData.getEntityToSpawn()); + Optional> type = net.minecraft.world.entity.EntityType.by(valueInput); - Optional> type = net.minecraft.world.entity.EntityType.by(spawnData.getEntityToSpawn()); - return type.map(CraftEntityType::minecraftToBukkit).map(CraftEntityType::bukkitToString).orElse(null); + return type.map(CraftEntityType::minecraftToBukkit).map(CraftEntityType::bukkitToString).orElse(null); + } } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java index 8244b7eaca..496027a464 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java @@ -1,5 +1,7 @@ package org.bukkit.craftbukkit.entity; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityReference; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.entity.Projectile; @@ -76,7 +78,12 @@ public abstract class AbstractProjectile extends CraftEntity implements Projecti @Override public java.util.UUID getOwnerUniqueId() { - return this.getHandle().ownerUUID; + EntityReference reference = this.getHandle().owner; + if (reference == null) { + return null; + } + + return reference.getUUID(); } // Paper end - More projectile API } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftAnimals.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftAnimals.java index 9bd90d0589..960864353d 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftAnimals.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftAnimals.java @@ -2,6 +2,8 @@ package org.bukkit.craftbukkit.entity; import com.google.common.base.Preconditions; import java.util.UUID; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.EntityReference; import net.minecraft.world.entity.animal.Animal; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftServer; @@ -22,12 +24,17 @@ public class CraftAnimals extends CraftAgeable implements Animals { @Override public UUID getBreedCause() { - return this.getHandle().loveCause; + EntityReference reference = this.getHandle().loveCause; + if (reference == null) { + return null; + } + + return reference.getUUID(); } @Override public void setBreedCause(UUID uuid) { - this.getHandle().loveCause = uuid; + this.getHandle().loveCause = new EntityReference<>(uuid); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java index 934eb5c668..9b862c0c1f 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java @@ -8,6 +8,7 @@ import java.util.Collection; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; +import com.mojang.logging.LogUtils; import io.papermc.paper.adventure.PaperAdventure; import net.kyori.adventure.key.Key; import net.minecraft.core.BlockPos; @@ -18,11 +19,13 @@ import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; import net.minecraft.network.protocol.game.ServerboundContainerClosePacket; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.ProblemReporter; import net.minecraft.world.MenuProvider; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.TamableAnimal; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.FireworkRocketEntity; @@ -38,6 +41,7 @@ import net.minecraft.world.level.block.BedBlock; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.storage.TagValueInput; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; @@ -78,9 +82,11 @@ import org.bukkit.permissions.PermissionAttachmentInfo; import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { + private static final Logger LOGGER = LogUtils.getLogger(); private CraftInventoryPlayer inventory; private final CraftInventory enderChest; protected final PermissibleBase perm = new PermissibleBase(this); @@ -175,7 +181,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { return null; } - net.minecraft.server.level.ServerLevel level = ((ServerPlayer) this.getHandle()).server.getLevel(respawnConfig.dimension()); + net.minecraft.server.level.ServerLevel level = ((ServerPlayer) this.getHandle()).getServer().getLevel(respawnConfig.dimension()); if (level == null) { return null; } @@ -769,8 +775,13 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { @Override public org.bukkit.entity.Entity getShoulderEntityLeft() { if (!this.getHandle().getShoulderEntityLeft().isEmpty()) { - Optional shoulder = EntityType.create(this.getHandle().getShoulderEntityLeft(), this.getHandle().level(), EntitySpawnReason.LOAD); - return shoulder.map(Entity::getBukkitEntity).orElse(null); + try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(this.getHandle().problemPath(), LOGGER)) { + return EntityType.create( + TagValueInput.create(scopedCollector.forChild(() -> ".shoulder"), this.getHandle().registryAccess(), this.getHandle().getShoulderEntityLeft()), + this.getHandle().level(), + EntitySpawnReason.LOAD + ).map(Entity::getBukkitEntity).orElse(null); + } } return null; @@ -787,8 +798,13 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { @Override public org.bukkit.entity.Entity getShoulderEntityRight() { if (!this.getHandle().getShoulderEntityRight().isEmpty()) { - Optional shoulder = EntityType.create(this.getHandle().getShoulderEntityRight(), this.getHandle().level(), EntitySpawnReason.LOAD); - return shoulder.map(Entity::getBukkitEntity).orElse(null); + try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(this.getHandle().problemPath(), LOGGER)) { + return EntityType.create( + TagValueInput.create(scopedCollector.forChild(() -> ".shoulder"), this.getHandle().registryAccess(), this.getHandle().getShoulderEntityRight()), + this.getHandle().level(), + EntitySpawnReason.LOAD + ).map(Entity::getBukkitEntity).orElse(null); + } } return null; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index b155e2da2f..5dc0895627 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -1562,7 +1562,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { final ServerPlayer.RespawnConfig respawnConfig = this.getHandle().getRespawnConfig(); if (respawnConfig == null) return null; - final ServerLevel world = this.getHandle().server.getLevel(respawnConfig.dimension()); + final ServerLevel world = this.getHandle().getServer().getLevel(respawnConfig.dimension()); if (world == null) return null; if (!loadLocationAndValidate) { @@ -1887,7 +1887,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { orb.setPosRaw(handle.getX(), handle.getY(), handle.getZ()); final int possibleDurabilityFromXp = net.minecraft.world.item.enchantment.EnchantmentHelper.modifyDurabilityToRepairFromXp( - handle.serverLevel(), itemstack, amount + handle.level(), itemstack, amount ); int i = Math.min(possibleDurabilityFromXp, itemstack.getDamageValue()); final int consumedExperience = i > 0 ? i * amount / possibleDurabilityFromXp : possibleDurabilityFromXp; // Paper - taken from ExperienceOrb#repairPlayerItems + prevent division by 0 @@ -2236,11 +2236,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player { ServerGamePacketListenerImpl connection = handle.connection; // Respawn the player then update their position and selected slot - ServerLevel level = handle.serverLevel(); + ServerLevel level = handle.level(); connection.send(new net.minecraft.network.protocol.game.ClientboundRespawnPacket(handle.createCommonSpawnInfo(level), net.minecraft.network.protocol.game.ClientboundRespawnPacket.KEEP_ALL_DATA)); handle.onUpdateAbilities(); connection.internalTeleport(net.minecraft.world.entity.PositionMoveRotation.of(this.getHandle()), java.util.Collections.emptySet()); - net.minecraft.server.players.PlayerList playerList = handle.server.getPlayerList(); + net.minecraft.server.players.PlayerList playerList = handle.getServer().getPlayerList(); playerList.sendPlayerPermissionLevel(handle, false); playerList.sendLevelInfo(handle, level); playerList.sendAllPlayerInfo(handle); @@ -3010,7 +3010,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { public void updateCommands() { if (this.getHandle().connection == null) return; - this.getHandle().server.getCommands().sendCommands(this.getHandle()); + this.getHandle().getServer().getCommands().sendCommands(this.getHandle()); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java index 4f3a82ce29..e48620d68b 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftEquippableComponent.java @@ -74,7 +74,8 @@ public final class CraftEquippableComponent implements EquippableComponent { (dispensable != null) ? dispensable : true, (swappable != null) ? swappable : true, (damageOnHurt != null) ? damageOnHurt : true, - (equipOnInteract != null) ? equipOnInteract : false + (equipOnInteract != null) ? equipOnInteract : false, + false, null // TODO - 1.21.5 ); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/spawner/PaperSharedSpawnerLogic.java b/paper-server/src/main/java/org/bukkit/craftbukkit/spawner/PaperSharedSpawnerLogic.java index b1d08dc4c4..11c7990422 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/spawner/PaperSharedSpawnerLogic.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/spawner/PaperSharedSpawnerLogic.java @@ -2,29 +2,39 @@ package org.bukkit.craftbukkit.spawner; import com.google.common.base.Preconditions; import java.util.Optional; +import com.mojang.logging.LogUtils; import net.minecraft.core.BlockPos; +import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.util.ProblemReporter; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.BaseSpawner; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.SpawnData; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.storage.TagValueOutput; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.inventory.ItemStack; import org.bukkit.spawner.Spawner; +import org.slf4j.Logger; /** * A common parent interface for both the {@link org.bukkit.craftbukkit.block.CraftCreatureSpawner} and minecart mob spawner. */ public interface PaperSharedSpawnerLogic extends Spawner { + static final Logger LOGGER = LogUtils.getLogger(); + BaseSpawner getSpawner(); Level getInternalWorld(); BlockPos getInternalPosition(); - default boolean isActivated() { return this.getSpawner().isNearPlayer(this.getInternalWorld(), this.getInternalPosition()); } @@ -41,16 +51,20 @@ public interface PaperSharedSpawnerLogic extends Spawner { Preconditions.checkArgument(itemStack != null && !itemStack.getType().isAir(), "spawners cannot spawn air"); final net.minecraft.world.item.ItemStack item = CraftItemStack.asNMSCopy(itemStack); - final CompoundTag entity = new CompoundTag(); - entity.putString(Entity.ID_TAG, BuiltInRegistries.ENTITY_TYPE.getKey(EntityType.ITEM).toString()); - entity.put("Item", item.save(this.getInternalWorld().registryAccess())); - this.setNextSpawnData( - new net.minecraft.world.level.SpawnData( - entity, - java.util.Optional.empty(), - Optional.ofNullable(this.getSpawner().nextSpawnData).flatMap(SpawnData::equipment) - ) - ); + try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(() -> getSpawner().toString(), LOGGER)) { + TagValueOutput tagValueOutput = TagValueOutput.createWithContext(scopedCollector, this.getInternalWorld().registryAccess()); + tagValueOutput.putString(Entity.TAG_ID, BuiltInRegistries.ENTITY_TYPE.getKey(EntityType.ITEM).toString()); + tagValueOutput.store("Item", net.minecraft.world.item.ItemStack.CODEC, item); + + this.setNextSpawnData( + new net.minecraft.world.level.SpawnData( + tagValueOutput.buildResult(), + java.util.Optional.empty(), + Optional.ofNullable(this.getSpawner().nextSpawnData).flatMap(SpawnData::equipment) + ) + ); + } + } }