more more more more more more more work

can't let lynx inflate his commit count too much
This commit is contained in:
Noah van der Aa 2023-09-22 16:58:35 +02:00
parent 2617c927a0
commit 772fb3e385
No known key found for this signature in database
GPG key ID: 547D90BC6FF753CF
32 changed files with 116 additions and 116 deletions

View file

@ -1,61 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Noah van der Aa <ndvdaa@gmail.com>
Date: Tue, 5 Oct 2021 20:04:21 +0200
Subject: [PATCH] Add config option for logging player ip addresses
diff --git a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
index 21393ad40095a4049e5b6871169b2db7aa92d13c..e6553b936dac1eb25a310d1a33acb0b1a5e646d2 100644
--- a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
+++ b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
@@ -185,7 +185,7 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter {
buf.release();
this.buf = null;
- LOGGER.debug("Ping: (1.6) from {}", ctx.channel().remoteAddress());
+ LOGGER.debug("Ping: (1.6) from {}", io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? ctx.channel().remoteAddress() : "<ip address withheld>"); // Paper
InetSocketAddress virtualHost = com.destroystokyo.paper.network.PaperNetworkClient.prepareVirtualHost(host, port);
com.destroystokyo.paper.event.server.PaperServerListPingEvent event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest(
diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
index e5e2f763d9b4b955df79ea0c4c79565be1fe59f0..2beddfc0532c3835d50724551e3d46cb0d7d2290 100644
--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
@@ -207,7 +207,7 @@ public class ServerConnectionListener {
throw new ReportedException(CrashReport.forThrowable(exception, "Ticking memory connection"));
}
- ServerConnectionListener.LOGGER.warn("Failed to handle packet for {}", networkmanager.getRemoteAddress(), exception);
+ ServerConnectionListener.LOGGER.warn("Failed to handle packet for {}", io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? String.valueOf(networkmanager.getRemoteAddress()) : "<ip address withheld>", exception); // Paper
MutableComponent ichatmutablecomponent = Component.literal("Internal server error");
networkmanager.send(new ClientboundDisconnectPacket(ichatmutablecomponent), PacketSendListener.thenRun(() -> {
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
index 595779cfd0ee1c405d7936f00a7cae1706125e7f..ed3af916dfa875dd0a5f1e730d20d11efd6419c6 100644
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -206,7 +206,10 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
}
public String getUserName() {
- return this.gameProfile != null ? this.gameProfile + " (" + this.connection.getRemoteAddress() + ")" : String.valueOf(this.connection.getRemoteAddress());
+ // Paper start
+ String ip = io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? String.valueOf(this.connection.getRemoteAddress()) : "<ip address withheld>";
+ return this.gameProfile != null ? this.gameProfile + " (" + ip + ")" : String.valueOf(ip);
+ // Paper end
}
@Override
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index c3fb1bbc0e2a44160e86b5bb4ab88f78991fa9e6..ffa831673805201932c36b814f4439f3bb5c4c04 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -255,7 +255,7 @@ public abstract class PlayerList {
String s1 = "local";
if (connection.getRemoteAddress() != null) {
- s1 = connection.getRemoteAddress().toString();
+ s1 = io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? connection.getRemoteAddress().toString() : "<ip address withheld>"; // Paper
}
// Spigot start - spawn location event

View file

@ -1,40 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <nassim@njahnke.dev>
Date: Tue, 31 Aug 2021 17:05:27 +0200
Subject: [PATCH] Configurable feature seeds
Co-authored-by: Thonk <30448663+ExcessiveAmountsOfZombies@users.noreply.github.com>
diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java
index 1080e1f67afe5574baca0df50cdb1d029a7a586a..a2f71a6d1a9e98133dff6cd0f625da9435a8af14 100644
--- a/src/main/java/co/aikar/timings/TimingsExport.java
+++ b/src/main/java/co/aikar/timings/TimingsExport.java
@@ -288,7 +288,7 @@ public class TimingsExport extends Thread {
JSONObject object = new JSONObject();
for (String key : config.getKeys(false)) {
String fullKey = (parentKey != null ? parentKey + "." + key : key);
- if (fullKey.equals("database") || fullKey.equals("settings.bungeecord-addresses") || TimingsManager.hiddenConfigs.contains(fullKey) || key.startsWith("seed-") || key.equals("worldeditregentempworld")) {
+ if (fullKey.equals("database") || fullKey.equals("settings.bungeecord-addresses") || TimingsManager.hiddenConfigs.contains(fullKey) || key.startsWith("seed-") || key.equals("worldeditregentempworld") || key.equals("feature-seeds")) {
continue;
}
final Object val = config.get(key);
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
index 3c7920721914588a3e7eaf1faff46f7305823416..eee2239cd715d01c5adbf1cd79282e115f42cd2e 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
@@ -431,7 +431,14 @@ public abstract class ChunkGenerator {
return (String) optional.orElseGet(placedfeature::toString);
};
- seededrandom.setFeatureSeed(i, l1, l);
+ // Paper start - change populationSeed used in random
+ long featurePopulationSeed = i;
+ final long configFeatureSeed = generatoraccessseed.getMinecraftWorld().paperConfig().featureSeeds.features.getLong(placedfeature.feature());
+ if (configFeatureSeed != -1) {
+ featurePopulationSeed = seededrandom.setDecorationSeed(configFeatureSeed, blockposition.getX(), blockposition.getZ()); // See seededrandom.setDecorationSeed from above
+ }
+ seededrandom.setFeatureSeed(featurePopulationSeed, l1, l);
+ // Paper end
try {
generatoraccessseed.setCurrentlyGenerating(supplier1);

View file

@ -1,79 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: egg82 <eggys82@gmail.com>
Date: Sat, 11 Sep 2021 22:55:14 +0200
Subject: [PATCH] Add root/admin user detection
This patch detects whether or not the server is currently executing as a privileged user and spits out a warning.
The warning serves as a sort-of PSA for newer server admins who don't understand the risks of running as root.
We've seen plenty of bad/malicious plugins hit markets, and there's been a few close-calls with exploits in the past.
Hopefully this helps mitigate some potential damage to servers, even if it is just a warning.
Co-authored-by: Noah van der Aa <ndvdaa@gmail.com>
diff --git a/src/main/java/io/papermc/paper/util/ServerEnvironment.java b/src/main/java/io/papermc/paper/util/ServerEnvironment.java
new file mode 100644
index 0000000000000000000000000000000000000000..6bd0afddbcc461149dfe9a5c7a86fff6ea13a5f1
--- /dev/null
+++ b/src/main/java/io/papermc/paper/util/ServerEnvironment.java
@@ -0,0 +1,40 @@
+package io.papermc.paper.util;
+
+import com.sun.security.auth.module.NTSystem;
+import com.sun.security.auth.module.UnixSystem;
+import org.apache.commons.lang.SystemUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Set;
+
+public class ServerEnvironment {
+ private static final boolean RUNNING_AS_ROOT_OR_ADMIN;
+ private static final String WINDOWS_HIGH_INTEGRITY_LEVEL = "S-1-16-12288";
+
+ static {
+ if (SystemUtils.IS_OS_WINDOWS) {
+ RUNNING_AS_ROOT_OR_ADMIN = Set.of(new NTSystem().getGroupIDs()).contains(WINDOWS_HIGH_INTEGRITY_LEVEL);
+ } else {
+ boolean isRunningAsRoot = false;
+ if (new UnixSystem().getUid() == 0) {
+ // Due to an OpenJDK bug (https://bugs.openjdk.java.net/browse/JDK-8274721), UnixSystem#getUid incorrectly
+ // returns 0 when the user doesn't have a username. Because of this, we'll have to double-check if the user ID is
+ // actually 0 by running the id -u command.
+ try {
+ Process process = new ProcessBuilder("id", "-u").start();
+ process.waitFor();
+ InputStream inputStream = process.getInputStream();
+ isRunningAsRoot = new String(inputStream.readAllBytes()).trim().equals("0");
+ } catch (InterruptedException | IOException ignored) {
+ isRunningAsRoot = false;
+ }
+ }
+ RUNNING_AS_ROOT_OR_ADMIN = isRunningAsRoot;
+ }
+ }
+
+ public static boolean userIsRootOrAdmin() {
+ return RUNNING_AS_ROOT_OR_ADMIN;
+ }
+}
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index 7d917aa8376fed8004f30e92bf88face17165a92..c9a6847b4eb29b8d0ed68741b5e6055de02d1e83 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -179,6 +179,16 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
DedicatedServer.LOGGER.warn("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\"");
}
+ // Paper start - detect running as root
+ if (io.papermc.paper.util.ServerEnvironment.userIsRootOrAdmin()) {
+ DedicatedServer.LOGGER.warn("****************************");
+ DedicatedServer.LOGGER.warn("YOU ARE RUNNING THIS SERVER AS AN ADMINISTRATIVE OR ROOT USER. THIS IS NOT ADVISED.");
+ DedicatedServer.LOGGER.warn("YOU ARE OPENING YOURSELF UP TO POTENTIAL RISKS WHEN DOING THIS.");
+ DedicatedServer.LOGGER.warn("FOR MORE INFORMATION, SEE https://madelinemiller.dev/blog/root-minecraft-server/");
+ DedicatedServer.LOGGER.warn("****************************");
+ }
+ // Paper end
+
DedicatedServer.LOGGER.info("Loading properties");
DedicatedServerProperties dedicatedserverproperties = this.settings.getProperties();

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Mon, 21 Jun 2021 22:12:53 -0400
Subject: [PATCH] Always allow item changing in Fireball
diff --git a/src/main/java/net/minecraft/world/entity/projectile/Fireball.java b/src/main/java/net/minecraft/world/entity/projectile/Fireball.java
index 307f545b79f01e22b1ffa9e41a0d353b3fa6a21d..58ea1fdc8dd5eb48d9642edecbbba1751e7037b6 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/Fireball.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/Fireball.java
@@ -27,7 +27,7 @@ public abstract class Fireball extends AbstractHurtingProjectile implements Item
}
public void setItem(ItemStack stack) {
- if (!stack.is(Items.FIRE_CHARGE) || stack.hasTag()) {
+ if (true || !stack.is(Items.FIRE_CHARGE) || stack.hasTag()) { // Paper - always allow item changing
this.getEntityData().set(Fireball.DATA_ITEM_STACK, stack.copyWithCount(1));
}

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: sulu5890 <sulu@sulu.me>
Date: Sun, 24 Oct 2021 22:48:14 -0500
Subject: [PATCH] don't attempt to teleport dead entities
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 61a3f7984e798191c74e85a514ca1ecde70e03ba..f1d9b75eae4d42c02974c8bface6d73cb1e58182 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -787,7 +787,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
// CraftBukkit start
public void postTick() {
// No clean way to break out of ticking once the entity has been copied to a new world, so instead we move the portalling later in the tick cycle
- if (!(this instanceof ServerPlayer)) {
+ if (!(this instanceof ServerPlayer) && this.isAlive()) { // Paper - don't attempt to teleport dead entities
this.handleNetherPortal();
}
}

View file

@ -1,37 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <nassim@njahnke.dev>
Date: Thu, 25 Nov 2021 10:25:09 +0100
Subject: [PATCH] Prevent excessive velocity through repeated crits
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 4e368756efce3cb31bd88a2145a97b00366fa977..b9c3e19feb29a4a67fe78cd5d5b0cca7b570d2de 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -2648,13 +2648,26 @@ public abstract class LivingEntity extends Entity implements Attackable {
return this.hasEffect(MobEffects.JUMP) ? 0.1F * ((float) this.getEffect(MobEffects.JUMP).getAmplifier() + 1.0F) : 0.0F;
}
+ protected long lastJumpTime = 0L; // Paper
protected void jumpFromGround() {
Vec3 vec3d = this.getDeltaMovement();
+ // Paper start
+ long time = System.nanoTime();
+ boolean canCrit = true;
+ if (this instanceof net.minecraft.world.entity.player.Player) {
+ canCrit = false;
+ if (time - this.lastJumpTime > (long)(0.250e9)) {
+ this.lastJumpTime = time;
+ canCrit = true;
+ }
+ }
+ // Paper end
this.setDeltaMovement(vec3d.x, (double) this.getJumpPower(), vec3d.z);
if (this.isSprinting()) {
float f = this.getYRot() * 0.017453292F;
+ if (canCrit) // Paper
this.setDeltaMovement(this.getDeltaMovement().add((double) (-Mth.sin(f) * 0.2F), 0.0D, (double) (Mth.cos(f) * 0.2F)));
}

View file

@ -1,31 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Fri, 26 Nov 2021 15:09:58 -0800
Subject: [PATCH] Remove client-side code using deprecated for removal
AccessController
Fixes warnings on build
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
index fcade0a121f155dbf4f5f8af66240923d8da460d..c60c73d9f998260f3abe6fe445255c6e7c38b0c3 100644
--- a/src/main/java/net/minecraft/Util.java
+++ b/src/main/java/net/minecraft/Util.java
@@ -909,17 +909,7 @@ public class Util {
}
public void openUrl(URL url) {
- try {
- Process process = AccessController.doPrivileged((PrivilegedExceptionAction<Process>)(() -> {
- return Runtime.getRuntime().exec(this.getOpenUrlArguments(url));
- }));
- process.getInputStream().close();
- process.getErrorStream().close();
- process.getOutputStream().close();
- } catch (IOException | PrivilegedActionException var3) {
- Util.LOGGER.error("Couldn't open url '{}'", url, var3);
- }
-
+ throw new IllegalStateException("This method is not useful on dedicated servers."); // Paper
}
public void openUri(URI uri) {

View file

@ -1,50 +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
== AT ==
public net.minecraft.world.item.crafting.RecipeManager byName
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java b/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java
index f12a93544313065fc9dc2a87063688aef79d3d96..548c3b288f2b3b711e1a75f1fc0d1e9713f47bcf 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java
@@ -12,6 +12,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();
@@ -35,15 +36,27 @@ 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
public void remove() {
Preconditions.checkState(this.current != null, "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 <nassim@njahnke.dev>
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 97da8896865ff0bdd4fe8f2155b0830b42051bb1..9ca897d92c5bdd2764d114c74d64c776674d6beb 100644
--- a/src/main/java/net/minecraft/network/syncher/EntityDataSerializers.java
+++ b/src/main/java/net/minecraft/network/syncher/EntityDataSerializers.java
@@ -42,7 +42,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, true)); // 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 e7c0d214abbad1f300049f790ae54e7ea488e150..24f0d61a2fa9ac95dd26443a978209b53baf10b1 100644
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
@@ -338,7 +338,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 b9c3e19feb29a4a67fe78cd5d5b0cca7b570d2de..de69507b71c79172f0581aa58a7ac7e9a002444f 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3157,7 +3157,10 @@ public abstract class LivingEntity extends Entity implements Attackable {
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);
@@ -3170,6 +3173,34 @@ public abstract class LivingEntity extends Entity implements Attackable {
((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,118 +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/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
index 24f0d61a2fa9ac95dd26443a978209b53baf10b1..31fa0f4fbf195d0db7a89a060b1cc4fd30dc5ab0 100644
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
@@ -340,7 +340,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/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 31c8b483006febd23363f7bcc2c09bde37b84847..81750c1551a69d1c77ab8c34437e5d839b7e2941 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2693,8 +2693,8 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
// Refresh the current entity metadata
entity.getEntityData().refresh(player);
// SPIGOT-7136 - Allays
- if (entity instanceof Allay) {
- ServerGamePacketListenerImpl.this.send(new ClientboundSetEquipmentPacket(entity.getId(), Arrays.stream(net.minecraft.world.entity.EquipmentSlot.values()).map((slot) -> Pair.of(slot, ((LivingEntity) entity).getItemBySlot(slot).copy())).collect(Collectors.toList())));
+ if (entity instanceof Allay allay) { // Paper
+ ServerGamePacketListenerImpl.this.send(new ClientboundSetEquipmentPacket(entity.getId(), Arrays.stream(net.minecraft.world.entity.EquipmentSlot.values()).map((slot) -> Pair.of(slot, allay.stripMeta(allay.getItemBySlot(slot), true))).collect(Collectors.toList()))); // Paper - remove unnecessary item meta
player.containerMenu.sendAllDataToRemote();
}
}
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index de69507b71c79172f0581aa58a7ac7e9a002444f..a35e59544786776391ba135f247ac1a28be3d754 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3159,7 +3159,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
// 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:
@@ -3173,6 +3173,70 @@ public abstract class LivingEntity extends Entity implements Attackable {
((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 (this.level().paperConfig().anticheat.obfuscation.items.hideDurability) {
+ // 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);
+ }
+ }
+
+ final CompoundTag tag = copy.getTag();
+ if (this.level().paperConfig().anticheat.obfuscation.items.hideItemmeta) {
+ // 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.
+ 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");
+ }
+ }
+
+ if (this.level().paperConfig().anticheat.obfuscation.items.hideItemmetaWithVisualEffects && tag != null) {
+ // Lodestone compasses
+ tag.remove("LodestonePos");
+ if (tag.contains("LodestoneDimension")) {
+ // The client shows the glint if either the position or the dimension is present, so we just wipe
+ // the position and fake the dimension
+ tag.putString("LodestoneDimension", "paper:paper");
+ }
+ }
+
+ 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,140 +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 Spigot growth modifiers
Fixes kelp modifier changing growth for other crops
Also add growth modifiers for glow berries, mangrove propagules,
torchflower crops and pitcher plant crops
Also fix above-mentioned modifiers from having the reverse effect
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
Co-authored-by: Noah van der Aa <ndvdaa@gmail.com>
Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.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 55f2fa02a36f0500b47f9ce377926719557106e5..18b5bce1138d50be32e5da013221be69dc47e21f 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, RandomSource random) {
- return super.getGrowIntoState(state, random).setValue(BERRIES, Boolean.valueOf(random.nextFloat() < 0.11F));
+ // Paper start
+ return this.getGrowIntoState(state, random, null);
}
+ @Override
+ protected BlockState getGrowIntoState(BlockState state, RandomSource random, @javax.annotation.Nullable Level level) {
+ final boolean value = random.nextFloat() < (level != null ? (0.11F * (level.spigotConfig.glowBerryModifier / 100.0F)) : 0.11F);
+ return (BlockState) 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/CropBlock.java b/src/main/java/net/minecraft/world/level/block/CropBlock.java
index 08d442713bf0cc4f01f693c9a2fbd1a17a6fa348..decb8caa67bc5f4525e4d92fedf465a17171fceb 100644
--- a/src/main/java/net/minecraft/world/level/block/CropBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/CropBlock.java
@@ -84,6 +84,10 @@ public class CropBlock extends BushBlock implements BonemealableBlock {
modifier = world.spigotConfig.carrotModifier;
} else if (this == Blocks.POTATOES) {
modifier = world.spigotConfig.potatoModifier;
+ // Paper start
+ } else if (this == Blocks.TORCHFLOWER_CROP) {
+ modifier = world.spigotConfig.torchFlowerModifier;
+ // Paper end
} else {
modifier = world.spigotConfig.wheatModifier;
}
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 53b91cf8092b46dbf45afea9ccf439d565d1914a..3a1aa4e2405090ccebefb7f5944f36462929e221 100644
--- a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
@@ -56,12 +56,18 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements
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, RandomSource random, @javax.annotation.Nullable Level level) {
+ return this.getGrowIntoState(state, random);
+ }
+ // Paper end
+
protected BlockState getGrowIntoState(BlockState state, RandomSource random) {
return (BlockState) state.cycle(GrowingPlantHeadBlock.AGE);
}
diff --git a/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java b/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java
index 5d78348fc18b22ccb7ad109890f867e20efec047..44c78f0d56c3459c063c104e401a521e3df7d8e5 100644
--- a/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java
@@ -89,7 +89,7 @@ public class MangrovePropaguleBlock extends SaplingBlock implements SimpleWaterl
@Override
public void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
if (!isHanging(state)) {
- if (random.nextInt(7) == 0) {
+ if (random.nextFloat() < (world.spigotConfig.saplingModifier / (100.0F * 7))) { // Paper
this.advanceTree(world, pos, state, random);
}
diff --git a/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java b/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java
index 593eae04ecf6dee86c9c3664ddcdc3f86d042e66..849c0ae6ca30691134f51e5d4d5da372e0e728bd 100644
--- a/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java
@@ -116,7 +116,7 @@ public class PitcherCropBlock extends DoublePlantBlock implements BonemealableBl
@Override
public void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
float f = CropBlock.getGrowthSpeed(this, world, pos);
- boolean bl = random.nextInt((int)(25.0F / f) + 1) == 0;
+ boolean bl = random.nextFloat() < (world.spigotConfig.pitcherPlantModifier / (100.0F * (Math.floor(25.0F / f) + 1))); // Paper
if (bl) {
this.grow(world, state, pos, 1);
}
diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java
index b7d6197cb5f46bb020fff049ae2dd8fc3ee8ff2f..38da4cc3fe3be86e43432de942a1290fa8215474 100644
--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
@@ -96,6 +96,7 @@ public class SpigotWorldConfig
public int beetrootModifier;
public int carrotModifier;
public int potatoModifier;
+ public int torchFlowerModifier; // Paper
public int wheatModifier;
public int wartModifier;
public int vineModifier;
@@ -106,6 +107,8 @@ public class SpigotWorldConfig
public int twistingVinesModifier;
public int weepingVinesModifier;
public int caveVinesModifier;
+ public int glowBerryModifier; // Paper
+ public int pitcherPlantModifier; // Paper
private int getAndValidateGrowth(String crop)
{
int modifier = this.getInt( "growth." + crop.toLowerCase(java.util.Locale.ENGLISH) + "-modifier", 100 );
@@ -129,6 +132,7 @@ public class SpigotWorldConfig
this.beetrootModifier = this.getAndValidateGrowth( "Beetroot" );
this.carrotModifier = this.getAndValidateGrowth( "Carrot" );
this.potatoModifier = this.getAndValidateGrowth( "Potato" );
+ this.torchFlowerModifier = this.getAndValidateGrowth("TorchFlower"); // Paper
this.wheatModifier = this.getAndValidateGrowth( "Wheat" );
this.wartModifier = this.getAndValidateGrowth( "NetherWart" );
this.vineModifier = this.getAndValidateGrowth( "Vine" );
@@ -139,6 +143,8 @@ public class SpigotWorldConfig
this.twistingVinesModifier = this.getAndValidateGrowth( "TwistingVines" );
this.weepingVinesModifier = this.getAndValidateGrowth( "WeepingVines" );
this.caveVinesModifier = this.getAndValidateGrowth( "CaveVines" );
+ this.glowBerryModifier = this.getAndValidateGrowth("GlowBerry"); // Paper
+ this.pitcherPlantModifier = this.getAndValidateGrowth("PitcherPlant"); // Paper
}
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 ba06184bad7e8ae55cb2d55f6196e8f990d2811d..3e4b3eecc788c564f81b7929bfab7d2fdb6e307d 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
@@ -64,6 +64,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,60 +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 dc999068891bfdfd4873ca939b4c4389d63f4415..a86472cce8e8fcde16d761842fe443a619f6e305 100644
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
@@ -3,6 +3,7 @@ package net.minecraft.world.entity.decoration;
import com.mojang.logging.LogUtils;
import java.util.OptionalInt;
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;
@@ -190,6 +191,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.gameEvent(GameEvent.BLOCK_CHANGE, source.getEntity());
this.playSound(this.getRemoveItemSound(), 1.0F, 1.0F);
@@ -456,13 +464,26 @@ public class ItemFrame extends HangingEntity {
}
}
- this.setItem(itemstack);
+ // Paper start - call PlayerItemFrameChangeEvent
+ PlayerItemFrameChangeEvent 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()));
+ // Paper end
this.gameEvent(GameEvent.BLOCK_CHANGE, player);
if (!player.getAbilities().instabuild) {
itemstack.shrink(1);
}
}
} else {
+ // Paper start - call PlayerItemFrameChangeEvent
+ PlayerItemFrameChangeEvent 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);
this.gameEvent(GameEvent.BLOCK_CHANGE, player);

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 a6d0008636f72ff6614eda4b1fa856798e6b46fd..50580313a1e224a9569e343ccf4aa0c00b906a30 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> idList, int indexBits, PaletteResize<T> listener, CrudeIncrementalIntIdentityHashBiMap<T> map) {
@@ -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,127 +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 7460e45e5a9a9733824161dc9a75bf66370f816b..2b4167581303c79ead5628745efb7a0fa87cf405 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2361,6 +2361,88 @@ public final class CraftServer implements Server {
return new OldCraftChunkData(world.getMinHeight(), world.getMaxHeight(), handle.registryAccess().registryOrThrow(Registries.BIOME), 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.FEATURES,
+ net.minecraft.world.level.chunk.ChunkStatus.INITIALIZE_LIGHT,
+ 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 net.minecraft.core.Registry<net.minecraft.world.level.biome.Biome> biomeRegistry = serverLevel.getServer().registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.BIOME);
+ 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.getDelegate();
+ } 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 net.minecraft.core.Holder<net.minecraft.world.level.biome.Biome> biomeHolder = serverLevel.registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.BIOME).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
+ ).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.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 a9700b750f124b5367c91ac071ee5194e9f7f8d8..1a363ceeefbf69618e5f17f67b6f6a2660579ba5 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,171 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
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
CHECK ME
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 81750c1551a69d1c77ab8c34437e5d839b7e2941..6345d9d3ade4c490e4a6266fc5ecbd5b2de8ddeb 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -649,7 +649,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
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
@@ -665,6 +665,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
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();
@@ -678,16 +679,24 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
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));
@@ -773,7 +782,32 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
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
@@ -1349,7 +1383,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
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());
}
@@ -1442,7 +1476,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
}
- AABB axisalignedbb = this.player.getBoundingBox();
+ AABB axisalignedbb = this.player.getBoundingBox(); // Paper - diff on change, should be old AABB
d6 = d0 - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
d7 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
@@ -1484,6 +1518,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
this.player.move(MoverType.PLAYER, new Vec3(d6, d7, d8));
this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
+ 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...
// Paper start - prevent position desync
if (this.awaitingPositionFromClient != null) {
return; // ... thanks Mojang for letting move calls teleport across dimensions.
@@ -1502,11 +1537,23 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
boolean flag2 = false;
if (!this.player.isChangingDimension() && d10 > 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());
}
- if (!this.player.noPhysics && !this.player.isSleeping() && (flag2 && worldserver.noCollision(this.player, axisalignedbb) || this.isPlayerCollidingWithAnythingNew(worldserver, axisalignedbb, d0, d1, d2))) {
+ // Paper start - optimise out extra getCubes
+ this.player.absMoveTo(d0, d1, d2, f, f1); // prevent desync by tping to the set position, dropped for unknown reasons by mojang
+ // 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()); // 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.
this.player.doCheckFallDamage(this.player.getX() - d3, this.player.getY() - d4, this.player.getZ() - d5, packet.isOnGround());
} else {
@@ -1592,6 +1639,26 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
}
+ // 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, double newX, double newY, double newZ) {
AABB axisalignedbb1 = this.player.getBoundingBox().move(newX - this.player.getX(), newY - this.player.getY(), newZ - this.player.getZ());
Iterable<VoxelShape> iterable = world.getCollisions(this.player, axisalignedbb1.deflate(9.999999747378752E-6D));

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 269ebe8e8826a0c89e471cb59b503900d7ebe0fa..883eed6e92792e225ebfa8667ce3f4eeb6287d6a 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
@@ -289,13 +289,17 @@ public class CraftChunk implements Chunk {
PalettedContainerRO<Holder<net.minecraft.world.level.biome.Biome>>[] biome = (includeBiome || includeBiomeTempRain) ? new PalettedContainer[cs.length] : null;
Registry<net.minecraft.world.level.biome.Biome> iregistry = this.worldServer.registryAccess().registryOrThrow(Registries.BIOME);
- Codec<PalettedContainerRO<Holder<net.minecraft.world.level.biome.Biome>>> biomeCodec = PalettedContainer.codecRO(iregistry.asHolderIdMap(), iregistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, iregistry.getHolderOrThrow(Biomes.PLAINS));
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 = this.worldServer.getLightEngine();
DataLayer skyLightArray = lightengine.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(x, i, z));
@@ -314,8 +318,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] = ((PalettedContainer<Holder<net.minecraft.world.level.biome.Biome>>) cs[i].getBiomes()).copy(); // Paper - use copy instead of round tripping with codecs
}
}

View file

@ -1,112 +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 0cd019dc20ff5b3e7ee663866f98595081e991a3..91feee1e284c929b008bc2df7ab548df898b3ef7 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
@@ -41,6 +41,7 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
public final int[] cookingProgress;
public final int[] cookingTime;
private final RecipeManager.CachedCheck<Container, CampfireCookingRecipe> quickCheck;
+ public final boolean[] stopCooking; // Paper
public CampfireBlockEntity(BlockPos pos, BlockState state) {
super(BlockEntityType.CAMPFIRE, pos, state);
@@ -48,6 +49,7 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
this.cookingProgress = new int[4];
this.cookingTime = new int[4];
this.quickCheck = RecipeManager.createCheck(RecipeType.CAMPFIRE_COOKING);
+ this.stopCooking = new boolean[4]; // Paper
}
public static void cookTick(Level world, BlockPos pos, BlockState state, CampfireBlockEntity campfire) {
@@ -58,7 +60,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});
@@ -167,6 +171,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
@@ -175,6 +189,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,97 +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 9bae47f99336c377beb72c4b50b7f01cb4db15da..dcfe090c269d4cbcc2eb1b6f85392848bb34656c 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
@@ -1004,6 +1004,9 @@ public class RegionFile implements AutoCloseable {
}
}
+
+ public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; // Paper - don't write garbage data to disk if writing serialization fails
+
// Paper end
private class ChunkBuffer extends ByteArrayOutputStream {
@@ -1019,6 +1022,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 > MAX_CHUNK_SIZE) {
+ 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 > MAX_CHUNK_SIZE) {
+ 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 c2643f61fe5efb62d15f0798db691c76c7674a6e..81554c321a78258ff78da3801f00d0fb90b9e113 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
@@ -345,10 +345,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);
}
@@ -356,10 +363,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
return;
@@ -405,4 +409,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 <nassim@njahnke.dev>
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 4e2fb4ee8e46b3c363992ff23e26f5a648c5f003..7f60175bf671d282c11e9084670d2bb900968255 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 4a516828e5c6abd63511ee7c93fcff11203cf8d0..004dce26ff073f1de52a84cd425c4f60fdab5e50 100644
--- a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
@@ -108,6 +108,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);
@@ -141,6 +147,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,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 23194249ab0add8cf2cbea190d3c6aee606b10a1..d441db38210b15c6fae5a1632f4e2372c7a04b7c 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -3444,6 +3444,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");
@@ -3530,10 +3537,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 ef1b0b716b11327a8f2856f51545aaba355ce74e..442ed17a4c91fe5ccf567f2af518569b945aa36c 100644
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java
@@ -145,6 +145,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 {
+ Preconditions.checkArgument(entity != null, "Entity cannot be null");
+ return getScore(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
+ }
+ // Paper end
+
@Override
public void unregister() {
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 052389310826ee6b97cf27dfd952e0101fb2d097..a8c5bfc54ed2b8bd873f124c7080d73fe73a86ad 100644
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java
@@ -233,4 +233,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 {
+ Preconditions.checkArgument(entity != null, "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 {
+ Preconditions.checkArgument(entity != null, "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 {
+ Preconditions.checkArgument(entity != null, "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 baff11728120fda1740d5e15163760f50fe1cd1d..4d65d1a0dd52aaeeeef8acf2b0023f27257f60a2 100644
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
@@ -304,6 +304,26 @@ final class CraftTeam extends CraftScoreboardComponent implements Team {
}
}
+ // Paper start
+ @Override
+ public void addEntity(org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException {
+ Preconditions.checkArgument(entity != null, "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 {
+ Preconditions.checkArgument(entity != null, "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 {
+ Preconditions.checkArgument(entity != null, "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,39 +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
== AT ==
public net.minecraft.world.entity.monster.Skeleton inPowderSnowTime
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index f96144b6ee8b4d1d114e38bb933dd3072191574c..d976796c6e80d8abc5c110bdefc09f63cfc4a60a 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -1381,5 +1381,10 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
this.entity.setRot(location.getYaw(), location.getPitch());
return !this.entity.valid && this.entity.level().addFreshEntity(this.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 956ddd955e6f9b2f02ef05b0e95150c9c90c3107..16e6325a944c1eb21dd5a3835aa8a00d238e7b5d 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java
@@ -45,4 +45,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,34 +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
== AT ==
public net.minecraft.world.entity.item.ItemEntity health
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
index ff6868ab31cec208045353c842f20ca31191bc0a..d160db37a3b7ef44b6de8fef209eeccef46c3a95 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
@@ -101,6 +101,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,156 +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/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java
index 308b3a36f063c401a447f9b7f0364700eee5a54c..43c71d9bf2eac98023057b4483fdd143a8343e98 100644
--- a/src/main/java/net/minecraft/commands/CommandSourceStack.java
+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java
@@ -441,4 +441,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 (io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && this.source instanceof ServerPlayer player) {
+ final Entity cameraEntity = player.getCamera();
+ final double pickDistance = player.gameMode.getGameModeForPlayer().isCreative() ? 6.0F : 4.5F;
+ final Vec3 min = cameraEntity.getEyePosition(1.0F);
+ final Vec3 viewVector = cameraEntity.getViewVector(1.0F);
+ final Vec3 max = min.add(viewVector.x * pickDistance, viewVector.y * pickDistance, viewVector.z * pickDistance);
+ final net.minecraft.world.phys.AABB aabb = cameraEntity.getBoundingBox().expandTowards(viewVector.scale(pickDistance)).inflate(1.0D, 1.0D, 1.0D);
+ final net.minecraft.world.phys.EntityHitResult hitResult = net.minecraft.world.entity.projectile.ProjectileUtil.getEntityHitResult(cameraEntity, min, max, aabb, (e) -> !e.isSpectator() && e.isPickable(), pickDistance * 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 7592b592a541912f729d6b99f455cd87ebcb34b8..f967e9039c87ec458da3f133743df834437b3e02 100644
--- a/src/main/java/net/minecraft/commands/Commands.java
+++ b/src/main/java/net/minecraft/commands/Commands.java
@@ -472,6 +472,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();
// Paper start
@@ -498,6 +499,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 (io.papermc.paper.configuration.GlobalConfiguration.get().commands.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 850db283bf12345e9e7d7e8e590dbe8135c6dce1..a71726cee91fb406875a4540c9fb7c0ecf757294 100644
--- a/src/main/java/net/minecraft/commands/arguments/EntityArgument.java
+++ b/src/main/java/net/minecraft/commands/arguments/EntityArgument.java
@@ -128,7 +128,7 @@ public class EntityArgument implements ArgumentType<EntitySelector> {
StringReader stringreader = new StringReader(suggestionsbuilder.getInput());
stringreader.setCursor(suggestionsbuilder.getStart());
- EntitySelectorParser argumentparserselector = new EntitySelectorParser(stringreader, icompletionprovider.hasPermission(2));
+ EntitySelectorParser argumentparserselector = new EntitySelectorParser(stringreader, icompletionprovider.hasPermission(2), true); // Paper
try {
argumentparserselector.parse();
@@ -137,7 +137,19 @@ public class EntityArgument implements ArgumentType<EntitySelector> {
}
return argumentparserselector.fillSuggestions(suggestionsbuilder, (suggestionsbuilder1) -> {
- Collection<String> collection = icompletionprovider.getOnlinePlayerNames();
+ // Paper start
+ final Collection<String> collection;
+ if (icompletionprovider instanceof CommandSourceStack commandSourceStack && commandSourceStack.getEntity() instanceof ServerPlayer sourcePlayer) {
+ collection = new java.util.ArrayList<>();
+ for (final ServerPlayer player : commandSourceStack.getServer().getPlayerList().getPlayers()) {
+ if (sourcePlayer.getBukkitEntity().canSee(player.getBukkitEntity())) {
+ collection.add(player.getGameProfile().getName());
+ }
+ }
+ } else {
+ collection = icompletionprovider.getOnlinePlayerNames();
+ }
+ // Paper end
Iterable<String> iterable = this.playersOnly ? collection : Iterables.concat(collection, icompletionprovider.getSelectedEntities());
SharedSuggestionProvider.suggest((Iterable) iterable, suggestionsbuilder1);
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 cdc1319a7cb45a7c5ea30885958b8c3c54f0a241..4cc2ee22369aef22c9bf9d2b244c7278d6db39bb 100644
--- a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
+++ b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
@@ -113,12 +113,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 027906d533717fa97a523f4b03b31270fe3fa5fc..c51bcb3d89936cf558a5fe8aa6371617274a02a1 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 Component.translatable("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(Registries.ENTITY_TYPE, ResourceLocation.read(reader.getReader()));
+ // Paper start - throw error if invalid entity tag (only on suggestions to keep cmd success behavior)
+ if (reader.parsingEntityArgumentSuggestions && io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.getTag(tagKey).isEmpty()) {
+ 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,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <nassim@njahnke.dev>
Date: Thu, 16 Dec 2021 09:40:39 +0100
Subject: [PATCH] Configurable max block light for monster spawning
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 6e0bd0eab0b06a4ac3042496bbb91292544e9f3c..55c245d0dfa369dc6de2197ae37335fba4fae4ae 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Monster.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Monster.java
@@ -93,7 +93,7 @@ public abstract class Monster extends PathfinderMob implements Enemy {
return false;
} else {
DimensionType dimensionType = world.dimensionType();
- int i = dimensionType.monsterSpawnBlockLightLimit();
+ int i = world.getLevel().paperConfig().entities.spawning.monsterSpawnMaxLightLevel >= 0 ? world.getLevel().paperConfig().entities.spawning.monsterSpawnMaxLightLevel : dimensionType.monsterSpawnBlockLightLimit(); // Paper
if (i < 15 && world.getBrightness(LightLayer.BLOCK, pos) > i) {
return false;
} else {

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 8125c334c54d41ad731bbc3481662b0cf0afee51..58d1f76544d7a8d196f75438579266664e5d7404 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
@@ -146,15 +146,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());
@@ -237,6 +237,13 @@ public class PistonBaseBlock extends DirectionalBlock {
BlockState iblockdata2 = (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, iblockdata2, 20);
world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); // Paper - diff on change
world.blockUpdated(pos, iblockdata2.getBlock());
@@ -263,6 +270,13 @@ public class PistonBaseBlock extends DirectionalBlock {
if (type == 1 && !iblockdata3.isAir() && PistonBaseBlock.isPushable(iblockdata3, world, blockposition1, enumdirection.getOpposite(), false, enumdirection) && (iblockdata3.getPistonPushReaction() == PushReaction.NORMAL || iblockdata3.is(Blocks.PISTON) || iblockdata3.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 ddb369057bbfeb67c7825f7a93fa68d1c18eb6fc..14fab63346d56c72cd7534a04760efd10eef4295 100644
--- a/src/main/java/net/minecraft/world/effect/MobEffectInstance.java
+++ b/src/main/java/net/minecraft/world/effect/MobEffectInstance.java
@@ -286,7 +286,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 82ad97800cb115cc4830337a59cc4608c1d4a7a0..41c9f074203915c31c1ae7a160ce509c13383f84 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
@@ -328,7 +328,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)) {
@@ -336,10 +336,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) {
@@ -428,12 +429,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 e730292edca4624400bdb89d555922c5f61db7a5..cbfca242f820d238b112f8ce64e9de8398c48a1c 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java
@@ -4,7 +4,7 @@ import com.google.common.base.Preconditions;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.Axolotl;
-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);