More more more more more more more more more patches

This commit is contained in:
Nassim Jahnke 2022-06-08 14:33:46 +02:00
parent 391e65f1af
commit 301cf577c2
No known key found for this signature in database
GPG key ID: 6BE3B555EBC5982B
36 changed files with 168 additions and 168 deletions

View file

@ -1,53 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Mon, 23 Aug 2021 04:50:05 -0700
Subject: [PATCH] Always parse protochunk light sources unless it is marked as
non-lit
Chunks not marked as lit will always go through the light engine,
so they should always have their block sources parsed.
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
index 54ade15cdab222e9818f2635a8a12418e78e1ce6..887b3bc6370d23d2ff38e8fdbe286d678b035cc7 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
@@ -312,16 +312,33 @@ public class ChunkSerializer {
BelowZeroRetrogen belowzeroretrogen = protochunk.getBelowZeroRetrogen();
boolean flag2 = chunkstatus.isOrAfter(ChunkStatus.LIGHT) || belowzeroretrogen != null && belowzeroretrogen.targetStatus().isOrAfter(ChunkStatus.LIGHT);
- if (!flag && flag2) {
- Iterator iterator = BlockPos.betweenClosed(chunkPos.getMinBlockX(), world.getMinBuildHeight(), chunkPos.getMinBlockZ(), chunkPos.getMaxBlockX(), world.getMaxBuildHeight() - 1, chunkPos.getMaxBlockZ()).iterator();
+ if (!flag) { // Paper - fix incorrect parsing of blocks that emit light - it should always parse it, unless the chunk is marked as lit
+ // Paper start - let's make sure the implementation isn't as slow as possible
+ int offX = chunkPos.x << 4;
+ int offZ = chunkPos.z << 4;
+
+ int minChunkSection = io.papermc.paper.util.WorldUtil.getMinSection(world);
+ int maxChunkSection = io.papermc.paper.util.WorldUtil.getMaxSection(world);
+
+ LevelChunkSection[] sections = achunksection;
+ for (int sectionY = minChunkSection; sectionY <= maxChunkSection; ++sectionY) {
+ LevelChunkSection section = sections[sectionY - minChunkSection];
+ if (section == null || section.hasOnlyAir()) {
+ // no sources in empty sections
+ continue;
+ }
+ int offY = sectionY << 4;
- while (iterator.hasNext()) {
- BlockPos blockposition = (BlockPos) iterator.next();
+ for (int index = 0; index < (16 * 16 * 16); ++index) {
+ if (section.states.get(index).getLightEmission() <= 0) {
+ continue;
+ }
- if (((ChunkAccess) object).getBlockState(blockposition).getLightEmission() != 0) {
- protochunk.addLight(blockposition);
+ // index = x | (z << 4) | (y << 8)
+ protochunk.addLight(new BlockPos(offX | (index & 15), offY | (index >>> 8), offZ | ((index >>> 4) & 15)));
}
}
+ // Paper end
}
}

View file

@ -1,49 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake <jake.m.potrebic@gmail.com>
Date: Tue, 30 Nov 2021 12:01:56 -0800
Subject: [PATCH] Fix removing recipes from RecipeIterator
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java b/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java
index 24f336c89b548c5ba2a95372db0d7c83b5c4ec47..91895c639c33a1cafd2a35bab7b5fd83e558468d 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java
@@ -11,6 +11,7 @@ import org.bukkit.inventory.Recipe;
public class RecipeIterator implements Iterator<Recipe> {
private final Iterator<Map.Entry<RecipeType<?>, Object2ObjectLinkedOpenHashMap<ResourceLocation, net.minecraft.world.item.crafting.Recipe<?>>>> recipes;
private Iterator<net.minecraft.world.item.crafting.Recipe<?>> current;
+ private Recipe currentRecipe; // Paper - fix removing recipes
public RecipeIterator() {
this.recipes = MinecraftServer.getServer().getRecipeManager().recipes.entrySet().iterator();
@@ -34,10 +35,16 @@ public class RecipeIterator implements Iterator<Recipe> {
public Recipe next() {
if (this.current == null || !this.current.hasNext()) {
this.current = this.recipes.next().getValue().values().iterator();
- return this.next();
+ // Paper start - fix removing recipes
+ this.currentRecipe = this.next();
+ return this.currentRecipe;
+ // Paper end
}
- return this.current.next().toBukkitRecipe();
+ // Paper start - fix removing recipes
+ this.currentRecipe = this.current.next().toBukkitRecipe();
+ return this.currentRecipe;
+ // Paper end
}
@Override
@@ -46,6 +53,11 @@ public class RecipeIterator implements Iterator<Recipe> {
throw new IllegalStateException("next() not yet called");
}
+ // Paper start - fix removing recipes
+ if (this.currentRecipe instanceof org.bukkit.Keyed keyed) {
+ MinecraftServer.getServer().getRecipeManager().byName.remove(org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(keyed.getKey()));
+ }
+ // Paper end
this.current.remove();
}
}

View file

@ -1,86 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <jahnke.nassim@gmail.com>
Date: Wed, 1 Dec 2021 12:36:25 +0100
Subject: [PATCH] Prevent sending oversized item data in equipment and metadata
diff --git a/src/main/java/net/minecraft/network/syncher/EntityDataSerializers.java b/src/main/java/net/minecraft/network/syncher/EntityDataSerializers.java
index 3eb6bf4258b1de4697f96c2011df493cf7414a0c..bbf4e6b0ca0fe046469c675fc9e0929b64006548 100644
--- a/src/main/java/net/minecraft/network/syncher/EntityDataSerializers.java
+++ b/src/main/java/net/minecraft/network/syncher/EntityDataSerializers.java
@@ -127,7 +127,7 @@ public class EntityDataSerializers {
public static final EntityDataSerializer<ItemStack> ITEM_STACK = new EntityDataSerializer<ItemStack>() {
@Override
public void write(FriendlyByteBuf buf, ItemStack value) {
- buf.writeItem(value);
+ buf.writeItem(net.minecraft.world.entity.LivingEntity.sanitizeItemStack(value, false)); // Paper - prevent oversized data
}
@Override
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
index 9760ff4b6ca0e555f01151968cbfe0cdb8960e35..7464336f0c7ee59e59552afbad7bed0afcecef87 100644
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
@@ -319,7 +319,10 @@ public class ServerEntity {
ItemStack itemstack = ((LivingEntity) this.entity).getItemBySlot(enumitemslot);
if (!itemstack.isEmpty()) {
- list.add(Pair.of(enumitemslot, itemstack.copy()));
+ // Paper start - prevent oversized data
+ final ItemStack sanitized = LivingEntity.sanitizeItemStack(itemstack.copy(), false);
+ list.add(Pair.of(enumitemslot, sanitized));
+ // Paper end
}
}
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 18dfc235f17510ae9eda3ffd7c04b7aa8c4aac89..1f8ba8dbb69bf9be998ed99095ecdeacba5ab03d 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3077,7 +3077,10 @@ public abstract class LivingEntity extends Entity {
equipmentChanges.forEach((enumitemslot, itemstack) -> {
ItemStack itemstack1 = itemstack.copy();
- list.add(Pair.of(enumitemslot, itemstack1));
+ // Paper start - prevent oversized data
+ ItemStack toSend = sanitizeItemStack(itemstack1, true);
+ list.add(Pair.of(enumitemslot, toSend));
+ // Paper end
switch (enumitemslot.getType()) {
case HAND:
this.setLastHandItem(enumitemslot, itemstack1);
@@ -3090,6 +3093,34 @@ public abstract class LivingEntity extends Entity {
((ServerLevel) this.level).getChunkSource().broadcast(this, new ClientboundSetEquipmentPacket(this.getId(), list));
}
+ // Paper start - prevent oversized data
+ public static ItemStack sanitizeItemStack(final ItemStack itemStack, final boolean copyItemStack) {
+ if (itemStack.isEmpty() || !itemStack.hasTag()) {
+ return itemStack;
+ }
+
+ final ItemStack copy = copyItemStack ? itemStack.copy() : itemStack;
+ final CompoundTag tag = copy.getTag();
+ if (copy.is(Items.BUNDLE) && tag.get("Items") instanceof ListTag oldItems && !oldItems.isEmpty()) {
+ // Bundles change their texture based on their fullness.
+ org.bukkit.inventory.meta.BundleMeta bundleMeta = (org.bukkit.inventory.meta.BundleMeta) copy.asBukkitMirror().getItemMeta();
+ int sizeUsed = 0;
+ for (org.bukkit.inventory.ItemStack item : bundleMeta.getItems()) {
+ int scale = 64 / item.getMaxStackSize();
+ sizeUsed += scale * item.getAmount();
+ }
+ // Now we add a single fake item that uses the same amount of slots as all other items.
+ ListTag items = new ListTag();
+ items.add(new ItemStack(Items.PAPER, sizeUsed).save(new CompoundTag()));
+ tag.put("Items", items);
+ }
+ if (tag.get("BlockEntityTag") instanceof CompoundTag blockEntityTag) {
+ blockEntityTag.remove("Items");
+ }
+ return copy;
+ }
+ // Paper end
+
private ItemStack getLastArmorItem(EquipmentSlot slot) {
return (ItemStack) this.lastArmorItemStacks.get(slot.getIndex());
}

View file

@ -1,110 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Noah van der Aa <ndvdaa@gmail.com>
Date: Tue, 3 Aug 2021 17:28:27 +0200
Subject: [PATCH] Hide unnecessary itemmeta from clients
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 409cffcf74b32beba09b2fe800d1329ee64426f8..99008ac6943c56f74f912e739709a4724da322ef 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -985,6 +985,13 @@ public class PaperWorldConfig {
behaviorTickRates = loadTickRates("behavior");
}
+ public boolean hideItemmetaFromClients = false;
+ public boolean hideDurabilityFromClients = false;
+ private void getHideItemmetaFromClients() {
+ hideItemmetaFromClients = getBoolean("anticheat.obfuscation.items.hide-itemmeta", hideItemmetaFromClients);
+ hideDurabilityFromClients = getBoolean("anticheat.obfuscation.items.hide-durability", hideDurabilityFromClients);
+ }
+
private com.google.common.collect.Table<String, String, Integer> loadTickRates(String type) {
log(" " + type + ":");
com.google.common.collect.Table<String, String, Integer> table = com.google.common.collect.HashBasedTable.create();
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
index 7464336f0c7ee59e59552afbad7bed0afcecef87..fe29bf349b987d633b185b9d44d221053fa2cc83 100644
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
@@ -321,7 +321,7 @@ public class ServerEntity {
if (!itemstack.isEmpty()) {
// Paper start - prevent oversized data
final ItemStack sanitized = LivingEntity.sanitizeItemStack(itemstack.copy(), false);
- list.add(Pair.of(enumitemslot, sanitized));
+ list.add(Pair.of(enumitemslot, ((LivingEntity) this.entity).stripMeta(sanitized, false))); // Paper - remove unnecessary item meta
// Paper end
}
}
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 1f8ba8dbb69bf9be998ed99095ecdeacba5ab03d..5ef73cf97df2949d308d4cc9213bfb173c15b4a5 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3079,7 +3079,7 @@ public abstract class LivingEntity extends Entity {
// Paper start - prevent oversized data
ItemStack toSend = sanitizeItemStack(itemstack1, true);
- list.add(Pair.of(enumitemslot, toSend));
+ list.add(Pair.of(enumitemslot, stripMeta(toSend, toSend == itemstack1))); // Paper - hide unnecessary item meta
// Paper end
switch (enumitemslot.getType()) {
case HAND:
@@ -3093,6 +3093,59 @@ public abstract class LivingEntity extends Entity {
((ServerLevel) this.level).getChunkSource().broadcast(this, new ClientboundSetEquipmentPacket(this.getId(), list));
}
+ // Paper start - hide unnecessary item meta
+ public ItemStack stripMeta(final ItemStack itemStack, final boolean copyItemStack) {
+ if (itemStack.isEmpty() || (!itemStack.hasTag() && itemStack.getCount() < 2)) {
+ return itemStack;
+ }
+
+ final ItemStack copy = copyItemStack ? itemStack.copy() : itemStack;
+ if (level.paperConfig.hideDurabilityFromClients) {
+ // Only show damage values for elytra's, since they show a different texture when broken.
+ if (!copy.is(Items.ELYTRA) || copy.getDamageValue() < copy.getMaxDamage() - 1) {
+ copy.setDamageValue(0);
+ }
+ }
+
+ if (level.paperConfig.hideItemmetaFromClients) {
+ // Some resource packs show different textures when there is more than one item. Since this shouldn't provide a big advantage,
+ // we'll tell the client if there's one or (more than) two items.
+ copy.setCount(copy.getCount() > 1 ? 2 : 1);
+ // We can't just strip out display, leather helmets still use the display.color tag.
+ final CompoundTag tag = copy.getTag();
+ if (tag != null) {
+ if (tag.get("display") instanceof CompoundTag displayTag) {
+ displayTag.remove("Lore");
+ displayTag.remove("Name");
+ }
+
+ if (tag.get("Enchantments") instanceof ListTag enchantmentsTag && !enchantmentsTag.isEmpty()) {
+ // The client still renders items with the enchantment glow if the enchantments tag contains at least one (empty) child.
+ ListTag enchantments = new ListTag();
+ CompoundTag fakeEnchantment = new CompoundTag();
+ // Soul speed boots generate client side particles.
+ if (EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SOUL_SPEED, itemStack) > 0) {
+ fakeEnchantment.putString("id", org.bukkit.enchantments.Enchantment.SOUL_SPEED.getKey().asString());
+ fakeEnchantment.putInt("lvl", 1);
+ }
+ enchantments.add(fakeEnchantment);
+ tag.put("Enchantments", enchantments);
+ }
+ tag.remove("AttributeModifiers");
+
+ // Books
+ tag.remove("author");
+ tag.remove("filtered_title");
+ tag.remove("pages");
+ tag.remove("filtered_pages");
+ tag.remove("title");
+ tag.remove("generation");
+ }
+ }
+ return copy;
+ }
+ // Paper end
+
// Paper start - prevent oversized data
public static ItemStack sanitizeItemStack(final ItemStack itemStack, final boolean copyItemStack) {
if (itemStack.isEmpty() || !itemStack.hasTag()) {

View file

@ -1,108 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Fri, 3 Dec 2021 17:09:24 -0800
Subject: [PATCH] Fix kelp modifier changing growth for other crops
Also add growth modifiers for twisting vines, weeping vines, cave vines,
and glow berries
Also fix above-mentioned modifiers from having the reverse effect
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
diff --git a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java
index 87dabe3c80b48bff52f2e3dbbaceb37a1a21e431..effee89e308c9a663938ac5b00a8c6512ce407c2 100644
--- a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java
@@ -47,9 +47,17 @@ public class CaveVinesBlock extends GrowingPlantHeadBlock implements Bonemealabl
@Override
protected BlockState getGrowIntoState(BlockState state, Random random) {
- return (BlockState) super.getGrowIntoState(state, random).setValue(CaveVinesBlock.BERRIES, random.nextFloat() < 0.11F);
+ // Paper start
+ return this.getGrowIntoState(state, random, null);
}
+ @Override
+ protected BlockState getGrowIntoState(BlockState state, Random random, Level level) {
+ final boolean value = (level == null ? random.nextFloat() : random.nextFloat(100.00F / level.spigotConfig.glowBerryModifier)) < 0.11F;
+ return super.getGrowIntoState(state, random).setValue(CaveVinesBlock.BERRIES, value);
+ }
+ // Paper end
+
@Override
public ItemStack getCloneItemStack(BlockGetter world, BlockPos pos, BlockState state) {
return new ItemStack(Items.GLOW_BERRIES);
diff --git a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
index def3b62feada5cebae4049883fa967b12f6f32b4..8e642ff6d387e05f900acfc3cf6cfa5975bf69e4 100644
--- a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
@@ -40,16 +40,36 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements
@Override
public void randomTick(BlockState state, ServerLevel world, BlockPos pos, Random random) {
- if ((Integer) state.getValue(GrowingPlantHeadBlock.AGE) < 25 && random.nextDouble() < (100.0D / world.spigotConfig.kelpModifier) * this.growPerTickProbability) { // Spigot
+ // Paper start
+ final int modifier;
+ if (state.is(Blocks.TWISTING_VINES) || state.is(Blocks.TWISTING_VINES_PLANT)) {
+ modifier = world.spigotConfig.twistingVinesModifier;
+ } else if (state.is(Blocks.WEEPING_VINES) || state.is(Blocks.WEEPING_VINES_PLANT)) {
+ modifier = world.spigotConfig.weepingVinesModifier;
+ } else if (state.is(Blocks.CAVE_VINES) || state.is(Blocks.CAVE_VINES_PLANT)) {
+ modifier = world.spigotConfig.caveVinesModifier;
+ } else if (state.is(Blocks.KELP) || state.is(Blocks.KELP_PLANT)) {
+ modifier = world.spigotConfig.kelpModifier;
+ } else {
+ modifier = 100; // Above cases are exhaustive as of 1.18
+ }
+ if ((Integer) state.getValue(GrowingPlantHeadBlock.AGE) < 25 && random.nextDouble() < (modifier / 100.0D) * this.growPerTickProbability) { // Spigot // Paper - fix growth modifier having the reverse effect
+ // Paper end
BlockPos blockposition1 = pos.relative(this.growthDirection);
if (this.canGrowInto(world.getBlockState(blockposition1))) {
- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, this.getGrowIntoState(state, world.random)); // CraftBukkit
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, this.getGrowIntoState(state, world.random, world)); // CraftBukkit // Paper
}
}
}
+ // Paper start
+ protected BlockState getGrowIntoState(BlockState state, Random random, Level level) {
+ return this.getGrowIntoState(state, random);
+ }
+ // Paper end
+
protected BlockState getGrowIntoState(BlockState state, Random random) {
return (BlockState) state.cycle(GrowingPlantHeadBlock.AGE);
}
diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java
index 32f8a6aed0f69ad07ab5b42fee38a3471a59d426..b498b027b127996976a394e9a86cfc90f8a8ed3b 100644
--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
@@ -103,6 +103,12 @@ public class SpigotWorldConfig
public int bambooModifier;
public int sweetBerryModifier;
public int kelpModifier;
+ // Paper start
+ public int twistingVinesModifier;
+ public int weepingVinesModifier;
+ public int caveVinesModifier;
+ public int glowBerryModifier;
+ // Paper end
private int getAndValidateGrowth(String crop)
{
int modifier = this.getInt( "growth." + crop.toLowerCase(java.util.Locale.ENGLISH) + "-modifier", 100 );
@@ -133,6 +139,12 @@ public class SpigotWorldConfig
this.bambooModifier = this.getAndValidateGrowth( "Bamboo" );
this.sweetBerryModifier = this.getAndValidateGrowth( "SweetBerry" );
this.kelpModifier = this.getAndValidateGrowth( "Kelp" );
+ // Paper start
+ this.twistingVinesModifier = this.getAndValidateGrowth("TwistingVines");
+ this.weepingVinesModifier = this.getAndValidateGrowth("WeepingVines");
+ this.caveVinesModifier = this.getAndValidateGrowth("CaveVines");
+ this.glowBerryModifier = this.getAndValidateGrowth("GlowBerry");
+ // Paper end
}
public double itemMerge;

View file

@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Tue, 30 Nov 2021 05:30:35 +0000
Subject: [PATCH] Prevent ContainerOpenersCounter openCount from going negative
diff --git a/src/main/java/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java b/src/main/java/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java
index 5dceda79d13412a73002af39511c9268c47788ea..55c5dfc51196ff04abeb8b0eb82a399dd8a90e1c 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java
@@ -50,6 +50,7 @@ public abstract class ContainerOpenersCounter {
public void decrementOpeners(Player player, Level world, BlockPos pos, BlockState state) {
int oldPower = Math.max(0, Math.min(15, this.openCount)); // CraftBukkit - Get power before new viewer is added
+ if (this.openCount == 0) return; // Paper
int i = this.openCount--;
// CraftBukkit start - Call redstone event

View file

@ -1,57 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: SamB440 <sam@islandearth.net>
Date: Mon, 15 Nov 2021 18:10:10 +0000
Subject: [PATCH] Add PlayerItemFrameChangeEvent
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
index d02f507ac58bae5d4f669dae52cc01c35651cee5..a6d94e99d18cd569545981014af733ba8fdb4d31 100644
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
@@ -2,6 +2,7 @@ package net.minecraft.world.entity.decoration;
import com.mojang.logging.LogUtils;
import javax.annotation.Nullable;
+import io.papermc.paper.event.player.PlayerItemFrameChangeEvent; // Paper
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
@@ -185,6 +186,13 @@ public class ItemFrame extends HangingEntity {
return true;
}
// CraftBukkit end
+ // Paper start - call PlayerItemFrameChangeEvent
+ if (source.getEntity() instanceof Player player) {
+ var event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), this.getItem().asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.REMOVE);
+ if (!event.callEvent()) return true; // return true here because you aren't cancelling the damage, just the change
+ this.setItem(ItemStack.fromBukkitCopy(event.getItemStack()), false);
+ }
+ // Paper end
this.dropItem(source.getEntity(), false);
this.playSound(this.getRemoveItemSound(), 1.0F, 1.0F);
}
@@ -427,13 +435,22 @@ public class ItemFrame extends HangingEntity {
return InteractionResult.FAIL;
}
}
-
- this.setItem(itemstack);
+ // Paper start - call PlayerItemFrameChangeEvent
+ var event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), itemstack.asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.PLACE);
+ if (!event.callEvent()) return InteractionResult.FAIL;
+ this.setItem(ItemStack.fromBukkitCopy(event.getItemStack()));
+ // this.setItem(itemstack);
+ // Paper end
if (!player.getAbilities().instabuild) {
itemstack.shrink(1);
}
}
} else {
+ // Paper start - call PlayerItemFrameChangeEvent
+ var event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), this.getItem().asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.ROTATE);
+ if (!event.callEvent()) return InteractionResult.FAIL;
+ setItem(ItemStack.fromBukkitCopy(event.getItemStack()), false, false);
+ // Paper end
this.playSound(this.getRotateItemSound(), 1.0F, 1.0F);
this.setRotation(this.getRotation() + 1);
}

View file

@ -1,39 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: SamB440 <sam@islandearth.net>
Date: Wed, 17 Nov 2021 12:31:42 +0000
Subject: [PATCH] Add player health update API
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 818e9f36f5e19bd160cf7ee0805f6337a418bce5..0978be96a4ef26dc0a2e3cc1bb10931496502413 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -2136,9 +2136,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
this.getHandle().maxHealthCache = getMaxHealth();
}
- public void sendHealthUpdate() {
+ // Paper start
+ @Override
+ public void sendHealthUpdate(final double health, final int foodLevel, final float saturationLevel) {
// Paper start - cancellable death event
- ClientboundSetHealthPacket packet = new ClientboundSetHealthPacket(this.getScaledHealth(), this.getHandle().getFoodData().getFoodLevel(), this.getHandle().getFoodData().getSaturationLevel());
+ ClientboundSetHealthPacket packet = new ClientboundSetHealthPacket((float) health, foodLevel, saturationLevel);
if (this.getHandle().queueHealthUpdatePacket) {
this.getHandle().queuedHealthUpdatePacket = packet;
} else {
@@ -2146,7 +2148,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
}
// Paper end
}
-
+
+ @Override
+ public void sendHealthUpdate() {
+ this.sendHealthUpdate(this.getScaledHealth(), this.getHandle().getFoodData().getFoodLevel(), this.getHandle().getFoodData().getSaturationLevel());
+ }
+ // Paper end
+
public void injectScaledMaxHealth(Collection<AttributeInstance> collection, boolean force) {
if (!this.scaledHealth && !force) {
return;

View file

@ -1,57 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: stonar96 <minecraft.stonar96@gmail.com>
Date: Sun, 17 Jan 2021 01:11:36 +0100
Subject: [PATCH] Optimize HashMapPalette
HashMapPalette uses an instance of CrudeIncrementalIntIdentityHashBiMap
internally. A Palette has a preset maximum size = 1 << bits.
CrudeIncrementalIntIdentityHashBiMap has an initial size but is
automatically resized. The CrudeIncrementalIntIdentityHashBiMap is created
with the maximum size in the constructor of HashMapPalette, with the aim
that it doesn't need to be resized anymore. However, there are two things
that I think Mojang hasn't considered here:
1) The CrudeIncrementalIntIdentityHashBiMap is resized, when its initial
size is reached and not the next time, when a further object is added.
2) HashMapPalette adds objects (unnecessarily) before checking if the
initial size of CrudeIncrementalIntIdentityHashBiMap is reached.
This means to actually avoid resize operations in
CrudeIncrementalIntIdentityHashBiMap, one has to add 2 to the initial size
or add 1 and check the size before adding objects. This commit implements
the second approach. Note that this isn't only an optimization but also
makes async reads of Palettes fail-safe. An async read while the
CrudeIncrementalIntIdentityHashBiMap is resized is fatal and can even lead
to corrupted data. This is also something that Anti-Xray is currently
relying on.
diff --git a/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java b/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java
index c5551c31597f5a7fe62ade325e36425e5f2df0b9..ba9b0f419b0785a0b1e3bc57f18bfe5edaa192bd 100644
--- a/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java
+++ b/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java
@@ -19,7 +19,7 @@ public class HashMapPalette<T> implements Palette<T> {
}
public HashMapPalette(IdMap<T> idList, int indexBits, PaletteResize<T> listener) {
- this(idList, indexBits, listener, CrudeIncrementalIntIdentityHashBiMap.create(1 << indexBits));
+ this(idList, indexBits, listener, CrudeIncrementalIntIdentityHashBiMap.create((1 << indexBits) + 1)); // Paper - Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap
}
private HashMapPalette(IdMap<T> idMap, int i, PaletteResize<T> paletteResize, CrudeIncrementalIntIdentityHashBiMap<T> crudeIncrementalIntIdentityHashBiMap) {
@@ -37,10 +37,16 @@ public class HashMapPalette<T> implements Palette<T> {
public int idFor(T object) {
int i = this.values.getId(object);
if (i == -1) {
- i = this.values.add(object);
- if (i >= 1 << this.bits) {
+ // Paper start - Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap and optimize
+ // We use size() instead of the result from add(K)
+ // This avoids adding another object unnecessarily
+ // Without this change, + 2 would be required in the constructor
+ if (this.values.size() >= 1 << this.bits) {
i = this.resizeHandler.onResize(this.bits + 1, object);
+ } else {
+ i = this.values.add(object);
}
+ // Paper end
}
return i;

View file

@ -1,129 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MiniDigger <admin@benndorf.dev>
Date: Wed, 29 Apr 2020 02:10:32 +0200
Subject: [PATCH] Allow delegation to vanilla chunk gen
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 83bbe0e65760a7f380e19da5a3938b1a30e5d679..8769e15a395b1c6e72f3e4a7f96b8c90c34e7569 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2317,6 +2317,90 @@ public final class CraftServer implements Server {
return new OldCraftChunkData(world.getMinHeight(), world.getMaxHeight(), handle.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), world); // Paper - Anti-Xray - Add parameters
}
+ // Paper start
+ private static final List<net.minecraft.world.level.chunk.ChunkStatus> VANILLA_GEN_STATUSES = List.of(
+ net.minecraft.world.level.chunk.ChunkStatus.EMPTY,
+ net.minecraft.world.level.chunk.ChunkStatus.STRUCTURE_STARTS,
+ net.minecraft.world.level.chunk.ChunkStatus.STRUCTURE_REFERENCES,
+ net.minecraft.world.level.chunk.ChunkStatus.BIOMES,
+ net.minecraft.world.level.chunk.ChunkStatus.NOISE,
+ net.minecraft.world.level.chunk.ChunkStatus.SURFACE,
+ net.minecraft.world.level.chunk.ChunkStatus.CARVERS,
+ net.minecraft.world.level.chunk.ChunkStatus.LIQUID_CARVERS,
+ net.minecraft.world.level.chunk.ChunkStatus.FEATURES,
+ net.minecraft.world.level.chunk.ChunkStatus.LIGHT
+ );
+
+ @Override
+ @Deprecated(forRemoval = true)
+ public ChunkGenerator.ChunkData createVanillaChunkData(World world, int x, int z) {
+ // do bunch of vanilla shit
+ final net.minecraft.server.level.ServerLevel serverLevel = ((CraftWorld) world).getHandle();
+ final Registry<net.minecraft.world.level.biome.Biome> biomeRegistry = serverLevel.getServer().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
+ final net.minecraft.world.level.chunk.ProtoChunk protoChunk = new net.minecraft.world.level.chunk.ProtoChunk(
+ new net.minecraft.world.level.ChunkPos(x, z),
+ net.minecraft.world.level.chunk.UpgradeData.EMPTY,
+ serverLevel,
+ biomeRegistry,
+ null
+ );
+
+ final net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator;
+ if (serverLevel.chunkSource.getGenerator() instanceof org.bukkit.craftbukkit.generator.CustomChunkGenerator bukkit) {
+ chunkGenerator = bukkit.delegate;
+ } else {
+ chunkGenerator = serverLevel.chunkSource.getGenerator();
+ }
+
+ final net.minecraft.world.level.ChunkPos chunkPos = new net.minecraft.world.level.ChunkPos(x, z);
+ final net.minecraft.util.thread.ProcessorMailbox<Runnable> mailbox = net.minecraft.util.thread.ProcessorMailbox.create(
+ net.minecraft.Util.backgroundExecutor(),
+ "CraftServer#createVanillaChunkData(worldName='" + world.getName() + "', x='" + x + "', z='" + z + "')"
+ );
+ for (final net.minecraft.world.level.chunk.ChunkStatus chunkStatus : VANILLA_GEN_STATUSES) {
+ final List<net.minecraft.world.level.chunk.ChunkAccess> chunks = Lists.newArrayList();
+ final int statusRange = Math.max(1, chunkStatus.getRange());
+
+ for (int zz = chunkPos.z - statusRange; zz <= chunkPos.z + statusRange; ++zz) {
+ for (int xx = chunkPos.x - statusRange; xx <= chunkPos.x + statusRange; ++xx) {
+ if (xx == chunkPos.x && zz == chunkPos.z) {
+ chunks.add(protoChunk);
+ } else {
+ final Holder<net.minecraft.world.level.biome.Biome> biomeHolder = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY).getHolderOrThrow(net.minecraft.world.level.biome.Biomes.PLAINS);
+ final net.minecraft.world.level.chunk.ChunkAccess chunk = new net.minecraft.world.level.chunk.EmptyLevelChunk(serverLevel, new net.minecraft.world.level.ChunkPos(xx, zz), biomeHolder);
+ chunks.add(chunk);
+ }
+ }
+ }
+
+ chunkStatus.generate(
+ mailbox::tell,
+ serverLevel,
+ chunkGenerator,
+ serverLevel.getStructureManager(),
+ serverLevel.chunkSource.getLightEngine(),
+ chunk -> {
+ throw new UnsupportedOperationException("Not creating full chunks here");
+ },
+ chunks,
+ true
+ ).thenAccept(either -> {
+ if (chunkStatus == net.minecraft.world.level.chunk.ChunkStatus.NOISE) {
+ either.left().ifPresent(chunk -> net.minecraft.world.level.levelgen.Heightmap.primeHeightmaps(chunk, net.minecraft.world.level.chunk.ChunkStatus.POST_FEATURES));
+ }
+ }).join();
+ }
+
+ // get empty object
+ OldCraftChunkData data = (OldCraftChunkData) this.createChunkData(world);
+ // copy over generated sections
+ data.getLights().addAll(protoChunk.getLights().toList());
+ data.setRawChunkData(protoChunk.getSections());
+ // hooray!
+ return data;
+ }
+ // Paper end
+
@Override
public BossBar createBossBar(String title, BarColor color, BarStyle style, BarFlag... flags) {
return new CraftBossBar(title, color, style, flags);
diff --git a/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java b/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java
index 6f6bf950cd15b34031618782c82824cf0b191ff8..8d8c7d84a76b11e14ee252e93349d495eec77957 100644
--- a/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java
+++ b/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java
@@ -23,7 +23,7 @@ import org.bukkit.material.MaterialData;
public final class OldCraftChunkData implements ChunkGenerator.ChunkData {
private final int minHeight;
private final int maxHeight;
- private final LevelChunkSection[] sections;
+ private LevelChunkSection[] sections; // Paper
private final Registry<net.minecraft.world.level.biome.Biome> biomes;
private Set<BlockPos> tiles;
private final Set<BlockPos> lights = new HashSet<>();
@@ -194,7 +194,13 @@ public final class OldCraftChunkData implements ChunkGenerator.ChunkData {
return this.tiles;
}
- Set<BlockPos> getLights() {
+ public Set<BlockPos> getLights() { // Paper
return this.lights;
}
+
+ // Paper start
+ public void setRawChunkData(LevelChunkSection[] sections) {
+ this.sections = sections;
+ }
+ // Paper end
}

View file

@ -1,170 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <spottedleaf@spottedleaf.dev>
Date: Thu, 2 Jul 2020 12:02:43 -0700
Subject: [PATCH] Optimise collision checking in player move packet handling
Move collision logic to just the hasNewCollision call instead of getCubes + hasNewCollision
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 6d1e3104750b23e9d4b0ddea35e1241f8434a1ac..1a15711e657c93965c2839dc130b7c53d86482b0 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -587,7 +587,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
return;
}
- boolean flag = worldserver.noCollision(entity, entity.getBoundingBox().deflate(0.0625D));
+ AABB oldBox = entity.getBoundingBox(); // Paper - copy from player movement packet
d6 = d3 - this.vehicleLastGoodX; // Paper - diff on change, used for checking large move vectors above
d7 = d4 - this.vehicleLastGoodY - 1.0E-6D; // Paper - diff on change, used for checking large move vectors above
@@ -595,6 +595,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
boolean flag1 = entity.verticalCollisionBelow;
entity.move(MoverType.PLAYER, new Vec3(d6, d7, d8));
+ boolean didCollide = toX != entity.getX() || toY != entity.getY() || toZ != entity.getZ(); // Paper - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be...
double d11 = d7;
d6 = d3 - entity.getX();
@@ -608,16 +609,24 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
boolean flag2 = false;
if (d10 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot
- flag2 = true;
+ flag2 = true; // Paper - diff on change, this should be moved wrongly
ServerGamePacketListenerImpl.LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", new Object[]{entity.getName().getString(), this.player.getName().getString(), Math.sqrt(d10)});
}
Location curPos = this.getCraftPlayer().getLocation(); // Spigot
entity.absMoveTo(d3, d4, d5, f, f1);
this.player.absMoveTo(d3, d4, d5, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
- boolean flag3 = worldserver.noCollision(entity, entity.getBoundingBox().deflate(0.0625D));
- if (flag && (flag2 || !flag3)) {
+ // Paper start - optimise out extra getCubes
+ boolean teleportBack = flag2; // violating this is always a fail
+ if (!teleportBack) {
+ // note: only call after setLocation, or else getBoundingBox is wrong
+ AABB newBox = entity.getBoundingBox();
+ if (didCollide || !oldBox.equals(newBox)) {
+ teleportBack = this.hasNewCollision(worldserver, entity, oldBox, newBox);
+ } // else: no collision at all detected, why do we care?
+ }
+ if (teleportBack) { // Paper end - optimise out extra getCubes
entity.absMoveTo(d0, d1, d2, f, f1);
this.player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
this.connection.send(new ClientboundMoveVehiclePacket(entity));
@@ -703,7 +712,32 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
}
private boolean noBlocksAround(Entity entity) {
- return entity.level.getBlockStates(entity.getBoundingBox().inflate(0.0625D).expandTowards(0.0D, -0.55D, 0.0D)).allMatch(BlockBehaviour.BlockStateBase::isAir);
+ // Paper start - stop using streams, this is already a known fixed problem in Entity#move
+ AABB box = entity.getBoundingBox().inflate(0.0625D).expandTowards(0.0D, -0.55D, 0.0D);
+ int minX = Mth.floor(box.minX);
+ int minY = Mth.floor(box.minY);
+ int minZ = Mth.floor(box.minZ);
+ int maxX = Mth.floor(box.maxX);
+ int maxY = Mth.floor(box.maxY);
+ int maxZ = Mth.floor(box.maxZ);
+
+ Level world = entity.level;
+ BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
+
+ for (int y = minY; y <= maxY; ++y) {
+ for (int z = minZ; z <= maxZ; ++z) {
+ for (int x = minX; x <= maxX; ++x) {
+ pos.set(x, y, z);
+ BlockState type = world.getBlockStateIfLoaded(pos);
+ if (type != null && !type.isAir()) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ // Paper end - stop using streams, this is already a known fixed problem in Entity#move
}
@Override
@@ -1252,7 +1286,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
}
if (this.awaitingPositionFromClient != null) {
- if (this.tickCount - this.awaitingTeleportTime > 20) {
+ if (false && this.tickCount - this.awaitingTeleportTime > 20) { // Paper - this will greatly screw with clients with > 1000ms RTT
this.awaitingTeleportTime = this.tickCount;
this.teleport(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot());
}
@@ -1346,7 +1380,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
}
}
- AABB axisalignedbb = this.player.getBoundingBox();
+ AABB axisalignedbb = this.player.getBoundingBox(); // Paper - diff on change, should be old AABB
d7 = d0 - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
d8 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
@@ -1387,6 +1421,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
boolean flag1 = this.player.verticalCollisionBelow;
this.player.move(MoverType.PLAYER, new Vec3(d7, d8, d9));
+ boolean didCollide = toX != this.player.getX() || toY != this.player.getY() || toZ != this.player.getZ(); // Paper - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be...
this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
// Paper start - prevent position desync
if (this.awaitingPositionFromClient != null) {
@@ -1406,12 +1441,23 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
boolean flag2 = false;
if (!this.player.isChangingDimension() && d11 > org.spigotmc.SpigotConfig.movedWronglyThreshold && !this.player.isSleeping() && !this.player.gameMode.isCreative() && this.player.gameMode.getGameModeForPlayer() != GameType.SPECTATOR) { // Spigot
- flag2 = true;
+ flag2 = true; // Paper - diff on change, this should be moved wrongly
ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!", this.player.getName().getString());
}
this.player.absMoveTo(d0, d1, d2, f, f1);
- if (!this.player.noPhysics && !this.player.isSleeping() && (flag2 && worldserver.noCollision(this.player, axisalignedbb) || this.isPlayerCollidingWithAnythingNew(worldserver, axisalignedbb))) {
+ // Paper start - optimise out extra getCubes
+ // Original for reference:
+ // boolean teleportBack = flag2 && worldserver.getCubes(this.player, axisalignedbb) || (didCollide && this.a((IWorldReader) worldserver, axisalignedbb));
+ boolean teleportBack = flag2; // violating this is always a fail
+ if (!this.player.noPhysics && !this.player.isSleeping() && !teleportBack) {
+ AABB newBox = this.player.getBoundingBox();
+ if (didCollide || !axisalignedbb.equals(newBox)) {
+ // note: only call after setLocation, or else getBoundingBox is wrong
+ teleportBack = this.hasNewCollision(worldserver, this.player, axisalignedbb, newBox);
+ } // else: no collision at all detected, why do we care?
+ }
+ if (!this.player.noPhysics && !this.player.isSleeping() && teleportBack) { // Paper end - optimise out extra getCubes
this.internalTeleport(d3, d4, d5, f, f1, Collections.emptySet(), false); // CraftBukkit - SPIGOT-1807: Don't call teleport event, when the client thinks the player is falling, because the chunks are not loaded on the client yet.
} else {
// CraftBukkit start - fire PlayerMoveEvent
@@ -1497,6 +1543,27 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
}
}
+ // Paper start - optimise out extra getCubes
+ private boolean hasNewCollision(final ServerLevel world, final Entity entity, final AABB oldBox, final AABB newBox) {
+ final List<AABB> collisions = io.papermc.paper.util.CachedLists.getTempCollisionList();
+ try {
+ io.papermc.paper.util.CollisionUtil.getCollisions(world, entity, newBox, collisions, false, true,
+ true, false, null, null);
+
+ for (int i = 0, len = collisions.size(); i < len; ++i) {
+ final AABB box = collisions.get(i);
+ if (!io.papermc.paper.util.CollisionUtil.voxelShapeIntersect(box, oldBox)) {
+ return true;
+ }
+ }
+
+ return false;
+ } finally {
+ io.papermc.paper.util.CachedLists.returnTempCollisionList(collisions);
+ }
+ }
+ // Paper end - optimise out extra getCubes
+
private boolean isPlayerCollidingWithAnythingNew(LevelReader world, AABB box) {
Iterable<VoxelShape> iterable = world.getCollisions(this.player, this.player.getBoundingBox().deflate(9.999999747378752E-6D));
VoxelShape voxelshape = Shapes.create(box.deflate(9.999999747378752E-6D));

View file

@ -1,325 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <spottedleaf@spottedleaf.dev>
Date: Mon, 31 Aug 2020 11:08:17 -0700
Subject: [PATCH] Actually unload POI data
While it's not likely for a poi data leak to be meaningful,
sometimes it is.
This patch also prevents the saving/unloading of POI data when
world saving is disabled.
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 727ee42ec573fd1d008f526f49d0e63396ef0a9d..0e6bc8f7b31581fe0e7adb13119b30295aeac48d 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -848,6 +848,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
// Paper end
}
+ this.getPoiManager().dequeueUnload(holder.pos.longKey); // Paper - unload POI data
this.updatingChunks.queueUpdate(pos, holder); // Paper - Don't copy
this.modified = true;
@@ -999,7 +1000,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
private void processUnloads(BooleanSupplier shouldKeepTicking) {
LongIterator longiterator = this.toDrop.iterator();
- for (int i = 0; longiterator.hasNext() && (shouldKeepTicking.getAsBoolean() || i < 200 || this.toDrop.size() > 2000); longiterator.remove()) {
+ for (int i = 0; longiterator.hasNext() && (shouldKeepTicking.getAsBoolean() || i < 200 || this.toDrop.size() > 2000); longiterator.remove()) { // Paper - diff on change
long j = longiterator.nextLong();
ChunkHolder playerchunk = this.updatingChunks.queueRemove(j); // Paper - Don't copy
@@ -1047,6 +1048,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z);
}
// Paper end
+ this.getPoiManager().queueUnload(holder.pos.longKey, MinecraftServer.currentTickLong + 1); // Paper - unload POI data
if (ichunkaccess instanceof LevelChunk) {
((LevelChunk) ichunkaccess).setLoaded(false);
}
@@ -1076,6 +1078,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
for (int index = 0, len = this.regionManagers.size(); index < len; ++index) {
this.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z);
}
+ this.getPoiManager().queueUnload(holder.pos.longKey, MinecraftServer.currentTickLong + 1); // Paper - unload POI data
} // Paper end
} finally { this.unloadingPlayerChunk = unloadingBefore; } // Paper - do not allow ticket level changes while unloading chunks
@@ -1152,6 +1155,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
this.poiManager.loadInData(pos, chunkHolder.poiData);
chunkHolder.tasks.forEach(Runnable::run);
+ this.getPoiManager().dequeueUnload(pos.longKey); // Paper
// Paper end
if (chunkHolder.protoChunk != null) {try (Timing ignored2 = this.level.timings.chunkLoadLevelTimer.startTimingIfSync()) { // Paper start - timings // Paper - chunk is created async
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
index 8a569e3300543cb171c3befae59969628adc424c..54013682ee07cfe34f47070b6460c21ff420130f 100644
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
@@ -1,5 +1,6 @@
package net.minecraft.world.entity.ai.village.poi;
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; // Paper
import com.mojang.datafixers.DataFixer;
import com.mojang.datafixers.util.Pair;
import it.unimi.dsi.fastutil.longs.Long2ByteMap;
@@ -35,16 +36,145 @@ import net.minecraft.world.level.chunk.storage.SectionStorage;
public class PoiManager extends SectionStorage<PoiSection> {
public static final int MAX_VILLAGE_DISTANCE = 6;
public static final int VILLAGE_SECTION_SIZE = 1;
- private final PoiManager.DistanceTracker distanceTracker;
+ // Paper start - unload poi data
+ // the vanilla tracker needs to be replaced because it does not support level removes
+ private final io.papermc.paper.util.misc.Delayed26WayDistancePropagator3D villageDistanceTracker = new io.papermc.paper.util.misc.Delayed26WayDistancePropagator3D();
+ static final int POI_DATA_SOURCE = 7;
+ public static int convertBetweenLevels(final int level) {
+ return POI_DATA_SOURCE - level;
+ }
+
+ protected void updateDistanceTracking(long section) {
+ if (this.isVillageCenter(section)) {
+ this.villageDistanceTracker.setSource(section, POI_DATA_SOURCE);
+ } else {
+ this.villageDistanceTracker.removeSource(section);
+ }
+ }
+ // Paper end - unload poi data
private final LongSet loadedChunks = new LongOpenHashSet();
public final net.minecraft.server.level.ServerLevel world; // Paper // Paper public
public PoiManager(Path path, DataFixer dataFixer, boolean dsync, LevelHeightAccessor world) {
super(path, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, world);
+ if (world == null) { throw new IllegalStateException("world must be non-null"); } // Paper - require non-null
this.world = (net.minecraft.server.level.ServerLevel)world; // Paper
- this.distanceTracker = new PoiManager.DistanceTracker();
}
+ // Paper start - actually unload POI data
+ private final java.util.TreeSet<QueuedUnload> queuedUnloads = new java.util.TreeSet<>();
+ private final Long2ObjectOpenHashMap<QueuedUnload> queuedUnloadsByCoordinate = new Long2ObjectOpenHashMap<>();
+
+ static final class QueuedUnload implements Comparable<QueuedUnload> {
+
+ private final long unloadTick;
+ private final long coordinate;
+
+ public QueuedUnload(long unloadTick, long coordinate) {
+ this.unloadTick = unloadTick;
+ this.coordinate = coordinate;
+ }
+
+ @Override
+ public int compareTo(QueuedUnload other) {
+ if (other.unloadTick == this.unloadTick) {
+ return Long.compare(this.coordinate, other.coordinate);
+ } else {
+ return Long.compare(this.unloadTick, other.unloadTick);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 1;
+ hash = hash * 31 + Long.hashCode(this.unloadTick);
+ hash = hash * 31 + Long.hashCode(this.coordinate);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || obj.getClass() != QueuedUnload.class) {
+ return false;
+ }
+ QueuedUnload other = (QueuedUnload)obj;
+ return other.unloadTick == this.unloadTick && other.coordinate == this.coordinate;
+ }
+ }
+
+ long determineDelay(long coordinate) {
+ if (this.isEmpty(coordinate)) {
+ return 5 * 60 * 20;
+ } else {
+ return 60 * 20;
+ }
+ }
+
+ public void queueUnload(long coordinate, long minTarget) {
+ io.papermc.paper.util.TickThread.softEnsureTickThread("async poi unload queue");
+ QueuedUnload unload = new QueuedUnload(minTarget + this.determineDelay(coordinate), coordinate);
+ QueuedUnload existing = this.queuedUnloadsByCoordinate.put(coordinate, unload);
+ if (existing != null) {
+ this.queuedUnloads.remove(existing);
+ }
+ this.queuedUnloads.add(unload);
+ }
+
+ public void dequeueUnload(long coordinate) {
+ io.papermc.paper.util.TickThread.softEnsureTickThread("async poi unload dequeue");
+ QueuedUnload unload = this.queuedUnloadsByCoordinate.remove(coordinate);
+ if (unload != null) {
+ this.queuedUnloads.remove(unload);
+ }
+ }
+
+ public void pollUnloads(BooleanSupplier canSleepForTick) {
+ io.papermc.paper.util.TickThread.softEnsureTickThread("async poi unload");
+ long currentTick = net.minecraft.server.MinecraftServer.currentTickLong;
+ net.minecraft.server.level.ServerChunkCache chunkProvider = this.world.getChunkSource();
+ net.minecraft.server.level.ChunkMap playerChunkMap = chunkProvider.chunkMap;
+ // copied target determination from PlayerChunkMap
+
+ java.util.Iterator<QueuedUnload> iterator = this.queuedUnloads.iterator();
+ for (int i = 0; iterator.hasNext() && (i < 200 || this.queuedUnloads.size() > 2000 || canSleepForTick.getAsBoolean()); i++) {
+ QueuedUnload unload = iterator.next();
+ if (unload.unloadTick > currentTick) {
+ break;
+ }
+
+ long coordinate = unload.coordinate;
+
+ iterator.remove();
+ this.queuedUnloadsByCoordinate.remove(coordinate);
+
+ if (playerChunkMap.getUnloadingChunkHolder(net.minecraft.server.MCUtil.getCoordinateX(coordinate), net.minecraft.server.MCUtil.getCoordinateZ(coordinate)) != null
+ || playerChunkMap.getUpdatingChunkIfPresent(coordinate) != null) {
+ continue;
+ }
+
+ this.unloadData(coordinate);
+ }
+ }
+
+ @Override
+ public void unloadData(long coordinate) {
+ io.papermc.paper.util.TickThread.softEnsureTickThread("async unloading poi data");
+ super.unloadData(coordinate);
+ }
+
+ @Override
+ protected void onUnload(long coordinate) {
+ io.papermc.paper.util.TickThread.softEnsureTickThread("async poi unload callback");
+ this.loadedChunks.remove(coordinate);
+ int chunkX = net.minecraft.server.MCUtil.getCoordinateX(coordinate);
+ int chunkZ = net.minecraft.server.MCUtil.getCoordinateZ(coordinate);
+ for (int section = this.levelHeightAccessor.getMinSection(); section < this.levelHeightAccessor.getMaxSection(); ++section) {
+ long sectionPos = SectionPos.asLong(chunkX, section, chunkZ);
+ this.updateDistanceTracking(sectionPos);
+ }
+ }
+ // Paper end - actually unload POI data
+
public void add(BlockPos pos, PoiType type) {
this.getOrCreate(SectionPos.asLong(pos)).add(pos, type);
}
@@ -181,8 +311,8 @@ public class PoiManager extends SectionStorage<PoiSection> {
}
public int sectionsToVillage(SectionPos pos) {
- this.distanceTracker.runAllUpdates();
- return this.distanceTracker.getLevel(pos.asLong());
+ this.villageDistanceTracker.propagateUpdates(); // Paper - replace distance tracking util
+ return convertBetweenLevels(this.villageDistanceTracker.getLevel(io.papermc.paper.util.CoordinateUtils.getChunkSectionKey(pos))); // Paper - replace distance tracking util
}
boolean isVillageCenter(long pos) {
@@ -195,7 +325,7 @@ public class PoiManager extends SectionStorage<PoiSection> {
@Override
public void tick(BooleanSupplier shouldKeepTicking) {
// Paper start - async chunk io
- while (!this.dirty.isEmpty() && shouldKeepTicking.getAsBoolean()) {
+ while (!this.dirty.isEmpty() && shouldKeepTicking.getAsBoolean() && !this.world.noSave()) { // Paper - unload POI data - don't write to disk if saving is disabled
ChunkPos chunkcoordintpair = SectionPos.of(this.dirty.firstLong()).chunk();
net.minecraft.nbt.CompoundTag data;
@@ -205,19 +335,24 @@ public class PoiManager extends SectionStorage<PoiSection> {
com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.scheduleSave(this.world,
chunkcoordintpair.x, chunkcoordintpair.z, data, null, com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY);
}
+ // Paper start - unload POI data
+ if (!this.world.noSave()) { // don't write to disk if saving is disabled
+ this.pollUnloads(shouldKeepTicking);
+ }
+ // Paper end - unload POI data
// Paper end
- this.distanceTracker.runAllUpdates();
+ this.villageDistanceTracker.propagateUpdates(); // Paper - replace distance tracking until
}
@Override
protected void setDirty(long pos) {
super.setDirty(pos);
- this.distanceTracker.update(pos, this.distanceTracker.getLevelFromSource(pos), false);
+ this.updateDistanceTracking(pos); // Paper - move to new distance tracking util
}
@Override
protected void onSectionLoad(long pos) {
- this.distanceTracker.update(pos, this.distanceTracker.getLevelFromSource(pos), false);
+ this.updateDistanceTracking(pos); // Paper - move to new distance tracking util
}
public void checkConsistencyWithBlocks(ChunkPos chunkPos, LevelChunkSection chunkSection) {
@@ -275,7 +410,7 @@ public class PoiManager extends SectionStorage<PoiSection> {
@Override
protected int getLevelFromSource(long id) {
- return PoiManager.this.isVillageCenter(id) ? 0 : 7;
+ return PoiManager.this.isVillageCenter(id) ? 0 : 7; // Paper - unload poi data - diff on change, this specifies the source level to use for distance tracking
}
@Override
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
index 3cfc57b49fb3d85c4b9039907fc22bad3a0efe3e..2df0b55a18e57163e49770e83ef067a5587d2126 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
@@ -52,6 +52,40 @@ public class SectionStorage<R> extends RegionFileStorage implements AutoCloseabl
// Paper - remove mojang I/O thread
}
+ // Paper start - actually unload POI data
+ public void unloadData(long coordinate) {
+ ChunkPos chunkPos = new ChunkPos(coordinate);
+ this.flush(chunkPos);
+
+ Long2ObjectMap<Optional<R>> data = this.storage;
+ int before = data.size();
+
+ for (int section = this.levelHeightAccessor.getMinSection(); section < this.levelHeightAccessor.getMaxSection(); ++section) {
+ data.remove(SectionPos.asLong(chunkPos.x, section, chunkPos.z));
+ }
+
+ if (before != data.size()) {
+ this.onUnload(coordinate);
+ }
+ }
+
+ protected void onUnload(long coordinate) {}
+
+ public boolean isEmpty(long coordinate) {
+ Long2ObjectMap<Optional<R>> data = this.storage;
+ int x = net.minecraft.server.MCUtil.getCoordinateX(coordinate);
+ int z = net.minecraft.server.MCUtil.getCoordinateZ(coordinate);
+ for (int section = this.levelHeightAccessor.getMinSection(); section < this.levelHeightAccessor.getMaxSection(); ++section) {
+ Optional<R> optional = data.get(SectionPos.asLong(x, section, z));
+ if (optional != null && optional.orElse(null) != null) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ // Paper end - actually unload POI data
+
protected void tick(BooleanSupplier shouldKeepTicking) {
while(this.hasWork() && shouldKeepTicking.getAsBoolean()) {
ChunkPos chunkPos = SectionPos.of(this.dirty.firstLong()).chunk();
@@ -166,6 +200,7 @@ public class SectionStorage<R> extends RegionFileStorage implements AutoCloseabl
});
}
}
+ if (this instanceof net.minecraft.world.entity.ai.village.poi.PoiManager) { ((net.minecraft.world.entity.ai.village.poi.PoiManager)this).queueUnload(pos.longKey, net.minecraft.server.MinecraftServer.currentTickLong + 1); } // Paper - unload POI data
}

View file

@ -1,43 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Thu, 9 Dec 2021 00:08:11 -0800
Subject: [PATCH] Fix ChunkSnapshot#isSectionEmpty(int) and optimize
PalettedContainer copying by not using codecs
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
index 0cf67d55ab30ab145ffb2ff562c26c47c2e2879e..403aba29347c779da75337531c3723632120e7c9 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
@@ -282,13 +282,17 @@ public class CraftChunk implements Chunk {
PalettedContainer<Holder<Biome>>[] biome = (includeBiome || includeBiomeTempRain) ? new PalettedContainer[cs.length] : null;
Registry<Biome> iregistry = this.worldServer.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
- Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codec(iregistry.asHolderIdMap(), iregistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, iregistry.getHolderOrThrow(Biomes.PLAINS), null); // Paper - Anti-Xray - Add preset biomes
for (int i = 0; i < cs.length; i++) {
- CompoundTag data = new CompoundTag();
- data.put("block_states", ChunkSerializer.BLOCK_STATE_CODEC.encodeStart(NbtOps.INSTANCE, cs[i].getStates()).get().left().get());
- sectionBlockIDs[i] = ChunkSerializer.BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, data.getCompound("block_states")).get().left().get();
+ // Paper start
+ sectionEmpty[i] = cs[i].hasOnlyAir(); // Paper - fix sectionEmpty array not being filled
+ if (!sectionEmpty[i]) {
+ sectionBlockIDs[i] = cs[i].getStates().copy(); // Paper - use copy instead of round tripping with codecs
+ } else {
+ sectionBlockIDs[i] = CraftChunk.emptyBlockIDs; // Paper - use cached instance for empty block sections
+ }
+ // Paper end
LevelLightEngine lightengine = chunk.level.getLightEngine();
DataLayer skyLightArray = lightengine.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(x, i, z));
@@ -307,8 +311,7 @@ public class CraftChunk implements Chunk {
}
if (biome != null) {
- data.put("biomes", biomeCodec.encodeStart(NbtOps.INSTANCE, cs[i].getBiomes()).get().left().get());
- biome[i] = biomeCodec.parse(NbtOps.INSTANCE, data.getCompound("biomes")).get().left().get();
+ biome[i] = cs[i].getBiomes().copy(); // Paper - use copy instead of round tripping with codecs
}
}

View file

@ -1,24 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: darbyjack <admin@glaremasters.me>
Date: Thu, 9 Dec 2021 19:17:02 -0600
Subject: [PATCH] Update Log4j
diff --git a/build.gradle.kts b/build.gradle.kts
index 4715d1386afd939628c392a7d8062e5887d7a507..0282e3b75470e1a68ea1fc228082483514ba432e 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -20,10 +20,11 @@ dependencies {
all its classes to check if they are plugins.
Scanning takes about 1-2 seconds so adding this speeds up the server start.
*/
- implementation("org.apache.logging.log4j:log4j-core:2.14.1") // Paper - implementation
- annotationProcessor("org.apache.logging.log4j:log4j-core:2.14.1") // Paper - Needed to generate meta for our Log4j plugins
+ implementation("org.apache.logging.log4j:log4j-core:2.17.1") // Paper - implementation
+ annotationProcessor("org.apache.logging.log4j:log4j-core:2.17.1") // Paper - Needed to generate meta for our Log4j plugins
// Paper end
implementation("org.apache.logging.log4j:log4j-iostreams:2.17.1") // Paper
+ implementation("org.apache.logging.log4j:log4j-slf4j18-impl:2.17.1") // Paper
implementation("org.ow2.asm:asm:9.2")
implementation("org.ow2.asm:asm-commons:9.2") // Paper - ASM event executor generation
runtimeOnly("org.xerial:sqlite-jdbc:3.36.0.3")

View file

@ -1,111 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: LemonCaramel <admin@caramel.moe>
Date: Fri, 16 Jul 2021 00:39:03 +0900
Subject: [PATCH] Add more Campfire API
diff --git a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
index 1d2dbaec8201de12fb65e2c01ca8a1ead7e873a7..96c161b15a62a720fa991e8849f35956f767ff09 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
@@ -32,12 +32,14 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
private final NonNullList<ItemStack> items;
public final int[] cookingProgress;
public final int[] cookingTime;
+ public final boolean[] stopCooking; // Paper
public CampfireBlockEntity(BlockPos pos, BlockState state) {
super(BlockEntityType.CAMPFIRE, pos, state);
this.items = NonNullList.withSize(4, ItemStack.EMPTY);
this.cookingProgress = new int[4];
this.cookingTime = new int[4];
+ this.stopCooking = new boolean[4]; // Paper
}
public static void cookTick(Level world, BlockPos pos, BlockState state, CampfireBlockEntity campfire) {
@@ -48,7 +50,9 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
if (!itemstack.isEmpty()) {
flag = true;
+ if (!campfire.stopCooking[i]) { // Paper
int j = campfire.cookingProgress[i]++;
+ } // Paper
if (campfire.cookingProgress[i] >= campfire.cookingTime[i]) {
SimpleContainer inventorysubcontainer = new SimpleContainer(new ItemStack[]{itemstack});
@@ -155,6 +159,16 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
System.arraycopy(aint, 0, this.cookingTime, 0, Math.min(this.cookingTime.length, aint.length));
}
+ // Paper start
+ if (nbt.contains("Paper.StopCooking", org.bukkit.craftbukkit.util.CraftMagicNumbers.NBT.TAG_BYTE_ARRAY)) {
+ byte[] abyte = nbt.getByteArray("Paper.StopCooking");
+ boolean[] cookingState = new boolean[4];
+ for (int index = 0; index < abyte.length; index++) {
+ cookingState[index] = abyte[index] == 1;
+ }
+ System.arraycopy(cookingState, 0, this.stopCooking, 0, Math.min(this.stopCooking.length, abyte.length));
+ }
+ // Paper end
}
@Override
@@ -163,6 +177,13 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
ContainerHelper.saveAllItems(nbt, this.items, true);
nbt.putIntArray("CookingTimes", this.cookingProgress);
nbt.putIntArray("CookingTotalTimes", this.cookingTime);
+ // Paper start
+ byte[] cookingState = new byte[4];
+ for (int index = 0; index < cookingState.length; index++) {
+ cookingState[index] = (byte) (this.stopCooking[index] ? 1 : 0);
+ }
+ nbt.putByteArray("Paper.StopCooking", cookingState);
+ // Paper end
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java b/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java
index 391ff41951f51a5f9225bf4a9e28c0a4d064d8c9..eafba0532920a3162575dbe656e07734605590f5 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java
@@ -47,4 +47,40 @@ public class CraftCampfire extends CraftBlockEntityState<CampfireBlockEntity> im
public void setCookTimeTotal(int index, int cookTimeTotal) {
getSnapshot().cookingTime[index] = cookTimeTotal;
}
+
+ // Paper start
+ @Override
+ public void stopCooking() {
+ for (int i = 0; i < getSnapshot().stopCooking.length; ++i)
+ this.stopCooking(i);
+ }
+
+ @Override
+ public void startCooking() {
+ for (int i = 0; i < getSnapshot().stopCooking.length; ++i)
+ this.startCooking(i);
+ }
+
+ @Override
+ public boolean stopCooking(int index) {
+ org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)");
+ boolean previous = this.isCookingDisabled(index);
+ getSnapshot().stopCooking[index] = true;
+ return previous;
+ }
+
+ @Override
+ public boolean startCooking(int index) {
+ org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)");
+ boolean previous = this.isCookingDisabled(index);
+ getSnapshot().stopCooking[index] = false;
+ return previous;
+ }
+
+ @Override
+ public boolean isCookingDisabled(int index) {
+ org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)");
+ return getSnapshot().stopCooking[index];
+ }
+ // Paper end
}

View file

@ -1,87 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sun, 19 Dec 2021 09:13:41 -0800
Subject: [PATCH] Only write chunk data to disk if it serializes without
throwing
This ensures at least a valid version of the chunk exists
on disk, even if outdated
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
index 8ff8855c5267379b3a5f5d8baa4a275ffee2c4bf..6704ae5c2ee01f8b319f4d425fe08c16d7b1b212 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
@@ -1019,6 +1019,24 @@ public class RegionFile implements AutoCloseable {
this.pos = chunkcoordintpair;
}
+ // Paper start - don't write garbage data to disk if writing serialization fails
+ @Override
+ public void write(final int b) {
+ if (this.count > 500_000_000) {
+ throw new RegionFileStorage.RegionFileSizeException("Region file too large: " + this.count);
+ }
+ super.write(b);
+ }
+
+ @Override
+ public void write(final byte[] b, final int off, final int len) {
+ if (this.count + len > 500_000_000) {
+ throw new RegionFileStorage.RegionFileSizeException("Region file too large: " + (this.count + len));
+ }
+ super.write(b, off, len);
+ }
+ // Paper end
+
public void close() throws IOException {
ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count);
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
index e5b444c6f2e45c50b4f7ab49c0dad801938f6cd9..303b70f0433ff49a3bee2a0d92c41f01aec38bee 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
@@ -298,10 +298,17 @@ public class RegionFileStorage implements AutoCloseable {
NbtIo.write(nbt, (DataOutput) dataoutputstream);
regionfile.setStatus(pos.x, pos.z, ChunkSerializer.getStatus(nbt)); // Paper - cache status on disk
regionfile.setOversized(pos.x, pos.z, false); // Paper - We don't do this anymore, mojang stores differently, but clear old meta flag if it exists to get rid of our own meta file once last oversized is gone
+ dataoutputstream.close(); // Paper - only write if successful
+ // Paper start - don't write garbage data to disk if writing serialization fails
+ } catch (RegionFileSizeException e) {
+ attempts = 5; // Don't retry
+ regionfile.clear(pos);
+ throw e;
+ // Paper end - don't write garbage data to disk if writing serialization fails
} catch (Throwable throwable) {
if (dataoutputstream != null) {
try {
- dataoutputstream.close();
+ //dataoutputstream.close(); // Paper - don't write garbage data to disk if writing serialization fails
} catch (Throwable throwable1) {
throwable.addSuppressed(throwable1);
}
@@ -309,10 +316,7 @@ public class RegionFileStorage implements AutoCloseable {
throw throwable;
}
-
- if (dataoutputstream != null) {
- dataoutputstream.close();
- }
+ // Paper - move into try block to only write if successfully serialized
}
// Paper start
@@ -359,4 +363,13 @@ public class RegionFileStorage implements AutoCloseable {
}
}
+
+ // Paper start
+ public static final class RegionFileSizeException extends RuntimeException {
+
+ public RegionFileSizeException(String message) {
+ super(message);
+ }
+ }
+ // Paper end
}

View file

@ -1,67 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <jahnke.nassim@gmail.com>
Date: Sun, 19 Dec 2021 21:11:20 +0100
Subject: [PATCH] Fix tripwire state inconsistency
This patch prevents updating and re-setting the tripwire when being removed in certain conditions
diff --git a/src/main/java/net/minecraft/world/level/block/TripWireBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireBlock.java
index 6b40bf94fbaa18605b59b92ad1582e8dc3a6a9cd..7d89b9ed84209c161b2c6fec5304abbbf41f2e80 100644
--- a/src/main/java/net/minecraft/world/level/block/TripWireBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/TripWireBlock.java
@@ -74,7 +74,7 @@ public class TripWireBlock extends Block {
@Override
public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean moved) {
if (!moved && !state.is(newState.getBlock())) {
- this.updateSource(world, pos, (BlockState) state.setValue(TripWireBlock.POWERED, true));
+ this.updateSource(world, pos, (BlockState) state.setValue(TripWireBlock.POWERED, true), true); // Paper - fix state inconsistency
}
}
@@ -89,6 +89,12 @@ public class TripWireBlock extends Block {
}
private void updateSource(Level world, BlockPos pos, BlockState state) {
+ // Paper start - fix state inconsistency
+ this.updateSource(world, pos, state, false);
+ }
+
+ private void updateSource(Level world, BlockPos pos, BlockState state, boolean beingRemoved) {
+ // Paper end
Direction[] aenumdirection = new Direction[]{Direction.SOUTH, Direction.WEST};
int i = aenumdirection.length;
int j = 0;
@@ -104,7 +110,7 @@ public class TripWireBlock extends Block {
if (iblockdata1.is((Block) this.hook)) {
if (iblockdata1.getValue(TripWireHookBlock.FACING) == enumdirection.getOpposite()) {
- this.hook.calculateState(world, blockposition1, iblockdata1, false, true, k, state);
+ this.hook.calculateState(world, blockposition1, iblockdata1, false, true, k, state, beingRemoved); // Paper - fix state inconsistency
}
} else if (iblockdata1.is((Block) this)) {
++k;
diff --git a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
index 02a3e1ced592784b9c66927c76376c7ab413367d..a4344bf2267112e3c1e31c07c9f6b8eae9666947 100644
--- a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
@@ -107,6 +107,12 @@ public class TripWireHookBlock extends Block {
}
public void calculateState(Level world, BlockPos pos, BlockState state, boolean beingRemoved, boolean flag1, int i, @Nullable BlockState iblockdata1) {
+ // Paper start - fix tripwire inconsistency
+ this.calculateState(world, pos, state, beingRemoved, flag1, i, iblockdata1, false);
+ }
+
+ public void calculateState(Level world, BlockPos pos, BlockState state, boolean beingRemoved, boolean flag1, int i, @Nullable BlockState iblockdata1, boolean tripWireBeingRemoved) {
+ // Paper end
Direction enumdirection = (Direction) state.getValue(TripWireHookBlock.FACING);
boolean flag2 = (Boolean) state.getValue(TripWireHookBlock.ATTACHED);
boolean flag3 = (Boolean) state.getValue(TripWireHookBlock.POWERED);
@@ -140,6 +146,7 @@ public class TripWireHookBlock extends Block {
boolean flag7 = (Boolean) iblockdata2.getValue(TripWireBlock.POWERED);
flag5 |= flag6 && flag7;
+ if (k != i || !tripWireBeingRemoved || !flag6) // Paper - don't update the tripwire again if being removed and not disarmed
aiblockdata[k] = iblockdata2;
if (k == i) {
world.scheduleTick(pos, (Block) this, 10);

View file

@ -1,29 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Tue, 21 Dec 2021 16:28:17 -0800
Subject: [PATCH] Fix fluid-logging on Block#breakNaturally
Leaves fluid if the block broken was fluid-logged which is what
happens if a player breaks a fluid-logged block
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
index 2881bcb570dc86a7602309e1f540ecd1c7f00284..0030ac394d44acddcd2fc716277ae2b509a378af 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
@@ -515,6 +515,7 @@ public class CraftBlock implements Block {
net.minecraft.world.level.block.state.BlockState iblockdata = this.getNMS();
net.minecraft.world.level.block.Block block = iblockdata.getBlock();
net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item);
+ net.minecraft.world.level.material.FluidState fluidState = this.world.getFluidState(this.position); // Paper
boolean result = false;
// Modelled off EntityHuman#hasBlock
@@ -525,7 +526,7 @@ public class CraftBlock implements Block {
}
// SPIGOT-6778: Directly call setBlock instead of setTypeAndData, so that the tile entiy is not removed and custom remove logic is run.
- return this.world.setBlock(position, Blocks.AIR.defaultBlockState(), 3) && result;
+ return this.world.setBlock(position, fluidState.createLegacyBlock(), 3) && result; // Paper - leave liquid if waterlogged
}
@Override

View file

@ -1,39 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sat, 4 Dec 2021 17:04:47 -0800
Subject: [PATCH] Forward CraftEntity in teleport command
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 396ee5a8aa57e7c2e9a14606d37cae3c02dc4283..18294d7cdb4619bb128c626ef567622bae187c8d 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -3177,6 +3177,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
}
public void restoreFrom(Entity original) {
+ // Paper start
+ CraftEntity bukkitEntity = original.bukkitEntity;
+ if (bukkitEntity != null) {
+ bukkitEntity.setHandle(this);
+ this.bukkitEntity = bukkitEntity;
+ }
+ // Paper end
CompoundTag nbttagcompound = original.saveWithoutId(new CompoundTag());
nbttagcompound.remove("Dimension");
@@ -3258,10 +3265,10 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
if (worldserver.getTypeKey() == LevelStem.END) { // CraftBukkit
ServerLevel.makeObsidianPlatform(worldserver, this); // CraftBukkit
}
- // CraftBukkit start - Forward the CraftEntity to the new entity
- this.getBukkitEntity().setHandle(entity);
- entity.bukkitEntity = this.getBukkitEntity();
- // CraftBukkit end
+ // // CraftBukkit start - Forward the CraftEntity to the new entity // Paper - moved to Entity#restoreFrom
+ // this.getBukkitEntity().setHandle(entity);
+ // entity.bukkitEntity = this.getBukkitEntity();
+ // // CraftBukkit end
}
this.removeAfterChangingDimensions();

View file

@ -1,84 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 4 Nov 2021 12:31:24 -0700
Subject: [PATCH] Improve scoreboard entries
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java
index 6752cd9b3bc246fc2a7764df0d2b40d3e638fa62..c5cf800ab8cbb5ebcf1b06ad591f08be75859b8c 100644
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java
@@ -138,6 +138,14 @@ final class CraftObjective extends CraftScoreboardComponent implements Objective
return new CraftScore(this, entry);
}
+ // Paper start
+ @Override
+ public Score getScoreFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException, IllegalStateException {
+ Validate.notNull(entity, "Entity cannot be null");
+ return getScore(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
+ }
+ // Paper end
+
@Override
public void unregister() throws IllegalStateException {
CraftScoreboard scoreboard = this.checkState();
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java
index 167376bcd547f55983ccbb0d46e571c45c7d1ed9..912d302af733d8ee2517cf5f243301e6452493f9 100644
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java
@@ -234,4 +234,23 @@ public final class CraftScoreboard implements org.bukkit.scoreboard.Scoreboard {
public Scoreboard getHandle() {
return this.board;
}
+ // Paper start
+ @Override
+ public ImmutableSet<Score> getScoresFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException {
+ Validate.notNull(entity, "Entity cannot be null");
+ return this.getScores(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
+ }
+
+ @Override
+ public void resetScoresFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException {
+ Validate.notNull(entity, "Entity cannot be null");
+ this.resetScores(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
+ }
+
+ @Override
+ public Team getEntityTeam(org.bukkit.entity.Entity entity) throws IllegalArgumentException {
+ Validate.notNull(entity, "Entity cannot be null");
+ return this.getEntryTeam(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
+ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
index 60b1cffdccde4715832546d6edbf206fbab4e82f..4b64d6c5c987e127d1ed5edad0a78f7172370b9f 100644
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
@@ -310,6 +310,26 @@ final class CraftTeam extends CraftScoreboardComponent implements Team {
}
}
+ // Paper start
+ @Override
+ public void addEntity(org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException {
+ Validate.notNull(entity, "Entity cannot be null");
+ this.addEntry(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
+ }
+
+ @Override
+ public boolean removeEntity(org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException {
+ Validate.notNull(entity, "Entity cannot be null");
+ return this.removeEntry(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
+ }
+
+ @Override
+ public boolean hasEntity(org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException {
+ Validate.notNull(entity, "Entity cannot be null");
+ return this.hasEntry(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
+ }
+ // Paper end
+
public static Visibility bukkitToNotch(NameTagVisibility visibility) {
switch (visibility) {
case ALWAYS:

View file

@ -1,37 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 24 Oct 2021 20:58:43 -0700
Subject: [PATCH] Entity powdered snow API
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 9e5f338d0bb64ac47a99cd08a2ab083d2f5caf6c..0a998832afacb25cbaf39737d14aa33eab6967b7 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -1294,5 +1294,10 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
entity.setRot(location.getYaw(), location.getPitch());
return !entity.valid && entity.level.addFreshEntity(entity, reason);
}
+
+ @Override
+ public boolean isInPowderedSnow() {
+ return getHandle().isInPowderSnow || getHandle().wasInPowderSnow; // depending on the location in the entity "tick" either could be needed.
+ }
// Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java
index 90f34d75f99f31f5c98c499df209979a03e23191..1737857424c5da885c46f39502cafd2a670d3be7 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java
@@ -51,4 +51,11 @@ public class CraftSkeleton extends CraftAbstractSkeleton implements Skeleton {
public SkeletonType getSkeletonType() {
return SkeletonType.NORMAL;
}
+
+ // Paper start
+ @Override
+ public int inPowderedSnowTime() {
+ return getHandle().inPowderSnowTime;
+ }
+ // Paper end
}

View file

@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sat, 28 Aug 2021 09:00:45 -0700
Subject: [PATCH] Add API for item entity health
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
index 1d90219c3a0e86786a9497d4c078c2d4077ab6cd..fea44ba6a6584b4a510af6a58cab07eecec6b68b 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
@@ -102,6 +102,21 @@ public class CraftItem extends CraftEntity implements Item {
public void setWillAge(boolean willAge) {
item.age = willAge ? 0 : NO_AGE_TIME;
}
+
+ @Override
+ public int getHealth() {
+ return item.health;
+ }
+
+ @Override
+ public void setHealth(int health) {
+ if (health <= 0) {
+ item.getItem().onDestroyed(item);
+ item.discard();
+ } else {
+ item.health = health;
+ }
+ }
// Paper End
@Override

View file

@ -1,151 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 22 Aug 2021 15:21:57 -0700
Subject: [PATCH] Fix entity type tags suggestions in selectors
This would really be better as a client fix because just to fix it
all EntityArguments have been told to ask the server for completions
when if this was fixed on the client, that wouldn't be needed.
Mojira Issue: https://bugs.mojang.com/browse/MC-235045
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index fa912cffb2349914d1a550d3d1c69ba5934658dc..9e01ee1776a02dd7be0a47ac3a06e69968d26bdc 100644
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
@@ -527,6 +527,11 @@ public class PaperConfig {
itemValidationBookPageLength = getInt("settings.item-validation.book.page", itemValidationBookPageLength);
}
+ public static boolean fixTargetSelectorTagCompletion = true;
+ private static void fixTargetSelectorTagCompletion() {
+ fixTargetSelectorTagCompletion = getBoolean("settings.fix-target-selector-tag-completion", fixTargetSelectorTagCompletion);
+ }
+
public static final class PacketLimit {
public final double packetLimitInterval;
public final double maxPacketRate;
diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java
index db26d834d9a59c4fd60f99077f0118c08293678f..00bbf33aa44e2d5a4e755a2d7c1a60de9e36674f 100644
--- a/src/main/java/net/minecraft/commands/CommandSourceStack.java
+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java
@@ -330,4 +330,20 @@ public class CommandSourceStack implements SharedSuggestionProvider, com.destroy
return this.source.getBukkitSender(this);
}
// CraftBukkit end
+ // Paper start - override getSelectedEntities
+ @Override
+ public Collection<String> getSelectedEntities() {
+ if (com.destroystokyo.paper.PaperConfig.fixTargetSelectorTagCompletion && this.source instanceof ServerPlayer player) {
+ double pickDistance = player.gameMode.getGameModeForPlayer().isCreative() ? 5.0F : 4.5F;
+ Vec3 min = player.getEyePosition(1.0F);
+ Vec3 viewVector = player.getViewVector(1.0F);
+ Vec3 max = min.add(viewVector.x * pickDistance, viewVector.y * pickDistance, viewVector.z * pickDistance);
+ net.minecraft.world.phys.AABB aabb = player.getBoundingBox().expandTowards(viewVector.scale(pickDistance)).inflate(1.0D, 1.0D, 1.0D);
+ pickDistance = player.gameMode.getGameModeForPlayer().isCreative() ? 6.0F : pickDistance;
+ net.minecraft.world.phys.EntityHitResult hitResult = net.minecraft.world.entity.projectile.ProjectileUtil.getEntityHitResult(player, min, max, aabb, (e) -> !e.isSpectator() && e.isPickable(), pickDistance);
+ return hitResult != null ? java.util.Collections.singletonList(hitResult.getEntity().getStringUUID()) : SharedSuggestionProvider.super.getSelectedEntities();
+ }
+ return SharedSuggestionProvider.super.getSelectedEntities();
+ }
+ // Paper end
}
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
index 13a0f78abbb00b489b63d88ce14f60cb04402085..b66afde6851ceaeccb84aea00cdc333dfbf3d4b0 100644
--- a/src/main/java/net/minecraft/commands/Commands.java
+++ b/src/main/java/net/minecraft/commands/Commands.java
@@ -409,6 +409,7 @@ public class Commands {
private void fillUsableCommands(CommandNode<CommandSourceStack> tree, CommandNode<SharedSuggestionProvider> result, CommandSourceStack source, Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> resultNodes) {
Iterator iterator = tree.getChildren().iterator();
+ boolean registeredAskServerSuggestionsForTree = false; // Paper - tell clients to ask server for suggestions for EntityArguments
while (iterator.hasNext()) {
CommandNode<CommandSourceStack> commandnode2 = (CommandNode) iterator.next();
if ( !org.spigotmc.SpigotConfig.sendNamespaced && commandnode2.getName().contains( ":" ) ) continue; // Spigot
@@ -430,6 +431,12 @@ public class Commands {
if (requiredargumentbuilder.getSuggestionsProvider() != null) {
requiredargumentbuilder.suggests(SuggestionProviders.safelySwap(requiredargumentbuilder.getSuggestionsProvider()));
+ // Paper start - tell clients to ask server for suggestions for EntityArguments
+ registeredAskServerSuggestionsForTree = requiredargumentbuilder.getSuggestionsProvider() == net.minecraft.commands.synchronization.SuggestionProviders.ASK_SERVER;
+ } else if (com.destroystokyo.paper.PaperConfig.fixTargetSelectorTagCompletion && !registeredAskServerSuggestionsForTree && requiredargumentbuilder.getType() instanceof net.minecraft.commands.arguments.EntityArgument) {
+ requiredargumentbuilder.suggests(requiredargumentbuilder.getType()::listSuggestions);
+ registeredAskServerSuggestionsForTree = true; // You can only
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
}
}
diff --git a/src/main/java/net/minecraft/commands/arguments/EntityArgument.java b/src/main/java/net/minecraft/commands/arguments/EntityArgument.java
index 1f3076e59bac23d428c747ae12619e4b4e5fdd5a..1d23d05d7028c5f820f172cc54153f56848e1d05 100644
--- a/src/main/java/net/minecraft/commands/arguments/EntityArgument.java
+++ b/src/main/java/net/minecraft/commands/arguments/EntityArgument.java
@@ -127,7 +127,7 @@ public class EntityArgument implements ArgumentType<EntitySelector> {
stringreader.setCursor(suggestionsbuilder.getStart());
SharedSuggestionProvider icompletionprovider = (SharedSuggestionProvider) commandcontext.getSource();
- EntitySelectorParser argumentparserselector = new EntitySelectorParser(stringreader, icompletionprovider.hasPermission(2));
+ EntitySelectorParser argumentparserselector = new EntitySelectorParser(stringreader, icompletionprovider.hasPermission(2), true); // Paper
try {
argumentparserselector.parse();
diff --git a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
index 2816fd4a57fe51689daf1b4850ad3ab3c9749225..cdbe0695a29d0854d7f59c1f63a74bd0c1dbf4d9 100644
--- a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
+++ b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
@@ -115,12 +115,19 @@ public class EntitySelectorParser {
private boolean hasScores;
private boolean hasAdvancements;
private boolean usesSelectors;
+ public boolean parsingEntityArgumentSuggestions; // Paper - track when parsing EntityArgument suggestions
public EntitySelectorParser(StringReader reader) {
this(reader, true);
}
public EntitySelectorParser(StringReader reader, boolean atAllowed) {
+ // Paper start
+ this(reader, atAllowed, false);
+ }
+ public EntitySelectorParser(StringReader reader, boolean atAllowed, boolean parsingEntityArgumentSuggestions) {
+ this.parsingEntityArgumentSuggestions = parsingEntityArgumentSuggestions;
+ // Paper end
this.distance = MinMaxBounds.Doubles.ANY;
this.level = MinMaxBounds.Ints.ANY;
this.rotX = WrappedMinMaxBounds.ANY;
diff --git a/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java b/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
index e5a23bf6ab92bb1fa7485df1fe52f68f111bc1b1..f0bc168393ba87310d3c43b236b024c46b66ba39 100644
--- a/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
+++ b/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
@@ -68,6 +68,19 @@ public class EntitySelectorOptions {
public static final DynamicCommandExceptionType ERROR_ENTITY_TYPE_INVALID = new DynamicCommandExceptionType((entity) -> {
return new TranslatableComponent("argument.entity.options.type.invalid", entity);
});
+ // Paper start
+ public static final DynamicCommandExceptionType ERROR_ENTITY_TAG_INVALID = new DynamicCommandExceptionType((object) -> {
+ return io.papermc.paper.adventure.PaperAdventure
+ .asVanilla(net.kyori.adventure.text.Component
+ .text("Invalid or unknown entity type tag '" + object + "'")
+ .hoverEvent(net.kyori.adventure.text.event.HoverEvent
+ .showText(net.kyori.adventure.text.Component
+ .text("You can disable this error in 'paper.yml'")
+ )
+ )
+ );
+ });
+ // Paper end
private static void register(String id, EntitySelectorOptions.Modifier handler, Predicate<EntitySelectorParser> condition, Component description) {
OPTIONS.put(id, new EntitySelectorOptions.Option(handler, condition, description));
@@ -315,6 +328,12 @@ public class EntitySelectorOptions {
if (reader.isTag()) {
TagKey<EntityType<?>> tagKey = TagKey.create(Registry.ENTITY_TYPE_REGISTRY, ResourceLocation.read(reader.getReader()));
+ // Paper start - throw error if invalid entity tag (only on suggestions to keep cmd success behavior)
+ if (com.destroystokyo.paper.PaperConfig.fixTargetSelectorTagCompletion && reader.parsingEntityArgumentSuggestions && !Registry.ENTITY_TYPE.isKnownTagName(tagKey)) {
+ reader.getReader().setCursor(i);
+ throw ERROR_ENTITY_TAG_INVALID.createWithContext(reader.getReader(), tagKey);
+ }
+ // Paper end
reader.addPredicate((entity) -> {
return entity.getType().is(tagKey) != bl;
});

View file

@ -1,33 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <jahnke.nassim@gmail.com>
Date: Thu, 16 Dec 2021 09:40:39 +0100
Subject: [PATCH] Configurable max block light for monster spawning
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 99008ac6943c56f74f912e739709a4724da322ef..b2d9dbf4e006899a932bd6bed40228d4f744d865 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -1083,4 +1083,9 @@ public class PaperWorldConfig {
Integer rate = table.get(columnKey, rowKey);
return rate != null && rate > -1 ? rate : def;
}
+
+ public int maxBlockLightForMonsterSpawning = -1;
+ private void minBlockLightForMobSpawning() {
+ this.maxBlockLightForMonsterSpawning = getInt("monster-spawn-max-light-level", maxBlockLightForMonsterSpawning);
+ }
}
diff --git a/src/main/java/net/minecraft/world/entity/monster/Monster.java b/src/main/java/net/minecraft/world/entity/monster/Monster.java
index 457880c9e894a83d88505cf0b7235df919eea591..1d66588cfe94d190a34dc376b4b5bff9461a3529 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Monster.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Monster.java
@@ -90,7 +90,7 @@ public abstract class Monster extends PathfinderMob implements Enemy {
public static boolean isDarkEnoughToSpawn(ServerLevelAccessor world, BlockPos pos, Random random) {
if (world.getBrightness(LightLayer.SKY, pos) > random.nextInt(32)) {
return false;
- } else if (world.getBrightness(LightLayer.BLOCK, pos) > 0) {
+ } else if (world.getBrightness(LightLayer.BLOCK, pos) > (world.getLevel().paperConfig.maxBlockLightForMonsterSpawning >= 0 ? world.getLevel().paperConfig.maxBlockLightForMonsterSpawning : 0)) { // Paper - configurable max block light level
return false;
} else {
int i = world.getLevel().isThundering() ? world.getMaxLocalRawBrightness(pos, 10) : world.getMaxLocalRawBrightness(pos);

View file

@ -1,85 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Wed, 22 Dec 2021 09:51:48 -0800
Subject: [PATCH] Fix sticky pistons and BlockPistonRetractEvent
There is an explicit check in the handling code for empty pistons that
prevents sticky pistons from firing the event. However when we look back
at the history we see that this check was originally added so that ONLY
sticky pistons would fire the retract event. I'm not sure why.
https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/1092acbddf07edfa4100bc6824504ac75088e913
Over the course of several updates, the meaning of that field appears to
have changed from "is NOT sticky" to "is sticky". So now its having the
opposite effect. Only normal pistons fire the retraction event. And like
all things in CB, it's just been carried around since.
If we are to believe the history, the correct fix for this issue is to
flip it so it only fires for sticky pistons, but that puts us in a
bind. It's already firing for non-sticky pistons, changing it now would
likely result in breakage. Furthermore, there is little documentation as
to WHY that was ever intended to be the case.
Instead we opt to remove the check entirely so that the event fires for
all piston types.
Co-authored-by: Zach Brown <zach@zachbr.io>
Co-authored-by: Madeline Miller <mnmiller1@me.com>
diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
index 322b3119682fbab5e790ce9255e96a519f03143d..2e5803035a46f890e8bfc59908c0040f9a960703 100644
--- a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
@@ -145,15 +145,15 @@ public class PistonBaseBlock extends DirectionalBlock {
}
// CraftBukkit start
- if (!this.isSticky) {
- org.bukkit.block.Block block = world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ());
- BlockPistonRetractEvent event = new BlockPistonRetractEvent(block, ImmutableList.<org.bukkit.block.Block>of(), CraftBlock.notchToBlockFace(enumdirection));
- world.getCraftServer().getPluginManager().callEvent(event);
-
- if (event.isCancelled()) {
- return;
- }
- }
+ // if (!this.isSticky) { // Paper - Move further down
+ // org.bukkit.block.Block block = world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ());
+ // BlockPistonRetractEvent event = new BlockPistonRetractEvent(block, ImmutableList.<org.bukkit.block.Block>of(), CraftBlock.notchToBlockFace(enumdirection));
+ // world.getCraftServer().getPluginManager().callEvent(event);
+ //
+ // if (event.isCancelled()) {
+ // return;
+ // }
+ // }
// PAIL: checkME - what happened to setTypeAndData?
// CraftBukkit end
world.blockEvent(pos, this, b0, enumdirection.get3DDataValue());
@@ -235,6 +235,13 @@ public class PistonBaseBlock extends DirectionalBlock {
BlockState iblockdata1 = (BlockState) ((BlockState) Blocks.MOVING_PISTON.defaultBlockState().setValue(MovingPistonBlock.FACING, enumdirection)).setValue(MovingPistonBlock.TYPE, this.isSticky ? PistonType.STICKY : PistonType.DEFAULT);
+ // Paper start - Move empty piston retract call to fix multiple event fires
+ if (!this.isSticky) {
+ if (!new BlockPistonRetractEvent(CraftBlock.at(world, pos), java.util.Collections.emptyList(), CraftBlock.notchToBlockFace(enumdirection)).callEvent()) {
+ return false;
+ }
+ }
+ // Paper end
world.setBlock(pos, iblockdata1, 20);
world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata1, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); // Paper - diff on change
world.blockUpdated(pos, iblockdata1.getBlock());
@@ -261,6 +268,13 @@ public class PistonBaseBlock extends DirectionalBlock {
if (type == 1 && !iblockdata2.isAir() && PistonBaseBlock.isPushable(iblockdata2, world, blockposition1, enumdirection.getOpposite(), false, enumdirection) && (iblockdata2.getPistonPushReaction() == PushReaction.NORMAL || iblockdata2.is(Blocks.PISTON) || iblockdata2.is(Blocks.STICKY_PISTON))) {
this.moveBlocks(world, pos, enumdirection, false);
} else {
+ // Paper start - fire BlockPistonRetractEvent for sticky pistons retracting nothing (air)
+ if (type == TRIGGER_CONTRACT && iblockdata2.isAir()) {
+ if (!new BlockPistonRetractEvent(CraftBlock.at(world, pos), java.util.Collections.emptyList(), CraftBlock.notchToBlockFace(enumdirection)).callEvent()) {
+ return false;
+ }
+ }
+ // Paper end
world.removeBlock(pos.relative(enumdirection), false);
}
}

View file

@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Tue, 21 Dec 2021 22:13:26 -0800
Subject: [PATCH] Load effect amplifiers greater than 127 correctly
MOJIRA: MC-118857
diff --git a/src/main/java/net/minecraft/world/effect/MobEffectInstance.java b/src/main/java/net/minecraft/world/effect/MobEffectInstance.java
index fefc8a1b5dbdc02f9f3e31055840170b9a6274b9..b84610d00f710c656d9eaf85b80e796f8be4bca3 100644
--- a/src/main/java/net/minecraft/world/effect/MobEffectInstance.java
+++ b/src/main/java/net/minecraft/world/effect/MobEffectInstance.java
@@ -235,7 +235,7 @@ public class MobEffectInstance implements Comparable<MobEffectInstance> {
}
private static MobEffectInstance loadSpecifiedEffect(MobEffect type, CompoundTag nbt) {
- int i = nbt.getByte("Amplifier");
+ int i = Byte.toUnsignedInt(nbt.getByte("Amplifier")); // Paper - correctly load amplifiers > 127
int j = nbt.getInt("Duration");
boolean bl = nbt.getBoolean("Ambient");
boolean bl2 = true;

View file

@ -1,31 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
Date: Thu, 23 Dec 2021 15:32:50 -0600
Subject: [PATCH] Expose isFuel and canSmelt methods to FurnaceInventory
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java
index 05c29a788c96282fc18066ae253cf0b5be37e95c..e8e53d3c7d8b1bba7d77dc0c76d242eb177ad851 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java
@@ -40,6 +40,20 @@ public class CraftInventoryFurnace extends CraftInventory implements FurnaceInve
setItem(0, stack);
}
+ // Paper start
+ @Override
+ public boolean isFuel(ItemStack stack) {
+ return stack != null && !stack.getType().isEmpty() && AbstractFurnaceBlockEntity.isFuel(CraftItemStack.asNMSCopy(stack));
+ }
+
+ @Override
+ public boolean canSmelt(ItemStack stack) {
+ // data packs are always loaded in the main world
+ net.minecraft.server.level.ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorlds().get(0)).getHandle();
+ return stack != null && !stack.getType().isEmpty() && world.getRecipeManager().getRecipeFor(((AbstractFurnaceBlockEntity) this.inventory).recipeType, new net.minecraft.world.SimpleContainer(CraftItemStack.asNMSCopy(stack)), world).isPresent();
+ }
+ // Paper end
+
@Override
public Furnace getHolder() {
return (Furnace) inventory.getOwner();

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, 21 Aug 2021 21:54:16 -0700
Subject: [PATCH] Fix bees aging inside hives
Fixes bees incorrectly being aged up due to upstream's
resetting the ticks inside hive on a failed release
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
index 19127ec5d89235ea9af549810b24783e0af85a3d..483dc52c793d9f90a35b1d091dd8ce71115e4640 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
@@ -325,7 +325,7 @@ public class BeehiveBlockEntity extends BlockEntity {
for (Iterator iterator = bees.iterator(); iterator.hasNext(); ++tileentitybeehive_hivebee.ticksInHive) {
tileentitybeehive_hivebee = (BeehiveBlockEntity.BeeData) iterator.next();
- if (tileentitybeehive_hivebee.ticksInHive > tileentitybeehive_hivebee.minOccupationTicks) {
+ if (tileentitybeehive_hivebee.exitTickCounter > tileentitybeehive_hivebee.minOccupationTicks) { // Paper - use exitTickCounter
BeehiveBlockEntity.BeeReleaseStatus tileentitybeehive_releasestatus = tileentitybeehive_hivebee.entityData.getBoolean("HasNectar") ? BeehiveBlockEntity.BeeReleaseStatus.HONEY_DELIVERED : BeehiveBlockEntity.BeeReleaseStatus.BEE_RELEASED;
if (BeehiveBlockEntity.releaseOccupant(world, pos, state, tileentitybeehive_hivebee, (List) null, tileentitybeehive_releasestatus, flowerPos)) {
@@ -333,10 +333,11 @@ public class BeehiveBlockEntity extends BlockEntity {
iterator.remove();
// CraftBukkit start
} else {
- tileentitybeehive_hivebee.ticksInHive = tileentitybeehive_hivebee.minOccupationTicks / 2; // Not strictly Vanilla behaviour in cases where bees cannot spawn but still reasonable
+ tileentitybeehive_hivebee.exitTickCounter = tileentitybeehive_hivebee.minOccupationTicks / 2; // Not strictly Vanilla behaviour in cases where bees cannot spawn but still reasonable // Paper - use exitTickCounter to keep actual bee life
// CraftBukkit end
}
}
+ tileentitybeehive_hivebee.exitTickCounter++; // Paper
}
if (flag) {
@@ -425,12 +426,14 @@ public class BeehiveBlockEntity extends BlockEntity {
final CompoundTag entityData;
int ticksInHive;
+ int exitTickCounter; // Paper - separate counter for checking if bee should exit to reduce exit attempts
final int minOccupationTicks;
BeeData(CompoundTag entityData, int ticksInHive, int minOccupationTicks) {
BeehiveBlockEntity.removeIgnoredBeeTags(entityData);
this.entityData = entityData;
this.ticksInHive = ticksInHive;
+ this.exitTickCounter = ticksInHive; // Paper
this.minOccupationTicks = minOccupationTicks;
}
}

View file

@ -1,69 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Sun, 26 Dec 2021 14:03:17 -0500
Subject: [PATCH] Bucketable API
diff --git a/src/main/java/io/papermc/paper/entity/PaperBucketable.java b/src/main/java/io/papermc/paper/entity/PaperBucketable.java
new file mode 100644
index 0000000000000000000000000000000000000000..c4eee682f5b8cd82f71f92f0549f39b76e735cd8
--- /dev/null
+++ b/src/main/java/io/papermc/paper/entity/PaperBucketable.java
@@ -0,0 +1,31 @@
+package io.papermc.paper.entity;
+
+import org.bukkit.Sound;
+import org.bukkit.craftbukkit.CraftSound;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.inventory.ItemStack;
+
+public interface PaperBucketable extends Bucketable {
+
+ net.minecraft.world.entity.animal.Bucketable getHandle();
+
+ @Override
+ default boolean isFromBucket() {
+ return this.getHandle().fromBucket();
+ }
+
+ @Override
+ default void setFromBucket(boolean fromBucket) {
+ this.getHandle().setFromBucket(fromBucket);
+ }
+
+ @Override
+ default ItemStack getBaseBucketItem() {
+ return CraftItemStack.asBukkitCopy(this.getHandle().getBucketItemStack());
+ }
+
+ @Override
+ default Sound getPickupSound() {
+ return CraftSound.getBukkit(this.getHandle().getPickupSound());
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java
index cd751a13a29c34be1d084253f19bf2dce8399d01..cdaf860ec1b84c4ad9f2345968786d878f483f74 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java
@@ -5,7 +5,7 @@ import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.Axolotl;
import org.bukkit.entity.EntityType;
-public class CraftAxolotl extends CraftAnimals implements Axolotl {
+public class CraftAxolotl extends CraftAnimals implements Axolotl, io.papermc.paper.entity.PaperBucketable { // Paper - Bucketable API
public CraftAxolotl(CraftServer server, net.minecraft.world.entity.animal.axolotl.Axolotl entity) {
super(server, entity);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java
index 69d103a8ec74b17ee3116bb4d448494bd66f50b6..3c64461119391ec2e987fc936104e21ef0a95ce4 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java
@@ -4,7 +4,7 @@ import net.minecraft.world.entity.animal.AbstractFish;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.Fish;
-public class CraftFish extends CraftWaterMob implements Fish {
+public class CraftFish extends CraftWaterMob implements Fish, io.papermc.paper.entity.PaperBucketable { // Paper - Bucketable API
public CraftFish(CraftServer server, AbstractFish entity) {
super(server, entity);

View file

@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: lexikiq <noellekiq@gmail.com>
Date: Sat, 17 Jul 2021 20:37:02 -0400
Subject: [PATCH] Check player world in endPortalSoundRadius
Fixes Spigot's endPortalSoundRadius not checking player worlds
diff --git a/src/main/java/net/minecraft/world/item/EnderEyeItem.java b/src/main/java/net/minecraft/world/item/EnderEyeItem.java
index beb3713937470d7c5d8cadce3f3a823ca48d3726..d9c20eca27382e89ddb13f1c8e84348242ca6ceb 100644
--- a/src/main/java/net/minecraft/world/item/EnderEyeItem.java
+++ b/src/main/java/net/minecraft/world/item/EnderEyeItem.java
@@ -66,7 +66,7 @@ public class EnderEyeItem extends Item {
double deltaX = soundPos.getX() - player.getX();
double deltaZ = soundPos.getZ() - player.getZ();
double distanceSquared = deltaX * deltaX + deltaZ * deltaZ;
- if (world.spigotConfig.endPortalSoundRadius > 0 && distanceSquared > world.spigotConfig.endPortalSoundRadius * world.spigotConfig.endPortalSoundRadius) continue; // Spigot
+ if (world.spigotConfig.endPortalSoundRadius > 0 && (distanceSquared > world.spigotConfig.endPortalSoundRadius * world.spigotConfig.endPortalSoundRadius || player.getLevel() != world)) continue; // Spigot // Paper - ensure recipient is in same world as portal
if (distanceSquared > viewDistance * viewDistance) {
double deltaLength = Math.sqrt(distanceSquared);
double relativeX = player.getX() + (deltaX / deltaLength) * viewDistance;

View file

@ -1,88 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sat, 1 Jan 2022 05:19:37 -0800
Subject: [PATCH] Validate usernames
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index 9e01ee1776a02dd7be0a47ac3a06e69968d26bdc..94a96c34e207a84a7c9226e9255beb6d0371f068 100644
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
@@ -495,6 +495,12 @@ public class PaperConfig {
set("settings.unsupported-settings.allow-tnt-duplication", null);
}
+ public static boolean performUsernameValidation;
+ private static void performUsernameValidation() {
+ performUsernameValidation = getBoolean("settings.unsupported-settings.perform-username-validation", true);
+ }
+
+
public static int playerAutoSaveRate = -1;
public static int maxPlayerAutoSavePerTick = 10;
private static void playerAutoSaveRate() {
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
index f5c1dff1d571e89f960f11400edbcbbea0620575..7065aa4522431d08018fec8e591ba7c255398140 100644
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -61,6 +61,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener
private ServerPlayer delayedAcceptPlayer;
public String hostname = ""; // CraftBukkit - add field
private int velocityLoginMessageId = -1; // Paper - Velocity support
+ public boolean iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation = false; // Paper - username validation overriding
public ServerLoginPacketListenerImpl(MinecraftServer server, Connection connection) {
this.state = ServerLoginPacketListenerImpl.State.HELLO;
@@ -226,11 +227,39 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener
// Paper end
}
+ // Paper start - validate usernames
+ public static boolean validateUsername(String in) {
+ if (in == null || in.isEmpty() || in.length() > 16) {
+ return false;
+ }
+
+ for (int i = 0, len = in.length(); i < len; ++i) {
+ char c = in.charAt(i);
+
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_' || c == '.')) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+ // Paper end - validate usernames
+
@Override
public void handleHello(ServerboundHelloPacket packet) {
Validate.validState(this.state == ServerLoginPacketListenerImpl.State.HELLO, "Unexpected hello packet", new Object[0]);
this.gameProfile = packet.getGameProfile();
Validate.validState(ServerLoginPacketListenerImpl.isValidUsername(this.gameProfile.getName()), "Invalid characters in username", new Object[0]);
+ // Paper start - validate usernames
+ if (com.destroystokyo.paper.PaperConfig.isProxyOnlineMode() && com.destroystokyo.paper.PaperConfig.performUsernameValidation) {
+ if (!this.iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation && !validateUsername(this.gameProfile.getName())) {
+ ServerLoginPacketListenerImpl.this.disconnect("Failed to verify username!");
+ return;
+ }
+ }
+ // Paper end - validate usernames
if (this.server.usesAuthentication() && !this.connection.isMemoryConnection()) {
this.state = ServerLoginPacketListenerImpl.State.KEY;
this.connection.send(new ClientboundHelloPacket("", this.server.getKeyPair().getPublic().getEncoded(), this.nonce));
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index bb4e844c77c76eb893c55844c5a814ccd337b7f4..32f710e52da781ed9a0df8249a9ca79f1804b24a 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -707,7 +707,7 @@ public abstract class PlayerList {
for (int i = 0; i < this.players.size(); ++i) {
entityplayer = (ServerPlayer) this.players.get(i);
- if (entityplayer.getUUID().equals(uuid)) {
+ if (entityplayer.getUUID().equals(uuid) || (com.destroystokyo.paper.PaperConfig.isProxyOnlineMode() && entityplayer.getGameProfile().getName().equalsIgnoreCase(gameprofile.getName()))) { // Paper - validate usernames
list.add(entityplayer);
}
}

View file

@ -1,50 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Brokkonaut <hannos17@gmx.de>
Date: Sat, 18 Dec 2021 08:26:55 +0100
Subject: [PATCH] Make water animal spawn height configurable
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index b2d9dbf4e006899a932bd6bed40228d4f744d865..100de7e366c4ea8ce158b0fc0258e4db0ee83249 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -426,6 +426,24 @@ public class PaperWorldConfig {
mobSpawnerTickRate = getInt("mob-spawner-tick-rate", 1);
}
+ public Integer waterAnimalMaxSpawnHeight;
+ private void waterAnimalMaxSpawnHeight() {
+ String v = getString("wateranimal-spawn-height.maximum", "default");
+ try {
+ waterAnimalMaxSpawnHeight = Integer.parseInt(v);
+ } catch (NumberFormatException ignored) {
+ }
+ }
+
+ public Integer waterAnimalMinSpawnHeight;
+ private void waterAnimalMinSpawnHeight() {
+ String v = getString("wateranimal-spawn-height.minimum", "default");
+ try {
+ waterAnimalMinSpawnHeight = Integer.parseInt(v);
+ } catch (NumberFormatException ignored) {
+ }
+ }
+
public int containerUpdateTickRate;
private void containerUpdateTickRate() {
containerUpdateTickRate = getInt("container-update-tick-rate", 1);
diff --git a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java
index 69f7e034cab1bfd7ca5dffc660b6decd739adf35..c039b896ee85543c26a8ab76640080f539deaa4c 100644
--- a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java
+++ b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java
@@ -79,6 +79,10 @@ public abstract class WaterAnimal extends PathfinderMob {
public static boolean checkSurfaceWaterAnimalSpawnRules(EntityType<? extends WaterAnimal> type, LevelAccessor world, MobSpawnType reason, BlockPos pos, Random random) {
int i = world.getSeaLevel();
int j = i - 13;
+ // Paper start
+ i = world.getMinecraftWorld().paperConfig.waterAnimalMaxSpawnHeight != null ? world.getMinecraftWorld().paperConfig.waterAnimalMaxSpawnHeight : i;
+ j = world.getMinecraftWorld().paperConfig.waterAnimalMinSpawnHeight != null ? world.getMinecraftWorld().paperConfig.waterAnimalMinSpawnHeight : j;
+ // Paper end
return pos.getY() >= j && pos.getY() <= i && world.getFluidState(pos.below()).is(FluidTags.WATER) && world.getBlockState(pos.above()).is(Blocks.WATER);
}
}

View file

@ -1,126 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Thu, 6 Jan 2022 15:59:06 -0800
Subject: [PATCH] Expose vanilla BiomeProvider from WorldInfo
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index df955666723a8cb1e612311f0b8e77fb577d6be5..01aefce226ae82d707b38b0d56d2580d411a3c9a 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -582,7 +582,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
chunkgenerator = worlddimension.generator();
}
- org.bukkit.generator.WorldInfo worldInfo = new org.bukkit.craftbukkit.generator.CraftWorldInfo(iworlddataserver, worldSession, org.bukkit.World.Environment.getEnvironment(dimension), holder.value());
+ org.bukkit.generator.WorldInfo worldInfo = new org.bukkit.craftbukkit.generator.CraftWorldInfo(iworlddataserver, worldSession, org.bukkit.World.Environment.getEnvironment(dimension), holder.value(), chunkgenerator, this.registryAccess().registryOrThrow(net.minecraft.core.Registry.BIOME_REGISTRY)); // Paper
if (biomeProvider == null && gen != null) {
biomeProvider = gen.getDefaultBiomeProvider(worldInfo);
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 8769e15a395b1c6e72f3e4a7f96b8c90c34e7569..b4133f8dde5edb75b8d2d1008c50db7810276913 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1217,7 +1217,7 @@ public final class CraftServer implements Server {
chunkgenerator = worlddimension.generator();
}
- WorldInfo worldInfo = new CraftWorldInfo(worlddata, worldSession, creator.environment(), holder.value());
+ WorldInfo worldInfo = new CraftWorldInfo(worlddata, worldSession, creator.environment(), holder.value(), chunkgenerator, this.getHandle().getServer().registryAccess().registryOrThrow(net.minecraft.core.Registry.BIOME_REGISTRY)); // Paper
if (biomeProvider == null && generator != null) {
biomeProvider = generator.getDefaultBiomeProvider(worldInfo);
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index f05ff9891d59cd7ae4e37c05c690dda0c75962fe..925907eff49e26cac48e895f44c55f80b9a6f81e 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -195,6 +195,31 @@ public class CraftWorld extends CraftRegionAccessor implements World {
public int getPlayerCount() {
return world.players().size();
}
+
+ @Override
+ public BiomeProvider vanillaBiomeProvider() {
+ final net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator;
+ if (this.getHandle().chunkSource.getGenerator() instanceof org.bukkit.craftbukkit.generator.CustomChunkGenerator bukkit) {
+ chunkGenerator = bukkit.delegate;
+ } else {
+ chunkGenerator = this.getHandle().chunkSource.getGenerator();
+ }
+ final net.minecraft.core.Registry<net.minecraft.world.level.biome.Biome> biomeRegistry = this.getHandle().registryAccess().registryOrThrow(net.minecraft.core.Registry.BIOME_REGISTRY);
+ final List<Biome> possibleBiomes = chunkGenerator.getBiomeSource().possibleBiomes().stream()
+ .map(biome -> CraftBlock.biomeBaseToBiome(biomeRegistry, biome))
+ .toList();
+ return new BiomeProvider() {
+ @Override
+ public Biome getBiome(final org.bukkit.generator.WorldInfo worldInfo, final int x, final int y, final int z) {
+ return CraftBlock.biomeBaseToBiome(biomeRegistry, chunkGenerator.getNoiseBiome(x >> 2, y >> 2, z >> 2));
+ }
+
+ @Override
+ public List<Biome> getBiomes(final org.bukkit.generator.WorldInfo worldInfo) {
+ return possibleBiomes;
+ }
+ };
+ }
// Paper end
private static final Random rand = new Random();
diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java
index aeffb30cd91d4b21850059d33070c537bd5cb25e..3918c24dfb6cda4cff18016cca807c2dbc2a9156 100644
--- a/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java
+++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java
@@ -17,8 +17,17 @@ public class CraftWorldInfo implements WorldInfo {
private final long seed;
private final int minHeight;
private final int maxHeight;
+ // Paper start
+ private final net.minecraft.world.level.chunk.ChunkGenerator vanillaChunkGenerator;
+ private final net.minecraft.core.Registry<net.minecraft.world.level.biome.Biome> biomeRegistry;
public CraftWorldInfo(ServerLevelData worldDataServer, LevelStorageSource.LevelStorageAccess session, World.Environment environment, DimensionType dimensionManager) {
+ this(worldDataServer, session, environment, dimensionManager, null, null);
+ }
+ public CraftWorldInfo(ServerLevelData worldDataServer, LevelStorageSource.LevelStorageAccess session, World.Environment environment, DimensionType dimensionManager, net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator, net.minecraft.core.Registry<net.minecraft.world.level.biome.Biome> biomeRegistry) {
+ this.biomeRegistry = biomeRegistry;
+ this.vanillaChunkGenerator = chunkGenerator;
+ // Paper end
this.name = worldDataServer.getLevelName();
this.uuid = WorldUUID.getUUID(session.levelPath.toFile());
this.environment = environment;
@@ -28,6 +37,10 @@ public class CraftWorldInfo implements WorldInfo {
}
public CraftWorldInfo(String name, UUID uuid, World.Environment environment, long seed, int minHeight, int maxHeight) {
+ // Paper start
+ this.vanillaChunkGenerator = null;
+ this.biomeRegistry = null;
+ // Paper end
this.name = name;
this.uuid = uuid;
this.environment = environment;
@@ -65,4 +78,24 @@ public class CraftWorldInfo implements WorldInfo {
public int getMaxHeight() {
return this.maxHeight;
}
+
+ // Paper start
+ @Override
+ public org.bukkit.generator.BiomeProvider vanillaBiomeProvider() {
+ final java.util.List<org.bukkit.block.Biome> possibleBiomes = CraftWorldInfo.this.vanillaChunkGenerator.getBiomeSource().possibleBiomes().stream()
+ .map(biome -> org.bukkit.craftbukkit.block.CraftBlock.biomeBaseToBiome(CraftWorldInfo.this.biomeRegistry, biome))
+ .toList();
+ return new org.bukkit.generator.BiomeProvider() {
+ @Override
+ public org.bukkit.block.Biome getBiome(final WorldInfo worldInfo, final int x, final int y, final int z) {
+ return org.bukkit.craftbukkit.block.CraftBlock.biomeBaseToBiome(CraftWorldInfo.this.biomeRegistry, CraftWorldInfo.this.vanillaChunkGenerator.getNoiseBiome(x >> 2, y >> 2, z >> 2));
+ }
+
+ @Override
+ public java.util.List<org.bukkit.block.Biome> getBiomes(final org.bukkit.generator.WorldInfo worldInfo) {
+ return possibleBiomes;
+ }
+ };
+ }
+ // Paper end
}

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, 2 Jan 2022 22:34:51 -0800
Subject: [PATCH] Add config option for worlds affected by time cmd
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index 94a96c34e207a84a7c9226e9255beb6d0371f068..318e28b5e93b6842d48745ec53bcc25dbfeaff72 100644
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
@@ -647,4 +647,9 @@ public class PaperConfig {
private static void sendFullPosForHardCollidingEntities() {
sendFullPosForHardCollidingEntities = getBoolean("settings.send-full-pos-for-hard-colliding-entities", true);
}
+
+ public static boolean timeCommandAffectsAllWorlds = false; // See https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/aeaeb359317e6ba25b7c45cf6d70ff945a3777cf
+ private static void timeCommandAffectsAllWorlds() {
+ timeCommandAffectsAllWorlds = getBoolean("settings.time-command-affects-all-worlds", timeCommandAffectsAllWorlds);
+ }
}
diff --git a/src/main/java/net/minecraft/server/commands/TimeCommand.java b/src/main/java/net/minecraft/server/commands/TimeCommand.java
index ad4860bf64979e6b10bc6aecc4ac67a5c069e030..da854c5bfaf9e791b272a497caf864748f3dfbda 100644
--- a/src/main/java/net/minecraft/server/commands/TimeCommand.java
+++ b/src/main/java/net/minecraft/server/commands/TimeCommand.java
@@ -51,7 +51,7 @@ public class TimeCommand {
}
public static int setTime(CommandSourceStack source, int time) {
- Iterator iterator = com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in
+ Iterator iterator = com.destroystokyo.paper.PaperConfig.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels().iterator() : com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change
while (iterator.hasNext()) {
ServerLevel worldserver = (ServerLevel) iterator.next();
@@ -70,7 +70,7 @@ public class TimeCommand {
}
public static int addTime(CommandSourceStack source, int time) {
- Iterator iterator = com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in
+ Iterator iterator = com.destroystokyo.paper.PaperConfig.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels().iterator() : com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change
while (iterator.hasNext()) {
ServerLevel worldserver = (ServerLevel) iterator.next();