This commit is contained in:
Noah van der Aa 2024-10-23 23:12:09 +02:00
parent cb79de80c4
commit 1dc142534d
No known key found for this signature in database
GPG key ID: 547D90BC6FF753CF
44 changed files with 194 additions and 194 deletions

View file

@ -1,54 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Wed, 2 Feb 2022 13:50:06 -0800
Subject: [PATCH] Trigger bee_nest_destroyed trigger in the correct place
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
index 073cf184a0e7af41048ae67a9b17b4cdfcc43c35..4d024956156aefde7df308642dfd0a40779e0633 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -429,12 +429,16 @@ public class ServerPlayerGameMode {
block.destroy(this.level, pos, iblockdata1);
}
+ ItemStack mainHandStack = null; // Paper - Trigger bee_nest_destroyed trigger in the correct place
+ boolean isCorrectTool = false; // Paper - Trigger bee_nest_destroyed trigger in the correct place
if (this.isCreative()) {
// return true; // CraftBukkit
} else {
ItemStack itemstack = this.player.getMainHandItem();
ItemStack itemstack1 = itemstack.copy();
boolean flag1 = this.player.hasCorrectToolForDrops(iblockdata1);
+ mainHandStack = itemstack1; // Paper - Trigger bee_nest_destroyed trigger in the correct place
+ isCorrectTool = flag1; // Paper - Trigger bee_nest_destroyed trigger in the correct place
itemstack.mineBlock(this.level, iblockdata1, pos, this.player);
if (flag && flag1 && event.isDropItems()) { // CraftBukkit - Check if block should drop items
@@ -455,6 +459,13 @@ public class ServerPlayerGameMode {
if (flag && event != null) {
iblockdata.getBlock().popExperience(this.level, pos, event.getExpToDrop(), this.player); // Paper
}
+ // Paper start - Trigger bee_nest_destroyed trigger in the correct place (check impls of block#playerDestroy)
+ if (mainHandStack != null) {
+ if (flag && isCorrectTool && event.isDropItems() && block instanceof net.minecraft.world.level.block.BeehiveBlock && tileentity instanceof net.minecraft.world.level.block.entity.BeehiveBlockEntity beehiveBlockEntity) { // simulates the guard on block#playerDestroy above
+ CriteriaTriggers.BEE_NEST_DESTROYED.trigger(player, iblockdata, mainHandStack, beehiveBlockEntity.getOccupantCount());
+ }
+ }
+ // Paper end - Trigger bee_nest_destroyed trigger in the correct place
return true;
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java
index 8d6736003934c5958f600660bdee58b386c39da4..c75227b2ea165dcd65c203e60157ac7cdebd4bc6 100644
--- a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java
@@ -95,7 +95,7 @@ public class BeehiveBlock extends BaseEntityBlock {
this.angerNearbyBees(world, pos);
}
- CriteriaTriggers.BEE_NEST_DESTROYED.trigger((ServerPlayer) player, state, tool, tileentitybeehive.getOccupantCount());
+ // CriteriaTriggers.BEE_NEST_DESTROYED.trigger((ServerPlayer) player, state, tool, tileentitybeehive.getOccupantCount()); // Paper - Trigger bee_nest_destroyed trigger in the correct place; moved until after items are dropped
}
}

View file

@ -1,43 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Fri, 18 Mar 2022 21:15:55 -0700
Subject: [PATCH] Add EntityDyeEvent and CollarColorable interface
diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java
index d44807c16712afd37efdbf434d1afb12a7c3d343..2ed442c8d36f285420cf84a956e90b6036384ce0 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Cat.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java
@@ -378,6 +378,13 @@ public class Cat extends TamableAnimal implements VariantHolder<Holder<CatVarian
DyeColor enumcolor = itemdye.getDyeColor();
if (enumcolor != this.getCollarColor()) {
+ // Paper start - Add EntityDyeEvent and CollarColorable interface
+ final io.papermc.paper.event.entity.EntityDyeEvent event = new io.papermc.paper.event.entity.EntityDyeEvent(this.getBukkitEntity(), org.bukkit.DyeColor.getByWoolData((byte) enumcolor.getId()), ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity());
+ if (!event.callEvent()) {
+ return InteractionResult.FAIL;
+ }
+ enumcolor = DyeColor.byId(event.getColor().getWoolData());
+ // Paper end - Add EntityDyeEvent and CollarColorable interface
if (!this.level().isClientSide()) {
this.setCollarColor(enumcolor);
itemstack.consume(1, player);
diff --git a/src/main/java/net/minecraft/world/entity/animal/Wolf.java b/src/main/java/net/minecraft/world/entity/animal/Wolf.java
index 00b14e588280e1ff2c9a04a415077399602ce95d..22024d79b566ad5d388ceb644605ada3123ca608 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Wolf.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Wolf.java
@@ -457,6 +457,14 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder<Hol
DyeColor enumcolor = itemdye.getDyeColor();
if (enumcolor != this.getCollarColor()) {
+ // Paper start - Add EntityDyeEvent and CollarColorable interface
+ final io.papermc.paper.event.entity.EntityDyeEvent event = new io.papermc.paper.event.entity.EntityDyeEvent(this.getBukkitEntity(), org.bukkit.DyeColor.getByWoolData((byte) enumcolor.getId()), ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity());
+ if (!event.callEvent()) {
+ return InteractionResult.FAIL;
+ }
+ enumcolor = DyeColor.byId(event.getColor().getWoolData());
+ // Paper end - Add EntityDyeEvent and CollarColorable interface
+
this.setCollarColor(enumcolor);
itemstack.consume(1, player);
return InteractionResult.SUCCESS;

View file

@ -1,122 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Tue, 29 Mar 2022 13:46:23 -0700
Subject: [PATCH] Fire CauldronLevelChange on initial fill
Also don't fire level events or game events if stalactite
drip is cancelled
diff --git a/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java b/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java
index 9ebd5310ee358acd83123a30415d9f7eb6aa36d9..f301c20e808b77cb3fcffd9a7c8102928306456e 100644
--- a/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java
+++ b/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java
@@ -81,7 +81,7 @@ public interface CauldronInteraction {
if (potioncontents != null && potioncontents.is(Potions.WATER)) {
if (!world.isClientSide) {
// CraftBukkit start
- if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, Blocks.WATER_CAULDRON.defaultBlockState(), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) {
+ if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, Blocks.WATER_CAULDRON.defaultBlockState(), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY, false)) { // Paper - Call CauldronLevelChangeEvent
return ItemInteractionResult.SUCCESS;
}
// CraftBukkit end
@@ -136,7 +136,7 @@ public interface CauldronInteraction {
if (potioncontents != null && potioncontents.is(Potions.WATER)) {
if (!world.isClientSide) {
// CraftBukkit start
- if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, iblockdata.cycle(LayeredCauldronBlock.LEVEL), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) {
+ if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, iblockdata.cycle(LayeredCauldronBlock.LEVEL), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY, false)) { // Paper - Call CauldronLevelChangeEvent
return ItemInteractionResult.SUCCESS;
}
// CraftBukkit end
@@ -222,7 +222,7 @@ public interface CauldronInteraction {
} else {
if (!world.isClientSide) {
// CraftBukkit start
- if (!LayeredCauldronBlock.changeLevel(state, world, pos, Blocks.CAULDRON.defaultBlockState(), player, CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL)) {
+ if (!LayeredCauldronBlock.changeLevel(state, world, pos, Blocks.CAULDRON.defaultBlockState(), player, CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL, false)) { // Paper - Call CauldronLevelChangeEvent
return ItemInteractionResult.SUCCESS;
}
// CraftBukkit end
@@ -243,7 +243,7 @@ public interface CauldronInteraction {
static ItemInteractionResult emptyBucket(Level world, BlockPos pos, Player player, InteractionHand hand, ItemStack stack, BlockState state, SoundEvent soundEvent) {
if (!world.isClientSide) {
// CraftBukkit start
- if (!LayeredCauldronBlock.changeLevel(state, world, pos, state, player, CauldronLevelChangeEvent.ChangeReason.BUCKET_EMPTY)) {
+ if (!LayeredCauldronBlock.changeLevel(state, world, pos, state, player, CauldronLevelChangeEvent.ChangeReason.BUCKET_EMPTY, false)) { // Paper - Call CauldronLevelChangeEvent
return ItemInteractionResult.SUCCESS;
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/level/block/CauldronBlock.java b/src/main/java/net/minecraft/world/level/block/CauldronBlock.java
index 8d5ad9848d9652b4fd7179c425c47a683ee169ef..c9968934f4ecaa8d81e545f279b3001c7b1ce545 100644
--- a/src/main/java/net/minecraft/world/level/block/CauldronBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/CauldronBlock.java
@@ -44,9 +44,19 @@ public class CauldronBlock extends AbstractCauldronBlock {
public void handlePrecipitation(BlockState state, Level world, BlockPos pos, Biome.Precipitation precipitation) {
if (CauldronBlock.shouldHandlePrecipitation(world, precipitation)) {
if (precipitation == Biome.Precipitation.RAIN) {
+ // Paper start - Call CauldronLevelChangeEvent
+ if (!LayeredCauldronBlock.changeLevel(state, world, pos, Blocks.WATER_CAULDRON.defaultBlockState(), null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL, false)) { // avoid duplicate game event
+ return;
+ }
+ // Paper end - Call CauldronLevelChangeEvent
world.setBlockAndUpdate(pos, Blocks.WATER_CAULDRON.defaultBlockState());
world.gameEvent((Entity) null, (Holder) GameEvent.BLOCK_CHANGE, pos);
} else if (precipitation == Biome.Precipitation.SNOW) {
+ // Paper start - Call CauldronLevelChangeEvent
+ if (!LayeredCauldronBlock.changeLevel(state, world, pos, Blocks.POWDER_SNOW_CAULDRON.defaultBlockState(), null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL, false)) { // avoid duplicate game event
+ return;
+ }
+ // Paper end - Call CauldronLevelChangeEvent
world.setBlockAndUpdate(pos, Blocks.POWDER_SNOW_CAULDRON.defaultBlockState());
world.gameEvent((Entity) null, (Holder) GameEvent.BLOCK_CHANGE, pos);
}
@@ -65,11 +75,19 @@ public class CauldronBlock extends AbstractCauldronBlock {
if (fluid == Fluids.WATER) {
iblockdata1 = Blocks.WATER_CAULDRON.defaultBlockState();
- LayeredCauldronBlock.changeLevel(state, world, pos, iblockdata1, null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL); // CraftBukkit
+ // Paper start - Call CauldronLevelChangeEvent; don't send level event or game event if cancelled
+ if (!LayeredCauldronBlock.changeLevel(state, world, pos, iblockdata1, null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL)) { // CraftBukkit
+ return;
+ }
+ // Paper end - Call CauldronLevelChangeEvent
world.levelEvent(1047, pos, 0);
} else if (fluid == Fluids.LAVA) {
iblockdata1 = Blocks.LAVA_CAULDRON.defaultBlockState();
- LayeredCauldronBlock.changeLevel(state, world, pos, iblockdata1, null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL); // CraftBukkit
+ // Paper start - Call CauldronLevelChangeEvent; don't send level event or game event if cancelled
+ if (!LayeredCauldronBlock.changeLevel(state, world, pos, iblockdata1, null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL)) { // CraftBukkit
+ return;
+ }
+ // Paper end - Call CauldronLevelChangeEvent
world.levelEvent(1046, pos, 0);
}
diff --git a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java
index 7c67efa6e344870b764eb39d5508190349e2e911..b222ac8e5b966c515be2aca86083f5640853cd29 100644
--- a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java
@@ -102,7 +102,13 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock {
}
// CraftBukkit start
- public static boolean changeLevel(BlockState iblockdata, Level world, BlockPos blockposition, BlockState newBlock, Entity entity, CauldronLevelChangeEvent.ChangeReason reason) {
+ // Paper start - Call CauldronLevelChangeEvent
+ public static boolean changeLevel(BlockState iblockdata, Level world, BlockPos blockposition, BlockState newBlock, @javax.annotation.Nullable Entity entity, CauldronLevelChangeEvent.ChangeReason reason) { // Paper - entity is nullable
+ return changeLevel(iblockdata, world, blockposition, newBlock, entity, reason, true);
+ }
+
+ public static boolean changeLevel(BlockState iblockdata, Level world, BlockPos blockposition, BlockState newBlock, @javax.annotation.Nullable Entity entity, CauldronLevelChangeEvent.ChangeReason reason, boolean sendGameEvent) { // Paper - entity is nullable
+ // Paper end - Call CauldronLevelChangeEvent
CraftBlockState newState = CraftBlockStates.getBlockState(world, blockposition);
newState.setData(newBlock);
@@ -115,7 +121,7 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock {
return false;
}
newState.update(true);
- world.gameEvent((Holder) GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(newBlock));
+ if (sendGameEvent) world.gameEvent((Holder) GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(newBlock)); // Paper - Call CauldronLevelChangeEvent
return true;
}
// CraftBukkit end

View file

@ -1,45 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 30 Dec 2021 14:02:13 -0800
Subject: [PATCH] fix powder snow cauldrons not turning to water
Powder snow cauldrons should turn to water when
extinguishing an entity
diff --git a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java
index b222ac8e5b966c515be2aca86083f5640853cd29..fa5366961861370c2366e6f0ff026a6d65128316 100644
--- a/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/LayeredCauldronBlock.java
@@ -70,7 +70,7 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock {
if (!world.isClientSide && entity.isOnFire() && this.isEntityInsideContent(state, pos, entity)) {
// CraftBukkit start
if (entity.mayInteract(world, pos)) {
- if (!LayeredCauldronBlock.lowerFillLevel(state, world, pos, entity, CauldronLevelChangeEvent.ChangeReason.EXTINGUISH)) {
+ if (!this.handleEntityOnFireInsideWithEvent(state, world, pos, entity)) { // Paper - fix powdered snow cauldron extinguishing entities
return;
}
}
@@ -80,6 +80,7 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock {
}
+ @io.papermc.paper.annotation.DoNotUse @Deprecated // Paper - fix powdered snow cauldron extinguishing entities; use #handleEntityOnFireInsideWithEvent
private void handleEntityOnFireInside(BlockState state, Level world, BlockPos pos) {
if (this.precipitationType == Biome.Precipitation.SNOW) {
LayeredCauldronBlock.lowerFillLevel((BlockState) Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, (Integer) state.getValue(LayeredCauldronBlock.LEVEL)), world, pos);
@@ -88,6 +89,15 @@ public class LayeredCauldronBlock extends AbstractCauldronBlock {
}
}
+ // Paper start - fix powdered snow cauldron extinguishing entities
+ protected boolean handleEntityOnFireInsideWithEvent(BlockState state, Level world, BlockPos pos, Entity entity) {
+ if (this.precipitationType == Biome.Precipitation.SNOW) {
+ return LayeredCauldronBlock.lowerFillLevel((BlockState) Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, (Integer) state.getValue(LayeredCauldronBlock.LEVEL)), world, pos, entity, CauldronLevelChangeEvent.ChangeReason.EXTINGUISH);
+ } else {
+ return LayeredCauldronBlock.lowerFillLevel(state, world, pos, entity, CauldronLevelChangeEvent.ChangeReason.EXTINGUISH);
+ }
+ }
+ // Paper end - fix powdered snow cauldron extinguishing entities
public static void lowerFillLevel(BlockState state, Level world, BlockPos pos) {
// CraftBukkit start

View file

@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: u9g <git@u9g.dev>
Date: Tue, 3 May 2022 20:41:37 -0400
Subject: [PATCH] Add PlayerStopUsingItemEvent
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 01a6e91f1b8f619e99d9bccde12f6e91e6ab5eb8..5383d231748f2d30b2f2bf3ce07d3667e4d828e9 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -4076,6 +4076,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
public void releaseUsingItem() {
if (!this.useItem.isEmpty()) {
+ if (this instanceof ServerPlayer) new io.papermc.paper.event.player.PlayerStopUsingItemEvent((Player) getBukkitEntity(), useItem.asBukkitMirror(), getTicksUsingItem()).callEvent(); // Paper - Add PlayerStopUsingItemEvent
this.useItem.releaseUsing(this.level(), this, this.getUseItemRemainingTicks());
if (this.useItem.useOnRelease()) {
this.updatingUsingItem();

View file

@ -1,36 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Noah van der Aa <ndvdaa@gmail.com>
Date: Fri, 7 Jan 2022 11:58:26 +0100
Subject: [PATCH] Don't tick markers
Fixes https://github.com/PaperMC/Paper/issues/7276 and https://github.com/PaperMC/Paper/issues/8118
by using a config option that, when set to false, does not add markers to the entity
tick list at all and ignores them in Spigot's activation range checks. The entity tick
list is only used in the tick and tickPassenger methods, so we can safely not add the
markers to it. When the config option is set to true, markers are ticked as normal.
diff --git a/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java b/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java
index 67fcba634f8183bb33834ac3b2c3dcfb8d87129e..777b789fdcdf297309cfb36fc7f77e3fdb6327ca 100644
--- a/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java
+++ b/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java
@@ -109,7 +109,7 @@ public final class EntityCommand implements PaperSubcommand {
ChunkPos chunk = e.chunkPosition();
info.left++;
info.right.put(chunk, info.right.getOrDefault(chunk, 0) + 1);
- if (!chunkProviderServer.isPositionTicking(e)) {
+ if (!chunkProviderServer.isPositionTicking(e) || (e instanceof net.minecraft.world.entity.Marker && !world.paperConfig().entities.markers.tick)) { // Paper - Configurable marker ticking
nonEntityTicking.merge(key, 1, Integer::sum);
}
});
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index a87a0c9672b53db0e06292c339b3b1e163901942..f4ab0ce684ae2a83a02848c4d18062e1b27377ce 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -2162,6 +2162,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
}
public void onTickingStart(Entity entity) {
+ if (entity instanceof net.minecraft.world.entity.Marker && !paperConfig().entities.markers.tick) return; // Paper - Configurable marker ticking
ServerLevel.this.entityTickList.add(entity);
}

View file

@ -1,107 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Sun, 5 Dec 2021 14:58:17 -0500
Subject: [PATCH] Expand FallingBlock API
- add auto expire setting
- add setter for block data
- add accessors for block state
== AT ==
public net.minecraft.world.entity.item.FallingBlockEntity blockState
Co-authored-by: Lukas Planz <lukas.planz@web.de>
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
index 01ac7bb0ef8ab13e7c4b5b56b768b7c0a642b300..caf9273cfafbbaaf8dc95498927383e608773665 100644
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -71,6 +71,7 @@ public class FallingBlockEntity extends Entity {
public CompoundTag blockData;
public boolean forceTickAfterTeleportToDuplicate;
protected static final EntityDataAccessor<BlockPos> DATA_START_POS = SynchedEntityData.defineId(FallingBlockEntity.class, EntityDataSerializers.BLOCK_POS);
+ public boolean autoExpire = true; // Paper - Expand FallingBlock API
public FallingBlockEntity(EntityType<? extends FallingBlockEntity> type, Level world) {
super(type, world);
@@ -176,7 +177,7 @@ public class FallingBlockEntity extends Entity {
}
if (!this.onGround() && !flag1) {
- if (!this.level().isClientSide && (this.time > 100 && (blockposition.getY() <= this.level().getMinBuildHeight() || blockposition.getY() > this.level().getMaxBuildHeight()) || this.time > 600)) {
+ if (!this.level().isClientSide && ((this.time > 100 && autoExpire) && (blockposition.getY() <= this.level().getMinBuildHeight() || blockposition.getY() > this.level().getMaxBuildHeight()) || (this.time > 600 && autoExpire))) { // Paper - Expand FallingBlock API
if (this.dropItem && this.level().getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
this.spawnAtLocation((ItemLike) block);
}
@@ -322,6 +323,7 @@ public class FallingBlockEntity extends Entity {
}
nbt.putBoolean("CancelDrop", this.cancelDrop);
+ if (!autoExpire) {nbt.putBoolean("Paper.AutoExpire", false);} // Paper - Expand FallingBlock API
}
@Override
@@ -349,6 +351,11 @@ public class FallingBlockEntity extends Entity {
this.blockState = Blocks.SAND.defaultBlockState();
}
+ // Paper start - Expand FallingBlock API
+ if (nbt.contains("Paper.AutoExpire")) {
+ this.autoExpire = nbt.getBoolean("Paper.AutoExpire");
+ }
+ // Paper end - Expand FallingBlock API
}
public void setHurtsEntities(float fallHurtAmount, int fallHurtMax) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java
index a7a3f74b846112d752fe04162b30805961457b11..1359d25a32b4a5d5e8e68ce737bd19f7b5afaf69 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java
@@ -33,6 +33,31 @@ public class CraftFallingBlock extends CraftEntity implements FallingBlock {
public BlockData getBlockData() {
return CraftBlockData.fromData(this.getHandle().getBlockState());
}
+ // Paper start - Expand FallingBlock API
+ @Override
+ public void setBlockData(final BlockData blockData) {
+ Preconditions.checkArgument(blockData != null, "blockData");
+ final net.minecraft.world.level.block.state.BlockState oldState = this.getHandle().blockState, newState = ((CraftBlockData) blockData).getState();
+ this.getHandle().blockState = newState;
+ this.getHandle().blockData = null;
+
+ if (oldState != newState) this.update();
+ }
+
+ @Override
+ public org.bukkit.block.BlockState getBlockState() {
+ return org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(this.getHandle().blockState, this.getHandle().blockData);
+ }
+
+ @Override
+ public void setBlockState(final org.bukkit.block.BlockState blockState) {
+ Preconditions.checkArgument(blockState != null, "blockState");
+ // Calls #update if needed, the block data compound tag is not synced with the client and hence can be mutated after the sync with clients.
+ // The call also clears any potential old block data.
+ this.setBlockData(blockState.getBlockData());
+ if (blockState instanceof final org.bukkit.craftbukkit.block.CraftBlockEntityState<?> tileEntity) this.getHandle().blockData = tileEntity.getSnapshotNBT();
+ }
+ // Paper end - Expand FallingBlock API
@Override
public boolean getDropItem() {
@@ -101,4 +126,15 @@ public class CraftFallingBlock extends CraftEntity implements FallingBlock {
this.setHurtEntities(true);
}
}
+ // Paper start - Expand FallingBlock API
+ @Override
+ public boolean doesAutoExpire() {
+ return this.getHandle().autoExpire;
+ }
+
+ @Override
+ public void shouldAutoExpire(boolean autoExpires) {
+ this.getHandle().autoExpire = autoExpires;
+ }
+ // Paper end - Expand FallingBlock API
}

View file

@ -1,65 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: PanSzelescik <panszelescik@gmail.com>
Date: Thu, 7 Apr 2022 16:13:39 +0200
Subject: [PATCH] Add support for Proxy Protocol
diff --git a/build.gradle.kts b/build.gradle.kts
index 6c3ed9e685473d7f555ae0e34fb9d4f3873f109a..ec9ae97b4a624bc208a778e63d0f0b86285167a6 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -28,6 +28,7 @@ dependencies {
log4jPlugins.annotationProcessorConfigurationName("org.apache.logging.log4j:log4j-core:2.19.0") // Paper - Needed to generate meta for our Log4j plugins
runtimeOnly(log4jPlugins.output)
alsoShade(log4jPlugins.output)
+ implementation("io.netty:netty-codec-haproxy:4.1.97.Final") // Paper - Add support for proxy protocol
// Paper end
implementation("org.apache.logging.log4j:log4j-iostreams:2.22.1") // Paper - remove exclusion
implementation("org.ow2.asm:asm-commons:9.7.1")
diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
index c63c194c44646e6bc1a59426552787011fc2ced5..c62df32af11636ad408b584fcc590590ce4fb0d0 100644
--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
@@ -104,6 +104,12 @@ public class ServerConnectionListener {
ServerConnectionListener.LOGGER.info("Using default channel type");
}
+ // Paper start - Warn people with console access that HAProxy is in use.
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.proxyProtocol) {
+ ServerConnectionListener.LOGGER.warn("Using HAProxy, please ensure the server port is adequately firewalled.");
+ }
+ // Paper end - Warn people with console access that HAProxy is in use.
+
this.channels.add(((ServerBootstrap) ((ServerBootstrap) (new ServerBootstrap()).channel(oclass)).childHandler(new ChannelInitializer<Channel>() {
protected void initChannel(Channel channel) {
try {
@@ -123,6 +129,29 @@ public class ServerConnectionListener {
Connection object = j > 0 ? new RateKickingConnection(j) : new Connection(PacketFlow.SERVERBOUND); // CraftBukkit - decompile error
//ServerConnectionListener.this.connections.add(object); // Paper
+ // Paper start - Add support for Proxy Protocol
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.proxyProtocol) {
+ channel.pipeline().addAfter("timeout", "haproxy-decoder", new io.netty.handler.codec.haproxy.HAProxyMessageDecoder());
+ channel.pipeline().addAfter("haproxy-decoder", "haproxy-handler", new ChannelInboundHandlerAdapter() {
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+ if (msg instanceof io.netty.handler.codec.haproxy.HAProxyMessage message) {
+ if (message.command() == io.netty.handler.codec.haproxy.HAProxyCommand.PROXY) {
+ String realaddress = message.sourceAddress();
+ int realport = message.sourcePort();
+
+ SocketAddress socketaddr = new java.net.InetSocketAddress(realaddress, realport);
+
+ Connection connection = (Connection) channel.pipeline().get("packet_handler");
+ connection.address = socketaddr;
+ }
+ } else {
+ super.channelRead(ctx, msg);
+ }
+ }
+ });
+ }
+ // Paper end - Add support for proxy protocol
pending.add(object); // Paper - prevent blocking on adding a new connection while the server is ticking
((Connection) object).configurePacketHandler(channelpipeline);
((Connection) object).setListenerForServerboundHandshake(new ServerHandshakePacketListenerImpl(ServerConnectionListener.this.server, (Connection) object));

View file

@ -1,46 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Mon, 30 May 2022 16:03:36 -0700
Subject: [PATCH] Fix OfflinePlayer#getBedSpawnLocation
When calling getBedSpawnLocation on an
instance of CraftOfflinePlayer the world was incorrect
due to the logic for reading the NBT not being up-to-date.
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
index e0d342a0ddd140b342f7af138c71596c6d718788..30c1c203022c2ed777dcddfd68ef2e3752c62ea1 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
@@ -37,6 +37,7 @@ import org.bukkit.profile.PlayerProfile;
@SerializableAs("Player")
public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializable {
+ private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Paper
private final GameProfile profile;
private final CraftServer server;
private final PlayerDataStorage storage;
@@ -361,11 +362,20 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa
if (data == null) return null;
if (data.contains("SpawnX") && data.contains("SpawnY") && data.contains("SpawnZ")) {
- String spawnWorld = data.getString("SpawnWorld");
- if (spawnWorld.equals("")) {
- spawnWorld = this.server.getWorlds().get(0).getName();
+ // Paper start - fix wrong world
+ final float respawnAngle = data.getFloat("SpawnAngle");
+ org.bukkit.World spawnWorld = this.server.getWorld(data.getString("SpawnWorld")); // legacy
+ if (data.contains("SpawnDimension")) {
+ com.mojang.serialization.DataResult<net.minecraft.resources.ResourceKey<net.minecraft.world.level.Level>> result = net.minecraft.world.level.Level.RESOURCE_KEY_CODEC.parse(net.minecraft.nbt.NbtOps.INSTANCE, data.get("SpawnDimension"));
+ net.minecraft.resources.ResourceKey<net.minecraft.world.level.Level> levelKey = result.resultOrPartial(LOGGER::error).orElse(net.minecraft.world.level.Level.OVERWORLD);
+ net.minecraft.server.level.ServerLevel level = this.server.console.getLevel(levelKey);
+ spawnWorld = level != null ? level.getWorld() : spawnWorld;
}
- return new Location(this.server.getWorld(spawnWorld), data.getInt("SpawnX"), data.getInt("SpawnY"), data.getInt("SpawnZ"));
+ if (spawnWorld == null) {
+ return null;
+ }
+ return new Location(spawnWorld, data.getInt("SpawnX"), data.getInt("SpawnY"), data.getInt("SpawnZ"), respawnAngle, 0);
+ // Paper end
}
return null;
}

View file

@ -1,49 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sat, 1 Jan 2022 23:11:26 -0800
Subject: [PATCH] Fix FurnaceInventory for smokers and blast furnaces
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java
index a6c758c5c5da2fb3f2d251bc109f72a5d8b0eb14..ad2cb9a1352abd855bf11a390c9788835857380a 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java
@@ -65,7 +65,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
return new CraftInventory(tileEntity);
}
- public static class Furnace extends CraftTileInventoryConverter {
+ public static class Furnace extends AbstractFurnaceInventoryConverter { // Paper - Furnace, BlastFurnace, and Smoker are pretty much identical
@Override
public Container getTileEntity() {
@@ -73,6 +73,11 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
return furnace;
}
+ // Paper start - abstract furnace converter to apply to all 3 furnaces
+ }
+
+ public static abstract class AbstractFurnaceInventoryConverter extends CraftTileInventoryConverter {
+ // Paper end - abstract furnace converter to apply to all 3 furnaces
// Paper start
@Override
public Inventory createInventory(InventoryHolder owner, InventoryType type, net.kyori.adventure.text.Component title) {
@@ -170,7 +175,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
}
}
- public static class BlastFurnace extends CraftTileInventoryConverter {
+ public static class BlastFurnace extends AbstractFurnaceInventoryConverter { // Paper - Furnace, BlastFurnace, and Smoker are pretty much identical
@Override
public Container getTileEntity() {
@@ -186,7 +191,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat
}
}
- public static class Smoker extends CraftTileInventoryConverter {
+ public static class Smoker extends AbstractFurnaceInventoryConverter { // Paper - Furnace, BlastFurnace, and Smoker are pretty much identical
@Override
public Container getTileEntity() {

View file

@ -1,50 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Fri, 3 Dec 2021 16:55:50 -0500
Subject: [PATCH] Sanitize sent BlockEntity NBT
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java
index 4f3ba61f13dbe5773034a19e749b7c4f5dc3d291..5d3e739d28d394ed59fe0003245cc55ac62e6087 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundBlockEntityDataPacket.java
@@ -29,7 +29,7 @@ public class ClientboundBlockEntityDataPacket implements Packet<ClientGamePacket
public static ClientboundBlockEntityDataPacket create(BlockEntity blockEntity, BiFunction<BlockEntity, RegistryAccess, CompoundTag> nbtGetter) {
RegistryAccess registryAccess = blockEntity.getLevel().registryAccess();
- return new ClientboundBlockEntityDataPacket(blockEntity.getBlockPos(), blockEntity.getType(), nbtGetter.apply(blockEntity, registryAccess));
+ return new ClientboundBlockEntityDataPacket(blockEntity.getBlockPos(), blockEntity.getType(), blockEntity.sanitizeSentNbt(nbtGetter.apply(blockEntity, registryAccess))); // Paper - Sanitize sent data
}
public static ClientboundBlockEntityDataPacket create(BlockEntity blockEntity) {
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
index ac900dfdc5c90e9e60d47efa734be8f0a5b20dca..ec1cb034d840633240f2b379b09f7d2f1c8971a5 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
@@ -154,6 +154,7 @@ public class ClientboundLevelChunkPacketData {
CompoundTag compoundTag = blockEntity.getUpdateTag(blockEntity.getLevel().registryAccess());
BlockPos blockPos = blockEntity.getBlockPos();
int i = SectionPos.sectionRelative(blockPos.getX()) << 4 | SectionPos.sectionRelative(blockPos.getZ());
+ blockEntity.sanitizeSentNbt(compoundTag); // Paper - Sanitize sent data
return new ClientboundLevelChunkPacketData.BlockEntityInfo(i, blockPos.getY(), blockEntity.getType(), compoundTag.isEmpty() ? null : compoundTag);
}
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
index cbb777f499a4e8a447153c04d09c0c71321c663c..41f43d7d12a47563360f48a793e63db8cf92ac69 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
@@ -394,6 +394,14 @@ public abstract class BlockEntity {
}
// CraftBukkit end
+ // Paper start - Sanitize sent data
+ public CompoundTag sanitizeSentNbt(CompoundTag tag) {
+ tag.remove("PublicBukkitValues");
+
+ return tag;
+ }
+ // Paper end - Sanitize sent data
+
private static class ComponentHelper {
public static final Codec<DataComponentMap> COMPONENTS_CODEC = DataComponentMap.CODEC.optionalFieldOf("components", DataComponentMap.EMPTY).codec();

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <nassim@njahnke.dev>
Date: Thu, 2 Jun 2022 20:35:58 +0200
Subject: [PATCH] Disable component selector resolving in books by default
diff --git a/src/main/java/net/minecraft/world/item/WrittenBookItem.java b/src/main/java/net/minecraft/world/item/WrittenBookItem.java
index 46383a9f8bd1075ea56847f5fd8437df0a5d4941..0a5182c52fe2fef05dabbeb5ed13487f9175efbe 100644
--- a/src/main/java/net/minecraft/world/item/WrittenBookItem.java
+++ b/src/main/java/net/minecraft/world/item/WrittenBookItem.java
@@ -54,7 +54,7 @@ public class WrittenBookItem extends Item {
public static boolean resolveBookComponents(ItemStack book, CommandSourceStack commandSource, @Nullable Player player) {
WrittenBookContent writtenBookContent = book.get(DataComponents.WRITTEN_BOOK_CONTENT);
- if (writtenBookContent != null && !writtenBookContent.resolved()) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().itemValidation.resolveSelectorsInBooks && writtenBookContent != null && !writtenBookContent.resolved()) { // Paper - Disable component selector resolving in books by default
WrittenBookContent writtenBookContent2 = writtenBookContent.resolve(commandSource, player);
if (writtenBookContent2 != null) {
book.set(DataComponents.WRITTEN_BOOK_CONTENT, writtenBookContent2);

View file

@ -1,81 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Sun, 6 Mar 2022 11:09:09 -0500
Subject: [PATCH] Prevent entity loading causing async lookups
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 3bb7e0f6a02b9b1726b8c878271d89a9c6d56c12..de483cc77931fcb1d8bb9b1bcfd6606706490fba 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -714,6 +714,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
public void baseTick() {
this.level().getProfiler().push("entityBaseTick");
+ if (firstTick && this instanceof net.minecraft.world.entity.NeutralMob neutralMob) neutralMob.tickInitialPersistentAnger(level); // Paper - Prevent entity loading causing async lookups
this.inBlockState = null;
if (this.isPassenger() && this.getVehicle().isRemoved()) {
this.stopRiding();
diff --git a/src/main/java/net/minecraft/world/entity/NeutralMob.java b/src/main/java/net/minecraft/world/entity/NeutralMob.java
index 3b08905ddc3c2506779ce0eac1a53a4d89442ddc..b55633bf4e26dc00e27ab28c7739c274e48b74c3 100644
--- a/src/main/java/net/minecraft/world/entity/NeutralMob.java
+++ b/src/main/java/net/minecraft/world/entity/NeutralMob.java
@@ -45,24 +45,11 @@ public interface NeutralMob {
UUID uuid = nbt.getUUID("AngryAt");
this.setPersistentAngerTarget(uuid);
- Entity entity = ((ServerLevel) world).getEntity(uuid);
-
- if (entity != null) {
- if (entity instanceof Mob) {
- Mob entityinsentient = (Mob) entity;
-
- this.setTarget(entityinsentient, EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit
- this.setLastHurtByMob(entityinsentient);
- }
-
- if (entity instanceof Player) {
- Player entityhuman = (Player) entity;
-
- this.setTarget(entityhuman, EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit
- this.setLastHurtByPlayer(entityhuman);
- }
-
- }
+ // Paper - Prevent entity loading causing async lookups; Moved diff to separate method
+ // If this entity already survived its first tick, e.g. is loaded and ticked in sync, actively
+ // tick the initial persistent anger.
+ // If not, let the first tick on the baseTick call the method later down the line.
+ if (this instanceof Entity entity && !entity.firstTick) this.tickInitialPersistentAnger(world);
}
}
}
@@ -136,4 +123,28 @@ public interface NeutralMob {
@Nullable
LivingEntity getTarget();
+
+ // Paper start - Prevent entity loading causing async lookups
+ // Update last hurt when ticking
+ default void tickInitialPersistentAnger(Level level) {
+ UUID target = getPersistentAngerTarget();
+ if (target == null) {
+ return;
+ }
+
+ Entity entity = ((ServerLevel) level).getEntity(target);
+
+ if (entity != null) {
+ if (entity instanceof Mob mob) {
+ this.setTarget(mob, EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit
+ this.setLastHurtByMob(mob);
+ }
+
+ if (entity instanceof Player player) {
+ this.setTarget(player, EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit
+ this.setLastHurtByPlayer(player);
+ }
+ }
+ }
+ // Paper end - Prevent entity loading causing async lookups
}

View file

@ -1,78 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Tue, 22 Mar 2022 12:44:30 -0700
Subject: [PATCH] Throw exception on world create while being ticked
There are no plans to support creating worlds while worlds are
being ticked themselvess.
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 94aa901b77b19445a33d5b2b24ba2e947d2a6aef..11b9eb8d7d5f9ad736f2c6784c5d9e745a355093 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -317,6 +317,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public final double[] recentTps = new double[ 3 ];
// Spigot end
public final io.papermc.paper.configuration.PaperConfigurations paperConfigurations; // Paper - add paper configuration files
+ public boolean isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
public static <S extends MinecraftServer> S spin(Function<Thread, S> serverFactory) {
AtomicReference<S> atomicreference = new AtomicReference();
@@ -1580,7 +1581,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.getFunctions().tick();
MinecraftTimings.commandFunctionsTimer.stopTiming(); // Spigot // Paper
this.profiler.popPush("levels");
- Iterator iterator = this.getAllLevels().iterator();
+ //Iterator iterator = this.getAllLevels().iterator(); // Paper - Throw exception on world create while being ticked; moved down
// CraftBukkit start
// Run tasks that are waiting on processing
@@ -1612,6 +1613,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// Paper end - Perf: Optimize time updates
MinecraftTimings.timeUpdateTimer.stopTiming(); // Spigot // Paper
+ this.isIteratingOverLevels = true; // Paper - Throw exception on world create while being ticked
+ Iterator iterator = this.getAllLevels().iterator(); // Paper - Throw exception on world create while being ticked; move down
while (iterator.hasNext()) {
ServerLevel worldserver = (ServerLevel) iterator.next();
worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
@@ -1647,6 +1650,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.profiler.pop();
worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions
}
+ this.isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
this.profiler.popPush("connection");
MinecraftTimings.connectionTimer.startTiming(); // Spigot // Paper
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index cfdfb81bc81382b71131c037ebd56f24573d4e34..8f8674ccee58f1910ffc3926d42913048da1810e 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -917,6 +917,11 @@ public final class CraftServer implements Server {
return new ArrayList<World>(this.worlds.values());
}
+ @Override
+ public boolean isTickingWorlds() {
+ return console.isIteratingOverLevels;
+ }
+
public DedicatedPlayerList getHandle() {
return this.playerList;
}
@@ -1180,6 +1185,7 @@ public final class CraftServer implements Server {
@Override
public World createWorld(WorldCreator creator) {
Preconditions.checkState(this.console.getAllLevels().iterator().hasNext(), "Cannot create additional worlds on STARTUP");
+ //Preconditions.checkState(!this.console.isIteratingOverLevels, "Cannot create a world while worlds are being ticked"); // Paper - Cat - Temp disable. We'll see how this goes.
Preconditions.checkArgument(creator != null, "WorldCreator cannot be null");
String name = creator.name();
@@ -1356,6 +1362,7 @@ public final class CraftServer implements Server {
@Override
public boolean unloadWorld(World world, boolean save) {
+ //Preconditions.checkState(!this.console.isIteratingOverLevels, "Cannot unload a world while worlds are being ticked"); // Paper - Cat - Temp disable. We'll see how this goes.
if (world == null) {
return false;
}

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Wed, 8 Jun 2022 11:04:47 -0400
Subject: [PATCH] Dont resent entity on art update
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java
index dd02cec9a82794a6b001c3b64f031f78d5fbb812..bcac1359c667ef1ee46384f9c7a5adf4010d2b08 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java
@@ -36,7 +36,7 @@ public class CraftPainting extends CraftHanging implements Painting {
painting.setDirection(painting.getDirection());
return false;
}
- this.update();
+ //this.update(); Paper - Don't resent entity on art update
return true;
}

View file

@ -1,39 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: nopjar <code.nopjar@gmail.com>
Date: Sun, 12 Jun 2022 02:26:04 +0200
Subject: [PATCH] Add WardenAngerChangeEvent
diff --git a/src/main/java/net/minecraft/world/entity/monster/warden/AngerManagement.java b/src/main/java/net/minecraft/world/entity/monster/warden/AngerManagement.java
index 27e52ee93ab591e97f37705de64cb5b62c06e253..3d792957f27fd4bdfad8d76262a8e2a2012bf35f 100644
--- a/src/main/java/net/minecraft/world/entity/monster/warden/AngerManagement.java
+++ b/src/main/java/net/minecraft/world/entity/monster/warden/AngerManagement.java
@@ -146,7 +146,7 @@ public class AngerManagement {
public int increaseAnger(Entity entity, int amount) {
boolean bl = !this.angerBySuspect.containsKey(entity);
- int i = this.angerBySuspect.computeInt(entity, (suspect, anger) -> Math.min(150, (anger == null ? 0 : anger) + amount));
+ int i = this.angerBySuspect.computeInt(entity, (suspect, anger) -> Math.min(150, (anger == null ? 0 : anger) + amount)); // Paper - diff on change (Warden#increaseAngerAt WardenAngerChangeEvent)
if (bl) {
int j = this.angerByUuid.removeInt(entity.getUUID());
i += j;
diff --git a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java
index aaa4b5d90e23b09f87847aa52c36548c94ddf548..38bf417a9ad4647f4af24d969f3bf4fed9c4bad7 100644
--- a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java
+++ b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java
@@ -479,6 +479,15 @@ public class Warden extends Monster implements VibrationSystem {
@VisibleForTesting
public void increaseAngerAt(@Nullable Entity entity, int amount, boolean listening) {
if (!this.isNoAi() && this.canTargetEntity(entity)) {
+ // Paper start - Add WardenAngerChangeEvent
+ int activeAnger = this.angerManagement.getActiveAnger(entity);
+ io.papermc.paper.event.entity.WardenAngerChangeEvent event = new io.papermc.paper.event.entity.WardenAngerChangeEvent((org.bukkit.entity.Warden) this.getBukkitEntity(), entity.getBukkitEntity(), activeAnger, Math.min(150, activeAnger + amount));
+ this.level().getCraftServer().getPluginManager().callEvent(event);
+ if (event.isCancelled()) {
+ return;
+ }
+ amount = event.getNewAnger() - activeAnger;
+ // Paper end - Add WardenAngerChangeEvent
WardenAi.setDigCooldown(this);
boolean flag1 = !(this.getTarget() instanceof Player);
int j = this.angerManagement.increaseAnger(entity, amount);

View file

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 12 Jun 2022 11:47:24 -0700
Subject: [PATCH] Add option for strict advancement dimension checks
Craftbukkit attempts to translate worlds that use the
same generation as the Overworld, The Nether, or The End
to use those dimensions when checking the `changed_dimension`
criteria trigger, or whether to trigger the `NETHER_TRAVEL`
distance trigger. This adds a config option to ignore that
and use the exact dimension key of the worlds involved.
diff --git a/src/main/java/net/minecraft/advancements/critereon/LocationPredicate.java b/src/main/java/net/minecraft/advancements/critereon/LocationPredicate.java
index 01b8f7024fbc965bc6a7f97f79ba3dec964ef769..801823d003a8e28a13fe90db4604cd0938899c6d 100644
--- a/src/main/java/net/minecraft/advancements/critereon/LocationPredicate.java
+++ b/src/main/java/net/minecraft/advancements/critereon/LocationPredicate.java
@@ -44,7 +44,7 @@ public record LocationPredicate(
public boolean matches(ServerLevel world, double x, double y, double z) {
if (this.position.isPresent() && !this.position.get().matches(x, y, z)) {
return false;
- } else if (this.dimension.isPresent() && this.dimension.get() != world.dimension()) {
+ } else if (this.dimension.isPresent() && this.dimension.get() != (io.papermc.paper.configuration.GlobalConfiguration.get().misc.strictAdvancementDimensionCheck ? world.dimension() : org.bukkit.craftbukkit.util.CraftDimensionUtil.getMainDimensionKey(world))) { // Paper - Add option for strict advancement dimension checks
return false;
} else {
BlockPos blockPos = BlockPos.containing(x, y, z);
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index f31eb944465e9011d8aad398eb60bafb44203ad5..ad3896dd524acb573adffdfb38b13dd699539cef 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1387,6 +1387,12 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
ResourceKey<Level> maindimensionkey = CraftDimensionUtil.getMainDimensionKey(origin);
ResourceKey<Level> maindimensionkey1 = CraftDimensionUtil.getMainDimensionKey(this.level());
+ // Paper start - Add option for strict advancement dimension checks
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.strictAdvancementDimensionCheck) {
+ maindimensionkey = resourcekey;
+ maindimensionkey1 = resourcekey1;
+ }
+ // Paper end - Add option for strict advancement dimension checks
CriteriaTriggers.CHANGED_DIMENSION.trigger(this, maindimensionkey, maindimensionkey1);
if (maindimensionkey != resourcekey || maindimensionkey1 != resourcekey1) {
CriteriaTriggers.CHANGED_DIMENSION.trigger(this, resourcekey, resourcekey1);

View file

@ -1,73 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Sun, 12 Jun 2022 13:25:52 -0400
Subject: [PATCH] Add missing important BlockStateListPopulator methods
Without these methods it causes exceptions due to these being used by certain feature generators.
diff --git a/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java b/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java
index ffe6881d93153838cd23f125980b832e6fd1d0eb..f5cbe9ae5802fa48e57092b1e5ca8a5f5f69ee60 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/BlockStateListPopulator.java
@@ -129,7 +129,7 @@ public class BlockStateListPopulator extends DummyGeneratorAccess {
@Override
public boolean isFluidAtPosition(BlockPos pos, Predicate<FluidState> state) {
- return this.world.isFluidAtPosition(pos, state);
+ return state.test(this.getFluidState(pos)); // Paper - fix
}
@Override
@@ -152,4 +152,33 @@ public class BlockStateListPopulator extends DummyGeneratorAccess {
public long nextSubTickCount() {
return this.world.nextSubTickCount();
}
+
+ // Paper start
+ @Override
+ public <T extends BlockEntity> java.util.Optional<T> getBlockEntity(BlockPos pos, net.minecraft.world.level.block.entity.BlockEntityType<T> type) {
+ BlockEntity tileentity = this.getBlockEntity(pos);
+
+ return tileentity != null && tileentity.getType() == type ? (java.util.Optional<T>) java.util.Optional.of(tileentity) : java.util.Optional.empty();
+ }
+
+ @Override
+ public BlockPos getHeightmapPos(net.minecraft.world.level.levelgen.Heightmap.Types heightmap, BlockPos pos) {
+ return world.getHeightmapPos(heightmap, pos);
+ }
+
+ @Override
+ public int getHeight(net.minecraft.world.level.levelgen.Heightmap.Types heightmap, int x, int z) {
+ return world.getHeight(heightmap, x, z);
+ }
+
+ @Override
+ public int getRawBrightness(BlockPos pos, int ambientDarkness) {
+ return world.getRawBrightness(pos, ambientDarkness);
+ }
+
+ @Override
+ public int getBrightness(net.minecraft.world.level.LightLayer type, BlockPos pos) {
+ return world.getBrightness(type, pos);
+ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java
index 4705aed1dd98378c146bf9e346df1a17f719ad36..daf3c26fce7569761951bfd5594c6726d854a9ff 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java
@@ -258,4 +258,14 @@ public class DummyGeneratorAccess implements WorldGenLevel {
public boolean destroyBlock(BlockPos pos, boolean drop, Entity breakingEntity, int maxUpdateDepth) {
return false; // SPIGOT-6515
}
+
+ // Paper start - add more methods
+ public void scheduleTick(BlockPos pos, Fluid fluid, int delay) {}
+
+ @Override
+ public void scheduleTick(BlockPos pos, Block block, int delay, net.minecraft.world.ticks.TickPriority priority) {}
+
+ @Override
+ public void scheduleTick(BlockPos pos, Fluid fluid, int delay, net.minecraft.world.ticks.TickPriority priority) {}
+ // Paper end - add more methods
}

View file

@ -1,50 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Thu, 7 Apr 2022 17:49:25 -0400
Subject: [PATCH] Nameable Banner API
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java
index 925608bfa9c848ed6285de5e35d60aa66e12004a..60c26076e7acf869fa0e20fdc14eeec341387d99 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java
@@ -29,7 +29,7 @@ public class BannerBlockEntity extends BlockEntity implements Nameable {
public static final int MAX_PATTERNS = 6;
private static final String TAG_PATTERNS = "patterns";
@Nullable
- private Component name;
+ public Component name; // Paper - public
public DyeColor baseColor;
private BannerPatternLayers patterns;
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java
index 5635230fc288fe5280bf785b42c862b8f111afb0..afed8bdb9bd6a135e9b5f7bd9bfc61964cb240f7 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java
@@ -112,4 +112,26 @@ public class CraftBanner extends CraftBlockEntityState<BannerBlockEntity> implem
public CraftBanner copy(Location location) {
return new CraftBanner(this, location);
}
+
+ // Paper start
+ @Override
+ public net.kyori.adventure.text.Component customName() {
+ return io.papermc.paper.adventure.PaperAdventure.asAdventure(this.getSnapshot().getCustomName());
+ }
+
+ @Override
+ public void customName(net.kyori.adventure.text.Component customName) {
+ this.getSnapshot().name = io.papermc.paper.adventure.PaperAdventure.asVanilla(customName);
+ }
+
+ @Override
+ public String getCustomName() {
+ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serializeOrNull(this.customName());
+ }
+
+ @Override
+ public void setCustomName(String name) {
+ this.customName(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserializeOrNull(name));
+ }
+ // Paper end
}

View file

@ -1,34 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 16 Jun 2022 14:22:56 -0700
Subject: [PATCH] Don't broadcast messages to command blocks
Previously the broadcast method would update the last output
in command blocks, and if called asynchronously, would throw
an error
diff --git a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
index 8c2dcc4134d96351cee75773214f3f47e71533e9..e6bfcc50cdf728216084bc00a5bb8b6b3b8f72e4 100644
--- a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
+++ b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
@@ -178,6 +178,7 @@ public abstract class BaseCommandBlock implements CommandSource {
@Override
public void sendSystemMessage(Component message) {
if (this.trackOutput) {
+ org.spigotmc.AsyncCatcher.catchOp("sendSystemMessage to a command block"); // Paper - Don't broadcast messages to command blocks
SimpleDateFormat simpledateformat = BaseCommandBlock.TIME_FORMAT;
Date date = new Date();
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 8f8674ccee58f1910ffc3926d42913048da1810e..3c5d44499e94bd19e4058eb2bf2d9b5d5890f980 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1925,7 +1925,7 @@ public final class CraftServer implements Server {
// Paper end
Set<CommandSender> recipients = new HashSet<>();
for (Permissible permissible : this.getPluginManager().getPermissionSubscriptions(permission)) {
- if (permissible instanceof CommandSender && permissible.hasPermission(permission)) {
+ if (permissible instanceof CommandSender && !(permissible instanceof org.bukkit.command.BlockCommandSender) && permissible.hasPermission(permission)) { // Paper - Don't broadcast messages to command blocks
recipients.add((CommandSender) permissible);
}
}

View file

@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Wed, 15 Jun 2022 21:52:57 -0400
Subject: [PATCH] Prevent empty items from being added to world
The previous solution caused a bunch of bandaid fixes inorder to resolve edge cases where minecraft/the api might spawn items that are air.
Just simply prevent them from being added to the world instead.
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 492e8a2ff5618c45bfffa3284f03be14ff162ce8..b88a7f580b4138ceb262f3d398e78fdc2e6b018c 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1235,6 +1235,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
// WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getKey(entity.getType())); // CraftBukkit
return false;
} else {
+ if (entity instanceof net.minecraft.world.entity.item.ItemEntity itemEntity && itemEntity.getItem().isEmpty()) return false; // Paper - Prevent empty items from being added
// Paper start - capture all item additions to the world
if (captureDrops != null && entity instanceof net.minecraft.world.entity.item.ItemEntity) {
captureDrops.add((net.minecraft.world.entity.item.ItemEntity) entity);

View file

@ -1,21 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 21 Apr 2022 18:18:02 -0700
Subject: [PATCH] Fix CCE for SplashPotion and LingeringPotion spawning
Remove in 1.19 along with the SplashPotion and
LingeringPotion interfaces
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java
index f6fa6f1ac50b757dd3bc9a8dee9f6085446182c8..65b6de9d21da6843d7c7087f0dea98d3b75f24cf 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java
@@ -14,7 +14,7 @@ import org.bukkit.entity.ThrownPotion;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
-public class CraftThrownPotion extends CraftThrowableProjectile implements ThrownPotion {
+public class CraftThrownPotion extends CraftThrowableProjectile implements ThrownPotion, org.bukkit.entity.SplashPotion, org.bukkit.entity.LingeringPotion { // Paper - implement other classes to avoid violating spawn method generic contracts
public CraftThrownPotion(CraftServer server, net.minecraft.world.entity.projectile.ThrownPotion entity) {
super(server, entity);
}

View file

@ -1,26 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: u9g <git@u9g.dev>
Date: Tue, 14 Jun 2022 19:36:10 -0400
Subject: [PATCH] Add Player#getFishHook
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
index 0222b6c68112551336f17a722fc3399898cdc7bb..049db909fbd8610ebb688d948f5d03c97ab23495 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
@@ -160,6 +160,15 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
return new Location(worldServer.getWorld(), bed.getX(), bed.getY(), bed.getZ());
}
// Paper end
+ // Paper start
+ @Override
+ public org.bukkit.entity.FishHook getFishHook() {
+ if (getHandle().fishing == null) {
+ return null;
+ }
+ return (org.bukkit.entity.FishHook) getHandle().fishing.getBukkitEntity();
+ }
+ // Paper end
@Override
public boolean sleep(Location location, boolean force) {
Preconditions.checkArgument(location != null, "Location cannot be null");

View file

@ -1,29 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sun, 3 Jul 2022 22:31:37 -0700
Subject: [PATCH] Do not sync load chunk for dynamic game event listener
registration
These can be called while an entity is being added to the world,
and if the entity is being added from a chunk load context the
sync load will block indefinitely (because the chunk load context
is for completing the chunk to FULL).
This does raise questions about the current system for these
dynamic registrations, as it looks like there is _zero_ logic
to account for the case where the chunk is _not_ currently loaded
and then later loaded.
diff --git a/src/main/java/net/minecraft/world/level/gameevent/DynamicGameEventListener.java b/src/main/java/net/minecraft/world/level/gameevent/DynamicGameEventListener.java
index af9437bddf69546a1a78eca7e858ac8d2e68ed0a..134b4ceec0ec5a2475881e739d6579fa5984c3dd 100644
--- a/src/main/java/net/minecraft/world/level/gameevent/DynamicGameEventListener.java
+++ b/src/main/java/net/minecraft/world/level/gameevent/DynamicGameEventListener.java
@@ -41,7 +41,7 @@ public class DynamicGameEventListener<T extends GameEventListener> {
private static void ifChunkExists(LevelReader world, @Nullable SectionPos sectionPos, Consumer<GameEventListenerRegistry> dispatcherConsumer) {
if (sectionPos != null) {
- ChunkAccess chunkAccess = world.getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.FULL, false);
+ ChunkAccess chunkAccess = world.getChunkIfLoadedImmediately(sectionPos.getX(), sectionPos.getZ()); // Paper - Perf: can cause sync loads while completing a chunk, resulting in deadlock
if (chunkAccess != null) {
dispatcherConsumer.accept(chunkAccess.getListenerRegistry(sectionPos.y()));
}

View file

@ -1,109 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Tue, 20 Jul 2021 21:35:47 -0700
Subject: [PATCH] Add various missing EntityDropItemEvent calls
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 8b0959050cd5e0ef24347632c3b4184eadf565e6..73a69c35bca89ab82da39149a2a7cb86d4878e3c 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -2557,6 +2557,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
stack.setCount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe
entityitem.setDefaultPickUpDelay();
+ // Paper start - Call EntityDropItemEvent
+ return this.spawnAtLocation(entityitem);
+ }
+ }
+ @Nullable
+ public ItemEntity spawnAtLocation(ItemEntity entityitem) {
+ {
+ // Paper end - Call EntityDropItemEvent
// CraftBukkit start
EntityDropItemEvent event = new EntityDropItemEvent(this.getBukkitEntity(), (org.bukkit.entity.Item) entityitem.getBukkitEntity());
Bukkit.getPluginManager().callEvent(event);
diff --git a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java
index 08823651b0a81b15bc33f86c96d6cc1dc72770f4..da45cc62985f8b67cdfeffc21cb33837db673555 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Dolphin.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Dolphin.java
@@ -576,7 +576,7 @@ public class Dolphin extends WaterAnimal {
float f2 = 0.02F * Dolphin.this.random.nextFloat();
entityitem.setDeltaMovement((double) (0.3F * -Mth.sin(Dolphin.this.getYRot() * 0.017453292F) * Mth.cos(Dolphin.this.getXRot() * 0.017453292F) + Mth.cos(f1) * f2), (double) (0.3F * Mth.sin(Dolphin.this.getXRot() * 0.017453292F) * 1.5F), (double) (0.3F * Mth.cos(Dolphin.this.getYRot() * 0.017453292F) * Mth.cos(Dolphin.this.getXRot() * 0.017453292F) + Mth.sin(f1) * f2));
- Dolphin.this.level().addFreshEntity(entityitem);
+ Dolphin.this.spawnAtLocation(entityitem); // Paper - Call EntityDropItemEvent
}
}
}
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 e46c8231ee318eda0512afbb6343b426b4838643..3265b3b5aede517b6fd8bb836947795bf8881350 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Fox.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java
@@ -507,14 +507,14 @@ public class Fox extends Animal implements VariantHolder<Fox.Type> {
entityitem.setPickUpDelay(40);
entityitem.setThrower(this);
this.playSound(SoundEvents.FOX_SPIT, 1.0F, 1.0F);
- this.level().addFreshEntity(entityitem);
+ this.spawnAtLocation(entityitem); // Paper - Call EntityDropItemEvent
}
}
private void dropItemStack(ItemStack stack) {
ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), stack);
- this.level().addFreshEntity(entityitem);
+ this.spawnAtLocation(entityitem); // Paper - Call EntityDropItemEvent
}
@Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java
index 3b2cf9ca8447321d64ffdb4fdb9569d736d63dbb..923806900ef6248576e71260d40e9caf2c8943e8 100644
--- a/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java
+++ b/src/main/java/net/minecraft/world/entity/animal/goat/Goat.java
@@ -361,8 +361,7 @@ public class Goat extends Animal {
double d2 = (double) Mth.randomBetween(this.random, -0.2F, 0.2F);
ItemEntity entityitem = new ItemEntity(this.level(), vec3d.x(), vec3d.y(), vec3d.z(), itemstack, d0, d1, d2);
- this.level().addFreshEntity(entityitem);
- return true;
+ return this.spawnAtLocation(entityitem) != null; // Paper - Call EntityDropItemEvent
}
}
diff --git a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java
index 94df94f7acc121201966955a09fb336b0a98e599..d34d8fe70379dcad9540739ec0ae1c94f01fc46b 100644
--- a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java
+++ b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java
@@ -350,8 +350,9 @@ public class Sniffer extends Animal {
entityitem.setDefaultPickUpDelay();
this.finalizeSpawnChildFromBreeding(world, other, (AgeableMob) null);
+ if (this.spawnAtLocation(entityitem) != null) { // Paper - Call EntityDropItemEvent
this.playSound(SoundEvents.SNIFFER_EGG_PLOP, 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 0.5F);
- world.addFreshEntity(entityitem);
+ } // Paper - Call EntityDropItemEvent
}
@Override
diff --git a/src/main/java/net/minecraft/world/item/ItemUtils.java b/src/main/java/net/minecraft/world/item/ItemUtils.java
index 66f88f44eb74dfbdafe0d6257dc1ef46238aaa92..4901f0d89ae2472bce7f242d9529236674f5d134 100644
--- a/src/main/java/net/minecraft/world/item/ItemUtils.java
+++ b/src/main/java/net/minecraft/world/item/ItemUtils.java
@@ -41,7 +41,15 @@ public class ItemUtils {
public static void onContainerDestroyed(ItemEntity itemEntity, Iterable<ItemStack> contents) {
Level level = itemEntity.level();
if (!level.isClientSide) {
- contents.forEach(stack -> level.addFreshEntity(new ItemEntity(level, itemEntity.getX(), itemEntity.getY(), itemEntity.getZ(), stack)));
+ // Paper start - call EntityDropItemEvent
+ contents.forEach(stack -> {
+ ItemEntity droppedItem = new ItemEntity(level, itemEntity.getX(), itemEntity.getY(), itemEntity.getZ(), stack);
+ org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(itemEntity.getBukkitEntity(), (org.bukkit.entity.Item) droppedItem.getBukkitEntity());
+ if (event.callEvent()) {
+ level.addFreshEntity(droppedItem);
+ }
+ });
+ // Paper end - call EntityDropItemEvent
}
}
}

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Wed, 6 Jul 2022 14:59:38 -0700
Subject: [PATCH] Fix Bee flower NPE
diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java
index f933654b66f7474dc071da5f10cf1684fdac367a..1b3978f4ea7e8491e0c0cb6de23c141f44fab414 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
@@ -805,7 +805,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
++this.pollinatingTicks;
if (this.pollinatingTicks > 600) {
Bee.this.savedFlowerPos = null;
- } else {
+ } else if (Bee.this.savedFlowerPos != null) { // Paper - add null check since API can manipulate this
Vec3 vec3d = Vec3.atBottomCenterOf(Bee.this.savedFlowerPos).add(0.0D, 0.6000000238418579D, 0.0D);
if (vec3d.distanceTo(Bee.this.position()) > 1.0D) {

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Doc <nachito94@msn.com>
Date: Sun, 17 Jul 2022 11:49:43 -0400
Subject: [PATCH] Fix Spigot Config not using commands.spam-exclusions
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 7c1a94980cf49d37be442e1b62de36d4395bcf2a..4fa49daf58723827366f611e006e77448cc73a0b 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2383,7 +2383,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
}
// Spigot end
// this.chatSpamTickCount += 20;
- if (this.chatSpamTickCount.addAndGet(20) > 200 && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(this.player.getGameProfile())) {
+ if (counted && this.chatSpamTickCount.addAndGet(20) > 200 && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(this.player.getGameProfile())) { // Paper - exclude from SpigotConfig.spamExclusions
// CraftBukkit end
this.disconnect((Component) Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause
}

View file

@ -1,269 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Sun, 5 Sep 2021 12:15:59 -0400
Subject: [PATCH] More Teleport API
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 4fa49daf58723827366f611e006e77448cc73a0b..f05297a2b349734b9700a0e977ee9b2bba030d65 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1565,11 +1565,17 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
return true; // CraftBukkit - Return event status
}
- PlayerTeleportEvent event = new PlayerTeleportEvent(player, from.clone(), to.clone(), cause);
+ // Paper start - Teleport API
+ Set<io.papermc.paper.entity.TeleportFlag.Relative> relativeFlags = java.util.EnumSet.noneOf(io.papermc.paper.entity.TeleportFlag.Relative.class);
+ for (RelativeMovement relativeArgument : set) {
+ relativeFlags.add(org.bukkit.craftbukkit.entity.CraftPlayer.toApiRelativeFlag(relativeArgument));
+ }
+ PlayerTeleportEvent event = new PlayerTeleportEvent(player, from.clone(), to.clone(), cause, java.util.Set.copyOf(relativeFlags));
+ // Paper end - Teleport API
this.cserver.getPluginManager().callEvent(event);
if (event.isCancelled() || !to.equals(event.getTo())) {
- set = Collections.emptySet(); // Can't relative teleport
+ // set = Collections.emptySet(); // Can't relative teleport // Paper - Teleport API; Now you can!
to = event.isCancelled() ? event.getFrom() : event.getTo();
d0 = to.getX();
d1 = to.getY();
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 4c09f2529dd8eb7ac7d260d177f5292ff2339442..94051ae8ea93ab144f3767345b1cda0438d2afc6 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -221,15 +221,36 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
@Override
public boolean teleport(Location location, TeleportCause cause) {
+ // Paper start - Teleport passenger API
+ return teleport(location, cause, new io.papermc.paper.entity.TeleportFlag[0]);
+ }
+
+ @Override
+ public boolean teleport(Location location, TeleportCause cause, io.papermc.paper.entity.TeleportFlag... flags) {
+ // Paper end
Preconditions.checkArgument(location != null, "location cannot be null");
location.checkFinite();
+ // Paper start - Teleport passenger API
+ Set<io.papermc.paper.entity.TeleportFlag> flagSet = Set.of(flags);
+ boolean dismount = !flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_VEHICLE);
+ boolean ignorePassengers = flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS);
+ // Don't allow teleporting between worlds while keeping passengers
+ if (flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS) && this.entity.isVehicle() && location.getWorld() != this.getWorld()) {
+ return false;
+ }
+
+ // Don't allow to teleport between worlds if remaining on vehicle
+ if (!dismount && this.entity.isPassenger() && location.getWorld() != this.getWorld()) {
+ return false;
+ }
+ // Paper end
- if (this.entity.isVehicle() || this.entity.isRemoved()) {
+ if ((!ignorePassengers && this.entity.isVehicle()) || this.entity.isRemoved()) { // Paper - Teleport passenger API
return false;
}
// If this entity is riding another entity, we must dismount before teleporting.
- this.entity.stopRiding();
+ if (dismount) this.entity.stopRiding(); // Paper - Teleport passenger API
// Let the server handle cross world teleports
if (location.getWorld() != null && !location.getWorld().equals(this.getWorld())) {
@@ -975,6 +996,39 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
return CraftEntity.perm;
}
+ // Paper start - more teleport API / async chunk API
+ @Override
+ public java.util.concurrent.CompletableFuture<Boolean> teleportAsync(final Location location, final TeleportCause cause, final io.papermc.paper.entity.TeleportFlag... teleportFlags) {
+ Preconditions.checkArgument(location != null, "location");
+ location.checkFinite();
+ Location locationClone = location.clone(); // clone so we don't need to worry about mutations after this call.
+
+ net.minecraft.server.level.ServerLevel world = ((CraftWorld)locationClone.getWorld()).getHandle();
+ java.util.concurrent.CompletableFuture<Boolean> ret = new java.util.concurrent.CompletableFuture<>();
+
+ world.loadChunksForMoveAsync(getHandle().getBoundingBoxAt(locationClone.getX(), locationClone.getY(), locationClone.getZ()),
+ this instanceof CraftPlayer ? ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.HIGHER : ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.NORMAL, (list) -> {
+ net.minecraft.server.level.ServerChunkCache chunkProviderServer = world.getChunkSource();
+ for (net.minecraft.world.level.chunk.ChunkAccess chunk : list) {
+ chunkProviderServer.addTicketAtLevel(net.minecraft.server.level.TicketType.POST_TELEPORT, chunk.getPos(), 33, CraftEntity.this.getEntityId());
+ }
+ net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> {
+ try {
+ ret.complete(CraftEntity.this.teleport(locationClone, cause, teleportFlags) ? Boolean.TRUE : Boolean.FALSE);
+ } catch (Throwable throwable) {
+ if (throwable instanceof ThreadDeath) {
+ throw (ThreadDeath)throwable;
+ }
+ net.minecraft.server.MinecraftServer.LOGGER.error("Failed to teleport entity " + CraftEntity.this, throwable);
+ ret.completeExceptionally(throwable);
+ }
+ });
+ });
+
+ return ret;
+ }
+ // Paper end - more teleport API / async chunk API
+
// Spigot start
private final org.bukkit.entity.Entity.Spigot spigot = new org.bukkit.entity.Entity.Spigot()
{
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index ef289dba67db65a5e43104a4ca68bc03c8c5e4cb..7f47005c08cccbcb8cd5ac56157c4e0d0dfe10b0 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1286,13 +1286,101 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
@Override
public void setRotation(float yaw, float pitch) {
- throw new UnsupportedOperationException("Cannot set rotation of players. Consider teleporting instead.");
+ // Paper start - Teleport API
+ Location targetLocation = this.getEyeLocation();
+ targetLocation.setYaw(yaw);
+ targetLocation.setPitch(pitch);
+
+ org.bukkit.util.Vector direction = targetLocation.getDirection();
+ direction.multiply(9999999); // We need to move the target block.. FAR out
+ targetLocation.add(direction);
+ this.lookAt(targetLocation, io.papermc.paper.entity.LookAnchor.EYES);
+ // Paper end
}
@Override
public boolean teleport(Location location, PlayerTeleportEvent.TeleportCause cause) {
+ // Paper start - Teleport API
+ return this.teleport(location, cause, new io.papermc.paper.entity.TeleportFlag[0]);
+ }
+
+ @Override
+ public void lookAt(@NotNull org.bukkit.entity.Entity entity, @NotNull io.papermc.paper.entity.LookAnchor playerAnchor, @NotNull io.papermc.paper.entity.LookAnchor entityAnchor) {
+ this.getHandle().lookAt(toNmsAnchor(playerAnchor), ((CraftEntity) entity).getHandle(), toNmsAnchor(entityAnchor));
+ }
+
+ @Override
+ public void lookAt(double x, double y, double z, @NotNull io.papermc.paper.entity.LookAnchor playerAnchor) {
+ this.getHandle().lookAt(toNmsAnchor(playerAnchor), new net.minecraft.world.phys.Vec3(x, y, z));
+ }
+
+ public static net.minecraft.commands.arguments.EntityAnchorArgument.Anchor toNmsAnchor(io.papermc.paper.entity.LookAnchor nmsAnchor) {
+ return switch (nmsAnchor) {
+ case EYES -> net.minecraft.commands.arguments.EntityAnchorArgument.Anchor.EYES;
+ case FEET -> net.minecraft.commands.arguments.EntityAnchorArgument.Anchor.FEET;
+ };
+ }
+
+ public static io.papermc.paper.entity.LookAnchor toApiAnchor(net.minecraft.commands.arguments.EntityAnchorArgument.Anchor playerAnchor) {
+ return switch (playerAnchor) {
+ case EYES -> io.papermc.paper.entity.LookAnchor.EYES;
+ case FEET -> io.papermc.paper.entity.LookAnchor.FEET;
+ };
+ }
+
+ public static net.minecraft.world.entity.RelativeMovement toNmsRelativeFlag(io.papermc.paper.entity.TeleportFlag.Relative apiFlag) {
+ return switch (apiFlag) {
+ case X -> net.minecraft.world.entity.RelativeMovement.X;
+ case Y -> net.minecraft.world.entity.RelativeMovement.Y;
+ case Z -> net.minecraft.world.entity.RelativeMovement.Z;
+ case PITCH -> net.minecraft.world.entity.RelativeMovement.X_ROT;
+ case YAW -> net.minecraft.world.entity.RelativeMovement.Y_ROT;
+ };
+ }
+
+ public static io.papermc.paper.entity.TeleportFlag.Relative toApiRelativeFlag(net.minecraft.world.entity.RelativeMovement nmsFlag) {
+ return switch (nmsFlag) {
+ case X -> io.papermc.paper.entity.TeleportFlag.Relative.X;
+ case Y -> io.papermc.paper.entity.TeleportFlag.Relative.Y;
+ case Z -> io.papermc.paper.entity.TeleportFlag.Relative.Z;
+ case X_ROT -> io.papermc.paper.entity.TeleportFlag.Relative.PITCH;
+ case Y_ROT -> io.papermc.paper.entity.TeleportFlag.Relative.YAW;
+ };
+ }
+
+ @Override
+ public boolean teleport(Location location, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause, io.papermc.paper.entity.TeleportFlag... flags) {
+ Set<io.papermc.paper.entity.TeleportFlag.Relative> relativeArguments;
+ Set<io.papermc.paper.entity.TeleportFlag> allFlags;
+ if (flags.length == 0) {
+ relativeArguments = Set.of();
+ allFlags = Set.of();
+ } else {
+ relativeArguments = java.util.EnumSet.noneOf(io.papermc.paper.entity.TeleportFlag.Relative.class);
+ allFlags = new HashSet<>();
+ for (io.papermc.paper.entity.TeleportFlag flag : flags) {
+ if (flag instanceof final io.papermc.paper.entity.TeleportFlag.Relative relativeTeleportFlag) {
+ relativeArguments.add(relativeTeleportFlag);
+ }
+ allFlags.add(flag);
+ }
+ }
+ boolean dismount = !allFlags.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_VEHICLE);
+ boolean ignorePassengers = allFlags.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS);
+ // Paper end - Teleport API
Preconditions.checkArgument(location != null, "location");
Preconditions.checkArgument(location.getWorld() != null, "location.world");
+ // Paper start - Teleport passenger API
+ // Don't allow teleporting between worlds while keeping passengers
+ if (ignorePassengers && entity.isVehicle() && location.getWorld() != this.getWorld()) {
+ return false;
+ }
+
+ // Don't allow to teleport between worlds if remaining on vehicle
+ if (!dismount && entity.isPassenger() && location.getWorld() != this.getWorld()) {
+ return false;
+ }
+ // Paper end
location.checkFinite();
ServerPlayer entity = this.getHandle();
@@ -1305,7 +1393,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
return false;
}
- if (entity.isVehicle()) {
+ if (entity.isVehicle() && !ignorePassengers) { // Paper - Teleport API
return false;
}
@@ -1314,7 +1402,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
// To = Players new Location if Teleport is Successful
Location to = location;
// Create & Call the Teleport Event.
- PlayerTeleportEvent event = new PlayerTeleportEvent(this, from, to, cause);
+ PlayerTeleportEvent event = new PlayerTeleportEvent(this, from, to, cause, Set.copyOf(relativeArguments)); // Paper - Teleport API
this.server.getPluginManager().callEvent(event);
// Return False to inform the Plugin that the Teleport was unsuccessful/cancelled.
@@ -1323,7 +1411,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
}
// If this player is riding another entity, we must dismount before teleporting.
- entity.stopRiding();
+ if (dismount) entity.stopRiding(); // Paper - Teleport API
// SPIGOT-5509: Wakeup, similar to riding
if (this.isSleeping()) {
@@ -1339,13 +1427,19 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
ServerLevel toWorld = ((CraftWorld) to.getWorld()).getHandle();
// Close any foreign inventory
- if (this.getHandle().containerMenu != this.getHandle().inventoryMenu) {
+ if (this.getHandle().containerMenu != this.getHandle().inventoryMenu && !allFlags.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_OPEN_INVENTORY)) { // Paper
this.getHandle().closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.TELEPORT); // Paper - Inventory close reason
}
// Check if the fromWorld and toWorld are the same.
if (fromWorld == toWorld) {
- entity.connection.teleport(to);
+ // Paper start - Teleport API
+ final Set<net.minecraft.world.entity.RelativeMovement> nms = java.util.EnumSet.noneOf(net.minecraft.world.entity.RelativeMovement.class);
+ for (final io.papermc.paper.entity.TeleportFlag.Relative bukkit : relativeArguments) {
+ nms.add(toNmsRelativeFlag(bukkit));
+ }
+ entity.connection.internalTeleport(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch(), nms);
+ // Paper end - Teleport API
} else {
entity.portalProcess = null; // SPIGOT-7785: there is no need to carry this over as it contains the old world/location and we might run into trouble if there is a portal in the same spot in both worlds
// The respawn reason should never be used if the passed location is non null.

View file

@ -1,25 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Wed, 12 May 2021 04:30:42 -0700
Subject: [PATCH] Add EntityPortalReadyEvent
diff --git a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
index e2969b49494c55c3705312361ee8083b05ef569e..417a9ab28d247d5fbb3f1097fdeccab7ad2a793b 100644
--- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
@@ -133,6 +133,14 @@ public class NetherPortalBlock extends Block implements Portal {
// CraftBukkit start
ResourceKey<Level> resourcekey = world.getTypeKey() == LevelStem.NETHER ? Level.OVERWORLD : Level.NETHER;
ServerLevel worldserver1 = world.getServer().getLevel(resourcekey);
+ // Paper start - Add EntityPortalReadyEvent
+ io.papermc.paper.event.entity.EntityPortalReadyEvent portalReadyEvent = new io.papermc.paper.event.entity.EntityPortalReadyEvent(entity.getBukkitEntity(), worldserver1 == null ? null : worldserver1.getWorld(), org.bukkit.PortalType.NETHER);
+ if (!portalReadyEvent.callEvent()) {
+ entity.portalProcess = null;
+ return null;
+ }
+ worldserver1 = portalReadyEvent.getTargetWorld() == null ? null : ((org.bukkit.craftbukkit.CraftWorld) portalReadyEvent.getTargetWorld()).getHandle();
+ // Paper end - Add EntityPortalReadyEvent
if (worldserver1 == null) {
return new DimensionTransition(PlayerTeleportEvent.TeleportCause.NETHER_PORTAL); // always fire event in case plugins wish to change it

View file

@ -1,41 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 10 Jul 2022 14:13:22 -0700
Subject: [PATCH] Don't use level random in entity constructors
Paper makes the entity random thread-safe
and constructing an entity off the main thread
should be supported. Some entities (for whatever
reason) use the level's random in some places.
diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
index df90d5b934f41f5d8c232e93830d6690b6ccf401..446c319524183d6a1b4d0e6f0613a8db690677da 100644
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
@@ -72,7 +72,12 @@ public class ItemEntity extends Entity implements TraceableEntity {
}
public ItemEntity(Level world, double x, double y, double z, ItemStack stack) {
- this(world, x, y, z, stack, world.random.nextDouble() * 0.2D - 0.1D, 0.2D, world.random.nextDouble() * 0.2D - 0.1D);
+ // Paper start - Don't use level random in entity constructors (to make them thread-safe)
+ this(EntityType.ITEM, world);
+ this.setPos(x, y, z);
+ this.setDeltaMovement(this.random.nextDouble() * 0.2D - 0.1D, 0.2D, this.random.nextDouble() * 0.2D - 0.1D);
+ this.setItem(stack);
+ // Paper end - Don't use level random in entity constructors
}
public ItemEntity(Level world, double x, double y, double z, ItemStack stack, double velocityX, double velocityY, double velocityZ) {
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
index 47f2a480f6a4b15e55cedbfa8a58459d33516a97..42bd2d9a1528b6210e4dfb56233062fd97c9743b 100644
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
@@ -62,7 +62,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
public PrimedTnt(Level world, double x, double y, double z, @Nullable LivingEntity igniter) {
this(EntityType.TNT, world);
this.setPos(x, y, z);
- double d3 = world.random.nextDouble() * 6.2831854820251465D;
+ double d3 = this.random.nextDouble() * 6.2831854820251465D; // Paper - Don't use level random in entity constructors
this.setDeltaMovement(-Math.sin(d3) * 0.02D, 0.20000000298023224D, -Math.cos(d3) * 0.02D);
this.setFuse(80);

View file

@ -1,91 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Sat, 25 Jun 2022 19:45:20 -0400
Subject: [PATCH] Send block entities after destroy prediction
Minecraft's prediction system does not handle block entities, so if we are manually sending block entities during
block breaking we need to set it after the prediction is finished. This fixes block entities not showing when cancelling the BlockBreakEvent.
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
index 4d024956156aefde7df308642dfd0a40779e0633..6abecaac8407b992d208a9108e11fd4954a4106f 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -63,6 +63,8 @@ public class ServerPlayerGameMode {
private BlockPos delayedDestroyPos;
private int delayedTickStart;
private int lastSentState;
+ public boolean captureSentBlockEntities = false; // Paper - Send block entities after destroy prediction
+ public boolean capturedBlockEntity = false; // Paper - Send block entities after destroy prediction
public ServerPlayerGameMode(ServerPlayer player) {
this.gameModeForPlayer = GameType.DEFAULT_MODE;
@@ -193,10 +195,7 @@ public class ServerPlayerGameMode {
this.player.connection.send(new ClientboundBlockUpdatePacket(pos, this.level.getBlockState(pos)));
this.debugLogging(pos, false, sequence, "may not interact");
// Update any tile entity data for this block
- BlockEntity tileentity = this.level.getBlockEntity(pos);
- if (tileentity != null) {
- this.player.connection.send(tileentity.getUpdatePacket());
- }
+ capturedBlockEntity = true; // Paper - Send block entities after destroy prediction
// CraftBukkit end
return;
}
@@ -207,10 +206,7 @@ public class ServerPlayerGameMode {
// Let the client know the block still exists
this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos));
// Update any tile entity data for this block
- BlockEntity tileentity = this.level.getBlockEntity(pos);
- if (tileentity != null) {
- this.player.connection.send(tileentity.getUpdatePacket());
- }
+ capturedBlockEntity = true; // Paper - Send block entities after destroy prediction
return;
}
// CraftBukkit end
@@ -395,10 +391,12 @@ public class ServerPlayerGameMode {
}
// Update any tile entity data for this block
+ if (!captureSentBlockEntities) { // Paper - Send block entities after destroy prediction
BlockEntity tileentity = this.level.getBlockEntity(pos);
if (tileentity != null) {
this.player.connection.send(tileentity.getUpdatePacket());
}
+ } else {capturedBlockEntity = true;} // Paper - Send block entities after destroy prediction
return false;
}
}
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index f05297a2b349734b9700a0e977ee9b2bba030d65..ca32e5aa6e77ca1bab886e7b6a778ec931ac4e4c 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1711,8 +1711,28 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
return;
}
// Paper end - Don't allow digging into unloaded chunks
+ // Paper start - Send block entities after destroy prediction
+ this.player.gameMode.capturedBlockEntity = false;
+ this.player.gameMode.captureSentBlockEntities = true;
+ // Paper end - Send block entities after destroy prediction
this.player.gameMode.handleBlockBreakAction(blockposition, packetplayinblockdig_enumplayerdigtype, packet.getDirection(), this.player.level().getMaxBuildHeight(), packet.getSequence());
this.player.connection.ackBlockChangesUpTo(packet.getSequence());
+ // Paper start - Send block entities after destroy prediction
+ this.player.gameMode.captureSentBlockEntities = false;
+ // If a block entity was modified speedup the block change ack to avoid the block entity
+ // being overriden.
+ if (this.player.gameMode.capturedBlockEntity) {
+ // manually tick
+ this.send(new ClientboundBlockChangedAckPacket(this.ackBlockChangesUpTo));
+ this.player.connection.ackBlockChangesUpTo = -1;
+
+ this.player.gameMode.capturedBlockEntity = false;
+ BlockEntity tileentity = this.player.level().getBlockEntity(blockposition);
+ if (tileentity != null) {
+ this.player.connection.send(tileentity.getUpdatePacket());
+ }
+ }
+ // Paper end - Send block entities after destroy prediction
return;
default:
throw new IllegalArgumentException("Invalid player action");

View file

@ -1,96 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Fri, 29 Jul 2022 12:35:19 -0400
Subject: [PATCH] Warn on plugins accessing faraway chunks
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index f800975068135fb86b025254db6f88f406cf0b65..63beee706d820bba5fb93db0bf53b4a6ecd403a1 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -339,7 +339,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
}
private static boolean isInWorldBoundsHorizontal(BlockPos pos) {
- return pos.getX() >= -30000000 && pos.getZ() >= -30000000 && pos.getX() < 30000000 && pos.getZ() < 30000000;
+ return pos.getX() >= -30000000 && pos.getZ() >= -30000000 && pos.getX() < 30000000 && pos.getZ() < 30000000; // Diff on change warnUnsafeChunk()
}
private static boolean isOutsideSpawnableHeight(int y) {
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 20a954c8637c2cf9cc6c0c823e33a44f668cc4f6..58cd4ecd5582c01b836814f4151df2538b93143c 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -305,9 +305,24 @@ public class CraftWorld extends CraftRegionAccessor implements World {
public boolean setSpawnLocation(int x, int y, int z) {
return this.setSpawnLocation(x, y, z, 0.0F);
}
+ // Paper start
+ private static void warnUnsafeChunk(String reason, int x, int z) {
+ // if any chunk coord is outside of 30 million blocks
+ if (x > 1875000 || z > 1875000 || x < -1875000 || z < -1875000) {
+ Plugin plugin = io.papermc.paper.util.StackWalkerUtil.getFirstPluginCaller();
+ if (plugin != null) {
+ plugin.getLogger().warning("Plugin is %s at (%s, %s), this might cause issues.".formatted(reason, x, z));
+ }
+ if (net.minecraft.server.MinecraftServer.getServer().isDebugging()) {
+ io.papermc.paper.util.TraceUtil.dumpTraceForThread("Dangerous chunk retrieval");
+ }
+ }
+ }
+ // Paper end
@Override
public Chunk getChunkAt(int x, int z) {
+ warnUnsafeChunk("getting a faraway chunk", x, z); // Paper
// Paper start - add ticket to hold chunk for a little while longer if plugin accesses it
net.minecraft.world.level.chunk.LevelChunk chunk = this.world.getChunkSource().getChunkAtIfLoadedImmediately(x, z);
if (chunk == null) {
@@ -413,6 +428,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
if (!unloadChunk0(x, z, false)) {
return false;
}
+ warnUnsafeChunk("regenerating a faraway chunk", x, z); // Paper
final long chunkKey = ChunkCoordIntPair.pair(x, z);
world.getChunkProvider().unloadQueue.remove(chunkKey);
@@ -486,6 +502,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public boolean loadChunk(int x, int z, boolean generate) {
org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot
+ warnUnsafeChunk("loading a faraway chunk", x, z); // Paper
ChunkAccess chunk = this.world.getChunkSource().getChunk(x, z, generate || isChunkGenerated(x, z) ? ChunkStatus.FULL : ChunkStatus.EMPTY, true); // Paper
// If generate = false, but the chunk already exists, we will get this back.
@@ -518,6 +535,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public boolean addPluginChunkTicket(int x, int z, Plugin plugin) {
+ warnUnsafeChunk("adding a faraway chunk ticket", x, z); // Paper
Preconditions.checkArgument(plugin != null, "null plugin");
Preconditions.checkArgument(plugin.isEnabled(), "plugin is not enabled");
@@ -618,6 +636,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public void setChunkForceLoaded(int x, int z, boolean forced) {
+ warnUnsafeChunk("forceloading a faraway chunk", x, z); // Paper
this.getHandle().setChunkForced(x, z, forced);
}
@@ -948,6 +967,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public int getHighestBlockYAt(int x, int z, org.bukkit.HeightMap heightMap) {
+ warnUnsafeChunk("getting a faraway chunk", x >> 4, z >> 4); // Paper
// Transient load for this tick
return this.world.getChunk(x >> 4, z >> 4).getHeight(CraftHeightMap.toNMS(heightMap), x, z);
}
@@ -2345,6 +2365,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
// Spigot end
// Paper start
public java.util.concurrent.CompletableFuture<Chunk> getChunkAtAsync(int x, int z, boolean gen, boolean urgent) {
+ warnUnsafeChunk("getting a faraway chunk async", x, z); // Paper
if (Bukkit.isPrimaryThread()) {
net.minecraft.world.level.chunk.LevelChunk immediate = this.world.getChunkSource().getChunkAtIfLoadedImmediately(x, z);
if (immediate != null) {

View file

@ -1,35 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Sat, 30 Jul 2022 11:23:05 -0400
Subject: [PATCH] Custom Chat Completion Suggestions API
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 7f47005c08cccbcb8cd5ac56157c4e0d0dfe10b0..3374dcd3b1f22b6c1803b9580c4cea6552b6afb1 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -691,6 +691,24 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
}
// Paper end - Add sendOpLevel API
+ // Paper start - custom chat completions API
+ @Override
+ public void addAdditionalChatCompletions(@NotNull Collection<String> completions) {
+ this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundCustomChatCompletionsPacket(
+ net.minecraft.network.protocol.game.ClientboundCustomChatCompletionsPacket.Action.ADD,
+ new ArrayList<>(completions)
+ ));
+ }
+
+ @Override
+ public void removeAdditionalChatCompletions(@NotNull Collection<String> completions) {
+ this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundCustomChatCompletionsPacket(
+ net.minecraft.network.protocol.game.ClientboundCustomChatCompletionsPacket.Action.REMOVE,
+ new ArrayList<>(completions)
+ ));
+ }
+ // Paper end - custom chat completions API
+
@Override
public void setCompassTarget(Location loc) {
Preconditions.checkArgument(loc != null, "Location cannot be null");

View file

@ -1,71 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Thu, 21 Jul 2022 12:07:54 -0400
Subject: [PATCH] Add and fix missing BlockFadeEvents
Beyond calling the BlockFadeEvent in more places, this patch also aims
to pass the proper replacement state to the event, specifically for
potentially waterlogged block states fading.
Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com>
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 669234bca9fa50548447f77dc5f314df8d9dd7c9..f2d4264743b6070f36adb66d00a3de0a72b86846 100644
--- a/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/FrogspawnBlock.java
@@ -92,6 +92,11 @@ public class FrogspawnBlock extends Block {
}
private void hatchFrogspawn(ServerLevel world, BlockPos pos, RandomSource random) {
+ // Paper start - Call BlockFadeEvent
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, Blocks.AIR.defaultBlockState()).isCancelled()) {
+ return;
+ }
+ // Paper end - Call BlockFadeEvent
this.destroyBlock(world, pos);
world.playSound(null, pos, SoundEvents.FROGSPAWN_HATCH, SoundSource.BLOCKS, 1.0F, 1.0F);
this.spawnTadpoles(world, pos, random);
diff --git a/src/main/java/net/minecraft/world/level/block/ScaffoldingBlock.java b/src/main/java/net/minecraft/world/level/block/ScaffoldingBlock.java
index 580c77eeaf88083f2aed2e46e6c57dc1fcf9564c..f4cccbc134b33758cd553a29b9f8e9967517500d 100644
--- a/src/main/java/net/minecraft/world/level/block/ScaffoldingBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/ScaffoldingBlock.java
@@ -103,7 +103,7 @@ public class ScaffoldingBlock extends Block implements SimpleWaterloggedBlock {
int i = ScaffoldingBlock.getDistance(world, pos);
BlockState iblockdata1 = (BlockState) ((BlockState) state.setValue(ScaffoldingBlock.DISTANCE, i)).setValue(ScaffoldingBlock.BOTTOM, this.isBottom(world, pos, i));
- if ((Integer) iblockdata1.getValue(ScaffoldingBlock.DISTANCE) == 7 && !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, Blocks.AIR.defaultBlockState()).isCancelled()) { // CraftBukkit - BlockFadeEvent
+ if ((Integer) iblockdata1.getValue(ScaffoldingBlock.DISTANCE) == 7 && !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, iblockdata1.getFluidState().createLegacyBlock()).isCancelled()) { // CraftBukkit - BlockFadeEvent // Paper - fix wrong block state
if ((Integer) state.getValue(ScaffoldingBlock.DISTANCE) == 7) {
FallingBlockEntity.fall(world, pos, iblockdata1);
} else {
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 14a5cd54820243f4ca59857b0d67c1e86457d590..f53808e200bd83ab80954ec5c1e9c14250302be8 100644
--- a/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java
@@ -60,12 +60,26 @@ public class SnifferEggBlock extends Block {
return this.getHatchLevel(state) == 2;
}
+ // Paper start - Call BlockFadeEvent
+ private void rescheduleTick(ServerLevel world, BlockPos pos) {
+ int baseDelay = hatchBoost(world, pos) ? BOOSTED_HATCH_TIME_TICKS : REGULAR_HATCH_TIME_TICKS;
+ world.scheduleTick(pos, this, (baseDelay / 3) + world.random.nextInt(RANDOM_HATCH_OFFSET_TICKS));
+ // reschedule to avoid being stuck here and behave like the other calls (see #onPlace)
+ }
+ // Paper end - Call BlockFadeEvent
+
@Override
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
if (!this.isReadyToHatch(state)) {
world.playSound(null, pos, SoundEvents.SNIFFER_EGG_CRACK, SoundSource.BLOCKS, 0.7F, 0.9F + random.nextFloat() * 0.2F);
world.setBlock(pos, state.setValue(HATCH, Integer.valueOf(this.getHatchLevel(state) + 1)), 2);
} else {
+ // Paper start - Call BlockFadeEvent
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, state.getFluidState().createLegacyBlock()).isCancelled()) {
+ this.rescheduleTick(world, pos);
+ return;
+ }
+ // Paper end - Call BlockFadeEvent
world.playSound(null, pos, SoundEvents.SNIFFER_EGG_HATCH, SoundSource.BLOCKS, 0.7F, 0.9F + random.nextFloat() * 0.2F);
world.destroyBlock(pos, false);
Sniffer sniffer = EntityType.SNIFFER.create(world);

View file

@ -1,48 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Wed, 6 Oct 2021 20:10:44 -0400
Subject: [PATCH] Collision API
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
index f6dd8665b9f6e2a8ff396deba8a021e695bedf7e..3c1937b43b6834ae0ffdd8d22ac32a776bc7fb64 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
@@ -543,5 +543,12 @@ public abstract class CraftRegionAccessor implements RegionAccessor {
return this.getHandle().clip(new net.minecraft.world.level.ClipContext(start, end, net.minecraft.world.level.ClipContext.Block.COLLIDER, net.minecraft.world.level.ClipContext.Fluid.NONE, net.minecraft.world.phys.shapes.CollisionContext.empty())).getType() == net.minecraft.world.phys.HitResult.Type.MISS;
}
+
+ @Override
+ public boolean hasCollisionsIn(@org.jetbrains.annotations.NotNull org.bukkit.util.BoundingBox boundingBox) {
+ net.minecraft.world.phys.AABB aabb = new net.minecraft.world.phys.AABB(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ(), boundingBox.getMaxX(), boundingBox.getMaxY(), boundingBox.getMaxZ());
+
+ return !this.getHandle().noCollision(aabb);
+ }
// Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 94051ae8ea93ab144f3767345b1cda0438d2afc6..f950102a324d07aeba260bfa82fe88728f2362e5 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -1193,4 +1193,20 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
return this.getHandle().noPhysics;
}
// Paper end - missing entity api
+
+ // Paper start - Collision API
+ @Override
+ public boolean collidesAt(@org.jetbrains.annotations.NotNull Location location) {
+ net.minecraft.world.phys.AABB aabb = this.getHandle().getBoundingBoxAt(location.getX(), location.getY(), location.getZ());
+
+ return !this.getHandle().level().noCollision(this.getHandle(), aabb);
+ }
+
+ @Override
+ public boolean wouldCollideUsing(@org.jetbrains.annotations.NotNull BoundingBox boundingBox) {
+ net.minecraft.world.phys.AABB aabb = new AABB(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ(), boundingBox.getMaxX(), boundingBox.getMaxY(), boundingBox.getMaxZ());
+
+ return !this.getHandle().level().noCollision(this.getHandle(), aabb);
+ }
+ // Paper end - Collision API
}

View file

@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: chickeneer <emcchickeneer@gmail.com>
Date: Mon, 1 Aug 2022 20:13:02 -0500
Subject: [PATCH] Fix suggest command message for brigadier syntax exceptions
This is a bug accidentally introduced in upstream CB
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
index 64656e69dbeb6a1cf399ca143a2d7e0a1ee85957..96ca1af97c1f63776b88bc428874742a5114564f 100644
--- a/src/main/java/net/minecraft/commands/Commands.java
+++ b/src/main/java/net/minecraft/commands/Commands.java
@@ -386,7 +386,7 @@ public class Commands {
if (commandsyntaxexception.getInput() != null && commandsyntaxexception.getCursor() >= 0) {
int i = Math.min(commandsyntaxexception.getInput().length(), commandsyntaxexception.getCursor());
MutableComponent ichatmutablecomponent = Component.empty().withStyle(ChatFormatting.GRAY).withStyle((chatmodifier) -> {
- return chatmodifier.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, label)); // CraftBukkit
+ return chatmodifier.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + label)); // CraftBukkit // Paper
});
if (i > 10) {

View file

@ -1,63 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Sun, 26 Dec 2021 13:23:46 -0500
Subject: [PATCH] Block Ticking API
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
index 6d10396347b69d9243ab902ecc68ede93fa17b7d..af219df5267589300f0ad1d30fa5c81a1f50234f 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
@@ -78,6 +78,12 @@ public class CraftBlock implements Block {
return this.world.getBlockState(this.position);
}
+ // Paper start
+ public net.minecraft.world.level.material.FluidState getNMSFluid() {
+ return this.world.getFluidState(this.position);
+ }
+ // Paper end
+
public BlockPos getPosition() {
return this.position;
}
@@ -709,5 +715,23 @@ public class CraftBlock implements Block {
public boolean isValidTool(ItemStack itemStack) {
return getDrops(itemStack).size() != 0;
}
+
+ @Override
+ public void tick() {
+ final ServerLevel level = this.world.getMinecraftWorld();
+ this.getNMS().tick(level, this.position, level.random);
+ }
+
+
+ @Override
+ public void fluidTick() {
+ this.getNMSFluid().tick(this.world.getMinecraftWorld(), this.position);
+ }
+
+ @Override
+ public void randomTick() {
+ final ServerLevel level = this.world.getMinecraftWorld();
+ this.getNMS().randomTick(level, this.position, level.random);
+ }
// Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java
index 33869e725c3b3f2120fa36ca468019a78321e862..64ddd6d1c40dc91b6e7fc3118403415bb4533d97 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java
@@ -752,4 +752,11 @@ public class CraftBlockData implements BlockData {
return speed;
}
// Paper end - destroy speed API
+
+ // Paper start - Block tick API
+ @Override
+ public boolean isRandomlyTicked() {
+ return this.state.isRandomlyTicking();
+ }
+ // Paper end - Block tick API
}

View file

@ -1,242 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Andrew Steinborn <git@steinborn.me>
Date: Mon, 8 Oct 2018 14:36:14 -0400
Subject: [PATCH] Add Velocity IP Forwarding Support
While Velocity supports BungeeCord-style IP forwarding, it is not secure. Users
have a lot of problems setting up firewalls or setting up plugins like IPWhitelist.
Further, the BungeeCord IP forwarding protocol still retains essentially its original
form, when there is brand new support for custom login plugin messages in 1.13.
Velocity's modern IP forwarding uses an HMAC-SHA256 code to ensure authenticity
of messages, is packed into a binary format that is smaller than BungeeCord's
forwarding, and is integrated into the Minecraft login process by using the 1.13
login plugin message packet.
diff --git a/src/main/java/com/destroystokyo/paper/proxy/VelocityProxy.java b/src/main/java/com/destroystokyo/paper/proxy/VelocityProxy.java
new file mode 100644
index 0000000000000000000000000000000000000000..1b797955357612a4319452de7461ba044cbb88d6
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/proxy/VelocityProxy.java
@@ -0,0 +1,86 @@
+package com.destroystokyo.paper.proxy;
+
+import io.papermc.paper.configuration.GlobalConfiguration;
+import com.google.common.net.InetAddresses;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import java.net.InetAddress;
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.UUID;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.protocol.login.custom.CustomQueryPayload;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.entity.player.ProfilePublicKey;
+
+/**
+ * While Velocity supports BungeeCord-style IP forwarding, it is not secure. Users
+ * have a lot of problems setting up firewalls or setting up plugins like IPWhitelist.
+ * Further, the BungeeCord IP forwarding protocol still retains essentially its original
+ * form, when there is brand-new support for custom login plugin messages in 1.13.
+ * <p>
+ * Velocity's modern IP forwarding uses an HMAC-SHA256 code to ensure authenticity
+ * of messages, is packed into a binary format that is smaller than BungeeCord's
+ * forwarding, and is integrated into the Minecraft login process by using the 1.13
+ * login plugin message packet.
+ */
+public class VelocityProxy {
+ private static final int SUPPORTED_FORWARDING_VERSION = 1;
+ public static final int MODERN_FORWARDING_WITH_KEY = 2;
+ public static final int MODERN_FORWARDING_WITH_KEY_V2 = 3;
+ public static final int MODERN_LAZY_SESSION = 4;
+ public static final byte MAX_SUPPORTED_FORWARDING_VERSION = MODERN_LAZY_SESSION;
+ public static final ResourceLocation PLAYER_INFO_CHANNEL = ResourceLocation.fromNamespaceAndPath("velocity", "player_info");
+
+ public static boolean checkIntegrity(final FriendlyByteBuf buf) {
+ final byte[] signature = new byte[32];
+ buf.readBytes(signature);
+
+ final byte[] data = new byte[buf.readableBytes()];
+ buf.getBytes(buf.readerIndex(), data);
+
+ try {
+ final Mac mac = Mac.getInstance("HmacSHA256");
+ mac.init(new SecretKeySpec(GlobalConfiguration.get().proxies.velocity.secret.getBytes(java.nio.charset.StandardCharsets.UTF_8), "HmacSHA256"));
+ final byte[] mySignature = mac.doFinal(data);
+ if (!MessageDigest.isEqual(signature, mySignature)) {
+ return false;
+ }
+ } catch (final InvalidKeyException | NoSuchAlgorithmException e) {
+ throw new AssertionError(e);
+ }
+
+ return true;
+ }
+
+ public static InetAddress readAddress(final FriendlyByteBuf buf) {
+ return InetAddresses.forString(buf.readUtf(Short.MAX_VALUE));
+ }
+
+ public static GameProfile createProfile(final FriendlyByteBuf buf) {
+ final GameProfile profile = new GameProfile(buf.readUUID(), buf.readUtf(16));
+ readProperties(buf, profile);
+ return profile;
+ }
+
+ private static void readProperties(final FriendlyByteBuf buf, final GameProfile profile) {
+ final int properties = buf.readVarInt();
+ for (int i1 = 0; i1 < properties; i1++) {
+ final String name = buf.readUtf(Short.MAX_VALUE);
+ final String value = buf.readUtf(Short.MAX_VALUE);
+ final String signature = buf.readBoolean() ? buf.readUtf(Short.MAX_VALUE) : null;
+ profile.getProperties().put(name, new Property(name, value, signature));
+ }
+ }
+
+ public static ProfilePublicKey.Data readForwardedKey(FriendlyByteBuf buf) {
+ return new ProfilePublicKey.Data(buf);
+ }
+
+ public static UUID readSignerUuidOrElse(FriendlyByteBuf buf, UUID orElse) {
+ return buf.readBoolean() ? buf.readUUID() : orElse;
+ }
+}
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index 585d3e51b4af87327fc2bc64a49f09732a8c61ab..aa39bdb0a4ba8fedf5052ea9700afa7d4d2a4300 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -291,13 +291,20 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.STARTUP);
// CraftBukkit end
+ // Paper start - Add Velocity IP Forwarding Support
+ boolean usingProxy = org.spigotmc.SpigotConfig.bungee || io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled;
+ String proxyFlavor = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "Velocity" : "BungeeCord";
+ String proxyLink = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "https://docs.papermc.io/velocity/security" : "http://www.spigotmc.org/wiki/firewall-guide/";
+ // Paper end - Add Velocity IP Forwarding Support
if (!this.usesAuthentication()) {
DedicatedServer.LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!");
DedicatedServer.LOGGER.warn("The server will make no attempt to authenticate usernames. Beware.");
// Spigot start
- if (org.spigotmc.SpigotConfig.bungee) {
- DedicatedServer.LOGGER.warn("Whilst this makes it possible to use BungeeCord, unless access to your server is properly restricted, it also opens up the ability for hackers to connect with any username they choose.");
- DedicatedServer.LOGGER.warn("Please see http://www.spigotmc.org/wiki/firewall-guide/ for further information.");
+ // Paper start - Add Velocity IP Forwarding Support
+ if (usingProxy) {
+ DedicatedServer.LOGGER.warn("Whilst this makes it possible to use " + proxyFlavor + ", unless access to your server is properly restricted, it also opens up the ability for hackers to connect with any username they choose.");
+ DedicatedServer.LOGGER.warn("Please see " + proxyLink + " for further information.");
+ // Paper end - Add Velocity IP Forwarding Support
} else {
DedicatedServer.LOGGER.warn("While this makes the game possible to play without internet access, it also opens up the ability for hackers to connect with any username they choose.");
}
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
index 9c343b579d9735dc59c8c74fde030d981a673c4f..35faa10f3b82504ae9d3f923fc04c5a99c1a624a 100644
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -91,6 +91,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
private final boolean transferred;
private ServerPlayer player; // CraftBukkit
public boolean iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation = false; // Paper - username validation overriding
+ private int velocityLoginMessageId = -1; // Paper - Add Velocity IP Forwarding Support
public ServerLoginPacketListenerImpl(MinecraftServer server, Connection connection, boolean transferred) {
this.state = ServerLoginPacketListenerImpl.State.HELLO;
@@ -189,6 +190,16 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
this.state = ServerLoginPacketListenerImpl.State.KEY;
this.connection.send(new ClientboundHelloPacket("", this.server.getKeyPair().getPublic().getEncoded(), this.challenge, true));
} else {
+ // Paper start - Add Velocity IP Forwarding Support
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) {
+ this.velocityLoginMessageId = java.util.concurrent.ThreadLocalRandom.current().nextInt();
+ net.minecraft.network.FriendlyByteBuf buf = new net.minecraft.network.FriendlyByteBuf(io.netty.buffer.Unpooled.buffer());
+ buf.writeByte(com.destroystokyo.paper.proxy.VelocityProxy.MAX_SUPPORTED_FORWARDING_VERSION);
+ net.minecraft.network.protocol.login.ClientboundCustomQueryPacket packet1 = new net.minecraft.network.protocol.login.ClientboundCustomQueryPacket(this.velocityLoginMessageId, new net.minecraft.network.protocol.login.ClientboundCustomQueryPacket.PlayerInfoChannelPayload(com.destroystokyo.paper.proxy.VelocityProxy.PLAYER_INFO_CHANNEL, buf));
+ this.connection.send(packet1);
+ return;
+ }
+ // Paper end - Add Velocity IP Forwarding Support
// CraftBukkit start
// Paper start - Cache authenticator threads
authenticatorPool.execute(new Runnable() {
@@ -341,6 +352,12 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
// CraftBukkit start
private GameProfile callPlayerPreLoginEvents(GameProfile gameprofile) throws Exception { // Paper - Add more fields to AsyncPlayerPreLoginEvent
+ // Paper start - Add Velocity IP Forwarding Support
+ if (ServerLoginPacketListenerImpl.this.velocityLoginMessageId == -1 && io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) {
+ disconnect("This server requires you to connect with Velocity.");
+ return gameprofile;
+ }
+ // Paper end - Add Velocity IP Forwarding Support
String playerName = gameprofile.getName();
java.net.InetAddress address = ((java.net.InetSocketAddress) this.connection.getRemoteAddress()).getAddress();
java.util.UUID uniqueId = gameprofile.getId();
@@ -386,6 +403,51 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
@Override
public void handleCustomQueryPacket(ServerboundCustomQueryAnswerPacket packet) {
+ // Paper start - Add Velocity IP Forwarding Support
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled && packet.transactionId() == this.velocityLoginMessageId) {
+ ServerboundCustomQueryAnswerPacket.QueryAnswerPayload payload = (ServerboundCustomQueryAnswerPacket.QueryAnswerPayload)packet.payload();
+ if (payload == null) {
+ this.disconnect("This server requires you to connect with Velocity.");
+ return;
+ }
+
+ net.minecraft.network.FriendlyByteBuf buf = payload.buffer;
+
+ if (!com.destroystokyo.paper.proxy.VelocityProxy.checkIntegrity(buf)) {
+ this.disconnect("Unable to verify player details");
+ return;
+ }
+
+ int version = buf.readVarInt();
+ if (version > com.destroystokyo.paper.proxy.VelocityProxy.MAX_SUPPORTED_FORWARDING_VERSION) {
+ throw new IllegalStateException("Unsupported forwarding version " + version + ", wanted upto " + com.destroystokyo.paper.proxy.VelocityProxy.MAX_SUPPORTED_FORWARDING_VERSION);
+ }
+
+ java.net.SocketAddress listening = this.connection.getRemoteAddress();
+ int port = 0;
+ if (listening instanceof java.net.InetSocketAddress) {
+ port = ((java.net.InetSocketAddress) listening).getPort();
+ }
+ this.connection.address = new java.net.InetSocketAddress(com.destroystokyo.paper.proxy.VelocityProxy.readAddress(buf), port);
+
+ this.authenticatedProfile = com.destroystokyo.paper.proxy.VelocityProxy.createProfile(buf);
+
+ //TODO Update handling for lazy sessions, might not even have to do anything?
+
+ // Proceed with login
+ authenticatorPool.execute(() -> {
+ try {
+ final GameProfile gameprofile = this.callPlayerPreLoginEvents(this.authenticatedProfile);
+ ServerLoginPacketListenerImpl.LOGGER.info("UUID of player {} is {}", gameprofile.getName(), gameprofile.getId());
+ ServerLoginPacketListenerImpl.this.startClientVerification(gameprofile);
+ } catch (Exception ex) {
+ disconnect("Failed to verify username!");
+ server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + this.authenticatedProfile.getName(), ex);
+ }
+ });
+ return;
+ }
+ // Paper end - Add Velocity IP Forwarding Support
this.disconnect(ServerCommonPacketListenerImpl.DISCONNECT_UNEXPECTED_QUERY);
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 3c5d44499e94bd19e4058eb2bf2d9b5d5890f980..96e7bad6620ff6dc17a80af3febcbc4e1623944e 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -846,7 +846,7 @@ public final class CraftServer implements Server {
@Override
public long getConnectionThrottle() {
// Spigot Start - Automatically set connection throttle for bungee configurations
- if (org.spigotmc.SpigotConfig.bungee) {
+ if (org.spigotmc.SpigotConfig.bungee || io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) { // Paper - Add Velocity IP Forwarding Support
return -1;
} else {
return this.configuration.getInt("settings.connection-throttle");

View file

@ -1,33 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Josh Roy <10731363+JRoy@users.noreply.github.com>
Date: Sun, 14 Aug 2022 12:23:11 -0400
Subject: [PATCH] Add NamespacedKey biome methods
Co-authored-by: Thonk <30448663+ExcessiveAmountsOfZombies@users.noreply.github.com>
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
index c10273445c4b5ef089f86fc08a944da69d708244..72c2f70d22c5ac920f13b11badac404dbb15c055 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@@ -584,6 +584,21 @@ public final class CraftMagicNumbers implements UnsafeValues {
}
// Paper end
+ // Paper start - namespaced key biome methods
+ @Override
+ public org.bukkit.NamespacedKey getBiomeKey(org.bukkit.RegionAccessor accessor, int x, int y, int z) {
+ org.bukkit.craftbukkit.CraftRegionAccessor cra = (org.bukkit.craftbukkit.CraftRegionAccessor) accessor;
+ return org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(cra.getHandle().registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.BIOME).getKey(cra.getHandle().getBiome(new net.minecraft.core.BlockPos(x, y, z)).value()));
+ }
+
+ @Override
+ public void setBiomeKey(org.bukkit.RegionAccessor accessor, int x, int y, int z, org.bukkit.NamespacedKey biomeKey) {
+ org.bukkit.craftbukkit.CraftRegionAccessor cra = (org.bukkit.craftbukkit.CraftRegionAccessor) accessor;
+ net.minecraft.core.Holder<net.minecraft.world.level.biome.Biome> biomeBase = cra.getHandle().registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.BIOME).getHolderOrThrow(net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.BIOME, org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(biomeKey)));
+ cra.setBiome(x, y, z, biomeBase);
+ }
+ // Paper end - namespaced key biome methods
+
@Override
public String get(Class<?> aClass, String s) {
if (aClass == Enchantment.class) {