A bunch more 637

This commit is contained in:
Shane Freeder 2024-10-23 21:10:14 +01:00
parent cbf64163ba
commit 6456b5dea8
No known key found for this signature in database
GPG key ID: A3F61EA5A085289C
42 changed files with 128 additions and 128 deletions

View file

@ -1,343 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Mon, 16 Aug 2021 01:31:54 -0500
Subject: [PATCH] Add '/paper mobcaps' and '/paper playermobcaps'
Add commands to get the mobcaps for a world, as well as the mobcaps for
each player when per-player mob spawning is enabled.
Also has a hover text on each mob category listing what entity types are
in said category
diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java
index cdad0fd5257ae842f83b9c1c98b4565b468d4f54..fd4f37711989431f997d77fb0917f8a9232ce53f 100644
--- a/src/main/java/io/papermc/paper/command/PaperCommand.java
+++ b/src/main/java/io/papermc/paper/command/PaperCommand.java
@@ -40,6 +40,7 @@ public final class PaperCommand extends Command {
commands.put(Set.of("dumpplugins"), new DumpPluginsCommand());
commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand());
commands.put(Set.of("dumpitem"), new DumpItemCommand());
+ commands.put(Set.of("mobcaps", "playermobcaps"), new MobcapsCommand());
return commands.entrySet().stream()
.flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue())))
diff --git a/src/main/java/io/papermc/paper/command/subcommands/MobcapsCommand.java b/src/main/java/io/papermc/paper/command/subcommands/MobcapsCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..d3b39d88a72ca25057fd8574d32f28db0d420818
--- /dev/null
+++ b/src/main/java/io/papermc/paper/command/subcommands/MobcapsCommand.java
@@ -0,0 +1,229 @@
+package io.papermc.paper.command.subcommands;
+
+import com.google.common.collect.ImmutableMap;
+import io.papermc.paper.command.CommandUtil;
+import io.papermc.paper.command.PaperSubcommand;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.function.ToIntFunction;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.ComponentLike;
+import net.kyori.adventure.text.JoinConfiguration;
+import net.kyori.adventure.text.TextComponent;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.format.TextColor;
+import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.entity.MobCategory;
+import net.minecraft.world.level.NaturalSpawner;
+import org.bukkit.Bukkit;
+import org.bukkit.World;
+import org.bukkit.command.CommandSender;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+@DefaultQualifier(NonNull.class)
+public final class MobcapsCommand implements PaperSubcommand {
+ static final Map<MobCategory, TextColor> MOB_CATEGORY_COLORS = ImmutableMap.<MobCategory, TextColor>builder()
+ .put(MobCategory.MONSTER, NamedTextColor.RED)
+ .put(MobCategory.CREATURE, NamedTextColor.GREEN)
+ .put(MobCategory.AMBIENT, NamedTextColor.GRAY)
+ .put(MobCategory.AXOLOTLS, TextColor.color(0x7324FF))
+ .put(MobCategory.UNDERGROUND_WATER_CREATURE, TextColor.color(0x3541E6))
+ .put(MobCategory.WATER_CREATURE, TextColor.color(0x006EFF))
+ .put(MobCategory.WATER_AMBIENT, TextColor.color(0x00B3FF))
+ .put(MobCategory.MISC, TextColor.color(0x636363))
+ .build();
+
+ @Override
+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
+ switch (subCommand) {
+ case "mobcaps" -> this.printMobcaps(sender, args);
+ case "playermobcaps" -> this.printPlayerMobcaps(sender, args);
+ }
+ return true;
+ }
+
+ @Override
+ public List<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) {
+ return switch (subCommand) {
+ case "mobcaps" -> CommandUtil.getListMatchingLast(sender, args, this.suggestMobcaps(args));
+ case "playermobcaps" -> CommandUtil.getListMatchingLast(sender, args, this.suggestPlayerMobcaps(sender, args));
+ default -> throw new IllegalArgumentException();
+ };
+ }
+
+ private List<String> suggestMobcaps(final String[] args) {
+ if (args.length == 1) {
+ final List<String> worlds = new ArrayList<>(Bukkit.getWorlds().stream().map(World::getName).toList());
+ worlds.add("*");
+ return worlds;
+ }
+
+ return Collections.emptyList();
+ }
+
+ private List<String> suggestPlayerMobcaps(final CommandSender sender, final String[] args) {
+ if (args.length == 1) {
+ final List<String> list = new ArrayList<>();
+ for (final Player player : Bukkit.getOnlinePlayers()) {
+ if (!(sender instanceof Player senderPlayer) || senderPlayer.canSee(player)) {
+ list.add(player.getName());
+ }
+ }
+ return list;
+ }
+
+ return Collections.emptyList();
+ }
+
+ private void printMobcaps(final CommandSender sender, final String[] args) {
+ final List<World> worlds;
+ if (args.length == 0) {
+ if (sender instanceof Player player) {
+ worlds = List.of(player.getWorld());
+ } else {
+ sender.sendMessage(Component.text("Must specify a world! ex: '/paper mobcaps world'", NamedTextColor.RED));
+ return;
+ }
+ } else if (args.length == 1) {
+ final String input = args[0];
+ if (input.equals("*")) {
+ worlds = Bukkit.getWorlds();
+ } else {
+ final @Nullable World world = Bukkit.getWorld(input);
+ if (world == null) {
+ sender.sendMessage(Component.text("'" + input + "' is not a valid world!", NamedTextColor.RED));
+ return;
+ } else {
+ worlds = List.of(world);
+ }
+ }
+ } else {
+ sender.sendMessage(Component.text("Too many arguments!", NamedTextColor.RED));
+ return;
+ }
+
+ for (final World world : worlds) {
+ final ServerLevel level = ((CraftWorld) world).getHandle();
+ final NaturalSpawner.@Nullable SpawnState state = level.getChunkSource().getLastSpawnState();
+
+ final int chunks;
+ if (state == null) {
+ chunks = 0;
+ } else {
+ chunks = state.getSpawnableChunkCount();
+ }
+ sender.sendMessage(Component.join(JoinConfiguration.noSeparators(),
+ Component.text("Mobcaps for world: "),
+ Component.text(world.getName(), NamedTextColor.AQUA),
+ Component.text(" (" + chunks + " spawnable chunks)")
+ ));
+
+ sender.sendMessage(createMobcapsComponent(
+ category -> {
+ if (state == null) {
+ return 0;
+ } else {
+ return state.getMobCategoryCounts().getOrDefault(category, 0);
+ }
+ },
+ category -> NaturalSpawner.globalLimitForCategory(level, category, chunks)
+ ));
+ }
+ }
+
+ private void printPlayerMobcaps(final CommandSender sender, final String[] args) {
+ final @Nullable Player player;
+ if (args.length == 0) {
+ if (sender instanceof Player pl) {
+ player = pl;
+ } else {
+ sender.sendMessage(Component.text("Must specify a player! ex: '/paper playermobcount playerName'", NamedTextColor.RED));
+ return;
+ }
+ } else if (args.length == 1) {
+ final String input = args[0];
+ player = Bukkit.getPlayerExact(input);
+ if (player == null) {
+ sender.sendMessage(Component.text("Could not find player named '" + input + "'", NamedTextColor.RED));
+ return;
+ }
+ } else {
+ sender.sendMessage(Component.text("Too many arguments!", NamedTextColor.RED));
+ return;
+ }
+
+ final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
+ final ServerLevel level = serverPlayer.serverLevel();
+
+ if (!level.paperConfig().entities.spawning.perPlayerMobSpawns) {
+ sender.sendMessage(Component.text("Use '/paper mobcaps' for worlds where per-player mob spawning is disabled.", NamedTextColor.RED));
+ return;
+ }
+
+ sender.sendMessage(Component.join(JoinConfiguration.noSeparators(), Component.text("Mobcaps for player: "), Component.text(player.getName(), NamedTextColor.GREEN)));
+ sender.sendMessage(createMobcapsComponent(
+ category -> level.chunkSource.chunkMap.getMobCountNear(serverPlayer, category),
+ category -> level.getWorld().getSpawnLimitUnsafe(org.bukkit.craftbukkit.util.CraftSpawnCategory.toBukkit(category))
+ ));
+ }
+
+ private static Component createMobcapsComponent(final ToIntFunction<MobCategory> countGetter, final ToIntFunction<MobCategory> limitGetter) {
+ return MOB_CATEGORY_COLORS.entrySet().stream()
+ .map(entry -> {
+ final MobCategory category = entry.getKey();
+ final TextColor color = entry.getValue();
+
+ final Component categoryHover = Component.join(JoinConfiguration.noSeparators(),
+ Component.text("Entity types in category ", TextColor.color(0xE0E0E0)),
+ Component.text(category.getName(), color),
+ Component.text(':', NamedTextColor.GRAY),
+ Component.newline(),
+ Component.newline(),
+ BuiltInRegistries.ENTITY_TYPE.entrySet().stream()
+ .filter(it -> it.getValue().getCategory() == category)
+ .map(it -> Component.translatable(it.getValue().getDescriptionId()))
+ .collect(Component.toComponent(Component.text(", ", NamedTextColor.GRAY)))
+ );
+
+ final Component categoryComponent = Component.text()
+ .content(" " + category.getName())
+ .color(color)
+ .hoverEvent(categoryHover)
+ .build();
+
+ final TextComponent.Builder builder = Component.text()
+ .append(
+ categoryComponent,
+ Component.text(": ", NamedTextColor.GRAY)
+ );
+ final int limit = limitGetter.applyAsInt(category);
+ if (limit != -1) {
+ builder.append(
+ Component.text(countGetter.applyAsInt(category)),
+ Component.text("/", NamedTextColor.GRAY),
+ Component.text(limit)
+ );
+ } else {
+ builder.append(Component.text()
+ .append(
+ Component.text('n'),
+ Component.text("/", NamedTextColor.GRAY),
+ Component.text('a')
+ )
+ .hoverEvent(Component.text("This category does not naturally spawn.")));
+ }
+ return builder;
+ })
+ .map(ComponentLike::asComponent)
+ .collect(Component.toComponent(Component.newline()));
+ }
+}
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
index 58ea6a1f95a09c22125a8262b1b221004ebce0e4..ea6533c1ac218aa075da3401807a06fcb7892321 100644
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
@@ -152,6 +152,16 @@ public final class NaturalSpawner {
world.getProfiler().pop();
}
+ // Paper start - Add mobcaps commands
+ public static int globalLimitForCategory(final ServerLevel level, final MobCategory category, final int spawnableChunkCount) {
+ final int categoryLimit = level.getWorld().getSpawnLimitUnsafe(CraftSpawnCategory.toBukkit(category));
+ if (categoryLimit < 1) {
+ return categoryLimit;
+ }
+ return categoryLimit * spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER;
+ }
+ // Paper end - Add mobcaps commands
+
public static void spawnCategoryForChunk(MobCategory group, ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner) {
BlockPos blockposition = NaturalSpawner.getRandomPosWithin(world, chunk);
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 36a1b2704debdb8a2f247180d263a1a95bcba24b..b638ccf0e46eeb375a59a42d6f29edd3f084fa17 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2331,6 +2331,11 @@ public final class CraftServer implements Server {
@Override
public int getSpawnLimit(SpawnCategory spawnCategory) {
+ // Paper start - Add mobcaps commands
+ return this.getSpawnLimitUnsafe(spawnCategory);
+ }
+ public int getSpawnLimitUnsafe(final SpawnCategory spawnCategory) {
+ // Paper end - Add mobcaps commands
return this.spawnCategoryLimit.getOrDefault(spawnCategory, -1);
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index bf4be21f24af1e569267be6413dbee533c153fc5..838ffddba99964748dfe95d68ca93b578bc3292b 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -1718,9 +1718,14 @@ public class CraftWorld extends CraftRegionAccessor implements World {
Preconditions.checkArgument(spawnCategory != null, "SpawnCategory cannot be null");
Preconditions.checkArgument(CraftSpawnCategory.isValidForLimits(spawnCategory), "SpawnCategory.%s are not supported", spawnCategory);
+ // Paper start - Add mobcaps commands
+ return this.getSpawnLimitUnsafe(spawnCategory);
+ }
+ public final int getSpawnLimitUnsafe(final SpawnCategory spawnCategory) {
int limit = this.spawnCategoryLimit.getOrDefault(spawnCategory, -1);
if (limit < 0) {
- limit = this.server.getSpawnLimit(spawnCategory);
+ limit = this.server.getSpawnLimitUnsafe(spawnCategory);
+ // Paper end - Add mobcaps commands
}
return limit;
}
diff --git a/src/test/java/io/papermc/paper/command/subcommands/MobcapsCommandTest.java b/src/test/java/io/papermc/paper/command/subcommands/MobcapsCommandTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..6fdc77caa74845786c78a6ba087062b4d698cb82
--- /dev/null
+++ b/src/test/java/io/papermc/paper/command/subcommands/MobcapsCommandTest.java
@@ -0,0 +1,22 @@
+package io.papermc.paper.command.subcommands;
+
+import java.util.HashSet;
+import java.util.Set;
+import net.minecraft.world.entity.MobCategory;
+import org.bukkit.support.environment.Normal;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+@Normal
+public class MobcapsCommandTest {
+ @Test
+ public void testMobCategoryColors() {
+ final Set<String> missing = new HashSet<>();
+ for (final MobCategory value : MobCategory.values()) {
+ if (!MobcapsCommand.MOB_CATEGORY_COLORS.containsKey(value)) {
+ missing.add(value.getName());
+ }
+ }
+ Assertions.assertTrue(missing.isEmpty(), "MobcapsCommand.MOB_CATEGORY_COLORS map missing TextColors for [" + String.join(", ", missing + "]"));
+ }
+}

View file

@ -1,28 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <nassim@njahnke.dev>
Date: Thu, 26 Aug 2021 12:09:47 +0200
Subject: [PATCH] Sanitize ResourceLocation error logging
diff --git a/src/main/java/net/minecraft/resources/ResourceLocation.java b/src/main/java/net/minecraft/resources/ResourceLocation.java
index 262660d115a5d5cbecfbae995955a24283e666b0..87afe84791af2d5e9f869cd4c09eed4bb5fee75b 100644
--- a/src/main/java/net/minecraft/resources/ResourceLocation.java
+++ b/src/main/java/net/minecraft/resources/ResourceLocation.java
@@ -247,7 +247,7 @@ public final class ResourceLocation implements Comparable<ResourceLocation> {
private static String assertValidNamespace(String namespace, String path) {
if (!isValidNamespace(namespace)) {
- throw new ResourceLocationException("Non [a-z0-9_.-] character in namespace of location: " + namespace + ":" + path);
+ throw new ResourceLocationException("Non [a-z0-9_.-] character in namespace of location: " + org.apache.commons.lang3.StringUtils.normalizeSpace(namespace) + ":" + org.apache.commons.lang3.StringUtils.normalizeSpace(path)); // Paper - Sanitize ResourceLocation error logging
} else {
return namespace;
}
@@ -268,7 +268,7 @@ public final class ResourceLocation implements Comparable<ResourceLocation> {
private static String assertValidPath(String namespace, String path) {
if (!isValidPath(path)) {
- throw new ResourceLocationException("Non [a-z0-9/._-] character in path of location: " + namespace + ":" + path);
+ throw new ResourceLocationException("Non [a-z0-9/._-] character in path of location: " + namespace + ":" + org.apache.commons.lang3.StringUtils.normalizeSpace(path)); // Paper - Sanitize ResourceLocation error logging
} else {
return path;
}

View file

@ -1,63 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Mon, 6 Jul 2020 22:48:48 -0700
Subject: [PATCH] Manually inline methods in BlockPosition
diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java
index 73d7b5148e3a92c085b08303589827a6f0ae8d07..12ff8886bb53ca15db745989c25b9bd2f45335e4 100644
--- a/src/main/java/net/minecraft/core/BlockPos.java
+++ b/src/main/java/net/minecraft/core/BlockPos.java
@@ -570,9 +570,9 @@ public class BlockPos extends Vec3i {
}
public BlockPos.MutableBlockPos set(int x, int y, int z) {
- this.setX(x);
- this.setY(y);
- this.setZ(z);
+ this.x = x; // Paper - Perf: Manually inline methods in BlockPosition
+ this.y = y; // Paper - Perf: Manually inline methods in BlockPosition
+ this.z = z; // Paper - Perf: Manually inline methods in BlockPosition
return this;
}
@@ -637,19 +637,19 @@ public class BlockPos extends Vec3i {
@Override
public BlockPos.MutableBlockPos setX(int i) {
- super.setX(i);
+ this.x = i; // Paper - Perf: Manually inline methods in BlockPosition
return this;
}
@Override
public BlockPos.MutableBlockPos setY(int i) {
- super.setY(i);
+ this.y = i; // Paper - Perf: Manually inline methods in BlockPosition
return this;
}
@Override
public BlockPos.MutableBlockPos setZ(int i) {
- super.setZ(i);
+ this.z = i; // Paper - Perf: Manually inline methods in BlockPosition
return this;
}
diff --git a/src/main/java/net/minecraft/core/Vec3i.java b/src/main/java/net/minecraft/core/Vec3i.java
index df4c9b275752ad97a4efe9380ae0d511ee760695..02367ef1371dde94ff6c4cd40bd32e800d6ccaaf 100644
--- a/src/main/java/net/minecraft/core/Vec3i.java
+++ b/src/main/java/net/minecraft/core/Vec3i.java
@@ -16,9 +16,9 @@ public class Vec3i implements Comparable<Vec3i> {
vec -> IntStream.of(vec.getX(), vec.getY(), vec.getZ())
);
public static final Vec3i ZERO = new Vec3i(0, 0, 0);
- private int x;
- private int y;
- private int z;
+ protected int x; // Paper - Perf: Manually inline methods in BlockPosition; protected
+ protected int y; // Paper - Perf: Manually inline methods in BlockPosition; protected
+ protected int z; // Paper - Perf: Manually inline methods in BlockPosition; protected
public static Codec<Vec3i> offsetCodec(int maxAbsValue) {
return CODEC.validate(

View file

@ -1,33 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sun, 19 Jul 2020 15:17:01 -0700
Subject: [PATCH] Name craft scheduler threads according to the plugin using
them
Provides quick access to culprits running far more threads than
they should be
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java
index 365b7e7c665bec357fb76d1479bf17da6f603590..e97f6b76ef2fe21c7c2eca8d4a707e5866d70de9 100644
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java
@@ -25,7 +25,10 @@ class CraftAsyncTask extends CraftTask {
@Override
public void run() {
final Thread thread = Thread.currentThread();
- synchronized (this.workers) {
+ // Paper start - name threads according to running plugin
+ final String nameBefore = thread.getName();
+ thread.setName(nameBefore + " - " + this.getOwner().getName());
+ try { synchronized (this.workers) { // Paper end - name threads according to running plugin
if (this.getPeriod() == CraftTask.CANCEL) {
// Never continue running after cancelled.
// Checking this with the lock is important!
@@ -92,6 +95,7 @@ class CraftAsyncTask extends CraftTask {
}
}
}
+ } finally { thread.setName(nameBefore); } // Paper - name threads according to running plugin
}
LinkedList<BukkitWorker> getWorkers() {

View file

@ -1,31 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sun, 20 Sep 2020 16:10:49 -0700
Subject: [PATCH] Make sure inlined getChunkAt has inlined logic for loaded
chunks
Tux did some profiling some time ago and showed that the
previous getChunkAt method which had inlined logic for loaded
chunks did get inlined, but the standard CPS.getChunkAt
method was not inlined.
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 20a14b4163807b806bf2ce5a88d3c35098bed929..b4111bcc6a676dc42b233761aa667708669c2ab8 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -352,7 +352,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@Override
public final LevelChunk getChunk(int chunkX, int chunkZ) { // Paper - final to help inline
- return (LevelChunk) this.getChunk(chunkX, chunkZ, ChunkStatus.FULL, true); // Paper - avoid a method jump
+ // Paper start - Perf: make sure loaded chunks get the inlined variant of this function
+ net.minecraft.server.level.ServerChunkCache cps = ((ServerLevel)this).getChunkSource();
+ LevelChunk ifLoaded = cps.getChunkAtIfLoadedImmediately(chunkX, chunkZ);
+ if (ifLoaded != null) {
+ return ifLoaded;
+ }
+ return (LevelChunk) cps.getChunk(chunkX, chunkZ, ChunkStatus.FULL, true); // Paper - avoid a method jump
+ // Paper end - Perf: make sure loaded chunks get the inlined variant of this function
}
// Paper start - if loaded

View file

@ -1,21 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sun, 11 Apr 2021 02:58:48 -0700
Subject: [PATCH] Don't read neighbour chunk data off disk when converting
chunks
Lighting is purged on update anyways, so let's not add more
into the conversion process
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
index 9aa9ab894080a5819fc45698771afd034906d36a..f0f5e9bb5ac65250f0a151f9f90b58468335a8c2 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
@@ -47,6 +47,7 @@ public class ChunkStorage implements AutoCloseable {
// CraftBukkit start
private boolean check(ServerChunkCache cps, int x, int z) {
+ if (true) return true; // Paper - Perf: this isn't even needed anymore, light is purged updating to 1.14+, why are we holding up the conversion process reading chunk data off disk - return true, we need to set light populated to true so the converter recognizes the chunk as being "full"
ChunkPos pos = new ChunkPos(x, z);
if (cps != null) {
com.google.common.base.Preconditions.checkState(org.bukkit.Bukkit.isPrimaryThread(), "primary thread");

View file

@ -1,26 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Fri, 28 Aug 2020 12:33:47 -0700
Subject: [PATCH] Don't lookup fluid state when raytracing, skip air blocks
Just use the iblockdata already retrieved, removes a getType call.
Also save approx. 5% for the raytrace call, as most (expensive)
raytracing tends to go through air and returning early is an
easy win. The remaining problems with this function
are mostly with the block getting itself.
diff --git a/src/main/java/net/minecraft/world/level/BlockGetter.java b/src/main/java/net/minecraft/world/level/BlockGetter.java
index c3760e0c8ac0b3ea200f4e1c237e250137a78caf..c978f3b2d42f512e982f289e76c2422e41b7eec6 100644
--- a/src/main/java/net/minecraft/world/level/BlockGetter.java
+++ b/src/main/java/net/minecraft/world/level/BlockGetter.java
@@ -79,7 +79,8 @@ public interface BlockGetter extends LevelHeightAccessor {
return BlockHitResult.miss(raytrace1.getTo(), Direction.getNearest(vec3d.x, vec3d.y, vec3d.z), BlockPos.containing(raytrace1.getTo()));
}
// Paper end - Prevent raytrace from loading chunks
- FluidState fluid = this.getFluidState(blockposition);
+ if (iblockdata.isAir()) return null; // Paper - Perf: optimise air cases
+ FluidState fluid = iblockdata.getFluidState(); // Paper - Perf: don't need to go to world state again
Vec3 vec3d = raytrace1.getFrom();
Vec3 vec3d1 = raytrace1.getTo();
VoxelShape voxelshape = raytrace1.getBlockShape(iblockdata, this, blockposition);

View file

@ -1,43 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Tue, 21 Apr 2020 01:53:22 -0700
Subject: [PATCH] Time scoreboard search
Plugins leaking scoreboards will make this very expensive,
let server owners debug it easily
diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java
index e2764186bd6b838ed5cd86c15597a08d079ef984..6b3cde6d4d1e63bec01f502f2027ee9fddac08aa 100644
--- a/src/main/java/co/aikar/timings/MinecraftTimings.java
+++ b/src/main/java/co/aikar/timings/MinecraftTimings.java
@@ -46,6 +46,7 @@ public final class MinecraftTimings {
public static final Timing antiXrayUpdateTimer = Timings.ofSafe("anti-xray - update");
public static final Timing antiXrayObfuscateTimer = Timings.ofSafe("anti-xray - obfuscate");
+ public static final Timing scoreboardScoreSearch = Timings.ofSafe("Scoreboard score search"); // Paper - add timings for scoreboard search
private static final Map<Class<?>, String> taskNameCache = new MapMaker().weakKeys().makeMap();
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java
index c7ca6210d6ae37fe95068c9baa5fb654f95307e0..cad42a0f3c016bf65181e50d139ae4e2fb9158a5 100644
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java
@@ -113,9 +113,18 @@ public final class CraftScoreboardManager implements ScoreboardManager {
// CraftBukkit method
public void forAllObjectives(ObjectiveCriteria criteria, ScoreHolder holder, Consumer<ScoreAccess> consumer) {
+ // Paper start - add timings for scoreboard search
+ // plugins leaking scoreboards will make this very expensive, let server owners debug it easily
+ co.aikar.timings.MinecraftTimings.scoreboardScoreSearch.startTimingIfSync();
+ try {
+ // Paper end - add timings for scoreboard search
for (CraftScoreboard scoreboard : this.scoreboards) {
Scoreboard board = scoreboard.board;
board.forAllObjectives(criteria, holder, (score) -> consumer.accept(score));
}
+ } finally { // Paper start - add timings for scoreboard search
+ co.aikar.timings.MinecraftTimings.scoreboardScoreSearch.stopTimingIfSync();
+ }
+ // Paper end - add timings for scoreboard search
}
}

View file

@ -1,21 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Fri, 19 Feb 2021 22:51:52 -0800
Subject: [PATCH] Oprimise map impl for tracked players
Reference2BooleanOpenHashMap is going to have
better lookups than HashMap.
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index d91279f3bd009e1542e73354aadd6a16c80965e2..071e9ef3680c5dc492c6142ccd05f6788ebc3035 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -1461,7 +1461,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
final Entity entity;
private final int range;
SectionPos lastSectionPos;
- public final Set<ServerPlayerConnection> seenBy = Sets.newIdentityHashSet();
+ public final Set<ServerPlayerConnection> seenBy = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl
public TrackedEntity(final Entity entity, final int i, final int j, final boolean flag) {
this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, this.seenBy); // CraftBukkit

View file

@ -1,22 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Wed, 27 Dec 2023 16:46:07 -0800
Subject: [PATCH] Add missing InventoryType
Upstream did not add a DECORATED_POT inventory type
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
index 3b0d3e9a067fccb10122c273aaf658ba240aa716..af1ae3dacb628da23f7d2988c6e76d3fb2d64103 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
@@ -541,6 +541,10 @@ public class CraftInventory implements Inventory {
return InventoryType.COMPOSTER;
} else if (this.inventory instanceof JukeboxBlockEntity) {
return InventoryType.JUKEBOX;
+ // Paper start
+ } else if (this.inventory instanceof net.minecraft.world.level.block.entity.DecoratedPotBlockEntity) {
+ return org.bukkit.event.inventory.InventoryType.DECORATED_POT;
+ // Paper end
} else {
return InventoryType.CHEST;
}

View file

@ -1,52 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Thu, 10 Jun 2021 14:36:00 -0700
Subject: [PATCH] Optimise BlockSoil nearby water lookup
Apparently the abstract block iteration was taking about
75% of the method call.
diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java
index 529f9f57249bd1ffa2698da76ffa9d4a284088db..d59e33e7326489c6d55d316d0130f22235f4c63c 100644
--- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java
@@ -152,19 +152,28 @@ public class FarmBlock extends Block {
}
private static boolean isNearWater(LevelReader world, BlockPos pos) {
- Iterator iterator = BlockPos.betweenClosed(pos.offset(-4, 0, -4), pos.offset(4, 1, 4)).iterator();
-
- BlockPos blockposition1;
-
- do {
- if (!iterator.hasNext()) {
- return false;
+ // Paper start - Perf: remove abstract block iteration
+ int xOff = pos.getX();
+ int yOff = pos.getY();
+ int zOff = pos.getZ();
+
+ for (int dz = -4; dz <= 4; ++dz) {
+ int z = dz + zOff;
+ for (int dx = -4; dx <= 4; ++dx) {
+ int x = xOff + dx;
+ for (int dy = 0; dy <= 1; ++dy) {
+ int y = dy + yOff;
+ net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk)world.getChunk(x >> 4, z >> 4);
+ net.minecraft.world.level.material.FluidState fluid = chunk.getBlockStateFinal(x, y, z).getFluidState();
+ if (fluid.is(FluidTags.WATER)) {
+ return true;
+ }
+ }
}
+ }
- blockposition1 = (BlockPos) iterator.next();
- } while (!world.getFluidState(blockposition1).is(FluidTags.WATER));
-
- return true;
+ return false;
+ // Paper end - Perf: remove abstract block iteration
}
@Override

View file

@ -1,22 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 2 Sep 2021 00:24:06 -0700
Subject: [PATCH] Fix merchant inventory not closing on entity removal
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index dba04a8de93b9afe8b51e473de9e1d485c93987e..a473993ea48afd05a884e3ffcbdd15abe74580d2 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -2247,6 +2247,11 @@ public class ServerLevel extends Level implements WorldGenLevel {
// Spigot end
// Spigot Start
if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder && (!(entity instanceof ServerPlayer) || entity.getRemovalReason() != Entity.RemovalReason.KILLED)) { // SPIGOT-6876: closeInventory clears death message
+ // Paper start - Fix merchant inventory not closing on entity removal
+ if (entity.getBukkitEntity() instanceof org.bukkit.inventory.Merchant merchant && merchant.getTrader() != null) {
+ merchant.getTrader().closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED);
+ }
+ // Paper end - Fix merchant inventory not closing on entity removal
for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((org.bukkit.inventory.InventoryHolder) entity.getBukkitEntity()).getInventory().getViewers())) {
h.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper - Inventory close reason
}

View file

@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: stonar96 <minecraft.stonar96@gmail.com>
Date: Sun, 12 Sep 2021 00:14:21 +0200
Subject: [PATCH] Check requirement before suggesting root nodes
Child nodes are handled by CommandDispatcher#parse checking
requirements.
Vanilla clients only send ServerboundCommandSuggestionPacket when
encountering a command node with ASK_SERVER suggestions, however a
modified client can send this packet whenever it wants.
diff --git a/src/main/java/com/mojang/brigadier/CommandDispatcher.java b/src/main/java/com/mojang/brigadier/CommandDispatcher.java
index 858e41fba7dc285dd21a93f3918cc5de3887df5f..92848b64a78fce7a92e1657c2da6fc5ee53eea44 100644
--- a/src/main/java/com/mojang/brigadier/CommandDispatcher.java
+++ b/src/main/java/com/mojang/brigadier/CommandDispatcher.java
@@ -538,10 +538,14 @@ public class CommandDispatcher<S> {
int i = 0;
for (final CommandNode<S> node : parent.getChildren()) {
CompletableFuture<Suggestions> future = Suggestions.empty();
+ // Paper start - Don't suggest if the requirement isn't met
+ if (parent != this.root || node.canUse(context.getSource())) {
try {
- if (node.canUse(parse.getContext().getSource())) future = node.listSuggestions(context.build(truncatedInput), new SuggestionsBuilder(truncatedInput, truncatedInputLowerCase, start)); // CraftBukkit
+ future = node.listSuggestions(context.build(truncatedInput), new SuggestionsBuilder(truncatedInput, truncatedInputLowerCase, start)); // CraftBukkit
} catch (final CommandSyntaxException ignored) {
}
+ }
+ // Paper end - Don't suggest if the requirement isn't met
futures[i++] = future;
}

View file

@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: stonar96 <minecraft.stonar96@gmail.com>
Date: Sun, 12 Sep 2021 00:14:21 +0200
Subject: [PATCH] Don't respond to ServerboundCommandSuggestionPacket when
tab-complete is disabled
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 926c0a5f4eaaa8fb650905216d2303fb476d3fa5..1e806fd16ca5f90bdb4f71dea008d7936eb82562 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -748,6 +748,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
return;
}
// CraftBukkit end
+ // Paper start - Don't suggest if tab-complete is disabled
+ if (org.spigotmc.SpigotConfig.tabComplete < 0) {
+ return;
+ }
+ // Paper end - Don't suggest if tab-complete is disabled
// Paper start - AsyncTabCompleteEvent
TAB_COMPLETE_EXECUTOR.execute(() -> this.handleCustomCommandSuggestions0(packet));
}

View file

@ -1,108 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Fri, 30 Oct 2020 22:37:16 -0700
Subject: [PATCH] Add packet limiter config
Example config:
packet-limiter:
kick-message: '&cSent too many packets'
limits:
all:
interval: 7.0
max-packet-rate: 500.0
ServerboundPlaceRecipePacket:
interval: 4.0
max-packet-rate: 5.0
action: DROP
all section refers to all incoming packets, the action for all is
hard coded to KICK.
For specific limits, the section name is the class's name,
and an action can be defined: DROP or KICK
If interval or rate are less-than 0, the limit is ignored
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
index 2b86415e4ea197c5c44c23072c9a1cda595544a8..4d9f1fc884050993287adfa4578a87da710623fb 100644
--- a/src/main/java/net/minecraft/network/Connection.java
+++ b/src/main/java/net/minecraft/network/Connection.java
@@ -137,6 +137,22 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
return null;
}
// Paper end - add utility methods
+ // Paper start - packet limiter
+ protected final Object PACKET_LIMIT_LOCK = new Object();
+ protected final @Nullable io.papermc.paper.util.IntervalledCounter allPacketCounts = io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.isEnabled() ? new io.papermc.paper.util.IntervalledCounter(
+ (long)(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.interval() * 1.0e9)
+ ) : null;
+ protected final java.util.Map<Class<? extends net.minecraft.network.protocol.Packet<?>>, io.papermc.paper.util.IntervalledCounter> packetSpecificLimits = new java.util.HashMap<>();
+
+ private boolean stopReadingPackets;
+ private void killForPacketSpam() {
+ this.sendPacket(new ClientboundDisconnectPacket(io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.kickMessage)), PacketSendListener.thenRun(() -> {
+ this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.kickMessage));
+ }), true);
+ this.setReadOnly();
+ this.stopReadingPackets = true;
+ }
+ // Paper end - packet limiter
public Connection(PacketFlow side) {
this.receiving = side;
@@ -215,6 +231,55 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
if (packetlistener == null) {
throw new IllegalStateException("Received a packet before the packet listener was initialized");
} else {
+ // Paper start - packet limiter
+ if (this.stopReadingPackets) {
+ return;
+ }
+ if (this.allPacketCounts != null ||
+ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.containsKey(packet.getClass())) {
+ long time = System.nanoTime();
+ synchronized (PACKET_LIMIT_LOCK) {
+ if (this.allPacketCounts != null) {
+ this.allPacketCounts.updateAndAdd(1, time);
+ if (this.allPacketCounts.getRate() >= io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.maxPacketRate()) {
+ this.killForPacketSpam();
+ return;
+ }
+ }
+
+ for (Class<?> check = packet.getClass(); check != Object.class; check = check.getSuperclass()) {
+ io.papermc.paper.configuration.GlobalConfiguration.PacketLimiter.PacketLimit packetSpecificLimit =
+ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.get(check);
+ if (packetSpecificLimit == null || !packetSpecificLimit.isEnabled()) {
+ continue;
+ }
+ io.papermc.paper.util.IntervalledCounter counter = this.packetSpecificLimits.computeIfAbsent((Class)check, (clazz) -> {
+ return new io.papermc.paper.util.IntervalledCounter((long)(packetSpecificLimit.interval() * 1.0e9));
+ });
+ counter.updateAndAdd(1, time);
+ if (counter.getRate() >= packetSpecificLimit.maxPacketRate()) {
+ switch (packetSpecificLimit.action()) {
+ case DROP:
+ return;
+ case KICK:
+ String deobfedPacketName = io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(check.getName());
+
+ String playerName;
+ if (this.packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl impl) {
+ playerName = impl.getOwner().getName();
+ } else {
+ playerName = this.getLoggableAddress(net.minecraft.server.MinecraftServer.getServer().logIPs());
+ }
+
+ Connection.LOGGER.warn("{} kicked for packet spamming: {}", playerName, deobfedPacketName.substring(deobfedPacketName.lastIndexOf(".") + 1));
+ this.killForPacketSpam();
+ return;
+ }
+ }
+ }
+ }
+ }
+ // Paper end - packet limiter
if (packetlistener.shouldHandleMessage(packet)) {
try {
Connection.genericsFtw(packet, packetlistener);

View file

@ -1,72 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bjarne Koll <lynxplay101@gmail.com>
Date: Sat, 6 Nov 2021 23:15:20 +0100
Subject: [PATCH] Fix setPatternColor on tropical fish bucket meta
Prior to this commit, the tropical fish bucket meta would set the body
color to the previous metas pattern colour when updating the pattern
colour.
This commit hence simply fixes this by using the proper body colour
value when updating the pattern color.
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java
index 8169d08c1bccf7c9896bb083eba388f918fac6c9..a514fe98d3d2b65d2cfd029079c69189bcb99c01 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java
@@ -128,7 +128,7 @@ class CraftMetaTropicalFishBucket extends CraftMetaItem implements TropicalFishB
if (this.variant == null) {
this.variant = 0;
}
- this.variant = CraftTropicalFish.getData(color, this.getPatternColor(), this.getPattern());
+ this.variant = CraftTropicalFish.getData(color, this.getBodyColor(), this.getPattern()); // Paper - properly set tropical fish pattern color without mutating body color
}
@Override
diff --git a/src/test/java/io/papermc/paper/inventory/CraftMetaTropicalFishBucketTest.java b/src/test/java/io/papermc/paper/inventory/CraftMetaTropicalFishBucketTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..68a557cedbffb41f27ba21096e2ae5eebbf13f5c
--- /dev/null
+++ b/src/test/java/io/papermc/paper/inventory/CraftMetaTropicalFishBucketTest.java
@@ -0,0 +1,41 @@
+package io.papermc.paper.inventory;
+
+import org.bukkit.DyeColor;
+import org.bukkit.Material;
+import org.bukkit.entity.TropicalFish;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.TropicalFishBucketMeta;
+import org.bukkit.support.environment.AllFeatures;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+@AllFeatures
+public class CraftMetaTropicalFishBucketTest {
+
+ @Test
+ public void testAllCombinations() {
+ final var rawMeta = new ItemStack(Material.TROPICAL_FISH_BUCKET).getItemMeta();
+ Assertions.assertTrue(rawMeta instanceof TropicalFishBucketMeta, "Meta was not a tropical fish bucket");
+
+ final var meta = (TropicalFishBucketMeta) rawMeta;
+
+ for (final var bodyColor : DyeColor.values()) {
+ for (final var pattern : TropicalFish.Pattern.values()) {
+ for (final var patternColor : DyeColor.values()) {
+ meta.setBodyColor(bodyColor);
+ Assertions.assertEquals(bodyColor, meta.getBodyColor(), "Body color did not match post body color!");
+
+ meta.setPattern(pattern);
+ Assertions.assertEquals(pattern, meta.getPattern(), "Pattern did not match post pattern!");
+ Assertions.assertEquals(bodyColor, meta.getBodyColor(), "Body color did not match post pattern!");
+
+ meta.setPatternColor(patternColor);
+ Assertions.assertEquals(pattern, meta.getPattern(), "Pattern did not match post pattern color!");
+ Assertions.assertEquals(bodyColor, meta.getBodyColor(), "Body color did not match post pattern color!");
+ Assertions.assertEquals(patternColor, meta.getPatternColor(), "Pattern color did not match post pattern color!");
+ }
+ }
+ }
+ }
+
+}

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <nassim@njahnke.dev>
Date: Tue, 28 Sep 2021 09:47:47 +0200
Subject: [PATCH] Ensure valid vehicle status
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 6648af4d8d795637fae444dc85803b399592fd7d..25ca370c0b19eca529fc2c980c50e899013f0897 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -574,7 +574,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
}
}
- if (persistVehicle && entity1 != null && entity != this && entity.hasExactlyOnePlayerPassenger()) {
+ if (persistVehicle && entity1 != null && entity != this && entity.hasExactlyOnePlayerPassenger() && !entity.isRemoved()) { // Paper - Ensure valid vehicle status
// CraftBukkit end
CompoundTag nbttagcompound2 = new CompoundTag();
CompoundTag nbttagcompound3 = new CompoundTag();

View file

@ -1,22 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Noah van der Aa <ndvdaa@gmail.com>
Date: Mon, 30 Aug 2021 15:22:18 +0200
Subject: [PATCH] Prevent softlocked end exit portal generation
diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
index 460744ec3a1abe9a2d9d16c2ec521c52c7f8db95..98d1c097fdbbc8080624f365634e0812a5eea5ac 100644
--- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
+++ b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
@@ -468,6 +468,11 @@ public class EndDragonFight {
}
}
+ // Paper start - Prevent "softlocked" exit portal generation
+ if (this.portalLocation.getY() <= this.level.getMinBuildHeight()) {
+ this.portalLocation = this.portalLocation.atY(this.level.getMinBuildHeight() + 1);
+ }
+ // Paper end - Prevent "softlocked" exit portal generation
if (worldgenendtrophy.place(FeatureConfiguration.NONE, this.level, this.level.getChunkSource().getGenerator(), RandomSource.create(), this.portalLocation)) {
int i = Mth.positiveCeilDiv(4, 16);

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Tue, 7 Sep 2021 21:29:38 +0100
Subject: [PATCH] Fix CocaoDecorator causing a crash when trying to generate
without logs
diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java b/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java
index 1b59f530840a2a490e295f73db90ab266b27712f..f924f09aaf5d8fd643f86d826ab053dbe861369e 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java
+++ b/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java
@@ -26,6 +26,7 @@ public class CocoaDecorator extends TreeDecorator {
@Override
public void place(TreeDecorator.Context generator) {
+ if (generator.logs().isEmpty()) return; // Paper - Fix crash when trying to generate without logs
RandomSource randomSource = generator.random();
if (!(randomSource.nextFloat() >= this.probability)) {
List<BlockPos> list = generator.logs();

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Noah van der Aa <ndvdaa@gmail.com>
Date: Tue, 14 Sep 2021 16:24:45 +0200
Subject: [PATCH] Don't log debug logging being disabled
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
index 85f3433860abd91a89961907940a807a8b190a46..4dbb109d0526afee99b9190fc256585121aac9b5 100644
--- a/src/main/java/org/spigotmc/SpigotConfig.java
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
@@ -381,7 +381,7 @@ public class SpigotConfig
Bukkit.getLogger().info( "Debug logging is enabled" );
} else
{
- Bukkit.getLogger().info( "Debug logging is disabled" );
+ // Bukkit.getLogger().info( "Debug logging is disabled" ); // Paper - Don't log if debug logging isn't enabled.
}
}

View file

@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 11 Jul 2021 12:52:56 -0700
Subject: [PATCH] fix various menus with empty level accesses
diff --git a/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java b/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java
index c96b04f045dda384cdee9254a1765ef97e5f7f03..85e336637db8643fc5aca1dba724c9b341cbf46f 100644
--- a/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java
+++ b/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java
@@ -27,6 +27,12 @@ public interface ContainerLevelAccess {
public <T> Optional<T> evaluate(BiFunction<Level, BlockPos, T> getter) {
return Optional.empty();
}
+ // Paper start - fix menus with empty level accesses
+ @Override
+ public org.bukkit.Location getLocation() {
+ return null;
+ }
+ // Paper end - fix menus with empty level accesses
};
static ContainerLevelAccess create(final Level world, final BlockPos pos) {

View file

@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: lexikiq <noellekiq@gmail.com>
Date: Mon, 21 Jun 2021 23:21:58 -0400
Subject: [PATCH] Preserve overstacked loot
Preserves overstacked items in loot tables, such as shulker box drops, to prevent the items
from being deleted (as they'd overflow past the bounds of the container)-- or worse, causing
chunk bans via the large amount of NBT created by unstacking the items.
Fixes GH-5140 and GH-4748.
diff --git a/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java b/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java
index b231f90317fe7df9133674b12d47873520b481cb..edaf7f1692ae059581f3abc24bb228874e6d114b 100644
--- a/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java
+++ b/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java
@@ -72,9 +72,10 @@ public class LootTable {
}
public static Consumer<ItemStack> createStackSplitter(ServerLevel world, Consumer<ItemStack> consumer) {
+ boolean skipSplitter = world != null && !world.paperConfig().fixes.splitOverstackedLoot; // Paper - preserve overstacked items
return (itemstack) -> {
if (itemstack.isItemEnabled(world.enabledFeatures())) {
- if (itemstack.getCount() < itemstack.getMaxStackSize()) {
+ if (skipSplitter || itemstack.getCount() < itemstack.getMaxStackSize()) { // Paper - preserve overstacked items
consumer.accept(itemstack);
} else {
int i = itemstack.getCount();

View file

@ -1,29 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Mon, 21 Jun 2021 21:55:23 -0400
Subject: [PATCH] Update head rotation in missing places
In certain areas the player's head rotation could be desynced when teleported/moved.
This is because bukkit uses a separate head rotation field for yaw.
This issue only applies to players.
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index f21bf6c8bbf30c59f1588c2105dbd7f80c07a0f1..e34260c80d19869c9bec5ba67f7ce7db9d13a1f1 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -1844,6 +1844,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.setXRot(Mth.clamp(pitch, -90.0F, 90.0F) % 360.0F);
this.yRotO = this.getYRot();
this.xRotO = this.getXRot();
+ this.setYHeadRot(yaw); // Paper - Update head rotation
}
public void absMoveTo(double x, double y, double z) {
@@ -1886,6 +1887,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.setXRot(pitch);
this.setOldPosAndRot();
this.reapplyPosition();
+ this.setYHeadRot(yaw); // Paper - Update head rotation
}
public final void setOldPosAndRot() {

View file

@ -1,25 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Mon, 13 Sep 2021 18:55:45 -0700
Subject: [PATCH] prevent unintended light block manipulation
diff --git a/src/main/java/net/minecraft/world/level/block/LightBlock.java b/src/main/java/net/minecraft/world/level/block/LightBlock.java
index 01722473a4861533dba0ab6edf3982c0278c41e1..2b3c395529a15c9f07a4c0cff7f82199298bcb6d 100644
--- a/src/main/java/net/minecraft/world/level/block/LightBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/LightBlock.java
@@ -49,6 +49,14 @@ public class LightBlock extends Block implements SimpleWaterloggedBlock {
builder.add(LEVEL, WATERLOGGED);
}
+ // Paper start - prevent unintended light block manipulation
+ @Override
+ protected net.minecraft.world.ItemInteractionResult useItemOn(final ItemStack stack, final BlockState state, final Level world, final BlockPos pos, final Player player, final net.minecraft.world.InteractionHand hand, final BlockHitResult hit) {
+ if (player.getItemInHand(hand).getItem() != Items.LIGHT || !player.mayInteract(world, pos) || !player.mayUseItemAt(pos, hit.getDirection(), player.getItemInHand(hand))) { return net.minecraft.world.ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION; } // Paper - Prevent unintended light block manipulation
+ return super.useItemOn(stack, state, world, pos, player, hand, hit);
+ }
+ // Paper end - prevent unintended light block manipulation
+
@Override
protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) {
if (!world.isClientSide && player.canUseGameMasterBlocks()) {

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Mon, 4 Oct 2021 22:31:51 -0700
Subject: [PATCH] Fix CraftCriteria defaults map
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java
index 441e2122f837712a21328eb7659cc9925ff9b6f8..8464531a4ee400834d25c23b1eb723f49be8689e 100644
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java
@@ -54,7 +54,7 @@ public final class CraftCriteria implements Criteria {
}
static CraftCriteria getFromNMS(Objective objective) {
- return CraftCriteria.DEFAULTS.get(objective.getCriteria().getName());
+ return java.util.Objects.requireNonNullElseGet(CraftCriteria.DEFAULTS.get(objective.getCriteria().getName()), () -> new CraftCriteria(objective.getCriteria())); // Paper
}
public static CraftCriteria getFromBukkit(String name) {

View file

@ -1,485 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Wed, 6 Oct 2021 20:50:48 -0700
Subject: [PATCH] Fix upstreams block state factories
Sometimes, blocks are changed and then logic is called before the associated
tile entity is removed. When this happens, the factories were relying on the
block at the position, not the tile entity. This change prioritizes using the
tile entity type to determine the block state factory and falls back on
the material type of the block at that location.
== AT ==
public net.minecraft.world.level.block.entity.BlockEntityType validBlocks
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
index 48bee70ba4188a4a55beb6584224b0f23784dd88..cbb777f499a4e8a447153c04d09c0c71321c663c 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
@@ -387,7 +387,7 @@ public abstract class BlockEntity {
// Paper end
if (this.level == null) return null;
org.bukkit.block.Block block = this.level.getWorld().getBlockAt(this.worldPosition.getX(), this.worldPosition.getY(), this.worldPosition.getZ());
- if (block.getType() == org.bukkit.Material.AIR) return null;
+ // if (block.getType() == org.bukkit.Material.AIR) return null; // Paper - actually get the tile entity if it still exists
org.bukkit.block.BlockState state = block.getState(useSnapshot); // Paper
if (state instanceof InventoryHolder) return (InventoryHolder) state;
return null;
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
index 80bd6e8a6dadb74356a9fa9aa394efbd31c49c37..fe7e3e0628783d8d1be9635b689da8a9cb46c5d7 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
@@ -20,7 +20,7 @@ import org.bukkit.persistence.PersistentDataContainer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-public class CraftBlockEntityState<T extends BlockEntity> extends CraftBlockState implements TileState {
+public abstract class CraftBlockEntityState<T extends BlockEntity> extends CraftBlockState implements TileState { // Paper - revert upstream's revert of the block state changes
private final T tileEntity;
private final T snapshot;
@@ -196,14 +196,10 @@ public class CraftBlockEntityState<T extends BlockEntity> extends CraftBlockStat
}
@Override
- public CraftBlockEntityState<T> copy() {
- return new CraftBlockEntityState<>(this, null);
- }
+ public abstract CraftBlockEntityState<T> copy(); // Paper - make abstract
@Override
- public CraftBlockEntityState<T> copy(Location location) {
- return new CraftBlockEntityState<>(this, location);
- }
+ public abstract CraftBlockEntityState<T> copy(Location location); // Paper - make abstract
// Paper start
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
index 83ac5fc6cbbd249b5865ab203b150f53f01c9f05..b7ff7af2513204b151340538d50a65c850bdb75f 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
@@ -22,6 +22,7 @@ import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
import net.minecraft.world.level.block.entity.BellBlockEntity;
import net.minecraft.world.level.block.entity.BlastFurnaceBlockEntity;
import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.block.entity.BlockEntityType; // Paper
import net.minecraft.world.level.block.entity.BrewingStandBlockEntity;
import net.minecraft.world.level.block.entity.BrushableBlockEntity;
import net.minecraft.world.level.block.entity.CalibratedSculkSensorBlockEntity;
@@ -87,9 +88,9 @@ public final class CraftBlockStates {
private static class BlockEntityStateFactory<T extends BlockEntity, B extends CraftBlockEntityState<T>> extends BlockStateFactory<B> {
private final BiFunction<World, T, B> blockStateConstructor;
- private final BiFunction<BlockPos, net.minecraft.world.level.block.state.BlockState, T> tileEntityConstructor;
+ private final BlockEntityType<? extends T> tileEntityConstructor; // Paper
- protected BlockEntityStateFactory(Class<B> blockStateType, BiFunction<World, T, B> blockStateConstructor, BiFunction<BlockPos, net.minecraft.world.level.block.state.BlockState, T> tileEntityConstructor) {
+ protected BlockEntityStateFactory(Class<B> blockStateType, BiFunction<World, T, B> blockStateConstructor, BlockEntityType<? extends T> tileEntityConstructor) { // Paper
super(blockStateType);
this.blockStateConstructor = blockStateConstructor;
this.tileEntityConstructor = tileEntityConstructor;
@@ -106,7 +107,7 @@ public final class CraftBlockStates {
}
private T createTileEntity(BlockPos blockPosition, net.minecraft.world.level.block.state.BlockState blockData) {
- return this.tileEntityConstructor.apply(blockPosition, blockData);
+ return this.tileEntityConstructor.create(blockPosition, blockData); // Paper
}
private B createBlockState(World world, T tileEntity) {
@@ -118,228 +119,65 @@ public final class CraftBlockStates {
private static final BlockStateFactory<?> DEFAULT_FACTORY = new BlockStateFactory<CraftBlockState>(CraftBlockState.class) {
@Override
public CraftBlockState createBlockState(World world, BlockPos blockPosition, net.minecraft.world.level.block.state.BlockState blockData, BlockEntity tileEntity) {
- // SPIGOT-6754, SPIGOT-6817: Restore previous behaviour for tile entities with removed blocks (loot generation post-destroy)
- if (tileEntity != null) {
- // block with unhandled TileEntity:
- return new CraftBlockEntityState<>(world, tileEntity);
- }
+ // Paper - revert upstream's revert of the block state changes. Block entities that have already had the block type set to AIR are still valid, upstream decided to ignore them
Preconditions.checkState(tileEntity == null, "Unexpected BlockState for %s", CraftBlockType.minecraftToBukkit(blockData.getBlock()));
return new CraftBlockState(world, blockPosition, blockData);
}
};
+ // Paper start
+ private static final Map<BlockEntityType<?>, BlockStateFactory<?>> FACTORIES_BY_BLOCK_ENTITY_TYPE = new HashMap<>();
+ private static void register(BlockEntityType<?> type, BlockStateFactory<?> factory) {
+ FACTORIES_BY_BLOCK_ENTITY_TYPE.put(type, factory);
+ }
+ // Paper end
static {
- register(
- Arrays.asList(
- Material.ACACIA_SIGN,
- Material.ACACIA_WALL_SIGN,
- Material.BAMBOO_SIGN,
- Material.BAMBOO_WALL_SIGN,
- Material.BIRCH_SIGN,
- Material.BIRCH_WALL_SIGN,
- Material.CHERRY_SIGN,
- Material.CHERRY_WALL_SIGN,
- Material.CRIMSON_SIGN,
- Material.CRIMSON_WALL_SIGN,
- Material.DARK_OAK_SIGN,
- Material.DARK_OAK_WALL_SIGN,
- Material.JUNGLE_SIGN,
- Material.JUNGLE_WALL_SIGN,
- Material.MANGROVE_SIGN,
- Material.MANGROVE_WALL_SIGN,
- Material.OAK_SIGN,
- Material.OAK_WALL_SIGN,
- Material.SPRUCE_SIGN,
- Material.SPRUCE_WALL_SIGN,
- Material.WARPED_SIGN,
- Material.WARPED_WALL_SIGN
- ), CraftSign.class, CraftSign::new, SignBlockEntity::new
- );
-
- register(
- Arrays.asList(
- Material.ACACIA_HANGING_SIGN,
- Material.ACACIA_WALL_HANGING_SIGN,
- Material.BAMBOO_HANGING_SIGN,
- Material.BAMBOO_WALL_HANGING_SIGN,
- Material.BIRCH_HANGING_SIGN,
- Material.BIRCH_WALL_HANGING_SIGN,
- Material.CHERRY_HANGING_SIGN,
- Material.CHERRY_WALL_HANGING_SIGN,
- Material.CRIMSON_HANGING_SIGN,
- Material.CRIMSON_WALL_HANGING_SIGN,
- Material.DARK_OAK_HANGING_SIGN,
- Material.DARK_OAK_WALL_HANGING_SIGN,
- Material.JUNGLE_HANGING_SIGN,
- Material.JUNGLE_WALL_HANGING_SIGN,
- Material.MANGROVE_HANGING_SIGN,
- Material.MANGROVE_WALL_HANGING_SIGN,
- Material.OAK_HANGING_SIGN,
- Material.OAK_WALL_HANGING_SIGN,
- Material.SPRUCE_HANGING_SIGN,
- Material.SPRUCE_WALL_HANGING_SIGN,
- Material.WARPED_HANGING_SIGN,
- Material.WARPED_WALL_HANGING_SIGN
- ), CraftHangingSign.class, CraftHangingSign::new, HangingSignBlockEntity::new
- );
-
- register(
- Arrays.asList(
- Material.CREEPER_HEAD,
- Material.CREEPER_WALL_HEAD,
- Material.DRAGON_HEAD,
- Material.DRAGON_WALL_HEAD,
- Material.PIGLIN_HEAD,
- Material.PIGLIN_WALL_HEAD,
- Material.PLAYER_HEAD,
- Material.PLAYER_WALL_HEAD,
- Material.SKELETON_SKULL,
- Material.SKELETON_WALL_SKULL,
- Material.WITHER_SKELETON_SKULL,
- Material.WITHER_SKELETON_WALL_SKULL,
- Material.ZOMBIE_HEAD,
- Material.ZOMBIE_WALL_HEAD
- ), CraftSkull.class, CraftSkull::new, SkullBlockEntity::new
- );
-
- register(
- Arrays.asList(
- Material.COMMAND_BLOCK,
- Material.REPEATING_COMMAND_BLOCK,
- Material.CHAIN_COMMAND_BLOCK
- ), CraftCommandBlock.class, CraftCommandBlock::new, CommandBlockEntity::new
- );
-
- register(
- Arrays.asList(
- Material.BLACK_BANNER,
- Material.BLACK_WALL_BANNER,
- Material.BLUE_BANNER,
- Material.BLUE_WALL_BANNER,
- Material.BROWN_BANNER,
- Material.BROWN_WALL_BANNER,
- Material.CYAN_BANNER,
- Material.CYAN_WALL_BANNER,
- Material.GRAY_BANNER,
- Material.GRAY_WALL_BANNER,
- Material.GREEN_BANNER,
- Material.GREEN_WALL_BANNER,
- Material.LIGHT_BLUE_BANNER,
- Material.LIGHT_BLUE_WALL_BANNER,
- Material.LIGHT_GRAY_BANNER,
- Material.LIGHT_GRAY_WALL_BANNER,
- Material.LIME_BANNER,
- Material.LIME_WALL_BANNER,
- Material.MAGENTA_BANNER,
- Material.MAGENTA_WALL_BANNER,
- Material.ORANGE_BANNER,
- Material.ORANGE_WALL_BANNER,
- Material.PINK_BANNER,
- Material.PINK_WALL_BANNER,
- Material.PURPLE_BANNER,
- Material.PURPLE_WALL_BANNER,
- Material.RED_BANNER,
- Material.RED_WALL_BANNER,
- Material.WHITE_BANNER,
- Material.WHITE_WALL_BANNER,
- Material.YELLOW_BANNER,
- Material.YELLOW_WALL_BANNER
- ), CraftBanner.class, CraftBanner::new, BannerBlockEntity::new
- );
-
- register(
- Arrays.asList(
- Material.SHULKER_BOX,
- Material.WHITE_SHULKER_BOX,
- Material.ORANGE_SHULKER_BOX,
- Material.MAGENTA_SHULKER_BOX,
- Material.LIGHT_BLUE_SHULKER_BOX,
- Material.YELLOW_SHULKER_BOX,
- Material.LIME_SHULKER_BOX,
- Material.PINK_SHULKER_BOX,
- Material.GRAY_SHULKER_BOX,
- Material.LIGHT_GRAY_SHULKER_BOX,
- Material.CYAN_SHULKER_BOX,
- Material.PURPLE_SHULKER_BOX,
- Material.BLUE_SHULKER_BOX,
- Material.BROWN_SHULKER_BOX,
- Material.GREEN_SHULKER_BOX,
- Material.RED_SHULKER_BOX,
- Material.BLACK_SHULKER_BOX
- ), CraftShulkerBox.class, CraftShulkerBox::new, ShulkerBoxBlockEntity::new
- );
-
- register(
- Arrays.asList(
- Material.BLACK_BED,
- Material.BLUE_BED,
- Material.BROWN_BED,
- Material.CYAN_BED,
- Material.GRAY_BED,
- Material.GREEN_BED,
- Material.LIGHT_BLUE_BED,
- Material.LIGHT_GRAY_BED,
- Material.LIME_BED,
- Material.MAGENTA_BED,
- Material.ORANGE_BED,
- Material.PINK_BED,
- Material.PURPLE_BED,
- Material.RED_BED,
- Material.WHITE_BED,
- Material.YELLOW_BED
- ), CraftBed.class, CraftBed::new, BedBlockEntity::new
- );
-
- register(
- Arrays.asList(
- Material.BEEHIVE,
- Material.BEE_NEST
- ), CraftBeehive.class, CraftBeehive::new, BeehiveBlockEntity::new
- );
-
- register(
- Arrays.asList(
- Material.CAMPFIRE,
- Material.SOUL_CAMPFIRE
- ), CraftCampfire.class, CraftCampfire::new, CampfireBlockEntity::new
- );
-
- register(Material.BARREL, CraftBarrel.class, CraftBarrel::new, BarrelBlockEntity::new);
- register(Material.BEACON, CraftBeacon.class, CraftBeacon::new, BeaconBlockEntity::new);
- register(Material.BELL, CraftBell.class, CraftBell::new, BellBlockEntity::new);
- register(Material.BLAST_FURNACE, CraftBlastFurnace.class, CraftBlastFurnace::new, BlastFurnaceBlockEntity::new);
- register(Material.BREWING_STAND, CraftBrewingStand.class, CraftBrewingStand::new, BrewingStandBlockEntity::new);
- register(Material.CHEST, CraftChest.class, CraftChest::new, ChestBlockEntity::new);
- register(Material.CHISELED_BOOKSHELF, CraftChiseledBookshelf.class, CraftChiseledBookshelf::new, ChiseledBookShelfBlockEntity::new);
- register(Material.COMPARATOR, CraftComparator.class, CraftComparator::new, ComparatorBlockEntity::new);
- register(Material.CONDUIT, CraftConduit.class, CraftConduit::new, ConduitBlockEntity::new);
- register(Material.DAYLIGHT_DETECTOR, CraftDaylightDetector.class, CraftDaylightDetector::new, DaylightDetectorBlockEntity::new);
- register(Material.DECORATED_POT, CraftDecoratedPot.class, CraftDecoratedPot::new, DecoratedPotBlockEntity::new);
- register(Material.DISPENSER, CraftDispenser.class, CraftDispenser::new, DispenserBlockEntity::new);
- register(Material.DROPPER, CraftDropper.class, CraftDropper::new, DropperBlockEntity::new);
- register(Material.ENCHANTING_TABLE, CraftEnchantingTable.class, CraftEnchantingTable::new, EnchantingTableBlockEntity::new);
- register(Material.ENDER_CHEST, CraftEnderChest.class, CraftEnderChest::new, EnderChestBlockEntity::new);
- register(Material.END_GATEWAY, CraftEndGateway.class, CraftEndGateway::new, TheEndGatewayBlockEntity::new);
- register(Material.END_PORTAL, CraftEndPortal.class, CraftEndPortal::new, TheEndPortalBlockEntity::new);
- register(Material.FURNACE, CraftFurnaceFurnace.class, CraftFurnaceFurnace::new, FurnaceBlockEntity::new);
- register(Material.HOPPER, CraftHopper.class, CraftHopper::new, HopperBlockEntity::new);
- register(Material.JIGSAW, CraftJigsaw.class, CraftJigsaw::new, JigsawBlockEntity::new);
- register(Material.JUKEBOX, CraftJukebox.class, CraftJukebox::new, JukeboxBlockEntity::new);
- register(Material.LECTERN, CraftLectern.class, CraftLectern::new, LecternBlockEntity::new);
- register(Material.MOVING_PISTON, CraftMovingPiston.class, CraftMovingPiston::new, PistonMovingBlockEntity::new);
- register(Material.SCULK_CATALYST, CraftSculkCatalyst.class, CraftSculkCatalyst::new, SculkCatalystBlockEntity::new);
- register(Material.CALIBRATED_SCULK_SENSOR, CraftCalibratedSculkSensor.class, CraftCalibratedSculkSensor::new, CalibratedSculkSensorBlockEntity::new);
- register(Material.SCULK_SENSOR, CraftSculkSensor.class, CraftSculkSensor::new, SculkSensorBlockEntity::new);
- register(Material.SCULK_SHRIEKER, CraftSculkShrieker.class, CraftSculkShrieker::new, SculkShriekerBlockEntity::new);
- register(Material.SMOKER, CraftSmoker.class, CraftSmoker::new, SmokerBlockEntity::new);
- register(Material.SPAWNER, CraftCreatureSpawner.class, CraftCreatureSpawner::new, SpawnerBlockEntity::new);
- register(Material.STRUCTURE_BLOCK, CraftStructureBlock.class, CraftStructureBlock::new, StructureBlockEntity::new);
- register(Material.SUSPICIOUS_SAND, CraftSuspiciousSand.class, CraftSuspiciousSand::new, BrushableBlockEntity::new);
- register(Material.SUSPICIOUS_GRAVEL, CraftBrushableBlock.class, CraftBrushableBlock::new, BrushableBlockEntity::new);
- register(Material.TRAPPED_CHEST, CraftChest.class, CraftChest::new, TrappedChestBlockEntity::new);
- register(Material.CRAFTER, CraftCrafter.class, CraftCrafter::new, CrafterBlockEntity::new);
- register(Material.TRIAL_SPAWNER, CraftTrialSpawner.class, CraftTrialSpawner::new, TrialSpawnerBlockEntity::new);
- register(Material.VAULT, CraftVault.class, CraftVault::new, VaultBlockEntity::new);
+ // Paper start - simplify
+ register(BlockEntityType.SIGN, CraftSign.class, CraftSign::new);
+ register(BlockEntityType.HANGING_SIGN, CraftHangingSign.class, CraftHangingSign::new);
+ register(BlockEntityType.SKULL, CraftSkull.class, CraftSkull::new);
+ register(BlockEntityType.COMMAND_BLOCK, CraftCommandBlock.class, CraftCommandBlock::new);
+ register(BlockEntityType.BANNER, CraftBanner.class, CraftBanner::new);
+ register(BlockEntityType.SHULKER_BOX, CraftShulkerBox.class, CraftShulkerBox::new);
+ register(BlockEntityType.BED, CraftBed.class, CraftBed::new);
+ register(BlockEntityType.BEEHIVE, CraftBeehive.class, CraftBeehive::new);
+ register(BlockEntityType.CAMPFIRE, CraftCampfire.class, CraftCampfire::new);
+ register(BlockEntityType.BARREL, CraftBarrel.class, CraftBarrel::new);
+ register(BlockEntityType.BEACON, CraftBeacon.class, CraftBeacon::new);
+ register(BlockEntityType.BELL, CraftBell.class, CraftBell::new);
+ register(BlockEntityType.BLAST_FURNACE, CraftBlastFurnace.class, CraftBlastFurnace::new);
+ register(BlockEntityType.BREWING_STAND, CraftBrewingStand.class, CraftBrewingStand::new);
+ register(BlockEntityType.CHEST, CraftChest.class, CraftChest::new);
+ register(BlockEntityType.CHISELED_BOOKSHELF, CraftChiseledBookshelf.class, CraftChiseledBookshelf::new);
+ register(BlockEntityType.COMPARATOR, CraftComparator.class, CraftComparator::new);
+ register(BlockEntityType.CONDUIT, CraftConduit.class, CraftConduit::new);
+ register(BlockEntityType.DAYLIGHT_DETECTOR, CraftDaylightDetector.class, CraftDaylightDetector::new);
+ register(BlockEntityType.DECORATED_POT, CraftDecoratedPot.class, CraftDecoratedPot::new);
+ register(BlockEntityType.DISPENSER, CraftDispenser.class, CraftDispenser::new);
+ register(BlockEntityType.DROPPER, CraftDropper.class, CraftDropper::new);
+ register(BlockEntityType.ENCHANTING_TABLE, CraftEnchantingTable.class, CraftEnchantingTable::new);
+ register(BlockEntityType.ENDER_CHEST, CraftEnderChest.class, CraftEnderChest::new);
+ register(BlockEntityType.END_GATEWAY, CraftEndGateway.class, CraftEndGateway::new);
+ register(BlockEntityType.END_PORTAL, CraftEndPortal.class, CraftEndPortal::new);
+ register(BlockEntityType.FURNACE, CraftFurnaceFurnace.class, CraftFurnaceFurnace::new);
+ register(BlockEntityType.HOPPER, CraftHopper.class, CraftHopper::new);
+ register(BlockEntityType.JIGSAW, CraftJigsaw.class, CraftJigsaw::new);
+ register(BlockEntityType.JUKEBOX, CraftJukebox.class, CraftJukebox::new);
+ register(BlockEntityType.LECTERN, CraftLectern.class, CraftLectern::new);
+ register(BlockEntityType.PISTON, CraftMovingPiston.class, CraftMovingPiston::new);
+ register(BlockEntityType.SCULK_CATALYST, CraftSculkCatalyst.class, CraftSculkCatalyst::new);
+ register(BlockEntityType.SCULK_SENSOR, CraftSculkSensor.class, CraftSculkSensor::new);
+ register(BlockEntityType.SCULK_SHRIEKER, CraftSculkShrieker.class, CraftSculkShrieker::new);
+ register(BlockEntityType.CALIBRATED_SCULK_SENSOR, CraftCalibratedSculkSensor.class, CraftCalibratedSculkSensor::new);
+ register(BlockEntityType.SMOKER, CraftSmoker.class, CraftSmoker::new);
+ register(BlockEntityType.MOB_SPAWNER, CraftCreatureSpawner.class, CraftCreatureSpawner::new);
+ register(BlockEntityType.STRUCTURE_BLOCK, CraftStructureBlock.class, CraftStructureBlock::new);
+ register(BlockEntityType.BRUSHABLE_BLOCK, CraftBrushableBlock.class, CraftBrushableBlock::new); // note: spigot still uses CraftSuspiciousSand impl for that block type
+ register(BlockEntityType.TRAPPED_CHEST, CraftChest.class, CraftChest::new);
+ register(BlockEntityType.CRAFTER, CraftCrafter.class, CraftCrafter::new);
+ register(BlockEntityType.TRIAL_SPAWNER, CraftTrialSpawner.class, CraftTrialSpawner::new);
+ register(BlockEntityType.VAULT, CraftVault.class, CraftVault::new);
+ // Paper end
}
private static void register(Material blockType, BlockStateFactory<?> factory) {
@@ -347,30 +185,33 @@ public final class CraftBlockStates {
}
private static <T extends BlockEntity, B extends CraftBlockEntityState<T>> void register(
- Material blockType,
+ net.minecraft.world.level.block.entity.BlockEntityType<? extends T> blockEntityType, // Paper
Class<B> blockStateType,
- BiFunction<World, T, B> blockStateConstructor,
- BiFunction<BlockPos, net.minecraft.world.level.block.state.BlockState, T> tileEntityConstructor
+ BiFunction<World, T, B> blockStateConstructor // Paper
) {
- CraftBlockStates.register(Collections.singletonList(blockType), blockStateType, blockStateConstructor, tileEntityConstructor);
- }
-
- private static <T extends BlockEntity, B extends CraftBlockEntityState<T>> void register(
- List<Material> blockTypes,
- Class<B> blockStateType,
- BiFunction<World, T, B> blockStateConstructor,
- BiFunction<BlockPos, net.minecraft.world.level.block.state.BlockState, T> tileEntityConstructor
- ) {
- BlockStateFactory<B> factory = new BlockEntityStateFactory<>(blockStateType, blockStateConstructor, tileEntityConstructor);
- for (Material blockType : blockTypes) {
- CraftBlockStates.register(blockType, factory);
+ // Paper start
+ BlockStateFactory<B> factory = new BlockEntityStateFactory<>(blockStateType, blockStateConstructor, blockEntityType); // Paper
+ for (net.minecraft.world.level.block.Block block : blockEntityType.validBlocks) {
+ CraftBlockStates.register(CraftBlockType.minecraftToBukkit(block), factory);
}
+ CraftBlockStates.register(blockEntityType, factory);
+ // Paper end
}
private static BlockStateFactory<?> getFactory(Material material) {
return CraftBlockStates.FACTORIES.getOrDefault(material, CraftBlockStates.DEFAULT_FACTORY);
}
+ // Paper start
+ private static BlockStateFactory<?> getFactory(Material material, BlockEntityType<?> type) {
+ if (type != null) {
+ return CraftBlockStates.FACTORIES_BY_BLOCK_ENTITY_TYPE.getOrDefault(type, getFactory(material));
+ } else {
+ return getFactory(material);
+ }
+ }
+ // Paper end
+
public static Class<? extends CraftBlockState> getBlockStateType(Material material) {
Preconditions.checkNotNull(material, "material is null");
return CraftBlockStates.getFactory(material).blockStateType;
@@ -386,6 +227,13 @@ public final class CraftBlockStates {
return null;
}
+ // Paper start
+ public static Class<? extends CraftBlockState> getBlockStateType(BlockEntityType<?> blockEntityType) {
+ Preconditions.checkNotNull(blockEntityType, "blockEntityType is null");
+ return CraftBlockStates.getFactory(null, blockEntityType).blockStateType;
+ }
+ // Paper end
+
public static BlockState getBlockState(Block block) {
// Paper start
return CraftBlockStates.getBlockState(block, true);
@@ -453,7 +301,7 @@ public final class CraftBlockStates {
if (world != null && tileEntity == null && CraftBlockStates.isTileEntityOptional(material)) {
factory = CraftBlockStates.DEFAULT_FACTORY;
} else {
- factory = CraftBlockStates.getFactory(material);
+ factory = CraftBlockStates.getFactory(material, tileEntity != null ? tileEntity.getType() : null); // Paper
}
return factory.createBlockState(world, blockPosition, blockData, tileEntity);
}
@@ -472,6 +320,14 @@ public final class CraftBlockStates {
return new CraftBlockState(CraftBlock.at(world, pos), flag);
}
+ // Paper start
+ @Nullable
+ public static BlockEntityType<?> getBlockEntityType(final Material material) {
+ final BlockStateFactory<?> factory = org.bukkit.craftbukkit.block.CraftBlockStates.FACTORIES.get(material);
+ return factory instanceof final BlockEntityStateFactory<?,?> blockEntityStateFactory ? blockEntityStateFactory.tileEntityConstructor : null;
+ }
+ // Paper end
+
private CraftBlockStates() {
}
}
diff --git a/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java b/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java
index c032daa6957df2ad8b621379e415ad925f5cc162..a9810c88e05ebc1af60c051faa45e50ee183924f 100644
--- a/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java
+++ b/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java
@@ -7,6 +7,7 @@ import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.block.entity.BlockEntityType;
import org.bukkit.Material;
import org.bukkit.support.environment.AllFeatures;
import org.junit.jupiter.api.Test;
@@ -42,4 +43,13 @@ public class BlockStateTest {
}
}
}
+
+ // Paper start
+ @Test
+ public void testBlockEntityTypes() {
+ for (var blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) {
+ org.junit.jupiter.api.Assertions.assertNotNull(CraftBlockStates.getBlockStateType(blockEntityType));
+ }
+ }
+ // Paper end
}

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 49028463ba47e760281545c2f7597e3db8d6c453..7620c72a4c243cbeea245203ce03a97cbfa7d922 100644
--- a/src/main/java/co/aikar/timings/TimingsExport.java
+++ b/src/main/java/co/aikar/timings/TimingsExport.java
@@ -286,7 +286,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 5adc1952504b26772116b55a5144b7704136edfa..c5dd3aac54aa5936da4bd9f54f0e76ecf8141d27 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
@@ -436,7 +436,14 @@ public abstract class ChunkGenerator {
return (String) optional.orElseGet(placedfeature::toString);
};
- seededrandom.setFeatureSeed(i, l1, l);
+ // Paper start - Configurable feature seeds; 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 - Configurable feature seeds
try {
generatoraccessseed.setCurrentlyGenerating(supplier1);

View file

@ -1,62 +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..68098dfe716e93aafcca4d8d5b5a81d8648b3654
--- /dev/null
+++ b/src/main/java/io/papermc/paper/util/ServerEnvironment.java
@@ -0,0 +1,23 @@
+package io.papermc.paper.util;
+
+import com.sun.security.auth.module.NTSystem;
+import com.sun.security.auth.module.UnixSystem;
+import java.util.Set;
+import org.apache.commons.lang.SystemUtils;
+
+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 {
+ RUNNING_AS_ROOT_OR_ADMIN = new UnixSystem().getUid() == 0;
+ }
+ }
+
+ 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 adbd61c41cc30afa89c6ee3544c562b351304a01..585d3e51b4af87327fc2bc64a49f09732a8c61ab 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -196,6 +196,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 - detect running as root
+
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: 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 e34260c80d19869c9bec5ba67f7ce7db9d13a1f1..35c0591f9d981f1cf7da4d1dea108a8bb3e46c7a 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -705,7 +705,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
// 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.handlePortal();
}
}

View file

@ -1,41 +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 4132b5dfbc6a7693f0bb923a8b14ded571560030..ee7bb1a01bf027eb7b28e3795950a17e5f686815 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -2773,17 +2773,29 @@ 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 - Prevent excessive velocity through repeated crits
@VisibleForTesting
public void jumpFromGround() {
float f = this.getJumpPower();
if (f > 1.0E-5F) {
Vec3 vec3d = this.getDeltaMovement();
+ // Paper start - Prevent excessive velocity through repeated crits
+ 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 - Prevent excessive velocity through repeated crits
this.setDeltaMovement(vec3d.x, (double) f, vec3d.z);
if (this.isSprinting()) {
float f1 = this.getYRot() * 0.017453292F;
-
+ if (canCrit) // Paper - Prevent excessive velocity through repeated crits
this.addDeltaMovement(new Vec3((double) (-Mth.sin(f1)) * 0.2D, 0.0D, (double) Mth.cos(f1) * 0.2D));
}

View file

@ -1,30 +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 4cf88f6d815d60cfbf8e4ecf9d96d0cfadd0620b..42d7ecfab6f72517904451d9df3f0404b176fdb2 100644
--- a/src/main/java/net/minecraft/Util.java
+++ b/src/main/java/net/minecraft/Util.java
@@ -1002,16 +1002,7 @@ public class Util {
}
public void openUri(URI uri) {
- try {
- Process process = AccessController.doPrivileged(
- (PrivilegedExceptionAction<Process>)(() -> Runtime.getRuntime().exec(this.getOpenUriArguments(uri)))
- );
- process.getInputStream().close();
- process.getErrorStream().close();
- process.getOutputStream().close();
- } catch (IOException | PrivilegedActionException var3) {
- Util.LOGGER.error("Couldn't open location '{}'", uri, var3);
- }
+ throw new IllegalStateException("This method is not useful on dedicated servers."); // Paper - Fix warnings on build by removing client-only code
}
public void openFile(File file) {

View file

@ -1,141 +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 1e7235413fae39dc530eb843f1846f74bb5268b6..635fc086d832c641f840cf36d18cdc0fcc3beef3 100644
--- a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java
@@ -50,9 +50,18 @@ public class CaveVinesBlock extends GrowingPlantHeadBlock implements Bonemealabl
return to.setValue(BERRIES, from.getValue(BERRIES));
}
+ // Paper start - Fix Spigot growth modifiers
+ @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 - Fix Spigot growth modifiers
+
@Override
protected BlockState getGrowIntoState(BlockState state, RandomSource random) {
- return super.getGrowIntoState(state, random).setValue(BERRIES, Boolean.valueOf(random.nextFloat() < 0.11F));
+ // Paper start - Fix Spigot growth modifiers
+ return this.getGrowIntoState(state, random, null);
}
@Override
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 73595922dcff8e7a8595fcf033ab238bc4096630..112d2feba5f75a2a873b595617780515945c10e4 100644
--- a/src/main/java/net/minecraft/world/level/block/CropBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/CropBlock.java
@@ -91,6 +91,10 @@ public class CropBlock extends BushBlock implements BonemealableBlock {
modifier = world.spigotConfig.carrotModifier;
} else if (this == Blocks.POTATOES) {
modifier = world.spigotConfig.potatoModifier;
+ // Paper start - Fix Spigot growth modifiers
+ } else if (this == Blocks.TORCHFLOWER_CROP) {
+ modifier = world.spigotConfig.torchFlowerModifier;
+ // Paper end - Fix Spigot growth modifiers
} 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 164a855d99cf36205bd9fce04640109f20a2b96c..cf05da1c86e3018db11dc079bf50317b6639e5cc 100644
--- a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
@@ -60,12 +60,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 - Fix Spigot growth modifiers
}
}
}
+ // Paper start - Fix Spigot growth modifiers
+ protected BlockState getGrowIntoState(BlockState state, RandomSource random, @javax.annotation.Nullable Level level) {
+ return this.getGrowIntoState(state, random);
+ }
+ // Paper end - Fix Spigot growth modifiers
+
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 fd7f7d58cd159f663f8f474d9c73841c795d2990..b98e17d21d43610fb7a7ce1641c518598ff48cb0 100644
--- a/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java
@@ -114,7 +114,7 @@ public class MangrovePropaguleBlock extends SaplingBlock implements SimpleWaterl
@Override
protected 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 - Fix Spigot growth modifiers
this.advanceTree(world, pos, state, random);
}
} else {
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 c9ed129db2cadd0a33d69993961f43088725c3cb..d06e3892cf42723f8e3f621b5497c5348fa1a715 100644
--- a/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java
@@ -123,7 +123,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 - Fix Spigot growth modifiers
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 491dd55b2870093184a606efabd251c68cc24719..e76f96a5c48d1eda2f9bbb3e11dd79f23f9ab75c 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 43e4e893f0e7eed1959e6ccfa43c39ff00f083b3..86dce6796f92a5b0ae2b1bd837267c4e3f6754d0 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
@@ -69,6 +69,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 - Prevent ContainerOpenersCounter openCount from going negative
int i = this.openCount--;
// CraftBukkit start - Call redstone event

View file

@ -1,58 +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 fdb6898519acfb27baf25d8bbad2013956c1361f..3c6edc5ea44b7ec15d8fc7a2dca95a11a0d6108a 100644
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
@@ -1,6 +1,7 @@
package net.minecraft.world.entity.decoration;
import javax.annotation.Nullable;
+import io.papermc.paper.event.player.PlayerItemFrameChangeEvent; // Paper - Add PlayerItemFrameChangeEvent
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.component.DataComponents;
@@ -154,6 +155,13 @@ public class ItemFrame extends HangingEntity {
return true;
}
// CraftBukkit end
+ // Paper start - Add 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 - Add PlayerItemFrameChangeEvent
this.dropItem(source.getEntity(), false);
this.gameEvent(GameEvent.BLOCK_CHANGE, source.getEntity());
this.playSound(this.getRemoveItemSound(), 1.0F, 1.0F);
@@ -394,11 +402,24 @@ public class ItemFrame extends HangingEntity {
}
}
- this.setItem(itemstack);
+ // Paper start - Add 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 - Add PlayerItemFrameChangeEvent
this.gameEvent(GameEvent.BLOCK_CHANGE, player);
itemstack.consume(1, player);
}
} else {
+ // Paper start - Add 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 - Add PlayerItemFrameChangeEvent
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 f80cde264393f3606bc0c54ba2fd6a467f4bcb5a..c5e1040c239874dcf20b79472bf690ee7f0a9e5f 100644
--- a/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java
+++ b/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java
@@ -20,7 +20,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 - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap
}
private HashMapPalette(IdMap<T> idList, int indexBits, PaletteResize<T> listener, CrudeIncrementalIntIdentityHashBiMap<T> map) {
@@ -38,10 +38,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 - Perf: 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 - Perf: Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap and optimize
}
return i;

View file

@ -1,44 +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 f1d5c2d423dc015cc7720a4544370895f3cc644b..d6eab2a0fdbafc35efa7ed5b404357391565f4f3 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
@@ -338,14 +338,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()).getOrThrow());
- sectionBlockIDs[i] = ChunkSerializer.BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, data.getCompound("block_states")).getOrThrow(ChunkSerializer.ChunkReadException::new);
- sectionEmpty[i] = cs[i].hasOnlyAir();
+ // Paper start - Fix ChunkSnapshot#isSectionEmpty(int); and remove codec usage
+ sectionEmpty[i] = cs[i].hasOnlyAir(); // fix sectionEmpty array not being filled
+ if (!sectionEmpty[i]) {
+ sectionBlockIDs[i] = cs[i].getStates().copy(); // use copy instead of round tripping with codecs
+ } else {
+ sectionBlockIDs[i] = CraftChunk.emptyBlockIDs; // use cached instance for empty block sections
+ }
+ // Paper end - Fix ChunkSnapshot#isSectionEmpty(int)
LevelLightEngine lightengine = this.worldServer.getLightEngine();
DataLayer skyLightArray = lightengine.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(this.x, chunk.getSectionYFromSectionIndex(i), this.z)); // SPIGOT-7498: Convert section index
@@ -364,8 +367,7 @@ public class CraftChunk implements Chunk {
}
if (biome != null) {
- data.put("biomes", biomeCodec.encodeStart(NbtOps.INSTANCE, cs[i].getBiomes()).getOrThrow());
- biome[i] = biomeCodec.parse(NbtOps.INSTANCE, data.getCompound("biomes")).getOrThrow(ChunkSerializer.ChunkReadException::new);
+ biome[i] = ((PalettedContainer<Holder<net.minecraft.world.level.biome.Biome>>) cs[i].getBiomes()).copy(); // Paper - Perf: 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 0c20a334be4b1c4cf7999826f8d9bff5e36bc2b8..6d58a30a588ec98bc343ab0ab82be82d9cf0618c 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
@@ -46,6 +46,7 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
public final int[] cookingProgress;
public final int[] cookingTime;
private final RecipeManager.CachedCheck<SingleRecipeInput, CampfireCookingRecipe> quickCheck;
+ public final boolean[] stopCooking; // Paper - Add more Campfire API
public CampfireBlockEntity(BlockPos pos, BlockState state) {
super(BlockEntityType.CAMPFIRE, pos, state);
@@ -53,6 +54,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 - Add more Campfire API
}
public static void cookTick(Level world, BlockPos pos, BlockState state, CampfireBlockEntity campfire) {
@@ -63,7 +65,9 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
if (!itemstack.isEmpty()) {
flag = true;
+ if (!campfire.stopCooking[i]) { // Paper - Add more Campfire API
int j = campfire.cookingProgress[i]++;
+ } // Paper - Add more Campfire API
if (campfire.cookingProgress[i] >= campfire.cookingTime[i]) {
SingleRecipeInput singlerecipeinput = new SingleRecipeInput(itemstack);
@@ -176,6 +180,16 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
System.arraycopy(aint, 0, this.cookingTime, 0, Math.min(this.cookingTime.length, aint.length));
}
+ // Paper start - Add more Campfire API
+ 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 - Add more Campfire API
}
@Override
@@ -184,6 +198,13 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
ContainerHelper.saveAllItems(nbt, this.items, true, registryLookup);
nbt.putIntArray("CookingTimes", this.cookingProgress);
nbt.putIntArray("CookingTotalTimes", this.cookingTime);
+ // Paper start - Add more Campfire API
+ 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 - Add more Campfire API
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java b/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java
index 4850cbf2c326f1155e04a204abed2d200c02342d..a776bba2ec51c6aecce98a3abceb2c235522d99d 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java
@@ -62,4 +62,40 @@ public class CraftCampfire extends CraftBlockEntityState<CampfireBlockEntity> im
public CraftCampfire copy(Location location) {
return new CraftCampfire(this, location);
}
+
+ // 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,94 +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 12b7d50f49a2184aaf220a4a50a137b217c57124..f1237f6fd6414900ffbad0caee31aa83310eeef4 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
@@ -442,6 +442,7 @@ 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
private class ChunkBuffer extends ByteArrayOutputStream {
private final ChunkPos pos;
@@ -455,6 +456,23 @@ public class RegionFile implements AutoCloseable {
super.write(RegionFile.this.version.getId());
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 - don't write garbage data to disk if writing serialization fails
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 491035aaefff4ee96435ec5d3f9417e28eae0796..4c1212c6ef48594e766fa9e35a6e15916602d587 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
@@ -147,10 +147,17 @@ public final class RegionFileStorage implements AutoCloseable {
try {
NbtIo.write(nbt, (DataOutput) dataoutputstream);
+ // Paper start - don't write garbage data to disk if writing serialization fails
+ dataoutputstream.close(); // Only write if successful
+ } catch (final 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);
}
@@ -158,10 +165,7 @@ public final class RegionFileStorage implements AutoCloseable {
throw throwable;
}
-
- if (dataoutputstream != null) {
- dataoutputstream.close();
- }
+ // Paper - don't write garbage data to disk if writing serialization fails; move into try block to only write if successfully serialized
}
// Paper start - Chunk save reattempt
return;
@@ -208,4 +212,13 @@ public final class RegionFileStorage implements AutoCloseable {
public RegionStorageInfo info() {
return this.info;
}
+
+ // Paper start - don't write garbage data to disk if writing serialization fails
+ public static final class RegionFileSizeException extends RuntimeException {
+
+ public RegionFileSizeException(String message) {
+ super(message);
+ }
+ }
+ // Paper end - don't write garbage data to disk if writing serialization fails
}

View file

@ -1,35 +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 0d98dcfeab1455931219e498072f7129016f6678..56ce703a3b33e0530eb86389f8290d109d321589 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -3353,6 +3353,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
public void restoreFrom(Entity original) {
+ // Paper start - Forward CraftEntity in teleport command
+ CraftEntity bukkitEntity = original.bukkitEntity;
+ if (bukkitEntity != null) {
+ bukkitEntity.setHandle(this);
+ this.bukkitEntity = bukkitEntity;
+ }
+ // Paper end - Forward CraftEntity in teleport command
CompoundTag nbttagcompound = original.saveWithoutId(new CompoundTag());
nbttagcompound.remove("Dimension");
@@ -3441,8 +3448,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
entity2.restoreFrom(this);
this.removeAfterChangingDimensions();
// CraftBukkit start - Forward the CraftEntity to the new entity
- this.getBukkitEntity().setHandle(entity2);
- entity2.bukkitEntity = this.getBukkitEntity();
+ // this.getBukkitEntity().setHandle(entity2); // Paper - forward CraftEntity in teleport command; moved to Entity#restoreFrom
+ // entity2.bukkitEntity = this.getBukkitEntity();
// CraftBukkit end
}

View file

@ -1,88 +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 da1e4496d78a2c1b258ff8bb316414cb8a662ba2..b36e5574c10e6d70a399e2ac0704fd4f43dbb444 100644
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java
@@ -144,6 +144,15 @@ final class CraftObjective extends CraftScoreboardComponent implements Objective
return new CraftScore(this, CraftScoreboard.getScoreHolder(entry));
}
+ // Paper start
+ @Override
+ public Score getScoreFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException, IllegalStateException {
+ Preconditions.checkArgument(entity != null, "Entity cannot be null");
+ this.checkState();
+ return new CraftScore(this, ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle());
+ }
+ // 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 c650fc3712de01184509a03f1d1b388859e163d7..253574890a9ed23d38a84680ba1eb221dc72b310 100644
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java
@@ -235,6 +235,26 @@ public final class CraftScoreboard implements org.bukkit.scoreboard.Scoreboard {
this.board.setDisplayObjective(CraftScoreboardTranslations.fromBukkitSlot(slot), null);
}
+ // 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());
+ }
+
+ @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());
+ }
+
+ @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
+
// CraftBukkit method
public Scoreboard getHandle() {
return this.board;
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
index 7900adb0b158bc17dd792dd082c338547bc1aa0a..27219bf2f16aed64c78623d44c3cc84aa9f47065 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: