even moar patches
This commit is contained in:
parent
44e22b45a5
commit
c31a22c563
25 changed files with 80 additions and 80 deletions
31
patches/server/0376-Villager-Restocks-API.patch
Normal file
31
patches/server/0376-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 87d9cd989be932cf3eb9e777cbc2d2246ccf9d9a..350cfc1526894f4dac56832a6d1dfbbc9b25123c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
@@ -92,6 +92,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 093eaae15344b39e217978e4c0bdbc37b83f6799..3c0f15d294891143624ac7feadb09c3f8de3059e 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -960,7 +960,14 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
@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/0378-Expose-game-version.patch
Normal file
24
patches/server/0378-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 7f4ee248bede39701365d200cdc4e39f7bdd8b26..db932976919ae8a2a258b61d386e6a5c54fe7be4 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -577,6 +577,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/0379-Optimize-Voxel-Shape-Merging.patch
Normal file
121
patches/server/0379-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 203a25a2a8d843c33440d849a94b85e2c717d2a0..9f1b363e1a6fa4925dc4560654af8426e6908c9d 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/0381-misc-debugging-dumps.patch
Normal file
87
patches/server/0381-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 d7428c963fc369e04926a5987653ea5bd325d51d..260fbcafbb4c2049372ea57451d22479e4a3addd 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -880,6 +880,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) {
|
||||
@@ -894,6 +895,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
|
||||
@@ -1025,6 +1027,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/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index 0c7f280bae81bbb492d5780a43e5ffda0f58756a..238a7bc87ab49da1f0fa3c733dd512fdffbd8ffc 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -183,6 +183,11 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
} catch (Exception exception) {
|
||||
ServerLoginPacketListenerImpl.LOGGER.error("Couldn't place player in world", exception);
|
||||
MutableComponent ichatmutablecomponent = Component.translatable("multiplayer.disconnect.invalid_player_data");
|
||||
+ // Paper start
|
||||
+ if (MinecraftServer.getServer().isDebugging()) {
|
||||
+ exception.printStackTrace();
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
this.connection.send(new ClientboundDisconnectPacket(ichatmutablecomponent));
|
||||
this.connection.disconnect(ichatmutablecomponent);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index db932976919ae8a2a258b61d386e6a5c54fe7be4..067457ff4f108a5725021cc2a9c501f5e9500307 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1015,6 +1015,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/0382-Prevent-teleporting-dead-entities.patch
Normal file
24
patches/server/0382-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 3c0f15d294891143624ac7feadb09c3f8de3059e..a9cdf3e774dbc8b689c7bbd95d94c8be32b33d92 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1605,6 +1605,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
}
|
||||
|
||||
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,664 @@
|
|||
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 d86a4eebb4fd4144d762407aaccc7de497d0a5c1..16739eb5fc89fce4a77ad84387c785a5d41a9df2 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -19,6 +19,7 @@ dependencies {
|
||||
Scanning takes about 1-2 seconds so adding this speeds up the server start.
|
||||
*/
|
||||
implementation("org.apache.logging.log4j:log4j-core:2.14.1") // Paper - implementation
|
||||
+ annotationProcessor("org.apache.logging.log4j:log4j-core:2.14.1") // Paper - Needed to generate meta for our Log4j plugins
|
||||
// Paper end
|
||||
implementation("org.apache.logging.log4j:log4j-iostreams:2.19.0") // Paper - remove exclusion
|
||||
implementation("org.ow2.asm:asm:9.4")
|
||||
@@ -26,6 +27,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.42.0.0")
|
||||
runtimeOnly("com.mysql:mysql-connector-j:8.0.33")
|
||||
runtimeOnly("com.lmax:disruptor:3.4.4") // Paper
|
||||
@@ -105,6 +107,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/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/logging/StacktraceDeobfuscatingRewritePolicy.java b/src/main/java/io/papermc/paper/logging/StacktraceDeobfuscatingRewritePolicy.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..c701ef3c287f62aa0ebfbdbd6da6ed82a1c7793c
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/logging/StacktraceDeobfuscatingRewritePolicy.java
|
||||
@@ -0,0 +1,38 @@
|
||||
+package io.papermc.paper.logging;
|
||||
+
|
||||
+import io.papermc.paper.util.StacktraceDeobfuscator;
|
||||
+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 StacktraceDeobfuscatingRewritePolicy() {
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @NonNull LogEvent rewrite(final @NonNull LogEvent rewrite) {
|
||||
+ final Throwable thrown = rewrite.getThrown();
|
||||
+ if (thrown != null) {
|
||||
+ StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(thrown);
|
||||
+ return new Log4jLogEvent.Builder(rewrite)
|
||||
+ .setThrownProxy(null)
|
||||
+ .build();
|
||||
+ }
|
||||
+ return rewrite;
|
||||
+ }
|
||||
+
|
||||
+ @PluginFactory
|
||||
+ public static @NonNull StacktraceDeobfuscatingRewritePolicy createPolicy() {
|
||||
+ return new StacktraceDeobfuscatingRewritePolicy();
|
||||
+ }
|
||||
+}
|
||||
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 30a58229aa6dac5039511d0c0df5f2912ea7de9f..abe37c7c3c6f5ab73afd738ec78f06d7e4d2ed96 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 7e11cf7d6871b6125ccccae2b765cd4dfcf38d3b..e857327b796455953e76ddf70913c37a3f1e2ee2 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -64,13 +64,13 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
});
|
||||
public static final AttributeKey<ConnectionProtocol> ATTRIBUTE_PROTOCOL = AttributeKey.valueOf("protocol");
|
||||
public static final LazyLoadedValue<NioEventLoopGroup> NETWORK_WORKER_GROUP = new LazyLoadedValue<>(() -> {
|
||||
- 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 LazyLoadedValue<EpollEventLoopGroup> NETWORK_EPOLL_WORKER_GROUP = new LazyLoadedValue<>(() -> {
|
||||
- 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 LazyLoadedValue<DefaultEventLoopGroup> LOCAL_WORKER_GROUP = new LazyLoadedValue<>(() -> {
|
||||
- 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<Connection.PacketHolder> queue = Queues.newConcurrentLinkedQueue();
|
||||
@@ -172,7 +172,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 eef9206a9d6a398eb1d44a36b6a1a342ed7bc878..9d2eb13130d3b68fd0ca07243a3a41735f89c7b2 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 a25d46fc3e2a106ab94c6b2b49558dd7be11c5b9..8cdb2bdd404f2f091493bb7a93f62f764a8e511b 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/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
index 776528e50a5abc0e02d9de99231fb47352aa4f43..4017c15a62ce1048a61f55f46f915fd516496181 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
@@ -51,10 +51,10 @@ public class ServerConnectionListener {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public static final LazyLoadedValue<NioEventLoopGroup> SERVER_EVENT_GROUP = new LazyLoadedValue<>(() -> {
|
||||
- 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 LazyLoadedValue<EpollEventLoopGroup> SERVER_EPOLL_EVENT_GROUP = new LazyLoadedValue<>(() -> {
|
||||
- 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/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index 238a7bc87ab49da1f0fa3c733dd512fdffbd8ffc..9858f907e58fa606510f87efbdf8793c35ec711c 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -185,7 +185,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
MutableComponent ichatmutablecomponent = Component.translatable("multiplayer.disconnect.invalid_player_data");
|
||||
// Paper start
|
||||
if (MinecraftServer.getServer().isDebugging()) {
|
||||
- exception.printStackTrace();
|
||||
+ io.papermc.paper.util.TraceUtil.printStackTrace(exception);
|
||||
}
|
||||
// Paper end
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/OldUsersConverter.java b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
index 6599f874d9f97e9ef4862039ecad7277bbc5fd91..7edd4b88eb0476f0630630bc4681e859bd145b2b 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
@@ -364,7 +364,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
|
||||
}
|
||||
|
||||
@@ -378,7 +378,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 cb8166771b57bb4dd7e64150bd02e8944307783f..04d0e2db1bb38700a1bc210296d7f8bfdd3aead5 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 29b315188e3deb994b45b2154b2ce4f17c4fde2d..571d80ca3e85fc108137b317ed1033ca4714718e 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 );
|
||||
}
|
||||
@@ -192,7 +192,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 d285dbec16272db6b8a71865e05924ad66087407..1a05d23ff886b015fb9396f119822c678a47ec6f 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/0384-Implement-Mob-Goal-API.patch
Normal file
918
patches/server/0384-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 16739eb5fc89fce4a77ad84387c785a5d41a9df2..bc71323234b69a07ac84703c04734711ca0dd113 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -36,6 +36,7 @@ dependencies {
|
||||
runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.10")
|
||||
runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.10")
|
||||
|
||||
+ 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 067457ff4f108a5725021cc2a9c501f5e9500307..b31657b4dd8ea2c8c3a4fb51ad37067118983d05 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2758,5 +2758,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/0385-Add-villager-reputation-API.patch
Normal file
122
patches/server/0385-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 350cfc1526894f4dac56832a6d1dfbbc9b25123c..e6fcdbabde66f4707627fc8c3012aa20de8e34e3 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java
|
||||
@@ -18,6 +18,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) {
|
||||
@@ -147,4 +154,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 4a1699b56f2111881653404b38f18c9e2e7473b4..3f6d9c6b88e14135917bdfe5e5df019213dde325 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -648,16 +648,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/0387-ExperienceOrbMergeEvent.patch
Normal file
23
patches/server/0387-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 3f6d9c6b88e14135917bdfe5e5df019213dde325..7af0710c40c1453bd0bd8ecb4ea7606bbe76c20f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -658,7 +658,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/0388-Fix-PotionEffect-ignores-icon-flag.patch
Normal file
19
patches/server/0388-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 c5784574f584a5588020b16776f01faf6902cbe8..658d4dbb45d17e7064f69b10af8fbfa473a8dffe 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
|
||||
@@ -431,7 +431,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
|
||||
|
||||
@Override
|
||||
public boolean addPotionEffect(PotionEffect effect, boolean force) {
|
||||
- this.getHandle().addEffect(new MobEffectInstance(MobEffect.byId(effect.getType().getId()), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles()), EntityPotionEffectEvent.Cause.PLUGIN);
|
||||
+ this.getHandle().addEffect(new MobEffectInstance(MobEffect.byId(effect.getType().getId()), 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/0390-Potential-bed-API.patch
Normal file
44
patches/server/0390-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 ed6d7743ab6513ee4f4c09eae1c7124197df4ed1..2d3a7bb9f68350df136ee3d2e3aed0bbbe1a91cc 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 260fbcafbb4c2049372ea57451d22479e4a3addd..49283b13a88402ac5b54fd8c64e90a82499d09d7 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -920,6 +920,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// CraftBukkit start
|
||||
if (this.server != null) {
|
||||
this.server.disablePlugins();
|
||||
+ this.server.waitForAsyncTasksShutdown(); // Paper
|
||||
}
|
||||
// CraftBukkit end
|
||||
if (this.getConnection() != null) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index b31657b4dd8ea2c8c3a4fb51ad37067118983d05..cd04bdf3637584b6ea7298b5d833d4a71ce427ff 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1025,6 +1025,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 d8834abadc82617a2d09506432102211ea99b0b7..11a999182fd561611b3399d93ce9e2565cd4332a 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 75d827f1eecb24f7ab985bdea2bbf65b8478fc8c..d646660f988994d4fdb05901349c5946a2f6c48c 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
@@ -168,6 +168,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)) {
|
||||
@@ -369,7 +370,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 cde79f2001904852159cc4ed8a42e9b5aac74851..4aad91def765910d6e8820cb92a288a304a17b5b 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -432,6 +432,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 9e70f5ba6ff0935d245f357131b062c1cc7058fc..4f6b7ed4809086811f0460544ba2ec0606f0f5da 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 2451bb61e304fbe5cdfd6bbb248575e9e1135075..74f84bfcb1da6186c7a6783512c2fc7ba995215f 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 389b63605d416678d35666bbd46e0fa05a02f898..33a6fda1e8f2df61b44f0e3ddda356ffa386f2df 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;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 27 Apr 2020 00:04:16 -0700
|
||||
Subject: [PATCH] Reduce allocation of Vec3D by entity tracker
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java b/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java
|
||||
index 05ac41e136da43284fb24a6b698ebd36318278fb..5ca3ad7b3d7606accd0a58b3c708fadb349608f7 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/game/VecDeltaCodec.java
|
||||
@@ -5,7 +5,7 @@ import org.jetbrains.annotations.VisibleForTesting;
|
||||
|
||||
public class VecDeltaCodec {
|
||||
private static final double TRUNCATION_STEPS = 4096.0D;
|
||||
- private Vec3 base = Vec3.ZERO;
|
||||
+ public Vec3 base = Vec3.ZERO; // Paper
|
||||
|
||||
@VisibleForTesting
|
||||
static long encode(double value) {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 3616f106b8bd5824700bfb67678599e6e1eca712..b312094bc88cd981fb424c244896c4c1d6454698 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1877,9 +1877,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
public void updatePlayer(ServerPlayer player) {
|
||||
org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot
|
||||
if (player != this.entity) {
|
||||
- Vec3 vec3d = player.position().subtract(this.entity.position());
|
||||
+ // Paper start - remove allocation of Vec3D here
|
||||
+ // Vec3 vec3d = player.position().subtract(this.entity.position());
|
||||
+ double vec3d_dx = player.getX() - this.entity.getX();
|
||||
+ double vec3d_dz = player.getZ() - this.entity.getZ();
|
||||
+ // Paper end - remove allocation of Vec3D here
|
||||
double d0 = (double) Math.min(this.getEffectiveRange(), ChunkMap.this.viewDistance * 16);
|
||||
- double d1 = vec3d.x * vec3d.x + vec3d.z * vec3d.z;
|
||||
+ double d1 = vec3d_dx * vec3d_dx + vec3d_dz * vec3d_dz; // Paper
|
||||
double d2 = d0 * d0;
|
||||
boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(player);
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
index 5ec480397fb043717c63961651f7c62440e57201..3f3c7ced3a43e2b0eb451930c09188e3706a1bee 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -161,7 +161,13 @@ public class ServerEntity {
|
||||
i = Mth.floor(this.entity.getYRot() * 256.0F / 360.0F);
|
||||
j = Mth.floor(this.entity.getXRot() * 256.0F / 360.0F);
|
||||
Vec3 vec3d = this.entity.trackingPosition();
|
||||
- boolean flag1 = this.positionCodec.delta(vec3d).lengthSqr() >= 7.62939453125E-6D;
|
||||
+ // Paper start - reduce allocation of Vec3D here
|
||||
+ Vec3 base = this.positionCodec.base;
|
||||
+ double vec3d_dx = vec3d.x - base.x;
|
||||
+ double vec3d_dy = vec3d.y - base.y;
|
||||
+ double vec3d_dz = vec3d.z - base.z;
|
||||
+ boolean flag1 = (vec3d_dx * vec3d_dx + vec3d_dy * vec3d_dy + vec3d_dz * vec3d_dz) >= 7.62939453125E-6D;
|
||||
+ // Paper end - reduce allocation of Vec3D here
|
||||
Packet<?> packet1 = null;
|
||||
boolean flag2 = flag1 || this.tickCount % 60 == 0;
|
||||
boolean flag3 = Math.abs(i - this.yRotp) >= 1 || Math.abs(j - this.xRotp) >= 1;
|
26
patches/server/0395-Ensure-safe-gateway-teleport.patch
Normal file
26
patches/server/0395-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 11f9b40d0cfb77d69ecd2c7ef71dc409d1d79eba..d9baa85962236c42219cf09d4f3129be93ff069c 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
|
||||
@@ -106,7 +106,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 a6612cc0ea87aeb8e87521ff7b5fe58c7b06b9ef..dfc15cfd897316f64a063b8ae93a0882ab5b3993 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/command/CraftRemoteConsoleCommandSender.java
|
||||
@@ -45,4 +45,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 67f34a1670cb51a3d2aca3140800ad9b92533d84..dc5908374565dd3080679779cbfe7620a4810015 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/trading/MerchantOffer.java
|
||||
@@ -115,7 +115,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/0398-Maps-shouldn-t-load-chunks.patch
Normal file
32
patches/server/0398-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 9b55b04ab2769c6089d16a9c7bc61ca41683559f..7a5e5fa67ed5625cfbe74ba8ea8810095100e836 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 7a5e5fa67ed5625cfbe74ba8ea8810095100e836..75b110c6fb685390306fe3b8504aeea9bd6deedd 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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue