Patched
This commit is contained in:
parent
6d118492b6
commit
91b45c49ce
59 changed files with 251 additions and 615 deletions
34
patches/server/0686-Distance-manager-tick-timings.patch
Normal file
34
patches/server/0686-Distance-manager-tick-timings.patch
Normal file
|
@ -0,0 +1,34 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 18 Jul 2020 16:03:57 -0700
|
||||
Subject: [PATCH] Distance manager tick timings
|
||||
|
||||
Recently this has been taking up more time, so add a timings to
|
||||
really figure out how much.
|
||||
|
||||
diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java
|
||||
index efbf77024d235d8af9f7efc938c17afd76a51b0c..670dcfa32d003870091b75937f1603a5ac9fa7d1 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 distanceManagerTick = Timings.ofSafe("Distance Manager Tick"); // Paper - add timings for distance manager
|
||||
|
||||
public static final Timing midTickChunkTasks = Timings.ofSafe("Mid Tick Chunk Tasks");
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java
|
||||
index 718c1dd7b52fb9a501d552fdbcb3f9ff79d127d8..3ea7a4b8de338610399d5fe4ff6cf07251916448 100644
|
||||
--- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java
|
||||
+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java
|
||||
@@ -1080,7 +1080,9 @@ public final class ChunkHolderManager {
|
||||
}
|
||||
|
||||
public boolean processTicketUpdates() {
|
||||
+ co.aikar.timings.MinecraftTimings.distanceManagerTick.startTiming(); try { // Paper - add timings for distance manager
|
||||
return this.processTicketUpdates(true, true, null);
|
||||
+ } finally { co.aikar.timings.MinecraftTimings.distanceManagerTick.stopTiming(); } // Paper - add timings for distance manager
|
||||
}
|
||||
|
||||
private static final ThreadLocal<List<ChunkProgressionTask>> CURRENT_TICKET_UPDATE_SCHEDULING = new ThreadLocal<>();
|
|
@ -0,0 +1,33 @@
|
|||
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 2f3e2a404f55f09ae4db8261e495275e31228034..6d66f83afbeb650b10669fd7eeb24a315951fa86 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 (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 worker thread according
|
||||
}
|
||||
|
||||
LinkedList<BukkitWorker> getWorkers() {
|
|
@ -0,0 +1,34 @@
|
|||
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.
|
||||
|
||||
Paper recently reverted this optimisation, so it's been reintroduced
|
||||
here.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 873a375946949a8f48109d5da925933f3956600b..2ed14a26084150fc67b031a7ab6b76fd8f0b075a 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -369,6 +369,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
|
||||
@Override
|
||||
public final LevelChunk getChunk(int chunkX, int chunkZ) { // Paper - final to help inline
|
||||
+ // Paper start - make sure loaded chunks get the inlined variant of this function
|
||||
+ net.minecraft.server.level.ServerChunkCache cps = ((ServerLevel)this).getChunkSource();
|
||||
+ if (cps.mainThread == Thread.currentThread()) {
|
||||
+ LevelChunk ifLoaded = cps.getChunkAtIfLoadedMainThread(chunkX, chunkZ);
|
||||
+ if (ifLoaded != null) {
|
||||
+ return ifLoaded;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - make sure loaded chunks get the inlined variant of this function
|
||||
return (LevelChunk) this.getChunk(chunkX, chunkZ, ChunkStatus.FULL, true); // Paper - avoid a method jump
|
||||
}
|
||||
|
99
patches/server/0689-Add-packet-limiter-config.patch
Normal file
99
patches/server/0689-Add-packet-limiter-config.patch
Normal file
|
@ -0,0 +1,99 @@
|
|||
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 b7b8ac7f0e93c183e0e7f39cb753f28daace843f..fde67116dde5dee59789de0e2ee70334db429559 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -120,6 +120,23 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
private static boolean enableExplicitFlush = Boolean.getBoolean("paper.explicit-flush");
|
||||
// Paper end
|
||||
|
||||
+ // 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));
|
||||
+ }));
|
||||
+ this.setReadOnly();
|
||||
+ this.stopReadingPackets = true;
|
||||
+ }
|
||||
+ // Paper end - packet limiter
|
||||
+
|
||||
public Connection(PacketFlow side) {
|
||||
this.receiving = side;
|
||||
}
|
||||
@@ -213,6 +230,45 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
|
||||
protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet<?> packet) {
|
||||
if (this.channel.isOpen()) {
|
||||
+ // 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:
|
||||
+ this.killForPacketSpam();
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - packet limiter
|
||||
try {
|
||||
Connection.genericsFtw(packet, this.packetListener);
|
||||
} catch (RunningOnDifferentThreadException cancelledpackethandleexception) {
|
|
@ -0,0 +1,21 @@
|
|||
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 2d93251abb1018381cf00dbbb120c8ea036710c6..6916255b55a31ddd5bc32ec47f0d5ebb417be738 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
|
||||
@@ -51,6 +51,7 @@ public class ChunkStorage implements AutoCloseable {
|
||||
|
||||
// CraftBukkit start
|
||||
private boolean check(ServerChunkCache cps, int x, int z) {
|
||||
+ if (true) return true; // Paper - 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"); // Paper - this function is now MT-Safe
|
|
@ -0,0 +1,52 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 4 Apr 2020 17:00:20 -0700
|
||||
Subject: [PATCH] Consolidate flush calls for entity tracker packets
|
||||
|
||||
Most server packets seem to be sent from here, so try to avoid
|
||||
expensive flush calls from them.
|
||||
|
||||
This change was motivated due to local testing:
|
||||
|
||||
- My server spawn has 130 cows in it (for testing a prev. patch)
|
||||
- Try to let 200 players join spawn
|
||||
|
||||
Without this change, I could only get 20 players on before they
|
||||
all started timing out due to the load put on the Netty I/O threads.
|
||||
|
||||
With this change I could get all 200 on at 0ms ping.
|
||||
|
||||
(one of the primary issues is that my CPU is kinda trash, and having
|
||||
4 extra threads at 100% is just too much for it).
|
||||
|
||||
So in general this patch should reduce Netty I/O thread load.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 371f7e71610ddfbdb32dcd493f15d6ff9b90326e..42526088af333f818b02c80a3f8aa890ab78f6fb 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -807,7 +807,24 @@ public class ServerChunkCache extends ChunkSource {
|
||||
this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing
|
||||
gameprofilerfiller.pop();
|
||||
// Paper end - use set of chunks requiring updates, rather than iterating every single one loaded
|
||||
+ // Paper start - controlled flush for entity tracker packets
|
||||
+ List<net.minecraft.network.Connection> disabledFlushes = new java.util.ArrayList<>(this.level.players.size());
|
||||
+ for (ServerPlayer player : this.level.players) {
|
||||
+ net.minecraft.server.network.ServerGamePacketListenerImpl connection = player.connection;
|
||||
+ if (connection != null) {
|
||||
+ connection.connection.disableAutomaticFlush();
|
||||
+ disabledFlushes.add(connection.connection);
|
||||
+ }
|
||||
+ }
|
||||
+ try { // Paper end - controlled flush for entity tracker packets
|
||||
this.chunkMap.tick();
|
||||
+ // Paper start - controlled flush for entity tracker packets
|
||||
+ } finally {
|
||||
+ for (net.minecraft.network.Connection networkManager : disabledFlushes) {
|
||||
+ networkManager.enableAutomaticFlush();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - controlled flush for entity tracker packets
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
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
|
||||
|
||||
Just use the iblockdata already retrieved, removes a getType call.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BlockGetter.java b/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||
index 89aadd30c1973cf45c5c05fd12462e04b0b05c97..04194b5d5560e3620131c2f5cdea84ff814a4c25 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||
@@ -79,7 +79,7 @@ public interface BlockGetter extends LevelHeightAccessor {
|
||||
return BlockHitResult.miss(raytrace1.getTo(), Direction.getNearest(vec3d.x, vec3d.y, vec3d.z), BlockPos.containing(raytrace1.getTo()));
|
||||
}
|
||||
// Paper end
|
||||
- FluidState fluid = this.getFluidState(blockposition);
|
||||
+ FluidState fluid = iblockdata.getFluidState(); // Paper - don't need to go to world state again
|
||||
Vec3 vec3d = raytrace1.getFrom();
|
||||
Vec3 vec3d1 = raytrace1.getTo();
|
||||
VoxelShape voxelshape = raytrace1.getBlockShape(iblockdata, this, blockposition);
|
43
patches/server/0693-Time-scoreboard-search.patch
Normal file
43
patches/server/0693-Time-scoreboard-search.patch
Normal file
|
@ -0,0 +1,43 @@
|
|||
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 670dcfa32d003870091b75937f1603a5ac9fa7d1..112029cb275d45dced60807820f1bfe9f394496d 100644
|
||||
--- a/src/main/java/co/aikar/timings/MinecraftTimings.java
|
||||
+++ b/src/main/java/co/aikar/timings/MinecraftTimings.java
|
||||
@@ -47,6 +47,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 distanceManagerTick = Timings.ofSafe("Distance Manager Tick"); // Paper - add timings for distance manager
|
||||
+ public static final Timing scoreboardScoreSearch = Timings.ofSafe("Scoreboard score search"); // Paper - add timings for scoreboard search
|
||||
|
||||
public static final Timing midTickChunkTasks = Timings.ofSafe("Mid Tick Chunk Tasks");
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java
|
||||
index 39e19bea16419b9cbe53016084b8bbf014dcb056..138407c2d4b0bc55ddb9aac5d2aa3edadda090fb 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 getScoreboardScores(ObjectiveCriteria criteria, String name, Consumer<Score> 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, name, (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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Tue, 16 Feb 2021 00:16:56 -0800
|
||||
Subject: [PATCH] Send full pos packets for hard colliding entities
|
||||
|
||||
Prevent collision problems due to desync (i.e boats)
|
||||
|
||||
Configurable under
|
||||
`send-full-pos-for-hard-colliding-entities`
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
index c41f06c82d2db758d8a91317ef21eb2f5eb76a49..09f6948a52721b27ccd7c761a7efd09bfd7a183c 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -180,7 +180,7 @@ public class ServerEntity {
|
||||
long i1 = this.positionCodec.encodeZ(vec3d);
|
||||
boolean flag6 = k < -32768L || k > 32767L || l < -32768L || l > 32767L || i1 < -32768L || i1 > 32767L;
|
||||
|
||||
- if (!flag6 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.onGround()) {
|
||||
+ if (!flag6 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.onGround()&& !(io.papermc.paper.configuration.GlobalConfiguration.get().collisions.sendFullPosForHardCollidingEntities && this.entity.hardCollides())) { // Paper - send full pos for hard colliding entities to prevent collision problems due to desync
|
||||
if ((!flag2 || !flag3) && !(this.entity instanceof AbstractArrow)) {
|
||||
if (flag2) {
|
||||
packet1 = new ClientboundMoveEntityPacket.Pos(this.entity.getId(), (short) ((int) k), (short) ((int) l), (short) ((int) i1), this.entity.onGround());
|
22
patches/server/0695-Do-not-run-raytrace-logic-for-AIR.patch
Normal file
22
patches/server/0695-Do-not-run-raytrace-logic-for-AIR.patch
Normal file
|
@ -0,0 +1,22 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 7 Mar 2021 13:15:04 -0800
|
||||
Subject: [PATCH] Do not run raytrace logic for AIR
|
||||
|
||||
Saves 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 04194b5d5560e3620131c2f5cdea84ff814a4c25..0e8746759752b692668886370181aa5db1fd0bb0 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||
@@ -79,6 +79,7 @@ public interface BlockGetter extends LevelHeightAccessor {
|
||||
return BlockHitResult.miss(raytrace1.getTo(), Direction.getNearest(vec3d.x, vec3d.y, vec3d.z), BlockPos.containing(raytrace1.getTo()));
|
||||
}
|
||||
// Paper end
|
||||
+ if (iblockdata.isAir()) return null; // Paper - optimise air cases
|
||||
FluidState fluid = iblockdata.getFluidState(); // Paper - don't need to go to world state again
|
||||
Vec3 vec3d = raytrace1.getFrom();
|
||||
Vec3 vec3d1 = raytrace1.getTo();
|
|
@ -0,0 +1,21 @@
|
|||
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 03b802f9f6e31b1ab23af0ff7b235f64c72ec462..84dfa7efa4be86558c38ee9e6f70f87b5638173a 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1343,7 +1343,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 ReferenceOpenHashSet<>(); // Paper - optimise map impl
|
||||
|
||||
public TrackedEntity(Entity entity, int i, int j, boolean flag) {
|
||||
this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, this.seenBy); // CraftBukkit
|
|
@ -0,0 +1,51 @@
|
|||
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 b78a65ed6f632093eb34872e07d0835e766101e2..552d8c8f3f56bfccd25d11488ed7ec1644a92f47 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java
|
||||
@@ -142,19 +142,27 @@ 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 - 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;
|
||||
}
|
||||
|
||||
@Override
|
454
patches/server/0698-Optimise-random-block-ticking.patch
Normal file
454
patches/server/0698-Optimise-random-block-ticking.patch
Normal file
|
@ -0,0 +1,454 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 20 Jun 2021 16:19:26 -0700
|
||||
Subject: [PATCH] Optimise random block ticking
|
||||
|
||||
Massive performance improvement for random block ticking.
|
||||
The performance increase comes from the fact that the vast
|
||||
majority of attempted block ticks (~95% in my testing) fail
|
||||
because the randomly selected block is not tickable.
|
||||
|
||||
Now only tickable blocks are targeted, however this means that
|
||||
the maximum number of block ticks occurs per chunk. However,
|
||||
not all chunks are going to be targeted. The percent chance
|
||||
of a chunk being targeted is based on how many tickable blocks
|
||||
are in the chunk.
|
||||
This means that while block ticks are spread out less, the
|
||||
total number of blocks ticked per world tick remains the same.
|
||||
Therefore, the chance of a random tickable block being ticked
|
||||
remains the same.
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/util/math/ThreadUnsafeRandom.java b/src/main/java/io/papermc/paper/util/math/ThreadUnsafeRandom.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..7d93652c1abbb6aee6eb7c26cf35d4d032ef7b69
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/math/ThreadUnsafeRandom.java
|
||||
@@ -0,0 +1,65 @@
|
||||
+package io.papermc.paper.util.math;
|
||||
+
|
||||
+import net.minecraft.util.RandomSource;
|
||||
+import net.minecraft.world.level.levelgen.LegacyRandomSource;
|
||||
+import net.minecraft.world.level.levelgen.PositionalRandomFactory;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public final class ThreadUnsafeRandom extends LegacyRandomSource {
|
||||
+
|
||||
+ // See javadoc and internal comments for java.util.Random where these values come from, how they are used, and the author for them.
|
||||
+ private static final long multiplier = 0x5DEECE66DL;
|
||||
+ private static final long addend = 0xBL;
|
||||
+ private static final long mask = (1L << 48) - 1;
|
||||
+
|
||||
+ private static long initialScramble(long seed) {
|
||||
+ return (seed ^ multiplier) & mask;
|
||||
+ }
|
||||
+
|
||||
+ private long seed;
|
||||
+
|
||||
+ public ThreadUnsafeRandom(long seed) {
|
||||
+ super(seed);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public RandomSource fork() {
|
||||
+ return new ThreadUnsafeRandom(this.nextLong());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public PositionalRandomFactory forkPositional() {
|
||||
+ throw new UnsupportedOperationException();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setSeed(long seed) {
|
||||
+ // note: called by Random constructor
|
||||
+ this.seed = initialScramble(seed);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int next(int bits) {
|
||||
+ // avoid the expensive CAS logic used by superclass
|
||||
+ return (int) (((this.seed = this.seed * multiplier + addend) & mask) >>> (48 - bits));
|
||||
+ }
|
||||
+
|
||||
+ // Taken from
|
||||
+ // https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
|
||||
+ // https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2016/06/25/fastrange.c
|
||||
+ // Original license is public domain
|
||||
+ public static int fastRandomBounded(final long randomInteger, final long limit) {
|
||||
+ // randomInteger must be [0, pow(2, 32))
|
||||
+ // limit must be [0, pow(2, 32))
|
||||
+ return (int)((randomInteger * limit) >>> 32);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int nextInt(int bound) {
|
||||
+ // yes this breaks random's spec
|
||||
+ // however there's nothing that uses this class that relies on it
|
||||
+ return fastRandomBounded(this.next(32) & 0xFFFFFFFFL, bound);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index f8bcf1239c18a6334936cec483f2ae316429a894..b1cc896a3f5d7e59a15969308d78d2ef036b0cb1 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -764,6 +764,10 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
entityplayer.stopSleepInBed(false, false);
|
||||
});
|
||||
}
|
||||
+ // Paper start - optimise random block ticking
|
||||
+ private final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos();
|
||||
+ private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(this.random.nextLong());
|
||||
+ // Paper end
|
||||
|
||||
public void tickChunk(LevelChunk chunk, int randomTickSpeed) {
|
||||
ChunkPos chunkcoordintpair = chunk.getPos();
|
||||
@@ -773,10 +777,10 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
ProfilerFiller gameprofilerfiller = this.getProfiler();
|
||||
|
||||
gameprofilerfiller.push("thunder");
|
||||
- BlockPos blockposition;
|
||||
+ final BlockPos.MutableBlockPos blockposition = this.chunkTickMutablePosition; // Paper - use mutable to reduce allocation rate, final to force compile fail on change
|
||||
|
||||
if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - disable thunder
|
||||
- blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15));
|
||||
+ blockposition.set(this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15))); // Paper
|
||||
if (this.isRainingAt(blockposition)) {
|
||||
DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition);
|
||||
boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * this.paperConfig().entities.spawning.skeletonHorseThunderSpawnChance.or(0.01D) && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD); // Paper
|
||||
@@ -807,16 +811,25 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
int i1;
|
||||
|
||||
if (!this.paperConfig().environment.disableIceAndSnow && this.random.nextInt(16) == 0) { // Paper - Disable ice and snow
|
||||
- blockposition = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.getBlockRandomPos(j, 0, k, 15));
|
||||
- BlockPos blockposition1 = blockposition.below();
|
||||
+ // Paper start - optimise chunk ticking
|
||||
+ this.getRandomBlockPosition(j, 0, k, 15, blockposition);
|
||||
+ int normalY = chunk.getHeight(Heightmap.Types.MOTION_BLOCKING, blockposition.getX() & 15, blockposition.getZ() & 15) + 1;
|
||||
+ int downY = normalY - 1;
|
||||
+ blockposition.setY(normalY);
|
||||
+ // Paper end
|
||||
Biome biomebase = (Biome) this.getBiome(blockposition).value();
|
||||
|
||||
- if (biomebase.shouldFreeze(this, blockposition1)) {
|
||||
- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition1, Blocks.ICE.defaultBlockState(), null); // CraftBukkit
|
||||
+ // Paper start - optimise chunk ticking
|
||||
+ blockposition.setY(downY);
|
||||
+ if (biomebase.shouldFreeze(this, blockposition)) {
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition, Blocks.ICE.defaultBlockState(), null); // CraftBukkit
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
l = this.getGameRules().getInt(GameRules.RULE_SNOW_ACCUMULATION_HEIGHT);
|
||||
+
|
||||
+ blockposition.setY(normalY); // Paper
|
||||
if (l > 0 && biomebase.shouldSnow(this, blockposition)) {
|
||||
BlockState iblockdata = this.getBlockState(blockposition);
|
||||
|
||||
@@ -832,51 +845,54 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition, Blocks.SNOW.defaultBlockState(), null); // CraftBukkit
|
||||
}
|
||||
}
|
||||
+ blockposition.setY(downY); // Paper
|
||||
|
||||
- Biome.Precipitation biomebase_precipitation = biomebase.getPrecipitationAt(blockposition1);
|
||||
+ Biome.Precipitation biomebase_precipitation = biomebase.getPrecipitationAt(blockposition); // Paper
|
||||
|
||||
if (biomebase_precipitation != Biome.Precipitation.NONE) {
|
||||
- BlockState iblockdata2 = this.getBlockState(blockposition1);
|
||||
+ BlockState iblockdata2 = this.getBlockState(blockposition); // Paper
|
||||
|
||||
- iblockdata2.getBlock().handlePrecipitation(iblockdata2, this, blockposition1, biomebase_precipitation);
|
||||
+ iblockdata2.getBlock().handlePrecipitation(iblockdata2, this, blockposition, biomebase_precipitation); // Paper
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- gameprofilerfiller.popPush("tickBlocks");
|
||||
+ // Paper start - optimise random block ticking
|
||||
+ gameprofilerfiller.popPush("randomTick");
|
||||
timings.chunkTicksBlocks.startTiming(); // Paper
|
||||
if (randomTickSpeed > 0) {
|
||||
- LevelChunkSection[] achunksection = chunk.getSections();
|
||||
-
|
||||
- for (int j1 = 0; j1 < achunksection.length; ++j1) {
|
||||
- LevelChunkSection chunksection = achunksection[j1];
|
||||
-
|
||||
- if (chunksection.isRandomlyTicking()) {
|
||||
- l = chunk.getSectionYFromSectionIndex(j1);
|
||||
- int k1 = SectionPos.sectionToBlockCoord(l);
|
||||
-
|
||||
- for (i1 = 0; i1 < randomTickSpeed; ++i1) {
|
||||
- BlockPos blockposition2 = this.getBlockRandomPos(j, k1, k, 15);
|
||||
-
|
||||
- gameprofilerfiller.push("randomTick");
|
||||
- BlockState iblockdata3 = chunksection.getBlockState(blockposition2.getX() - j, blockposition2.getY() - k1, blockposition2.getZ() - k);
|
||||
+ LevelChunkSection[] sections = chunk.getSections();
|
||||
+ int minSection = io.papermc.paper.util.WorldUtil.getMinSection(this);
|
||||
+ for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) {
|
||||
+ LevelChunkSection section = sections[sectionIndex];
|
||||
+ if (section == null || section.tickingList.size() == 0) {
|
||||
+ continue;
|
||||
+ }
|
||||
|
||||
- if (iblockdata3.isRandomlyTicking()) {
|
||||
- iblockdata3.randomTick(this, blockposition2, this.random);
|
||||
- }
|
||||
+ int yPos = (sectionIndex + minSection) << 4;
|
||||
+ for (int a = 0; a < randomTickSpeed; ++a) {
|
||||
+ int tickingBlocks = section.tickingList.size();
|
||||
+ int index = this.randomTickRandom.nextInt(16 * 16 * 16);
|
||||
+ if (index >= tickingBlocks) {
|
||||
+ continue;
|
||||
+ }
|
||||
|
||||
- FluidState fluid = iblockdata3.getFluidState();
|
||||
+ long raw = section.tickingList.getRaw(index);
|
||||
+ int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw);
|
||||
+ int randomX = location & 15;
|
||||
+ int randomY = ((location >>> (4 + 4)) & 255) | yPos;
|
||||
+ int randomZ = (location >>> 4) & 15;
|
||||
|
||||
- if (fluid.isRandomlyTicking()) {
|
||||
- fluid.randomTick(this, blockposition2, this.random);
|
||||
- }
|
||||
+ BlockPos blockposition2 = blockposition.set(j + randomX, randomY, k + randomZ);
|
||||
+ BlockState iblockdata = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw);
|
||||
|
||||
- gameprofilerfiller.pop();
|
||||
- }
|
||||
+ iblockdata.randomTick(this, blockposition2, this.randomTickRandom);
|
||||
+ // We drop the fluid tick since LAVA is ALREADY TICKED by the above method (See LiquidBlock).
|
||||
+ // TODO CHECK ON UPDATE (ping the Canadian)
|
||||
}
|
||||
}
|
||||
}
|
||||
-
|
||||
+ // Paper end - optimise random block ticking
|
||||
timings.chunkTicksBlocks.stopTiming(); // Paper
|
||||
gameprofilerfiller.pop();
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/util/BitStorage.java b/src/main/java/net/minecraft/util/BitStorage.java
|
||||
index 68648c5a5e3ff079f832092af0f2f801c42d1ede..8bafd5fd7499ba4a04bf706cfd1e156073716e21 100644
|
||||
--- a/src/main/java/net/minecraft/util/BitStorage.java
|
||||
+++ b/src/main/java/net/minecraft/util/BitStorage.java
|
||||
@@ -20,4 +20,15 @@ public interface BitStorage {
|
||||
void unpack(int[] out);
|
||||
|
||||
BitStorage copy();
|
||||
+
|
||||
+ // Paper start
|
||||
+ void forEach(DataBitConsumer consumer);
|
||||
+
|
||||
+ @FunctionalInterface
|
||||
+ interface DataBitConsumer {
|
||||
+
|
||||
+ void accept(int location, int data);
|
||||
+
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/util/SimpleBitStorage.java b/src/main/java/net/minecraft/util/SimpleBitStorage.java
|
||||
index 2b3fd62dca2d1475075b5dcde56cea85b749cb44..e4d0d7e8fc58b8f9f614d74a141e452166e0364c 100644
|
||||
--- a/src/main/java/net/minecraft/util/SimpleBitStorage.java
|
||||
+++ b/src/main/java/net/minecraft/util/SimpleBitStorage.java
|
||||
@@ -124,6 +124,28 @@ public class SimpleBitStorage implements BitStorage {
|
||||
return this.bits;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public final void forEach(DataBitConsumer consumer) {
|
||||
+ int i = 0;
|
||||
+ long[] along = this.data;
|
||||
+ int j = along.length;
|
||||
+
|
||||
+ for (int k = 0; k < j; ++k) {
|
||||
+ long l = along[k];
|
||||
+
|
||||
+ for (int i1 = 0; i1 < this.valuesPerLong; ++i1) {
|
||||
+ consumer.accept(i, (int) (l & this.mask));
|
||||
+ l >>= this.bits;
|
||||
+ ++i;
|
||||
+ if (i >= this.size) {
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public void getAll(IntConsumer action) {
|
||||
int i = 0;
|
||||
diff --git a/src/main/java/net/minecraft/util/ZeroBitStorage.java b/src/main/java/net/minecraft/util/ZeroBitStorage.java
|
||||
index f0f764f36fb92c64ab2dc8a0a50c3f48321c3c9a..311625277a26c9c187025a1036978229241b965f 100644
|
||||
--- a/src/main/java/net/minecraft/util/ZeroBitStorage.java
|
||||
+++ b/src/main/java/net/minecraft/util/ZeroBitStorage.java
|
||||
@@ -46,6 +46,15 @@ public class ZeroBitStorage implements BitStorage {
|
||||
return 0;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void forEach(DataBitConsumer consumer) {
|
||||
+ for(int i = 0; i < this.size; ++i) {
|
||||
+ consumer.accept(i, 0);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public void getAll(IntConsumer action) {
|
||||
for(int i = 0; i < this.size; ++i) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
||||
index 99fc97051c61ac8d08afdc0ea4845e96705e243b..c48bf4ca76f70d878378fc43c8270de5c3332824 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
||||
@@ -84,7 +84,7 @@ public class Turtle extends Animal {
|
||||
}
|
||||
|
||||
public void setHomePos(BlockPos pos) {
|
||||
- this.entityData.set(Turtle.HOME_POS, pos);
|
||||
+ this.entityData.set(Turtle.HOME_POS, pos.immutable()); // Paper - called with mutablepos...
|
||||
}
|
||||
|
||||
public BlockPos getHomePos() {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 2ed14a26084150fc67b031a7ab6b76fd8f0b075a..4847b6358e823bd53ecfaf7d82ed9e36d45b1233 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -1293,10 +1293,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
public abstract RecipeManager getRecipeManager();
|
||||
|
||||
public BlockPos getBlockRandomPos(int x, int y, int z, int l) {
|
||||
+ // Paper start - allow use of mutable pos
|
||||
+ BlockPos.MutableBlockPos ret = new BlockPos.MutableBlockPos();
|
||||
+ this.getRandomBlockPosition(x, y, z, l, ret);
|
||||
+ return ret.immutable();
|
||||
+ }
|
||||
+ public final BlockPos.MutableBlockPos getRandomBlockPosition(int x, int y, int z, int l, BlockPos.MutableBlockPos out) {
|
||||
+ // Paper end
|
||||
this.randValue = this.randValue * 3 + 1013904223;
|
||||
int i1 = this.randValue >> 2;
|
||||
|
||||
- return new BlockPos(x + (i1 & 15), y + (i1 >> 16 & l), z + (i1 >> 8 & 15));
|
||||
+ out.set(x + (i1 & 15), y + (i1 >> 16 & l), z + (i1 >> 8 & 15)); // Paper - change to setValues call
|
||||
+ return out; // Paper
|
||||
}
|
||||
|
||||
public boolean noSave() {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
index 789664d53584c7d958572c63db22f904fb411a58..5d53b09e19b664fad337ea5098bf9cf41a7168f8 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
@@ -25,6 +25,7 @@ public class LevelChunkSection {
|
||||
public final PalettedContainer<BlockState> states;
|
||||
// CraftBukkit start - read/write
|
||||
private PalettedContainer<Holder<Biome>> biomes;
|
||||
+ public final com.destroystokyo.paper.util.maplist.IBlockDataList tickingList = new com.destroystokyo.paper.util.maplist.IBlockDataList(); // Paper
|
||||
|
||||
public LevelChunkSection(PalettedContainer<BlockState> datapaletteblock, PalettedContainer<Holder<Biome>> palettedcontainerro) {
|
||||
// CraftBukkit end
|
||||
@@ -74,6 +75,9 @@ public class LevelChunkSection {
|
||||
--this.nonEmptyBlockCount;
|
||||
if (iblockdata1.isRandomlyTicking()) {
|
||||
--this.tickingBlockCount;
|
||||
+ // Paper start
|
||||
+ this.tickingList.remove(x, y, z);
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +89,9 @@ public class LevelChunkSection {
|
||||
++this.nonEmptyBlockCount;
|
||||
if (state.isRandomlyTicking()) {
|
||||
++this.tickingBlockCount;
|
||||
+ // Paper start
|
||||
+ this.tickingList.add(x, y, z, state);
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,40 +119,31 @@ public class LevelChunkSection {
|
||||
}
|
||||
|
||||
public void recalcBlockCounts() {
|
||||
- class a implements PalettedContainer.CountConsumer<BlockState> {
|
||||
-
|
||||
- public int nonEmptyBlockCount;
|
||||
- public int tickingBlockCount;
|
||||
- public int tickingFluidCount;
|
||||
-
|
||||
- a() {}
|
||||
-
|
||||
- public void accept(BlockState iblockdata, int i) {
|
||||
- FluidState fluid = iblockdata.getFluidState();
|
||||
-
|
||||
- if (!iblockdata.isAir()) {
|
||||
- this.nonEmptyBlockCount += i;
|
||||
- if (iblockdata.isRandomlyTicking()) {
|
||||
- this.tickingBlockCount += i;
|
||||
- }
|
||||
+ // Paper start - unfuck this
|
||||
+ this.tickingList.clear();
|
||||
+ this.nonEmptyBlockCount = 0;
|
||||
+ this.tickingBlockCount = 0;
|
||||
+ this.tickingFluidCount = 0;
|
||||
+ this.states.forEachLocation((BlockState iblockdata, int i) -> {
|
||||
+ FluidState fluid = iblockdata.getFluidState();
|
||||
+
|
||||
+ if (!iblockdata.isAir()) {
|
||||
+ this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + 1);
|
||||
+ if (iblockdata.isRandomlyTicking()) {
|
||||
+ this.tickingBlockCount = (short)(this.tickingBlockCount + 1);
|
||||
+ this.tickingList.add(i, iblockdata);
|
||||
}
|
||||
+ }
|
||||
|
||||
- if (!fluid.isEmpty()) {
|
||||
- this.nonEmptyBlockCount += i;
|
||||
- if (fluid.isRandomlyTicking()) {
|
||||
- this.tickingFluidCount += i;
|
||||
- }
|
||||
+ if (!fluid.isEmpty()) {
|
||||
+ this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + 1);
|
||||
+ if (fluid.isRandomlyTicking()) {
|
||||
+ this.tickingFluidCount = (short) (this.tickingFluidCount + 1);
|
||||
}
|
||||
-
|
||||
}
|
||||
- }
|
||||
-
|
||||
- a a0 = new a();
|
||||
|
||||
- this.states.count(a0);
|
||||
- this.nonEmptyBlockCount = (short) a0.nonEmptyBlockCount;
|
||||
- this.tickingBlockCount = (short) a0.tickingBlockCount;
|
||||
- this.tickingFluidCount = (short) a0.tickingFluidCount;
|
||||
+ });
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public PalettedContainer<BlockState> getStates() {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||
index a8dc502fffdce89c44ec16cb158b04c30fb1a9cf..f4658eea741bed1c80f8aca7dc365b897b698cd4 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||
@@ -315,6 +315,14 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public void forEachLocation(PalettedContainer.CountConsumer<T> consumer) {
|
||||
+ this.data.storage.forEach((int location, int data) -> {
|
||||
+ consumer.accept(this.data.palette.valueFor(data), location);
|
||||
+ });
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@FunctionalInterface
|
||||
public interface CountConsumer<T> {
|
||||
void accept(T object, int count);
|
426
patches/server/0699-Optimise-nearby-player-lookups.patch
Normal file
426
patches/server/0699-Optimise-nearby-player-lookups.patch
Normal file
|
@ -0,0 +1,426 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 27 Aug 2020 16:22:52 -0700
|
||||
Subject: [PATCH] Optimise nearby player lookups
|
||||
|
||||
Use a distance map to map out close players.
|
||||
Note that it's important that we cache the distance map value per chunk
|
||||
since the penalty of a map lookup could outweigh the benefits of
|
||||
searching less players (as it basically did in the outside range patch).
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
index 3914fae62d3e0c0a9aeb8fd2bd48e76889c25a3a..25f983442b844465bde333131972d15df8e14415 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
@@ -96,6 +96,12 @@ public class ChunkHolder {
|
||||
this.chunkMap.needsChangeBroadcasting.add(this);
|
||||
}
|
||||
// Paper end - optimise chunk tick iteration
|
||||
+ // Paper start - optimise checkDespawn
|
||||
+ LevelChunk chunk = this.getFullChunkNowUnchecked();
|
||||
+ if (chunk != null) {
|
||||
+ chunk.updateGeneralAreaCache();
|
||||
+ }
|
||||
+ // Paper end - optimise checkDespawn
|
||||
}
|
||||
|
||||
public void onChunkRemove() {
|
||||
@@ -108,6 +114,12 @@ public class ChunkHolder {
|
||||
this.chunkMap.needsChangeBroadcasting.remove(this);
|
||||
}
|
||||
// Paper end - optimise chunk tick iteration
|
||||
+ // Paper start - optimise checkDespawn
|
||||
+ LevelChunk chunk = this.getFullChunkNowUnchecked();
|
||||
+ if (chunk != null) {
|
||||
+ chunk.removeGeneralAreaCache();
|
||||
+ }
|
||||
+ // Paper end - optimise checkDespawn
|
||||
}
|
||||
// Paper end
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 84dfa7efa4be86558c38ee9e6f70f87b5638173a..c2dec99102fa4c64c3c874f725cdc65845cd98d2 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -157,6 +157,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
public final ReferenceOpenHashSet<ChunkHolder> needsChangeBroadcasting = new ReferenceOpenHashSet<>();
|
||||
|
||||
// Paper - rewrite chunk system
|
||||
+ // Paper start - optimise checkDespawn
|
||||
+ public static final int GENERAL_AREA_MAP_SQUARE_RADIUS = 40;
|
||||
+ public static final double GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE = 16.0 * (GENERAL_AREA_MAP_SQUARE_RADIUS - 1);
|
||||
+ public static final double GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE_SQUARED = GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE * GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE;
|
||||
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerGeneralAreaMap;
|
||||
+ // Paper end - optimise checkDespawn
|
||||
|
||||
// Paper start - distance maps
|
||||
private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets<ServerPlayer> pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>();
|
||||
@@ -184,6 +190,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.playerMobDistanceMap.add(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player));
|
||||
}
|
||||
// Paper end - per player mob spawning
|
||||
+ this.playerGeneralAreaMap.add(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); // Paper - optimise checkDespawn
|
||||
}
|
||||
|
||||
void removePlayerFromDistanceMaps(ServerPlayer player) {
|
||||
@@ -193,6 +200,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.playerMobSpawnMap.remove(player);
|
||||
this.playerChunkTickRangeMap.remove(player);
|
||||
// Paper end - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
+ this.playerGeneralAreaMap.remove(player); // Paper - optimise checkDespawns
|
||||
// Paper start - per player mob spawning
|
||||
if (this.playerMobDistanceMap != null) {
|
||||
this.playerMobDistanceMap.remove(player);
|
||||
@@ -211,6 +219,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.playerMobDistanceMap.update(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player));
|
||||
}
|
||||
// Paper end - per player mob spawning
|
||||
+ this.playerGeneralAreaMap.update(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); // Paper - optimise checkDespawn
|
||||
}
|
||||
// Paper end
|
||||
// Paper start
|
||||
@@ -329,6 +338,23 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
});
|
||||
// Paper end - optimise ChunkMap#anyPlayerCloseEnoughForSpawning
|
||||
+ // Paper start - optimise checkDespawn
|
||||
+ this.playerGeneralAreaMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
|
||||
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
||||
+ LevelChunk chunk = ChunkMap.this.level.getChunkSource().getChunkAtIfCachedImmediately(rangeX, rangeZ);
|
||||
+ if (chunk != null) {
|
||||
+ chunk.updateGeneralAreaCache(newState);
|
||||
+ }
|
||||
+ },
|
||||
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
||||
+ LevelChunk chunk = ChunkMap.this.level.getChunkSource().getChunkAtIfCachedImmediately(rangeX, rangeZ);
|
||||
+ if (chunk != null) {
|
||||
+ chunk.updateGeneralAreaCache(newState);
|
||||
+ }
|
||||
+ });
|
||||
+ // Paper end - optimise checkDespawn
|
||||
}
|
||||
|
||||
protected ChunkGenerator generator() {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index b1cc896a3f5d7e59a15969308d78d2ef036b0cb1..4bec4a6955d6c38c8bd8fb9a10d153209d693a01 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -481,6 +481,84 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
}
|
||||
// Paper end
|
||||
|
||||
+ // Paper start - optimise checkDespawn
|
||||
+ public final List<ServerPlayer> playersAffectingSpawning = new java.util.ArrayList<>();
|
||||
+ // Paper end - optimise checkDespawn
|
||||
+ // Paper start - optimise get nearest players for entity AI
|
||||
+ @Override
|
||||
+ public final ServerPlayer getNearestPlayer(net.minecraft.world.entity.ai.targeting.TargetingConditions condition, @Nullable LivingEntity source,
|
||||
+ double centerX, double centerY, double centerZ) {
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> nearby;
|
||||
+ nearby = this.getChunkSource().chunkMap.playerGeneralAreaMap.getObjectsInRange(Mth.floor(centerX) >> 4, Mth.floor(centerZ) >> 4);
|
||||
+
|
||||
+ if (nearby == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ Object[] backingSet = nearby.getBackingSet();
|
||||
+
|
||||
+ double closestDistanceSquared = Double.MAX_VALUE;
|
||||
+ ServerPlayer closest = null;
|
||||
+
|
||||
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
||||
+ Object _player = backingSet[i];
|
||||
+ if (!(_player instanceof ServerPlayer)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ ServerPlayer player = (ServerPlayer)_player;
|
||||
+
|
||||
+ double distanceSquared = player.distanceToSqr(centerX, centerY, centerZ);
|
||||
+ if (distanceSquared < closestDistanceSquared && condition.test(source, player)) {
|
||||
+ closest = player;
|
||||
+ closestDistanceSquared = distanceSquared;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return closest;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Player getNearestPlayer(net.minecraft.world.entity.ai.targeting.TargetingConditions pathfindertargetcondition, LivingEntity entityliving) {
|
||||
+ return this.getNearestPlayer(pathfindertargetcondition, entityliving, entityliving.getX(), entityliving.getY(), entityliving.getZ());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Player getNearestPlayer(net.minecraft.world.entity.ai.targeting.TargetingConditions pathfindertargetcondition,
|
||||
+ double d0, double d1, double d2) {
|
||||
+ return this.getNearestPlayer(pathfindertargetcondition, null, d0, d1, d2);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<Player> getNearbyPlayers(net.minecraft.world.entity.ai.targeting.TargetingConditions condition, LivingEntity source, AABB axisalignedbb) {
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> nearby;
|
||||
+ double centerX = (axisalignedbb.maxX + axisalignedbb.minX) * 0.5;
|
||||
+ double centerZ = (axisalignedbb.maxZ + axisalignedbb.minZ) * 0.5;
|
||||
+ nearby = this.getChunkSource().chunkMap.playerGeneralAreaMap.getObjectsInRange(Mth.floor(centerX) >> 4, Mth.floor(centerZ) >> 4);
|
||||
+
|
||||
+ List<Player> ret = new java.util.ArrayList<>();
|
||||
+
|
||||
+ if (nearby == null) {
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ Object[] backingSet = nearby.getBackingSet();
|
||||
+
|
||||
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
||||
+ Object _player = backingSet[i];
|
||||
+ if (!(_player instanceof ServerPlayer)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ ServerPlayer player = (ServerPlayer)_player;
|
||||
+
|
||||
+ if (axisalignedbb.contains(player.getX(), player.getY(), player.getZ()) && condition.test(source, player)) {
|
||||
+ ret.add(player);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+ // Paper end - optimise get nearest players for entity AI
|
||||
+
|
||||
// Add env and gen to constructor, IWorldDataServer -> WorldDataServer
|
||||
public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey<Level> resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List<CustomSpawner> list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) {
|
||||
// IRegistryCustom.Dimension iregistrycustom_dimension = minecraftserver.registryAccess(); // CraftBukkit - decompile error
|
||||
@@ -606,6 +684,14 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
}
|
||||
|
||||
public void tick(BooleanSupplier shouldKeepTicking) {
|
||||
+ // Paper start - optimise checkDespawn
|
||||
+ this.playersAffectingSpawning.clear();
|
||||
+ for (ServerPlayer player : this.players) {
|
||||
+ if (net.minecraft.world.entity.EntitySelector.PLAYER_AFFECTS_SPAWNING.test(player)) {
|
||||
+ this.playersAffectingSpawning.add(player);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - optimise checkDespawn
|
||||
ProfilerFiller gameprofilerfiller = this.getProfiler();
|
||||
|
||||
this.handlingTick = true;
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
index b6e48531a2a1316eef786e0476574eb1c3c29a9e..e2a25c29ec74147b3e66aa0b3deb85a8f6ee53a5 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
@@ -858,7 +858,12 @@ public abstract class Mob extends LivingEntity implements Targeting {
|
||||
if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) {
|
||||
this.discard();
|
||||
} else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) {
|
||||
- Player entityhuman = this.level().findNearbyPlayer(this, -1.0D, EntitySelector.PLAYER_AFFECTS_SPAWNING); // Paper
|
||||
+ // Paper start - optimise checkDespawn
|
||||
+ Player entityhuman = this.level().findNearbyPlayer(this, level().paperConfig().entities.spawning.despawnRanges.get(this.getType().getCategory()).hard() + 1, EntitySelector.PLAYER_AFFECTS_SPAWNING); // Paper
|
||||
+ if (entityhuman == null) {
|
||||
+ entityhuman = ((ServerLevel)this.level()).playersAffectingSpawning.isEmpty() ? null : ((ServerLevel)this.level()).playersAffectingSpawning.get(0);
|
||||
+ }
|
||||
+ // Paper end - optimise checkDespawn
|
||||
|
||||
if (entityhuman != null) {
|
||||
double d0 = entityhuman.distanceToSqr((Entity) this);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 4847b6358e823bd53ecfaf7d82ed9e36d45b1233..799d31874be8a7498e71e7e01f84aa81a7f1eed4 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -206,6 +206,69 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
return this.getChunkIfLoaded(chunkX, chunkZ) != null;
|
||||
}
|
||||
// Paper end
|
||||
+ // Paper start - optimise checkDespawn
|
||||
+ public final List<net.minecraft.server.level.ServerPlayer> getNearbyPlayers(@Nullable Entity source, double sourceX, double sourceY,
|
||||
+ double sourceZ, double maxRange, @Nullable Predicate<Entity> predicate) {
|
||||
+ LevelChunk chunk;
|
||||
+ if (maxRange < 0.0 || maxRange >= net.minecraft.server.level.ChunkMap.GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE ||
|
||||
+ (chunk = (LevelChunk)this.getChunkIfLoadedImmediately(Mth.floor(sourceX) >> 4, Mth.floor(sourceZ) >> 4)) == null) {
|
||||
+ return this.getNearbyPlayersSlow(source, sourceX, sourceY, sourceZ, maxRange, predicate);
|
||||
+ }
|
||||
+
|
||||
+ List<net.minecraft.server.level.ServerPlayer> ret = new java.util.ArrayList<>();
|
||||
+ chunk.getNearestPlayers(sourceX, sourceY, sourceZ, predicate, maxRange, ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ private List<net.minecraft.server.level.ServerPlayer> getNearbyPlayersSlow(@Nullable Entity source, double sourceX, double sourceY,
|
||||
+ double sourceZ, double maxRange, @Nullable Predicate<Entity> predicate) {
|
||||
+ List<net.minecraft.server.level.ServerPlayer> ret = new java.util.ArrayList<>();
|
||||
+ double maxRangeSquared = maxRange * maxRange;
|
||||
+
|
||||
+ for (net.minecraft.server.level.ServerPlayer player : (List<net.minecraft.server.level.ServerPlayer>)this.players()) {
|
||||
+ if ((maxRange < 0.0 || player.distanceToSqr(sourceX, sourceY, sourceZ) < maxRangeSquared)) {
|
||||
+ if (predicate == null || predicate.test(player)) {
|
||||
+ ret.add(player);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ private net.minecraft.server.level.ServerPlayer getNearestPlayerSlow(@Nullable Entity source, double sourceX, double sourceY,
|
||||
+ double sourceZ, double maxRange, @Nullable Predicate<Entity> predicate) {
|
||||
+ net.minecraft.server.level.ServerPlayer closest = null;
|
||||
+ double closestRangeSquared = maxRange < 0.0 ? Double.MAX_VALUE : maxRange * maxRange;
|
||||
+
|
||||
+ for (net.minecraft.server.level.ServerPlayer player : (List<net.minecraft.server.level.ServerPlayer>)this.players()) {
|
||||
+ double distanceSquared = player.distanceToSqr(sourceX, sourceY, sourceZ);
|
||||
+ if (distanceSquared < closestRangeSquared && (predicate == null || predicate.test(player))) {
|
||||
+ closest = player;
|
||||
+ closestRangeSquared = distanceSquared;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return closest;
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ public final net.minecraft.server.level.ServerPlayer getNearestPlayer(@Nullable Entity source, double sourceX, double sourceY,
|
||||
+ double sourceZ, double maxRange, @Nullable Predicate<Entity> predicate) {
|
||||
+ LevelChunk chunk;
|
||||
+ if (maxRange < 0.0 || maxRange >= net.minecraft.server.level.ChunkMap.GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE ||
|
||||
+ (chunk = (LevelChunk)this.getChunkIfLoadedImmediately(Mth.floor(sourceX) >> 4, Mth.floor(sourceZ) >> 4)) == null) {
|
||||
+ return this.getNearestPlayerSlow(source, sourceX, sourceY, sourceZ, maxRange, predicate);
|
||||
+ }
|
||||
+
|
||||
+ return chunk.findNearestPlayer(sourceX, sourceY, sourceZ, maxRange, predicate);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @Nullable Player getNearestPlayer(double d0, double d1, double d2, double d3, @Nullable Predicate<Entity> predicate) {
|
||||
+ return this.getNearestPlayer(null, d0, d1, d2, d3, predicate);
|
||||
+ }
|
||||
+ // Paper end - optimise checkDespawn
|
||||
|
||||
public abstract ResourceKey<LevelStem> getTypeKey();
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
index d4f99f4592a86e2d8344bc2c44711fef1543acdf..089dd93d4cd4c1f72e63c4944b3b82c1e2ba732d 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
@@ -260,7 +260,7 @@ public final class NaturalSpawner {
|
||||
blockposition_mutableblockposition.set(l, i, i1);
|
||||
double d0 = (double) l + 0.5D;
|
||||
double d1 = (double) i1 + 0.5D;
|
||||
- Player entityhuman = world.getNearestPlayer(d0, (double) i, d1, -1.0D, false);
|
||||
+ Player entityhuman = (chunk instanceof LevelChunk) ? ((LevelChunk)chunk).findNearestPlayer(d0, i, d1, 576.0D, net.minecraft.world.entity.EntitySelector.NO_SPECTATORS) : world.getNearestPlayer(d0, (double) i, d1, -1.0D, false); // Paper - use chunk's player cache to optimize search in range
|
||||
|
||||
if (entityhuman != null) {
|
||||
double d2 = entityhuman.distanceToSqr(d0, (double) i, d1);
|
||||
@@ -334,7 +334,7 @@ public final class NaturalSpawner {
|
||||
}
|
||||
|
||||
private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel world, ChunkAccess chunk, BlockPos.MutableBlockPos pos, double squaredDistance) {
|
||||
- return squaredDistance <= 576.0D ? false : (world.getSharedSpawnPos().closerToCenterThan(new Vec3((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D), 24.0D) ? false : Objects.equals(new ChunkPos(pos), chunk.getPos()) || world.isNaturalSpawningAllowed((BlockPos) pos));
|
||||
+ return squaredDistance <= 576.0D ? false : (world.getSharedSpawnPos().closerToCenterThan(new Vec3((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D), 24.0D) ? false : Objects.equals(new ChunkPos(pos), chunk.getPos()) || world.isNaturalSpawningAllowed((BlockPos) pos)); // Paper - diff on change, copy into caller
|
||||
}
|
||||
|
||||
private static Boolean isValidSpawnPostitionForType(ServerLevel world, MobCategory group, StructureManager structureAccessor, ChunkGenerator chunkGenerator, MobSpawnSettings.SpawnerData spawnEntry, BlockPos.MutableBlockPos pos, double squaredDistance) { // Paper
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 72da008040147bc080a3e61b926a9afaaca390dd..7568baab4bec3ded6456332ed0f6a20e2721b03f 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -221,6 +221,98 @@ public class LevelChunk extends ChunkAccess {
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
+ // Paper start - optimise checkDespawn
|
||||
+ private boolean playerGeneralAreaCacheSet;
|
||||
+ private com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<net.minecraft.server.level.ServerPlayer> playerGeneralAreaCache;
|
||||
+
|
||||
+ public com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<net.minecraft.server.level.ServerPlayer> getPlayerGeneralAreaCache() {
|
||||
+ if (!this.playerGeneralAreaCacheSet) {
|
||||
+ this.updateGeneralAreaCache();
|
||||
+ }
|
||||
+ return this.playerGeneralAreaCache;
|
||||
+ }
|
||||
+
|
||||
+ public void updateGeneralAreaCache() {
|
||||
+ this.updateGeneralAreaCache(((ServerLevel)this.level).getChunkSource().chunkMap.playerGeneralAreaMap.getObjectsInRange(this.coordinateKey));
|
||||
+ }
|
||||
+
|
||||
+ public void removeGeneralAreaCache() {
|
||||
+ this.playerGeneralAreaCacheSet = false;
|
||||
+ this.playerGeneralAreaCache = null;
|
||||
+ }
|
||||
+
|
||||
+ public void updateGeneralAreaCache(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<net.minecraft.server.level.ServerPlayer> value) {
|
||||
+ this.playerGeneralAreaCacheSet = true;
|
||||
+ this.playerGeneralAreaCache = value;
|
||||
+ }
|
||||
+
|
||||
+ public net.minecraft.server.level.ServerPlayer findNearestPlayer(double sourceX, double sourceY, double sourceZ,
|
||||
+ double maxRange, java.util.function.Predicate<Entity> predicate) {
|
||||
+ if (!this.playerGeneralAreaCacheSet) {
|
||||
+ this.updateGeneralAreaCache();
|
||||
+ }
|
||||
+
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<net.minecraft.server.level.ServerPlayer> nearby = this.playerGeneralAreaCache;
|
||||
+
|
||||
+ if (nearby == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ Object[] backingSet = nearby.getBackingSet();
|
||||
+ double closestDistance = maxRange < 0.0 ? Double.MAX_VALUE : maxRange * maxRange;
|
||||
+ net.minecraft.server.level.ServerPlayer closest = null;
|
||||
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
||||
+ Object _player = backingSet[i];
|
||||
+ if (!(_player instanceof net.minecraft.server.level.ServerPlayer)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ net.minecraft.server.level.ServerPlayer player = (net.minecraft.server.level.ServerPlayer)_player;
|
||||
+
|
||||
+ double distance = player.distanceToSqr(sourceX, sourceY, sourceZ);
|
||||
+ if (distance < closestDistance && predicate.test(player)) {
|
||||
+ closest = player;
|
||||
+ closestDistance = distance;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return closest;
|
||||
+ }
|
||||
+
|
||||
+ public void getNearestPlayers(double sourceX, double sourceY, double sourceZ, java.util.function.Predicate<Entity> predicate,
|
||||
+ double range, java.util.List<net.minecraft.server.level.ServerPlayer> ret) {
|
||||
+ if (!this.playerGeneralAreaCacheSet) {
|
||||
+ this.updateGeneralAreaCache();
|
||||
+ }
|
||||
+
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<net.minecraft.server.level.ServerPlayer> nearby = this.playerGeneralAreaCache;
|
||||
+
|
||||
+ if (nearby == null) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ double rangeSquared = range * range;
|
||||
+
|
||||
+ Object[] backingSet = nearby.getBackingSet();
|
||||
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
||||
+ Object _player = backingSet[i];
|
||||
+ if (!(_player instanceof net.minecraft.server.level.ServerPlayer)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ net.minecraft.server.level.ServerPlayer player = (net.minecraft.server.level.ServerPlayer)_player;
|
||||
+
|
||||
+ if (range >= 0.0) {
|
||||
+ double distanceSquared = player.distanceToSqr(sourceX, sourceY, sourceZ);
|
||||
+ if (distanceSquared > rangeSquared) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (predicate == null || predicate.test(player)) {
|
||||
+ ret.add(player);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - optimise checkDespawn
|
||||
|
||||
public LevelChunk(ServerLevel world, ProtoChunk protoChunk, @Nullable LevelChunk.PostLoadProcessor entityLoader) {
|
||||
this(world, protoChunk.getPos(), protoChunk.getUpgradeData(), protoChunk.unpackBlockTicks(), protoChunk.unpackFluidTicks(), protoChunk.getInhabitedTime(), protoChunk.getSections(), entityLoader, protoChunk.getBlendingData());
|
187
patches/server/0700-Remove-streams-for-villager-AI.patch
Normal file
187
patches/server/0700-Remove-streams-for-villager-AI.patch
Normal file
|
@ -0,0 +1,187 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 27 Aug 2020 20:51:40 -0700
|
||||
Subject: [PATCH] Remove streams for villager AI
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java
|
||||
index b45c4f50705f80163d44d9e588f86a5770f5be38..10cbb80c7cd9ba30150d8d935c0d115719c35509 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java
|
||||
@@ -52,7 +52,7 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
|
||||
if (this.hasRequiredMemories(entity)) {
|
||||
this.status = Behavior.Status.RUNNING;
|
||||
this.orderPolicy.apply(this.behaviors);
|
||||
- this.runningPolicy.apply(this.behaviors.stream(), world, entity, time);
|
||||
+ this.runningPolicy.apply(this.behaviors.entries, world, entity, time);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -61,11 +61,13 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
|
||||
|
||||
@Override
|
||||
public final void tickOrStop(ServerLevel world, E entity, long time) {
|
||||
- this.behaviors.stream().filter((task) -> {
|
||||
- return task.getStatus() == Behavior.Status.RUNNING;
|
||||
- }).forEach((task) -> {
|
||||
- task.tickOrStop(world, entity, time);
|
||||
- });
|
||||
+ // Paper start
|
||||
+ for (BehaviorControl<? super E> task : this.behaviors) {
|
||||
+ if (task.getStatus() == Behavior.Status.RUNNING) {
|
||||
+ task.tickOrStop(world, entity, time);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
if (this.behaviors.stream().noneMatch((task) -> {
|
||||
return task.getStatus() == Behavior.Status.RUNNING;
|
||||
})) {
|
||||
@@ -77,11 +79,11 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
|
||||
@Override
|
||||
public final void doStop(ServerLevel world, E entity, long time) {
|
||||
this.status = Behavior.Status.STOPPED;
|
||||
- this.behaviors.stream().filter((task) -> {
|
||||
- return task.getStatus() == Behavior.Status.RUNNING;
|
||||
- }).forEach((task) -> {
|
||||
- task.doStop(world, entity, time);
|
||||
- });
|
||||
+ for (BehaviorControl<? super E> behavior : this.behaviors) {
|
||||
+ if (behavior.getStatus() == Behavior.Status.RUNNING) {
|
||||
+ behavior.doStop(world, entity, time);
|
||||
+ }
|
||||
+ }
|
||||
this.exitErasedMemories.forEach(entity.getBrain()::eraseMemory);
|
||||
}
|
||||
|
||||
@@ -117,25 +119,31 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
|
||||
public static enum RunningPolicy {
|
||||
RUN_ONE {
|
||||
@Override
|
||||
- public <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> tasks, ServerLevel world, E entity, long time) {
|
||||
- tasks.filter((task) -> {
|
||||
- return task.getStatus() == Behavior.Status.STOPPED;
|
||||
- }).filter((task) -> {
|
||||
- return task.tryStart(world, entity, time);
|
||||
- }).findFirst();
|
||||
+ // Paper start - remove streams
|
||||
+ public <E extends LivingEntity> void apply(List<ShufflingList.WeightedEntry<BehaviorControl<? super E>>> tasks, ServerLevel world, E entity, long time) {
|
||||
+ for (ShufflingList.WeightedEntry<BehaviorControl<? super E>> task : tasks) {
|
||||
+ final BehaviorControl<? super E> behavior = task.getData();
|
||||
+ if (behavior.getStatus() == Behavior.Status.STOPPED && behavior.tryStart(world, entity, time)) {
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - remove streams
|
||||
}
|
||||
},
|
||||
TRY_ALL {
|
||||
@Override
|
||||
- public <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> tasks, ServerLevel world, E entity, long time) {
|
||||
- tasks.filter((task) -> {
|
||||
- return task.getStatus() == Behavior.Status.STOPPED;
|
||||
- }).forEach((task) -> {
|
||||
- task.tryStart(world, entity, time);
|
||||
- });
|
||||
+ // Paper start - remove streams
|
||||
+ public <E extends LivingEntity> void apply(List<ShufflingList.WeightedEntry<BehaviorControl<? super E>>> tasks, ServerLevel world, E entity, long time) {
|
||||
+ for (ShufflingList.WeightedEntry<BehaviorControl<? super E>> task : tasks) {
|
||||
+ final BehaviorControl<? super E> behavior = task.getData();
|
||||
+ if (behavior.getStatus() == Behavior.Status.STOPPED) {
|
||||
+ behavior.tryStart(world, entity, time);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - remove streams
|
||||
}
|
||||
};
|
||||
|
||||
- public abstract <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> tasks, ServerLevel world, E entity, long time);
|
||||
+ public abstract <E extends LivingEntity> void apply(List<ShufflingList.WeightedEntry<BehaviorControl<? super E>>> tasks, ServerLevel world, E entity, long time); // Paper - remove streams
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java
|
||||
index 731ef21dbbd25d6924717de42f4569a9b5935643..fe3ab3d388f0481fb0db06b7f730f868dbf8e8a5 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/ShufflingList.java
|
||||
@@ -14,7 +14,7 @@ import java.util.stream.Stream;
|
||||
import net.minecraft.util.RandomSource;
|
||||
|
||||
public class ShufflingList<U> implements Iterable<U> {
|
||||
- protected final List<ShufflingList.WeightedEntry<U>> entries;
|
||||
+ public final List<ShufflingList.WeightedEntry<U>> entries; // Paper - public
|
||||
private final RandomSource random = RandomSource.create();
|
||||
private final boolean isUnsafe; // Paper
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
|
||||
index 1dfcc5cba6ffb463acf161a23fff1ca452184290..2c4517850a9692f1c2b1332b58e8312fe1166772 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
|
||||
@@ -25,13 +25,16 @@ public class NearestItemSensor extends Sensor<Mob> {
|
||||
protected void doTick(ServerLevel world, Mob entity) {
|
||||
Brain<?> brain = entity.getBrain();
|
||||
List<ItemEntity> list = world.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0D, 16.0D, 32.0D), (itemEntity) -> {
|
||||
- return true;
|
||||
+ return itemEntity.closerThan(entity, 9.0D) && entity.wantsToPickUp(itemEntity.getItem()); // Paper - move predicate into getEntities
|
||||
});
|
||||
- list.sort(Comparator.comparingDouble(entity::distanceToSqr));
|
||||
+ list.sort((e1, e2) -> Double.compare(entity.distanceToSqr(e1), entity.distanceToSqr(e2))); // better to take the sort perf hit than using line of sight more than we need to.
|
||||
+ // Paper start - remove streams
|
||||
// Paper start - remove streams in favour of lists
|
||||
ItemEntity nearest = null;
|
||||
- for (ItemEntity entityItem : list) {
|
||||
- if (entity.wantsToPickUp(entityItem.getItem()) && entityItem.closerThan(entity, 32.0D) && entity.hasLineOfSight(entityItem)) {
|
||||
+ for (int i = 0; i < list.size(); i++) {
|
||||
+ ItemEntity entityItem = list.get(i);
|
||||
+ if (entity.hasLineOfSight(entityItem)) {
|
||||
+ // Paper end - remove streams
|
||||
nearest = entityItem;
|
||||
break;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java
|
||||
index 312775d0430f793720211dc29bb293503e799d11..75d9c4f011b5a97def215784c92bb57bbb35d06b 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java
|
||||
@@ -21,25 +21,30 @@ public class PlayerSensor extends Sensor<LivingEntity> {
|
||||
|
||||
@Override
|
||||
protected void doTick(ServerLevel world, LivingEntity entity) {
|
||||
- List<Player> players = new java.util.ArrayList<>(world.players());
|
||||
- players.removeIf(player -> !EntitySelector.NO_SPECTATORS.test(player) || !entity.closerThan(player, 16.0D));
|
||||
- players.sort(Comparator.comparingDouble(entity::distanceTo));
|
||||
+ // Paper start - remove streams
|
||||
+ List<Player> players = (List)world.getNearbyPlayers(entity, entity.getX(), entity.getY(), entity.getZ(), 16.0D, EntitySelector.NO_SPECTATORS);
|
||||
+ players.sort((e1, e2) -> Double.compare(entity.distanceToSqr(e1), entity.distanceToSqr(e2)));
|
||||
Brain<?> brain = entity.getBrain();
|
||||
|
||||
brain.setMemory(MemoryModuleType.NEAREST_PLAYERS, players);
|
||||
|
||||
- Player nearest = null, nearestTargetable = null;
|
||||
- for (Player player : players) {
|
||||
- if (Sensor.isEntityTargetable(entity, player)) {
|
||||
- if (nearest == null) nearest = player;
|
||||
- if (Sensor.isEntityAttackable(entity, player)) {
|
||||
- nearestTargetable = player;
|
||||
- break; // Both variables are assigned, no reason to loop further
|
||||
- }
|
||||
+ Player firstTargetable = null;
|
||||
+ Player firstAttackable = null;
|
||||
+ for (int index = 0, len = players.size(); index < len; ++index) {
|
||||
+ Player player = players.get(index);
|
||||
+ if (firstTargetable == null && isEntityTargetable(entity, player)) {
|
||||
+ firstTargetable = player;
|
||||
+ }
|
||||
+ if (firstAttackable == null && isEntityAttackable(entity, player)) {
|
||||
+ firstAttackable = player;
|
||||
+ }
|
||||
+
|
||||
+ if (firstAttackable != null && firstTargetable != null) {
|
||||
+ break;
|
||||
}
|
||||
}
|
||||
- brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_PLAYER, nearest);
|
||||
- brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, nearestTargetable);
|
||||
- // Paper end
|
||||
+ brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_PLAYER, firstTargetable);
|
||||
+ brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, Optional.ofNullable(firstAttackable));
|
||||
+ // Paper end - remove streams
|
||||
}
|
||||
}
|
|
@ -0,0 +1,364 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Steinborn <git@steinborn.me>
|
||||
Date: Mon, 26 Jul 2021 02:15:17 -0400
|
||||
Subject: [PATCH] Use Velocity compression and cipher natives
|
||||
|
||||
|
||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||
index bc71323234b69a07ac84703c04734711ca0dd113..e1e8f7c42f5e68da25b11c4cfadd67425395e558 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -31,6 +31,11 @@ dependencies {
|
||||
runtimeOnly("org.xerial:sqlite-jdbc:3.42.0.0")
|
||||
runtimeOnly("com.mysql:mysql-connector-j:8.0.33")
|
||||
runtimeOnly("com.lmax:disruptor:3.4.4") // Paper
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ implementation("com.velocitypowered:velocity-native:3.1.2-SNAPSHOT") {
|
||||
+ isTransitive = false
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
runtimeOnly("org.apache.maven:maven-resolver-provider:3.9.2")
|
||||
runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.10")
|
||||
diff --git a/src/main/java/net/minecraft/network/CipherDecoder.java b/src/main/java/net/minecraft/network/CipherDecoder.java
|
||||
index 778beb445eac5769b9e4e07b4d1294c50ae2602b..c712fb8193115e1ab71b5e40fb0ccb9413062b03 100644
|
||||
--- a/src/main/java/net/minecraft/network/CipherDecoder.java
|
||||
+++ b/src/main/java/net/minecraft/network/CipherDecoder.java
|
||||
@@ -7,13 +7,29 @@ import java.util.List;
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
public class CipherDecoder extends MessageToMessageDecoder<ByteBuf> {
|
||||
- private final CipherBase cipher;
|
||||
+ private final com.velocitypowered.natives.encryption.VelocityCipher cipher; // Paper
|
||||
|
||||
- public CipherDecoder(Cipher cipher) {
|
||||
- this.cipher = new CipherBase(cipher);
|
||||
+ public CipherDecoder(com.velocitypowered.natives.encryption.VelocityCipher cipher) { // Paper
|
||||
+ this.cipher = cipher; // Paper
|
||||
}
|
||||
|
||||
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
|
||||
- list.add(this.cipher.decipher(channelHandlerContext, byteBuf));
|
||||
+ // Paper start
|
||||
+ ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), cipher, byteBuf);
|
||||
+ try {
|
||||
+ cipher.process(compatible);
|
||||
+ list.add(compatible);
|
||||
+ } catch (Exception e) {
|
||||
+ compatible.release(); // compatible will never be used if we throw an exception
|
||||
+ throw e;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
|
||||
+ cipher.close();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/CipherEncoder.java b/src/main/java/net/minecraft/network/CipherEncoder.java
|
||||
index 0f3d502a9680006bcdcd7d272240a2e5c3b46790..5dd7be70603e8754d2625bb9d16900cb01b9c730 100644
|
||||
--- a/src/main/java/net/minecraft/network/CipherEncoder.java
|
||||
+++ b/src/main/java/net/minecraft/network/CipherEncoder.java
|
||||
@@ -4,15 +4,32 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import javax.crypto.Cipher;
|
||||
+import java.util.List;
|
||||
|
||||
-public class CipherEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
- private final CipherBase cipher;
|
||||
+public class CipherEncoder extends io.netty.handler.codec.MessageToMessageEncoder<ByteBuf> { // Paper - change superclass
|
||||
+ private final com.velocitypowered.natives.encryption.VelocityCipher cipher; // Paper
|
||||
|
||||
- public CipherEncoder(Cipher cipher) {
|
||||
- this.cipher = new CipherBase(cipher);
|
||||
+ public CipherEncoder(com.velocitypowered.natives.encryption.VelocityCipher cipher) { // Paper
|
||||
+ this.cipher = cipher; // Paper
|
||||
}
|
||||
|
||||
- protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, ByteBuf byteBuf2) throws Exception {
|
||||
- this.cipher.encipher(byteBuf, byteBuf2);
|
||||
+ protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
|
||||
+ // Paper start
|
||||
+ ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), cipher, byteBuf);
|
||||
+ try {
|
||||
+ cipher.process(compatible);
|
||||
+ list.add(compatible);
|
||||
+ } catch (Exception e) {
|
||||
+ compatible.release(); // compatible will never be used if we throw an exception
|
||||
+ throw e;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
|
||||
+ cipher.close();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/CompressionDecoder.java b/src/main/java/net/minecraft/network/CompressionDecoder.java
|
||||
index b62be99c57b0a5bba0dc29809557d4d247698b13..f4d4ad983baf24d889441541d5a84dc1f49ea4d4 100644
|
||||
--- a/src/main/java/net/minecraft/network/CompressionDecoder.java
|
||||
+++ b/src/main/java/net/minecraft/network/CompressionDecoder.java
|
||||
@@ -12,13 +12,20 @@ public class CompressionDecoder extends ByteToMessageDecoder {
|
||||
public static final int MAXIMUM_COMPRESSED_LENGTH = 2097152;
|
||||
public static final int MAXIMUM_UNCOMPRESSED_LENGTH = 8388608;
|
||||
private final Inflater inflater;
|
||||
+ private final com.velocitypowered.natives.compression.VelocityCompressor compressor; // Paper
|
||||
private int threshold;
|
||||
private boolean validateDecompressed;
|
||||
|
||||
+ // Paper start
|
||||
public CompressionDecoder(int compressionThreshold, boolean rejectsBadPackets) {
|
||||
+ this(null, compressionThreshold, rejectsBadPackets);
|
||||
+ }
|
||||
+ public CompressionDecoder(com.velocitypowered.natives.compression.VelocityCompressor compressor, int compressionThreshold, boolean rejectsBadPackets) {
|
||||
this.threshold = compressionThreshold;
|
||||
this.validateDecompressed = rejectsBadPackets;
|
||||
- this.inflater = new Inflater();
|
||||
+ this.inflater = compressor == null ? new Inflater() : null;
|
||||
+ this.compressor = compressor;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
|
||||
@@ -38,6 +45,8 @@ public class CompressionDecoder extends ByteToMessageDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ if (this.inflater != null) {
|
||||
byte[] bs = new byte[friendlyByteBuf.readableBytes()];
|
||||
friendlyByteBuf.readBytes(bs);
|
||||
this.inflater.setInput(bs);
|
||||
@@ -45,10 +54,36 @@ public class CompressionDecoder extends ByteToMessageDecoder {
|
||||
this.inflater.inflate(cs);
|
||||
list.add(Unpooled.wrappedBuffer(cs));
|
||||
this.inflater.reset();
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ int claimedUncompressedSize = i; // OBFHELPER
|
||||
+ ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), this.compressor, byteBuf);
|
||||
+ ByteBuf uncompressed = com.velocitypowered.natives.util.MoreByteBufUtils.preferredBuffer(channelHandlerContext.alloc(), this.compressor, claimedUncompressedSize);
|
||||
+ try {
|
||||
+ this.compressor.inflate(compatibleIn, uncompressed, claimedUncompressedSize);
|
||||
+ list.add(uncompressed);
|
||||
+ byteBuf.clear();
|
||||
+ } catch (Exception e) {
|
||||
+ uncompressed.release();
|
||||
+ throw e;
|
||||
+ } finally {
|
||||
+ compatibleIn.release();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception {
|
||||
+ if (this.compressor != null) {
|
||||
+ this.compressor.close();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public void setThreshold(int compressionThreshold, boolean rejectsBadPackets) {
|
||||
this.threshold = compressionThreshold;
|
||||
this.validateDecompressed = rejectsBadPackets;
|
||||
diff --git a/src/main/java/net/minecraft/network/CompressionEncoder.java b/src/main/java/net/minecraft/network/CompressionEncoder.java
|
||||
index 792883afe53d2b7989c25a81c2f9a639d5e21d20..c04379ca8a4db0f4de46ad2b3b3384310eebddf3 100644
|
||||
--- a/src/main/java/net/minecraft/network/CompressionEncoder.java
|
||||
+++ b/src/main/java/net/minecraft/network/CompressionEncoder.java
|
||||
@@ -6,22 +6,37 @@ import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
- private final byte[] encodeBuf = new byte[8192];
|
||||
+ private final byte[] encodeBuf; // Paper
|
||||
private final Deflater deflater;
|
||||
+ private final com.velocitypowered.natives.compression.VelocityCompressor compressor; // Paper
|
||||
private int threshold;
|
||||
|
||||
+ // Paper start
|
||||
public CompressionEncoder(int compressionThreshold) {
|
||||
+ this(null, compressionThreshold);
|
||||
+ }
|
||||
+ public CompressionEncoder(com.velocitypowered.natives.compression.VelocityCompressor compressor, int compressionThreshold) {
|
||||
this.threshold = compressionThreshold;
|
||||
- this.deflater = new Deflater();
|
||||
+ if (compressor == null) {
|
||||
+ this.encodeBuf = new byte[8192];
|
||||
+ this.deflater = new Deflater();
|
||||
+ } else {
|
||||
+ this.encodeBuf = null;
|
||||
+ this.deflater = null;
|
||||
+ }
|
||||
+ this.compressor = compressor;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
- protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, ByteBuf byteBuf2) {
|
||||
+ protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, ByteBuf byteBuf2) throws Exception { // Paper
|
||||
int i = byteBuf.readableBytes();
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(byteBuf2);
|
||||
if (i < this.threshold) {
|
||||
friendlyByteBuf.writeVarInt(0);
|
||||
friendlyByteBuf.writeBytes(byteBuf);
|
||||
} else {
|
||||
+ // Paper start
|
||||
+ if (this.deflater != null) {
|
||||
byte[] bs = new byte[i];
|
||||
byteBuf.readBytes(bs);
|
||||
friendlyByteBuf.writeVarInt(bs.length);
|
||||
@@ -34,10 +49,48 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
}
|
||||
|
||||
this.deflater.reset();
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ friendlyByteBuf.writeVarInt(i);
|
||||
+ ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), this.compressor, byteBuf);
|
||||
+ try {
|
||||
+ this.compressor.deflate(compatibleIn, byteBuf2);
|
||||
+ } finally {
|
||||
+ compatibleIn.release();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) throws Exception{
|
||||
+ if (this.compressor != null) {
|
||||
+ // We allocate bytes to be compressed plus 1 byte. This covers two cases:
|
||||
+ //
|
||||
+ // - Compression
|
||||
+ // According to https://github.com/ebiggers/libdeflate/blob/master/libdeflate.h#L103,
|
||||
+ // if the data compresses well (and we do not have some pathological case) then the maximum
|
||||
+ // size the compressed size will ever be is the input size minus one.
|
||||
+ // - Uncompressed
|
||||
+ // This is fairly obvious - we will then have one more than the uncompressed size.
|
||||
+ int initialBufferSize = msg.readableBytes() + 1;
|
||||
+ return com.velocitypowered.natives.util.MoreByteBufUtils.preferredBuffer(ctx.alloc(), this.compressor, initialBufferSize);
|
||||
+ }
|
||||
+
|
||||
+ return super.allocateBuffer(ctx, msg, preferDirect);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
|
||||
+ if (this.compressor != null) {
|
||||
+ this.compressor.close();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public int getThreshold() {
|
||||
return this.threshold;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
||||
index fde67116dde5dee59789de0e2ee70334db429559..f1d4d8001b44ded431ecfccafd7cefee6a552709 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -513,11 +513,28 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
return networkmanager;
|
||||
}
|
||||
|
||||
- public void setEncryptionKey(Cipher decryptionCipher, Cipher encryptionCipher) {
|
||||
- this.encrypted = true;
|
||||
- this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryptionCipher));
|
||||
- this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryptionCipher));
|
||||
+ // Paper start
|
||||
+// public void setEncryptionKey(Cipher decryptionCipher, Cipher encryptionCipher) {
|
||||
+// this.encrypted = true;
|
||||
+// this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryptionCipher));
|
||||
+// this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryptionCipher));
|
||||
+// }
|
||||
+
|
||||
+ public void setupEncryption(javax.crypto.SecretKey key) throws net.minecraft.util.CryptException {
|
||||
+ if (!this.encrypted) {
|
||||
+ try {
|
||||
+ com.velocitypowered.natives.encryption.VelocityCipher decryption = com.velocitypowered.natives.util.Natives.cipher.get().forDecryption(key);
|
||||
+ com.velocitypowered.natives.encryption.VelocityCipher encryption = com.velocitypowered.natives.util.Natives.cipher.get().forEncryption(key);
|
||||
+
|
||||
+ this.encrypted = true;
|
||||
+ this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryption));
|
||||
+ this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryption));
|
||||
+ } catch (java.security.GeneralSecurityException e) {
|
||||
+ throw new net.minecraft.util.CryptException(e);
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
+ // Paper end
|
||||
|
||||
public boolean isEncrypted() {
|
||||
return this.encrypted;
|
||||
@@ -549,16 +566,17 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
|
||||
public void setupCompression(int compressionThreshold, boolean rejectsBadPackets) {
|
||||
if (compressionThreshold >= 0) {
|
||||
+ com.velocitypowered.natives.compression.VelocityCompressor compressor = com.velocitypowered.natives.util.Natives.compress.get().create(-1); // Paper
|
||||
if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder) {
|
||||
((CompressionDecoder) this.channel.pipeline().get("decompress")).setThreshold(compressionThreshold, rejectsBadPackets);
|
||||
} else {
|
||||
- this.channel.pipeline().addBefore("decoder", "decompress", new CompressionDecoder(compressionThreshold, rejectsBadPackets));
|
||||
+ this.channel.pipeline().addBefore("decoder", "decompress", new CompressionDecoder(compressor, compressionThreshold, rejectsBadPackets)); // Paper
|
||||
}
|
||||
|
||||
if (this.channel.pipeline().get("compress") instanceof CompressionEncoder) {
|
||||
((CompressionEncoder) this.channel.pipeline().get("compress")).setThreshold(compressionThreshold);
|
||||
} else {
|
||||
- this.channel.pipeline().addBefore("encoder", "compress", new CompressionEncoder(compressionThreshold));
|
||||
+ this.channel.pipeline().addBefore("encoder", "compress", new CompressionEncoder(compressor, compressionThreshold)); // Paper
|
||||
}
|
||||
this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_THRESHOLD_SET); // Paper
|
||||
} else {
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
index d86830ea180bebb409fc20ed43dd25cd0856f623..14f037e721ac8ba885536cab43d3d398b011a397 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
@@ -101,6 +101,11 @@ public class ServerConnectionListener {
|
||||
ServerConnectionListener.LOGGER.info("Using default channel type");
|
||||
}
|
||||
|
||||
+ // Paper start - indicate Velocity natives in use
|
||||
+ ServerConnectionListener.LOGGER.info("Paper: Using " + com.velocitypowered.natives.util.Natives.compress.getLoadedVariant() + " compression from Velocity.");
|
||||
+ ServerConnectionListener.LOGGER.info("Paper: Using " + com.velocitypowered.natives.util.Natives.cipher.getLoadedVariant() + " cipher from Velocity.");
|
||||
+ // Paper end
|
||||
+
|
||||
this.channels.add(((ServerBootstrap) ((ServerBootstrap) (new ServerBootstrap()).channel(oclass)).childHandler(new ChannelInitializer<Channel>() {
|
||||
protected void initChannel(Channel channel) {
|
||||
try {
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index b026c003e1fc02a9ea426f3126acb788fc09a874..595779cfd0ee1c405d7936f00a7cae1706125e7f 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -265,12 +265,14 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
}
|
||||
|
||||
SecretKey secretkey = packet.getSecretKey(privatekey);
|
||||
- Cipher cipher = Crypt.getCipher(2, secretkey);
|
||||
- Cipher cipher1 = Crypt.getCipher(1, secretkey);
|
||||
+ // Paper start
|
||||
+// Cipher cipher = Crypt.getCipher(2, secretkey);
|
||||
+// Cipher cipher1 = Crypt.getCipher(1, secretkey);
|
||||
+ // Paper end
|
||||
|
||||
s = (new BigInteger(Crypt.digestData("", this.server.getKeyPair().getPublic(), secretkey))).toString(16);
|
||||
this.state = ServerLoginPacketListenerImpl.State.AUTHENTICATING;
|
||||
- this.connection.setEncryptionKey(cipher, cipher1);
|
||||
+ this.connection.setupEncryption(secretkey); // Paper
|
||||
} catch (CryptException cryptographyexception) {
|
||||
throw new IllegalStateException("Protocol error", cryptographyexception);
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 30 Aug 2021 04:26:40 -0700
|
||||
Subject: [PATCH] Reduce worldgen thread worker count for low core count CPUs
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
|
||||
index 5579dad0ba8f2e4ce43883e7d36059c2a2bd1b83..fcade0a121f155dbf4f5f8af66240923d8da460d 100644
|
||||
--- a/src/main/java/net/minecraft/Util.java
|
||||
+++ b/src/main/java/net/minecraft/Util.java
|
||||
@@ -147,7 +147,19 @@ public class Util {
|
||||
|
||||
private static ExecutorService makeExecutor(String s, int priorityModifier) { // Paper - add priority
|
||||
// Paper start - use simpler thread pool that allows 1 thread
|
||||
- int i = Math.min(8, Math.max(Runtime.getRuntime().availableProcessors() - 2, 1));
|
||||
+ // Paper start - also try to avoid suffocating the system with the worldgen workers
|
||||
+ int cpus = Runtime.getRuntime().availableProcessors() / 2;
|
||||
+ int i;
|
||||
+ if (cpus <= 4) {
|
||||
+ i = cpus <= 2 ? 1 : 2;
|
||||
+ } else if (cpus <= 8) {
|
||||
+ // [5, 8]
|
||||
+ i = Math.max(3, cpus - 2);
|
||||
+ } else {
|
||||
+ i = cpus * 2 / 3;
|
||||
+ }
|
||||
+ i = Math.min(8, i);
|
||||
+ // Paper end - also try to avoid suffocating the system with the worldgen workers
|
||||
i = Integer.getInteger("Paper.WorkerThreadCount", i);
|
||||
ExecutorService executorService;
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nassim Jahnke <nassim@njahnke.dev>
|
||||
Date: Sun, 24 Oct 2021 15:49:35 +0200
|
||||
Subject: [PATCH] Fix Bukkit NamespacedKey shenanigans
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java
|
||||
index 9ca389ca789dc54bba3542cac0aac2e1dc66c870..15173e715fa36546820d930a46e0f0c493d07cfc 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java
|
||||
@@ -17,7 +17,7 @@ public class PaperContainerEntityLootableInventory implements PaperLootableEntit
|
||||
|
||||
@Override
|
||||
public org.bukkit.loot.LootTable getLootTable() {
|
||||
- return entity.getLootTable() != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(entity.getLootTable())) : null;
|
||||
+ return entity.getLootTable() != null && !entity.getLootTable().getPath().isEmpty() ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(entity.getLootTable())) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
|
||||
index 9cfa5d36a6991067a3866e0d437749fafcc0158e..2ee4ee14ab3345486dad6b24fd9a4fcc6c746b99 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
|
||||
@@ -15,7 +15,7 @@ public class PaperTileEntityLootableInventory implements PaperLootableBlockInven
|
||||
|
||||
@Override
|
||||
public org.bukkit.loot.LootTable getLootTable() {
|
||||
- return tileEntityLootable.lootTable != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(tileEntityLootable.lootTable)) : null;
|
||||
+ return tileEntityLootable.lootTable != null && !tileEntityLootable.lootTable.getPath().isEmpty() ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(tileEntityLootable.lootTable)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java b/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java
|
||||
index 5f40d240b879e3989897b6e45725a8e5a6a7f194..5014192edb9616ce725fc1592832034789527b6f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java
|
||||
@@ -13,7 +13,7 @@ public final class CraftNamespacedKey {
|
||||
return null;
|
||||
}
|
||||
ResourceLocation minecraft = ResourceLocation.tryParse(string);
|
||||
- return (minecraft == null) ? null : CraftNamespacedKey.fromMinecraft(minecraft);
|
||||
+ return (minecraft == null || minecraft.getPath().isEmpty()) ? null : CraftNamespacedKey.fromMinecraft(minecraft); // Paper - Bukkit's parser does not match Vanilla for empty paths
|
||||
}
|
||||
|
||||
public static NamespacedKey fromString(String string) {
|
|
@ -0,0 +1,22 @@
|
|||
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 4bec4a6955d6c38c8bd8fb9a10d153209d693a01..b89544fdfceee67fb452c37294131efca007e2fe 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -2656,6 +2656,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
|
||||
+ if (entity.getBukkitEntity() instanceof org.bukkit.inventory.Merchant merchant && merchant.getTrader() != null) {
|
||||
+ merchant.getTrader().closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED);
|
||||
+ }
|
||||
+ // Paper end
|
||||
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
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
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 e733a5657032d29e5a0d64375c9e36639360a7e0..b64c98c173e25055f4ff9d7124d0a3cb7ff6ab1d 100644
|
||||
--- a/src/main/java/com/mojang/brigadier/CommandDispatcher.java
|
||||
+++ b/src/main/java/com/mojang/brigadier/CommandDispatcher.java
|
||||
@@ -595,10 +595,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
|
||||
futures[i++] = future;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
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 ee5f58ae4c276b4529d7dd35aa5cfa515e058d77..2b6e315d275cf5e303663c175745a5fe2e35969f 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -847,6 +847,11 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
}
|
||||
// Paper end
|
||||
// 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 - async tab completion
|
||||
TAB_COMPLETE_EXECUTOR.execute(() -> {
|
||||
StringReader stringreader = new StringReader(packet.getCommand());
|
|
@ -0,0 +1,71 @@
|
|||
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 581e0f4d68d6eb8eb04449586ffdba35e8b3ad2b..9a045a7793ec20334853a0e1c3529b31899214b3 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java
|
||||
@@ -107,7 +107,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..2e7f8ef88ae74c7cbfdb7f397951cbc8479a995f
|
||||
--- /dev/null
|
||||
+++ b/src/test/java/io/papermc/paper/inventory/CraftMetaTropicalFishBucketTest.java
|
||||
@@ -0,0 +1,40 @@
|
||||
+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.AbstractTestingBase;
|
||||
+import org.junit.Assert;
|
||||
+import org.junit.Test;
|
||||
+
|
||||
+public class CraftMetaTropicalFishBucketTest extends AbstractTestingBase {
|
||||
+
|
||||
+ @Test
|
||||
+ public void testAllCombinations() {
|
||||
+ final var rawMeta = new ItemStack(Material.TROPICAL_FISH_BUCKET).getItemMeta();
|
||||
+ Assert.assertTrue("Meta was not a tropical fish bucket", rawMeta instanceof TropicalFishBucketMeta);
|
||||
+
|
||||
+ 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);
|
||||
+ Assert.assertEquals("Body color did not match post body color!", bodyColor, meta.getBodyColor());
|
||||
+
|
||||
+ meta.setPattern(pattern);
|
||||
+ Assert.assertEquals("Pattern did not match post pattern!", pattern, meta.getPattern());
|
||||
+ Assert.assertEquals("Body color did not match post pattern!", bodyColor, meta.getBodyColor());
|
||||
+
|
||||
+ meta.setPatternColor(patternColor);
|
||||
+ Assert.assertEquals("Pattern did not match post pattern color!", pattern, meta.getPattern());
|
||||
+ Assert.assertEquals("Body color did not match post pattern color!", bodyColor, meta.getBodyColor());
|
||||
+ Assert.assertEquals("Pattern color did not match post pattern color!", patternColor, meta.getPatternColor());
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+}
|
19
patches/server/0708-Ensure-valid-vehicle-status.patch
Normal file
19
patches/server/0708-Ensure-valid-vehicle-status.patch
Normal file
|
@ -0,0 +1,19 @@
|
|||
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 c9b07d321a22060086a8608c6ff5f8f0608d988f..768f9ef872ed1bb3157c6fa122e1e3d76417a4b6 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -568,7 +568,7 @@ public class ServerPlayer extends Player {
|
||||
}
|
||||
}
|
||||
|
||||
- if (persistVehicle && entity1 != null && entity != this && entity.hasExactlyOnePlayerPassenger()) {
|
||||
+ if (persistVehicle && entity1 != null && entity != this && entity.hasExactlyOnePlayerPassenger() && !entity.isRemoved()) { // Paper
|
||||
// CraftBukkit end
|
||||
CompoundTag nbttagcompound2 = new CompoundTag();
|
||||
CompoundTag nbttagcompound3 = new CompoundTag();
|
|
@ -0,0 +1,22 @@
|
|||
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 eab54838ba540f41cc59a359dd00ba80d82c771e..17b5386d147dc007c487da3561ea5a5d3cd6db22 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
|
||||
@@ -412,6 +412,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
|
||||
endPodiumFeature.place(FeatureConfiguration.NONE, this.level, this.level.getChunkSource().getGenerator(), RandomSource.create(), this.portalLocation);
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
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 42b4b306ee89a9e422d234bdaa9b43b118f8bd0a..0fc355bd847749f7ce716b283dd571f143824795 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
|
||||
@@ -25,6 +25,7 @@ public class CocoaDecorator extends TreeDecorator {
|
||||
|
||||
@Override
|
||||
public void place(TreeDecorator.Context generator) {
|
||||
+ if (generator.logs().isEmpty()) return; // Paper
|
||||
RandomSource randomSource = generator.random();
|
||||
if (!(randomSource.nextFloat() >= this.probability)) {
|
||||
List<BlockPos> list = generator.logs();
|
|
@ -0,0 +1,19 @@
|
|||
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 3ac48dafe2300ff4cf4591569fec9ce4916503cd..612c3169c3463d702b85975e1db79ae6e47d60d0 100644
|
||||
--- a/src/main/java/org/spigotmc/SpigotConfig.java
|
||||
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
|
||||
@@ -382,7 +382,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.
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
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..f00a957a0f55e69f93e6d7dc80193304447c3dcb 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
|
||||
+ @Override
|
||||
+ public org.bukkit.Location getLocation() {
|
||||
+ return null;
|
||||
+ }
|
||||
+ // Paper end
|
||||
};
|
||||
|
||||
static ContainerLevelAccess create(final Level world, final BlockPos pos) {
|
27
patches/server/0713-Preserve-overstacked-loot.patch
Normal file
27
patches/server/0713-Preserve-overstacked-loot.patch
Normal file
|
@ -0,0 +1,27 @@
|
|||
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 d123bd7095355dff84b9859657e24258c5a204e3..e46a0afa45ee771a0114703acc314d7cf8e8ffed 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
|
||||
@@ -62,9 +62,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();
|
|
@ -0,0 +1,29 @@
|
|||
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 eb9f56de921edfefc0655be47449ffbc97145e07..d776c95e7c0752cdfcc44fb17509d5dc8605d8a8 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -1870,6 +1870,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
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) {
|
||||
@@ -1908,6 +1909,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
this.setXRot(pitch);
|
||||
this.setOldPosAndRot();
|
||||
this.reapplyPosition();
|
||||
+ this.setYHeadRot(yaw); // Paper - Update head rotation
|
||||
}
|
||||
|
||||
public final void setOldPosAndRot() {
|
|
@ -0,0 +1,18 @@
|
|||
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 6427302f53336fe035882d0a09e3e2d2d929d3b7..6eec44c484763f877aece6d9676ffc166bc10395 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/LightBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/LightBlock.java
|
||||
@@ -46,6 +46,7 @@ public class LightBlock extends Block implements SimpleWaterloggedBlock {
|
||||
@Override
|
||||
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||
if (!world.isClientSide && player.canUseGameMasterBlocks()) {
|
||||
+ if (player.getItemInHand(hand).getItem() != Items.LIGHT || !player.mayInteract(world, pos) || !player.mayUseItemAt(pos, hit.getDirection(), player.getItemInHand(hand))) { return InteractionResult.FAIL; } // Paper
|
||||
world.setBlock(pos, state.cycle(LEVEL), 2);
|
||||
return InteractionResult.SUCCESS;
|
||||
} else {
|
19
patches/server/0716-Fix-CraftCriteria-defaults-map.patch
Normal file
19
patches/server/0716-Fix-CraftCriteria-defaults-map.patch
Normal file
|
@ -0,0 +1,19 @@
|
|||
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 a8728102499ec8a0b4946bcc9b59c16193731f8c..d849ef9a51dc901c8045d63218b8ee5fa5c7ee7a 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) {
|
415
patches/server/0717-Fix-upstreams-block-state-factories.patch
Normal file
415
patches/server/0717-Fix-upstreams-block-state-factories.patch
Normal file
|
@ -0,0 +1,415 @@
|
|||
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 d156f7cc71050f13b2feca00c52ca6b64572b60e..e3557f4c8cee7c88b3e352cd246078da7762effc 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
|
||||
@@ -247,7 +247,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 87c25170fbe8b0591d452612496ee1a627138de7..a2894f02ceb7c58f6eafe055e1ff47b197b100f2 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||
@@ -6,7 +6,7 @@ import org.bukkit.World;
|
||||
import org.bukkit.block.TileState;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
|
||||
-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;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
|
||||
index 17e1131c79ad140c0803a914621ce7924f0f2a6d..d7663b902b768030008b28f9a8f6dd324a30e38f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
|
||||
@@ -19,6 +19,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;
|
||||
@@ -113,225 +114,61 @@ 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", CraftMagicNumbers.getMaterial(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, EnchantmentTableBlockEntity::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);
|
||||
+ // 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.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); // TODO: HANDLE DIFFERENT MATERIALS....
|
||||
+ register(BlockEntityType.TRAPPED_CHEST, CraftChest.class, CraftChest::new);
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
private static void register(Material blockType, BlockStateFactory<?> factory) {
|
||||
@@ -339,30 +176,33 @@ public final class CraftBlockStates {
|
||||
}
|
||||
|
||||
private static <T extends BlockEntity, B extends CraftBlockEntityState<T>> void register(
|
||||
- Material blockType,
|
||||
- Class<B> blockStateType,
|
||||
- BiFunction<World, T, B> blockStateConstructor,
|
||||
- BiFunction<BlockPos, net.minecraft.world.level.block.state.BlockState, T> tileEntityConstructor
|
||||
- ) {
|
||||
- CraftBlockStates.register(Collections.singletonList(blockType), blockStateType, blockStateConstructor, tileEntityConstructor);
|
||||
- }
|
||||
-
|
||||
- private static <T extends BlockEntity, B extends CraftBlockEntityState<T>> void register(
|
||||
- List<Material> blockTypes,
|
||||
+ 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
|
||||
) {
|
||||
- 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::create);
|
||||
+ for (net.minecraft.world.level.block.Block block : blockEntityType.validBlocks) {
|
||||
+ CraftBlockStates.register(CraftMagicNumbers.getMaterial(block), factory);
|
||||
}
|
||||
+ CraftBlockStates.register(blockEntityType, factory);
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
private static BlockStateFactory<?> getFactory(Material material) {
|
||||
return CraftBlockStates.FACTORIES.getOrDefault(material, 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;
|
||||
@@ -378,6 +218,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);
|
||||
@@ -435,7 +282,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);
|
||||
}
|
||||
diff --git a/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java b/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java
|
||||
index a6dbd1919bce5b5092666372f4cc31d2e2190c42..04710abbfb50eaa6e3e4d96fca5f0355f940a452 100644
|
||||
--- a/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java
|
||||
+++ b/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java
|
||||
@@ -45,4 +45,11 @@ public class BlockStateTest extends AbstractTestingBase {
|
||||
}
|
||||
}
|
||||
}
|
||||
+
|
||||
+ @Test
|
||||
+ public void testBlockEntityTypes() {
|
||||
+ for (var blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) {
|
||||
+ org.junit.Assert.assertNotNull(CraftBlockStates.getBlockStateType(blockEntityType));
|
||||
+ }
|
||||
+ }
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Noah van der Aa <ndvdaa@gmail.com>
|
||||
Date: Tue, 5 Oct 2021 20:04:21 +0200
|
||||
Subject: [PATCH] Add config option for logging player ip addresses
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
|
||||
index 21393ad40095a4049e5b6871169b2db7aa92d13c..e6553b936dac1eb25a310d1a33acb0b1a5e646d2 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
|
||||
@@ -185,7 +185,7 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter {
|
||||
buf.release();
|
||||
this.buf = null;
|
||||
|
||||
- LOGGER.debug("Ping: (1.6) from {}", ctx.channel().remoteAddress());
|
||||
+ LOGGER.debug("Ping: (1.6) from {}", io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? ctx.channel().remoteAddress() : "<ip address withheld>"); // Paper
|
||||
|
||||
InetSocketAddress virtualHost = com.destroystokyo.paper.network.PaperNetworkClient.prepareVirtualHost(host, port);
|
||||
com.destroystokyo.paper.event.server.PaperServerListPingEvent event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest(
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
index 14f037e721ac8ba885536cab43d3d398b011a397..17f42a4097d9c91bae2ccb02365498a0f7c7f8f8 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
@@ -204,7 +204,7 @@ public class ServerConnectionListener {
|
||||
throw new ReportedException(CrashReport.forThrowable(exception, "Ticking memory connection"));
|
||||
}
|
||||
|
||||
- ServerConnectionListener.LOGGER.warn("Failed to handle packet for {}", networkmanager.getRemoteAddress(), exception);
|
||||
+ ServerConnectionListener.LOGGER.warn("Failed to handle packet for {}", io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? String.valueOf(networkmanager.getRemoteAddress()) : "<ip address withheld>", exception); // Paper
|
||||
MutableComponent ichatmutablecomponent = Component.literal("Internal server error");
|
||||
|
||||
networkmanager.send(new ClientboundDisconnectPacket(ichatmutablecomponent), PacketSendListener.thenRun(() -> {
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index 595779cfd0ee1c405d7936f00a7cae1706125e7f..ed3af916dfa875dd0a5f1e730d20d11efd6419c6 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -206,7 +206,10 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
- return this.gameProfile != null ? this.gameProfile + " (" + this.connection.getRemoteAddress() + ")" : String.valueOf(this.connection.getRemoteAddress());
|
||||
+ // Paper start
|
||||
+ String ip = io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? String.valueOf(this.connection.getRemoteAddress()) : "<ip address withheld>";
|
||||
+ return this.gameProfile != null ? this.gameProfile + " (" + ip + ")" : String.valueOf(ip);
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 348265d5686072d625d694a5a3cdbe3060c950f7..5f957a28e9d30144f724ebdc581d5f0b80bf6dc1 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -255,7 +255,7 @@ public abstract class PlayerList {
|
||||
String s1 = "local";
|
||||
|
||||
if (connection.getRemoteAddress() != null) {
|
||||
- s1 = connection.getRemoteAddress().toString();
|
||||
+ s1 = io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? connection.getRemoteAddress().toString() : "<ip address withheld>"; // Paper
|
||||
}
|
||||
|
||||
// Spigot start - spawn location event
|
40
patches/server/0719-Configurable-feature-seeds.patch
Normal file
40
patches/server/0719-Configurable-feature-seeds.patch
Normal file
|
@ -0,0 +1,40 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nassim Jahnke <nassim@njahnke.dev>
|
||||
Date: Tue, 31 Aug 2021 17:05:27 +0200
|
||||
Subject: [PATCH] Configurable feature seeds
|
||||
|
||||
Co-authored-by: Thonk <30448663+ExcessiveAmountsOfZombies@users.noreply.github.com>
|
||||
|
||||
diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java
|
||||
index 1080e1f67afe5574baca0df50cdb1d029a7a586a..a2f71a6d1a9e98133dff6cd0f625da9435a8af14 100644
|
||||
--- a/src/main/java/co/aikar/timings/TimingsExport.java
|
||||
+++ b/src/main/java/co/aikar/timings/TimingsExport.java
|
||||
@@ -288,7 +288,7 @@ public class TimingsExport extends Thread {
|
||||
JSONObject object = new JSONObject();
|
||||
for (String key : config.getKeys(false)) {
|
||||
String fullKey = (parentKey != null ? parentKey + "." + key : key);
|
||||
- if (fullKey.equals("database") || fullKey.equals("settings.bungeecord-addresses") || TimingsManager.hiddenConfigs.contains(fullKey) || key.startsWith("seed-") || key.equals("worldeditregentempworld")) {
|
||||
+ if (fullKey.equals("database") || fullKey.equals("settings.bungeecord-addresses") || TimingsManager.hiddenConfigs.contains(fullKey) || key.startsWith("seed-") || key.equals("worldeditregentempworld") || key.equals("feature-seeds")) {
|
||||
continue;
|
||||
}
|
||||
final Object val = config.get(key);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
|
||||
index 354d386940b5ee7c92708390b83db51c281660f4..31955f62253feb111239247c4f8c2215b3080c1d 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
|
||||
@@ -431,7 +431,14 @@ public abstract class ChunkGenerator {
|
||||
return (String) optional.orElseGet(placedfeature::toString);
|
||||
};
|
||||
|
||||
- seededrandom.setFeatureSeed(i, l1, l);
|
||||
+ // Paper start - change populationSeed used in random
|
||||
+ long featurePopulationSeed = i;
|
||||
+ final long configFeatureSeed = generatoraccessseed.getMinecraftWorld().paperConfig().featureSeeds.features.getLong(placedfeature.feature());
|
||||
+ if (configFeatureSeed != -1) {
|
||||
+ featurePopulationSeed = seededrandom.setDecorationSeed(configFeatureSeed, blockposition.getX(), blockposition.getZ()); // See seededrandom.setDecorationSeed from above
|
||||
+ }
|
||||
+ seededrandom.setFeatureSeed(featurePopulationSeed, l1, l);
|
||||
+ // Paper end
|
||||
|
||||
try {
|
||||
generatoraccessseed.setCurrentlyGenerating(supplier1);
|
|
@ -0,0 +1,23 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Fri, 10 Sep 2021 15:49:12 -0700
|
||||
Subject: [PATCH] VanillaCommandWrapper didnt account for entity senders
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
|
||||
index 8dca2ad7d25f740941187698d77819af8ebc2805..6df44aa60d2b41b95fe79ed4cf92a6d3369400ea 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
|
||||
@@ -64,8 +64,10 @@ public final class VanillaCommandWrapper extends BukkitCommand {
|
||||
}
|
||||
|
||||
public static CommandSourceStack getListener(CommandSender sender) {
|
||||
- if (sender instanceof Player) {
|
||||
- return ((CraftPlayer) sender).getHandle().createCommandSourceStack();
|
||||
+ // Paper start - account for other entity command senders
|
||||
+ if (sender instanceof org.bukkit.craftbukkit.entity.CraftEntity craftEntity) {
|
||||
+ return craftEntity.getHandle().createCommandSourceStack();
|
||||
+ // Paper end
|
||||
}
|
||||
if (sender instanceof BlockCommandSender) {
|
||||
return ((CraftBlockCommandSender) sender).getWrapper();
|
79
patches/server/0721-Add-root-admin-user-detection.patch
Normal file
79
patches/server/0721-Add-root-admin-user-detection.patch
Normal file
|
@ -0,0 +1,79 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: egg82 <eggys82@gmail.com>
|
||||
Date: Sat, 11 Sep 2021 22:55:14 +0200
|
||||
Subject: [PATCH] Add root/admin user detection
|
||||
|
||||
This patch detects whether or not the server is currently executing as a privileged user and spits out a warning.
|
||||
The warning serves as a sort-of PSA for newer server admins who don't understand the risks of running as root.
|
||||
We've seen plenty of bad/malicious plugins hit markets, and there's been a few close-calls with exploits in the past.
|
||||
Hopefully this helps mitigate some potential damage to servers, even if it is just a warning.
|
||||
|
||||
Co-authored-by: Noah van der Aa <ndvdaa@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/util/ServerEnvironment.java b/src/main/java/io/papermc/paper/util/ServerEnvironment.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..6bd0afddbcc461149dfe9a5c7a86fff6ea13a5f1
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/ServerEnvironment.java
|
||||
@@ -0,0 +1,40 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import com.sun.security.auth.module.NTSystem;
|
||||
+import com.sun.security.auth.module.UnixSystem;
|
||||
+import org.apache.commons.lang.SystemUtils;
|
||||
+
|
||||
+import java.io.IOException;
|
||||
+import java.io.InputStream;
|
||||
+import java.util.Set;
|
||||
+
|
||||
+public class ServerEnvironment {
|
||||
+ private static final boolean RUNNING_AS_ROOT_OR_ADMIN;
|
||||
+ private static final String WINDOWS_HIGH_INTEGRITY_LEVEL = "S-1-16-12288";
|
||||
+
|
||||
+ static {
|
||||
+ if (SystemUtils.IS_OS_WINDOWS) {
|
||||
+ RUNNING_AS_ROOT_OR_ADMIN = Set.of(new NTSystem().getGroupIDs()).contains(WINDOWS_HIGH_INTEGRITY_LEVEL);
|
||||
+ } else {
|
||||
+ boolean isRunningAsRoot = false;
|
||||
+ if (new UnixSystem().getUid() == 0) {
|
||||
+ // Due to an OpenJDK bug (https://bugs.openjdk.java.net/browse/JDK-8274721), UnixSystem#getUid incorrectly
|
||||
+ // returns 0 when the user doesn't have a username. Because of this, we'll have to double-check if the user ID is
|
||||
+ // actually 0 by running the id -u command.
|
||||
+ try {
|
||||
+ Process process = new ProcessBuilder("id", "-u").start();
|
||||
+ process.waitFor();
|
||||
+ InputStream inputStream = process.getInputStream();
|
||||
+ isRunningAsRoot = new String(inputStream.readAllBytes()).trim().equals("0");
|
||||
+ } catch (InterruptedException | IOException ignored) {
|
||||
+ isRunningAsRoot = false;
|
||||
+ }
|
||||
+ }
|
||||
+ RUNNING_AS_ROOT_OR_ADMIN = isRunningAsRoot;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static boolean userIsRootOrAdmin() {
|
||||
+ return RUNNING_AS_ROOT_OR_ADMIN;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 4757d6432631f0c5379597b40fda169ac7cd8621..9951e999b1440ef623f14bdd46b5e42a90387f1e 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -179,6 +179,16 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
DedicatedServer.LOGGER.warn("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\"");
|
||||
}
|
||||
|
||||
+ // Paper start - detect running as root
|
||||
+ if (io.papermc.paper.util.ServerEnvironment.userIsRootOrAdmin()) {
|
||||
+ DedicatedServer.LOGGER.warn("****************************");
|
||||
+ DedicatedServer.LOGGER.warn("YOU ARE RUNNING THIS SERVER AS AN ADMINISTRATIVE OR ROOT USER. THIS IS NOT ADVISED.");
|
||||
+ DedicatedServer.LOGGER.warn("YOU ARE OPENING YOURSELF UP TO POTENTIAL RISKS WHEN DOING THIS.");
|
||||
+ DedicatedServer.LOGGER.warn("FOR MORE INFORMATION, SEE https://madelinemiller.dev/blog/root-minecraft-server/");
|
||||
+ DedicatedServer.LOGGER.warn("****************************");
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
DedicatedServer.LOGGER.info("Loading properties");
|
||||
DedicatedServerProperties dedicatedserverproperties = this.settings.getProperties();
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
|
||||
Date: Mon, 21 Jun 2021 22:12:53 -0400
|
||||
Subject: [PATCH] Always allow item changing in Fireball
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/projectile/Fireball.java b/src/main/java/net/minecraft/world/entity/projectile/Fireball.java
|
||||
index 307f545b79f01e22b1ffa9e41a0d353b3fa6a21d..58ea1fdc8dd5eb48d9642edecbbba1751e7037b6 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/projectile/Fireball.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/Fireball.java
|
||||
@@ -27,7 +27,7 @@ public abstract class Fireball extends AbstractHurtingProjectile implements Item
|
||||
}
|
||||
|
||||
public void setItem(ItemStack stack) {
|
||||
- if (!stack.is(Items.FIRE_CHARGE) || stack.hasTag()) {
|
||||
+ if (true || !stack.is(Items.FIRE_CHARGE) || stack.hasTag()) { // Paper - always allow item changing
|
||||
this.getEntityData().set(Fireball.DATA_ITEM_STACK, stack.copyWithCount(1));
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
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 d776c95e7c0752cdfcc44fb17509d5dc8605d8a8..6068d70f5eb566396d8c6bf6137e2c6cf21e33cf 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -754,7 +754,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
// CraftBukkit start
|
||||
public void postTick() {
|
||||
// No clean way to break out of ticking once the entity has been copied to a new world, so instead we move the portalling later in the tick cycle
|
||||
- if (!(this instanceof ServerPlayer)) {
|
||||
+ if (!(this instanceof ServerPlayer) && this.isAlive()) { // Paper - don't attempt to teleport dead entities
|
||||
this.handleNetherPortal();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
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 dffce1de1254f0194db2f28b797155846d3beeb0..8b01e2fb891339867256ae45a5178af0beadc8cb 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -2655,13 +2655,26 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
return this.hasEffect(MobEffects.JUMP) ? 0.1F * ((float) this.getEffect(MobEffects.JUMP).getAmplifier() + 1.0F) : 0.0F;
|
||||
}
|
||||
|
||||
+ protected long lastJumpTime = 0L; // Paper
|
||||
protected void jumpFromGround() {
|
||||
Vec3 vec3d = this.getDeltaMovement();
|
||||
+ // Paper start
|
||||
+ long time = System.nanoTime();
|
||||
+ boolean canCrit = true;
|
||||
+ if (this instanceof net.minecraft.world.entity.player.Player) {
|
||||
+ canCrit = false;
|
||||
+ if (time - this.lastJumpTime > (long)(0.250e9)) {
|
||||
+ this.lastJumpTime = time;
|
||||
+ canCrit = true;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
this.setDeltaMovement(vec3d.x, (double) this.getJumpPower(), vec3d.z);
|
||||
if (this.isSprinting()) {
|
||||
float f = this.getYRot() * 0.017453292F;
|
||||
|
||||
+ if (canCrit) // Paper
|
||||
this.setDeltaMovement(this.getDeltaMovement().add((double) (-Mth.sin(f) * 0.2F), 0.0D, (double) (Mth.cos(f) * 0.2F)));
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
|
||||
Date: Fri, 26 Nov 2021 15:09:58 -0800
|
||||
Subject: [PATCH] Remove client-side code using deprecated for removal
|
||||
AccessController
|
||||
|
||||
Fixes warnings on build
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
|
||||
index fcade0a121f155dbf4f5f8af66240923d8da460d..c60c73d9f998260f3abe6fe445255c6e7c38b0c3 100644
|
||||
--- a/src/main/java/net/minecraft/Util.java
|
||||
+++ b/src/main/java/net/minecraft/Util.java
|
||||
@@ -909,17 +909,7 @@ public class Util {
|
||||
}
|
||||
|
||||
public void openUrl(URL url) {
|
||||
- try {
|
||||
- Process process = AccessController.doPrivileged((PrivilegedExceptionAction<Process>)(() -> {
|
||||
- return Runtime.getRuntime().exec(this.getOpenUrlArguments(url));
|
||||
- }));
|
||||
- process.getInputStream().close();
|
||||
- process.getErrorStream().close();
|
||||
- process.getOutputStream().close();
|
||||
- } catch (IOException | PrivilegedActionException var3) {
|
||||
- Util.LOGGER.error("Couldn't open url '{}'", url, var3);
|
||||
- }
|
||||
-
|
||||
+ throw new IllegalStateException("This method is not useful on dedicated servers."); // Paper
|
||||
}
|
||||
|
||||
public void openUri(URI uri) {
|
|
@ -0,0 +1,51 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake <jake.m.potrebic@gmail.com>
|
||||
Date: Tue, 30 Nov 2021 12:01:56 -0800
|
||||
Subject: [PATCH] Fix removing recipes from RecipeIterator
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.item.crafting.RecipeManager byName
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java b/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java
|
||||
index 24f336c89b548c5ba2a95372db0d7c83b5c4ec47..91895c639c33a1cafd2a35bab7b5fd83e558468d 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java
|
||||
@@ -11,6 +11,7 @@ import org.bukkit.inventory.Recipe;
|
||||
public class RecipeIterator implements Iterator<Recipe> {
|
||||
private final Iterator<Map.Entry<RecipeType<?>, Object2ObjectLinkedOpenHashMap<ResourceLocation, net.minecraft.world.item.crafting.Recipe<?>>>> recipes;
|
||||
private Iterator<net.minecraft.world.item.crafting.Recipe<?>> current;
|
||||
+ private Recipe currentRecipe; // Paper - fix removing recipes
|
||||
|
||||
public RecipeIterator() {
|
||||
this.recipes = MinecraftServer.getServer().getRecipeManager().recipes.entrySet().iterator();
|
||||
@@ -34,10 +35,16 @@ public class RecipeIterator implements Iterator<Recipe> {
|
||||
public Recipe next() {
|
||||
if (this.current == null || !this.current.hasNext()) {
|
||||
this.current = this.recipes.next().getValue().values().iterator();
|
||||
- return this.next();
|
||||
+ // Paper start - fix removing recipes
|
||||
+ this.currentRecipe = this.next();
|
||||
+ return this.currentRecipe;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
- return this.current.next().toBukkitRecipe();
|
||||
+ // Paper start - fix removing recipes
|
||||
+ this.currentRecipe = this.current.next().toBukkitRecipe();
|
||||
+ return this.currentRecipe;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -46,6 +53,11 @@ public class RecipeIterator implements Iterator<Recipe> {
|
||||
throw new IllegalStateException("next() not yet called");
|
||||
}
|
||||
|
||||
+ // Paper start - fix removing recipes
|
||||
+ if (this.currentRecipe instanceof org.bukkit.Keyed keyed) {
|
||||
+ MinecraftServer.getServer().getRecipeManager().byName.remove(org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(keyed.getKey()));
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.current.remove();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nassim Jahnke <nassim@njahnke.dev>
|
||||
Date: Wed, 1 Dec 2021 12:36:25 +0100
|
||||
Subject: [PATCH] Prevent sending oversized item data in equipment and metadata
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/syncher/EntityDataSerializers.java b/src/main/java/net/minecraft/network/syncher/EntityDataSerializers.java
|
||||
index 97da8896865ff0bdd4fe8f2155b0830b42051bb1..17d0519ce3c097a38f9867fff3e1c25eb7febb59 100644
|
||||
--- a/src/main/java/net/minecraft/network/syncher/EntityDataSerializers.java
|
||||
+++ b/src/main/java/net/minecraft/network/syncher/EntityDataSerializers.java
|
||||
@@ -42,7 +42,7 @@ public class EntityDataSerializers {
|
||||
public static final EntityDataSerializer<ItemStack> ITEM_STACK = new EntityDataSerializer<ItemStack>() {
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf, ItemStack value) {
|
||||
- buf.writeItem(value);
|
||||
+ buf.writeItem(net.minecraft.world.entity.LivingEntity.sanitizeItemStack(value, false)); // Paper - prevent oversized data
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
index 09f6948a52721b27ccd7c761a7efd09bfd7a183c..71a8812365503d840f6702a21d504a37d67c7194 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -338,7 +338,10 @@ public class ServerEntity {
|
||||
ItemStack itemstack = ((LivingEntity) this.entity).getItemBySlot(enumitemslot);
|
||||
|
||||
if (!itemstack.isEmpty()) {
|
||||
- list.add(Pair.of(enumitemslot, itemstack.copy()));
|
||||
+ // Paper start - prevent oversized data
|
||||
+ final ItemStack sanitized = LivingEntity.sanitizeItemStack(itemstack.copy(), false);
|
||||
+ list.add(Pair.of(enumitemslot, sanitized));
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 8b01e2fb891339867256ae45a5178af0beadc8cb..8e7fb632e5ab2c2d7c890fcab2133ea431ed0380 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3164,7 +3164,10 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
equipmentChanges.forEach((enumitemslot, itemstack) -> {
|
||||
ItemStack itemstack1 = itemstack.copy();
|
||||
|
||||
- list.add(Pair.of(enumitemslot, itemstack1));
|
||||
+ // Paper start - prevent oversized data
|
||||
+ ItemStack toSend = sanitizeItemStack(itemstack1, true);
|
||||
+ list.add(Pair.of(enumitemslot, toSend));
|
||||
+ // Paper end
|
||||
switch (enumitemslot.getType()) {
|
||||
case HAND:
|
||||
this.setLastHandItem(enumitemslot, itemstack1);
|
||||
@@ -3177,6 +3180,34 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
((ServerLevel) this.level()).getChunkSource().broadcast(this, new ClientboundSetEquipmentPacket(this.getId(), list));
|
||||
}
|
||||
|
||||
+ // Paper start - prevent oversized data
|
||||
+ public static ItemStack sanitizeItemStack(final ItemStack itemStack, final boolean copyItemStack) {
|
||||
+ if (itemStack.isEmpty() || !itemStack.hasTag()) {
|
||||
+ return itemStack;
|
||||
+ }
|
||||
+
|
||||
+ final ItemStack copy = copyItemStack ? itemStack.copy() : itemStack;
|
||||
+ final CompoundTag tag = copy.getTag();
|
||||
+ if (copy.is(Items.BUNDLE) && tag.get("Items") instanceof ListTag oldItems && !oldItems.isEmpty()) {
|
||||
+ // Bundles change their texture based on their fullness.
|
||||
+ org.bukkit.inventory.meta.BundleMeta bundleMeta = (org.bukkit.inventory.meta.BundleMeta) copy.asBukkitMirror().getItemMeta();
|
||||
+ int sizeUsed = 0;
|
||||
+ for (org.bukkit.inventory.ItemStack item : bundleMeta.getItems()) {
|
||||
+ int scale = 64 / item.getMaxStackSize();
|
||||
+ sizeUsed += scale * item.getAmount();
|
||||
+ }
|
||||
+ // Now we add a single fake item that uses the same amount of slots as all other items.
|
||||
+ ListTag items = new ListTag();
|
||||
+ items.add(new ItemStack(Items.PAPER, sizeUsed).save(new CompoundTag()));
|
||||
+ tag.put("Items", items);
|
||||
+ }
|
||||
+ if (tag.get("BlockEntityTag") instanceof CompoundTag blockEntityTag) {
|
||||
+ blockEntityTag.remove("Items");
|
||||
+ }
|
||||
+ return copy;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
private ItemStack getLastArmorItem(EquipmentSlot slot) {
|
||||
return (ItemStack) this.lastArmorItemStacks.get(slot.getIndex());
|
||||
}
|
118
patches/server/0728-Hide-unnecessary-itemmeta-from-clients.patch
Normal file
118
patches/server/0728-Hide-unnecessary-itemmeta-from-clients.patch
Normal file
|
@ -0,0 +1,118 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Noah van der Aa <ndvdaa@gmail.com>
|
||||
Date: Tue, 3 Aug 2021 17:28:27 +0200
|
||||
Subject: [PATCH] Hide unnecessary itemmeta from clients
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
index 71a8812365503d840f6702a21d504a37d67c7194..63561c0044375465fa0023b2b563a6516d7fa76c 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -340,7 +340,7 @@ public class ServerEntity {
|
||||
if (!itemstack.isEmpty()) {
|
||||
// Paper start - prevent oversized data
|
||||
final ItemStack sanitized = LivingEntity.sanitizeItemStack(itemstack.copy(), false);
|
||||
- list.add(Pair.of(enumitemslot, sanitized));
|
||||
+ list.add(Pair.of(enumitemslot, ((LivingEntity) this.entity).stripMeta(sanitized, false))); // Paper - remove unnecessary item meta
|
||||
// Paper end
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 2b6e315d275cf5e303663c175745a5fe2e35969f..13e73042653909f194cfc909a96370656cbcf1ca 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -2705,8 +2705,8 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
// Refresh the current entity metadata
|
||||
entity.getEntityData().refresh(player);
|
||||
// SPIGOT-7136 - Allays
|
||||
- if (entity instanceof Allay) {
|
||||
- ServerGamePacketListenerImpl.this.send(new ClientboundSetEquipmentPacket(entity.getId(), Arrays.stream(net.minecraft.world.entity.EquipmentSlot.values()).map((slot) -> Pair.of(slot, ((LivingEntity) entity).getItemBySlot(slot).copy())).collect(Collectors.toList())));
|
||||
+ if (entity instanceof Allay allay) { // Paper
|
||||
+ ServerGamePacketListenerImpl.this.send(new ClientboundSetEquipmentPacket(entity.getId(), Arrays.stream(net.minecraft.world.entity.EquipmentSlot.values()).map((slot) -> Pair.of(slot, allay.stripMeta(allay.getItemBySlot(slot), true))).collect(Collectors.toList()))); // Paper - remove unnecessary item meta
|
||||
player.containerMenu.sendAllDataToRemote();
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 8e7fb632e5ab2c2d7c890fcab2133ea431ed0380..29a8b2bddf4257e74db27bf990c8aa1fd99c341b 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3166,7 +3166,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
|
||||
// Paper start - prevent oversized data
|
||||
ItemStack toSend = sanitizeItemStack(itemstack1, true);
|
||||
- list.add(Pair.of(enumitemslot, toSend));
|
||||
+ list.add(Pair.of(enumitemslot, stripMeta(toSend, toSend == itemstack1))); // Paper - hide unnecessary item meta
|
||||
// Paper end
|
||||
switch (enumitemslot.getType()) {
|
||||
case HAND:
|
||||
@@ -3180,6 +3180,70 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
((ServerLevel) this.level()).getChunkSource().broadcast(this, new ClientboundSetEquipmentPacket(this.getId(), list));
|
||||
}
|
||||
|
||||
+ // Paper start - hide unnecessary item meta
|
||||
+ public ItemStack stripMeta(final ItemStack itemStack, final boolean copyItemStack) {
|
||||
+ if (itemStack.isEmpty() || (!itemStack.hasTag() && itemStack.getCount() < 2)) {
|
||||
+ return itemStack;
|
||||
+ }
|
||||
+
|
||||
+ final ItemStack copy = copyItemStack ? itemStack.copy() : itemStack;
|
||||
+ if (level.paperConfig().anticheat.obfuscation.items.hideDurability) {
|
||||
+ // Only show damage values for elytra's, since they show a different texture when broken.
|
||||
+ if (!copy.is(Items.ELYTRA) || copy.getDamageValue() < copy.getMaxDamage() - 1) {
|
||||
+ copy.setDamageValue(0);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ final CompoundTag tag = copy.getTag();
|
||||
+ if (level.paperConfig().anticheat.obfuscation.items.hideItemmeta) {
|
||||
+ // Some resource packs show different textures when there is more than one item. Since this shouldn't provide a big advantage,
|
||||
+ // we'll tell the client if there's one or (more than) two items.
|
||||
+ copy.setCount(copy.getCount() > 1 ? 2 : 1);
|
||||
+ // We can't just strip out display, leather helmets still use the display.color tag.
|
||||
+ if (tag != null) {
|
||||
+ if (tag.get("display") instanceof CompoundTag displayTag) {
|
||||
+ displayTag.remove("Lore");
|
||||
+ displayTag.remove("Name");
|
||||
+ }
|
||||
+
|
||||
+ if (tag.get("Enchantments") instanceof ListTag enchantmentsTag && !enchantmentsTag.isEmpty()) {
|
||||
+ // The client still renders items with the enchantment glow if the enchantments tag contains at least one (empty) child.
|
||||
+ ListTag enchantments = new ListTag();
|
||||
+ CompoundTag fakeEnchantment = new CompoundTag();
|
||||
+ // Soul speed boots generate client side particles.
|
||||
+ if (EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SOUL_SPEED, itemStack) > 0) {
|
||||
+ fakeEnchantment.putString("id", org.bukkit.enchantments.Enchantment.SOUL_SPEED.getKey().asString());
|
||||
+ fakeEnchantment.putInt("lvl", 1);
|
||||
+ }
|
||||
+ enchantments.add(fakeEnchantment);
|
||||
+ tag.put("Enchantments", enchantments);
|
||||
+ }
|
||||
+ tag.remove("AttributeModifiers");
|
||||
+
|
||||
+ // Books
|
||||
+ tag.remove("author");
|
||||
+ tag.remove("filtered_title");
|
||||
+ tag.remove("pages");
|
||||
+ tag.remove("filtered_pages");
|
||||
+ tag.remove("title");
|
||||
+ tag.remove("generation");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (level.paperConfig().anticheat.obfuscation.items.hideItemmetaWithVisualEffects && tag != null) {
|
||||
+ // Lodestone compasses
|
||||
+ tag.remove("LodestonePos");
|
||||
+ if (tag.contains("LodestoneDimension")) {
|
||||
+ // The client shows the glint if either the position or the dimension is present, so we just wipe
|
||||
+ // the position and fake the dimension
|
||||
+ tag.putString("LodestoneDimension", "paper:paper");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return copy;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
// Paper start - prevent oversized data
|
||||
public static ItemStack sanitizeItemStack(final ItemStack itemStack, final boolean copyItemStack) {
|
||||
if (itemStack.isEmpty() || !itemStack.hasTag()) {
|
125
patches/server/0729-Fix-Spigot-growth-modifiers.patch
Normal file
125
patches/server/0729-Fix-Spigot-growth-modifiers.patch
Normal file
|
@ -0,0 +1,125 @@
|
|||
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
|
||||
and torchflower crops
|
||||
Also fix above-mentioned modifiers from having the reverse effect
|
||||
|
||||
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Co-authored-by: Noah van der Aa <ndvdaa@gmail.com>
|
||||
Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java
|
||||
index 55f2fa02a36f0500b47f9ce377926719557106e5..18b5bce1138d50be32e5da013221be69dc47e21f 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java
|
||||
@@ -47,9 +47,17 @@ public class CaveVinesBlock extends GrowingPlantHeadBlock implements Bonemealabl
|
||||
|
||||
@Override
|
||||
protected BlockState getGrowIntoState(BlockState state, RandomSource random) {
|
||||
- return super.getGrowIntoState(state, random).setValue(BERRIES, Boolean.valueOf(random.nextFloat() < 0.11F));
|
||||
+ // Paper start
|
||||
+ return this.getGrowIntoState(state, random, null);
|
||||
}
|
||||
|
||||
+ @Override
|
||||
+ protected BlockState getGrowIntoState(BlockState state, RandomSource random, @javax.annotation.Nullable Level level) {
|
||||
+ final boolean value = random.nextFloat() < (level != null ? (0.11F * (level.spigotConfig.glowBerryModifier / 100.0F)) : 0.11F);
|
||||
+ return (BlockState) super.getGrowIntoState(state, random).setValue(CaveVinesBlock.BERRIES, value);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public ItemStack getCloneItemStack(BlockGetter world, BlockPos pos, BlockState state) {
|
||||
return new ItemStack(Items.GLOW_BERRIES);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/CropBlock.java b/src/main/java/net/minecraft/world/level/block/CropBlock.java
|
||||
index 448c958a7a40258132add92da74fa689cf2ac046..c463adf131c4ca6e38f18d4efd94f4629bcfafe9 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/CropBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/CropBlock.java
|
||||
@@ -84,6 +84,10 @@ public class CropBlock extends BushBlock implements BonemealableBlock {
|
||||
modifier = world.spigotConfig.carrotModifier;
|
||||
} else if (this == Blocks.POTATOES) {
|
||||
modifier = world.spigotConfig.potatoModifier;
|
||||
+ // Paper start
|
||||
+ } else if (this == Blocks.TORCHFLOWER_CROP) {
|
||||
+ modifier = world.spigotConfig.torchFlowerModifier;
|
||||
+ // Paper end
|
||||
} else {
|
||||
modifier = world.spigotConfig.wheatModifier;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
|
||||
index 53b91cf8092b46dbf45afea9ccf439d565d1914a..3a1aa4e2405090ccebefb7f5944f36462929e221 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
|
||||
@@ -56,12 +56,18 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements
|
||||
BlockPos blockposition1 = pos.relative(this.growthDirection);
|
||||
|
||||
if (this.canGrowInto(world.getBlockState(blockposition1))) {
|
||||
- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, this.getGrowIntoState(state, world.random)); // CraftBukkit
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, this.getGrowIntoState(state, world.random, world)); // CraftBukkit // Paper
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ protected BlockState getGrowIntoState(BlockState state, RandomSource random, @javax.annotation.Nullable Level level) {
|
||||
+ return this.getGrowIntoState(state, random);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
protected BlockState getGrowIntoState(BlockState state, RandomSource random) {
|
||||
return (BlockState) state.cycle(GrowingPlantHeadBlock.AGE);
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java b/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java
|
||||
index 5d78348fc18b22ccb7ad109890f867e20efec047..44c78f0d56c3459c063c104e401a521e3df7d8e5 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/MangrovePropaguleBlock.java
|
||||
@@ -89,7 +89,7 @@ public class MangrovePropaguleBlock extends SaplingBlock implements SimpleWaterl
|
||||
@Override
|
||||
public void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
|
||||
if (!isHanging(state)) {
|
||||
- if (random.nextInt(7) == 0) {
|
||||
+ if (random.nextFloat() < (world.spigotConfig.saplingModifier / (100.0F * 7))) { // Paper
|
||||
this.advanceTree(world, pos, state, random);
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java
|
||||
index b7d6197cb5f46bb020fff049ae2dd8fc3ee8ff2f..8c45f28450bc1079ee5d184591f1ac03babced4e 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,7 @@ public class SpigotWorldConfig
|
||||
public int twistingVinesModifier;
|
||||
public int weepingVinesModifier;
|
||||
public int caveVinesModifier;
|
||||
+ public int glowBerryModifier; // Paper
|
||||
private int getAndValidateGrowth(String crop)
|
||||
{
|
||||
int modifier = this.getInt( "growth." + crop.toLowerCase(java.util.Locale.ENGLISH) + "-modifier", 100 );
|
||||
@@ -129,6 +131,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 +142,7 @@ public class SpigotWorldConfig
|
||||
this.twistingVinesModifier = this.getAndValidateGrowth( "TwistingVines" );
|
||||
this.weepingVinesModifier = this.getAndValidateGrowth( "WeepingVines" );
|
||||
this.caveVinesModifier = this.getAndValidateGrowth( "CaveVines" );
|
||||
+ this.glowBerryModifier = this.getAndValidateGrowth("GlowBerry"); // Paper
|
||||
}
|
||||
|
||||
public double itemMerge;
|
|
@ -0,0 +1,18 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Tue, 30 Nov 2021 05:30:35 +0000
|
||||
Subject: [PATCH] Prevent ContainerOpenersCounter openCount from going negative
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java b/src/main/java/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java
|
||||
index ba06184bad7e8ae55cb2d55f6196e8f990d2811d..3e4b3eecc788c564f81b7929bfab7d2fdb6e307d 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java
|
||||
@@ -64,6 +64,7 @@ public abstract class ContainerOpenersCounter {
|
||||
|
||||
public void decrementOpeners(Player player, Level world, BlockPos pos, BlockState state) {
|
||||
int oldPower = Math.max(0, Math.min(15, this.openCount)); // CraftBukkit - Get power before new viewer is added
|
||||
+ if (this.openCount == 0) return; // Paper
|
||||
int i = this.openCount--;
|
||||
|
||||
// CraftBukkit start - Call redstone event
|
60
patches/server/0731-Add-PlayerItemFrameChangeEvent.patch
Normal file
60
patches/server/0731-Add-PlayerItemFrameChangeEvent.patch
Normal file
|
@ -0,0 +1,60 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: SamB440 <sam@islandearth.net>
|
||||
Date: Mon, 15 Nov 2021 18:10:10 +0000
|
||||
Subject: [PATCH] Add PlayerItemFrameChangeEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
index dc999068891bfdfd4873ca939b4c4389d63f4415..a86472cce8e8fcde16d761842fe443a619f6e305 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
@@ -3,6 +3,7 @@ package net.minecraft.world.entity.decoration;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import java.util.OptionalInt;
|
||||
import javax.annotation.Nullable;
|
||||
+import io.papermc.paper.event.player.PlayerItemFrameChangeEvent; // Paper
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
@@ -190,6 +191,13 @@ public class ItemFrame extends HangingEntity {
|
||||
return true;
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Paper start - call PlayerItemFrameChangeEvent
|
||||
+ if (source.getEntity() instanceof Player player) {
|
||||
+ var event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), this.getItem().asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.REMOVE);
|
||||
+ if (!event.callEvent()) return true; // return true here because you aren't cancelling the damage, just the change
|
||||
+ this.setItem(ItemStack.fromBukkitCopy(event.getItemStack()), false);
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.dropItem(source.getEntity(), false);
|
||||
this.gameEvent(GameEvent.BLOCK_CHANGE, source.getEntity());
|
||||
this.playSound(this.getRemoveItemSound(), 1.0F, 1.0F);
|
||||
@@ -456,13 +464,26 @@ public class ItemFrame extends HangingEntity {
|
||||
}
|
||||
}
|
||||
|
||||
- this.setItem(itemstack);
|
||||
+ // Paper start - call PlayerItemFrameChangeEvent
|
||||
+ PlayerItemFrameChangeEvent event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), itemstack.asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.PLACE);
|
||||
+ if (!event.callEvent()) {
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
+ this.setItem(ItemStack.fromBukkitCopy(event.getItemStack()));
|
||||
+ // Paper end
|
||||
this.gameEvent(GameEvent.BLOCK_CHANGE, player);
|
||||
if (!player.getAbilities().instabuild) {
|
||||
itemstack.shrink(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
+ // Paper start - call PlayerItemFrameChangeEvent
|
||||
+ PlayerItemFrameChangeEvent event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), this.getItem().asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.ROTATE);
|
||||
+ if (!event.callEvent()) {
|
||||
+ return InteractionResult.FAIL;
|
||||
+ }
|
||||
+ setItem(ItemStack.fromBukkitCopy(event.getItemStack()), false, false);
|
||||
+ // Paper end
|
||||
this.playSound(this.getRotateItemSound(), 1.0F, 1.0F);
|
||||
this.setRotation(this.getRotation() + 1);
|
||||
this.gameEvent(GameEvent.BLOCK_CHANGE, player);
|
37
patches/server/0732-Add-player-health-update-API.patch
Normal file
37
patches/server/0732-Add-player-health-update-API.patch
Normal file
|
@ -0,0 +1,37 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: SamB440 <sam@islandearth.net>
|
||||
Date: Wed, 17 Nov 2021 12:31:42 +0000
|
||||
Subject: [PATCH] Add player health update API
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 7fedfc313be736255067d12d7524439d42575524..5f046c62a1764c13df3c11ecd4be0ecc9553e529 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -2366,9 +2366,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
this.getHandle().maxHealthCache = getMaxHealth();
|
||||
}
|
||||
|
||||
- public void sendHealthUpdate() {
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void sendHealthUpdate(final double health, final int foodLevel, final float saturationLevel) {
|
||||
// Paper start - cancellable death event
|
||||
- ClientboundSetHealthPacket packet = new ClientboundSetHealthPacket(this.getScaledHealth(), this.getHandle().getFoodData().getFoodLevel(), this.getHandle().getFoodData().getSaturationLevel());
|
||||
+ ClientboundSetHealthPacket packet = new ClientboundSetHealthPacket((float) health, foodLevel, saturationLevel);
|
||||
if (this.getHandle().queueHealthUpdatePacket) {
|
||||
this.getHandle().queuedHealthUpdatePacket = packet;
|
||||
} else {
|
||||
@@ -2377,6 +2379,12 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
// Paper end
|
||||
}
|
||||
|
||||
+ @Override
|
||||
+ public void sendHealthUpdate() {
|
||||
+ this.sendHealthUpdate(this.getScaledHealth(), this.getHandle().getFoodData().getFoodLevel(), this.getHandle().getFoodData().getSaturationLevel());
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public void injectScaledMaxHealth(Collection<AttributeInstance> collection, boolean force) {
|
||||
if (!this.scaledHealth && !force) {
|
||||
return;
|
57
patches/server/0733-Optimize-HashMapPalette.patch
Normal file
57
patches/server/0733-Optimize-HashMapPalette.patch
Normal file
|
@ -0,0 +1,57 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: stonar96 <minecraft.stonar96@gmail.com>
|
||||
Date: Sun, 17 Jan 2021 01:11:36 +0100
|
||||
Subject: [PATCH] Optimize HashMapPalette
|
||||
|
||||
HashMapPalette uses an instance of CrudeIncrementalIntIdentityHashBiMap
|
||||
internally. A Palette has a preset maximum size = 1 << bits.
|
||||
CrudeIncrementalIntIdentityHashBiMap has an initial size but is
|
||||
automatically resized. The CrudeIncrementalIntIdentityHashBiMap is created
|
||||
with the maximum size in the constructor of HashMapPalette, with the aim
|
||||
that it doesn't need to be resized anymore. However, there are two things
|
||||
that I think Mojang hasn't considered here:
|
||||
1) The CrudeIncrementalIntIdentityHashBiMap is resized, when its initial
|
||||
size is reached and not the next time, when a further object is added.
|
||||
2) HashMapPalette adds objects (unnecessarily) before checking if the
|
||||
initial size of CrudeIncrementalIntIdentityHashBiMap is reached.
|
||||
This means to actually avoid resize operations in
|
||||
CrudeIncrementalIntIdentityHashBiMap, one has to add 2 to the initial size
|
||||
or add 1 and check the size before adding objects. This commit implements
|
||||
the second approach. Note that this isn't only an optimization but also
|
||||
makes async reads of Palettes fail-safe. An async read while the
|
||||
CrudeIncrementalIntIdentityHashBiMap is resized is fatal and can even lead
|
||||
to corrupted data. This is also something that Anti-Xray is currently
|
||||
relying on.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java b/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java
|
||||
index a6d0008636f72ff6614eda4b1fa856798e6b46fd..50580313a1e224a9569e343ccf4aa0c00b906a30 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/HashMapPalette.java
|
||||
@@ -19,7 +19,7 @@ public class HashMapPalette<T> implements Palette<T> {
|
||||
}
|
||||
|
||||
public HashMapPalette(IdMap<T> idList, int indexBits, PaletteResize<T> listener) {
|
||||
- this(idList, indexBits, listener, CrudeIncrementalIntIdentityHashBiMap.create(1 << indexBits));
|
||||
+ this(idList, indexBits, listener, CrudeIncrementalIntIdentityHashBiMap.create((1 << indexBits) + 1)); // Paper - Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap
|
||||
}
|
||||
|
||||
private HashMapPalette(IdMap<T> idList, int indexBits, PaletteResize<T> listener, CrudeIncrementalIntIdentityHashBiMap<T> map) {
|
||||
@@ -37,10 +37,16 @@ public class HashMapPalette<T> implements Palette<T> {
|
||||
public int idFor(T object) {
|
||||
int i = this.values.getId(object);
|
||||
if (i == -1) {
|
||||
- i = this.values.add(object);
|
||||
- if (i >= 1 << this.bits) {
|
||||
+ // Paper start - Avoid unnecessary resize operation in CrudeIncrementalIntIdentityHashBiMap and optimize
|
||||
+ // We use size() instead of the result from add(K)
|
||||
+ // This avoids adding another object unnecessarily
|
||||
+ // Without this change, + 2 would be required in the constructor
|
||||
+ if (this.values.size() >= 1 << this.bits) {
|
||||
i = this.resizeHandler.onResize(this.bits + 1, object);
|
||||
+ } else {
|
||||
+ i = this.values.add(object);
|
||||
}
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
return i;
|
129
patches/server/0734-Allow-delegation-to-vanilla-chunk-gen.patch
Normal file
129
patches/server/0734-Allow-delegation-to-vanilla-chunk-gen.patch
Normal file
|
@ -0,0 +1,129 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MiniDigger <admin@benndorf.dev>
|
||||
Date: Wed, 29 Apr 2020 02:10:32 +0200
|
||||
Subject: [PATCH] Allow delegation to vanilla chunk gen
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index ecd6d91ca1ddee0d0d3b6d41fb96f432273deffc..9b2f05e6d1d8e52842abaa4c92b60f7558480c70 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2354,6 +2354,90 @@ public final class CraftServer implements Server {
|
||||
return new OldCraftChunkData(world.getMinHeight(), world.getMaxHeight(), handle.registryAccess().registryOrThrow(Registries.BIOME));
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ private static final List<net.minecraft.world.level.chunk.ChunkStatus> VANILLA_GEN_STATUSES = List.of(
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.EMPTY,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.STRUCTURE_STARTS,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.STRUCTURE_REFERENCES,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.BIOMES,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.NOISE,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.SURFACE,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.CARVERS,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.LIQUID_CARVERS,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.FEATURES,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.LIGHT
|
||||
+ );
|
||||
+
|
||||
+ @Override
|
||||
+ @Deprecated(forRemoval = true)
|
||||
+ public ChunkGenerator.ChunkData createVanillaChunkData(World world, int x, int z) {
|
||||
+ // do bunch of vanilla shit
|
||||
+ final net.minecraft.server.level.ServerLevel serverLevel = ((CraftWorld) world).getHandle();
|
||||
+ final net.minecraft.core.Registry<net.minecraft.world.level.biome.Biome> biomeRegistry = serverLevel.getServer().registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.BIOME);
|
||||
+ final net.minecraft.world.level.chunk.ProtoChunk protoChunk = new net.minecraft.world.level.chunk.ProtoChunk(
|
||||
+ new net.minecraft.world.level.ChunkPos(x, z),
|
||||
+ net.minecraft.world.level.chunk.UpgradeData.EMPTY,
|
||||
+ serverLevel,
|
||||
+ biomeRegistry,
|
||||
+ null
|
||||
+ );
|
||||
+
|
||||
+ final net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator;
|
||||
+ if (serverLevel.chunkSource.getGenerator() instanceof org.bukkit.craftbukkit.generator.CustomChunkGenerator bukkit) {
|
||||
+ chunkGenerator = bukkit.getDelegate();
|
||||
+ } else {
|
||||
+ chunkGenerator = serverLevel.chunkSource.getGenerator();
|
||||
+ }
|
||||
+
|
||||
+ final net.minecraft.world.level.ChunkPos chunkPos = new net.minecraft.world.level.ChunkPos(x, z);
|
||||
+ final net.minecraft.util.thread.ProcessorMailbox<Runnable> mailbox = net.minecraft.util.thread.ProcessorMailbox.create(
|
||||
+ net.minecraft.Util.backgroundExecutor(),
|
||||
+ "CraftServer#createVanillaChunkData(worldName='" + world.getName() + "', x='" + x + "', z='" + z + "')"
|
||||
+ );
|
||||
+ for (final net.minecraft.world.level.chunk.ChunkStatus chunkStatus : VANILLA_GEN_STATUSES) {
|
||||
+ final List<net.minecraft.world.level.chunk.ChunkAccess> chunks = Lists.newArrayList();
|
||||
+ final int statusRange = Math.max(1, chunkStatus.getRange());
|
||||
+
|
||||
+ for (int zz = chunkPos.z - statusRange; zz <= chunkPos.z + statusRange; ++zz) {
|
||||
+ for (int xx = chunkPos.x - statusRange; xx <= chunkPos.x + statusRange; ++xx) {
|
||||
+ if (xx == chunkPos.x && zz == chunkPos.z) {
|
||||
+ chunks.add(protoChunk);
|
||||
+ } else {
|
||||
+ final net.minecraft.core.Holder<net.minecraft.world.level.biome.Biome> biomeHolder = serverLevel.registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.BIOME).getHolderOrThrow(net.minecraft.world.level.biome.Biomes.PLAINS);
|
||||
+ final net.minecraft.world.level.chunk.ChunkAccess chunk = new net.minecraft.world.level.chunk.EmptyLevelChunk(serverLevel, new net.minecraft.world.level.ChunkPos(xx, zz), biomeHolder);
|
||||
+ chunks.add(chunk);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ chunkStatus.generate(
|
||||
+ mailbox::tell,
|
||||
+ serverLevel,
|
||||
+ chunkGenerator,
|
||||
+ serverLevel.getStructureManager(),
|
||||
+ serverLevel.chunkSource.getLightEngine(),
|
||||
+ chunk -> {
|
||||
+ throw new UnsupportedOperationException("Not creating full chunks here");
|
||||
+ },
|
||||
+ chunks,
|
||||
+ true
|
||||
+ ).thenAccept(either -> {
|
||||
+ if (chunkStatus == net.minecraft.world.level.chunk.ChunkStatus.NOISE) {
|
||||
+ either.left().ifPresent(chunk -> net.minecraft.world.level.levelgen.Heightmap.primeHeightmaps(chunk, net.minecraft.world.level.chunk.ChunkStatus.POST_FEATURES));
|
||||
+ }
|
||||
+ }).join();
|
||||
+ }
|
||||
+
|
||||
+ // get empty object
|
||||
+ OldCraftChunkData data = (OldCraftChunkData) this.createChunkData(world);
|
||||
+ // copy over generated sections
|
||||
+ data.getLights().addAll(protoChunk.getLights().toList());
|
||||
+ data.setRawChunkData(protoChunk.getSections());
|
||||
+ // hooray!
|
||||
+ return data;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public BossBar createBossBar(String title, BarColor color, BarStyle style, BarFlag... flags) {
|
||||
return new CraftBossBar(title, color, style, flags);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java b/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java
|
||||
index c23ce88cb9693291fec81a99e3a5bcb2615bb897..189a584b4b81bbc28d4c47b901b5aa6f85fb7932 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java
|
||||
@@ -23,7 +23,7 @@ import org.bukkit.material.MaterialData;
|
||||
public final class OldCraftChunkData implements ChunkGenerator.ChunkData {
|
||||
private final int minHeight;
|
||||
private final int maxHeight;
|
||||
- private final LevelChunkSection[] sections;
|
||||
+ private LevelChunkSection[] sections; // Paper
|
||||
private final Registry<net.minecraft.world.level.biome.Biome> biomes;
|
||||
private Set<BlockPos> tiles;
|
||||
private final Set<BlockPos> lights = new HashSet<>();
|
||||
@@ -189,7 +189,13 @@ public final class OldCraftChunkData implements ChunkGenerator.ChunkData {
|
||||
return this.tiles;
|
||||
}
|
||||
|
||||
- Set<BlockPos> getLights() {
|
||||
+ public Set<BlockPos> getLights() { // Paper
|
||||
return this.lights;
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ public void setRawChunkData(LevelChunkSection[] sections) {
|
||||
+ this.sections = sections;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,170 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 2 Jul 2020 12:02:43 -0700
|
||||
Subject: [PATCH] Optimise collision checking in player move packet handling
|
||||
|
||||
Move collision logic to just the hasNewCollision call instead of getCubes + hasNewCollision
|
||||
|
||||
CHECK ME
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 13e73042653909f194cfc909a96370656cbcf1ca..be79308ac6d30afe7b626f325a44b607969477fe 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -647,7 +647,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
return;
|
||||
}
|
||||
|
||||
- boolean flag = worldserver.noCollision(entity, entity.getBoundingBox().deflate(0.0625D));
|
||||
+ AABB oldBox = entity.getBoundingBox(); // Paper - copy from player movement packet
|
||||
|
||||
d6 = d3 - this.vehicleLastGoodX; // Paper - diff on change, used for checking large move vectors above
|
||||
d7 = d4 - this.vehicleLastGoodY - 1.0E-6D; // Paper - diff on change, used for checking large move vectors above
|
||||
@@ -663,6 +663,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
}
|
||||
|
||||
entity.move(MoverType.PLAYER, new Vec3(d6, d7, d8));
|
||||
+ boolean didCollide = toX != entity.getX() || toY != entity.getY() || toZ != entity.getZ(); // Paper - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be...
|
||||
double d11 = d7;
|
||||
|
||||
d6 = d3 - entity.getX();
|
||||
@@ -676,16 +677,24 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
boolean flag2 = false;
|
||||
|
||||
if (d10 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot
|
||||
- flag2 = true;
|
||||
+ flag2 = true; // Paper - diff on change, this should be moved wrongly
|
||||
ServerGamePacketListenerImpl.LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", new Object[]{entity.getName().getString(), this.player.getName().getString(), Math.sqrt(d10)});
|
||||
}
|
||||
Location curPos = this.getCraftPlayer().getLocation(); // Spigot
|
||||
|
||||
entity.absMoveTo(d3, d4, d5, f, f1);
|
||||
this.player.absMoveTo(d3, d4, d5, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
|
||||
- boolean flag3 = worldserver.noCollision(entity, entity.getBoundingBox().deflate(0.0625D));
|
||||
|
||||
- if (flag && (flag2 || !flag3)) {
|
||||
+ // Paper start - optimise out extra getCubes
|
||||
+ boolean teleportBack = flag2; // violating this is always a fail
|
||||
+ if (!teleportBack) {
|
||||
+ // note: only call after setLocation, or else getBoundingBox is wrong
|
||||
+ AABB newBox = entity.getBoundingBox();
|
||||
+ if (didCollide || !oldBox.equals(newBox)) {
|
||||
+ teleportBack = this.hasNewCollision(worldserver, entity, oldBox, newBox);
|
||||
+ } // else: no collision at all detected, why do we care?
|
||||
+ }
|
||||
+ if (teleportBack) { // Paper end - optimise out extra getCubes
|
||||
entity.absMoveTo(d0, d1, d2, f, f1);
|
||||
this.player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
|
||||
this.connection.send(new ClientboundMoveVehiclePacket(entity));
|
||||
@@ -771,7 +780,32 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
}
|
||||
|
||||
private boolean noBlocksAround(Entity entity) {
|
||||
- return entity.level().getBlockStates(entity.getBoundingBox().inflate(0.0625D).expandTowards(0.0D, -0.55D, 0.0D)).allMatch(BlockBehaviour.BlockStateBase::isAir);
|
||||
+ // Paper start - stop using streams, this is already a known fixed problem in Entity#move
|
||||
+ AABB box = entity.getBoundingBox().inflate(0.0625D).expandTowards(0.0D, -0.55D, 0.0D);
|
||||
+ int minX = Mth.floor(box.minX);
|
||||
+ int minY = Mth.floor(box.minY);
|
||||
+ int minZ = Mth.floor(box.minZ);
|
||||
+ int maxX = Mth.floor(box.maxX);
|
||||
+ int maxY = Mth.floor(box.maxY);
|
||||
+ int maxZ = Mth.floor(box.maxZ);
|
||||
+
|
||||
+ Level world = entity.level();
|
||||
+ BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
|
||||
+
|
||||
+ for (int y = minY; y <= maxY; ++y) {
|
||||
+ for (int z = minZ; z <= maxZ; ++z) {
|
||||
+ for (int x = minX; x <= maxX; ++x) {
|
||||
+ pos.set(x, y, z);
|
||||
+ BlockState type = world.getBlockStateIfLoaded(pos);
|
||||
+ if (type != null && !type.isAir()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+ // Paper end - stop using streams, this is already a known fixed problem in Entity#move
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1347,7 +1381,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
}
|
||||
|
||||
if (this.awaitingPositionFromClient != null) {
|
||||
- if (this.tickCount - this.awaitingTeleportTime > 20) {
|
||||
+ if (false && this.tickCount - this.awaitingTeleportTime > 20) { // Paper - this will greatly screw with clients with > 1000ms RTT
|
||||
this.awaitingTeleportTime = this.tickCount;
|
||||
this.teleport(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot());
|
||||
}
|
||||
@@ -1440,7 +1474,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
}
|
||||
}
|
||||
|
||||
- AABB axisalignedbb = this.player.getBoundingBox();
|
||||
+ AABB axisalignedbb = this.player.getBoundingBox(); // Paper - diff on change, should be old AABB
|
||||
|
||||
d6 = d0 - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
|
||||
d7 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
|
||||
@@ -1482,6 +1516,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
|
||||
this.player.move(MoverType.PLAYER, new Vec3(d6, d7, d8));
|
||||
this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
|
||||
+ boolean didCollide = toX != this.player.getX() || toY != this.player.getY() || toZ != this.player.getZ(); // Paper - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be...
|
||||
// Paper start - prevent position desync
|
||||
if (this.awaitingPositionFromClient != null) {
|
||||
return; // ... thanks Mojang for letting move calls teleport across dimensions.
|
||||
@@ -1500,11 +1535,22 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
boolean flag2 = false;
|
||||
|
||||
if (!this.player.isChangingDimension() && d10 > org.spigotmc.SpigotConfig.movedWronglyThreshold && !this.player.isSleeping() && !this.player.gameMode.isCreative() && this.player.gameMode.getGameModeForPlayer() != GameType.SPECTATOR) { // Spigot
|
||||
- flag2 = true;
|
||||
+ flag2 = true; // Paper - diff on change, this should be moved wrongly
|
||||
ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!", this.player.getName().getString());
|
||||
}
|
||||
|
||||
- if (!this.player.noPhysics && !this.player.isSleeping() && (flag2 && worldserver.noCollision(this.player, axisalignedbb) || this.isPlayerCollidingWithAnythingNew(worldserver, axisalignedbb, d0, d1, d2))) {
|
||||
+ // Paper start - optimise out extra getCubes
|
||||
+ // Original for reference:
|
||||
+ // boolean teleportBack = flag2 && worldserver.getCubes(this.player, axisalignedbb) || (didCollide && this.a((IWorldReader) worldserver, axisalignedbb));
|
||||
+ boolean teleportBack = flag2; // violating this is always a fail
|
||||
+ if (!this.player.noPhysics && !this.player.isSleeping() && !teleportBack) {
|
||||
+ AABB newBox = this.player.getBoundingBox();
|
||||
+ if (didCollide || !axisalignedbb.equals(newBox)) {
|
||||
+ // note: only call after setLocation, or else getBoundingBox is wrong
|
||||
+ teleportBack = this.hasNewCollision(worldserver, this.player, axisalignedbb, newBox);
|
||||
+ } // else: no collision at all detected, why do we care?
|
||||
+ }
|
||||
+ if (!this.player.noPhysics && !this.player.isSleeping() && teleportBack) { // Paper end - optimise out extra getCubes
|
||||
this.internalTeleport(d3, d4, d5, f, f1, Collections.emptySet()); // CraftBukkit - SPIGOT-1807: Don't call teleport event, when the client thinks the player is falling, because the chunks are not loaded on the client yet.
|
||||
this.player.doCheckFallDamage(this.player.getX() - d3, this.player.getY() - d4, this.player.getZ() - d5, packet.isOnGround());
|
||||
} else {
|
||||
@@ -1587,6 +1633,26 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - optimise out extra getCubes
|
||||
+ private boolean hasNewCollision(final ServerLevel world, final Entity entity, final AABB oldBox, final AABB newBox) {
|
||||
+ final List<AABB> collisions = io.papermc.paper.util.CachedLists.getTempCollisionList();
|
||||
+ try {
|
||||
+ io.papermc.paper.util.CollisionUtil.getCollisions(world, entity, newBox, collisions, false, true,
|
||||
+ true, false, null, null);
|
||||
+
|
||||
+ for (int i = 0, len = collisions.size(); i < len; ++i) {
|
||||
+ final AABB box = collisions.get(i);
|
||||
+ if (!io.papermc.paper.util.CollisionUtil.voxelShapeIntersect(box, oldBox)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+ } finally {
|
||||
+ io.papermc.paper.util.CachedLists.returnTempCollisionList(collisions);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - optimise out extra getCubes
|
||||
private boolean isPlayerCollidingWithAnythingNew(LevelReader world, AABB box, double newX, double newY, double newZ) {
|
||||
AABB axisalignedbb1 = this.player.getBoundingBox().move(newX - this.player.getX(), newY - this.player.getY(), newZ - this.player.getZ());
|
||||
Iterable<VoxelShape> iterable = world.getCollisions(this.player, axisalignedbb1.deflate(9.999999747378752E-6D));
|
|
@ -0,0 +1,43 @@
|
|||
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 b738e1f7debac7d70910d5ac908ca9d4f60640d5..007fd353bd55056ecddba2e16c5fa8c479961402 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
@@ -289,13 +289,17 @@ public class CraftChunk implements Chunk {
|
||||
PalettedContainerRO<Holder<net.minecraft.world.level.biome.Biome>>[] biome = (includeBiome || includeBiomeTempRain) ? new PalettedContainer[cs.length] : null;
|
||||
|
||||
Registry<net.minecraft.world.level.biome.Biome> iregistry = this.worldServer.registryAccess().registryOrThrow(Registries.BIOME);
|
||||
- Codec<PalettedContainerRO<Holder<net.minecraft.world.level.biome.Biome>>> biomeCodec = PalettedContainer.codecRO(iregistry.asHolderIdMap(), iregistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, iregistry.getHolderOrThrow(Biomes.PLAINS));
|
||||
|
||||
for (int i = 0; i < cs.length; i++) {
|
||||
- CompoundTag data = new CompoundTag();
|
||||
|
||||
- data.put("block_states", ChunkSerializer.BLOCK_STATE_CODEC.encodeStart(NbtOps.INSTANCE, cs[i].getStates()).get().left().get());
|
||||
- sectionBlockIDs[i] = ChunkSerializer.BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, data.getCompound("block_states")).get().left().get();
|
||||
+ // Paper start
|
||||
+ sectionEmpty[i] = cs[i].hasOnlyAir(); // Paper - fix sectionEmpty array not being filled
|
||||
+ if (!sectionEmpty[i]) {
|
||||
+ sectionBlockIDs[i] = cs[i].getStates().copy(); // Paper - use copy instead of round tripping with codecs
|
||||
+ } else {
|
||||
+ sectionBlockIDs[i] = CraftChunk.emptyBlockIDs; // Paper - use cached instance for empty block sections
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
LevelLightEngine lightengine = this.worldServer.getLightEngine();
|
||||
DataLayer skyLightArray = lightengine.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(x, i, z));
|
||||
@@ -314,8 +318,7 @@ public class CraftChunk implements Chunk {
|
||||
}
|
||||
|
||||
if (biome != null) {
|
||||
- data.put("biomes", biomeCodec.encodeStart(NbtOps.INSTANCE, cs[i].getBiomes()).get().left().get());
|
||||
- biome[i] = biomeCodec.parse(NbtOps.INSTANCE, data.getCompound("biomes")).get().left().get();
|
||||
+ biome[i] = ((PalettedContainer<Holder<net.minecraft.world.level.biome.Biome>>) cs[i].getBiomes()).copy(); // Paper - use copy instead of round tripping with codecs
|
||||
}
|
||||
}
|
||||
|
112
patches/server/0738-Add-more-Campfire-API.patch
Normal file
112
patches/server/0738-Add-more-Campfire-API.patch
Normal file
|
@ -0,0 +1,112 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: LemonCaramel <admin@caramel.moe>
|
||||
Date: Fri, 16 Jul 2021 00:39:03 +0900
|
||||
Subject: [PATCH] Add more Campfire API
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
|
||||
index 0cd019dc20ff5b3e7ee663866f98595081e991a3..91feee1e284c929b008bc2df7ab548df898b3ef7 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
|
||||
@@ -41,6 +41,7 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
|
||||
public final int[] cookingProgress;
|
||||
public final int[] cookingTime;
|
||||
private final RecipeManager.CachedCheck<Container, CampfireCookingRecipe> quickCheck;
|
||||
+ public final boolean[] stopCooking; // Paper
|
||||
|
||||
public CampfireBlockEntity(BlockPos pos, BlockState state) {
|
||||
super(BlockEntityType.CAMPFIRE, pos, state);
|
||||
@@ -48,6 +49,7 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
|
||||
this.cookingProgress = new int[4];
|
||||
this.cookingTime = new int[4];
|
||||
this.quickCheck = RecipeManager.createCheck(RecipeType.CAMPFIRE_COOKING);
|
||||
+ this.stopCooking = new boolean[4]; // Paper
|
||||
}
|
||||
|
||||
public static void cookTick(Level world, BlockPos pos, BlockState state, CampfireBlockEntity campfire) {
|
||||
@@ -58,7 +60,9 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
|
||||
|
||||
if (!itemstack.isEmpty()) {
|
||||
flag = true;
|
||||
+ if (!campfire.stopCooking[i]) { // Paper
|
||||
int j = campfire.cookingProgress[i]++;
|
||||
+ } // Paper
|
||||
|
||||
if (campfire.cookingProgress[i] >= campfire.cookingTime[i]) {
|
||||
SimpleContainer inventorysubcontainer = new SimpleContainer(new ItemStack[]{itemstack});
|
||||
@@ -167,6 +171,16 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
|
||||
System.arraycopy(aint, 0, this.cookingTime, 0, Math.min(this.cookingTime.length, aint.length));
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ if (nbt.contains("Paper.StopCooking", org.bukkit.craftbukkit.util.CraftMagicNumbers.NBT.TAG_BYTE_ARRAY)) {
|
||||
+ byte[] abyte = nbt.getByteArray("Paper.StopCooking");
|
||||
+ boolean[] cookingState = new boolean[4];
|
||||
+ for (int index = 0; index < abyte.length; index++) {
|
||||
+ cookingState[index] = abyte[index] == 1;
|
||||
+ }
|
||||
+ System.arraycopy(cookingState, 0, this.stopCooking, 0, Math.min(this.stopCooking.length, abyte.length));
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -175,6 +189,13 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
|
||||
ContainerHelper.saveAllItems(nbt, this.items, true);
|
||||
nbt.putIntArray("CookingTimes", this.cookingProgress);
|
||||
nbt.putIntArray("CookingTotalTimes", this.cookingTime);
|
||||
+ // Paper start
|
||||
+ byte[] cookingState = new byte[4];
|
||||
+ for (int index = 0; index < cookingState.length; index++) {
|
||||
+ cookingState[index] = (byte) (this.stopCooking[index] ? 1 : 0);
|
||||
+ }
|
||||
+ nbt.putByteArray("Paper.StopCooking", cookingState);
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java b/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java
|
||||
index 391ff41951f51a5f9225bf4a9e28c0a4d064d8c9..eafba0532920a3162575dbe656e07734605590f5 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java
|
||||
@@ -47,4 +47,40 @@ public class CraftCampfire extends CraftBlockEntityState<CampfireBlockEntity> im
|
||||
public void setCookTimeTotal(int index, int cookTimeTotal) {
|
||||
getSnapshot().cookingTime[index] = cookTimeTotal;
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void stopCooking() {
|
||||
+ for (int i = 0; i < getSnapshot().stopCooking.length; ++i)
|
||||
+ this.stopCooking(i);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void startCooking() {
|
||||
+ for (int i = 0; i < getSnapshot().stopCooking.length; ++i)
|
||||
+ this.startCooking(i);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean stopCooking(int index) {
|
||||
+ org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)");
|
||||
+ boolean previous = this.isCookingDisabled(index);
|
||||
+ getSnapshot().stopCooking[index] = true;
|
||||
+ return previous;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean startCooking(int index) {
|
||||
+ org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)");
|
||||
+ boolean previous = this.isCookingDisabled(index);
|
||||
+ getSnapshot().stopCooking[index] = false;
|
||||
+ return previous;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isCookingDisabled(int index) {
|
||||
+ org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)");
|
||||
+ return getSnapshot().stopCooking[index];
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
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 98c436d84e4aedbdb805129fcdb6b871a1b4e3d9..536892e60d4a834161963bb587dc10c37b081a0a 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
@@ -1004,6 +1004,9 @@ public class RegionFile implements AutoCloseable {
|
||||
}
|
||||
|
||||
}
|
||||
+
|
||||
+ public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; // Paper - don't write garbage data to disk if writing serialization fails
|
||||
+
|
||||
// Paper end
|
||||
private class ChunkBuffer extends ByteArrayOutputStream {
|
||||
|
||||
@@ -1019,6 +1022,24 @@ public class RegionFile implements AutoCloseable {
|
||||
this.pos = chunkcoordintpair;
|
||||
}
|
||||
|
||||
+ // Paper start - don't write garbage data to disk if writing serialization fails
|
||||
+ @Override
|
||||
+ public void write(final int b) {
|
||||
+ if (this.count > MAX_CHUNK_SIZE) {
|
||||
+ throw new RegionFileStorage.RegionFileSizeException("Region file too large: " + this.count);
|
||||
+ }
|
||||
+ super.write(b);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void write(final byte[] b, final int off, final int len) {
|
||||
+ if (this.count + len > MAX_CHUNK_SIZE) {
|
||||
+ throw new RegionFileStorage.RegionFileSizeException("Region file too large: " + (this.count + len));
|
||||
+ }
|
||||
+ super.write(b, off, len);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public void close() throws IOException {
|
||||
ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count);
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index 5291bbe208397d73e6950e9f196bcd1da55c1fad..9bb8938fe3dff4cda2d1324c041f03299aa761e4 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
|
||||
@@ -344,10 +344,17 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
NbtIo.write(nbt, (DataOutput) dataoutputstream);
|
||||
regionfile.setStatus(pos.x, pos.z, ChunkSerializer.getStatus(nbt)); // Paper - cache status on disk
|
||||
regionfile.setOversized(pos.x, pos.z, false); // Paper - We don't do this anymore, mojang stores differently, but clear old meta flag if it exists to get rid of our own meta file once last oversized is gone
|
||||
+ dataoutputstream.close(); // Paper - only write if successful
|
||||
+ // Paper start - don't write garbage data to disk if writing serialization fails
|
||||
+ } catch (RegionFileSizeException e) {
|
||||
+ attempts = 5; // Don't retry
|
||||
+ regionfile.clear(pos);
|
||||
+ throw e;
|
||||
+ // Paper end - don't write garbage data to disk if writing serialization fails
|
||||
} catch (Throwable throwable) {
|
||||
if (dataoutputstream != null) {
|
||||
try {
|
||||
- dataoutputstream.close();
|
||||
+ //dataoutputstream.close(); // Paper - don't write garbage data to disk if writing serialization fails
|
||||
} catch (Throwable throwable1) {
|
||||
throwable.addSuppressed(throwable1);
|
||||
}
|
||||
@@ -355,10 +362,7 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
|
||||
throw throwable;
|
||||
}
|
||||
-
|
||||
- if (dataoutputstream != null) {
|
||||
- dataoutputstream.close();
|
||||
- }
|
||||
+ // Paper - move into try block to only write if successfully serialized
|
||||
}
|
||||
|
||||
} finally { // Paper start
|
||||
@@ -393,4 +397,13 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
}
|
||||
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ public static final class RegionFileSizeException extends RuntimeException {
|
||||
+
|
||||
+ public RegionFileSizeException(String message) {
|
||||
+ super(message);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
67
patches/server/0740-Fix-tripwire-state-inconsistency.patch
Normal file
67
patches/server/0740-Fix-tripwire-state-inconsistency.patch
Normal file
|
@ -0,0 +1,67 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nassim Jahnke <nassim@njahnke.dev>
|
||||
Date: Sun, 19 Dec 2021 21:11:20 +0100
|
||||
Subject: [PATCH] Fix tripwire state inconsistency
|
||||
|
||||
This patch prevents updating and re-setting the tripwire when being removed in certain conditions
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/TripWireBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireBlock.java
|
||||
index 4e2fb4ee8e46b3c363992ff23e26f5a648c5f003..7f60175bf671d282c11e9084670d2bb900968255 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/TripWireBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/TripWireBlock.java
|
||||
@@ -74,7 +74,7 @@ public class TripWireBlock extends Block {
|
||||
@Override
|
||||
public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean moved) {
|
||||
if (!moved && !state.is(newState.getBlock())) {
|
||||
- this.updateSource(world, pos, (BlockState) state.setValue(TripWireBlock.POWERED, true));
|
||||
+ this.updateSource(world, pos, (BlockState) state.setValue(TripWireBlock.POWERED, true), true); // Paper - fix state inconsistency
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,12 @@ public class TripWireBlock extends Block {
|
||||
}
|
||||
|
||||
private void updateSource(Level world, BlockPos pos, BlockState state) {
|
||||
+ // Paper start - fix state inconsistency
|
||||
+ this.updateSource(world, pos, state, false);
|
||||
+ }
|
||||
+
|
||||
+ private void updateSource(Level world, BlockPos pos, BlockState state, boolean beingRemoved) {
|
||||
+ // Paper end
|
||||
Direction[] aenumdirection = new Direction[]{Direction.SOUTH, Direction.WEST};
|
||||
int i = aenumdirection.length;
|
||||
int j = 0;
|
||||
@@ -104,7 +110,7 @@ public class TripWireBlock extends Block {
|
||||
|
||||
if (iblockdata1.is((Block) this.hook)) {
|
||||
if (iblockdata1.getValue(TripWireHookBlock.FACING) == enumdirection.getOpposite()) {
|
||||
- this.hook.calculateState(world, blockposition1, iblockdata1, false, true, k, state);
|
||||
+ this.hook.calculateState(world, blockposition1, iblockdata1, false, true, k, state, beingRemoved); // Paper - fix state inconsistency
|
||||
}
|
||||
} else if (iblockdata1.is((Block) this)) {
|
||||
++k;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
index 4a516828e5c6abd63511ee7c93fcff11203cf8d0..004dce26ff073f1de52a84cd425c4f60fdab5e50 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
@@ -108,6 +108,12 @@ public class TripWireHookBlock extends Block {
|
||||
}
|
||||
|
||||
public void calculateState(Level world, BlockPos pos, BlockState state, boolean beingRemoved, boolean flag1, int i, @Nullable BlockState iblockdata1) {
|
||||
+ // Paper start - fix tripwire inconsistency
|
||||
+ this.calculateState(world, pos, state, beingRemoved, flag1, i, iblockdata1, false);
|
||||
+ }
|
||||
+
|
||||
+ public void calculateState(Level world, BlockPos pos, BlockState state, boolean beingRemoved, boolean flag1, int i, @Nullable BlockState iblockdata1, boolean tripWireBeingRemoved) {
|
||||
+ // Paper end
|
||||
Direction enumdirection = (Direction) state.getValue(TripWireHookBlock.FACING);
|
||||
boolean flag2 = (Boolean) state.getValue(TripWireHookBlock.ATTACHED);
|
||||
boolean flag3 = (Boolean) state.getValue(TripWireHookBlock.POWERED);
|
||||
@@ -141,6 +147,7 @@ public class TripWireHookBlock extends Block {
|
||||
boolean flag7 = (Boolean) iblockdata2.getValue(TripWireBlock.POWERED);
|
||||
|
||||
flag5 |= flag6 && flag7;
|
||||
+ if (k != i || !tripWireBeingRemoved || !flag6) // Paper - don't update the tripwire again if being removed and not disarmed
|
||||
aiblockdata[k] = iblockdata2;
|
||||
if (k == i) {
|
||||
world.scheduleTick(pos, (Block) this, 10);
|
|
@ -0,0 +1,39 @@
|
|||
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 6068d70f5eb566396d8c6bf6137e2c6cf21e33cf..f4edaa4395a0ec0d6c507ad7231c3992ab812d1c 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -3321,6 +3321,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
}
|
||||
|
||||
public void restoreFrom(Entity original) {
|
||||
+ // Paper start
|
||||
+ CraftEntity bukkitEntity = original.bukkitEntity;
|
||||
+ if (bukkitEntity != null) {
|
||||
+ bukkitEntity.setHandle(this);
|
||||
+ this.bukkitEntity = bukkitEntity;
|
||||
+ }
|
||||
+ // Paper end
|
||||
CompoundTag nbttagcompound = original.saveWithoutId(new CompoundTag());
|
||||
|
||||
nbttagcompound.remove("Dimension");
|
||||
@@ -3402,10 +3409,10 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
if (worldserver.getTypeKey() == LevelStem.END) { // CraftBukkit
|
||||
ServerLevel.makeObsidianPlatform(worldserver, this); // CraftBukkit
|
||||
}
|
||||
- // CraftBukkit start - Forward the CraftEntity to the new entity
|
||||
- this.getBukkitEntity().setHandle(entity);
|
||||
- entity.bukkitEntity = this.getBukkitEntity();
|
||||
- // CraftBukkit end
|
||||
+ // // CraftBukkit start - Forward the CraftEntity to the new entity // Paper - moved to Entity#restoreFrom
|
||||
+ // this.getBukkitEntity().setHandle(entity);
|
||||
+ // entity.bukkitEntity = this.getBukkitEntity();
|
||||
+ // // CraftBukkit end
|
||||
}
|
||||
|
||||
this.removeAfterChangingDimensions();
|
84
patches/server/0742-Improve-scoreboard-entries.patch
Normal file
84
patches/server/0742-Improve-scoreboard-entries.patch
Normal file
|
@ -0,0 +1,84 @@
|
|||
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 b7f0277b50a0f45c32b818bf9fe1218874aa8533..20b29f78fe56909e02061021b82a84cb7728d8a8 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java
|
||||
@@ -146,6 +146,14 @@ final class CraftObjective extends CraftScoreboardComponent implements Objective
|
||||
return new CraftScore(this, entry);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public Score getScoreFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException, IllegalStateException {
|
||||
+ Validate.notNull(entity, "Entity cannot be null");
|
||||
+ return getScore(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public void unregister() throws IllegalStateException {
|
||||
CraftScoreboard scoreboard = this.checkState();
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java
|
||||
index a038ede38ebb507d6a0182a4a34f2b0722ef024e..fe57437155ff9471738d3b85e787350601b79584 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java
|
||||
@@ -247,4 +247,23 @@ public final class CraftScoreboard implements org.bukkit.scoreboard.Scoreboard {
|
||||
public Scoreboard getHandle() {
|
||||
return this.board;
|
||||
}
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public ImmutableSet<Score> getScoresFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException {
|
||||
+ Validate.notNull(entity, "Entity cannot be null");
|
||||
+ return this.getScores(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void resetScoresFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException {
|
||||
+ Validate.notNull(entity, "Entity cannot be null");
|
||||
+ this.resetScores(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Team getEntityTeam(org.bukkit.entity.Entity entity) throws IllegalArgumentException {
|
||||
+ Validate.notNull(entity, "Entity cannot be null");
|
||||
+ return this.getEntryTeam(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
|
||||
index 60b1cffdccde4715832546d6edbf206fbab4e82f..4b64d6c5c987e127d1ed5edad0a78f7172370b9f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
|
||||
@@ -310,6 +310,26 @@ final class CraftTeam extends CraftScoreboardComponent implements Team {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void addEntity(org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException {
|
||||
+ Validate.notNull(entity, "Entity cannot be null");
|
||||
+ this.addEntry(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean removeEntity(org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException {
|
||||
+ Validate.notNull(entity, "Entity cannot be null");
|
||||
+ return this.removeEntry(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasEntity(org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException {
|
||||
+ Validate.notNull(entity, "Entity cannot be null");
|
||||
+ return this.hasEntry(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public static Visibility bukkitToNotch(NameTagVisibility visibility) {
|
||||
switch (visibility) {
|
||||
case ALWAYS:
|
Loading…
Add table
Add a link
Reference in a new issue