and some more patches
This commit is contained in:
parent
2bc818efd4
commit
24fd5aea0c
51 changed files with 189 additions and 189 deletions
|
@ -6,7 +6,7 @@ Subject: [PATCH] Ability to change PlayerProfile in AsyncPreLoginEvent
|
|||
This will allow you to change the players name or skin on login.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index 1202a60cf955dbfbfc2135c06d3304f215b23c2c..1b00de7f44169a10702dab64c4b4f40e08afd3f9 100644
|
||||
index 1202a60cf955dbfbfc2135c06d3304f215b23c2c..41de3c342f1dae9fc6af1b4938a676d337bcf5fa 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -292,8 +292,16 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
|
@ -20,9 +20,9 @@ index 1202a60cf955dbfbfc2135c06d3304f215b23c2c..1b00de7f44169a10702dab64c4b4f40e
|
|||
server.getPluginManager().callEvent(asyncEvent);
|
||||
+ profile = asyncEvent.getPlayerProfile();
|
||||
+ profile.complete();
|
||||
+ gameProfile = com.destroystokyo.paper.profile.CraftPlayerProfile.asAuthlibCopy(profile);
|
||||
+ playerName = gameProfile.getName();
|
||||
+ uniqueId = gameProfile.getId();
|
||||
+ gameprofile = com.destroystokyo.paper.profile.CraftPlayerProfile.asAuthlibCopy(profile);
|
||||
+ playerName = gameprofile.getName();
|
||||
+ uniqueId = gameprofile.getId();
|
||||
+ // Paper end
|
||||
|
||||
if (PlayerPreLoginEvent.getHandlerList().getRegisteredListeners().length != 0) {
|
||||
|
|
|
@ -22,7 +22,7 @@ index c14ebcc46c033834a14de5d6335a4dcc7830069d..6ad9b294aadf96465834cde1ff1cda17
|
|||
if (Float.isNaN(f)) {
|
||||
f = 0;
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index 1b00de7f44169a10702dab64c4b4f40e08afd3f9..69564543d143c697db0ffee959c41a2163371bbe 100644
|
||||
index 41de3c342f1dae9fc6af1b4938a676d337bcf5fa..f870c20ecce27ebd893107a35e1b8f15e462ff85 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -293,11 +293,11 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
|
@ -30,15 +30,15 @@ index 1b00de7f44169a10702dab64c4b4f40e08afd3f9..69564543d143c697db0ffee959c41a21
|
|||
|
||||
// Paper start
|
||||
- com.destroystokyo.paper.profile.PlayerProfile profile = org.bukkit.Bukkit.createProfile(uniqueId, playerName);
|
||||
+ com.destroystokyo.paper.profile.PlayerProfile profile = com.destroystokyo.paper.profile.CraftPlayerProfile.asBukkitMirror(ServerLoginPacketListenerImpl.this.gameProfile);
|
||||
+ com.destroystokyo.paper.profile.PlayerProfile profile = com.destroystokyo.paper.profile.CraftPlayerProfile.asBukkitMirror(gameprofile);
|
||||
AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, uniqueId, profile);
|
||||
server.getPluginManager().callEvent(asyncEvent);
|
||||
profile = asyncEvent.getPlayerProfile();
|
||||
- profile.complete();
|
||||
+ profile.complete(true); // Paper - setPlayerProfileAPI
|
||||
gameProfile = com.destroystokyo.paper.profile.CraftPlayerProfile.asAuthlibCopy(profile);
|
||||
playerName = gameProfile.getName();
|
||||
uniqueId = gameProfile.getId();
|
||||
gameprofile = com.destroystokyo.paper.profile.CraftPlayerProfile.asAuthlibCopy(profile);
|
||||
playerName = gameprofile.getName();
|
||||
uniqueId = gameprofile.getId();
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
|
||||
index b17fe83bcd7bde44ee8c1f872fffa8bf40707c50..aac78c13361b19efa7b43a0c95458390f1ba8340 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
|
||||
|
|
31
patches/server/0381-Villager-Restocks-API.patch
Normal file
31
patches/server/0381-Villager-Restocks-API.patch
Normal file
|
@ -0,0 +1,31 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: zbk <zbk@projectsolaris.net>
|
||||
Date: Sun, 26 Apr 2020 23:49:01 -0400
|
||||
Subject: [PATCH] Villager Restocks API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.npc.Villager numberOfRestocksToday
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
index 0f12be424a9868c7c34174f92b503cd63399df19..6160f2c2886569b4400080d11beca399ef002ea0 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
@@ -85,6 +85,18 @@ public class CraftVillager extends CraftAbstractVillager implements Villager {
|
||||
this.getHandle().setVillagerXp(experience);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public int getRestocksToday() {
|
||||
+ return getHandle().numberOfRestocksToday;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setRestocksToday(int restocksToday) {
|
||||
+ getHandle().numberOfRestocksToday = restocksToday;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public boolean sleep(Location location) {
|
||||
Preconditions.checkArgument(location != null, "Location cannot be null");
|
|
@ -0,0 +1,26 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 2 May 2020 03:09:46 -0400
|
||||
Subject: [PATCH] Validate PickItem Packet and kick for invalid
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 717f23a92017a589e639c09e15377e30f602d8fe..1f5d20f46ac358855f857a2c5fb348233b56bf2e 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -859,7 +859,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
@Override
|
||||
public void handlePickItem(ServerboundPickItemPacket packet) {
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
|
||||
- this.player.getInventory().pickSlot(packet.getSlot());
|
||||
+ // Paper start - validate pick item position
|
||||
+ if (!(packet.getSlot() >= 0 && packet.getSlot() < this.player.getInventory().items.size())) {
|
||||
+ ServerGamePacketListenerImpl.LOGGER.warn("{} tried to set an invalid carried item", this.player.getName().getString());
|
||||
+ this.disconnect("Invalid hotbar selection (Hacking?)");
|
||||
+ return;
|
||||
+ }
|
||||
+ this.player.getInventory().pickSlot(packet.getSlot()); // Paper - Diff above if changed
|
||||
+ // Paper end
|
||||
this.player.connection.send(new ClientboundContainerSetSlotPacket(-2, 0, this.player.getInventory().selected, this.player.getInventory().getItem(this.player.getInventory().selected)));
|
||||
this.player.connection.send(new ClientboundContainerSetSlotPacket(-2, 0, packet.getSlot(), this.player.getInventory().getItem(packet.getSlot())));
|
||||
this.player.connection.send(new ClientboundSetCarriedItemPacket(this.player.getInventory().selected));
|
24
patches/server/0383-Expose-game-version.patch
Normal file
24
patches/server/0383-Expose-game-version.patch
Normal file
|
@ -0,0 +1,24 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Vainomaa <mikroskeem@mikroskeem.eu>
|
||||
Date: Fri, 1 May 2020 17:39:26 +0300
|
||||
Subject: [PATCH] Expose game version
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 712bee34303ca3ceec4520e265f4defdc27ea8ff..3597b4f98c73b781a3f2389e563e3dc2c2f711fe 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -585,6 +585,13 @@ public final class CraftServer implements Server {
|
||||
return this.bukkitVersion;
|
||||
}
|
||||
|
||||
+ // Paper start - expose game version
|
||||
+ @Override
|
||||
+ public String getMinecraftVersion() {
|
||||
+ return console.getServerVersion();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public List<CraftPlayer> getOnlinePlayers() {
|
||||
return this.playerView;
|
121
patches/server/0384-Optimize-Voxel-Shape-Merging.patch
Normal file
121
patches/server/0384-Optimize-Voxel-Shape-Merging.patch
Normal file
|
@ -0,0 +1,121 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 3 May 2020 22:35:09 -0400
|
||||
Subject: [PATCH] Optimize Voxel Shape Merging
|
||||
|
||||
This method shows up as super hot in profiler, and also a high "self" time.
|
||||
|
||||
Upon analyzing, it appears most usages of this method fall down to the final
|
||||
else statement of the nasty ternary.
|
||||
|
||||
Upon even further analyzation, it appears then the majority of those have a
|
||||
consistent list 1.... One with Infinity head and Tails.
|
||||
|
||||
First optimization is to detect these infinite states and immediately return that
|
||||
VoxelShapeMergerList so we can avoid testing the rest for most cases.
|
||||
|
||||
Break the method into 2 to help the JVM promote inlining of this fast path.
|
||||
|
||||
Then it was also noticed that VoxelShapeMergerList constructor is also a hotspot
|
||||
with a high self time...
|
||||
|
||||
Well, knowing that in most cases our list 1 is actualy the same value, it allows
|
||||
us to know that with an infinite list1, the result on the merger is essentially
|
||||
list2 as the final values.
|
||||
|
||||
This let us analyze the 2 potential states (Infinite with 2 sources or 4 sources)
|
||||
and compute a deterministic result for the MergerList values.
|
||||
|
||||
Additionally, this lets us avoid even allocating new objects for this too, further
|
||||
reducing memory usage.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java b/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
|
||||
index 0d9c15120148409967027dead617e80769939697..2214a3198c712deaac0f3d3478c85352185761d4 100644
|
||||
--- a/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
|
||||
+++ b/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
|
||||
@@ -10,12 +10,33 @@ public class IndirectMerger implements IndexMerger {
|
||||
private final int[] firstIndices;
|
||||
private final int[] secondIndices;
|
||||
private final int resultLength;
|
||||
+ // Paper start
|
||||
+ private static final int[] INFINITE_B_1 = new int[]{1, 1};
|
||||
+ private static final int[] INFINITE_B_0 = new int[]{0, 0};
|
||||
+ private static final int[] INFINITE_C = new int[]{0, 1};
|
||||
+ // Paper end
|
||||
|
||||
public IndirectMerger(DoubleList first, DoubleList second, boolean includeFirstOnly, boolean includeSecondOnly) {
|
||||
double d = Double.NaN;
|
||||
int i = first.size();
|
||||
int j = second.size();
|
||||
int k = i + j;
|
||||
+ // Paper start - optimize common path of infinity doublelist
|
||||
+ int size = first.size();
|
||||
+ double tail = first.getDouble(size - 1);
|
||||
+ double head = first.getDouble(0);
|
||||
+ if (head == Double.NEGATIVE_INFINITY && tail == Double.POSITIVE_INFINITY && !includeFirstOnly && !includeSecondOnly && (size == 2 || size == 4)) {
|
||||
+ this.result = second.toDoubleArray();
|
||||
+ this.resultLength = second.size();
|
||||
+ if (size == 2) {
|
||||
+ this.firstIndices = INFINITE_B_0;
|
||||
+ } else {
|
||||
+ this.firstIndices = INFINITE_B_1;
|
||||
+ }
|
||||
+ this.secondIndices = INFINITE_C;
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.result = new double[k];
|
||||
this.firstIndices = new int[k];
|
||||
this.secondIndices = new int[k];
|
||||
diff --git a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
|
||||
index 2d273be8145bbd86ffdf33358629da7fc08b4d4c..9176735c08a75854209f24113b0e78332249dc4d 100644
|
||||
--- a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
|
||||
+++ b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
|
||||
@@ -247,9 +247,21 @@ public final class Shapes {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
- protected static IndexMerger createIndexMerger(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) {
|
||||
+ private static IndexMerger createIndexMerger(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) { // Paper - private
|
||||
+ // Paper start - fast track the most common scenario
|
||||
+ // doublelist is usually a DoubleArrayList with Infinite head/tails that falls to the final else clause
|
||||
+ // This is actually the most common path, so jump to it straight away
|
||||
+ if (first.getDouble(0) == Double.NEGATIVE_INFINITY && first.getDouble(first.size() - 1) == Double.POSITIVE_INFINITY) {
|
||||
+ return new IndirectMerger(first, second, includeFirst, includeSecond);
|
||||
+ }
|
||||
+ // Split out rest to hopefully inline the above
|
||||
+ return lessCommonMerge(size, first, second, includeFirst, includeSecond);
|
||||
+ }
|
||||
+
|
||||
+ private static IndexMerger lessCommonMerge(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) {
|
||||
int i = first.size() - 1;
|
||||
int j = second.size() - 1;
|
||||
+ // Paper note - Rewrite below as optimized order if instead of nasty ternary
|
||||
if (first instanceof CubePointRange && second instanceof CubePointRange) {
|
||||
long l = lcm(i, j);
|
||||
if ((long)size * l <= 256L) {
|
||||
@@ -257,13 +269,22 @@ public final class Shapes {
|
||||
}
|
||||
}
|
||||
|
||||
- if (first.getDouble(i) < second.getDouble(0) - 1.0E-7D) {
|
||||
+ // Paper start - Identical happens more often than Disjoint
|
||||
+ if (i == j && Objects.equals(first, second)) {
|
||||
+ if (first instanceof IdenticalMerger) {
|
||||
+ return (IndexMerger) first;
|
||||
+ } else if (second instanceof IdenticalMerger) {
|
||||
+ return (IndexMerger) second;
|
||||
+ }
|
||||
+ return new IdenticalMerger(first);
|
||||
+ } else if (first.getDouble(i) < second.getDouble(0) - 1.0E-7D) {
|
||||
return new NonOverlappingMerger(first, second, false);
|
||||
} else if (second.getDouble(j) < first.getDouble(0) - 1.0E-7D) {
|
||||
return new NonOverlappingMerger(second, first, true);
|
||||
} else {
|
||||
- return (IndexMerger)(i == j && Objects.equals(first, second) ? new IdenticalMerger(first) : new IndirectMerger(first, second, includeFirst, includeSecond));
|
||||
+ return new IndirectMerger(first, second, includeFirst, includeSecond);
|
||||
}
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public interface DoubleLineConsumer {
|
|
@ -0,0 +1,30 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 4 May 2020 01:08:56 -0400
|
||||
Subject: [PATCH] Set cap on JDK per-thread native byte buffer cache
|
||||
|
||||
See: https://www.evanjones.ca/java-bytebuffer-leak.html
|
||||
|
||||
This is potentially a source of lots of native memory usage.
|
||||
|
||||
We are clearly seeing native usage upwards to 1-4GB which doesn't make sense.
|
||||
|
||||
Region File usage fixed in previous patch should of tecnically only been somewhat
|
||||
temporary until GC finally gets it some time later, but between all the various
|
||||
plugins doing IO on various threads, this hidden detail of the JDK could be
|
||||
keeping long lived large direct buffers in cache.
|
||||
|
||||
Set system properly at server startup if not set already to help protect from this.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
index c561677e81095ab6735d81a414a249838b135f7a..224be855fd16b37c8766c3c07b81905d50d5518d 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -26,6 +26,7 @@ public class Main {
|
||||
}
|
||||
// Paper end
|
||||
// Todo: Installation script
|
||||
+ if (System.getProperty("jdk.nio.maxCachedBufferSize") == null) System.setProperty("jdk.nio.maxCachedBufferSize", "262144"); // Paper - cap per-thread NIO cache size
|
||||
OptionParser parser = new OptionParser() {
|
||||
{
|
||||
acceptsAll(Main.asList("?", "help"), "Show the help");
|
87
patches/server/0386-misc-debugging-dumps.patch
Normal file
87
patches/server/0386-misc-debugging-dumps.patch
Normal file
|
@ -0,0 +1,87 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Thu, 18 Feb 2021 20:23:28 +0000
|
||||
Subject: [PATCH] misc debugging dumps
|
||||
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/util/TraceUtil.java b/src/main/java/io/papermc/paper/util/TraceUtil.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..2d5494d2813b773e60ddba6790b750a9a08f21f8
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/TraceUtil.java
|
||||
@@ -0,0 +1,18 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import org.bukkit.Bukkit;
|
||||
+
|
||||
+public final class TraceUtil {
|
||||
+
|
||||
+ public static void dumpTraceForThread(Thread thread, String reason) {
|
||||
+ Bukkit.getLogger().warning(thread.getName() + ": " + reason);
|
||||
+ StackTraceElement[] trace = thread.getStackTrace();
|
||||
+ for (StackTraceElement traceElement : trace) {
|
||||
+ Bukkit.getLogger().warning("\tat " + traceElement);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static void dumpTraceForThread(String reason) {
|
||||
+ new Throwable(reason).printStackTrace();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index d50878653132218dd494e0e5ed6fc3a32d4f1465..ad7f14d78fea3e6aba9576114463907b292c45a0 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -862,6 +862,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// CraftBukkit start
|
||||
private boolean hasStopped = false;
|
||||
public volatile boolean hasFullyShutdown = false; // Paper
|
||||
+ private boolean hasLoggedStop = false; // Paper
|
||||
private final Object stopLock = new Object();
|
||||
public final boolean hasStopped() {
|
||||
synchronized (this.stopLock) {
|
||||
@@ -876,6 +877,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
if (this.hasStopped) return;
|
||||
this.hasStopped = true;
|
||||
}
|
||||
+ if (!hasLoggedStop && isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper
|
||||
// Paper start - kill main thread, and kill it hard
|
||||
shutdownThread = Thread.currentThread();
|
||||
org.spigotmc.WatchdogThread.doStop(); // Paper
|
||||
@@ -1004,6 +1006,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
public void safeShutdown(boolean waitForShutdown, boolean isRestarting) {
|
||||
this.isRestarting = isRestarting;
|
||||
+ this.hasLoggedStop = true; // Paper
|
||||
+ if (isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper
|
||||
// Paper end
|
||||
this.running = false;
|
||||
if (waitForShutdown) {
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
index ea26375d6f23b14a8a1cd926fe410713551de99d..496ac1d2fd43c5ddfe7fa7a8b72a75860ec43443 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
@@ -130,6 +130,11 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis
|
||||
this.connection.resumeInboundAfterProtocolChange();
|
||||
} catch (Exception exception) {
|
||||
ServerConfigurationPacketListenerImpl.LOGGER.error("Couldn't place player in world", exception);
|
||||
+ // Paper start
|
||||
+ if (MinecraftServer.getServer().isDebugging()) {
|
||||
+ exception.printStackTrace();
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.connection.send(new ClientboundDisconnectPacket(ServerConfigurationPacketListenerImpl.DISCONNECT_REASON_INVALID_DATA));
|
||||
this.connection.disconnect(ServerConfigurationPacketListenerImpl.DISCONNECT_REASON_INVALID_DATA);
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 3597b4f98c73b781a3f2389e563e3dc2c2f711fe..64663e74d85979f857d748f0c252c0568f5d95ae 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1009,6 +1009,7 @@ public final class CraftServer implements Server {
|
||||
plugin.getDescription().getFullName(),
|
||||
"This plugin is not properly shutting down its async tasks when it is being reloaded. This may cause conflicts with the newly loaded version of the plugin"
|
||||
));
|
||||
+ if (console.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread(worker.getThread(), "still running"); // Paper
|
||||
}
|
||||
io.papermc.paper.plugin.PluginInitializerManager.reload(this.console); // Paper
|
||||
this.loadPlugins();
|
24
patches/server/0387-Prevent-teleporting-dead-entities.patch
Normal file
24
patches/server/0387-Prevent-teleporting-dead-entities.patch
Normal file
|
@ -0,0 +1,24 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Tue, 3 Mar 2020 05:26:40 +0000
|
||||
Subject: [PATCH] Prevent teleporting dead entities
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 1f5d20f46ac358855f857a2c5fb348233b56bf2e..7f4bae60e44d9624871b5b447ea2df11f95d82fe 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1507,6 +1507,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
}
|
||||
|
||||
public void internalTeleport(double d0, double d1, double d2, float f, float f1, Set<RelativeMovement> set) { // Paper
|
||||
+ // Paper start
|
||||
+ if (player.isRemoved()) {
|
||||
+ LOGGER.info("Attempt to teleport removed player {} restricted", player.getScoreboardName());
|
||||
+ if (server.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Attempt to teleport removed player");
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
// CraftBukkit start
|
||||
if (Float.isNaN(f)) {
|
||||
f = 0;
|
|
@ -0,0 +1,684 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
|
||||
Date: Sun, 20 Jun 2021 18:19:09 -0700
|
||||
Subject: [PATCH] Deobfuscate stacktraces in log messages, crash reports, and
|
||||
etc.
|
||||
|
||||
|
||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||
index 7f005b9a41064f1929e8d9cb53c5ab207d3a333d..dfb43cf7be60733f3ab142de66139971bca1b1fe 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -37,6 +37,7 @@ dependencies {
|
||||
testImplementation("org.mockito:mockito-core:4.9.0") // Paper - switch to mockito
|
||||
implementation("org.spongepowered:configurate-yaml:4.1.2") // Paper - config files
|
||||
implementation("commons-lang:commons-lang:2.6")
|
||||
+ implementation("net.fabricmc:mapping-io:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation
|
||||
runtimeOnly("org.xerial:sqlite-jdbc:3.43.0.0")
|
||||
runtimeOnly("com.mysql:mysql-connector-j:8.1.0")
|
||||
runtimeOnly("com.lmax:disruptor:3.4.4") // Paper
|
||||
@@ -121,6 +122,18 @@ tasks.check {
|
||||
}
|
||||
// Paper end
|
||||
|
||||
+// Paper start - include reobf mappings in jar for stacktrace deobfuscation
|
||||
+val includeMappings = tasks.register<io.papermc.paperweight.tasks.IncludeMappings>("includeMappings") {
|
||||
+ inputJar.set(tasks.fixJarForReobf.flatMap { it.outputJar })
|
||||
+ mappings.set(tasks.reobfJar.flatMap { it.mappingsFile })
|
||||
+ mappingsDest.set("META-INF/mappings/reobf.tiny")
|
||||
+}
|
||||
+
|
||||
+tasks.reobfJar {
|
||||
+ inputJar.set(includeMappings.flatMap { it.outputJar })
|
||||
+}
|
||||
+// Paper end - include reobf mappings in jar for stacktrace deobfuscation
|
||||
+
|
||||
tasks.test {
|
||||
exclude("org/bukkit/craftbukkit/inventory/ItemStack*Test.class")
|
||||
}
|
||||
diff --git a/src/log4jPlugins/java/io/papermc/paper/logging/StacktraceDeobfuscatingRewritePolicy.java b/src/log4jPlugins/java/io/papermc/paper/logging/StacktraceDeobfuscatingRewritePolicy.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..66b6011ee3684695b2ab9292961c80bf2a420ee9
|
||||
--- /dev/null
|
||||
+++ b/src/log4jPlugins/java/io/papermc/paper/logging/StacktraceDeobfuscatingRewritePolicy.java
|
||||
@@ -0,0 +1,66 @@
|
||||
+package io.papermc.paper.logging;
|
||||
+
|
||||
+import java.lang.invoke.MethodHandle;
|
||||
+import java.lang.invoke.MethodHandles;
|
||||
+import java.lang.invoke.VarHandle;
|
||||
+import org.apache.logging.log4j.core.Core;
|
||||
+import org.apache.logging.log4j.core.LogEvent;
|
||||
+import org.apache.logging.log4j.core.appender.rewrite.RewritePolicy;
|
||||
+import org.apache.logging.log4j.core.config.plugins.Plugin;
|
||||
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
|
||||
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+
|
||||
+@Plugin(
|
||||
+ name = "StacktraceDeobfuscatingRewritePolicy",
|
||||
+ category = Core.CATEGORY_NAME,
|
||||
+ elementType = "rewritePolicy",
|
||||
+ printObject = true
|
||||
+)
|
||||
+public final class StacktraceDeobfuscatingRewritePolicy implements RewritePolicy {
|
||||
+ private static final MethodHandle DEOBFUSCATE_THROWABLE;
|
||||
+
|
||||
+ static {
|
||||
+ try {
|
||||
+ final Class<?> cls = Class.forName("io.papermc.paper.util.StacktraceDeobfuscator");
|
||||
+ final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
+ final VarHandle instanceHandle = lookup.findStaticVarHandle(cls, "INSTANCE", cls);
|
||||
+ final Object deobfuscator = instanceHandle.get();
|
||||
+ DEOBFUSCATE_THROWABLE = lookup
|
||||
+ .unreflect(cls.getDeclaredMethod("deobfuscateThrowable", Throwable.class))
|
||||
+ .bindTo(deobfuscator);
|
||||
+ } catch (final ReflectiveOperationException ex) {
|
||||
+ throw new IllegalStateException(ex);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private StacktraceDeobfuscatingRewritePolicy() {
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @NonNull LogEvent rewrite(final @NonNull LogEvent rewrite) {
|
||||
+ final Throwable thrown = rewrite.getThrown();
|
||||
+ if (thrown != null) {
|
||||
+ deobfuscateThrowable(thrown);
|
||||
+ return new Log4jLogEvent.Builder(rewrite)
|
||||
+ .setThrownProxy(null)
|
||||
+ .build();
|
||||
+ }
|
||||
+ return rewrite;
|
||||
+ }
|
||||
+
|
||||
+ private static void deobfuscateThrowable(final Throwable thrown) {
|
||||
+ try {
|
||||
+ DEOBFUSCATE_THROWABLE.invoke(thrown);
|
||||
+ } catch (final Error e) {
|
||||
+ throw e;
|
||||
+ } catch (final Throwable e) {
|
||||
+ throw new RuntimeException(e);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @PluginFactory
|
||||
+ public static @NonNull StacktraceDeobfuscatingRewritePolicy createPolicy() {
|
||||
+ return new StacktraceDeobfuscatingRewritePolicy();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java b/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java
|
||||
index 0bb4aaa546939b67a5d22865190f30478a9337c1..d3e619655382e50e9ac9323ed942502d85c9599c 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/io/SyncLoadFinder.java
|
||||
@@ -91,7 +91,7 @@ public class SyncLoadFinder {
|
||||
|
||||
final JsonArray traces = new JsonArray();
|
||||
|
||||
- for (StackTraceElement element : pair.getFirst().stacktrace) {
|
||||
+ for (StackTraceElement element : io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(pair.getFirst().stacktrace)) {
|
||||
traces.add(String.valueOf(element));
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/util/ObfHelper.java b/src/main/java/io/papermc/paper/util/ObfHelper.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b8b17d046f836c8652ab094db00ab1af84971b2c
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/ObfHelper.java
|
||||
@@ -0,0 +1,146 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import java.io.IOException;
|
||||
+import java.io.InputStream;
|
||||
+import java.io.InputStreamReader;
|
||||
+import java.nio.charset.StandardCharsets;
|
||||
+import java.util.HashMap;
|
||||
+import java.util.HashSet;
|
||||
+import java.util.Map;
|
||||
+import java.util.Set;
|
||||
+import java.util.function.Function;
|
||||
+import java.util.stream.Collectors;
|
||||
+import net.fabricmc.mappingio.MappingReader;
|
||||
+import net.fabricmc.mappingio.format.MappingFormat;
|
||||
+import net.fabricmc.mappingio.tree.MappingTree;
|
||||
+import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public enum ObfHelper {
|
||||
+ INSTANCE;
|
||||
+
|
||||
+ public static final String MOJANG_PLUS_YARN_NAMESPACE = "mojang+yarn";
|
||||
+ public static final String SPIGOT_NAMESPACE = "spigot";
|
||||
+
|
||||
+ private final @Nullable Map<String, ClassMapping> mappingsByObfName;
|
||||
+ private final @Nullable Map<String, ClassMapping> mappingsByMojangName;
|
||||
+
|
||||
+ ObfHelper() {
|
||||
+ final @Nullable Set<ClassMapping> maps = loadMappingsIfPresent();
|
||||
+ if (maps != null) {
|
||||
+ this.mappingsByObfName = maps.stream().collect(Collectors.toUnmodifiableMap(ClassMapping::obfName, map -> map));
|
||||
+ this.mappingsByMojangName = maps.stream().collect(Collectors.toUnmodifiableMap(ClassMapping::mojangName, map -> map));
|
||||
+ } else {
|
||||
+ this.mappingsByObfName = null;
|
||||
+ this.mappingsByMojangName = null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public @Nullable Map<String, ClassMapping> mappingsByObfName() {
|
||||
+ return this.mappingsByObfName;
|
||||
+ }
|
||||
+
|
||||
+ public @Nullable Map<String, ClassMapping> mappingsByMojangName() {
|
||||
+ return this.mappingsByMojangName;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Attempts to get the obf name for a given class by its Mojang name. Will
|
||||
+ * return the input string if mappings are not present.
|
||||
+ *
|
||||
+ * @param fullyQualifiedMojangName fully qualified class name (dotted)
|
||||
+ * @return mapped or original fully qualified (dotted) class name
|
||||
+ */
|
||||
+ public String reobfClassName(final String fullyQualifiedMojangName) {
|
||||
+ if (this.mappingsByMojangName == null) {
|
||||
+ return fullyQualifiedMojangName;
|
||||
+ }
|
||||
+
|
||||
+ final ClassMapping map = this.mappingsByMojangName.get(fullyQualifiedMojangName);
|
||||
+ if (map == null) {
|
||||
+ return fullyQualifiedMojangName;
|
||||
+ }
|
||||
+
|
||||
+ return map.obfName();
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Attempts to get the Mojang name for a given class by its obf name. Will
|
||||
+ * return the input string if mappings are not present.
|
||||
+ *
|
||||
+ * @param fullyQualifiedObfName fully qualified class name (dotted)
|
||||
+ * @return mapped or original fully qualified (dotted) class name
|
||||
+ */
|
||||
+ public String deobfClassName(final String fullyQualifiedObfName) {
|
||||
+ if (this.mappingsByObfName == null) {
|
||||
+ return fullyQualifiedObfName;
|
||||
+ }
|
||||
+
|
||||
+ final ClassMapping map = this.mappingsByObfName.get(fullyQualifiedObfName);
|
||||
+ if (map == null) {
|
||||
+ return fullyQualifiedObfName;
|
||||
+ }
|
||||
+
|
||||
+ return map.mojangName();
|
||||
+ }
|
||||
+
|
||||
+ private static @Nullable Set<ClassMapping> loadMappingsIfPresent() {
|
||||
+ try (final @Nullable InputStream mappingsInputStream = ObfHelper.class.getClassLoader().getResourceAsStream("META-INF/mappings/reobf.tiny")) {
|
||||
+ if (mappingsInputStream == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ final MemoryMappingTree tree = new MemoryMappingTree();
|
||||
+ MappingReader.read(new InputStreamReader(mappingsInputStream, StandardCharsets.UTF_8), MappingFormat.TINY_2, tree);
|
||||
+ final Set<ClassMapping> classes = new HashSet<>();
|
||||
+
|
||||
+ final StringPool pool = new StringPool();
|
||||
+ for (final MappingTree.ClassMapping cls : tree.getClasses()) {
|
||||
+ final Map<String, String> methods = new HashMap<>();
|
||||
+
|
||||
+ for (final MappingTree.MethodMapping methodMapping : cls.getMethods()) {
|
||||
+ methods.put(
|
||||
+ pool.string(methodKey(
|
||||
+ methodMapping.getName(SPIGOT_NAMESPACE),
|
||||
+ methodMapping.getDesc(SPIGOT_NAMESPACE)
|
||||
+ )),
|
||||
+ pool.string(methodMapping.getName(MOJANG_PLUS_YARN_NAMESPACE))
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ final ClassMapping map = new ClassMapping(
|
||||
+ cls.getName(SPIGOT_NAMESPACE).replace('/', '.'),
|
||||
+ cls.getName(MOJANG_PLUS_YARN_NAMESPACE).replace('/', '.'),
|
||||
+ Map.copyOf(methods)
|
||||
+ );
|
||||
+ classes.add(map);
|
||||
+ }
|
||||
+
|
||||
+ return Set.copyOf(classes);
|
||||
+ } catch (final IOException ex) {
|
||||
+ System.err.println("Failed to load mappings for stacktrace deobfuscation.");
|
||||
+ ex.printStackTrace();
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static String methodKey(final String obfName, final String obfDescriptor) {
|
||||
+ return obfName + obfDescriptor;
|
||||
+ }
|
||||
+
|
||||
+ private static final class StringPool {
|
||||
+ private final Map<String, String> pool = new HashMap<>();
|
||||
+
|
||||
+ public String string(final String string) {
|
||||
+ return this.pool.computeIfAbsent(string, Function.identity());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public record ClassMapping(
|
||||
+ String obfName,
|
||||
+ String mojangName,
|
||||
+ Map<String, String> methodsByObf
|
||||
+ ) {}
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java b/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..eb910d4abf91488fa7cf1f5d47e0ee916c47f512
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java
|
||||
@@ -0,0 +1,163 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import io.papermc.paper.configuration.GlobalConfiguration;
|
||||
+import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
+import it.unimi.dsi.fastutil.ints.IntList;
|
||||
+import java.io.IOException;
|
||||
+import java.io.InputStream;
|
||||
+import java.util.Collections;
|
||||
+import java.util.HashMap;
|
||||
+import java.util.LinkedHashMap;
|
||||
+import java.util.Map;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+import org.objectweb.asm.ClassReader;
|
||||
+import org.objectweb.asm.ClassVisitor;
|
||||
+import org.objectweb.asm.Label;
|
||||
+import org.objectweb.asm.MethodVisitor;
|
||||
+import org.objectweb.asm.Opcodes;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public enum StacktraceDeobfuscator {
|
||||
+ INSTANCE;
|
||||
+
|
||||
+ private final Map<Class<?>, Map<String, IntList>> lineMapCache = Collections.synchronizedMap(new LinkedHashMap<>(128, 0.75f, true) {
|
||||
+ @Override
|
||||
+ protected boolean removeEldestEntry(final Map.Entry<Class<?>, Map<String, IntList>> eldest) {
|
||||
+ return this.size() > 127;
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ public void deobfuscateThrowable(final Throwable throwable) {
|
||||
+ if (GlobalConfiguration.get() != null && !GlobalConfiguration.get().logging.deobfuscateStacktraces) { // handle null as true
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ throwable.setStackTrace(this.deobfuscateStacktrace(throwable.getStackTrace()));
|
||||
+ final Throwable cause = throwable.getCause();
|
||||
+ if (cause != null) {
|
||||
+ this.deobfuscateThrowable(cause);
|
||||
+ }
|
||||
+ for (final Throwable suppressed : throwable.getSuppressed()) {
|
||||
+ this.deobfuscateThrowable(suppressed);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public StackTraceElement[] deobfuscateStacktrace(final StackTraceElement[] traceElements) {
|
||||
+ if (GlobalConfiguration.get() != null && !GlobalConfiguration.get().logging.deobfuscateStacktraces) { // handle null as true
|
||||
+ return traceElements;
|
||||
+ }
|
||||
+
|
||||
+ final @Nullable Map<String, ObfHelper.ClassMapping> mappings = ObfHelper.INSTANCE.mappingsByObfName();
|
||||
+ if (mappings == null || traceElements.length == 0) {
|
||||
+ return traceElements;
|
||||
+ }
|
||||
+ final StackTraceElement[] result = new StackTraceElement[traceElements.length];
|
||||
+ for (int i = 0; i < traceElements.length; i++) {
|
||||
+ final StackTraceElement element = traceElements[i];
|
||||
+
|
||||
+ final String className = element.getClassName();
|
||||
+ final String methodName = element.getMethodName();
|
||||
+
|
||||
+ final ObfHelper.ClassMapping classMapping = mappings.get(className);
|
||||
+ if (classMapping == null) {
|
||||
+ result[i] = element;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ final Class<?> clazz;
|
||||
+ try {
|
||||
+ clazz = Class.forName(className);
|
||||
+ } catch (final ClassNotFoundException ex) {
|
||||
+ throw new RuntimeException(ex);
|
||||
+ }
|
||||
+ final @Nullable String methodKey = this.determineMethodForLine(clazz, element.getLineNumber());
|
||||
+ final @Nullable String mappedMethodName = methodKey == null ? null : classMapping.methodsByObf().get(methodKey);
|
||||
+
|
||||
+ result[i] = new StackTraceElement(
|
||||
+ element.getClassLoaderName(),
|
||||
+ element.getModuleName(),
|
||||
+ element.getModuleVersion(),
|
||||
+ classMapping.mojangName(),
|
||||
+ mappedMethodName != null ? mappedMethodName : methodName,
|
||||
+ sourceFileName(classMapping.mojangName()),
|
||||
+ element.getLineNumber()
|
||||
+ );
|
||||
+ }
|
||||
+ return result;
|
||||
+ }
|
||||
+
|
||||
+ private @Nullable String determineMethodForLine(final Class<?> clazz, final int lineNumber) {
|
||||
+ final Map<String, IntList> lineMap = this.lineMapCache.computeIfAbsent(clazz, StacktraceDeobfuscator::buildLineMap);
|
||||
+ for (final var entry : lineMap.entrySet()) {
|
||||
+ final String methodKey = entry.getKey();
|
||||
+ final IntList lines = entry.getValue();
|
||||
+ for (int i = 0, linesSize = lines.size(); i < linesSize; i++) {
|
||||
+ final int num = lines.getInt(i);
|
||||
+ if (num == lineNumber) {
|
||||
+ return methodKey;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ private static String sourceFileName(final String fullClassName) {
|
||||
+ final int dot = fullClassName.lastIndexOf('.');
|
||||
+ final String className = dot == -1
|
||||
+ ? fullClassName
|
||||
+ : fullClassName.substring(dot + 1);
|
||||
+ final String rootClassName = className.split("\\$")[0];
|
||||
+ return rootClassName + ".java";
|
||||
+ }
|
||||
+
|
||||
+ private static Map<String, IntList> buildLineMap(final Class<?> key) {
|
||||
+ final Map<String, IntList> lineMap = new HashMap<>();
|
||||
+ final class LineCollectingMethodVisitor extends MethodVisitor {
|
||||
+ private final IntList lines = new IntArrayList();
|
||||
+ private final String name;
|
||||
+ private final String descriptor;
|
||||
+
|
||||
+ LineCollectingMethodVisitor(String name, String descriptor) {
|
||||
+ super(Opcodes.ASM9);
|
||||
+ this.name = name;
|
||||
+ this.descriptor = descriptor;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void visitLineNumber(int line, Label start) {
|
||||
+ super.visitLineNumber(line, start);
|
||||
+ this.lines.add(line);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void visitEnd() {
|
||||
+ super.visitEnd();
|
||||
+ lineMap.put(ObfHelper.methodKey(this.name, this.descriptor), this.lines);
|
||||
+ }
|
||||
+ }
|
||||
+ final ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM9) {
|
||||
+ @Override
|
||||
+ public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
||||
+ return new LineCollectingMethodVisitor(name, descriptor);
|
||||
+ }
|
||||
+ };
|
||||
+ try {
|
||||
+ final @Nullable InputStream inputStream = StacktraceDeobfuscator.class.getClassLoader()
|
||||
+ .getResourceAsStream(key.getName().replace('.', '/') + ".class");
|
||||
+ if (inputStream == null) {
|
||||
+ throw new IllegalStateException("Could not find class file: " + key.getName());
|
||||
+ }
|
||||
+ final byte[] classData;
|
||||
+ try (inputStream) {
|
||||
+ classData = inputStream.readAllBytes();
|
||||
+ }
|
||||
+ final ClassReader reader = new ClassReader(classData);
|
||||
+ reader.accept(classVisitor, 0);
|
||||
+ } catch (final IOException ex) {
|
||||
+ throw new RuntimeException(ex);
|
||||
+ }
|
||||
+ return lineMap;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/util/TraceUtil.java b/src/main/java/io/papermc/paper/util/TraceUtil.java
|
||||
index 2d5494d2813b773e60ddba6790b750a9a08f21f8..0b210bdf7c1f5962afbd44195af6f84f625635e3 100644
|
||||
--- a/src/main/java/io/papermc/paper/util/TraceUtil.java
|
||||
+++ b/src/main/java/io/papermc/paper/util/TraceUtil.java
|
||||
@@ -6,13 +6,20 @@ public final class TraceUtil {
|
||||
|
||||
public static void dumpTraceForThread(Thread thread, String reason) {
|
||||
Bukkit.getLogger().warning(thread.getName() + ": " + reason);
|
||||
- StackTraceElement[] trace = thread.getStackTrace();
|
||||
+ StackTraceElement[] trace = StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(thread.getStackTrace());
|
||||
for (StackTraceElement traceElement : trace) {
|
||||
Bukkit.getLogger().warning("\tat " + traceElement);
|
||||
}
|
||||
}
|
||||
|
||||
public static void dumpTraceForThread(String reason) {
|
||||
- new Throwable(reason).printStackTrace();
|
||||
+ final Throwable throwable = new Throwable(reason);
|
||||
+ StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(throwable);
|
||||
+ throwable.printStackTrace();
|
||||
+ }
|
||||
+
|
||||
+ public static void printStackTrace(Throwable thr) {
|
||||
+ StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(thr);
|
||||
+ thr.printStackTrace();
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/CrashReport.java b/src/main/java/net/minecraft/CrashReport.java
|
||||
index 226cba0c1eeedd9e80acd603c46b802c183db1fa..1d714d3eff11ed14f218656008190017494d4830 100644
|
||||
--- a/src/main/java/net/minecraft/CrashReport.java
|
||||
+++ b/src/main/java/net/minecraft/CrashReport.java
|
||||
@@ -32,6 +32,7 @@ public class CrashReport {
|
||||
private final SystemReport systemReport = new SystemReport();
|
||||
|
||||
public CrashReport(String message, Throwable cause) {
|
||||
+ io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(cause); // Paper
|
||||
this.title = message;
|
||||
this.exception = cause;
|
||||
this.systemReport.setDetail("CraftBukkit Information", new org.bukkit.craftbukkit.CraftCrashReport()); // CraftBukkit
|
||||
diff --git a/src/main/java/net/minecraft/CrashReportCategory.java b/src/main/java/net/minecraft/CrashReportCategory.java
|
||||
index 52eb3176437113f9a0ff85d10ce5c2415e1b5570..b54ddd0ba0b001fbcb1838a838ca4890df936f1b 100644
|
||||
--- a/src/main/java/net/minecraft/CrashReportCategory.java
|
||||
+++ b/src/main/java/net/minecraft/CrashReportCategory.java
|
||||
@@ -104,6 +104,7 @@ public class CrashReportCategory {
|
||||
} else {
|
||||
this.stackTrace = new StackTraceElement[stackTraceElements.length - 3 - ignoredCallCount];
|
||||
System.arraycopy(stackTraceElements, 3 + ignoredCallCount, this.stackTrace, 0, this.stackTrace.length);
|
||||
+ this.stackTrace = io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(this.stackTrace); // Paper
|
||||
return this.stackTrace.length;
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
||||
index 62df5c51fa11f85ec2fad20c0ea5aa6241294e8a..81e49a770fd8a10e987f3e67a5ab99fc39d5e47f 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -75,13 +75,13 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
public static final AttributeKey<ConnectionProtocol.CodecData<?>> ATTRIBUTE_SERVERBOUND_PROTOCOL = AttributeKey.valueOf("serverbound_protocol");
|
||||
public static final AttributeKey<ConnectionProtocol.CodecData<?>> ATTRIBUTE_CLIENTBOUND_PROTOCOL = AttributeKey.valueOf("clientbound_protocol");
|
||||
public static final Supplier<NioEventLoopGroup> NETWORK_WORKER_GROUP = Suppliers.memoize(() -> {
|
||||
- return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Client IO #%d").setDaemon(true).build());
|
||||
+ return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Client IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper
|
||||
});
|
||||
public static final Supplier<EpollEventLoopGroup> NETWORK_EPOLL_WORKER_GROUP = Suppliers.memoize(() -> {
|
||||
- return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Client IO #%d").setDaemon(true).build());
|
||||
+ return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Client IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper
|
||||
});
|
||||
public static final Supplier<DefaultEventLoopGroup> LOCAL_WORKER_GROUP = Suppliers.memoize(() -> {
|
||||
- return new DefaultEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Local Client IO #%d").setDaemon(true).build());
|
||||
+ return new DefaultEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Local Client IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper
|
||||
});
|
||||
private final PacketFlow receiving;
|
||||
private final Queue<Consumer<Connection>> pendingActions = Queues.newConcurrentLinkedQueue();
|
||||
@@ -195,7 +195,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
|
||||
}
|
||||
}
|
||||
- if (net.minecraft.server.MinecraftServer.getServer().isDebugging()) throwable.printStackTrace(); // Spigot
|
||||
+ if (net.minecraft.server.MinecraftServer.getServer().isDebugging()) io.papermc.paper.util.TraceUtil.printStackTrace(throwable); // Spigot // Paper
|
||||
}
|
||||
|
||||
protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet<?> packet) {
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index f72c1a4baff6ac9a3b1df83ece3925e2b1678df9..967817ad15146407668361a85c89be6beb6a73f9 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -195,6 +195,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
org.spigotmc.SpigotConfig.registerCommands();
|
||||
// Spigot end
|
||||
// Paper start
|
||||
+ io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // Paper - load mappings for stacktrace deobf and etc.
|
||||
paperConfigurations.initializeGlobalConfiguration();
|
||||
paperConfigurations.initializeWorldDefaultsConfiguration();
|
||||
org.spigotmc.WatchdogThread.doStart(org.spigotmc.SpigotConfig.timeoutTime, org.spigotmc.SpigotConfig.restartOnCrash);
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 4307b72acc389ccab97b2b7f3f824ddeca5a3cda..6bb7f2050e93f63045ea608672751da28138d3f8 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -221,7 +221,9 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
public final UUID uuid;
|
||||
public boolean hasPhysicsEvent = true; // Paper
|
||||
public static Throwable getAddToWorldStackTrace(Entity entity) {
|
||||
- return new Throwable(entity + " Added to world at " + new java.util.Date());
|
||||
+ final Throwable thr = new Throwable(entity + " Added to world at " + new java.util.Date());
|
||||
+ io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(thr);
|
||||
+ return thr;
|
||||
}
|
||||
|
||||
@Override public LevelChunk getChunkIfLoaded(int x, int z) { // Paper - this was added in world too but keeping here for NMS ABI
|
||||
@@ -1235,7 +1237,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
if (entity.isRemoved()) {
|
||||
// Paper start
|
||||
if (DEBUG_ENTITIES) {
|
||||
- new Throwable("Tried to add entity " + entity + " but it was marked as removed already").printStackTrace(); // CraftBukkit
|
||||
+ io.papermc.paper.util.TraceUtil.dumpTraceForThread("Tried to add entity " + entity + " but it was marked as removed already"); // CraftBukkit
|
||||
getAddToWorldStackTrace(entity).printStackTrace();
|
||||
}
|
||||
// Paper end
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
index 496ac1d2fd43c5ddfe7fa7a8b72a75860ec43443..6c2a5b2cb57fe799cc1c5002662894ad6e2b22aa 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
@@ -132,7 +132,7 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis
|
||||
ServerConfigurationPacketListenerImpl.LOGGER.error("Couldn't place player in world", exception);
|
||||
// Paper start
|
||||
if (MinecraftServer.getServer().isDebugging()) {
|
||||
- exception.printStackTrace();
|
||||
+ io.papermc.paper.util.TraceUtil.printStackTrace(exception);
|
||||
}
|
||||
// Paper end
|
||||
this.connection.send(new ClientboundDisconnectPacket(ServerConfigurationPacketListenerImpl.DISCONNECT_REASON_INVALID_DATA));
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
index d870fbec236a3660f12e0f45cf9431067b18468b..c98d3c5afcce17a6f13f8d456b9f77b1f2a4f3f0 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
@@ -52,10 +52,10 @@ public class ServerConnectionListener {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public static final Supplier<NioEventLoopGroup> SERVER_EVENT_GROUP = Suppliers.memoize(() -> {
|
||||
- return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Server IO #%d").setDaemon(true).build());
|
||||
+ return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Server IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper
|
||||
});
|
||||
public static final Supplier<EpollEventLoopGroup> SERVER_EPOLL_EVENT_GROUP = Suppliers.memoize(() -> {
|
||||
- return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Server IO #%d").setDaemon(true).build());
|
||||
+ return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Server IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper
|
||||
});
|
||||
final MinecraftServer server;
|
||||
public volatile boolean running;
|
||||
diff --git a/src/main/java/net/minecraft/server/players/OldUsersConverter.java b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
index 5db27d7bcaaa2eeaeeb08401513d8d23f6cb63c7..ce43cb0152ba07c6c21e08142d65813d47c3b63b 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
@@ -359,7 +359,7 @@ public class OldUsersConverter {
|
||||
try {
|
||||
root = NbtIo.readCompressed(new java.io.FileInputStream(file5));
|
||||
} catch (Exception exception) {
|
||||
- exception.printStackTrace();
|
||||
+ io.papermc.paper.util.TraceUtil.printStackTrace(exception); // Paper
|
||||
ServerInternalException.reportInternalException(exception); // Paper
|
||||
}
|
||||
|
||||
@@ -373,7 +373,7 @@ public class OldUsersConverter {
|
||||
try {
|
||||
NbtIo.writeCompressed(root, new java.io.FileOutputStream(file2));
|
||||
} catch (Exception exception) {
|
||||
- exception.printStackTrace();
|
||||
+ io.papermc.paper.util.TraceUtil.printStackTrace(exception); // Paper
|
||||
ServerInternalException.reportInternalException(exception); // 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 c9a6a56dfd25601bc0a11e5ddb349dba372c0e18..9cb4c145a36de0fe5be148b854ebb6f2a8446f49 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -603,7 +603,7 @@ public class LevelChunk extends ChunkAccess {
|
||||
+ " (" + getBlockState(blockposition) + ") where there was no entity tile!\n" +
|
||||
"Chunk coordinates: " + (this.chunkPos.x * 16) + "," + (this.chunkPos.z * 16) +
|
||||
"\nWorld: " + level.getLevel().dimension().location());
|
||||
- e.printStackTrace();
|
||||
+ io.papermc.paper.util.TraceUtil.printStackTrace(e);
|
||||
ServerInternalException.reportInternalException(e);
|
||||
// Paper end
|
||||
// CraftBukkit end
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java
|
||||
index 3c1992e212a6d6f1db4d5b807b38d71913619fc0..9c1aff17aabd062640e3f451a2ef8c50a7c62f10 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java
|
||||
@@ -40,9 +40,9 @@ public class CraftAsyncScheduler extends CraftScheduler {
|
||||
|
||||
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
|
||||
4, Integer.MAX_VALUE,30L, TimeUnit.SECONDS, new SynchronousQueue<>(),
|
||||
- new ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %1$d").build());
|
||||
+ new ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %1$d").setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(net.minecraft.server.MinecraftServer.LOGGER)).build()); // Paper
|
||||
private final Executor management = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder()
|
||||
- .setNameFormat("Craft Async Scheduler Management Thread").build());
|
||||
+ .setNameFormat("Craft Async Scheduler Management Thread").setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(net.minecraft.server.MinecraftServer.LOGGER)).build()); // Paper
|
||||
private final List<CraftTask> temp = new ArrayList<>();
|
||||
|
||||
CraftAsyncScheduler() {
|
||||
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
index e71041d41eae31cce73d8817c4f95f16c8c600aa..71dbda5ae954b31ca3915de8823b552a09dfcab8 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -105,7 +105,7 @@ public class WatchdogThread extends Thread
|
||||
log.log( Level.SEVERE, "During the run of the server, a plugin set an excessive velocity on an entity" );
|
||||
log.log( Level.SEVERE, "This may be the cause of the issue, or it may be entirely unrelated" );
|
||||
log.log( Level.SEVERE, org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getMessage());
|
||||
- for ( StackTraceElement stack : org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getStackTrace() )
|
||||
+ for ( StackTraceElement stack : io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getStackTrace()) ) // Paper
|
||||
{
|
||||
log.log( Level.SEVERE, "\t\t" + stack );
|
||||
}
|
||||
@@ -191,7 +191,7 @@ public class WatchdogThread extends Thread
|
||||
}
|
||||
log.log( Level.SEVERE, "\tStack:" );
|
||||
//
|
||||
- for ( StackTraceElement stack : thread.getStackTrace() )
|
||||
+ for ( StackTraceElement stack : io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(thread.getStackTrace()) ) // Paper
|
||||
{
|
||||
log.log( Level.SEVERE, "\t\t" + stack );
|
||||
}
|
||||
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
|
||||
index 266b4e6fb3988b5848021c83fdc68e342c70b188..2b247d55e39246fbef31279b14c45fc40f956bfb 100644
|
||||
--- a/src/main/resources/log4j2.xml
|
||||
+++ b/src/main/resources/log4j2.xml
|
||||
@@ -30,10 +30,14 @@
|
||||
<DefaultRolloverStrategy max="1000"/>
|
||||
</RollingRandomAccessFile>
|
||||
<Async name="Async">
|
||||
+ <AppenderRef ref="rewrite"/>
|
||||
+ </Async>
|
||||
+ <Rewrite name="rewrite">
|
||||
+ <StacktraceDeobfuscatingRewritePolicy />
|
||||
<AppenderRef ref="File"/>
|
||||
<AppenderRef ref="TerminalConsole" level="info"/>
|
||||
<AppenderRef ref="ServerGuiConsole" level="info"/>
|
||||
- </Async>
|
||||
+ </Rewrite>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Root level="info">
|
918
patches/server/0389-Implement-Mob-Goal-API.patch
Normal file
918
patches/server/0389-Implement-Mob-Goal-API.patch
Normal file
|
@ -0,0 +1,918 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MiniDigger <admin@benndorf.dev>
|
||||
Date: Fri, 3 Jan 2020 16:26:19 +0100
|
||||
Subject: [PATCH] Implement Mob Goal API
|
||||
|
||||
|
||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||
index dfb43cf7be60733f3ab142de66139971bca1b1fe..b81b99a7767e3b0d3549e49529e98efdb7334101 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -46,6 +46,7 @@ dependencies {
|
||||
runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.7.3")
|
||||
runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.7.3")
|
||||
|
||||
+ testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
testImplementation("org.hamcrest:hamcrest-library:1.3")
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..f80a6ad7638453348ee82ea00b166a3aac029142
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java
|
||||
@@ -0,0 +1,374 @@
|
||||
+package com.destroystokyo.paper.entity.ai;
|
||||
+
|
||||
+import com.destroystokyo.paper.entity.RangedEntity;
|
||||
+import com.destroystokyo.paper.util.set.OptimizedSmallEnumSet;
|
||||
+import com.google.common.collect.BiMap;
|
||||
+import com.google.common.collect.HashBiMap;
|
||||
+import io.papermc.paper.util.ObfHelper;
|
||||
+import java.lang.reflect.Constructor;
|
||||
+import java.util.EnumSet;
|
||||
+import java.util.HashMap;
|
||||
+import java.util.HashSet;
|
||||
+import java.util.Map;
|
||||
+import java.util.Set;
|
||||
+import net.minecraft.world.entity.FlyingMob;
|
||||
+import net.minecraft.world.entity.PathfinderMob;
|
||||
+import net.minecraft.world.entity.TamableAnimal;
|
||||
+import net.minecraft.world.entity.ai.goal.Goal;
|
||||
+import net.minecraft.world.entity.ambient.AmbientCreature;
|
||||
+import net.minecraft.world.entity.animal.AbstractFish;
|
||||
+import net.minecraft.world.entity.animal.AbstractGolem;
|
||||
+import net.minecraft.world.entity.animal.AbstractSchoolingFish;
|
||||
+import net.minecraft.world.entity.animal.Animal;
|
||||
+import net.minecraft.world.entity.animal.Pufferfish;
|
||||
+import net.minecraft.world.entity.animal.ShoulderRidingEntity;
|
||||
+import net.minecraft.world.entity.animal.SnowGolem;
|
||||
+import net.minecraft.world.entity.animal.WaterAnimal;
|
||||
+import net.minecraft.world.entity.animal.camel.Camel;
|
||||
+import net.minecraft.world.entity.animal.horse.AbstractChestedHorse;
|
||||
+import net.minecraft.world.entity.boss.wither.WitherBoss;
|
||||
+import net.minecraft.world.entity.monster.AbstractIllager;
|
||||
+import net.minecraft.world.entity.monster.EnderMan;
|
||||
+import net.minecraft.world.entity.monster.PatrollingMonster;
|
||||
+import net.minecraft.world.entity.monster.RangedAttackMob;
|
||||
+import net.minecraft.world.entity.monster.SpellcasterIllager;
|
||||
+import net.minecraft.world.entity.monster.ZombifiedPiglin;
|
||||
+import net.minecraft.world.entity.monster.piglin.AbstractPiglin;
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.entity.AbstractHorse;
|
||||
+import org.bukkit.entity.AbstractSkeleton;
|
||||
+import org.bukkit.entity.AbstractVillager;
|
||||
+import org.bukkit.entity.Ageable;
|
||||
+import org.bukkit.entity.Ambient;
|
||||
+import org.bukkit.entity.Animals;
|
||||
+import org.bukkit.entity.Bat;
|
||||
+import org.bukkit.entity.Bee;
|
||||
+import org.bukkit.entity.Blaze;
|
||||
+import org.bukkit.entity.Cat;
|
||||
+import org.bukkit.entity.CaveSpider;
|
||||
+import org.bukkit.entity.ChestedHorse;
|
||||
+import org.bukkit.entity.Chicken;
|
||||
+import org.bukkit.entity.Cod;
|
||||
+import org.bukkit.entity.Cow;
|
||||
+import org.bukkit.entity.Creature;
|
||||
+import org.bukkit.entity.Creeper;
|
||||
+import org.bukkit.entity.Dolphin;
|
||||
+import org.bukkit.entity.Donkey;
|
||||
+import org.bukkit.entity.Drowned;
|
||||
+import org.bukkit.entity.ElderGuardian;
|
||||
+import org.bukkit.entity.EnderDragon;
|
||||
+import org.bukkit.entity.Enderman;
|
||||
+import org.bukkit.entity.Endermite;
|
||||
+import org.bukkit.entity.Evoker;
|
||||
+import org.bukkit.entity.Fish;
|
||||
+import org.bukkit.entity.Flying;
|
||||
+import org.bukkit.entity.Fox;
|
||||
+import org.bukkit.entity.Ghast;
|
||||
+import org.bukkit.entity.Giant;
|
||||
+import org.bukkit.entity.Golem;
|
||||
+import org.bukkit.entity.Guardian;
|
||||
+import org.bukkit.entity.Hoglin;
|
||||
+import org.bukkit.entity.Horse;
|
||||
+import org.bukkit.entity.Husk;
|
||||
+import org.bukkit.entity.Illager;
|
||||
+import org.bukkit.entity.Illusioner;
|
||||
+import org.bukkit.entity.IronGolem;
|
||||
+import org.bukkit.entity.Llama;
|
||||
+import org.bukkit.entity.MagmaCube;
|
||||
+import org.bukkit.entity.Mob;
|
||||
+import org.bukkit.entity.Monster;
|
||||
+import org.bukkit.entity.Mule;
|
||||
+import org.bukkit.entity.MushroomCow;
|
||||
+import org.bukkit.entity.Ocelot;
|
||||
+import org.bukkit.entity.Panda;
|
||||
+import org.bukkit.entity.Parrot;
|
||||
+import org.bukkit.entity.Phantom;
|
||||
+import org.bukkit.entity.Pig;
|
||||
+import org.bukkit.entity.PigZombie;
|
||||
+import org.bukkit.entity.Piglin;
|
||||
+import org.bukkit.entity.PiglinAbstract;
|
||||
+import org.bukkit.entity.PiglinBrute;
|
||||
+import org.bukkit.entity.Pillager;
|
||||
+import org.bukkit.entity.PolarBear;
|
||||
+import org.bukkit.entity.PufferFish;
|
||||
+import org.bukkit.entity.Rabbit;
|
||||
+import org.bukkit.entity.Raider;
|
||||
+import org.bukkit.entity.Ravager;
|
||||
+import org.bukkit.entity.Salmon;
|
||||
+import org.bukkit.entity.Sheep;
|
||||
+import org.bukkit.entity.Shulker;
|
||||
+import org.bukkit.entity.Silverfish;
|
||||
+import org.bukkit.entity.Skeleton;
|
||||
+import org.bukkit.entity.SkeletonHorse;
|
||||
+import org.bukkit.entity.Slime;
|
||||
+import org.bukkit.entity.Snowman;
|
||||
+import org.bukkit.entity.Spellcaster;
|
||||
+import org.bukkit.entity.Spider;
|
||||
+import org.bukkit.entity.Squid;
|
||||
+import org.bukkit.entity.Stray;
|
||||
+import org.bukkit.entity.Strider;
|
||||
+import org.bukkit.entity.Tameable;
|
||||
+import org.bukkit.entity.TraderLlama;
|
||||
+import org.bukkit.entity.TropicalFish;
|
||||
+import org.bukkit.entity.Turtle;
|
||||
+import org.bukkit.entity.Vex;
|
||||
+import org.bukkit.entity.Villager;
|
||||
+import org.bukkit.entity.Vindicator;
|
||||
+import org.bukkit.entity.WanderingTrader;
|
||||
+import org.bukkit.entity.WaterMob;
|
||||
+import org.bukkit.entity.Witch;
|
||||
+import org.bukkit.entity.Wither;
|
||||
+import org.bukkit.entity.WitherSkeleton;
|
||||
+import org.bukkit.entity.Wolf;
|
||||
+import org.bukkit.entity.Zoglin;
|
||||
+import org.bukkit.entity.Zombie;
|
||||
+import org.bukkit.entity.ZombieHorse;
|
||||
+import org.bukkit.entity.ZombieVillager;
|
||||
+
|
||||
+public class MobGoalHelper {
|
||||
+
|
||||
+ private static final BiMap<String, String> deobfuscationMap = HashBiMap.create();
|
||||
+ private static final Map<Class<? extends Goal>, Class<? extends Mob>> entityClassCache = new HashMap<>();
|
||||
+ private static final Map<Class<? extends net.minecraft.world.entity.Mob>, Class<? extends Mob>> bukkitMap = new HashMap<>();
|
||||
+
|
||||
+ static final Set<String> ignored = new HashSet<>();
|
||||
+
|
||||
+ static {
|
||||
+ // TODO these kinda should be checked on each release, in case obfuscation changes
|
||||
+ deobfuscationMap.put("abstract_skeleton_1", "abstract_skeleton_melee");
|
||||
+
|
||||
+ ignored.add("goal_selector_1");
|
||||
+ ignored.add("goal_selector_2");
|
||||
+ ignored.add("selector_1");
|
||||
+ ignored.add("selector_2");
|
||||
+ ignored.add("wrapped");
|
||||
+
|
||||
+ bukkitMap.put(net.minecraft.world.entity.Mob.class, Mob.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.AgeableMob.class, Ageable.class);
|
||||
+ bukkitMap.put(AmbientCreature.class, Ambient.class);
|
||||
+ bukkitMap.put(Animal.class, Animals.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.ambient.Bat.class, Bat.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Bee.class, Bee.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Blaze.class, Blaze.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Cat.class, Cat.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.CaveSpider.class, CaveSpider.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Chicken.class, Chicken.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Cod.class, Cod.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Cow.class, Cow.class);
|
||||
+ bukkitMap.put(PathfinderMob.class, Creature.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Creeper.class, Creeper.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Dolphin.class, Dolphin.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Drowned.class, Drowned.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.boss.enderdragon.EnderDragon.class, EnderDragon.class);
|
||||
+ bukkitMap.put(EnderMan.class, Enderman.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Endermite.class, Endermite.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Evoker.class, Evoker.class);
|
||||
+ bukkitMap.put(AbstractFish.class, Fish.class);
|
||||
+ bukkitMap.put(AbstractSchoolingFish.class, Fish.class); // close enough
|
||||
+ bukkitMap.put(FlyingMob.class, Flying.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Fox.class, Fox.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Ghast.class, Ghast.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Giant.class, Giant.class);
|
||||
+ bukkitMap.put(AbstractGolem.class, Golem.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Guardian.class, Guardian.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.ElderGuardian.class, ElderGuardian.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.horse.Horse.class, Horse.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.horse.AbstractHorse.class, AbstractHorse.class);
|
||||
+ bukkitMap.put(AbstractChestedHorse.class, ChestedHorse.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.horse.Donkey.class, Donkey.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.horse.Mule.class, Mule.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.horse.SkeletonHorse.class, SkeletonHorse.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.horse.ZombieHorse.class, ZombieHorse.class);
|
||||
+ bukkitMap.put(Camel.class, org.bukkit.entity.Camel.class);
|
||||
+ bukkitMap.put(AbstractIllager.class, Illager.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Illusioner.class, Illusioner.class);
|
||||
+ bukkitMap.put(SpellcasterIllager.class, Spellcaster.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.IronGolem.class, IronGolem.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.horse.Llama.class, Llama.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.horse.TraderLlama.class, TraderLlama.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.MagmaCube.class, MagmaCube.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Monster.class, Monster.class);
|
||||
+ bukkitMap.put(PatrollingMonster.class, Raider.class); // close enough
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.MushroomCow.class, MushroomCow.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Ocelot.class, Ocelot.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Panda.class, Panda.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Parrot.class, Parrot.class);
|
||||
+ bukkitMap.put(ShoulderRidingEntity.class, Parrot.class); // close enough
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Phantom.class, Phantom.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Pig.class, Pig.class);
|
||||
+ bukkitMap.put(ZombifiedPiglin.class, PigZombie.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Pillager.class, Pillager.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.PolarBear.class, PolarBear.class);
|
||||
+ bukkitMap.put(Pufferfish.class, PufferFish.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Rabbit.class, Rabbit.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.raid.Raider.class, Raider.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Ravager.class, Ravager.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Salmon.class, Salmon.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Sheep.class, Sheep.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Shulker.class, Shulker.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Silverfish.class, Silverfish.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Skeleton.class, Skeleton.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.AbstractSkeleton.class, AbstractSkeleton.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Stray.class, Stray.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.WitherSkeleton.class, WitherSkeleton.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Slime.class, Slime.class);
|
||||
+ bukkitMap.put(SnowGolem.class, Snowman.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Spider.class, Spider.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Squid.class, Squid.class);
|
||||
+ bukkitMap.put(TamableAnimal.class, Tameable.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.TropicalFish.class, TropicalFish.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Turtle.class, Turtle.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Vex.class, Vex.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.npc.Villager.class, Villager.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.npc.AbstractVillager.class, AbstractVillager.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.npc.WanderingTrader.class, WanderingTrader.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Vindicator.class, Vindicator.class);
|
||||
+ bukkitMap.put(WaterAnimal.class, WaterMob.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Witch.class, Witch.class);
|
||||
+ bukkitMap.put(WitherBoss.class, Wither.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.Wolf.class, Wolf.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Zombie.class, Zombie.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Husk.class, Husk.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.ZombieVillager.class, ZombieVillager.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.hoglin.Hoglin.class, Hoglin.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.piglin.Piglin.class, Piglin.class);
|
||||
+ bukkitMap.put(AbstractPiglin.class, PiglinAbstract.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.piglin.PiglinBrute.class, PiglinBrute.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Strider.class, Strider.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.Zoglin.class, Zoglin.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.GlowSquid.class, org.bukkit.entity.GlowSquid.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.axolotl.Axolotl.class, org.bukkit.entity.Axolotl.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.goat.Goat.class, org.bukkit.entity.Goat.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.frog.Frog.class, org.bukkit.entity.Frog.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.frog.Tadpole.class, org.bukkit.entity.Tadpole.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.monster.warden.Warden.class, org.bukkit.entity.Warden.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.allay.Allay.class, org.bukkit.entity.Allay.class);
|
||||
+ bukkitMap.put(net.minecraft.world.entity.animal.sniffer.Sniffer.class, org.bukkit.entity.Sniffer.class);
|
||||
+ }
|
||||
+
|
||||
+ public static String getUsableName(Class<?> clazz) {
|
||||
+ String name = ObfHelper.INSTANCE.deobfClassName(clazz.getName());
|
||||
+ name = name.substring(name.lastIndexOf(".") + 1);
|
||||
+ boolean flag = false;
|
||||
+ // inner classes
|
||||
+ if (name.contains("$")) {
|
||||
+ String cut = name.substring(name.indexOf("$") + 1);
|
||||
+ if (cut.length() <= 2) {
|
||||
+ name = name.replace("Entity", "");
|
||||
+ name = name.replace("$", "_");
|
||||
+ flag = true;
|
||||
+ } else {
|
||||
+ // mapped, wooo
|
||||
+ name = cut;
|
||||
+ }
|
||||
+ }
|
||||
+ name = name.replace("PathfinderGoal", "");
|
||||
+ name = name.replace("TargetGoal", "");
|
||||
+ name = name.replace("Goal", "");
|
||||
+ StringBuilder sb = new StringBuilder();
|
||||
+ for (char c : name.toCharArray()) {
|
||||
+ if (c >= 'A' && c <= 'Z') {
|
||||
+ sb.append("_");
|
||||
+ sb.append(Character.toLowerCase(c));
|
||||
+ } else {
|
||||
+ sb.append(c);
|
||||
+ }
|
||||
+ }
|
||||
+ name = sb.toString();
|
||||
+ name = name.replaceFirst("_", "");
|
||||
+
|
||||
+ if (flag && !deobfuscationMap.containsKey(name.toLowerCase()) && !ignored.contains(name)) {
|
||||
+ System.out.println("need to map " + clazz.getName() + " (" + name.toLowerCase() + ")");
|
||||
+ }
|
||||
+
|
||||
+ // did we rename this key?
|
||||
+ return deobfuscationMap.getOrDefault(name, name);
|
||||
+ }
|
||||
+
|
||||
+ public static EnumSet<GoalType> vanillaToPaper(OptimizedSmallEnumSet<Goal.Flag> types) {
|
||||
+ EnumSet<GoalType> goals = EnumSet.noneOf(GoalType.class);
|
||||
+ for (GoalType type : GoalType.values()) {
|
||||
+ if (types.hasElement(paperToVanilla(type))) {
|
||||
+ goals.add(type);
|
||||
+ }
|
||||
+ }
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ public static GoalType vanillaToPaper(Goal.Flag type) {
|
||||
+ switch (type) {
|
||||
+ case MOVE:
|
||||
+ return GoalType.MOVE;
|
||||
+ case LOOK:
|
||||
+ return GoalType.LOOK;
|
||||
+ case JUMP:
|
||||
+ return GoalType.JUMP;
|
||||
+ case UNKNOWN_BEHAVIOR:
|
||||
+ return GoalType.UNKNOWN_BEHAVIOR;
|
||||
+ case TARGET:
|
||||
+ return GoalType.TARGET;
|
||||
+ default:
|
||||
+ throw new IllegalArgumentException("Unknown vanilla mob goal type " + type.name());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static EnumSet<Goal.Flag> paperToVanilla(EnumSet<GoalType> types) {
|
||||
+ EnumSet<Goal.Flag> goals = EnumSet.noneOf(Goal.Flag.class);
|
||||
+ for (GoalType type : types) {
|
||||
+ goals.add(paperToVanilla(type));
|
||||
+ }
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ public static Goal.Flag paperToVanilla(GoalType type) {
|
||||
+ switch (type) {
|
||||
+ case MOVE:
|
||||
+ return Goal.Flag.MOVE;
|
||||
+ case LOOK:
|
||||
+ return Goal.Flag.LOOK;
|
||||
+ case JUMP:
|
||||
+ return Goal.Flag.JUMP;
|
||||
+ case UNKNOWN_BEHAVIOR:
|
||||
+ return Goal.Flag.UNKNOWN_BEHAVIOR;
|
||||
+ case TARGET:
|
||||
+ return Goal.Flag.TARGET;
|
||||
+ default:
|
||||
+ throw new IllegalArgumentException("Unknown paper mob goal type " + type.name());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static <T extends Mob> GoalKey<T> getKey(Class<? extends Goal> goalClass) {
|
||||
+ String name = getUsableName(goalClass);
|
||||
+ if (ignored.contains(name)) {
|
||||
+ //noinspection unchecked
|
||||
+ return (GoalKey<T>) GoalKey.of(Mob.class, NamespacedKey.minecraft(name));
|
||||
+ }
|
||||
+ return GoalKey.of(getEntity(goalClass), NamespacedKey.minecraft(name));
|
||||
+ }
|
||||
+
|
||||
+ public static <T extends Mob> Class<T> getEntity(Class<? extends Goal> goalClass) {
|
||||
+ //noinspection unchecked
|
||||
+ return (Class<T>) entityClassCache.computeIfAbsent(goalClass, key -> {
|
||||
+ for (Constructor<?> ctor : key.getDeclaredConstructors()) {
|
||||
+ for (int i = 0; i < ctor.getParameterCount(); i++) {
|
||||
+ Class<?> param = ctor.getParameterTypes()[i];
|
||||
+ if (net.minecraft.world.entity.Mob.class.isAssignableFrom(param)) {
|
||||
+ //noinspection unchecked
|
||||
+ return toBukkitClass((Class<? extends net.minecraft.world.entity.Mob>) param);
|
||||
+ } else if (RangedAttackMob.class.isAssignableFrom(param)) {
|
||||
+ return RangedEntity.class;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ throw new RuntimeException("Can't figure out applicable entity for mob goal " + goalClass); // maybe just return EntityInsentient?
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ public static Class<? extends Mob> toBukkitClass(Class<? extends net.minecraft.world.entity.Mob> nmsClass) {
|
||||
+ Class<? extends Mob> bukkitClass = bukkitMap.get(nmsClass);
|
||||
+ if (bukkitClass == null) {
|
||||
+ throw new RuntimeException("Can't figure out applicable bukkit entity for nms entity " + nmsClass); // maybe just return Mob?
|
||||
+ }
|
||||
+ return bukkitClass;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/PaperCustomGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/PaperCustomGoal.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..26c745dd9ccdfdd5c5039f2acc5201b9b91fb274
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/PaperCustomGoal.java
|
||||
@@ -0,0 +1,53 @@
|
||||
+package com.destroystokyo.paper.entity.ai;
|
||||
+
|
||||
+import org.bukkit.entity.Mob;
|
||||
+
|
||||
+/**
|
||||
+ * Wraps api in vanilla
|
||||
+ */
|
||||
+public class PaperCustomGoal<T extends Mob> extends net.minecraft.world.entity.ai.goal.Goal {
|
||||
+
|
||||
+ private final Goal<T> handle;
|
||||
+
|
||||
+ public PaperCustomGoal(Goal<T> handle) {
|
||||
+ this.handle = handle;
|
||||
+
|
||||
+ this.setFlags(MobGoalHelper.paperToVanilla(handle.getTypes()));
|
||||
+ if (this.getFlags().size() == 0) {
|
||||
+ this.getFlags().addUnchecked(Flag.UNKNOWN_BEHAVIOR);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean canUse() {
|
||||
+ return handle.shouldActivate();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean canContinueToUse() {
|
||||
+ return handle.shouldStayActive();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void start() {
|
||||
+ handle.start();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void stop() {
|
||||
+ handle.stop();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void tick() {
|
||||
+ handle.tick();
|
||||
+ }
|
||||
+
|
||||
+ public Goal<T> getHandle() {
|
||||
+ return handle;
|
||||
+ }
|
||||
+
|
||||
+ public GoalKey<T> getKey() {
|
||||
+ return handle.getKey();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/PaperMobGoals.java b/src/main/java/com/destroystokyo/paper/entity/ai/PaperMobGoals.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..5e7b4a8698a00f72d6e817cc7c6716e7605a3484
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/PaperMobGoals.java
|
||||
@@ -0,0 +1,213 @@
|
||||
+package com.destroystokyo.paper.entity.ai;
|
||||
+
|
||||
+import java.util.Collection;
|
||||
+import java.util.EnumSet;
|
||||
+import java.util.HashSet;
|
||||
+import java.util.LinkedList;
|
||||
+import java.util.List;
|
||||
+import java.util.Set;
|
||||
+import net.minecraft.world.entity.ai.goal.GoalSelector;
|
||||
+import net.minecraft.world.entity.ai.goal.WrappedGoal;
|
||||
+import org.bukkit.craftbukkit.entity.CraftMob;
|
||||
+import org.bukkit.entity.Mob;
|
||||
+
|
||||
+public class PaperMobGoals implements MobGoals {
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> void addGoal(T mob, int priority, Goal<T> goal) {
|
||||
+ CraftMob craftMob = (CraftMob) mob;
|
||||
+ getHandle(craftMob, goal.getTypes()).addGoal(priority, new PaperCustomGoal<>(goal));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> void removeGoal(T mob, Goal<T> goal) {
|
||||
+ CraftMob craftMob = (CraftMob) mob;
|
||||
+ if (goal instanceof PaperCustomGoal) {
|
||||
+ getHandle(craftMob, goal.getTypes()).removeGoal((net.minecraft.world.entity.ai.goal.Goal) goal);
|
||||
+ } else if (goal instanceof PaperVanillaGoal) {
|
||||
+ getHandle(craftMob, goal.getTypes()).removeGoal(((PaperVanillaGoal<?>) goal).getHandle());
|
||||
+ } else {
|
||||
+ List<net.minecraft.world.entity.ai.goal.Goal> toRemove = new LinkedList<>();
|
||||
+ for (WrappedGoal item : getHandle(craftMob, goal.getTypes()).getAvailableGoals()) {
|
||||
+ if (item.getGoal() instanceof PaperCustomGoal) {
|
||||
+ //noinspection unchecked
|
||||
+ if (((PaperCustomGoal<T>) item.getGoal()).getHandle() == goal) {
|
||||
+ toRemove.add(item.getGoal());
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (net.minecraft.world.entity.ai.goal.Goal g : toRemove) {
|
||||
+ getHandle(craftMob, goal.getTypes()).removeGoal(g);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> void removeAllGoals(T mob) {
|
||||
+ for (GoalType type : GoalType.values()) {
|
||||
+ removeAllGoals(mob, type);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> void removeAllGoals(T mob, GoalType type) {
|
||||
+ for (Goal<T> goal : getAllGoals(mob, type)) {
|
||||
+ removeGoal(mob, goal);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> void removeGoal(T mob, GoalKey<T> key) {
|
||||
+ for (Goal<T> goal : getGoals(mob, key)) {
|
||||
+ removeGoal(mob, goal);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> boolean hasGoal(T mob, GoalKey<T> key) {
|
||||
+ for (Goal<T> g : getAllGoals(mob)) {
|
||||
+ if (g.getKey().equals(key)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> Goal<T> getGoal(T mob, GoalKey<T> key) {
|
||||
+ for (Goal<T> g : getAllGoals(mob)) {
|
||||
+ if (g.getKey().equals(key)) {
|
||||
+ return g;
|
||||
+ }
|
||||
+ }
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> Collection<Goal<T>> getGoals(T mob, GoalKey<T> key) {
|
||||
+ Set<Goal<T>> goals = new HashSet<>();
|
||||
+ for (Goal<T> g : getAllGoals(mob)) {
|
||||
+ if (g.getKey().equals(key)) {
|
||||
+ goals.add(g);
|
||||
+ }
|
||||
+ }
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> Collection<Goal<T>> getAllGoals(T mob) {
|
||||
+ Set<Goal<T>> goals = new HashSet<>();
|
||||
+ for (GoalType type : GoalType.values()) {
|
||||
+ goals.addAll(getAllGoals(mob, type));
|
||||
+ }
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> Collection<Goal<T>> getAllGoals(T mob, GoalType type) {
|
||||
+ CraftMob craftMob = (CraftMob) mob;
|
||||
+ Set<Goal<T>> goals = new HashSet<>();
|
||||
+ for (WrappedGoal item : getHandle(craftMob, type).getAvailableGoals()) {
|
||||
+ if (!item.getGoal().getFlags().hasElement(MobGoalHelper.paperToVanilla(type))) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (item.getGoal() instanceof PaperCustomGoal) {
|
||||
+ //noinspection unchecked
|
||||
+ goals.add(((PaperCustomGoal<T>) item.getGoal()).getHandle());
|
||||
+ } else {
|
||||
+ goals.add(item.getGoal().asPaperVanillaGoal());
|
||||
+ }
|
||||
+ }
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> Collection<Goal<T>> getAllGoalsWithout(T mob, GoalType type) {
|
||||
+ CraftMob craftMob = (CraftMob) mob;
|
||||
+ Set<Goal<T>> goals = new HashSet<>();
|
||||
+ for (GoalType internalType : GoalType.values()) {
|
||||
+ if (internalType == type) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ for (WrappedGoal item : getHandle(craftMob, internalType).getAvailableGoals()) {
|
||||
+ if (item.getGoal().getFlags().hasElement(MobGoalHelper.paperToVanilla(type))) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (item.getGoal() instanceof PaperCustomGoal) {
|
||||
+ //noinspection unchecked
|
||||
+ goals.add(((PaperCustomGoal<T>) item.getGoal()).getHandle());
|
||||
+ } else {
|
||||
+ goals.add(item.getGoal().asPaperVanillaGoal());
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> Collection<Goal<T>> getRunningGoals(T mob) {
|
||||
+ Set<Goal<T>> goals = new HashSet<>();
|
||||
+ for (GoalType type : GoalType.values()) {
|
||||
+ goals.addAll(getRunningGoals(mob, type));
|
||||
+ }
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> Collection<Goal<T>> getRunningGoals(T mob, GoalType type) {
|
||||
+ CraftMob craftMob = (CraftMob) mob;
|
||||
+ Set<Goal<T>> goals = new HashSet<>();
|
||||
+ getHandle(craftMob, type).getRunningGoals()
|
||||
+ .filter(item -> item.getGoal().getFlags().hasElement(MobGoalHelper.paperToVanilla(type)))
|
||||
+ .forEach(item -> {
|
||||
+ if (item.getGoal() instanceof PaperCustomGoal) {
|
||||
+ //noinspection unchecked
|
||||
+ goals.add(((PaperCustomGoal<T>) item.getGoal()).getHandle());
|
||||
+ } else {
|
||||
+ goals.add(item.getGoal().asPaperVanillaGoal());
|
||||
+ }
|
||||
+ });
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Mob> Collection<Goal<T>> getRunningGoalsWithout(T mob, GoalType type) {
|
||||
+ CraftMob craftMob = (CraftMob) mob;
|
||||
+ Set<Goal<T>> goals = new HashSet<>();
|
||||
+ for (GoalType internalType : GoalType.values()) {
|
||||
+ if (internalType == type) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ getHandle(craftMob, internalType).getRunningGoals()
|
||||
+ .filter(item -> !item.getGoal().getFlags().hasElement(MobGoalHelper.paperToVanilla(type)))
|
||||
+ .forEach(item -> {
|
||||
+ if (item.getGoal() instanceof PaperCustomGoal) {
|
||||
+ //noinspection unchecked
|
||||
+ goals.add(((PaperCustomGoal<T>) item.getGoal()).getHandle());
|
||||
+ } else {
|
||||
+ goals.add(item.getGoal().asPaperVanillaGoal());
|
||||
+ }
|
||||
+ });
|
||||
+ }
|
||||
+ return goals;
|
||||
+ }
|
||||
+
|
||||
+ private GoalSelector getHandle(CraftMob mob, EnumSet<GoalType> types) {
|
||||
+ if (types.contains(GoalType.TARGET)) {
|
||||
+ return mob.getHandle().targetSelector;
|
||||
+ } else {
|
||||
+ return mob.getHandle().goalSelector;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private GoalSelector getHandle(CraftMob mob, GoalType type) {
|
||||
+ if (type == GoalType.TARGET) {
|
||||
+ return mob.getHandle().targetSelector;
|
||||
+ } else {
|
||||
+ return mob.getHandle().goalSelector;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/PaperVanillaGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/PaperVanillaGoal.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0d30e0b21b9024df939a9d070bd4a99b217e7c12
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/PaperVanillaGoal.java
|
||||
@@ -0,0 +1,61 @@
|
||||
+package com.destroystokyo.paper.entity.ai;
|
||||
+
|
||||
+import java.util.EnumSet;
|
||||
+import net.minecraft.world.entity.ai.goal.Goal;
|
||||
+import org.bukkit.entity.Mob;
|
||||
+
|
||||
+/**
|
||||
+ * Wraps vanilla in api
|
||||
+ */
|
||||
+public class PaperVanillaGoal<T extends Mob> implements VanillaGoal<T> {
|
||||
+
|
||||
+ private final Goal handle;
|
||||
+ private final GoalKey<T> key;
|
||||
+
|
||||
+ private final EnumSet<GoalType> types;
|
||||
+
|
||||
+ public PaperVanillaGoal(Goal handle) {
|
||||
+ this.handle = handle;
|
||||
+ this.key = MobGoalHelper.getKey(handle.getClass());
|
||||
+ this.types = MobGoalHelper.vanillaToPaper(handle.getFlags());
|
||||
+ }
|
||||
+
|
||||
+ public Goal getHandle() {
|
||||
+ return handle;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean shouldActivate() {
|
||||
+ return handle.canUse();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean shouldStayActive() {
|
||||
+ return handle.canContinueToUse();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void start() {
|
||||
+ handle.start();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void stop() {
|
||||
+ handle.stop();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void tick() {
|
||||
+ handle.tick();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public GoalKey<T> getKey() {
|
||||
+ return key;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public EnumSet<GoalType> getTypes() {
|
||||
+ return types;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
index 4379b9948f1eecfe6fd7dea98e298ad5f761019a..3f081183521603824430709886a9cc313c28e7cb 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
@@ -7,6 +7,14 @@ public abstract class Goal {
|
||||
private final EnumSet<Goal.Flag> flags = EnumSet.noneOf(Goal.Flag.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be.
|
||||
private final com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> goalTypes = new com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector
|
||||
|
||||
+ // Paper start make sure goaltypes is never empty
|
||||
+ public Goal() {
|
||||
+ if (this.goalTypes.size() == 0) {
|
||||
+ this.goalTypes.addUnchecked(Flag.UNKNOWN_BEHAVIOR);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public abstract boolean canUse();
|
||||
|
||||
public boolean canContinueToUse() {
|
||||
@@ -34,6 +42,10 @@ public abstract class Goal {
|
||||
// Paper start - remove streams from pathfindergoalselector
|
||||
this.goalTypes.clear();
|
||||
this.goalTypes.addAllUnchecked(controls);
|
||||
+ // make sure its never empty
|
||||
+ if (this.goalTypes.size() == 0) {
|
||||
+ this.goalTypes.addUnchecked(Flag.UNKNOWN_BEHAVIOR);
|
||||
+ }
|
||||
// Paper end - remove streams from pathfindergoalselector
|
||||
}
|
||||
|
||||
@@ -56,7 +68,19 @@ public abstract class Goal {
|
||||
return Mth.positiveCeilDiv(serverTicks, 2);
|
||||
}
|
||||
|
||||
+ // Paper start - mob goal api
|
||||
+ private com.destroystokyo.paper.entity.ai.PaperVanillaGoal<?> vanillaGoal = null;
|
||||
+ public <T extends org.bukkit.entity.Mob> com.destroystokyo.paper.entity.ai.Goal<T> asPaperVanillaGoal() {
|
||||
+ if(this.vanillaGoal == null) {
|
||||
+ this.vanillaGoal = new com.destroystokyo.paper.entity.ai.PaperVanillaGoal<>(this);
|
||||
+ }
|
||||
+ //noinspection unchecked
|
||||
+ return (com.destroystokyo.paper.entity.ai.Goal<T>) this.vanillaGoal;
|
||||
+ }
|
||||
+ // Paper end - mob goal api
|
||||
+
|
||||
public static enum Flag {
|
||||
+ UNKNOWN_BEHAVIOR, // Paper - add UNKNOWN_BEHAVIOR
|
||||
MOVE,
|
||||
LOOK,
|
||||
JUMP,
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 64663e74d85979f857d748f0c252c0568f5d95ae..5918b0296cf011f562e219984e6ad12a975318fb 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2777,5 +2777,11 @@ public final class CraftServer implements Server {
|
||||
public boolean isStopping() {
|
||||
return net.minecraft.server.MinecraftServer.getServer().hasStopped();
|
||||
}
|
||||
+
|
||||
+ private com.destroystokyo.paper.entity.ai.MobGoals mobGoals = new com.destroystokyo.paper.entity.ai.PaperMobGoals();
|
||||
+ @Override
|
||||
+ public com.destroystokyo.paper.entity.ai.MobGoals getMobGoals() {
|
||||
+ return mobGoals;
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
||||
diff --git a/src/test/java/com/destroystokyo/paper/entity/ai/VanillaMobGoalTest.java b/src/test/java/com/destroystokyo/paper/entity/ai/VanillaMobGoalTest.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b2d510459bcf90a3611f3d91dae4ccc3d29b4079
|
||||
--- /dev/null
|
||||
+++ b/src/test/java/com/destroystokyo/paper/entity/ai/VanillaMobGoalTest.java
|
||||
@@ -0,0 +1,103 @@
|
||||
+package com.destroystokyo.paper.entity.ai;
|
||||
+
|
||||
+import org.junit.Assert;
|
||||
+import org.junit.Test;
|
||||
+
|
||||
+import java.lang.reflect.Field;
|
||||
+import java.lang.reflect.Modifier;
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.Collections;
|
||||
+import java.util.List;
|
||||
+import java.util.stream.Collectors;
|
||||
+
|
||||
+import org.bukkit.entity.Mob;
|
||||
+
|
||||
+import io.github.classgraph.ClassGraph;
|
||||
+import io.github.classgraph.ScanResult;
|
||||
+
|
||||
+public class VanillaMobGoalTest {
|
||||
+
|
||||
+ @Test
|
||||
+ public void testKeys() {
|
||||
+ List<GoalKey<?>> deprecated = new ArrayList<>();
|
||||
+ List<GoalKey<?>> keys = new ArrayList<>();
|
||||
+ for (Field field : VanillaGoal.class.getFields()) {
|
||||
+ if (field.getType().equals(GoalKey.class)) {
|
||||
+ try {
|
||||
+ GoalKey<?> goalKey = (GoalKey<?>) field.get(null);
|
||||
+ if (field.getAnnotation(Deprecated.class) != null) {
|
||||
+ deprecated.add(goalKey);
|
||||
+ } else {
|
||||
+ keys.add(goalKey);
|
||||
+ }
|
||||
+ } catch (IllegalAccessException e) {
|
||||
+ System.out.println("Skipping " + field.getName() + ": " + e.getMessage());
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ List<Class<?>> classes;
|
||||
+ try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages("net.minecraft").scan()) {
|
||||
+ classes = scanResult.getSubclasses(net.minecraft.world.entity.ai.goal.Goal.class.getName()).loadClasses();
|
||||
+ }
|
||||
+
|
||||
+ List<GoalKey<?>> vanillaNames = classes.stream()
|
||||
+ .filter(VanillaMobGoalTest::hasNoEnclosingClass)
|
||||
+ .filter(clazz -> !Modifier.isAbstract(clazz.getModifiers()))
|
||||
+ .filter(clazz -> !net.minecraft.world.entity.ai.goal.WrappedGoal.class.equals(clazz)) // TODO - properly fix
|
||||
+ .map(goalClass -> MobGoalHelper.getKey((Class<? extends net.minecraft.world.entity.ai.goal.Goal>) goalClass))
|
||||
+ .collect(Collectors.toList());
|
||||
+
|
||||
+ List<GoalKey<?>> missingFromAPI = new ArrayList<>(vanillaNames);
|
||||
+ missingFromAPI.removeAll(keys);
|
||||
+ missingFromAPI.removeIf(k -> MobGoalHelper.ignored.contains(k.getNamespacedKey().getKey()));
|
||||
+ List<GoalKey<?>> missingFromVanilla = new ArrayList<>(keys);
|
||||
+ missingFromVanilla.removeAll(vanillaNames);
|
||||
+
|
||||
+ boolean shouldFail = false;
|
||||
+ if (missingFromAPI.size() != 0) {
|
||||
+ System.out.println("Missing from API: ");
|
||||
+ for (GoalKey<?> key : missingFromAPI) {
|
||||
+ System.out.println("GoalKey<" + key.getEntityClass().getSimpleName() + "> " + key.getNamespacedKey().getKey().toUpperCase() +
|
||||
+ " = GoalKey.of(" + key.getEntityClass().getSimpleName() + ".class, NamespacedKey.minecraft(\"" + key.getNamespacedKey().getKey() + "\"));");
|
||||
+ }
|
||||
+ shouldFail = true;
|
||||
+ }
|
||||
+ if (missingFromVanilla.size() != 0) {
|
||||
+ System.out.println("Missing from vanilla: ");
|
||||
+ missingFromVanilla.forEach(System.out::println);
|
||||
+ shouldFail = true;
|
||||
+ }
|
||||
+
|
||||
+ if (deprecated.size() != 0) {
|
||||
+ System.out.println("Deprecated (might want to remove them at some point): ");
|
||||
+ deprecated.forEach(System.out::println);
|
||||
+ }
|
||||
+
|
||||
+ if (shouldFail) Assert.fail("See above");
|
||||
+ }
|
||||
+
|
||||
+ private static boolean hasNoEnclosingClass(Class<?> clazz) {
|
||||
+ return clazz.getEnclosingClass() == null || hasNoEnclosingClass(clazz.getSuperclass());
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void testBukkitMap() {
|
||||
+ List<Class<?>> classes;
|
||||
+ try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages("net.minecraft.world.entity").scan()) {
|
||||
+ classes = scanResult.getSubclasses("net.minecraft.world.entity.Mob").loadClasses();
|
||||
+ }
|
||||
+ Assert.assertNotEquals("There are supposed to be more than 0 entity types!", Collections.emptyList(), classes);
|
||||
+
|
||||
+ boolean shouldFail = false;
|
||||
+ for (Class<?> nmsClass : classes) {
|
||||
+ Class<? extends Mob> bukkitClass = MobGoalHelper.toBukkitClass((Class<? extends net.minecraft.world.entity.Mob>) nmsClass);
|
||||
+ if (bukkitClass == null) {
|
||||
+ shouldFail = true;
|
||||
+ System.out.println("Missing bukkitMap.put(" + nmsClass.getSimpleName() + ".class, " + nmsClass.getSimpleName().replace("Entity", "") + ".class);");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (shouldFail) Assert.fail("See above");
|
||||
+ }
|
||||
+}
|
122
patches/server/0390-Add-villager-reputation-API.patch
Normal file
122
patches/server/0390-Add-villager-reputation-API.patch
Normal file
|
@ -0,0 +1,122 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mariell Hoversholm <proximyst@proximyst.com>
|
||||
Date: Wed, 22 Apr 2020 23:29:20 +0200
|
||||
Subject: [PATCH] Add villager reputation API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.ai.gossip.GossipContainer$EntityGossips
|
||||
public net.minecraft.world.entity.ai.gossip.GossipContainer$EntityGossips <init>()V
|
||||
public net.minecraft.world.entity.ai.gossip.GossipContainer gossips
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
index a28f359202e6502c6ea5e9c918ec0b3e9a3fca61..76dffb2705e5207db96895f82f1c7c5638f817c6 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
@@ -231,6 +231,43 @@ public class GossipContainer {
|
||||
public void remove(GossipType gossipType) {
|
||||
this.entries.removeInt(gossipType);
|
||||
}
|
||||
+
|
||||
+ // Paper start - Add villager reputation API
|
||||
+ private static final GossipType[] TYPES = GossipType.values();
|
||||
+ public com.destroystokyo.paper.entity.villager.Reputation getPaperReputation() {
|
||||
+ Map<com.destroystokyo.paper.entity.villager.ReputationType, Integer> map = new java.util.EnumMap<>(com.destroystokyo.paper.entity.villager.ReputationType.class);
|
||||
+ for (Object2IntMap.Entry<GossipType> type : this.entries.object2IntEntrySet()) {
|
||||
+ map.put(toApi(type.getKey()), type.getIntValue());
|
||||
+ }
|
||||
+
|
||||
+ return new com.destroystokyo.paper.entity.villager.Reputation(map);
|
||||
+ }
|
||||
+
|
||||
+ public void assignFromPaperReputation(com.destroystokyo.paper.entity.villager.Reputation rep) {
|
||||
+ for (GossipType type : TYPES) {
|
||||
+ com.destroystokyo.paper.entity.villager.ReputationType api = toApi(type);
|
||||
+
|
||||
+ if (rep.hasReputationSet(api)) {
|
||||
+ int reputation = rep.getReputation(api);
|
||||
+ if (reputation == 0) {
|
||||
+ this.entries.removeInt(type);
|
||||
+ } else {
|
||||
+ this.entries.put(type, reputation);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static com.destroystokyo.paper.entity.villager.ReputationType toApi(GossipType type) {
|
||||
+ return switch (type) {
|
||||
+ case MAJOR_NEGATIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MAJOR_NEGATIVE;
|
||||
+ case MINOR_NEGATIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MINOR_NEGATIVE;
|
||||
+ case MINOR_POSITIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MINOR_POSITIVE;
|
||||
+ case MAJOR_POSITIVE -> com.destroystokyo.paper.entity.villager.ReputationType.MAJOR_POSITIVE;
|
||||
+ case TRADING -> com.destroystokyo.paper.entity.villager.ReputationType.TRADING;
|
||||
+ };
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
static record GossipEntry(UUID target, GossipType type, int value) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
index 6160f2c2886569b4400080d11beca399ef002ea0..b27b9001b8eb74c713e6766f0919110432775a2e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
@@ -16,6 +16,13 @@ import org.bukkit.entity.Villager;
|
||||
import org.bukkit.entity.ZombieVillager;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
|
||||
+// Paper start
|
||||
+import com.destroystokyo.paper.entity.villager.Reputation;
|
||||
+import com.google.common.collect.Maps;
|
||||
+import java.util.Map;
|
||||
+import java.util.UUID;
|
||||
+// Paper end
|
||||
+
|
||||
public class CraftVillager extends CraftAbstractVillager implements Villager {
|
||||
|
||||
public CraftVillager(CraftServer server, net.minecraft.world.entity.npc.Villager entity) {
|
||||
@@ -140,4 +147,45 @@ public class CraftVillager extends CraftAbstractVillager implements Villager {
|
||||
public static VillagerProfession bukkitToNmsProfession(Profession bukkit) {
|
||||
return BuiltInRegistries.VILLAGER_PROFESSION.get(CraftNamespacedKey.toMinecraft(bukkit.getKey()));
|
||||
}
|
||||
+
|
||||
+ // Paper start - Add villager reputation API
|
||||
+ @Override
|
||||
+ public Reputation getReputation(UUID uniqueId) {
|
||||
+ net.minecraft.world.entity.ai.gossip.GossipContainer.EntityGossips rep = getHandle().getGossips().gossips.get(uniqueId);
|
||||
+ if (rep == null) {
|
||||
+ return new Reputation(new java.util.EnumMap<>(com.destroystokyo.paper.entity.villager.ReputationType.class));
|
||||
+ }
|
||||
+
|
||||
+ return rep.getPaperReputation();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Map<UUID, Reputation> getReputations() {
|
||||
+ return getHandle().getGossips().gossips.entrySet()
|
||||
+ .stream()
|
||||
+ .collect(java.util.stream.Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getPaperReputation()));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setReputation(UUID uniqueId, Reputation reputation) {
|
||||
+ net.minecraft.world.entity.ai.gossip.GossipContainer.EntityGossips nmsReputation =
|
||||
+ getHandle().getGossips().gossips.computeIfAbsent(
|
||||
+ uniqueId,
|
||||
+ key -> new net.minecraft.world.entity.ai.gossip.GossipContainer.EntityGossips()
|
||||
+ );
|
||||
+ nmsReputation.assignFromPaperReputation(reputation);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setReputations(Map<UUID, Reputation> reputations) {
|
||||
+ for (Map.Entry<UUID, Reputation> entry : reputations.entrySet()) {
|
||||
+ setReputation(entry.getKey(), entry.getValue());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void clearReputations() {
|
||||
+ getHandle().getGossips().gossips.clear();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Fri, 10 Nov 2017 23:03:12 -0500
|
||||
Subject: [PATCH] Option for maximum exp value when merging orbs
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index 0b45481cdbbfbe4e1756e19e696e1c11d8fccd00..b71024ebd675f4afd7ad2aa96393532758a28b63 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -688,16 +688,30 @@ public class CraftEventFactory {
|
||||
net.minecraft.world.entity.ExperienceOrb xp = (net.minecraft.world.entity.ExperienceOrb) entity;
|
||||
double radius = world.spigotConfig.expMerge;
|
||||
if (radius > 0) {
|
||||
+ // Paper start - Maximum exp value when merging - Whole section has been tweaked, see comments for specifics
|
||||
+ final int maxValue = world.paperConfig().entities.behavior.experienceMergeMaxValue;
|
||||
+ final boolean mergeUnconditionally = world.paperConfig().entities.behavior.experienceMergeMaxValue <= 0;
|
||||
+ if (mergeUnconditionally || xp.value < maxValue) { // Paper - Skip iteration if unnecessary
|
||||
+
|
||||
List<Entity> entities = world.getEntities(entity, entity.getBoundingBox().inflate(radius, radius, radius));
|
||||
for (Entity e : entities) {
|
||||
if (e instanceof net.minecraft.world.entity.ExperienceOrb) {
|
||||
net.minecraft.world.entity.ExperienceOrb loopItem = (net.minecraft.world.entity.ExperienceOrb) e;
|
||||
- if (!loopItem.isRemoved()) {
|
||||
+ // Paper start
|
||||
+ if (!loopItem.isRemoved() && !(maxValue > 0 && loopItem.value >= maxValue)) {
|
||||
+ long newTotal = (long)xp.value + (long)loopItem.value;
|
||||
+ if ((int) newTotal < 0) continue; // Overflow
|
||||
+ if (maxValue > 0 && newTotal > (long)maxValue) {
|
||||
+ loopItem.value = (int) (newTotal - maxValue);
|
||||
+ xp.value = maxValue;
|
||||
+ } else {
|
||||
xp.value += loopItem.value;
|
||||
loopItem.discard();
|
||||
+ } // Paper end
|
||||
}
|
||||
}
|
||||
}
|
||||
+ } // Paper end - End iteration skip check - All tweaking ends here
|
||||
}
|
||||
// Spigot end
|
||||
} else if (!(entity instanceof ServerPlayer)) {
|
23
patches/server/0392-ExperienceOrbMergeEvent.patch
Normal file
23
patches/server/0392-ExperienceOrbMergeEvent.patch
Normal file
|
@ -0,0 +1,23 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 19 Dec 2017 22:57:26 -0500
|
||||
Subject: [PATCH] ExperienceOrbMergeEvent
|
||||
|
||||
Has to be reimplemented at one point maybe
|
||||
Fired when the server is about to merge 2 experience orbs
|
||||
Plugins can cancel this if they want to ensure experience orbs do not lose important
|
||||
metadata such as spawn reason, or conditionally move data from source to target.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index b71024ebd675f4afd7ad2aa96393532758a28b63..7aba049b426a25981376205410acf41327993d30 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -698,7 +698,7 @@ public class CraftEventFactory {
|
||||
if (e instanceof net.minecraft.world.entity.ExperienceOrb) {
|
||||
net.minecraft.world.entity.ExperienceOrb loopItem = (net.minecraft.world.entity.ExperienceOrb) e;
|
||||
// Paper start
|
||||
- if (!loopItem.isRemoved() && !(maxValue > 0 && loopItem.value >= maxValue)) {
|
||||
+ if (!loopItem.isRemoved() && !(maxValue > 0 && loopItem.value >= maxValue) && new com.destroystokyo.paper.event.entity.ExperienceOrbMergeEvent((org.bukkit.entity.ExperienceOrb) entity.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) loopItem.getBukkitEntity()).callEvent()) { // Paper - ExperienceOrbMergeEvent
|
||||
long newTotal = (long)xp.value + (long)loopItem.value;
|
||||
if ((int) newTotal < 0) continue; // Overflow
|
||||
if (maxValue > 0 && newTotal > (long)maxValue) {
|
19
patches/server/0393-Fix-PotionEffect-ignores-icon-flag.patch
Normal file
19
patches/server/0393-Fix-PotionEffect-ignores-icon-flag.patch
Normal file
|
@ -0,0 +1,19 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kickash32 <kickash32@gmail.com>
|
||||
Date: Fri, 8 May 2020 00:49:18 -0400
|
||||
Subject: [PATCH] Fix PotionEffect ignores icon flag
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
index 607e48cf2eb50f477bcacca636cacf27f01342ef..02b7780a05f0119c2d1e9d379321105822629793 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
@@ -443,7 +443,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
||||
|
||||
@Override
|
||||
public boolean addPotionEffect(PotionEffect effect, boolean force) {
|
||||
- this.getHandle().addEffect(new MobEffectInstance(CraftPotionEffectType.bukkitToMinecraft(effect.getType()), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles()), EntityPotionEffectEvent.Cause.PLUGIN);
|
||||
+ this.getHandle().addEffect(new MobEffectInstance(CraftPotionEffectType.bukkitToMinecraft(effect.getType()), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles(), effect.hasIcon()), EntityPotionEffectEvent.Cause.PLUGIN); // Paper - Don't ignore icon
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: virustotalop <virustotalop@gmail.com>
|
||||
Date: Thu, 16 Apr 2020 20:51:32 -0700
|
||||
Subject: [PATCH] Optimize brigadier child sorting performance
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
index 3384501f83d445f45aa8233e98c7597daa67b8ef..20a7cdf87f307878d66922aaac0c60cff218e46c 100644
|
||||
--- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
+++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
|
||||
@@ -26,7 +26,7 @@ import java.util.function.Predicate;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
|
||||
public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
|
||||
- private final Map<String, CommandNode<S>> children = new LinkedHashMap<>();
|
||||
+ private Map<String, CommandNode<S>> children = com.google.common.collect.Maps.newTreeMap(); // Paper - Switch to tree map for automatic sorting
|
||||
private final Map<String, LiteralCommandNode<S>> literals = new LinkedHashMap<>();
|
||||
private final Map<String, ArgumentCommandNode<S, ?>> arguments = new LinkedHashMap<>();
|
||||
public Predicate<S> requirement;
|
||||
@@ -107,6 +107,8 @@ public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
|
||||
this.arguments.put(node.getName(), (ArgumentCommandNode<S, ?>) node);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Paper - Remove manual sorting, it is no longer needed
|
||||
}
|
||||
|
||||
public void findAmbiguities(final AmbiguityConsumer<S> consumer) {
|
44
patches/server/0395-Potential-bed-API.patch
Normal file
44
patches/server/0395-Potential-bed-API.patch
Normal file
|
@ -0,0 +1,44 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: JRoy <joshroy126@gmail.com>
|
||||
Date: Sun, 10 May 2020 23:06:30 -0400
|
||||
Subject: [PATCH] Potential bed API
|
||||
|
||||
Adds a new method to fetch the location of a player's bed without generating any sync loads.
|
||||
|
||||
getPotentialBedLocation - Gets the last known location of a player's bed. This does not preform any check if the bed is still valid and does not load any chunks.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
index 872adf91703baa24d67f417e7a45309f92984da9..80694a1d660a10909408c9b3169dda7847bf295e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
@@ -12,6 +12,7 @@ import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket;
|
||||
import net.minecraft.network.protocol.game.ServerboundContainerClosePacket;
|
||||
+import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
@@ -130,6 +131,22 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
|
||||
return this.getHandle().sleepCounter;
|
||||
}
|
||||
|
||||
+ // Paper start - Potential bed api
|
||||
+ @Override
|
||||
+ public Location getPotentialBedLocation() {
|
||||
+ ServerPlayer handle = (ServerPlayer) getHandle();
|
||||
+ BlockPos bed = handle.getRespawnPosition();
|
||||
+ if (bed == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ ServerLevel worldServer = handle.server.getLevel(handle.getRespawnDimension());
|
||||
+ if (worldServer == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ return new Location(worldServer.getWorld(), bed.getX(), bed.getY(), bed.getZ());
|
||||
+ }
|
||||
+ // Paper end
|
||||
@Override
|
||||
public boolean sleep(Location location, boolean force) {
|
||||
Preconditions.checkArgument(location != null, "Location cannot be null");
|
|
@ -0,0 +1,59 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 10 May 2020 22:16:17 -0400
|
||||
Subject: [PATCH] Wait for Async Tasks during shutdown
|
||||
|
||||
Server.reload() had this logic to give time for tasks to shutdown,
|
||||
however shutdown did not...
|
||||
|
||||
Adds a 5 second grace period for any async tasks to finish and warns
|
||||
if any are still running after that delay just as reload does.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index ad7f14d78fea3e6aba9576114463907b292c45a0..020c6ee8df9a97ca84f1fb36b03abfcd5df24744 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -902,6 +902,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// CraftBukkit start
|
||||
if (this.server != null) {
|
||||
this.server.disablePlugins();
|
||||
+ this.server.waitForAsyncTasksShutdown(); // Paper
|
||||
}
|
||||
// CraftBukkit end
|
||||
this.getConnection().stop();
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 5918b0296cf011f562e219984e6ad12a975318fb..4c4cee10d688aa0a3aab29f42c4cd8fd22488796 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1019,6 +1019,31 @@ public final class CraftServer implements Server {
|
||||
org.spigotmc.WatchdogThread.hasStarted = true; // Paper - Disable watchdog early timeout on reload
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public void waitForAsyncTasksShutdown() {
|
||||
+ int pollCount = 0;
|
||||
+
|
||||
+ // Wait for at most 5 seconds for plugins to close their threads
|
||||
+ while (pollCount < 10*5 && getScheduler().getActiveWorkers().size() > 0) {
|
||||
+ try {
|
||||
+ Thread.sleep(100);
|
||||
+ } catch (InterruptedException e) {}
|
||||
+ pollCount++;
|
||||
+ }
|
||||
+
|
||||
+ List<BukkitWorker> overdueWorkers = getScheduler().getActiveWorkers();
|
||||
+ for (BukkitWorker worker : overdueWorkers) {
|
||||
+ Plugin plugin = worker.getOwner();
|
||||
+ getLogger().log(Level.SEVERE, String.format(
|
||||
+ "Nag author(s): '%s' of '%s' about the following: %s",
|
||||
+ plugin.getPluginMeta().getAuthors(),
|
||||
+ plugin.getPluginMeta().getDisplayName(),
|
||||
+ "This plugin is not properly shutting down its async tasks when it is being shut down. This task may throw errors during the final shutdown logs and might not complete before process dies."
|
||||
+ ));
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public void reloadData() {
|
||||
ReloadCommand.reload(console);
|
|
@ -0,0 +1,19 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kickash32 <kickash32@gmail.com>
|
||||
Date: Sat, 9 May 2020 02:01:48 -0400
|
||||
Subject: [PATCH] Ensure EntityRaider respects game and entity rules for
|
||||
picking up items
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/raid/Raider.java b/src/main/java/net/minecraft/world/entity/raid/Raider.java
|
||||
index b35fcab88e9fd883a854c6861b6c69d725105539..49e07b33fccfe339712e5d1bd72e6c0edbd2e922 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/raid/Raider.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/raid/Raider.java
|
||||
@@ -312,6 +312,7 @@ public abstract class Raider extends PatrollingMonster {
|
||||
|
||||
@Override
|
||||
public boolean canUse() {
|
||||
+ if (!this.mob.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) || !this.mob.canPickUpLoot()) return false; // Paper - respect game and entity rules for picking up items
|
||||
Raid raid = this.mob.getCurrentRaid();
|
||||
|
||||
if (this.mob.hasActiveRaid() && !this.mob.getCurrentRaid().isOver() && this.mob.canBeLeader() && !ItemStack.matches(this.mob.getItemBySlot(EquipmentSlot.HEAD), Raid.getLeaderBannerInstance())) {
|
|
@ -0,0 +1,169 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 13 May 2020 23:01:26 -0400
|
||||
Subject: [PATCH] Protect Bedrock and End Portal/Frames from being destroyed
|
||||
|
||||
This fixes exploits that let players destroy bedrock by Pistons, explosions
|
||||
and Mushrooom/Tree generation.
|
||||
|
||||
These blocks are designed to not be broken except by creative players/commands.
|
||||
So protect them from a multitude of methods of destroying them.
|
||||
|
||||
A config is provided if you rather let players use these exploits, and let
|
||||
them destroy the worlds End Portals and get on top of the nether easy.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
index c0227cda09b9ca508c1de1fbe1e57afd743a9426..93529defa5d36bb9b4c69eedda9b7ac3d0a189ce 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
@@ -169,6 +169,7 @@ public class Explosion {
|
||||
for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F) {
|
||||
BlockPos blockposition = BlockPos.containing(d4, d5, d6);
|
||||
BlockState iblockdata = this.level.getBlockState(blockposition);
|
||||
+ if (!iblockdata.isDestroyable()) continue; // Paper
|
||||
FluidState fluid = iblockdata.getFluidState(); // Paper
|
||||
|
||||
if (!this.level.isInWorldBounds(blockposition)) {
|
||||
@@ -371,7 +372,7 @@ public class Explosion {
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
- if (!iblockdata.isAir()) {
|
||||
+ if (!iblockdata.isAir() && iblockdata.isDestroyable()) { // Paper
|
||||
BlockPos blockposition1 = blockposition.immutable();
|
||||
|
||||
this.level.getProfiler().push("explosion_blocks");
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 8b0c85d341c75e86421fc7c72aefcce83a165075..ea11bea03a15bfd79b82da60c48bfb23a44acda4 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -516,6 +516,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) {
|
||||
// CraftBukkit start - tree generation
|
||||
if (this.captureTreeGeneration) {
|
||||
+ // Paper start
|
||||
+ BlockState type = getBlockState(pos);
|
||||
+ if (!type.isDestroyable()) return false;
|
||||
+ // Paper end
|
||||
CraftBlockState blockstate = this.capturedBlockStates.get(pos);
|
||||
if (blockstate == null) {
|
||||
blockstate = CapturedBlockState.getTreeBlockState(this, pos, flags);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
|
||||
index 7646b66bc5ba0288608de0d836c7307e02eebe67..36b196c8834c4eb873bfca0b12f1fc2b421ea071 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/Block.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
|
||||
@@ -88,6 +88,19 @@ public class Block extends BlockBehaviour implements ItemLike {
|
||||
protected final StateDefinition<Block, BlockState> stateDefinition;
|
||||
private BlockState defaultBlockState;
|
||||
// Paper start
|
||||
+ public final boolean isDestroyable() {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits ||
|
||||
+ this != Blocks.BEDROCK &&
|
||||
+ this != Blocks.END_PORTAL_FRAME &&
|
||||
+ this != Blocks.END_PORTAL &&
|
||||
+ this != Blocks.END_GATEWAY &&
|
||||
+ this != Blocks.COMMAND_BLOCK &&
|
||||
+ this != Blocks.REPEATING_COMMAND_BLOCK &&
|
||||
+ this != Blocks.CHAIN_COMMAND_BLOCK &&
|
||||
+ this != Blocks.BARRIER &&
|
||||
+ this != Blocks.STRUCTURE_BLOCK &&
|
||||
+ this != Blocks.JIGSAW;
|
||||
+ }
|
||||
public co.aikar.timings.Timing timing;
|
||||
public co.aikar.timings.Timing getTiming() {
|
||||
if (timing == null) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
|
||||
index 6c90a37f8f98be975b9f961259aaadd03b091760..7248a8c51d0e285e2296826e48782f721265605b 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
|
||||
@@ -199,6 +199,12 @@ public class PistonBaseBlock extends DirectionalBlock {
|
||||
@Override
|
||||
public boolean triggerEvent(BlockState state, Level world, BlockPos pos, int type, int data) {
|
||||
Direction enumdirection = (Direction) state.getValue(PistonBaseBlock.FACING);
|
||||
+ // Paper start - prevent retracting when we're facing the wrong way (we were replaced before retraction could occur)
|
||||
+ Direction directionQueuedAs = Direction.from3DDataValue(data & 7); // Paper - copied from below
|
||||
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits && enumdirection != directionQueuedAs) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end - prevent retracting when we're facing the wrong way
|
||||
BlockState iblockdata1 = (BlockState) state.setValue(PistonBaseBlock.EXTENDED, true);
|
||||
|
||||
if (!world.isClientSide) {
|
||||
@@ -232,7 +238,7 @@ public class PistonBaseBlock extends DirectionalBlock {
|
||||
BlockState iblockdata2 = (BlockState) ((BlockState) Blocks.MOVING_PISTON.defaultBlockState().setValue(MovingPistonBlock.FACING, enumdirection)).setValue(MovingPistonBlock.TYPE, this.isSticky ? PistonType.STICKY : PistonType.DEFAULT);
|
||||
|
||||
world.setBlock(pos, iblockdata2, 20);
|
||||
- world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true));
|
||||
+ world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); // Paper - diff on change
|
||||
world.blockUpdated(pos, iblockdata2.getBlock());
|
||||
iblockdata2.updateNeighbourShapes(world, pos, 2);
|
||||
if (this.isSticky) {
|
||||
@@ -261,7 +267,14 @@ public class PistonBaseBlock extends DirectionalBlock {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
- world.removeBlock(pos.relative(enumdirection), false);
|
||||
+ // Paper start - fix headless pistons breaking blocks
|
||||
+ BlockPos headPos = pos.relative(enumdirection);
|
||||
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits || world.getBlockState(headPos) == Blocks.PISTON_HEAD.defaultBlockState().setValue(FACING, enumdirection)) { // double check to make sure we're not a headless piston.
|
||||
+ world.removeBlock(headPos, false);
|
||||
+ } else {
|
||||
+ ((ServerLevel)world).getChunkSource().blockChanged(headPos); // ... fix client desync
|
||||
+ }
|
||||
+ // Paper end - fix headless pistons breaking blocks
|
||||
}
|
||||
|
||||
world.playSound((Player) null, pos, SoundEvents.PISTON_CONTRACT, SoundSource.BLOCKS, 0.5F, world.random.nextFloat() * 0.15F + 0.6F);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
index 916d7b35145345cb3bf5ca46df38eae0512c4e95..a5942b6683d38f067f8ca1dfbe467b72df242632 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
@@ -229,7 +229,7 @@ public abstract class BlockBehaviour implements FeatureElement {
|
||||
/** @deprecated */
|
||||
@Deprecated
|
||||
public boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
|
||||
- return state.canBeReplaced() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem()));
|
||||
+ return state.canBeReplaced() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem())) && (state.isDestroyable() || (context.getPlayer() != null && context.getPlayer().getAbilities().instabuild)); // Paper;
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
@@ -891,6 +891,12 @@ public abstract class BlockBehaviour implements FeatureElement {
|
||||
return this.legacySolid;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public final boolean isDestroyable() {
|
||||
+ return getBlock().isDestroyable();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public boolean isValidSpawn(BlockGetter world, BlockPos pos, EntityType<?> type) {
|
||||
return this.getBlock().properties.isValidSpawn.test(this.asState(), world, pos, type);
|
||||
}
|
||||
@@ -994,7 +1000,7 @@ public abstract class BlockBehaviour implements FeatureElement {
|
||||
}
|
||||
|
||||
public PushReaction getPistonPushReaction() {
|
||||
- return this.pushReaction;
|
||||
+ return !this.isDestroyable() ? PushReaction.BLOCK : this.pushReaction; // Paper
|
||||
}
|
||||
|
||||
public boolean isSolidRender(BlockGetter world, BlockPos pos) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
index ed5210c63d964be7c28f59df315766794ec3ea1f..08325c055b04355089d75031522c7b74d83c6cca 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
@@ -221,6 +221,13 @@ public class PortalForcer {
|
||||
for (int j = -1; j < 3; ++j) {
|
||||
for (int k = -1; k < 4; ++k) {
|
||||
temp.setWithOffset(pos, portalDirection.getStepX() * j + enumdirection1.getStepX() * distanceOrthogonalToPortal, k, portalDirection.getStepZ() * j + enumdirection1.getStepZ() * distanceOrthogonalToPortal);
|
||||
+ // Paper start - prevent destroying unbreakable blocks
|
||||
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits) {
|
||||
+ if (!this.level.getBlockState(temp).isDestroyable()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - prevent destroying unbreakable blocks
|
||||
if (k < 0 && !this.level.getBlockState(temp).isSolid()) {
|
||||
return false;
|
||||
}
|
26
patches/server/0399-Ensure-safe-gateway-teleport.patch
Normal file
26
patches/server/0399-Ensure-safe-gateway-teleport.patch
Normal file
|
@ -0,0 +1,26 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kickash32 <kickash32@gmail.com>
|
||||
Date: Fri, 15 May 2020 01:10:03 -0400
|
||||
Subject: [PATCH] Ensure safe gateway teleport
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
|
||||
index 85914124014b4e6f0a561cf560918af68682b6f5..1ec80f9c901dff1c9f29befa5a8e3c3f6f37aaf7 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
|
||||
@@ -105,7 +105,14 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity {
|
||||
List<Entity> list = world.getEntitiesOfClass(Entity.class, new AABB(pos), TheEndGatewayBlockEntity::canEntityTeleport);
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
- TheEndGatewayBlockEntity.teleportEntity(world, pos, state, (Entity) list.get(world.random.nextInt(list.size())), blockEntity);
|
||||
+ // Paper start
|
||||
+ for (Entity entity : list) {
|
||||
+ if (entity.canChangeDimensions()) {
|
||||
+ TheEndGatewayBlockEntity.teleportEntity(world, pos, state, entity, blockEntity);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
if (blockEntity.age % 2400L == 0L) {
|
|
@ -0,0 +1,47 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mariell Hoversholm <proximyst@proximyst.com>
|
||||
Date: Sat, 16 May 2020 10:12:15 +0200
|
||||
Subject: [PATCH] Add option for console having all permissions
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java b/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java
|
||||
index 324e6d1a4fadd3e557e4ba05f04e6a5891cc54df..4e56018b64d11f76c8da43fd8f85c6de72204e36 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java
|
||||
@@ -93,5 +93,15 @@ public class CraftConsoleCommandSender extends ServerCommandSender implements Co
|
||||
public void sendMessage(final net.kyori.adventure.identity.Identity identity, final net.kyori.adventure.text.Component message, final net.kyori.adventure.audience.MessageType type) {
|
||||
this.sendRawMessage(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(message));
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasPermission(String name) {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(name);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasPermission(org.bukkit.permissions.Permission perm) {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(perm);
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java b/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java
|
||||
index ad731c5f76f19394866a121c64d4169ea8fb8cd7..55413cc3da415326b280ddbc0b4f4b201a301d5b 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java
|
||||
@@ -55,4 +55,16 @@ public class CraftRemoteConsoleCommandSender extends ServerCommandSender impleme
|
||||
public void setOp(boolean value) {
|
||||
throw new UnsupportedOperationException("Cannot change operator status of remote controller.");
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean hasPermission(String name) {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(name);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasPermission(org.bukkit.permissions.Permission perm) {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().console.hasAllPermissions || super.hasPermission(perm);
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: chickeneer <emcchickeneer@gmail.com>
|
||||
Date: Fri, 5 Jun 2020 20:02:04 -0500
|
||||
Subject: [PATCH] Fix villager trading demand - MC-163962
|
||||
|
||||
Prevent demand from going negative and tending to negative infinity
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java
|
||||
index a580011cd3b2b7129f2d09f37a3c26cdaafeefe8..1d755d04515f20dbd69931084b4cc894e52d35c9 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java
|
||||
@@ -130,7 +130,7 @@ public class MerchantOffer {
|
||||
}
|
||||
|
||||
public void updateDemand() {
|
||||
- this.demand = this.demand + this.uses - (this.maxUses - this.uses);
|
||||
+ this.demand = Math.max(0, this.demand + this.uses - (this.maxUses - this.uses)); // Paper
|
||||
}
|
||||
|
||||
public ItemStack assemble() {
|
32
patches/server/0402-Maps-shouldn-t-load-chunks.patch
Normal file
32
patches/server/0402-Maps-shouldn-t-load-chunks.patch
Normal file
|
@ -0,0 +1,32 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Phoenix616 <mail@moep.tv>
|
||||
Date: Sun, 7 Jun 2020 21:43:42 +0100
|
||||
Subject: [PATCH] Maps shouldn't load chunks
|
||||
|
||||
Previously maps would load all chunks in a certain radius depending on
|
||||
their scale when trying to update their content. This would result in
|
||||
main thread chunk loads when they weren't really necessary, especially
|
||||
on low view distances or "slow" async chunk loads after teleports or
|
||||
other prioritisation.
|
||||
|
||||
This changes it to only try to render already loaded chunks based on
|
||||
the assumption that the chunks around the player will get loaded
|
||||
eventually anyways and that maps will get checked for update every
|
||||
five ticks that movement occur in anyways.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/item/MapItem.java b/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
index 592bdf191f8787cf35d8844f66371c92179545ad..709928f6220c2148f95afa94c34df2a87cff0e1f 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
@@ -134,9 +134,9 @@ public class MapItem extends ComplexItem {
|
||||
int j2 = (j / i + k1 - 64) * i;
|
||||
int k2 = (k / i + l1 - 64) * i;
|
||||
Multiset<MapColor> multiset = LinkedHashMultiset.create();
|
||||
- LevelChunk chunk = world.getChunk(SectionPos.blockToSectionCoord(j2), SectionPos.blockToSectionCoord(k2));
|
||||
+ LevelChunk chunk = world.getChunkIfLoaded(SectionPos.blockToSectionCoord(j2), SectionPos.blockToSectionCoord(k2)); // Paper - Maps shouldn't load chunks
|
||||
|
||||
- if (!chunk.isEmpty()) {
|
||||
+ if (chunk != null && !chunk.isEmpty()) { // Paper - Maps shouldn't load chunks
|
||||
int l2 = 0;
|
||||
double d1 = 0.0D;
|
||||
int i3;
|
|
@ -0,0 +1,27 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 7 Jun 2020 19:25:13 -0400
|
||||
Subject: [PATCH] Use seed based lookup for Treasure Maps - Fixes lag from
|
||||
carto/sunken maps
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/item/MapItem.java b/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
index 709928f6220c2148f95afa94c34df2a87cff0e1f..53515854d05a0c27a65f71193424236a21b11f5f 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/MapItem.java
|
||||
@@ -250,14 +250,13 @@ public class MapItem extends ComplexItem {
|
||||
boolean[] aboolean = new boolean[16384];
|
||||
int l = j / i - 64;
|
||||
int i1 = k / i - 64;
|
||||
- BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
|
||||
|
||||
int j1;
|
||||
int k1;
|
||||
|
||||
for (j1 = 0; j1 < 128; ++j1) {
|
||||
for (k1 = 0; k1 < 128; ++k1) {
|
||||
- Holder<Biome> holder = world.getBiome(blockposition_mutableblockposition.set((l + k1) * i, 0, (i1 + j1) * i));
|
||||
+ Holder<Biome> holder = world.getUncachedNoiseBiome((l + k1) * i, 0, (i1 + j1) * i); // Paper
|
||||
|
||||
aboolean[j1 * 128 + k1] = holder.is(BiomeTags.WATER_ON_MAP_OUTLINES);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: ossi <oser0002@gmail.com>
|
||||
Date: Fri, 12 Jun 2020 01:38:06 +0300
|
||||
Subject: [PATCH] Fix CraftScheduler#runTaskTimerAsynchronously(Plugin,
|
||||
Consumer<BukkitTask>, long, long) scheduling a non-repeating task instead of
|
||||
a repeating one.
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
index 918e11422854d7301c84b466533770c2a429a682..addf3c442a085281a7ac06245ccd741f08ed7ccb 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
@@ -196,7 +196,7 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
|
||||
@Override
|
||||
public void runTaskTimerAsynchronously(Plugin plugin, Consumer<BukkitTask> task, long delay, long period) throws IllegalArgumentException {
|
||||
- this.runTaskTimerAsynchronously(plugin, (Object) task, delay, CraftTask.NO_REPEATING);
|
||||
+ this.runTaskTimerAsynchronously(plugin, (Object) task, delay, period);
|
||||
}
|
||||
|
||||
@Override
|
|
@ -0,0 +1,80 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 11 Jun 2020 17:29:42 -0700
|
||||
Subject: [PATCH] Fix piston physics inconsistency - MC-188840
|
||||
|
||||
Pistons invoke physics when they move blocks. The physics can cause
|
||||
tnt blocks to ignite. However, pistons (when storing the blocks they "moved")
|
||||
don't actually go back to the world state sometimes to check if something
|
||||
like that happened. As a result they end up moving the tnt like it was
|
||||
never ignited. This resulted in the ability to create machines
|
||||
that can duplicate tnt, called "world eaters".
|
||||
This patch makes the piston logic retrieve the block state from the world
|
||||
prevent this from occuring.
|
||||
|
||||
This patch also sets the moved pos to air immediately after creating
|
||||
the moving piston TE. This prevents the block from being updated from
|
||||
other physics calls by the piston.
|
||||
|
||||
Tested against the following tnt duper design:
|
||||
https://www.youtube.com/watch?v=mS7xxNGhjxs
|
||||
|
||||
This patch also affects every type of machine that utilises
|
||||
this mechanic. For example, dead coral is removed by a physics
|
||||
update when being moved while it is attached to slimeblocks.
|
||||
|
||||
Standard piston machines that don't destroy or modify the
|
||||
blocks they move by physics updates should be entirely
|
||||
unaffected.
|
||||
|
||||
This patch fixes https://bugs.mojang.com/browse/MC-188840
|
||||
|
||||
This patch also fixes rail duping and carpet duping.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
|
||||
index 7248a8c51d0e285e2296826e48782f721265605b..48ee146dea30f7d8c48c6bee7a1547ad2a69959d 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
|
||||
@@ -413,14 +413,26 @@ public class PistonBaseBlock extends DirectionalBlock {
|
||||
}
|
||||
|
||||
for (j = list.size() - 1; j >= 0; --j) {
|
||||
- blockposition3 = (BlockPos) list.get(j);
|
||||
- iblockdata1 = world.getBlockState(blockposition3);
|
||||
+ // Paper start - fix a variety of piston desync dupes
|
||||
+ boolean allowDesync = io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication;
|
||||
+ BlockPos oldPos = blockposition3 = (BlockPos) list.get(j);
|
||||
+ iblockdata1 = allowDesync ? world.getBlockState(oldPos) : null;
|
||||
+ // Paper end - fix a variety of piston desync dupes
|
||||
blockposition3 = blockposition3.relative(enumdirection1);
|
||||
map.remove(blockposition3);
|
||||
BlockState iblockdata2 = (BlockState) Blocks.MOVING_PISTON.defaultBlockState().setValue(PistonBaseBlock.FACING, dir);
|
||||
|
||||
world.setBlock(blockposition3, iblockdata2, 68);
|
||||
- world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(blockposition3, iblockdata2, (BlockState) list1.get(j), dir, retract, false));
|
||||
+ // Paper start - fix a variety of piston desync dupes
|
||||
+ if (!allowDesync) {
|
||||
+ iblockdata1 = world.getBlockState(oldPos);
|
||||
+ map.replace(oldPos, iblockdata1);
|
||||
+ }
|
||||
+ world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(blockposition3, iblockdata2, allowDesync ? list1.get(j) : iblockdata1, dir, retract, false));
|
||||
+ if (!allowDesync) {
|
||||
+ world.setBlock(oldPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE | Block.UPDATE_MOVE_BY_PISTON | 1024); // set air to prevent later physics updates from seeing this block
|
||||
+ }
|
||||
+ // Paper end - fix a variety of piston desync dupes
|
||||
aiblockdata[i++] = iblockdata1;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
index 17a6327ab7b26dfab38881bbc0689b0b25f8f025..1ef87580574919796dbba707f44a413ee5c5781b 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
@@ -288,7 +288,7 @@ public class PistonMovingBlockEntity extends BlockEntity {
|
||||
if (world.getBlockState(pos).is(Blocks.MOVING_PISTON)) {
|
||||
BlockState blockState = Block.updateFromNeighbourShapes(blockEntity.movedState, world, pos);
|
||||
if (blockState.isAir()) {
|
||||
- world.setBlock(pos, blockEntity.movedState, 84);
|
||||
+ world.setBlock(pos, blockEntity.movedState, io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication ? 84 : (84 | Block.UPDATE_CLIENTS)); // Paper - force notify (flag 2), it's possible the set type by the piston block (which doesn't notify) set this block to air
|
||||
Block.updateOrDestroy(blockEntity.movedState, blockState, world, pos, 3);
|
||||
} else {
|
||||
if (blockState.hasProperty(BlockStateProperties.WATERLOGGED) && blockState.getValue(BlockStateProperties.WATERLOGGED)) {
|
38
patches/server/0406-Fix-sand-duping.patch
Normal file
38
patches/server/0406-Fix-sand-duping.patch
Normal file
|
@ -0,0 +1,38 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 12 Jun 2020 13:33:19 -0700
|
||||
Subject: [PATCH] Fix sand duping
|
||||
|
||||
If the falling block dies during teleportation (entity#move), then we need
|
||||
to detect that by placing a check after the move.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
index b8c8b10656e4151c8c19b8cecc3bc7502dd57d3d..c64dcceabc41c11542b535d104b7f43172032842 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
@@ -131,6 +131,11 @@ public class FallingBlockEntity extends Entity {
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
+ // Paper start - fix sand duping
|
||||
+ if (this.isRemoved()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - fix sand duping
|
||||
if (this.blockState.isAir()) {
|
||||
this.discard();
|
||||
} else {
|
||||
@@ -142,6 +147,13 @@ public class FallingBlockEntity extends Entity {
|
||||
}
|
||||
|
||||
this.move(MoverType.SELF, this.getDeltaMovement());
|
||||
+
|
||||
+ // Paper start - fix sand duping
|
||||
+ if (this.isRemoved()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - fix sand duping
|
||||
+
|
||||
// Paper start - Configurable EntityFallingBlock height nerf
|
||||
if (this.level().paperConfig().fixes.fallingBlockHeightNerf.test(v -> this.getY() > v)) {
|
||||
if (this.dropItem && this.level().getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
|
|
@ -0,0 +1,29 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: David Slovikosky <davidslovikosky@gmail.com>
|
||||
Date: Tue, 9 Jun 2020 00:10:03 -0700
|
||||
Subject: [PATCH] Fix missing chunks due to integer overflow
|
||||
|
||||
This patch fixes a bug in the EndIslandDensityFunction class where the distance
|
||||
from 0,0 squared overflows the maximum size of an integer. The overflow leads
|
||||
to hard chunk borders around 370,000 blocks from 0,0. After this cutoff there
|
||||
is a few hundred thousand block gap before end land resuming to generate at
|
||||
530,000 blocks from spawn. This is due to the integer flipping back and forth.
|
||||
|
||||
The fix for the issue is quite simple, casting chunk coordinates to longs
|
||||
allows the distance calculation to avoid overflow and work as intended.
|
||||
|
||||
This issue is being tracked in Mojira ticket MC-159283
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java b/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java
|
||||
index 299116c5c4d25c78a2af00bb44c4f51ac04286e8..fac92f37c32e0398ebc05d9a0378446fcabaef1a 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java
|
||||
@@ -502,7 +502,7 @@ public final class DensityFunctions {
|
||||
int j = z / 2;
|
||||
int k = x % 2;
|
||||
int l = z % 2;
|
||||
- float f = 100.0F - Mth.sqrt((float)(x * x + z * z)) * 8.0F;
|
||||
+ float f = 100.0F - Mth.sqrt((long) x * (long) x + (long) z * (long) z) * 8.0F; // Paper - cast ints to long to avoid integer overflow
|
||||
f = Mth.clamp(f, -100.0F, 80.0F);
|
||||
|
||||
for(int m = -12; m <= 12; ++m) {
|
|
@ -0,0 +1,31 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 12 Jun 2020 16:51:39 -0700
|
||||
Subject: [PATCH] Prevent position desync in playerconnection causing tp
|
||||
exploit
|
||||
|
||||
Caused the server to revert to the player's overworld coordinates
|
||||
after teleporting into the end.
|
||||
|
||||
Sidenote: The underlying issue is that the move call can teleport
|
||||
entities and do other things like kill the entity. In the future,
|
||||
to fix all exploits derieved from this usually unexpected
|
||||
behaviour, we need to move all of this dangerous logic outside
|
||||
of the move call and into an appropriate place in the tick method.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 7f4bae60e44d9624871b5b447ea2df11f95d82fe..0790b86a4cb1068041d8e94aef84067b3039a055 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1333,6 +1333,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
|
||||
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
|
||||
+ // Paper start - prevent position desync
|
||||
+ if (this.awaitingPositionFromClient != null) {
|
||||
+ return; // ... thanks Mojang for letting move calls teleport across dimensions.
|
||||
+ }
|
||||
+ // Paper end - prevent position desync
|
||||
double d11 = d7;
|
||||
|
||||
d6 = d0 - this.player.getX();
|
|
@ -0,0 +1,42 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Phoenix616 <mail@moep.tv>
|
||||
Date: Wed, 10 Jun 2020 23:55:15 +0100
|
||||
Subject: [PATCH] Inventory getHolder method without block snapshot
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
|
||||
index c064022d248ff3e0b52c0e815ab90527f9132fb7..3680f101036d98814fe47b707baeeb8e55bfc4b7 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
|
||||
@@ -538,6 +538,13 @@ public class CraftInventory implements Inventory {
|
||||
return this.inventory.getOwner();
|
||||
}
|
||||
|
||||
+ // Paper start - getHolder without snapshot
|
||||
+ @Override
|
||||
+ public InventoryHolder getHolder(boolean useSnapshot) {
|
||||
+ return inventory instanceof net.minecraft.world.level.block.entity.BlockEntity ? ((net.minecraft.world.level.block.entity.BlockEntity) inventory).getOwner(useSnapshot) : getHolder();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public int getMaxStackSize() {
|
||||
return this.inventory.getMaxStackSize();
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java
|
||||
index d5defc82aec2279463e14029e213cfb8c3a40ce1..83712cc8da9751b6d4cc1f34a1cc0798bf848ae1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java
|
||||
@@ -63,6 +63,13 @@ public class CraftInventoryDoubleChest extends CraftInventory implements DoubleC
|
||||
return new DoubleChest(this);
|
||||
}
|
||||
|
||||
+ // Paper start - getHolder without snapshot
|
||||
+ @Override
|
||||
+ public DoubleChest getHolder(boolean useSnapshot) {
|
||||
+ return getHolder();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return this.getLeftSide().getLocation().add(this.getRightSide().getLocation()).multiply(0.5);
|
38
patches/server/0410-Improve-Arrow-API.patch
Normal file
38
patches/server/0410-Improve-Arrow-API.patch
Normal file
|
@ -0,0 +1,38 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nesaak <52047222+Nesaak@users.noreply.github.com>
|
||||
Date: Sat, 23 May 2020 10:31:11 -0400
|
||||
Subject: [PATCH] Improve Arrow API
|
||||
|
||||
Add method to get the arrow's itemstack and a method
|
||||
to set the arrow's "noclip" status
|
||||
|
||||
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java
|
||||
index e734cdb23f6289ac1cf3494f8efd2cae0562657e..5056ec1ad51be9209591d34d32d256c350feed63 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java
|
||||
@@ -99,6 +99,23 @@ public class CraftArrow extends AbstractProjectile implements AbstractArrow {
|
||||
this.getHandle().pickup = net.minecraft.world.entity.projectile.AbstractArrow.Pickup.byOrdinal(status.ordinal());
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public org.bukkit.craftbukkit.inventory.CraftItemStack getItemStack() {
|
||||
+ return org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(getHandle().getPickupItem());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setNoPhysics(boolean noPhysics) {
|
||||
+ this.getHandle().setNoPhysics(noPhysics);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasNoPhysics() {
|
||||
+ return this.getHandle().isNoPhysics();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public void setTicksLived(int value) {
|
||||
super.setTicksLived(value);
|
|
@ -0,0 +1,55 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: JRoy <joshroy126@gmail.com>
|
||||
Date: Fri, 5 Jun 2020 18:24:06 -0400
|
||||
Subject: [PATCH] Add and implement PlayerRecipeBookClickEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 0790b86a4cb1068041d8e94aef84067b3039a055..f16327556a5302c319b164897d2c5b3b4883ed31 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -2951,16 +2951,40 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
if (!this.player.containerMenu.stillValid(this.player)) {
|
||||
ServerGamePacketListenerImpl.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu);
|
||||
} else {
|
||||
+ // Paper start
|
||||
+ ResourceLocation recipeName = packet.getRecipe();
|
||||
+ boolean makeAll = packet.isShiftDown();
|
||||
+ com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent paperEvent = new com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent(
|
||||
+ this.player.getBukkitEntity(), org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(recipeName), makeAll
|
||||
+ );
|
||||
+ if (!paperEvent.callEvent()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ recipeName = CraftNamespacedKey.toMinecraft(paperEvent.getRecipe());
|
||||
+ makeAll = paperEvent.isMakeAll();
|
||||
+ if (org.bukkit.event.player.PlayerRecipeBookClickEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
||||
+ // Paper end
|
||||
// CraftBukkit start - implement PlayerRecipeBookClickEvent
|
||||
- org.bukkit.inventory.Recipe recipe = this.cserver.getRecipe(CraftNamespacedKey.fromMinecraft(packet.getRecipe()));
|
||||
+ org.bukkit.inventory.Recipe recipe = this.cserver.getRecipe(CraftNamespacedKey.fromMinecraft(recipeName)); // Paper
|
||||
if (recipe == null) {
|
||||
return;
|
||||
}
|
||||
- org.bukkit.event.player.PlayerRecipeBookClickEvent event = CraftEventFactory.callRecipeBookClickEvent(this.player, recipe, packet.isShiftDown());
|
||||
+ // Paper start
|
||||
+ org.bukkit.event.player.PlayerRecipeBookClickEvent event = CraftEventFactory.callRecipeBookClickEvent(this.player, recipe, makeAll);
|
||||
+ recipeName = CraftNamespacedKey.toMinecraft(((org.bukkit.Keyed) event.getRecipe()).getKey());
|
||||
+ makeAll = event.isShiftClick();
|
||||
+ }
|
||||
+ if (!(this.player.containerMenu instanceof RecipeBookMenu<?> recipeBookMenu)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
// Cast to keyed should be safe as the recipe will never be a MerchantRecipe.
|
||||
- this.server.getRecipeManager().byKey(CraftNamespacedKey.toMinecraft(((org.bukkit.Keyed) event.getRecipe()).getKey())).ifPresent((recipeholder) -> {
|
||||
- ((RecipeBookMenu) this.player.containerMenu).handlePlacement(event.isShiftClick(), recipeholder, this.player);
|
||||
+ // Paper start
|
||||
+ final boolean finalMakeAll = makeAll;
|
||||
+ this.server.getRecipeManager().byKey(recipeName).ifPresent((recipeholder) -> {
|
||||
+ recipeBookMenu.handlePlacement(finalMakeAll, recipeholder, this.player);
|
||||
+ // Paper end
|
||||
});
|
||||
// CraftBukkit end
|
||||
}
|
23
patches/server/0412-Hide-sync-chunk-writes-behind-flag.patch
Normal file
23
patches/server/0412-Hide-sync-chunk-writes-behind-flag.patch
Normal file
|
@ -0,0 +1,23 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 26 Jun 2020 22:35:08 -0700
|
||||
Subject: [PATCH] Hide sync chunk writes behind flag
|
||||
|
||||
Syncing writes on each write call has terrible performance
|
||||
on harddrives.
|
||||
|
||||
-DPaper.enable-sync-chunk-writes=true to enable
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
||||
index 97e9a3e567a53c21aff8c525259b9dd83f222ebf..0d0ed4cb50364828d0a028ee69654e23b3b8d913 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
||||
@@ -145,7 +145,7 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
|
||||
this.maxWorldSize = this.get("max-world-size", (integer) -> {
|
||||
return Mth.clamp(integer, 1, 29999984);
|
||||
}, 29999984);
|
||||
- this.syncChunkWrites = this.get("sync-chunk-writes", true);
|
||||
+ this.syncChunkWrites = this.get("sync-chunk-writes", true) && Boolean.getBoolean("Paper.enable-sync-chunk-writes"); // Paper - hide behind flag
|
||||
this.enableJmxMonitoring = this.get("enable-jmx-monitoring", false);
|
||||
this.enableStatus = this.get("enable-status", true);
|
||||
this.hideOnlinePlayers = this.get("hide-online-players", false);
|
79
patches/server/0413-Add-permission-for-command-blocks.patch
Normal file
79
patches/server/0413-Add-permission-for-command-blocks.patch
Normal file
|
@ -0,0 +1,79 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mariell Hoversholm <proximyst@proximyst.com>
|
||||
Date: Sat, 16 May 2020 10:05:30 +0200
|
||||
Subject: [PATCH] Add permission for command blocks
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
index bdf11a98614c9c12d3112f437651be81d0d9872a..3622708c453feb6da3d5be192291d63abbe83068 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
@@ -402,7 +402,7 @@ public class ServerPlayerGameMode {
|
||||
BlockEntity tileentity = this.level.getBlockEntity(pos);
|
||||
Block block = iblockdata.getBlock();
|
||||
|
||||
- if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks()) {
|
||||
+ if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks() && !(block instanceof net.minecraft.world.level.block.CommandBlock && (this.player.isCreative() && this.player.getBukkitEntity().hasPermission("minecraft.commandblock")))) { // Paper - command block permission
|
||||
this.level.sendBlockUpdated(pos, iblockdata, iblockdata, 3);
|
||||
return false;
|
||||
} else if (this.player.blockActionRestricted(this.level, pos, this.gameModeForPlayer)) {
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index f16327556a5302c319b164897d2c5b3b4883ed31..dc5bcf6cf46d32961da9a2a6e9691ab30bb96045 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -770,7 +770,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
|
||||
if (!this.server.isCommandBlockEnabled()) {
|
||||
this.player.sendSystemMessage(Component.translatable("advMode.notEnabled"));
|
||||
- } else if (!this.player.canUseGameMasterBlocks()) {
|
||||
+ } else if (!this.player.canUseGameMasterBlocks() && (!this.player.isCreative() || !this.player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission
|
||||
this.player.sendSystemMessage(Component.translatable("advMode.notAllowed"));
|
||||
} else {
|
||||
BaseCommandBlock commandblocklistenerabstract = null;
|
||||
@@ -837,7 +837,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
|
||||
if (!this.server.isCommandBlockEnabled()) {
|
||||
this.player.sendSystemMessage(Component.translatable("advMode.notEnabled"));
|
||||
- } else if (!this.player.canUseGameMasterBlocks()) {
|
||||
+ } else if (!this.player.canUseGameMasterBlocks() && (!this.player.isCreative() || !this.player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission
|
||||
this.player.sendSystemMessage(Component.translatable("advMode.notAllowed"));
|
||||
} else {
|
||||
BaseCommandBlock commandblocklistenerabstract = packet.getCommandBlock(this.player.level());
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
|
||||
index 9c7b7434ccd64668eb5d7bb61d03a9cb4105ea6e..e05eb08a9c229b371887676da510df948b896a85 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
|
||||
@@ -198,7 +198,7 @@ public abstract class BaseCommandBlock implements CommandSource {
|
||||
}
|
||||
|
||||
public InteractionResult usedBy(Player player) {
|
||||
- if (!player.canUseGameMasterBlocks()) {
|
||||
+ if (!player.canUseGameMasterBlocks() && (!player.isCreative() || !player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission
|
||||
return InteractionResult.PASS;
|
||||
} else {
|
||||
if (player.getCommandSenderWorld().isClientSide) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/CommandBlock.java b/src/main/java/net/minecraft/world/level/block/CommandBlock.java
|
||||
index 061a56e3828767cd6576d5a9edde5f3498e609d0..2e7c03b00bc941b86df6a7f1b2b188c9f0aede22 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/CommandBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/CommandBlock.java
|
||||
@@ -130,7 +130,7 @@ public class CommandBlock extends BaseEntityBlock implements GameMasterBlock {
|
||||
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||
BlockEntity tileentity = world.getBlockEntity(pos);
|
||||
|
||||
- if (tileentity instanceof CommandBlockEntity && player.canUseGameMasterBlocks()) {
|
||||
+ if (tileentity instanceof CommandBlockEntity && (player.canUseGameMasterBlocks() || (player.isCreative() && player.getBukkitEntity().hasPermission("minecraft.commandblock")))) { // Paper - command block permission
|
||||
player.openCommandBlock((CommandBlockEntity) tileentity);
|
||||
return InteractionResult.sidedSuccess(world.isClientSide);
|
||||
} else {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java b/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java
|
||||
index 70d3949616c63038ad3e9bd1069db5ea2fb3f3b8..8e06bc11fb28baee3407bbfe9d7b3689d6f85ff2 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java
|
||||
@@ -16,6 +16,7 @@ public final class CraftDefaultPermissions {
|
||||
DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".nbt.copy", "Gives the user the ability to copy NBT in creative", org.bukkit.permissions.PermissionDefault.TRUE, parent);
|
||||
DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".debugstick", "Gives the user the ability to use the debug stick in creative", org.bukkit.permissions.PermissionDefault.OP, parent);
|
||||
DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".debugstick.always", "Gives the user the ability to use the debug stick in all game modes", org.bukkit.permissions.PermissionDefault.FALSE/* , parent */); // Paper - should not have this parent, as it's not a "vanilla" utility
|
||||
+ DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".commandblock", "Gives the user the ability to use command blocks.", org.bukkit.permissions.PermissionDefault.OP, parent); // Paper
|
||||
// Spigot end
|
||||
parent.recalculatePermissibles();
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 10 May 2020 22:12:46 -0400
|
||||
Subject: [PATCH] Ensure Entity AABB's are never invalid
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index f57d9a298a6e3be63c37ed7e14c99b154d372709..7b182384ca7f2b36513856e247072c3c5c05b5e7 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -636,8 +636,8 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
}
|
||||
|
||||
public void setPos(double x, double y, double z) {
|
||||
- this.setPosRaw(x, y, z);
|
||||
- this.setBoundingBox(this.makeBoundingBox());
|
||||
+ this.setPosRaw(x, y, z, true); // Paper - force bounding box update
|
||||
+ // this.setBoundingBox(this.makeBoundingBox()); // Paper - move into setPositionRaw
|
||||
}
|
||||
|
||||
protected AABB makeBoundingBox() {
|
||||
@@ -4128,6 +4128,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
}
|
||||
|
||||
public final void setPosRaw(double x, double y, double z) {
|
||||
+ // Paper start
|
||||
+ this.setPosRaw(x, y, z, false);
|
||||
+ }
|
||||
+ public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) {
|
||||
+ // Paper end
|
||||
if (this.position.x != x || this.position.y != y || this.position.z != z) {
|
||||
this.position = new Vec3(x, y, z);
|
||||
int i = Mth.floor(x);
|
||||
@@ -4145,6 +4150,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
this.levelCallback.onMove();
|
||||
}
|
||||
|
||||
+ // Paper start - never allow AABB to become desynced from position
|
||||
+ // hanging has its own special logic
|
||||
+ if (!(this instanceof net.minecraft.world.entity.decoration.HangingEntity) && (forceBoundingBoxUpdate || this.position.x != x || this.position.y != y || this.position.z != z)) {
|
||||
+ this.setBoundingBox(this.makeBoundingBox());
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public void checkDespawn() {}
|
|
@ -0,0 +1,131 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 28 Jun 2020 03:59:10 -0400
|
||||
Subject: [PATCH] Fix Per World Difficulty / Remembering Difficulty
|
||||
|
||||
Fixes per world difficulty with /difficulty command and also
|
||||
makes it so that the server keeps the last difficulty used instead
|
||||
of restoring the server.properties every single load.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 020c6ee8df9a97ca84f1fb36b03abfcd5df24744..ac7c70533659c5683f72ded537f76cb6ff4e3777 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -782,7 +782,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
if (worldserver.getWorld().getKeepSpawnInMemory()) worldloadlistener.stop(); // Paper
|
||||
// CraftBukkit start
|
||||
// this.updateMobSpawningFlags();
|
||||
- worldserver.setSpawnSettings(this.isSpawningMonsters(), this.isSpawningAnimals());
|
||||
+ worldserver.setSpawnSettings(worldserver.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && ((DedicatedServer) this).settings.getProperties().spawnMonsters, this.isSpawningAnimals()); // Paper - per level difficulty (from setDifficulty(ServerLevel, Difficulty, boolean))
|
||||
|
||||
this.forceTicks = false;
|
||||
// CraftBukkit end
|
||||
@@ -1731,11 +1731,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
}
|
||||
|
||||
- public void setDifficulty(Difficulty difficulty, boolean forceUpdate) {
|
||||
- if (forceUpdate || !this.worldData.isDifficultyLocked()) {
|
||||
- this.worldData.setDifficulty(this.worldData.isHardcore() ? Difficulty.HARD : difficulty);
|
||||
- this.updateMobSpawningFlags();
|
||||
- this.getPlayerList().getPlayers().forEach(this::sendDifficultyUpdate);
|
||||
+ // Paper start - remember per level difficulty
|
||||
+ public void setDifficulty(ServerLevel level, Difficulty difficulty, boolean forceUpdate) {
|
||||
+ PrimaryLevelData worldData = level.serverLevelData;
|
||||
+ if (forceUpdate || !worldData.isDifficultyLocked()) {
|
||||
+ worldData.setDifficulty(worldData.isHardcore() ? Difficulty.HARD : difficulty);
|
||||
+ level.setSpawnSettings(worldData.getDifficulty() != Difficulty.PEACEFUL && ((DedicatedServer) this).settings.getProperties().spawnMonsters, this.isSpawningAnimals());
|
||||
+ // this.getPlayerList().getPlayers().forEach(this::sendDifficultyUpdate);
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1749,7 +1752,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
while (iterator.hasNext()) {
|
||||
ServerLevel worldserver = (ServerLevel) iterator.next();
|
||||
|
||||
- worldserver.setSpawnSettings(this.isSpawningMonsters(), this.isSpawningAnimals());
|
||||
+ worldserver.setSpawnSettings(worldserver.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && ((DedicatedServer) this).settings.getProperties().spawnMonsters, this.isSpawningAnimals()); // Paper - per level difficulty (from setDifficulty(ServerLevel, Difficulty, boolean))
|
||||
}
|
||||
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/commands/DifficultyCommand.java b/src/main/java/net/minecraft/server/commands/DifficultyCommand.java
|
||||
index 89be3991ef4fb2deb7276c5409cb571a7fb1f821..9c272f7cf8cbd2bbe147e57f7fabe135b6ff5c0b 100644
|
||||
--- a/src/main/java/net/minecraft/server/commands/DifficultyCommand.java
|
||||
+++ b/src/main/java/net/minecraft/server/commands/DifficultyCommand.java
|
||||
@@ -49,7 +49,7 @@ public class DifficultyCommand {
|
||||
if (worldServer.getDifficulty() == difficulty) { // CraftBukkit
|
||||
throw DifficultyCommand.ERROR_ALREADY_DIFFICULT.create(difficulty.getKey());
|
||||
} else {
|
||||
- worldServer.serverLevelData.setDifficulty(difficulty); // CraftBukkit
|
||||
+ minecraftserver.setDifficulty(worldServer, difficulty, true); // Paper - don't skip other difficulty-changing logic (fix upstream's fix)
|
||||
source.sendSuccess(() -> {
|
||||
return Component.translatable("commands.difficulty.success", difficulty.getDisplayName());
|
||||
}, true);
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 967817ad15146407668361a85c89be6beb6a73f9..5d90fc103577a5dab63daf9a23ba46da7eba1e18 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -325,7 +325,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
|
||||
@Override
|
||||
public void forceDifficulty() {
|
||||
- this.setDifficulty(this.getProperties().difficulty, true);
|
||||
+ // this.setDifficulty(this.getProperties().difficulty, true); // Paper - Don't overwrite level.dat's difficulty, keep current
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index fcf875c6145c2428cab7a801442f34adc098b3ce..b70165b6ffce01aadf30af33746d347457dc150a 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1162,7 +1162,7 @@ public class ServerPlayer extends Player {
|
||||
this.isChangingDimension = true; // CraftBukkit - Set teleport invulnerability only if player changing worlds
|
||||
|
||||
this.connection.send(new ClientboundRespawnPacket(this.createCommonSpawnInfo(worldserver), (byte) 3));
|
||||
- this.connection.send(new ClientboundChangeDifficultyPacket(this.level().getDifficulty(), this.level().getLevelData().isDifficultyLocked()));
|
||||
+ this.connection.send(new ClientboundChangeDifficultyPacket(worldserver.getDifficulty(), this.level().getLevelData().isDifficultyLocked())); // Paper - fix difficulty sync issue
|
||||
PlayerList playerlist = this.server.getPlayerList();
|
||||
|
||||
playerlist.sendPlayerPermissionLevel(this);
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index dc5bcf6cf46d32961da9a2a6e9691ab30bb96045..c6b5bc584fc117240c4290ba48dd71e5d70c2abb 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -3153,7 +3153,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
public void handleChangeDifficulty(ServerboundChangeDifficultyPacket packet) {
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
|
||||
if (this.player.hasPermissions(2) || this.isSingleplayerOwner()) {
|
||||
- this.server.setDifficulty(packet.getDifficulty(), false);
|
||||
+ // this.server.setDifficulty(packet.getDifficulty(), false); // Paper - don't allow clients to change this
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 4c4cee10d688aa0a3aab29f42c4cd8fd22488796..cc28da02a5736508bc82f31401646de2c0d7ab99 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -958,8 +958,8 @@ public final class CraftServer implements Server {
|
||||
org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot
|
||||
this.console.paperConfigurations.reloadConfigs(this.console);
|
||||
for (ServerLevel world : this.console.getAllLevels()) {
|
||||
- world.serverLevelData.setDifficulty(config.difficulty);
|
||||
- world.setSpawnSettings(config.spawnMonsters, config.spawnAnimals);
|
||||
+ // world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty
|
||||
+ world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters, config.spawnAnimals); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean))
|
||||
|
||||
for (SpawnCategory spawnCategory : SpawnCategory.values()) {
|
||||
if (CraftSpawnCategory.isValidForLimits(spawnCategory)) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index b266cd21fec4c48d2fc4676eb30b1bfdaa4acd98..4f40c0fcab774647cc89c04d51ae47444bc88874 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -1155,7 +1155,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
|
||||
@Override
|
||||
public void setDifficulty(Difficulty difficulty) {
|
||||
- this.getHandle().serverLevelData.setDifficulty(net.minecraft.world.Difficulty.byId(difficulty.getValue()));
|
||||
+ this.getHandle().getServer().setDifficulty(this.getHandle(), net.minecraft.world.Difficulty.byId(difficulty.getValue()), true); // Paper - don't skip other difficulty-changing logic
|
||||
}
|
||||
|
||||
@Override
|
84
patches/server/0416-Paper-dumpitem-command.patch
Normal file
84
patches/server/0416-Paper-dumpitem-command.patch
Normal file
|
@ -0,0 +1,84 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 28 Jun 2020 19:27:20 -0400
|
||||
Subject: [PATCH] Paper dumpitem command
|
||||
|
||||
Let's you quickly view the item in your hands NBT data
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
index 43573b5ef76c8bb42411c3707cb13d90d531b905..a27c90ea7af63b0d42f202ed1a7dab6e42daed9f 100644
|
||||
--- a/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
+++ b/src/main/java/io/papermc/paper/command/PaperCommand.java
|
||||
@@ -40,6 +40,7 @@ public final class PaperCommand extends Command {
|
||||
commands.put(Set.of("dumpplugins"), new DumpPluginsCommand());
|
||||
commands.put(Set.of("fixlight"), new FixLightCommand());
|
||||
commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand());
|
||||
+ commands.put(Set.of("dumpitem"), new DumpItemCommand());
|
||||
|
||||
return commands.entrySet().stream()
|
||||
.flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue())))
|
||||
diff --git a/src/main/java/io/papermc/paper/command/subcommands/DumpItemCommand.java b/src/main/java/io/papermc/paper/command/subcommands/DumpItemCommand.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..5f0b0fe73a47e6a5ca8706f11e78b4b08e6ccd9a
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/command/subcommands/DumpItemCommand.java
|
||||
@@ -0,0 +1,59 @@
|
||||
+package io.papermc.paper.command.subcommands;
|
||||
+
|
||||
+import io.papermc.paper.adventure.PaperAdventure;
|
||||
+import io.papermc.paper.command.PaperSubcommand;
|
||||
+import java.util.Objects;
|
||||
+import net.kyori.adventure.text.Component;
|
||||
+import net.kyori.adventure.text.event.ClickEvent;
|
||||
+import net.minecraft.core.registries.Registries;
|
||||
+import net.minecraft.nbt.CompoundTag;
|
||||
+import net.minecraft.world.item.ItemStack;
|
||||
+import org.bukkit.Bukkit;
|
||||
+import org.bukkit.command.CommandSender;
|
||||
+import org.bukkit.craftbukkit.CraftWorld;
|
||||
+import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.entity.Player;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+import static net.kyori.adventure.text.Component.text;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
|
||||
+import static net.kyori.adventure.text.format.NamedTextColor.YELLOW;
|
||||
+import static net.kyori.adventure.text.format.TextDecoration.ITALIC;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public final class DumpItemCommand implements PaperSubcommand {
|
||||
+ @Override
|
||||
+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
|
||||
+ this.doDumpItem(sender);
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ private void doDumpItem(final CommandSender sender) {
|
||||
+ if (!(sender instanceof Player)) {
|
||||
+ sender.sendMessage("Only players can use this command");
|
||||
+ return;
|
||||
+ }
|
||||
+ final ItemStack itemStack = CraftItemStack.asNMSCopy(((CraftPlayer) sender).getItemInHand());
|
||||
+ final @Nullable CompoundTag tag = itemStack.getTag();
|
||||
+ final @Nullable Component nbtComponent = tag == null ? null : PaperAdventure.asAdventure(net.minecraft.nbt.NbtUtils.toPrettyComponent(tag));
|
||||
+ final String itemId = Objects.requireNonNull(((CraftWorld) ((CraftPlayer) sender).getWorld()).getHandle().registryAccess()
|
||||
+ .registryOrThrow(Registries.ITEM).getKey(itemStack.getItem())).toString();
|
||||
+ final Component message = text()
|
||||
+ .append(text(itemId, YELLOW))
|
||||
+ .apply(b -> {
|
||||
+ if (nbtComponent != null) {
|
||||
+ b.append(nbtComponent);
|
||||
+ }
|
||||
+ })
|
||||
+ .build();
|
||||
+ Bukkit.getConsoleSender().sendMessage(message);
|
||||
+ sender.sendMessage(message);
|
||||
+ sender.sendMessage(text().content(" Click to copy item to clipboard")
|
||||
+ .color(GRAY)
|
||||
+ .decorate(ITALIC)
|
||||
+ .clickEvent(ClickEvent.copyToClipboard(tag == null ? itemId : (itemId + tag))));
|
||||
+ }
|
||||
+}
|
|
@ -0,0 +1,56 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 28 Jun 2020 19:08:41 -0400
|
||||
Subject: [PATCH] Improve Legacy Component serialization size
|
||||
|
||||
Don't constantly send format: false for all formatting options when parent already
|
||||
has it false
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java
|
||||
index 4fede2161792ba3e7cdf0cc5a1f533188becc6f7..0f70be614f8f5350ad558d0ae645cdf0027e1e76 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java
|
||||
@@ -47,6 +47,7 @@ public final class CraftChatMessage {
|
||||
// Separate pattern with no group 3, new lines are part of previous string
|
||||
private static final Pattern INCREMENTAL_PATTERN_KEEP_NEWLINES = Pattern.compile("(" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + "[0-9a-fk-orx])|((?:(?:https?):\\/\\/)?(?:[-\\w_\\.]{2,}\\.[a-z]{2,4}.*?(?=[\\.\\?!,;:]?(?:[" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + " ]|$))))", Pattern.CASE_INSENSITIVE);
|
||||
// ChatColor.b does not explicitly reset, its more of empty
|
||||
+ private static final Style EMPTY = Style.EMPTY.withItalic(false); // Paper - OBFHELPER
|
||||
private static final Style RESET = Style.EMPTY.withBold(false).withItalic(false).withUnderlined(false).withStrikethrough(false).withObfuscated(false);
|
||||
|
||||
private final List<Component> list = new ArrayList<Component>();
|
||||
@@ -68,6 +69,7 @@ public final class CraftChatMessage {
|
||||
Matcher matcher = (keepNewlines ? StringMessage.INCREMENTAL_PATTERN_KEEP_NEWLINES : StringMessage.INCREMENTAL_PATTERN).matcher(message);
|
||||
String match = null;
|
||||
boolean needsAdd = false;
|
||||
+ boolean hasReset = false; // Paper
|
||||
while (matcher.find()) {
|
||||
int groupId = 0;
|
||||
while ((match = matcher.group(++groupId)) == null) {
|
||||
@@ -113,7 +115,26 @@ public final class CraftChatMessage {
|
||||
throw new AssertionError("Unexpected message format");
|
||||
}
|
||||
} else { // Color resets formatting
|
||||
- this.modifier = StringMessage.RESET.withColor(format);
|
||||
+ // Paper start - improve legacy formatting
|
||||
+ Style previous = modifier;
|
||||
+ modifier = (!hasReset ? RESET : EMPTY).withColor(format);
|
||||
+ hasReset = true;
|
||||
+ if (previous.isBold()) {
|
||||
+ modifier = modifier.withBold(false);
|
||||
+ }
|
||||
+ if (previous.isItalic()) {
|
||||
+ modifier = modifier.withItalic(false);
|
||||
+ }
|
||||
+ if (previous.isObfuscated()) {
|
||||
+ modifier = modifier.withObfuscated(false);
|
||||
+ }
|
||||
+ if (previous.isStrikethrough()) {
|
||||
+ modifier = modifier.withStrikethrough(false);
|
||||
+ }
|
||||
+ if (previous.isUnderlined()) {
|
||||
+ modifier = modifier.withUnderlined(false);
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
needsAdd = true;
|
||||
break;
|
213
patches/server/0418-Optimize-Bit-Operations-by-inlining.patch
Normal file
213
patches/server/0418-Optimize-Bit-Operations-by-inlining.patch
Normal file
|
@ -0,0 +1,213 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 4 Jun 2020 02:24:49 -0400
|
||||
Subject: [PATCH] Optimize Bit Operations by inlining
|
||||
|
||||
Inline bit operations and reduce instruction count to make these hot
|
||||
operations faster
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java
|
||||
index fbdbf61f49bd6867eea609d5572fb31ece094944..441ea6b9fd55a5288f264472d7297728d0546d6b 100644
|
||||
--- a/src/main/java/net/minecraft/core/BlockPos.java
|
||||
+++ b/src/main/java/net/minecraft/core/BlockPos.java
|
||||
@@ -37,15 +37,16 @@ public class BlockPos extends Vec3i {
|
||||
}).stable();
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public static final BlockPos ZERO = new BlockPos(0, 0, 0);
|
||||
- private static final int PACKED_X_LENGTH = 1 + Mth.log2(Mth.smallestEncompassingPowerOfTwo(30000000));
|
||||
- private static final int PACKED_Z_LENGTH = PACKED_X_LENGTH;
|
||||
- public static final int PACKED_Y_LENGTH = 64 - PACKED_X_LENGTH - PACKED_Z_LENGTH;
|
||||
- private static final long PACKED_X_MASK = (1L << PACKED_X_LENGTH) - 1L;
|
||||
- private static final long PACKED_Y_MASK = (1L << PACKED_Y_LENGTH) - 1L;
|
||||
- private static final long PACKED_Z_MASK = (1L << PACKED_Z_LENGTH) - 1L;
|
||||
- private static final int Y_OFFSET = 0;
|
||||
- private static final int Z_OFFSET = PACKED_Y_LENGTH;
|
||||
- private static final int X_OFFSET = PACKED_Y_LENGTH + PACKED_Z_LENGTH;
|
||||
+ // Paper start - static constants
|
||||
+ private static final int PACKED_X_LENGTH = 26;
|
||||
+ private static final int PACKED_Z_LENGTH = 26;
|
||||
+ public static final int PACKED_Y_LENGTH = 12;
|
||||
+ private static final long PACKED_X_MASK = 67108863;
|
||||
+ private static final long PACKED_Y_MASK = 4095;
|
||||
+ private static final long PACKED_Z_MASK = 67108863;
|
||||
+ private static final int Z_OFFSET = 12;
|
||||
+ private static final int X_OFFSET = 38;
|
||||
+ // Paper end
|
||||
|
||||
public BlockPos(int x, int y, int z) {
|
||||
super(x, y, z);
|
||||
@@ -55,28 +56,29 @@ public class BlockPos extends Vec3i {
|
||||
this(pos.getX(), pos.getY(), pos.getZ());
|
||||
}
|
||||
|
||||
+ public static long getAdjacent(int baseX, int baseY, int baseZ, Direction enumdirection) { return asLong(baseX + enumdirection.getStepX(), baseY + enumdirection.getStepY(), baseZ + enumdirection.getStepZ()); } // Paper
|
||||
public static long offset(long value, Direction direction) {
|
||||
return offset(value, direction.getStepX(), direction.getStepY(), direction.getStepZ());
|
||||
}
|
||||
|
||||
public static long offset(long value, int x, int y, int z) {
|
||||
- return asLong(getX(value) + x, getY(value) + y, getZ(value) + z);
|
||||
+ return asLong((int) (value >> 38) + x, (int) ((value << 52) >> 52) + y, (int) ((value << 26) >> 38) + z); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static int getX(long packedPos) {
|
||||
- return (int)(packedPos << 64 - X_OFFSET - PACKED_X_LENGTH >> 64 - PACKED_X_LENGTH);
|
||||
+ return (int) (packedPos >> 38); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static int getY(long packedPos) {
|
||||
- return (int)(packedPos << 64 - PACKED_Y_LENGTH >> 64 - PACKED_Y_LENGTH);
|
||||
+ return (int) ((packedPos << 52) >> 52); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static int getZ(long packedPos) {
|
||||
- return (int)(packedPos << 64 - Z_OFFSET - PACKED_Z_LENGTH >> 64 - PACKED_Z_LENGTH);
|
||||
+ return (int) ((packedPos << 26) >> 38); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static BlockPos of(long packedPos) {
|
||||
- return new BlockPos(getX(packedPos), getY(packedPos), getZ(packedPos));
|
||||
+ return new BlockPos((int) (packedPos >> 38), (int) ((packedPos << 52) >> 52), (int) ((packedPos << 26) >> 38)); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static BlockPos containing(double x, double y, double z) {
|
||||
@@ -92,10 +94,7 @@ public class BlockPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static long asLong(int x, int y, int z) {
|
||||
- long l = 0L;
|
||||
- l |= ((long)x & PACKED_X_MASK) << X_OFFSET;
|
||||
- l |= ((long)y & PACKED_Y_MASK) << 0;
|
||||
- return l | ((long)z & PACKED_Z_MASK) << Z_OFFSET;
|
||||
+ return (((long) x & (long) 67108863) << 38) | (((long) y & (long) 4095)) | (((long) z & (long) 67108863) << 12); // Paper - inline constants and simplify
|
||||
}
|
||||
|
||||
public static long getFlatIndex(long y) {
|
||||
diff --git a/src/main/java/net/minecraft/core/SectionPos.java b/src/main/java/net/minecraft/core/SectionPos.java
|
||||
index eb97928380384b8c33cf142dd9a5db65951c94c6..392c3681c08d9e3d99cbabaf72d22c1d1518998d 100644
|
||||
--- a/src/main/java/net/minecraft/core/SectionPos.java
|
||||
+++ b/src/main/java/net/minecraft/core/SectionPos.java
|
||||
@@ -38,7 +38,7 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static SectionPos of(BlockPos pos) {
|
||||
- return new SectionPos(blockToSectionCoord(pos.getX()), blockToSectionCoord(pos.getY()), blockToSectionCoord(pos.getZ()));
|
||||
+ return new SectionPos(pos.getX() >> 4, pos.getY() >> 4, pos.getZ() >> 4); // Paper
|
||||
}
|
||||
|
||||
public static SectionPos of(ChunkPos chunkPos, int y) {
|
||||
@@ -54,7 +54,7 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static SectionPos of(long packed) {
|
||||
- return new SectionPos(x(packed), y(packed), z(packed));
|
||||
+ return new SectionPos((int) (packed >> 42), (int) (packed << 44 >> 44), (int) (packed << 22 >> 42)); // Paper
|
||||
}
|
||||
|
||||
public static SectionPos bottomOf(ChunkAccess chunk) {
|
||||
@@ -65,8 +65,16 @@ public class SectionPos extends Vec3i {
|
||||
return offset(packed, direction.getStepX(), direction.getStepY(), direction.getStepZ());
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public static long getAdjacentFromBlockPos(int x, int y, int z, Direction enumdirection) {
|
||||
+ return (((long) ((x >> 4) + enumdirection.getStepX()) & 4194303L) << 42) | (((long) ((y >> 4) + enumdirection.getStepY()) & 1048575L)) | (((long) ((z >> 4) + enumdirection.getStepZ()) & 4194303L) << 20);
|
||||
+ }
|
||||
+ public static long getAdjacentFromSectionPos(int x, int y, int z, Direction enumdirection) {
|
||||
+ return (((long) (x + enumdirection.getStepX()) & 4194303L) << 42) | (((long) ((y) + enumdirection.getStepY()) & 1048575L)) | (((long) (z + enumdirection.getStepZ()) & 4194303L) << 20);
|
||||
+ }
|
||||
+ // Paper end
|
||||
public static long offset(long packed, int x, int y, int z) {
|
||||
- return asLong(x(packed) + x, y(packed) + y, z(packed) + z);
|
||||
+ return (((long) ((int) (packed >> 42) + x) & 4194303L) << 42) | (((long) ((int) (packed << 44 >> 44) + y) & 1048575L)) | (((long) ((int) (packed << 22 >> 42) + z) & 4194303L) << 20); // Simplify to reduce instruction count
|
||||
}
|
||||
|
||||
public static int posToSectionCoord(double coord) {
|
||||
@@ -86,10 +94,7 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static short sectionRelativePos(BlockPos pos) {
|
||||
- int i = sectionRelative(pos.getX());
|
||||
- int j = sectionRelative(pos.getY());
|
||||
- int k = sectionRelative(pos.getZ());
|
||||
- return (short)(i << 8 | k << 4 | j << 0);
|
||||
+ return (short) ((pos.getX() & 15) << 8 | (pos.getZ() & 15) << 4 | pos.getY() & 15); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static int sectionRelativeX(short packedLocalPos) {
|
||||
@@ -152,16 +157,16 @@ public class SectionPos extends Vec3i {
|
||||
return this.getZ();
|
||||
}
|
||||
|
||||
- public int minBlockX() {
|
||||
- return sectionToBlockCoord(this.x());
|
||||
+ public final int minBlockX() { // Paper - make final
|
||||
+ return this.getX() << 4; // Paper - inline
|
||||
}
|
||||
|
||||
- public int minBlockY() {
|
||||
- return sectionToBlockCoord(this.y());
|
||||
+ public final int minBlockY() { // Paper - make final
|
||||
+ return this.getY() << 4; // Paper - inline
|
||||
}
|
||||
|
||||
- public int minBlockZ() {
|
||||
- return sectionToBlockCoord(this.z());
|
||||
+ public int minBlockZ() { // Paper - make final
|
||||
+ return this.getZ() << 4; // Paper - inline
|
||||
}
|
||||
|
||||
public int maxBlockX() {
|
||||
@@ -177,7 +182,8 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static long blockToSection(long blockPos) {
|
||||
- return asLong(blockToSectionCoord(BlockPos.getX(blockPos)), blockToSectionCoord(BlockPos.getY(blockPos)), blockToSectionCoord(BlockPos.getZ(blockPos)));
|
||||
+ // b(a(BlockPosition.b(i)), a(BlockPosition.c(i)), a(BlockPosition.d(i)));
|
||||
+ return (((long) (int) (blockPos >> 42) & 4194303L) << 42) | (((long) (int) ((blockPos << 52) >> 56) & 1048575L)) | (((long) (int) ((blockPos << 26) >> 42) & 4194303L) << 20); // Simplify to reduce instruction count
|
||||
}
|
||||
|
||||
public static long getZeroNode(int x, int z) {
|
||||
@@ -205,15 +211,18 @@ public class SectionPos extends Vec3i {
|
||||
return asLong(blockToSectionCoord(pos.getX()), blockToSectionCoord(pos.getY()), blockToSectionCoord(pos.getZ()));
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public static long blockPosAsSectionLong(int i, int j, int k) {
|
||||
+ return (((long) (i >> 4) & 4194303L) << 42) | (((long) (j >> 4) & 1048575L)) | (((long) (k >> 4) & 4194303L) << 20);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public static long asLong(int x, int y, int z) {
|
||||
- long l = 0L;
|
||||
- l |= ((long)x & 4194303L) << 42;
|
||||
- l |= ((long)y & 1048575L) << 0;
|
||||
- return l | ((long)z & 4194303L) << 20;
|
||||
+ return (((long) x & 4194303L) << 42) | (((long) y & 1048575L)) | (((long) z & 4194303L) << 20); // Paper - Simplify to reduce instruction count
|
||||
}
|
||||
|
||||
public long asLong() {
|
||||
- return asLong(this.x(), this.y(), this.z());
|
||||
+ return (((long) getX() & 4194303L) << 42) | (((long) getY() & 1048575L)) | (((long) getZ() & 4194303L) << 20); // Paper - Simplify to reduce instruction count
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -226,16 +235,11 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static Stream<SectionPos> cube(SectionPos center, int radius) {
|
||||
- int i = center.x();
|
||||
- int j = center.y();
|
||||
- int k = center.z();
|
||||
- return betweenClosedStream(i - radius, j - radius, k - radius, i + radius, j + radius, k + radius);
|
||||
+ return betweenClosedStream(center.getX() - radius, center.getY() - radius, center.getZ() - radius, center.getX() + radius, center.getY() + radius, center.getZ() + radius); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static Stream<SectionPos> aroundChunk(ChunkPos center, int radius, int minY, int maxY) {
|
||||
- int i = center.x;
|
||||
- int j = center.z;
|
||||
- return betweenClosedStream(i - radius, minY, j - radius, i + radius, maxY - 1, j + radius);
|
||||
+ return betweenClosedStream(center.x - radius, 0, center.z - radius, center.x + radius, 15, center.z + radius); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static Stream<SectionPos> betweenClosedStream(final int minX, final int minY, final int minZ, final int maxX, final int maxY, final int maxZ) {
|
|
@ -0,0 +1,126 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 9 Jun 2020 03:33:03 -0400
|
||||
Subject: [PATCH] Add Plugin Tickets to API Chunk Methods
|
||||
|
||||
Like previous versions, plugins loading chunks kept them loaded until
|
||||
they garbage collected to avoid constant spamming of chunk loads
|
||||
|
||||
This adds tickets to a few more places so that they can be unloaded.
|
||||
|
||||
Additionally, this drops their ticket level to BORDER so they wont be ticking
|
||||
so they will just sit inactive instead.
|
||||
|
||||
Using .loadChunk to keep a chunk ticking was a horrible idea for upstream
|
||||
when we have TWO methods that are able to do that already in the API.
|
||||
|
||||
Also reduce their collection count down to a maximum of 1 second. Barely
|
||||
anyone knows what chunk-gc is in bukkit.yml as its less relevant now, and
|
||||
since this wasn't spigot behavior, this is safe to mostly ignore (unless someone
|
||||
wants it to collect even faster, they can restore that setting back to 1 instead of 20+)
|
||||
|
||||
Not adding it to .getType() though to keep behavior consistent with vanilla for performance reasons.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index cc28da02a5736508bc82f31401646de2c0d7ab99..970a604108c0b7e410af356e3d12559af0b0b78b 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -385,7 +385,7 @@ public final class CraftServer implements Server {
|
||||
this.overrideSpawnLimits();
|
||||
console.autosavePeriod = this.configuration.getInt("ticks-per.autosave");
|
||||
this.warningState = WarningState.value(this.configuration.getString("settings.deprecated-verbose"));
|
||||
- TicketType.PLUGIN.timeout = this.configuration.getInt("chunk-gc.period-in-ticks");
|
||||
+ TicketType.PLUGIN.timeout = Math.min(20, this.configuration.getInt("chunk-gc.period-in-ticks")); // Paper - cap plugin loads to 1 second
|
||||
this.minimumAPI = this.configuration.getString("settings.minimum-api");
|
||||
this.loadIcon();
|
||||
|
||||
@@ -938,7 +938,7 @@ public final class CraftServer implements Server {
|
||||
this.console.setMotd(config.motd);
|
||||
this.overrideSpawnLimits();
|
||||
this.warningState = WarningState.value(this.configuration.getString("settings.deprecated-verbose"));
|
||||
- TicketType.PLUGIN.timeout = this.configuration.getInt("chunk-gc.period-in-ticks");
|
||||
+ TicketType.PLUGIN.timeout = Math.min(20, configuration.getInt("chunk-gc.period-in-ticks")); // Paper - cap plugin loads to 1 second
|
||||
this.minimumAPI = this.configuration.getString("settings.minimum-api");
|
||||
this.printSaveWarning = false;
|
||||
console.autosavePeriod = this.configuration.getInt("ticks-per.autosave");
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index 4f40c0fcab774647cc89c04d51ae47444bc88874..6137e49ba4f7dd121bbb7b13add3d63285df52d5 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -279,7 +279,13 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
|
||||
@Override
|
||||
public Chunk getChunkAt(int x, int z) {
|
||||
- net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk) this.world.getChunk(x, z, ChunkStatus.FULL, true);
|
||||
+ // Paper start - add ticket to hold chunk for a little while longer if plugin accesses it
|
||||
+ net.minecraft.world.level.chunk.LevelChunk chunk = this.world.getChunkSource().getChunkAtIfLoadedImmediately(x, z);
|
||||
+ if (chunk == null) {
|
||||
+ this.addTicket(x, z);
|
||||
+ chunk = this.world.getChunkSource().getChunk(x, z, true);
|
||||
+ }
|
||||
+ // Paper end
|
||||
return new CraftChunk(chunk);
|
||||
}
|
||||
|
||||
@@ -293,6 +299,12 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
return new CraftChunk(this.getHandle(), x, z);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ private void addTicket(int x, int z) {
|
||||
+ io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> this.world.getChunkSource().addRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 0, Unit.INSTANCE)); // Paper
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public Chunk getChunkAt(Block block) {
|
||||
Preconditions.checkArgument(block != null, "null block");
|
||||
@@ -358,7 +370,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
public boolean unloadChunkRequest(int x, int z) {
|
||||
org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot
|
||||
if (this.isChunkLoaded(x, z)) {
|
||||
- this.world.getChunkSource().removeRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 1, Unit.INSTANCE);
|
||||
+ this.world.getChunkSource().removeRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 0, Unit.INSTANCE); // Paper
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -436,9 +448,12 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot
|
||||
// Paper start - Optimize this method
|
||||
ChunkPos chunkPos = new ChunkPos(x, z);
|
||||
+ ChunkAccess immediate = world.getChunkSource().getChunkAtIfLoadedImmediately(x, z); // Paper
|
||||
+ if (immediate != null) return true; // Paper
|
||||
|
||||
if (!generate) {
|
||||
- ChunkAccess immediate = world.getChunkSource().getChunkAtImmediately(x, z);
|
||||
+
|
||||
+ //IChunkAccess immediate = world.getChunkProvider().getChunkAtImmediately(x, z); // Paper
|
||||
if (immediate == null) {
|
||||
immediate = world.getChunkSource().chunkMap.getUnloadingChunk(x, z);
|
||||
}
|
||||
@@ -446,7 +461,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
if (!(immediate instanceof ImposterProtoChunk) && !(immediate instanceof net.minecraft.world.level.chunk.LevelChunk)) {
|
||||
return false; // not full status
|
||||
}
|
||||
- world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 1, Unit.INSTANCE);
|
||||
+ world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 0, Unit.INSTANCE); // Paper
|
||||
world.getChunk(x, z); // make sure we're at ticket level 32 or lower
|
||||
return true;
|
||||
}
|
||||
@@ -472,7 +487,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
// we do this so we do not re-read the chunk data on disk
|
||||
}
|
||||
|
||||
- world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 1, Unit.INSTANCE);
|
||||
+ world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 0, Unit.INSTANCE); // Paper
|
||||
world.getChunkSource().getChunk(x, z, ChunkStatus.FULL, true);
|
||||
return true;
|
||||
// Paper end
|
||||
@@ -2174,6 +2189,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
io.papermc.paper.chunk.system.ChunkSystem.scheduleChunkLoad(this.getHandle(), x, z, gen, ChunkStatus.FULL, true, priority, (c) -> {
|
||||
net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> {
|
||||
net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk)c;
|
||||
+ if (chunk != null) this.addTicket(x, z); // Paper
|
||||
ret.complete(chunk == null ? null : new CraftChunk(chunk));
|
||||
});
|
||||
});
|
164
patches/server/0420-incremental-chunk-and-player-saving.patch
Normal file
164
patches/server/0420-incremental-chunk-and-player-saving.patch
Normal file
|
@ -0,0 +1,164 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Sun, 9 Jun 2019 03:53:22 +0100
|
||||
Subject: [PATCH] incremental chunk and player saving
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index ac7c70533659c5683f72ded537f76cb6ff4e3777..e82e5df0abf64b27733beedb4a545a0a1a2119f3 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -845,7 +845,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
try {
|
||||
this.isSaving = true;
|
||||
- this.getPlayerList().saveAll();
|
||||
+ this.getPlayerList().saveAll(); // Diff on change
|
||||
flag3 = this.saveAllChunks(suppressLogs, flush, force);
|
||||
} finally {
|
||||
this.isSaving = false;
|
||||
@@ -1368,13 +1368,28 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.status = this.buildServerStatus();
|
||||
}
|
||||
|
||||
- if (this.autosavePeriod > 0 && this.tickCount % this.autosavePeriod == 0) { // CraftBukkit
|
||||
- MinecraftServer.LOGGER.debug("Autosave started");
|
||||
- this.profiler.push("save");
|
||||
- this.saveEverything(true, false, false);
|
||||
- this.profiler.pop();
|
||||
- MinecraftServer.LOGGER.debug("Autosave finished");
|
||||
+ // Paper start - incremental chunk and player saving
|
||||
+ int playerSaveInterval = io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.rate;
|
||||
+ if (playerSaveInterval < 0) {
|
||||
+ playerSaveInterval = autosavePeriod;
|
||||
}
|
||||
+ this.profiler.push("save");
|
||||
+ final boolean fullSave = autosavePeriod > 0 && this.tickCount % autosavePeriod == 0;
|
||||
+ try {
|
||||
+ this.isSaving = true;
|
||||
+ if (playerSaveInterval > 0) {
|
||||
+ this.playerList.saveAll(playerSaveInterval);
|
||||
+ }
|
||||
+ for (ServerLevel level : this.getAllLevels()) {
|
||||
+ if (level.paperConfig().chunks.autoSaveInterval.value() > 0) {
|
||||
+ level.saveIncrementally(fullSave);
|
||||
+ }
|
||||
+ }
|
||||
+ } finally {
|
||||
+ this.isSaving = false;
|
||||
+ }
|
||||
+ this.profiler.pop();
|
||||
+ // Paper end
|
||||
io.papermc.paper.util.CachedLists.reset(); // Paper
|
||||
// Paper start - move executeAll() into full server tick timing
|
||||
try (co.aikar.timings.Timing ignored = MinecraftTimings.processTasksTimer.startTiming()) {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 7aceefc28f310e704ca8803e95c40ada13718988..70a7abf4738cc5da94d7465884d9a5a1dd7c828c 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -603,6 +603,15 @@ public class ServerChunkCache extends ChunkSource {
|
||||
} // Paper - Timings
|
||||
}
|
||||
|
||||
+ // Paper start - duplicate save, but call incremental
|
||||
+ public void saveIncrementally() {
|
||||
+ this.runDistanceManagerUpdates();
|
||||
+ try (co.aikar.timings.Timing timed = level.timings.chunkSaveData.startTiming()) { // Paper - Timings
|
||||
+ this.chunkMap.saveIncrementally();
|
||||
+ } // Paper - Timings
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// CraftBukkit start
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 6bb7f2050e93f63045ea608672751da28138d3f8..b84a5fcda10711c896c9a670343d961b9536f888 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1051,6 +1051,37 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
return !this.server.isUnderSpawnProtection(this, pos, player) && this.getWorldBorder().isWithinBounds(pos);
|
||||
}
|
||||
|
||||
+ // Paper start - derived from below
|
||||
+ public void saveIncrementally(boolean doFull) {
|
||||
+ ServerChunkCache chunkproviderserver = this.getChunkSource();
|
||||
+
|
||||
+ if (doFull) {
|
||||
+ org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld()));
|
||||
+ }
|
||||
+
|
||||
+ try (co.aikar.timings.Timing ignored = this.timings.worldSave.startTiming()) {
|
||||
+ if (doFull) {
|
||||
+ this.saveLevelData();
|
||||
+ }
|
||||
+
|
||||
+ this.timings.worldSaveChunks.startTiming(); // Paper
|
||||
+ if (!this.noSave()) chunkproviderserver.saveIncrementally();
|
||||
+ this.timings.worldSaveChunks.stopTiming(); // Paper
|
||||
+
|
||||
+ // Copied from save()
|
||||
+ // CraftBukkit start - moved from MinecraftServer.saveChunks
|
||||
+ if (doFull) { // Paper
|
||||
+ ServerLevel worldserver1 = this;
|
||||
+
|
||||
+ this.serverLevelData.setWorldBorder(worldserver1.getWorldBorder().createSettings());
|
||||
+ this.serverLevelData.setCustomBossEvents(this.server.getCustomBossEvents().save());
|
||||
+ this.convertable.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData());
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public void save(@Nullable ProgressListener progressListener, boolean flush, boolean savingDisabled) {
|
||||
ServerChunkCache chunkproviderserver = this.getChunkSource();
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index b70165b6ffce01aadf30af33746d347457dc150a..0661ed6cac8da2a1cc94abe7e1017fcd04a9e9c2 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -184,6 +184,7 @@ import org.bukkit.inventory.MainHand;
|
||||
public class ServerPlayer extends Player {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
+ public long lastSave = MinecraftServer.currentTick; // Paper
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32;
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
|
||||
public ServerGamePacketListenerImpl connection;
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index fdd518b5ea21ae617069fd03429712de4b44841b..2de6d47c2289faac019e4f68dcc7df910a03e206 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -522,6 +522,7 @@ public abstract class PlayerList {
|
||||
|
||||
protected void save(ServerPlayer player) {
|
||||
if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit
|
||||
+ player.lastSave = MinecraftServer.currentTick; // Paper
|
||||
this.playerIo.save(player);
|
||||
ServerStatsCounter serverstatisticmanager = (ServerStatsCounter) player.getStats(); // CraftBukkit
|
||||
|
||||
@@ -1119,10 +1120,22 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
public void saveAll() {
|
||||
+ // Paper start - incremental player saving
|
||||
+ this.saveAll(-1);
|
||||
+ }
|
||||
+
|
||||
+ public void saveAll(int interval) {
|
||||
io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main
|
||||
MinecraftTimings.savePlayers.startTiming(); // Paper
|
||||
+ int numSaved = 0;
|
||||
+ long now = MinecraftServer.currentTick;
|
||||
for (int i = 0; i < this.players.size(); ++i) {
|
||||
- this.save(this.players.get(i));
|
||||
+ ServerPlayer entityplayer = this.players.get(i);
|
||||
+ if (interval == -1 || now - entityplayer.lastSave >= interval) {
|
||||
+ this.save(entityplayer);
|
||||
+ if (interval != -1 && ++numSaved >= io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick()) { break; }
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
MinecraftTimings.savePlayers.stopTiming(); // Paper
|
||||
return null; }); // Paper - ensure main
|
63
patches/server/0421-Support-old-UUID-format-for-NBT.patch
Normal file
63
patches/server/0421-Support-old-UUID-format-for-NBT.patch
Normal file
|
@ -0,0 +1,63 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 29 Jun 2020 03:26:17 -0400
|
||||
Subject: [PATCH] Support old UUID format for NBT
|
||||
|
||||
We have stored UUID in plenty of places that did not get DFU'd
|
||||
|
||||
So just look for old format and load it if it exists.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/nbt/CompoundTag.java b/src/main/java/net/minecraft/nbt/CompoundTag.java
|
||||
index ad0251b73d21b36bf19e9aa649817b4da2d0a6b4..84fc2adf591f02a14862f7c1cd645c2efde55c3d 100644
|
||||
--- a/src/main/java/net/minecraft/nbt/CompoundTag.java
|
||||
+++ b/src/main/java/net/minecraft/nbt/CompoundTag.java
|
||||
@@ -233,6 +233,12 @@ public class CompoundTag implements Tag {
|
||||
}
|
||||
|
||||
public void putUUID(String key, UUID value) {
|
||||
+ // Paper start - support old format
|
||||
+ if (this.contains(key + "Most", 99) && this.contains(key + "Least", 99)) {
|
||||
+ this.tags.remove(key + "Most");
|
||||
+ this.tags.remove(key + "Least");
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.tags.put(key, NbtUtils.createUUID(value));
|
||||
}
|
||||
|
||||
@@ -241,10 +247,20 @@ public class CompoundTag implements Tag {
|
||||
* You must use {@link #hasUUID(String)} before or else it <b>will</b> throw an NPE.
|
||||
*/
|
||||
public UUID getUUID(String key) {
|
||||
+ // Paper start - support old format
|
||||
+ if (!contains(key, 11) && this.contains(key + "Most", 99) && this.contains(key + "Least", 99)) {
|
||||
+ return new UUID(this.getLong(key + "Most"), this.getLong(key + "Least"));
|
||||
+ }
|
||||
+ // Paper end
|
||||
return NbtUtils.loadUUID(this.get(key));
|
||||
}
|
||||
|
||||
public boolean hasUUID(String key) {
|
||||
+ // Paper start - support old format
|
||||
+ if (this.contains(key + "Most", 99) && this.contains(key + "Least", 99)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end
|
||||
Tag tag = this.get(key);
|
||||
return tag != null && tag.getType() == IntArrayTag.TYPE && ((IntArrayTag)tag).getAsIntArray().length == 4;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/nbt/NbtUtils.java b/src/main/java/net/minecraft/nbt/NbtUtils.java
|
||||
index 4388f2a8b05f5ed2f0934c1693299a4c92072adc..b65dcff9812dbc3256c080ac264c4aafd83ce276 100644
|
||||
--- a/src/main/java/net/minecraft/nbt/NbtUtils.java
|
||||
+++ b/src/main/java/net/minecraft/nbt/NbtUtils.java
|
||||
@@ -72,6 +72,11 @@ public final class NbtUtils {
|
||||
@Nullable
|
||||
public static GameProfile readGameProfile(CompoundTag nbt) {
|
||||
UUID uUID = nbt.hasUUID("Id") ? nbt.getUUID("Id") : Util.NIL_UUID;
|
||||
+ // Paper start - support string UUID's
|
||||
+ if (nbt.contains("Id", Tag.TAG_STRING)) {
|
||||
+ uUID = UUID.fromString(nbt.getString("Id"));
|
||||
+ }
|
||||
+ // Paper end
|
||||
String string = nbt.getString("Name");
|
||||
|
||||
try {
|
|
@ -0,0 +1,44 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 1 Jul 2020 04:50:22 -0400
|
||||
Subject: [PATCH] Convert legacy attributes in Item Meta
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java
|
||||
index fac4097be2ee3d0bffbc92fb217f98831e78d6b3..233e372ba5d785352c9ac12dac37395bac63315c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java
|
||||
@@ -12,6 +12,20 @@ import org.bukkit.craftbukkit.util.CraftNamespacedKey;
|
||||
public class CraftAttributeMap implements Attributable {
|
||||
|
||||
private final AttributeMap handle;
|
||||
+ // Paper start - convert legacy attributes
|
||||
+ private static final com.google.common.collect.ImmutableMap<String, String> legacyNMS = com.google.common.collect.ImmutableMap.<String, String>builder().put("generic.maxHealth", "generic.max_health").put("Max Health", "generic.max_health").put("zombie.spawnReinforcements", "zombie.spawn_reinforcements").put("Spawn Reinforcements Chance", "zombie.spawn_reinforcements").put("horse.jumpStrength", "horse.jump_strength").put("Jump Strength", "horse.jump_strength").put("generic.followRange", "generic.follow_range").put("Follow Range", "generic.follow_range").put("generic.knockbackResistance", "generic.knockback_resistance").put("Knockback Resistance", "generic.knockback_resistance").put("generic.movementSpeed", "generic.movement_speed").put("Movement Speed", "generic.movement_speed").put("generic.flyingSpeed", "generic.flying_speed").put("Flying Speed", "generic.flying_speed").put("generic.attackDamage", "generic.attack_damage").put("generic.attackKnockback", "generic.attack_knockback").put("generic.attackSpeed", "generic.attack_speed").put("generic.armorToughness", "generic.armor_toughness").build();
|
||||
+
|
||||
+ public static String convertIfNeeded(String nms) {
|
||||
+ if (nms == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ nms = legacyNMS.getOrDefault(nms, nms);
|
||||
+ if (!nms.toLowerCase().equals(nms) || nms.indexOf(' ') != -1) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ return nms;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
public CraftAttributeMap(AttributeMap handle) {
|
||||
this.handle = handle;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
index d7102d83bb781b6cf296cf9c637f8270f4ee8b14..d1f21b5f5600dba41a93378853aadacd24f4a1f3 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
@@ -483,7 +483,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
|
||||
AttributeModifier attribMod = CraftAttributeInstance.convert(nmsModifier);
|
||||
|
||||
- String attributeName = entry.getString(ATTRIBUTES_IDENTIFIER.NBT);
|
||||
+ String attributeName = CraftAttributeMap.convertIfNeeded(entry.getString(ATTRIBUTES_IDENTIFIER.NBT)); // Paper
|
||||
if (attributeName == null || attributeName.isEmpty()) {
|
||||
continue;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: JRoy <joshroy126@gmail.com>
|
||||
Date: Mon, 29 Jun 2020 17:03:06 -0400
|
||||
Subject: [PATCH] Remove some streams from structures
|
||||
|
||||
This showed up a lot in the spark profiler, should have a low-medium performance improvement.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java b/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
index bb8d8edb47621665872a5e8fc01512ba40c1b913..5d721dc196a6bde511f46dbdedb2e1d98553ac52 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
@@ -36,9 +36,10 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
|
||||
int j = pos.getMinBlockZ();
|
||||
ObjectList<Beardifier.Rigid> objectList = new ObjectArrayList<>(10);
|
||||
ObjectList<JigsawJunction> objectList2 = new ObjectArrayList<>(32);
|
||||
- world.startsForStructure(pos, (structure) -> {
|
||||
+ // Paper start - replace for each
|
||||
+ for (net.minecraft.world.level.levelgen.structure.StructureStart start : world.startsForStructure(pos, (structure) -> {
|
||||
return structure.terrainAdaptation() != TerrainAdjustment.NONE;
|
||||
- }).forEach((start) -> {
|
||||
+ })) { // Paper end
|
||||
TerrainAdjustment terrainAdjustment = start.getStructure().terrainAdaptation();
|
||||
|
||||
for(StructurePiece structurePiece : start.getPieces()) {
|
||||
@@ -51,9 +52,11 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
|
||||
}
|
||||
|
||||
for(JigsawJunction jigsawJunction : poolElementStructurePiece.getJunctions()) {
|
||||
- int i = jigsawJunction.getSourceX();
|
||||
- int j = jigsawJunction.getSourceZ();
|
||||
- if (i > i - 12 && j > j - 12 && i < i + 15 + 12 && j < j + 15 + 12) {
|
||||
+ // Paper start - decompile fix
|
||||
+ int i2 = jigsawJunction.getSourceX();
|
||||
+ int j2 = jigsawJunction.getSourceZ();
|
||||
+ if (i2 > i - 12 && j2 > j - 12 && i2 < i + 15 + 12 && j2 < j + 15 + 12) {
|
||||
+ // Paper end
|
||||
objectList2.add(jigsawJunction);
|
||||
}
|
||||
}
|
||||
@@ -63,7 +66,7 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
|
||||
}
|
||||
}
|
||||
|
||||
- });
|
||||
+ } // Paper
|
||||
return new Beardifier(objectList.iterator(), objectList2.iterator());
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: JRoy <joshroy126@gmail.com>
|
||||
Date: Wed, 1 Jul 2020 18:01:49 -0400
|
||||
Subject: [PATCH] Remove streams from classes related villager gossip
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
index 76dffb2705e5207db96895f82f1c7c5638f817c6..097007c1c25ba55d9916fc820dd1d1149d81f6f4 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
@@ -61,8 +61,22 @@ public class GossipContainer {
|
||||
});
|
||||
}
|
||||
|
||||
+ // Paper start - Remove streams from reputation
|
||||
+ private List<GossipContainer.GossipEntry> decompress() {
|
||||
+ List<GossipContainer.GossipEntry> list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
|
||||
+ for (Map.Entry<UUID, GossipContainer.EntityGossips> entry : this.gossips.entrySet()) {
|
||||
+ for (GossipContainer.GossipEntry cur : entry.getValue().decompress(entry.getKey())) {
|
||||
+ if (cur.weightedValue() != 0) {
|
||||
+ list.add(cur);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return list;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
private Collection<GossipContainer.GossipEntry> selectGossipsForTransfer(RandomSource random, int count) {
|
||||
- List<GossipContainer.GossipEntry> list = this.unpack().toList();
|
||||
+ List<GossipContainer.GossipEntry> list = this.decompress(); // Paper - Remove streams from reputation
|
||||
if (list.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
@@ -156,7 +170,7 @@ public class GossipContainer {
|
||||
}
|
||||
|
||||
public <T> T store(DynamicOps<T> ops) {
|
||||
- return GossipContainer.GossipEntry.LIST_CODEC.encodeStart(ops, this.unpack().toList()).resultOrPartial((error) -> {
|
||||
+ return GossipContainer.GossipEntry.LIST_CODEC.encodeStart(ops, this.decompress()).resultOrPartial((error) -> {
|
||||
LOGGER.warn("Failed to serialize gossips: {}", (Object)error);
|
||||
}).orElseGet(ops::emptyList);
|
||||
}
|
||||
@@ -184,11 +198,23 @@ public class GossipContainer {
|
||||
final Object2IntMap<GossipType> entries = new Object2IntOpenHashMap<>();
|
||||
|
||||
public int weightedValue(Predicate<GossipType> gossipTypeFilter) {
|
||||
- return this.entries.object2IntEntrySet().stream().filter((entry) -> {
|
||||
- return gossipTypeFilter.test(entry.getKey());
|
||||
- }).mapToInt((entry) -> {
|
||||
- return entry.getIntValue() * (entry.getKey()).weight;
|
||||
- }).sum();
|
||||
+ // Paper start - Remove streams from reputation
|
||||
+ int weight = 0;
|
||||
+ for (Object2IntMap.Entry<GossipType> entry : entries.object2IntEntrySet()) {
|
||||
+ if (gossipTypeFilter.test(entry.getKey())) {
|
||||
+ weight += entry.getIntValue() * entry.getKey().weight;
|
||||
+ }
|
||||
+ }
|
||||
+ return weight;
|
||||
+ }
|
||||
+
|
||||
+ public List<GossipContainer.GossipEntry> decompress(UUID uuid) {
|
||||
+ List<GossipContainer.GossipEntry> list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
|
||||
+ for (Object2IntMap.Entry<GossipType> entry : entries.object2IntEntrySet()) {
|
||||
+ list.add(new GossipContainer.GossipEntry(uuid, entry.getKey(), entry.getIntValue()));
|
||||
+ }
|
||||
+ return list;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public Stream<GossipContainer.GossipEntry> unpack(UUID target) {
|
83
patches/server/0425-Support-components-in-ItemMeta.patch
Normal file
83
patches/server/0425-Support-components-in-ItemMeta.patch
Normal file
|
@ -0,0 +1,83 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MiniDigger <admin@benndorf.dev>
|
||||
Date: Sat, 6 Jun 2020 18:13:42 +0200
|
||||
Subject: [PATCH] Support components in ItemMeta
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
index d1f21b5f5600dba41a93378853aadacd24f4a1f3..b34f364f8580ae900e25ef3f31f58f4e8fee88e0 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
@@ -877,11 +877,23 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
return CraftChatMessage.fromJSONComponent(displayName);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public net.md_5.bungee.api.chat.BaseComponent[] getDisplayNameComponent() {
|
||||
+ return displayName == null ? new net.md_5.bungee.api.chat.BaseComponent[0] : net.md_5.bungee.chat.ComponentSerializer.parse(displayName);
|
||||
+ }
|
||||
+ // Paper end
|
||||
@Override
|
||||
public final void setDisplayName(String name) {
|
||||
this.displayName = CraftChatMessage.fromStringOrNullToJSON(name);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void setDisplayNameComponent(net.md_5.bungee.api.chat.BaseComponent[] component) {
|
||||
+ this.displayName = net.md_5.bungee.chat.ComponentSerializer.toString(component);
|
||||
+ }
|
||||
+ // Paper end
|
||||
@Override
|
||||
public boolean hasDisplayName() {
|
||||
return this.displayName != null;
|
||||
@@ -1024,6 +1036,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
return this.lore == null ? null : new ArrayList<String>(Lists.transform(this.lore, CraftChatMessage::fromJSONComponent));
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public List<net.md_5.bungee.api.chat.BaseComponent[]> getLoreComponents() {
|
||||
+ return this.lore == null ? null : new ArrayList<>(this.lore.stream().map(entry ->
|
||||
+ net.md_5.bungee.chat.ComponentSerializer.parse(entry)
|
||||
+ ).collect(java.util.stream.Collectors.toList()));
|
||||
+ }
|
||||
+ // Paper end
|
||||
@Override
|
||||
public void setLore(List<String> lore) {
|
||||
if (lore == null || lore.isEmpty()) {
|
||||
@@ -1038,6 +1058,21 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void setLoreComponents(List<net.md_5.bungee.api.chat.BaseComponent[]> lore) {
|
||||
+ if (lore == null) {
|
||||
+ this.lore = null;
|
||||
+ } else {
|
||||
+ if (this.lore == null) {
|
||||
+ safelyAdd(lore, this.lore = new ArrayList<>(lore.size()), false);
|
||||
+ } else {
|
||||
+ this.lore.clear();
|
||||
+ safelyAdd(lore, this.lore, false);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
@Override
|
||||
public boolean hasCustomModelData() {
|
||||
return this.customModelData != null;
|
||||
@@ -1506,6 +1541,11 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
}
|
||||
|
||||
for (Object object : addFrom) {
|
||||
+ // Paper start - support components
|
||||
+ if(object instanceof net.md_5.bungee.api.chat.BaseComponent[]) {
|
||||
+ addTo.add(net.md_5.bungee.chat.ComponentSerializer.toString((net.md_5.bungee.api.chat.BaseComponent[]) object));
|
||||
+ } else
|
||||
+ // Paper end
|
||||
if (!(object instanceof String)) {
|
||||
if (object != null) {
|
||||
// SPIGOT-7399: Null check via if is important,
|
|
@ -0,0 +1,48 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Fri, 9 Dec 2022 03:10:23 -0800
|
||||
Subject: [PATCH] Improve/fix EntityTargetLivingEntityEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java b/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java
|
||||
index 5aeef564cdaabeed88a52635e56073cca3a9d1f1..fe635e46569c67dac1d3581ee930d1bfa8b4030e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java
|
||||
@@ -47,17 +47,30 @@ public class StopAttackingIfTargetInvalid {
|
||||
if (entityinsentient.canAttack(entityliving) && (!shouldForgetIfTargetUnreachable || !StopAttackingIfTargetInvalid.isTiredOfTryingToReachTarget(entityinsentient, behaviorbuilder_b.tryGet(memoryaccessor1))) && entityliving.isAlive() && entityliving.level() == entityinsentient.level() && !alternativeCondition.test(entityliving)) {
|
||||
return true;
|
||||
} else {
|
||||
+ // Paper start - better track target change reason
|
||||
+ final EntityTargetEvent.TargetReason reason;
|
||||
+ if (!entityinsentient.canAttack(entityliving)) {
|
||||
+ reason = EntityTargetEvent.TargetReason.TARGET_INVALID;
|
||||
+ } else if (shouldForgetIfTargetUnreachable && StopAttackingIfTargetInvalid.isTiredOfTryingToReachTarget(entityinsentient, behaviorbuilder_b.tryGet(memoryaccessor1))) {
|
||||
+ reason = EntityTargetEvent.TargetReason.FORGOT_TARGET;
|
||||
+ } else if (!entityliving.isAlive()) {
|
||||
+ reason = EntityTargetEvent.TargetReason.TARGET_DIED;
|
||||
+ } else if (entityliving.level() != entityinsentient.level()) {
|
||||
+ reason = EntityTargetEvent.TargetReason.TARGET_OTHER_LEVEL;
|
||||
+ } else {
|
||||
+ reason = EntityTargetEvent.TargetReason.TARGET_INVALID;
|
||||
+ }
|
||||
+ // Paper end
|
||||
// CraftBukkit start
|
||||
- LivingEntity old = entityinsentient.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).orElse(null);
|
||||
- EntityTargetEvent event = CraftEventFactory.callEntityTargetLivingEvent(entityinsentient, null, (old != null && !old.isAlive()) ? EntityTargetEvent.TargetReason.TARGET_DIED : EntityTargetEvent.TargetReason.FORGOT_TARGET);
|
||||
+ EntityTargetEvent event = CraftEventFactory.callEntityTargetLivingEvent(entityinsentient, null, reason); // Paper
|
||||
if (event.isCancelled()) {
|
||||
return false;
|
||||
}
|
||||
- if (event.getTarget() == null) {
|
||||
- memoryaccessor.erase();
|
||||
- return true;
|
||||
- }
|
||||
- entityliving = ((CraftLivingEntity) event.getTarget()).getHandle();
|
||||
+ // if (event.getTarget() == null) { // Paper - this is wrong, you are skipping the forgetCallback
|
||||
+ // memoryaccessor.erase();
|
||||
+ // return true;
|
||||
+ // }
|
||||
+ // entityliving = ((CraftLivingEntity) event.getTarget()).getHandle();
|
||||
// CraftBukkit end
|
||||
forgetCallback.accept(entityinsentient, entityliving);
|
||||
memoryaccessor.erase();
|
54
patches/server/0427-Add-entity-liquid-API.patch
Normal file
54
patches/server/0427-Add-entity-liquid-API.patch
Normal file
|
@ -0,0 +1,54 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Thu, 2 Jul 2020 18:11:43 -0500
|
||||
Subject: [PATCH] Add entity liquid API
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.Entity isInRain()Z
|
||||
public net.minecraft.world.entity.Entity isInBubbleColumn()Z
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
index c7cd18de51c5e7c9d194ba65902084194d4408ec..91d199250d856baa869258282bb04ed5897b14e9 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
@@ -1312,5 +1312,40 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason getEntitySpawnReason() {
|
||||
return getHandle().spawnReason;
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isUnderWater() {
|
||||
+ return getHandle().isUnderWater();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isInRain() {
|
||||
+ return getHandle().isInRain();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isInBubbleColumn() {
|
||||
+ return getHandle().isInBubbleColumn();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isInWaterOrRain() {
|
||||
+ return getHandle().isInWaterOrRain();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isInWaterOrBubbleColumn() {
|
||||
+ return getHandle().isInWaterOrBubble();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isInWaterOrRainOrBubbleColumn() {
|
||||
+ return getHandle().isInWaterRainOrBubble();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isInLava() {
|
||||
+ return getHandle().isInLava();
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue