diff --git a/patches/api/0003-Test-changes.patch b/patches/api/0003-Test-changes.patch index 08d0ec7654..9c96414a6b 100644 --- a/patches/api/0003-Test-changes.patch +++ b/patches/api/0003-Test-changes.patch @@ -288,12 +288,12 @@ index 4ac3dd977e75cd8464163351d306e037ee32cb48..c26ea217927ba77611e6ae93f8df50a8 + return true; + } + } - -- private static boolean isWellAnnotated(@Nullable List annotations) { ++ + return false; + } + // Paper end -+ + +- private static boolean isWellAnnotated(@Nullable List annotations) { + private static boolean isWellAnnotated(@Nullable List annotations) { // Paper if (annotations == null) { return false; diff --git a/patches/api/0005-Adventure.patch b/patches/api/0005-Adventure.patch index aba39bbe77..b7ee529c68 100644 --- a/patches/api/0005-Adventure.patch +++ b/patches/api/0005-Adventure.patch @@ -939,21 +939,21 @@ index 446e4d21c5b9b624e633875df62160a7351517d9..16ec0cd908659d6d53e565281b8db9f8 } + // Paper start - /** - * Gets the default message that is displayed when the server is stopped. - * - * @return the shutdown message - */ -+ public static net.kyori.adventure.text.@Nullable Component shutdownMessage() { -+ return server.shutdownMessage(); -+ } -+ // Paper end + /** + * Gets the default message that is displayed when the server is stopped. + * + * @return the shutdown message -+ * @deprecated in favour of {@link #shutdownMessage()} + */ ++ public static net.kyori.adventure.text.@Nullable Component shutdownMessage() { ++ return server.shutdownMessage(); ++ } ++ // Paper end + /** + * Gets the default message that is displayed when the server is stopped. + * + * @return the shutdown message ++ * @deprecated in favour of {@link #shutdownMessage()} + */ @Nullable + @Deprecated // Paper public static String getShutdownMessage() { @@ -1233,21 +1233,11 @@ index 52dd3148ae2a3480982593dc627ef7eede52bc5a..0a333c1439b3623d38029b88ce6d5ff1 Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, @NotNull String title); /** -@@ -1151,6 +1209,7 @@ public interface Server extends PluginMessageRecipient { +@@ -1151,6 +1209,22 @@ public interface Server extends PluginMessageRecipient { @NotNull Inventory createInventory(@Nullable InventoryHolder owner, int size) throws IllegalArgumentException; + // Paper start - /** - * Creates an empty inventory of type {@link InventoryType#CHEST} with the - * specified size and title. -@@ -1163,8 +1222,26 @@ public interface Server extends PluginMessageRecipient { - * @throws IllegalArgumentException if the size is not a multiple of 9 - */ - @NotNull -+ Inventory createInventory(@Nullable InventoryHolder owner, int size, net.kyori.adventure.text.@NotNull Component title) throws IllegalArgumentException; -+ // Paper end -+ + /** + * Creates an empty inventory of type {@link InventoryType#CHEST} with the + * specified size and title. @@ -1258,10 +1248,22 @@ index 52dd3148ae2a3480982593dc627ef7eede52bc5a..0a333c1439b3623d38029b88ce6d5ff1 + * viewed + * @return a new inventory + * @throws IllegalArgumentException if the size is not a multiple of 9 -+ * @deprecated in favour of {@link #createInventory(InventoryHolder, int, net.kyori.adventure.text.Component)} + */ -+ @Deprecated // Paper + @NotNull ++ Inventory createInventory(@Nullable InventoryHolder owner, int size, net.kyori.adventure.text.@NotNull Component title) throws IllegalArgumentException; ++ // Paper end ++ + /** + * Creates an empty inventory of type {@link InventoryType#CHEST} with the + * specified size and title. +@@ -1161,10 +1235,13 @@ public interface Server extends PluginMessageRecipient { + * viewed + * @return a new inventory + * @throws IllegalArgumentException if the size is not a multiple of 9 ++ * @deprecated in favour of {@link #createInventory(InventoryHolder, int, net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + @NotNull Inventory createInventory(@Nullable InventoryHolder owner, int size, @NotNull String title) throws IllegalArgumentException; + // Paper start @@ -1311,19 +1313,19 @@ index 52dd3148ae2a3480982593dc627ef7eede52bc5a..0a333c1439b3623d38029b88ce6d5ff1 String getMotd(); + // Paper start - /** - * Gets the default message that is displayed when the server is stopped. - * - * @return the shutdown message - */ -+ net.kyori.adventure.text.@Nullable Component shutdownMessage(); -+ // Paper end + /** + * Gets the default message that is displayed when the server is stopped. + * + * @return the shutdown message -+ * @deprecated in favour of {@link #shutdownMessage()} + */ ++ net.kyori.adventure.text.@Nullable Component shutdownMessage(); ++ // Paper end + /** + * Gets the default message that is displayed when the server is stopped. + * + * @return the shutdown message ++ * @deprecated in favour of {@link #shutdownMessage()} + */ @Nullable + @Deprecated // Paper String getShutdownMessage(); @@ -1517,53 +1519,18 @@ diff --git a/src/main/java/org/bukkit/block/Sign.java b/src/main/java/org/bukkit index ab6b0ec328e94bf65a0dafd0403e5ee3b870296c..f87bdb2757760d95038d1a1cf6e7f5b2cff91432 100644 --- a/src/main/java/org/bukkit/block/Sign.java +++ b/src/main/java/org/bukkit/block/Sign.java -@@ -7,14 +7,14 @@ import org.jetbrains.annotations.NotNull; +@@ -7,13 +7,48 @@ import org.jetbrains.annotations.NotNull; * Represents a captured state of either a SignPost or a WallSign. */ public interface Sign extends TileState, Colorable { -- + // Paper start - /** - * Gets all the lines of text currently on this sign. - * - * @return Array of Strings containing each line of text - */ - @NotNull -- public String[] getLines(); -+ public java.util.List lines(); - - /** - * Gets the line of text at the specified index. -@@ -22,11 +22,11 @@ public interface Sign extends TileState, Colorable { - * For example, getLine(0) will return the first line of text. - * - * @param index Line number to get the text from, starting at 0 -- * @return Text on the given line - * @throws IndexOutOfBoundsException Thrown when the line does not exist -+ * @return Text on the given line - */ - @NotNull -- public String getLine(int index) throws IndexOutOfBoundsException; -+ public net.kyori.adventure.text.Component line(int index) throws IndexOutOfBoundsException; - - /** - * Sets the line of text at the specified index. -@@ -38,6 +38,45 @@ public interface Sign extends TileState, Colorable { - * @param line New text to set at the specified index - * @throws IndexOutOfBoundsException If the index is out of the range 0..3 - */ -+ public void line(int index, net.kyori.adventure.text.@NotNull Component line) throws IndexOutOfBoundsException; -+ // Paper end -+ + /** + * Gets all the lines of text currently on this sign. + * + * @return Array of Strings containing each line of text -+ * @deprecated in favour of {@link #lines()} + */ + @NotNull -+ @Deprecated // Paper -+ public String[] getLines(); ++ public java.util.List lines(); + + /** + * Gets the line of text at the specified index. @@ -1571,13 +1538,11 @@ index ab6b0ec328e94bf65a0dafd0403e5ee3b870296c..f87bdb2757760d95038d1a1cf6e7f5b2 + * For example, getLine(0) will return the first line of text. + * + * @param index Line number to get the text from, starting at 0 -+ * @return Text on the given line + * @throws IndexOutOfBoundsException Thrown when the line does not exist -+ * @deprecated in favour of {@link #line(int)} ++ * @return Text on the given line + */ + @NotNull -+ @Deprecated // Paper -+ public String getLine(int index) throws IndexOutOfBoundsException; ++ public net.kyori.adventure.text.Component line(int index) throws IndexOutOfBoundsException; + + /** + * Sets the line of text at the specified index. @@ -1588,8 +1553,38 @@ index ab6b0ec328e94bf65a0dafd0403e5ee3b870296c..f87bdb2757760d95038d1a1cf6e7f5b2 + * @param index Line number to set the text at, starting from 0 + * @param line New text to set at the specified index + * @throws IndexOutOfBoundsException If the index is out of the range 0..3 -+ * @deprecated in favour of {@link #line(int, net.kyori.adventure.text.Component)} + */ ++ public void line(int index, net.kyori.adventure.text.@NotNull Component line) throws IndexOutOfBoundsException; ++ // Paper end + + /** + * Gets all the lines of text currently on this sign. + * + * @return Array of Strings containing each line of text ++ * @deprecated in favour of {@link #lines()} + */ + @NotNull ++ @Deprecated // Paper + public String[] getLines(); + + /** +@@ -24,8 +59,10 @@ public interface Sign extends TileState, Colorable { + * @param index Line number to get the text from, starting at 0 + * @return Text on the given line + * @throws IndexOutOfBoundsException Thrown when the line does not exist ++ * @deprecated in favour of {@link #line(int)} + */ + @NotNull ++ @Deprecated // Paper + public String getLine(int index) throws IndexOutOfBoundsException; + + /** +@@ -37,7 +74,9 @@ public interface Sign extends TileState, Colorable { + * @param index Line number to set the text at, starting from 0 + * @param line New text to set at the specified index + * @throws IndexOutOfBoundsException If the index is out of the range 0..3 ++ * @deprecated in favour of {@link #line(int, net.kyori.adventure.text.Component)} + */ + @Deprecated // Paper public void setLine(int index, @NotNull String line) throws IndexOutOfBoundsException; @@ -2132,29 +2127,47 @@ index c60e1fc1cad1b9889a508602df84840723b7b966..fbf56bcc4540f7f1a8ced7cc2cd96e29 /** * Says a message (or runs a command). * -@@ -573,6 +659,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM +@@ -573,6 +659,90 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM */ public void sendEquipmentChange(@NotNull LivingEntity entity, @NotNull Map items); + // Paper start - /** - * Send a sign change. This fakes a sign change packet for a user at - * a certain location. This will not actually change the world in any way. -@@ -588,7 +675,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * @throws IllegalArgumentException if location is null - * @throws IllegalArgumentException if lines is non-null and has a length less than 4 - */ -- public void sendSignChange(@NotNull Location loc, @Nullable String[] lines) throws IllegalArgumentException; ++ /** ++ * Send a sign change. This fakes a sign change packet for a user at ++ * a certain location. This will not actually change the world in any way. ++ * This method will use a sign at the location's block or a faked sign ++ * sent via ++ * {@link #sendBlockChange(org.bukkit.Location, org.bukkit.Material, byte)}. ++ *

++ * If the client does not have a sign at the given location it will ++ * display an error message to the user. ++ * ++ * @param loc the location of the sign ++ * @param lines the new text on the sign or null to clear it ++ * @throws IllegalArgumentException if location is null ++ * @throws IllegalArgumentException if lines is non-null and has a length less than 4 ++ */ + default void sendSignChange(@NotNull Location loc, @Nullable java.util.List lines) throws IllegalArgumentException { + this.sendSignChange(loc, lines, DyeColor.BLACK); + } - - /** - * Send a sign change. This fakes a sign change packet for a user at -@@ -607,6 +696,91 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * @throws IllegalArgumentException if dyeColor is null - * @throws IllegalArgumentException if lines is non-null and has a length less than 4 - */ ++ ++ /** ++ * Send a sign change. This fakes a sign change packet for a user at ++ * a certain location. This will not actually change the world in any way. ++ * This method will use a sign at the location's block or a faked sign ++ * sent via ++ * {@link #sendBlockChange(org.bukkit.Location, org.bukkit.Material, byte)}. ++ *

++ * If the client does not have a sign at the given location it will ++ * display an error message to the user. ++ * ++ * @param loc the location of the sign ++ * @param lines the new text on the sign or null to clear it ++ * @param dyeColor the color of the sign ++ * @throws IllegalArgumentException if location is null ++ * @throws IllegalArgumentException if dyeColor is null ++ * @throws IllegalArgumentException if lines is non-null and has a length less than 4 ++ */ + default void sendSignChange(@NotNull Location loc, @Nullable java.util.List lines, @NotNull DyeColor dyeColor) throws IllegalArgumentException { + this.sendSignChange(loc, lines, dyeColor, false); + } @@ -2202,43 +2215,25 @@ index c60e1fc1cad1b9889a508602df84840723b7b966..fbf56bcc4540f7f1a8ced7cc2cd96e29 + throws IllegalArgumentException; + // Paper end + -+ /** -+ * Send a sign change. This fakes a sign change packet for a user at -+ * a certain location. This will not actually change the world in any way. -+ * This method will use a sign at the location's block or a faked sign -+ * sent via -+ * {@link #sendBlockChange(org.bukkit.Location, org.bukkit.Material, byte)}. -+ *

-+ * If the client does not have a sign at the given location it will -+ * display an error message to the user. -+ * -+ * @param loc the location of the sign -+ * @param lines the new text on the sign or null to clear it -+ * @throws IllegalArgumentException if location is null -+ * @throws IllegalArgumentException if lines is non-null and has a length less than 4 + /** + * Send a sign change. This fakes a sign change packet for a user at + * a certain location. This will not actually change the world in any way. +@@ -587,7 +757,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param lines the new text on the sign or null to clear it + * @throws IllegalArgumentException if location is null + * @throws IllegalArgumentException if lines is non-null and has a length less than 4 + * @deprecated in favour of {@link #sendSignChange(org.bukkit.Location, java.util.List)} -+ */ + */ + @Deprecated // Paper -+ public void sendSignChange(@NotNull Location loc, @Nullable String[] lines) throws IllegalArgumentException; -+ -+ /** -+ * Send a sign change. This fakes a sign change packet for a user at -+ * a certain location. This will not actually change the world in any way. -+ * This method will use a sign at the location's block or a faked sign -+ * sent via -+ * {@link #sendBlockChange(org.bukkit.Location, org.bukkit.Material, byte)}. -+ *

-+ * If the client does not have a sign at the given location it will -+ * display an error message to the user. -+ * -+ * @param loc the location of the sign -+ * @param lines the new text on the sign or null to clear it -+ * @param dyeColor the color of the sign -+ * @throws IllegalArgumentException if location is null -+ * @throws IllegalArgumentException if dyeColor is null -+ * @throws IllegalArgumentException if lines is non-null and has a length less than 4 + public void sendSignChange(@NotNull Location loc, @Nullable String[] lines) throws IllegalArgumentException; + + /** +@@ -606,7 +778,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @throws IllegalArgumentException if location is null + * @throws IllegalArgumentException if dyeColor is null + * @throws IllegalArgumentException if lines is non-null and has a length less than 4 + * @deprecated in favour of {@link #sendSignChange(org.bukkit.Location, java.util.List, org.bukkit.DyeColor)} -+ */ + */ + @Deprecated // Paper public void sendSignChange(@NotNull Location loc, @Nullable String[] lines, @NotNull DyeColor dyeColor) throws IllegalArgumentException; @@ -2261,7 +2256,7 @@ index c60e1fc1cad1b9889a508602df84840723b7b966..fbf56bcc4540f7f1a8ced7cc2cd96e29 * @param url The URL from which the client will download the resource * pack. The string must contain only US-ASCII characters and should * be encoded as per RFC 1738. -@@ -1145,8 +1322,57 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM +@@ -1145,8 +1322,10 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * @throws IllegalArgumentException Thrown if the hash is not 20 bytes * long. */ @@ -2269,6 +2264,25 @@ index c60e1fc1cad1b9889a508602df84840723b7b966..fbf56bcc4540f7f1a8ced7cc2cd96e29 public void setResourcePack(@NotNull String url, @Nullable byte[] hash, @Nullable String prompt); + // Paper start + /** + * Request that the player's client download and switch resource packs. + *

+@@ -1182,6 +1361,54 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param hash The sha1 hash sum of the resource pack file which is used + * to apply a cached version of the pack directly without downloading + * if it is available. Hast to be 20 bytes long! ++ * @param prompt The optional custom prompt message to be shown to client. ++ * @throws IllegalArgumentException Thrown if the URL is null. ++ * @throws IllegalArgumentException Thrown if the URL is too long. The ++ * length restriction is an implementation specific arbitrary value. ++ * @throws IllegalArgumentException Thrown if the hash is not 20 bytes ++ * long. ++ */ ++ default void setResourcePack(@NotNull String url, byte @Nullable [] hash, net.kyori.adventure.text.@Nullable Component prompt) { ++ this.setResourcePack(url, hash, prompt, false); ++ } ++ // Paper end ++ + /** + * Request that the player's client download and switch resource packs. + *

@@ -2298,35 +2312,16 @@ index c60e1fc1cad1b9889a508602df84840723b7b966..fbf56bcc4540f7f1a8ced7cc2cd96e29 + * pack correctly. + * + * ++ * @deprecated in favour of {@link #setResourcePack(String, byte[], Component, boolean)} + * @param url The URL from which the client will download the resource + * pack. The string must contain only US-ASCII characters and should + * be encoded as per RFC 1738. + * @param hash The sha1 hash sum of the resource pack file which is used + * to apply a cached version of the pack directly without downloading + * if it is available. Hast to be 20 bytes long! -+ * @param prompt The optional custom prompt message to be shown to client. -+ * @throws IllegalArgumentException Thrown if the URL is null. -+ * @throws IllegalArgumentException Thrown if the URL is too long. The -+ * length restriction is an implementation specific arbitrary value. -+ * @throws IllegalArgumentException Thrown if the hash is not 20 bytes -+ * long. -+ */ -+ default void setResourcePack(@NotNull String url, byte @Nullable [] hash, net.kyori.adventure.text.@Nullable Component prompt) { -+ this.setResourcePack(url, hash, prompt, false); -+ } -+ // Paper end -+ - /** - * Request that the player's client download and switch resource packs. - *

-@@ -1176,6 +1402,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - * pack correctly. - * - * -+ * @deprecated in favour of {@link #setResourcePack(String, byte[], Component, boolean)} - * @param url The URL from which the client will download the resource - * pack. The string must contain only US-ASCII characters and should - * be encoded as per RFC 1738. + * @param force If true, the client will be disconnected from the server + * when it declines to use the resource pack. + * @throws IllegalArgumentException Thrown if the URL is null. @@ -1236,8 +1463,57 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * @throws IllegalArgumentException Thrown if the hash is not 20 bytes * long. @@ -2587,55 +2582,18 @@ index 7190db11eff7d48df8a99f405a9dbaefdfa76e3d..c40536f781393cb39e6a1a4ba6e78071 } /** -@@ -34,14 +47,14 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { +@@ -34,14 +47,52 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { return player; } + // Paper start - /** - * Gets all of the lines of text from the sign involved in this event. - * - * @return the String array for the sign's lines new text - */ -- @NotNull -- public String[] getLines() { -- return lines; -+ public @NotNull java.util.List lines() { -+ return this.adventure$lines; - } - - /** -@@ -53,9 +66,8 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { - * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 - * or < 0} - */ -- @Nullable -- public String getLine(int index) throws IndexOutOfBoundsException { -- return lines[index]; -+ public net.kyori.adventure.text.@Nullable Component line(int index) throws IndexOutOfBoundsException { -+ return this.adventure$lines.get(index); - } - - /** -@@ -66,8 +78,51 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { - * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 - * or < 0} - */ -+ public void line(int index, net.kyori.adventure.text.@Nullable Component line) throws IndexOutOfBoundsException { -+ this.adventure$lines.set(index, line); -+ } -+ // Paper end -+ + /** + * Gets all of the lines of text from the sign involved in this event. + * + * @return the String array for the sign's lines new text -+ * @deprecated in favour of {@link #lines()} + */ -+ @NotNull -+ @Deprecated // Paper -+ public String[] getLines() { -+ return adventure$lines.stream().map(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection()::serialize).toArray(String[]::new); // Paper ++ public @NotNull java.util.List lines() { ++ return this.adventure$lines; + } + + /** @@ -2646,12 +2604,9 @@ index 7190db11eff7d48df8a99f405a9dbaefdfa76e3d..c40536f781393cb39e6a1a4ba6e78071 + * provided index + * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 + * or < 0} -+ * @deprecated in favour of {@link #line(int)} + */ -+ @Nullable -+ @Deprecated // Paper -+ public String getLine(int index) throws IndexOutOfBoundsException { -+ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.adventure$lines.get(index)); // Paper ++ public net.kyori.adventure.text.@Nullable Component line(int index) throws IndexOutOfBoundsException { ++ return this.adventure$lines.get(index); + } + + /** @@ -2661,8 +2616,46 @@ index 7190db11eff7d48df8a99f405a9dbaefdfa76e3d..c40536f781393cb39e6a1a4ba6e78071 + * @param line text to set + * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 + * or < 0} -+ * @deprecated in favour of {@link #line(int, net.kyori.adventure.text.Component)} + */ ++ public void line(int index, net.kyori.adventure.text.@Nullable Component line) throws IndexOutOfBoundsException { ++ this.adventure$lines.set(index, line); ++ } ++ // Paper end ++ + /** + * Gets all of the lines of text from the sign involved in this event. + * + * @return the String array for the sign's lines new text ++ * @deprecated in favour of {@link #lines()} + */ + @NotNull ++ @Deprecated // Paper + public String[] getLines() { +- return lines; ++ return adventure$lines.stream().map(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection()::serialize).toArray(String[]::new); // Paper + } + + /** +@@ -52,10 +103,12 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { + * provided index + * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 + * or < 0} ++ * @deprecated in favour of {@link #line(int)} + */ + @Nullable ++ @Deprecated // Paper + public String getLine(int index) throws IndexOutOfBoundsException { +- return lines[index]; ++ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.adventure$lines.get(index)); // Paper + } + + /** +@@ -65,9 +118,11 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { + * @param line text to set + * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 + * or < 0} ++ * @deprecated in favour of {@link #line(int, net.kyori.adventure.text.Component)} + */ + @Deprecated // Paper public void setLine(int index, @Nullable String line) throws IndexOutOfBoundsException { - lines[index] = line; @@ -2687,11 +2680,11 @@ index 3c2ea8fec3a748cab7f5ad9100d12bd8213ec6c9..a803bfea5400b3578bb4cf3261874e87 + public PlayerDeathEvent(@NotNull final Player player, @NotNull final List drops, final int droppedExp, @Nullable final net.kyori.adventure.text.Component adventure$deathMessage) { + this(player, drops, droppedExp, 0, adventure$deathMessage, null); + } - ++ + public PlayerDeathEvent(@NotNull final Player player, @NotNull final List drops, final int droppedExp, final int newExp, @Nullable final net.kyori.adventure.text.Component adventure$deathMessage, @Nullable String deathMessage) { + this(player, drops, droppedExp, newExp, 0, 0, adventure$deathMessage, deathMessage); + } -+ + + public PlayerDeathEvent(@NotNull final Player player, @NotNull final List drops, final int droppedExp, final int newExp, final int newTotalExp, final int newLevel, @Nullable final net.kyori.adventure.text.Component adventure$deathMessage, @Nullable String deathMessage) { + super(player, drops, droppedExp); + this.newExp = newExp; @@ -2723,59 +2716,56 @@ index 3c2ea8fec3a748cab7f5ad9100d12bd8213ec6c9..a803bfea5400b3578bb4cf3261874e87 } @NotNull -@@ -39,13 +62,15 @@ public class PlayerDeathEvent extends EntityDeathEvent { +@@ -39,25 +62,55 @@ public class PlayerDeathEvent extends EntityDeathEvent { return (Player) entity; } + // Paper start - /** - * Set the death message that will appear to everyone on the server. - * - * @param deathMessage Message to appear to other players on the server. - */ -- public void setDeathMessage(@Nullable String deathMessage) { -- this.deathMessage = deathMessage; ++ /** ++ * Set the death message that will appear to everyone on the server. ++ * ++ * @param deathMessage Message to appear to other players on the server. ++ */ + public void deathMessage(net.kyori.adventure.text.@Nullable Component deathMessage) { + this.deathMessage = null; + this.adventure$deathMessage = deathMessage; - } - - /** -@@ -53,11 +78,39 @@ public class PlayerDeathEvent extends EntityDeathEvent { - * - * @return Message to appear to other players on the server. - */ -- @Nullable -- public String getDeathMessage() { -- return deathMessage; ++ } ++ ++ /** ++ * Get the death message that will appear to everyone on the server. ++ * ++ * @return Message to appear to other players on the server. ++ */ + public net.kyori.adventure.text.@Nullable Component deathMessage() { + return this.adventure$deathMessage; + } + // Paper end + -+ /** -+ * Set the death message that will appear to everyone on the server. -+ * -+ * @param deathMessage Message to appear to other players on the server. + /** + * Set the death message that will appear to everyone on the server. + * + * @param deathMessage Message to appear to other players on the server. + * @deprecated in favour of {@link #deathMessage(net.kyori.adventure.text.Component)} -+ */ + */ + @Deprecated // Paper -+ public void setDeathMessage(@Nullable String deathMessage) { -+ this.deathMessage = deathMessage; + public void setDeathMessage(@Nullable String deathMessage) { + this.deathMessage = deathMessage; + this.adventure$deathMessage = deathMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(deathMessage) : null; // Paper } -+ /** -+ * Get the death message that will appear to everyone on the server. -+ * -+ * @return Message to appear to other players on the server. + /** + * Get the death message that will appear to everyone on the server. + * + * @return Message to appear to other players on the server. + * @deprecated in favour of {@link #deathMessage()} -+ */ -+ @Nullable + */ + @Nullable + @Deprecated // Paper -+ public String getDeathMessage() { + public String getDeathMessage() { +- return deathMessage; + return this.deathMessage != null ? this.deathMessage : (this.adventure$deathMessage != null ? getDeathMessageString(this.adventure$deathMessage) : null); // Paper -+ } + } +- + // Paper start //TODO: add translation API to drop String deathMessage in favor of just Adventure + private static String getDeathMessageString(net.kyori.adventure.text.Component component) { + return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(component); @@ -2878,32 +2868,23 @@ index 9866c07c999f46cb585709804aaad710c3031d5a..c7c45e2de8cca1bf8b8e12752e08db62 return message; } -@@ -95,29 +96,81 @@ public class AsyncPlayerPreLoginEvent extends Event { +@@ -95,16 +96,66 @@ public class AsyncPlayerPreLoginEvent extends Event { * * @param message New kick message */ - public void setKickMessage(@NotNull final String message) { + public void kickMessage(@NotNull final net.kyori.adventure.text.Component message) { - this.message = message; - } - -- /** -- * Allows the player to log in -- */ -- public void allow() { -- result = Result.ALLOWED; -- message = ""; -- } -- - /** - * Disallows the player from logging in, with the given reason - * - * @param result New result for disallowing the player - * @param message Kick message to display to the user - */ -- public void disallow(@NotNull final Result result, @NotNull final String message) { ++ this.message = message; ++ } ++ ++ /** ++ * Disallows the player from logging in, with the given reason ++ * ++ * @param result New result for disallowing the player ++ * @param message Kick message to display to the user ++ */ + public void disallow(@NotNull final Result result, @NotNull final net.kyori.adventure.text.Component message) { - this.result = result; ++ this.result = result; this.message = message; } @@ -2945,31 +2926,31 @@ index 9866c07c999f46cb585709804aaad710c3031d5a..c7c45e2de8cca1bf8b8e12752e08db62 + public void setKickMessage(@NotNull final String message) { + this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper + } -+ -+ /** -+ * Allows the player to log in -+ */ -+ public void allow() { -+ result = Result.ALLOWED; -+ message = net.kyori.adventure.text.Component.empty(); // Paper -+ } -+ -+ /** -+ * Disallows the player from logging in, with the given reason -+ * -+ * @param result New result for disallowing the player -+ * @param message Kick message to display to the user -+ * @deprecated in favour of {@link #disallow(org.bukkit.event.player.AsyncPlayerPreLoginEvent.Result, net.kyori.adventure.text.Component)} -+ */ -+ @Deprecated // Paper -+ public void disallow(@NotNull final Result result, @NotNull final String message) { -+ this.result = result; -+ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper -+ } + /** - * Disallows the player from logging in, with the given reason + * Allows the player to log in + */ + public void allow() { + result = Result.ALLOWED; +- message = ""; ++ message = net.kyori.adventure.text.Component.empty(); // Paper + } + + /** +@@ -112,10 +163,12 @@ public class AsyncPlayerPreLoginEvent extends Event { * + * @param result New result for disallowing the player + * @param message Kick message to display to the user ++ * @deprecated in favour of {@link #disallow(org.bukkit.event.player.AsyncPlayerPreLoginEvent.Result, net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void disallow(@NotNull final Result result, @NotNull final String message) { + this.result = result; +- this.message = message; ++ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper + } + + /** @@ -130,7 +183,7 @@ public class AsyncPlayerPreLoginEvent extends Event { @Deprecated public void disallow(@NotNull final PlayerPreLoginEvent.Result result, @NotNull final String message) { @@ -3008,75 +2989,70 @@ diff --git a/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java b/src/ma index d06684aba7688ce06777dbd837a46856a9d7767f..3e1e7cd0415509da4dd887db59efa55011b1dab4 100644 --- a/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java +++ b/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java -@@ -10,21 +10,27 @@ import org.jetbrains.annotations.Nullable; +@@ -10,30 +10,60 @@ import org.jetbrains.annotations.Nullable; */ public class PlayerJoinEvent extends PlayerEvent { private static final HandlerList handlers = new HandlerList(); - private String joinMessage; -- -- public PlayerJoinEvent(@NotNull final Player playerJoined, @Nullable final String joinMessage) { + // Paper start + private net.kyori.adventure.text.Component joinMessage; + public PlayerJoinEvent(@NotNull final Player playerJoined, @Nullable final net.kyori.adventure.text.Component joinMessage) { - super(playerJoined); - this.joinMessage = joinMessage; - } ++ super(playerJoined); ++ this.joinMessage = joinMessage; ++ } + @Deprecated // Paper end -+ public PlayerJoinEvent(@NotNull final Player playerJoined, @Nullable final String joinMessage) { -+ super(playerJoined); + public PlayerJoinEvent(@NotNull final Player playerJoined, @Nullable final String joinMessage) { + super(playerJoined); + this.joinMessage = joinMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(joinMessage) : null; // Paper end + } + + // Paper start - /** - * Gets the join message to send to all online players - * - * @return string join message. Can be null - */ -- @Nullable -- public String getJoinMessage() { -- return joinMessage; -+ public net.kyori.adventure.text.@Nullable Component joinMessage() { -+ return this.joinMessage; - } - - /** -@@ -32,9 +38,33 @@ public class PlayerJoinEvent extends PlayerEvent { - * - * @param joinMessage join message. If null, no message will be sent - */ -- public void setJoinMessage(@Nullable String joinMessage) { -+ public void joinMessage(net.kyori.adventure.text.@Nullable Component joinMessage) { - this.joinMessage = joinMessage; - } -+ // Paper end -+ + /** + * Gets the join message to send to all online players + * + * @return string join message. Can be null -+ * @deprecated in favour of {@link #joinMessage()} + */ -+ @Nullable -+ @Deprecated // Paper -+ public String getJoinMessage() { -+ return this.joinMessage == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.joinMessage); // Paper ++ public net.kyori.adventure.text.@Nullable Component joinMessage() { ++ return this.joinMessage; + } + + /** + * Sets the join message to send to all online players + * + * @param joinMessage join message. If null, no message will be sent -+ * @deprecated in favour of {@link #joinMessage(net.kyori.adventure.text.Component)} + */ ++ public void joinMessage(net.kyori.adventure.text.@Nullable Component joinMessage) { + this.joinMessage = joinMessage; + } ++ // Paper end + + /** + * Gets the join message to send to all online players + * + * @return string join message. Can be null ++ * @deprecated in favour of {@link #joinMessage()} + */ + @Nullable + @Deprecated // Paper -+ public void setJoinMessage(@Nullable String joinMessage) { + public String getJoinMessage() { +- return joinMessage; ++ return this.joinMessage == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.joinMessage); // Paper + } + + /** + * Sets the join message to send to all online players + * + * @param joinMessage join message. If null, no message will be sent ++ * @deprecated in favour of {@link #joinMessage(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setJoinMessage(@Nullable String joinMessage) { +- this.joinMessage = joinMessage; + this.joinMessage = joinMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(joinMessage) : null; // Paper -+ } + } @NotNull - @Override diff --git a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java b/src/main/java/org/bukkit/event/player/PlayerKickEvent.java index 2f6ca42330675733b2b4132cbb66e433788d05d5..997b06c19a5277656521e0e298f2958c209f1da1 100644 --- a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java @@ -3244,7 +3220,7 @@ index 084ca8cfcb7381bfa4fa6280748cf9b81210a9c1..62fb782baad5c80a3daaa557c0faa674 private final InetAddress realAddress; // Spigot /** -@@ -53,13 +53,53 @@ public class PlayerLoginEvent extends PlayerEvent { +@@ -53,12 +53,52 @@ public class PlayerLoginEvent extends PlayerEvent { * @param result The result status for this event * @param message The message to be displayed if result denies login * @param realAddress the actual, unspoofed connecting address @@ -3252,8 +3228,8 @@ index 084ca8cfcb7381bfa4fa6280748cf9b81210a9c1..62fb782baad5c80a3daaa557c0faa674 */ + @Deprecated // Paper public PlayerLoginEvent(@NotNull final Player player, @NotNull String hostname, @NotNull final InetAddress address, @NotNull final Result result, @NotNull final String message, @NotNull final InetAddress realAddress) { // Spigot -+ this(player, hostname, address, realAddress); // Spigot -+ this.result = result; + this(player, hostname, address, realAddress); // Spigot + this.result = result; + this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper + } + @@ -3270,11 +3246,11 @@ index 084ca8cfcb7381bfa4fa6280748cf9b81210a9c1..62fb782baad5c80a3daaa557c0faa674 + * @param realAddress the actual, unspoofed connecting address + */ + public PlayerLoginEvent(@NotNull final Player player, @NotNull String hostname, @NotNull final InetAddress address, @NotNull final Result result, @NotNull final net.kyori.adventure.text.Component message, @NotNull final InetAddress realAddress) { // Spigot - this(player, hostname, address, realAddress); // Spigot - this.result = result; - this.message = message; - } - ++ this(player, hostname, address, realAddress); // Spigot ++ this.result = result; ++ this.message = message; ++ } ++ + /** + * Gets the current kick message that will be used if getResult() != + * Result.ALLOWED @@ -3291,13 +3267,12 @@ index 084ca8cfcb7381bfa4fa6280748cf9b81210a9c1..62fb782baad5c80a3daaa557c0faa674 + * @param message New kick message + */ + public void kickMessage(net.kyori.adventure.text.@NotNull Component message) { -+ this.message = message; -+ } + this.message = message; + } + // Paper end -+ + // Spigot start /** - * Gets the connection address of this player, regardless of whether it has been spoofed or not. @@ -96,19 +136,23 @@ public class PlayerLoginEvent extends PlayerEvent { * Result.ALLOWED * @@ -3394,7 +3369,7 @@ index fb066251f793ec3b41bfc075b9478901b15ee549..6800132c6288b4588fd02b08d26f016c return message; } -@@ -72,28 +73,65 @@ public class PlayerPreLoginEvent extends Event { +@@ -72,16 +73,51 @@ public class PlayerPreLoginEvent extends Event { * * @param message New kick message */ @@ -3403,25 +3378,16 @@ index fb066251f793ec3b41bfc075b9478901b15ee549..6800132c6288b4588fd02b08d26f016c this.message = message; } -- /** -- * Allows the player to log in -- */ -- public void allow() { -- result = Result.ALLOWED; -- message = ""; -- } -- - /** - * Disallows the player from logging in, with the given reason - * - * @param result New result for disallowing the player - * @param message Kick message to display to the user - */ -- public void disallow(@NotNull final Result result, @NotNull final String message) { ++ /** ++ * Disallows the player from logging in, with the given reason ++ * ++ * @param result New result for disallowing the player ++ * @param message Kick message to display to the user ++ */ + public void disallow(@NotNull final Result result, @NotNull final net.kyori.adventure.text.Component message) { - this.result = result; - this.message = message; - } ++ this.result = result; ++ this.message = message; ++ } + // Paper end + /** + * Gets the current kick message that will be used if getResult() != @@ -3447,34 +3413,35 @@ index fb066251f793ec3b41bfc075b9478901b15ee549..6800132c6288b4588fd02b08d26f016c + this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper + } + -+ /** -+ * Allows the player to log in -+ */ -+ public void allow() { -+ result = Result.ALLOWED; + /** + * Allows the player to log in + */ + public void allow() { + result = Result.ALLOWED; +- message = ""; + message = net.kyori.adventure.text.Component.empty(); // Paper -+ } -+ -+ /** -+ * Disallows the player from logging in, with the given reason -+ * -+ * @param result New result for disallowing the player -+ * @param message Kick message to display to the user -+ * @deprecated in favour of {@link #disallow(org.bukkit.event.player.PlayerPreLoginEvent.Result, net.kyori.adventure.text.Component)} -+ */ -+ @Deprecated // Paper -+ public void disallow(@NotNull final Result result, @NotNull final String message) { -+ this.result = result; -+ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper -+ } + } + + /** +@@ -89,10 +125,12 @@ public class PlayerPreLoginEvent extends Event { + * + * @param result New result for disallowing the player + * @param message Kick message to display to the user ++ * @deprecated in favour of {@link #disallow(org.bukkit.event.player.PlayerPreLoginEvent.Result, net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void disallow(@NotNull final Result result, @NotNull final String message) { + this.result = result; +- this.message = message; ++ this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper + } /** - * Gets the player's name. diff --git a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java index d70c25f404e994766a9ebce89a917c8d0719777c..14b27eaaf744736b3e56bb1383481df98a218c43 100644 --- a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java +++ b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java -@@ -10,9 +10,15 @@ import org.jetbrains.annotations.Nullable; +@@ -10,30 +10,59 @@ import org.jetbrains.annotations.Nullable; */ public class PlayerQuitEvent extends PlayerEvent { private static final HandlerList handlers = new HandlerList(); @@ -3483,59 +3450,60 @@ index d70c25f404e994766a9ebce89a917c8d0719777c..14b27eaaf744736b3e56bb1383481df9 + @Deprecated // Paper public PlayerQuitEvent(@NotNull final Player who, @Nullable final String quitMessage) { -+ super(who); + super(who); + this.quitMessage = quitMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(quitMessage) : null; // Paper + } + // Paper start + public PlayerQuitEvent(@NotNull final Player who, @Nullable final net.kyori.adventure.text.Component quitMessage) { - super(who); - this.quitMessage = quitMessage; - } -@@ -22,8 +28,7 @@ public class PlayerQuitEvent extends PlayerEvent { - * - * @return string quit message - */ -- @Nullable -- public String getQuitMessage() { -+ public net.kyori.adventure.text.@Nullable Component quitMessage() { - return quitMessage; - } - -@@ -32,9 +37,33 @@ public class PlayerQuitEvent extends PlayerEvent { - * - * @param quitMessage quit message - */ -- public void setQuitMessage(@Nullable String quitMessage) { -+ public void quitMessage(net.kyori.adventure.text.@Nullable Component quitMessage) { - this.quitMessage = quitMessage; - } -+ // Paper end ++ super(who); ++ this.quitMessage = quitMessage; ++ } + + /** + * Gets the quit message to send to all online players + * + * @return string quit message -+ * @deprecated in favour of {@link #quitMessage()} + */ -+ @Nullable -+ @Deprecated // Paper -+ public String getQuitMessage() { -+ return this.quitMessage == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.quitMessage); // Paper ++ public net.kyori.adventure.text.@Nullable Component quitMessage() { ++ return quitMessage; + } + + /** + * Sets the quit message to send to all online players + * + * @param quitMessage quit message -+ * @deprecated in favour of {@link #quitMessage(net.kyori.adventure.text.Component)} + */ ++ public void quitMessage(net.kyori.adventure.text.@Nullable Component quitMessage) { + this.quitMessage = quitMessage; + } ++ // Paper end + + /** + * Gets the quit message to send to all online players + * + * @return string quit message ++ * @deprecated in favour of {@link #quitMessage()} + */ + @Nullable + @Deprecated // Paper -+ public void setQuitMessage(@Nullable String quitMessage) { + public String getQuitMessage() { +- return quitMessage; ++ return this.quitMessage == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.quitMessage); // Paper + } + + /** + * Sets the quit message to send to all online players + * + * @param quitMessage quit message ++ * @deprecated in favour of {@link #quitMessage(net.kyori.adventure.text.Component)} + */ ++ @Deprecated // Paper + public void setQuitMessage(@Nullable String quitMessage) { +- this.quitMessage = quitMessage; + this.quitMessage = quitMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(quitMessage) : null; // Paper -+ } + } @NotNull - @Override diff --git a/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java b/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java index 03bfca9d368bbe4b7c1353d52c883e756bf69bda..1bfd8ba2a9fa16f2084ad36515644f6af79fdced 100644 --- a/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java @@ -3649,9 +3617,9 @@ index 5adbe0514129abf3cfbc4b29a213f522359fe2e1..72ebc29db42d08d1d0361dba462fc8a5 + @Deprecated // Paper protected ServerListPingEvent(@NotNull final String hostname, @NotNull final InetAddress address, @NotNull final String motd, final int maxPlayers) { super(true); -+ this.numPlayers = MAGIC_PLAYER_COUNT; -+ this.hostname = hostname; -+ this.address = address; + this.numPlayers = MAGIC_PLAYER_COUNT; + this.hostname = hostname; + this.address = address; + this.motd = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(motd); // Paper + this.maxPlayers = maxPlayers; + } @@ -3665,10 +3633,10 @@ index 5adbe0514129abf3cfbc4b29a213f522359fe2e1..72ebc29db42d08d1d0361dba462fc8a5 + Preconditions.checkArgument(numPlayers >= 0, "Cannot have negative number of players online (%s)", numPlayers); + this.hostname = hostname; + this.address = address; -+ this.motd = motd; + this.motd = motd; + this.numPlayers = numPlayers; -+ this.maxPlayers = maxPlayers; -+ } + this.maxPlayers = maxPlayers; + } + /** + * This constructor is intended for implementations that provide the + * {@link #iterator()} method, thus provided the {@link #getNumPlayers()} @@ -3695,12 +3663,12 @@ index 5adbe0514129abf3cfbc4b29a213f522359fe2e1..72ebc29db42d08d1d0361dba462fc8a5 + * @param maxPlayers the max number of players + */ + protected ServerListPingEvent(final @NotNull String hostname, final @NotNull InetAddress address, final net.kyori.adventure.text.@NotNull Component motd, final int maxPlayers) { - this.numPlayers = MAGIC_PLAYER_COUNT; - this.hostname = hostname; - this.address = address; - this.motd = motd; - this.maxPlayers = maxPlayers; - } ++ this.numPlayers = MAGIC_PLAYER_COUNT; ++ this.hostname = hostname; ++ this.address = address; ++ this.motd = motd; ++ this.maxPlayers = maxPlayers; ++ } + /** + * Get the message of the day message. + * @@ -3854,13 +3822,12 @@ index 94852d50e88d0594b84b581cd627174043629995..be7c2cfc757e4dd15927be850739d401 /** * Represents the generation (or level of copying) of a written book -@@ -119,16 +119,60 @@ public interface BookMeta extends ItemMeta { +@@ -119,6 +119,109 @@ public interface BookMeta extends ItemMeta { */ boolean hasPages(); + // Paper start - /** -- * Gets the specified page in the book. The given page must exist. ++ /** + * Gets the title of the book. + *

+ * Plugins should check that hasTitle() returns true before calling this @@ -3906,55 +3873,34 @@ index 94852d50e88d0594b84b581cd627174043629995..be7c2cfc757e4dd15927be850739d401 + + /** + * Gets the specified page in the book. The page must exist. - *

- * Pages are 1-indexed. - * - * @param page the page number to get, in range [1, getPageCount()] - * @return the page from the book - */ -- @NotNull -- String getPage(int page); ++ *

++ * Pages are 1-indexed. ++ * ++ * @param page the page number to get, in range [1, getPageCount()] ++ * @return the page from the book ++ */ + net.kyori.adventure.text.@NotNull Component page(int page); - - /** - * Sets the specified page in the book. Pages of the book must be -@@ -142,31 +186,7 @@ public interface BookMeta extends ItemMeta { - * @param page the page number to set, in range [1, getPageCount()] - * @param data the data to set for that page - */ -- void setPage(int page, @NotNull String data); -- -- /** -- * Gets all the pages in the book. -- * -- * @return list of all the pages in the book -- */ -- @NotNull -- List getPages(); -- -- /** -- * Clears the existing book pages, and sets the book to use the provided -- * pages. Maximum 100 pages with 256 characters per page. -- * -- * @param pages A list of pages to set the book to use -- */ -- void setPages(@NotNull List pages); -- -- /** -- * Clears the existing book pages, and sets the book to use the provided -- * pages. Maximum 50 pages with 256 characters per page. -- * -- * @param pages A list of strings, each being a page -- */ -- void setPages(@NotNull String... pages); ++ ++ /** ++ * Sets the specified page in the book. Pages of the book must be ++ * contiguous. ++ *

++ * The data can be up to 256 characters in length, additional characters ++ * are truncated. ++ *

++ * Pages are 1-indexed. ++ * ++ * @param page the page number to set, in range [1, getPageCount()] ++ * @param data the data to set for that page ++ */ + void page(int page, net.kyori.adventure.text.@NotNull Component data); - - /** - * Adds new pages to the end of the book. Up to a maximum of 50 pages with -@@ -174,6 +194,101 @@ public interface BookMeta extends ItemMeta { - * - * @param pages A list of strings, each being a page - */ ++ ++ /** ++ * Adds new pages to the end of the book. Up to a maximum of 50 pages with ++ * 256 characters per page. ++ * ++ * @param pages A list of strings, each being a page ++ */ + void addPages(net.kyori.adventure.text.@NotNull Component @NotNull ... pages); + + interface BookMetaBuilder extends Builder { @@ -3983,72 +3929,66 @@ index 94852d50e88d0594b84b581cd627174043629995..be7c2cfc757e4dd15927be850739d401 + + // Paper end + -+ /** -+ * Gets the specified page in the book. The given page must exist. -+ *

-+ * Pages are 1-indexed. -+ * -+ * @param page the page number to get, in range [1, getPageCount()] -+ * @return the page from the book + /** + * Gets the specified page in the book. The given page must exist. + *

+@@ -126,8 +229,10 @@ public interface BookMeta extends ItemMeta { + * + * @param page the page number to get, in range [1, getPageCount()] + * @return the page from the book + * @deprecated in favour of {@link #page(int)} -+ */ -+ @NotNull + */ + @NotNull + @Deprecated // Paper -+ String getPage(int page); -+ -+ /** -+ * Sets the specified page in the book. Pages of the book must be -+ * contiguous. -+ *

-+ * The data can be up to 256 characters in length, additional characters -+ * are truncated. -+ *

-+ * Pages are 1-indexed. -+ * -+ * @param page the page number to set, in range [1, getPageCount()] -+ * @param data the data to set for that page + String getPage(int page); + + /** +@@ -141,15 +246,19 @@ public interface BookMeta extends ItemMeta { + * + * @param page the page number to set, in range [1, getPageCount()] + * @param data the data to set for that page + * @deprecated in favour of {@link #page(int, net.kyori.adventure.text.Component)} -+ */ + */ + @Deprecated // Paper -+ void setPage(int page, @NotNull String data); -+ -+ /** -+ * Gets all the pages in the book. -+ * -+ * @return list of all the pages in the book + void setPage(int page, @NotNull String data); + + /** + * Gets all the pages in the book. + * + * @return list of all the pages in the book + * @deprecated in favour of {@link #pages()} -+ */ -+ @NotNull + */ + @NotNull + @Deprecated // Paper -+ List getPages(); -+ -+ /** -+ * Clears the existing book pages, and sets the book to use the provided -+ * pages. Maximum 100 pages with 256 characters per page. -+ * -+ * @param pages A list of pages to set the book to use + List getPages(); + + /** +@@ -157,7 +266,9 @@ public interface BookMeta extends ItemMeta { + * pages. Maximum 100 pages with 256 characters per page. + * + * @param pages A list of pages to set the book to use + * @deprecated in favour of {@link #pages(List)} -+ */ + */ + @Deprecated // Paper -+ void setPages(@NotNull List pages); -+ -+ /** -+ * Clears the existing book pages, and sets the book to use the provided -+ * pages. Maximum 50 pages with 256 characters per page. -+ * -+ * @param pages A list of strings, each being a page + void setPages(@NotNull List pages); + + /** +@@ -165,7 +276,9 @@ public interface BookMeta extends ItemMeta { + * pages. Maximum 50 pages with 256 characters per page. + * + * @param pages A list of strings, each being a page + * @deprecated in favour of {@link #pages(net.kyori.adventure.text.Component...)} -+ */ + */ + @Deprecated // Paper -+ void setPages(@NotNull String... pages); -+ -+ /** -+ * Adds new pages to the end of the book. Up to a maximum of 50 pages with -+ * 256 characters per page. -+ * -+ * @param pages A list of strings, each being a page + void setPages(@NotNull String... pages); + + /** +@@ -173,7 +286,9 @@ public interface BookMeta extends ItemMeta { + * 256 characters per page. + * + * @param pages A list of strings, each being a page + * @deprecated in favour of {@link #addPages(net.kyori.adventure.text.Component...)} -+ */ + */ + @Deprecated // Paper void addPage(@NotNull String... pages); @@ -4231,7 +4171,7 @@ index 83354b2a38b6261b172b91c1008dcf3313cc4a8f..762d8a53bbfa82edcd725a52d630b61c } /** -@@ -37,9 +37,30 @@ public final class MapCursor { +@@ -37,7 +37,7 @@ public final class MapCursor { * @param visible Whether the cursor is visible by default. */ public MapCursor(byte x, byte y, byte direction, @NotNull Type type, boolean visible) { @@ -4239,6 +4179,24 @@ index 83354b2a38b6261b172b91c1008dcf3313cc4a8f..762d8a53bbfa82edcd725a52d630b61c + this(x, y, direction, type, visible, (String) null); // Paper } + /** +@@ -49,7 +49,7 @@ public final class MapCursor { + * @param type The type (color/style) of the map cursor. + * @param visible Whether the cursor is visible by default. + * @param caption cursor caption +- * @deprecated Magic value ++ * @deprecated Magic value. Use {@link #MapCursor(byte, byte, byte, byte, boolean, net.kyori.adventure.text.Component)} + */ + @Deprecated + public MapCursor(byte x, byte y, byte direction, byte type, boolean visible, @Nullable String caption) { +@@ -58,8 +58,42 @@ public final class MapCursor { + setDirection(direction); + setRawType(type); + this.visible = visible; +- this.caption = caption; ++ this.caption = caption == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(caption); // Paper + } ++ // Paper start + /** + * Initialize the map cursor. + * @@ -4248,35 +4206,14 @@ index 83354b2a38b6261b172b91c1008dcf3313cc4a8f..762d8a53bbfa82edcd725a52d630b61c + * @param type The type (color/style) of the map cursor. + * @param visible Whether the cursor is visible by default. + * @param caption cursor caption -+ * @deprecated Magic value. Use {@link #MapCursor(byte, byte, byte, byte, boolean, net.kyori.adventure.text.Component)} ++ * @deprecated Magic value + */ + @Deprecated -+ public MapCursor(byte x, byte y, byte direction, byte type, boolean visible, @Nullable String caption) { -+ this.x = x; -+ this.y = y; -+ setDirection(direction); -+ setRawType(type); -+ this.visible = visible; -+ this.caption = caption == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(caption); // Paper -+ } -+ // Paper start - /** - * Initialize the map cursor. - * -@@ -52,14 +73,27 @@ public final class MapCursor { - * @deprecated Magic value - */ - @Deprecated -- public MapCursor(byte x, byte y, byte direction, byte type, boolean visible, @Nullable String caption) { -- this.x = x; -- this.y = y; + public MapCursor(byte x, byte y, byte direction, byte type, boolean visible, net.kyori.adventure.text.@Nullable Component caption) { + this.x = x; this.y = y; this.visible = visible; this.caption = caption; - setDirection(direction); - setRawType(type); -- this.visible = visible; -- this.caption = caption; - } ++ setDirection(direction); ++ setRawType(type); ++ } + /** + * Initialize the map cursor. + * @@ -4310,11 +4247,11 @@ index 83354b2a38b6261b172b91c1008dcf3313cc4a8f..762d8a53bbfa82edcd725a52d630b61c } + // Paper start - /** - * Gets the caption on this cursor. - * - * @return caption - */ ++ /** ++ * Gets the caption on this cursor. ++ * ++ * @return caption ++ */ + public net.kyori.adventure.text.@Nullable Component caption() { + return this.caption; + } @@ -4327,12 +4264,12 @@ index 83354b2a38b6261b172b91c1008dcf3313cc4a8f..762d8a53bbfa82edcd725a52d630b61c + this.caption = caption; + } + // Paper end -+ /** -+ * Gets the caption on this cursor. -+ * -+ * @return caption + /** + * Gets the caption on this cursor. + * + * @return caption + * @deprecated in favour of {@link #caption()} -+ */ + */ @Nullable + @Deprecated // Paper public String getCaption() { @@ -4445,14 +4382,13 @@ index 2ff3a11f1f9c115722ea224873e7eb6dc6dc63e6..86a0a6f9e8487d6dfaf60876ace3dcc9 */ @NotNull String getName() throws IllegalStateException; -- + // Paper start - /** - * Gets the name displayed to players for this objective - * - * @return this objective's display name - * @throws IllegalStateException if this objective has been unregistered - */ ++ /** ++ * Gets the name displayed to players for this objective ++ * ++ * @return this objective's display name ++ * @throws IllegalStateException if this objective has been unregistered ++ */ + net.kyori.adventure.text.@NotNull Component displayName() throws IllegalStateException; + /** + * Sets the name displayed to players for this objective. @@ -4465,14 +4401,14 @@ index 2ff3a11f1f9c115722ea224873e7eb6dc6dc63e6..86a0a6f9e8487d6dfaf60876ace3dcc9 + */ + void displayName(net.kyori.adventure.text.@Nullable Component displayName) throws IllegalStateException, IllegalArgumentException; + // Paper end -+ -+ /** -+ * Gets the name displayed to players for this objective -+ * -+ * @return this objective's display name -+ * @throws IllegalStateException if this objective has been unregistered + + /** + * Gets the name displayed to players for this objective + * + * @return this objective's display name + * @throws IllegalStateException if this objective has been unregistered + * @deprecated in favour of {@link #displayName()} -+ */ + */ @NotNull + @Deprecated // Paper String getDisplayName() throws IllegalStateException; @@ -4631,14 +4567,13 @@ index 0db7fe1b9fe5621ceed3f4f046691e359f5949dd..4d625f79ba2e3fe074feade98f7c1bc2 */ @NotNull String getName() throws IllegalStateException; -- + // Paper start - /** - * Gets the name displayed to entries for this team - * - * @return Team display name - * @throws IllegalStateException if this team has been unregistered - */ ++ /** ++ * Gets the name displayed to entries for this team ++ * ++ * @return Team display name ++ * @throws IllegalStateException if this team has been unregistered ++ */ + net.kyori.adventure.text.@NotNull Component displayName() throws IllegalStateException; + + /** @@ -4716,14 +4651,14 @@ index 0db7fe1b9fe5621ceed3f4f046691e359f5949dd..4d625f79ba2e3fe074feade98f7c1bc2 + */ + void color(net.kyori.adventure.text.format.@Nullable NamedTextColor color); + // Paper end -+ -+ /** -+ * Gets the name displayed to entries for this team -+ * -+ * @return Team display name -+ * @throws IllegalStateException if this team has been unregistered + + /** + * Gets the name displayed to entries for this team + * + * @return Team display name + * @throws IllegalStateException if this team has been unregistered + * @deprecated in favour of {@link #displayName()} -+ */ + */ @NotNull + @Deprecated // Paper String getDisplayName() throws IllegalStateException; diff --git a/patches/api/0008-Paper-Plugins.patch b/patches/api/0008-Paper-Plugins.patch index 708554a590..f62a996f4b 100644 --- a/patches/api/0008-Paper-Plugins.patch +++ b/patches/api/0008-Paper-Plugins.patch @@ -2194,7 +2194,7 @@ index 2f74ec96ece706de23156ebabfe493211bc05391..302319acbc257a075adfb78d9f5c49fd - javaPlugin.init(loader, loader.server, description, dataFolder, file, this); + javaPlugin.init(null, org.bukkit.Bukkit.getServer(), description, dataFolder, file, this); // Paper - } ++ } + + // Paper start + @Override @@ -2219,7 +2219,7 @@ index 2f74ec96ece706de23156ebabfe493211bc05391..302319acbc257a075adfb78d9f5c49fd + Class serializable = clazz.asSubclass(org.bukkit.configuration.serialization.ConfigurationSerializable.class); + org.bukkit.configuration.serialization.ConfigurationSerialization.unregisterClass(serializable); + } -+ } + } + + @Override + public @Nullable io.papermc.paper.plugin.provider.classloader.PluginClassLoaderGroup getGroup() { diff --git a/patches/api/0010-Timings-v2.patch b/patches/api/0010-Timings-v2.patch index 1b4abe69e4..672a87b5f8 100644 --- a/patches/api/0010-Timings-v2.patch +++ b/patches/api/0010-Timings-v2.patch @@ -3400,12 +3400,12 @@ index fbf56bcc4540f7f1a8ced7cc2cd96e291c1ac273..8602b96bfc860ff1fea4c1c7a3655ce3 public void sendMessage(@NotNull net.md_5.bungee.api.ChatMessageType position, @Nullable java.util.UUID sender, @NotNull net.md_5.bungee.api.chat.BaseComponent... components) { throw new UnsupportedOperationException("Not supported yet."); + - } ++ } + + // Paper start + public int getPing() { + throw new UnsupportedOperationException( "Not supported yet." ); -+ } + } + // Paper end } @@ -3611,8 +3611,7 @@ index 44badfedcc3fdc26bdc293b85d8c781d6f659faa..123647bb10fc89508437d7a0bd3fd31d public CustomTimingsHandler(@NotNull String name) { - this(name, null); - } -+ Timing timing; - +- - public CustomTimingsHandler(@NotNull String name, @Nullable CustomTimingsHandler parent) { - this.name = name; - this.parent = parent; @@ -3635,16 +3634,7 @@ index 44badfedcc3fdc26bdc293b85d8c781d6f659faa..123647bb10fc89508437d7a0bd3fd31d - long avg = time / count; - - printStream.println(" " + timings.name + " Time: " + time + " Count: " + count + " Avg: " + avg + " Violations: " + timings.violations); -+ new AuthorNagException("Deprecated use of CustomTimingsHandler. Please Switch to Timings.of ASAP").printStackTrace(); -+ try { -+ final Method ofSafe = TimingsManager.class.getDeclaredMethod("getHandler", String.class, String.class, Timing.class); -+ ofSafe.setAccessible(true); -+ timing = (Timing) ofSafe.invoke(null,"Minecraft", "(Deprecated API) " + name, null); -+ } catch (Exception e) { -+ e.printStackTrace(); -+ Bukkit.getLogger().log(Level.SEVERE, "This handler could not be registered"); -+ timing = Timings.NULL_HANDLER; - } +- } - printStream.println("# Version " + Bukkit.getVersion()); - int entities = 0; - int livingEntities = 0; @@ -3654,9 +3644,8 @@ index 44badfedcc3fdc26bdc293b85d8c781d6f659faa..123647bb10fc89508437d7a0bd3fd31d - } - printStream.println("# Entities " + entities); - printStream.println("# LivingEntities " + livingEntities); -+ handler = timing; - } - +- } +- - /** - * Resets all timings. - */ @@ -3668,9 +3657,7 @@ index 44badfedcc3fdc26bdc293b85d8c781d6f659faa..123647bb10fc89508437d7a0bd3fd31d - } - TimingsCommand.timingStart = System.nanoTime(); - } -+ public void startTiming() { handler.startTiming(); } -+ public void stopTiming() { handler.stopTiming(); } - +- - /** - * Ticked every tick by CraftBukkit to count the number of times a timer - * caused TPS loss. @@ -3686,7 +3673,8 @@ index 44badfedcc3fdc26bdc293b85d8c781d6f659faa..123647bb10fc89508437d7a0bd3fd31d - } - } - } -- ++ Timing timing; + - /** - * Starts timing to track a section of code. - */ @@ -3697,9 +3685,19 @@ index 44badfedcc3fdc26bdc293b85d8c781d6f659faa..123647bb10fc89508437d7a0bd3fd31d - if (parent != null && ++parent.timingDepth == 1) { - parent.start = start; - } -- } -- } -- ++ new AuthorNagException("Deprecated use of CustomTimingsHandler. Please Switch to Timings.of ASAP").printStackTrace(); ++ try { ++ final Method ofSafe = TimingsManager.class.getDeclaredMethod("getHandler", String.class, String.class, Timing.class); ++ ofSafe.setAccessible(true); ++ timing = (Timing) ofSafe.invoke(null,"Minecraft", "(Deprecated API) " + name, null); ++ } catch (Exception e) { ++ e.printStackTrace(); ++ Bukkit.getLogger().log(Level.SEVERE, "This handler could not be registered"); ++ timing = Timings.NULL_HANDLER; + } ++ handler = timing; + } + - /** - * Stops timing a section of code. - */ @@ -3718,7 +3716,9 @@ index 44badfedcc3fdc26bdc293b85d8c781d6f659faa..123647bb10fc89508437d7a0bd3fd31d - } - } - } -- ++ public void startTiming() { handler.startTiming(); } ++ public void stopTiming() { handler.stopTiming(); } + - /** - * Reset this timer, setting all values to zero. - */ diff --git a/patches/api/0039-EntityRegainHealthEvent-isFastRegen-API.patch b/patches/api/0039-EntityRegainHealthEvent-isFastRegen-API.patch index f2bf91f480..f06ee13d15 100644 --- a/patches/api/0039-EntityRegainHealthEvent-isFastRegen-API.patch +++ b/patches/api/0039-EntityRegainHealthEvent-isFastRegen-API.patch @@ -8,7 +8,7 @@ diff --git a/src/main/java/org/bukkit/event/entity/EntityRegainHealthEvent.java index 8feb6698f9630f099be99e52d1149cd6bc615197..d51d2ec1d04d9ea8a25a70d0d856f2355ebfcb4a 100644 --- a/src/main/java/org/bukkit/event/entity/EntityRegainHealthEvent.java +++ b/src/main/java/org/bukkit/event/entity/EntityRegainHealthEvent.java -@@ -13,13 +13,32 @@ public class EntityRegainHealthEvent extends EntityEvent implements Cancellable +@@ -13,12 +13,31 @@ public class EntityRegainHealthEvent extends EntityEvent implements Cancellable private boolean cancelled; private double amount; private final RegainReason regainReason; @@ -25,8 +25,8 @@ index 8feb6698f9630f099be99e52d1149cd6bc615197..d51d2ec1d04d9ea8a25a70d0d856f235 this.amount = amount; this.regainReason = regainReason; + this.isFastRegen = isFastRegen; // Paper - } - ++ } ++ + // Paper start - Add getter for isFastRegen + /** + * Is this event a result of the fast regeneration mechanic @@ -35,9 +35,8 @@ index 8feb6698f9630f099be99e52d1149cd6bc615197..d51d2ec1d04d9ea8a25a70d0d856f235 + */ + public boolean isFastRegen() { + return isFastRegen; -+ } + } + // Paper end -+ + /** * Gets the amount of regained health - * diff --git a/patches/api/0080-Ability-to-apply-mending-to-XP-API.patch b/patches/api/0080-Ability-to-apply-mending-to-XP-API.patch index 2f780e2e68..76d3f0d052 100644 --- a/patches/api/0080-Ability-to-apply-mending-to-XP-API.patch +++ b/patches/api/0080-Ability-to-apply-mending-to-XP-API.patch @@ -18,21 +18,21 @@ index dbe15267053cfd6bdac093f798dda1cb5aff02c4..95130fde38e7fcec4139fac97df25d82 public void resetPlayerWeather(); + // Paper start - /** - * Gives the player the amount of experience specified. - * - * @param amount Exp amount to give - */ -- public void giveExp(int amount); -+ public default void giveExp(int amount) { -+ giveExp(amount, false); -+ } + /** + * Gives the player the amount of experience specified. + * + * @param amount Exp amount to give -+ * @param applyMending Mend players items with mending, with same behavior as picking up orbs. calls {@link #applyMending(int)} + */ ++ public default void giveExp(int amount) { ++ giveExp(amount, false); ++ } + /** + * Gives the player the amount of experience specified. + * + * @param amount Exp amount to give ++ * @param applyMending Mend players items with mending, with same behavior as picking up orbs. calls {@link #applyMending(int)} + */ +- public void giveExp(int amount); + public void giveExp(int amount, boolean applyMending); + + /** diff --git a/patches/api/0110-EntityShootBowEvent-consumeArrow-and-getArrowItem-AP.patch b/patches/api/0110-EntityShootBowEvent-consumeArrow-and-getArrowItem-AP.patch index ca44e557bb..71a82a8eae 100644 --- a/patches/api/0110-EntityShootBowEvent-consumeArrow-and-getArrowItem-AP.patch +++ b/patches/api/0110-EntityShootBowEvent-consumeArrow-and-getArrowItem-AP.patch @@ -18,7 +18,7 @@ index d4d7ad9c3c953680342c121f39ddaef476549047..719d0d878320c1903b44076053989ba9 + public void setConsumeArrow(boolean consumeArrow) { + this.setConsumeItem(consumeArrow); + } - ++ + @Deprecated + public boolean getConsumeArrow() { + return this.shouldConsumeItem(); @@ -33,7 +33,7 @@ index d4d7ad9c3c953680342c121f39ddaef476549047..719d0d878320c1903b44076053989ba9 + public EntityShootBowEvent(@NotNull final LivingEntity shooter, @Nullable final ItemStack bow, @NotNull final Entity projectile, final float force) { + this(shooter, bow, new ItemStack(org.bukkit.Material.AIR), projectile, force); + } -+ + + @Deprecated + public EntityShootBowEvent(@NotNull final LivingEntity shooter, @Nullable final ItemStack bow, @NotNull ItemStack arrowItem, @NotNull final Entity projectile, final float force) { + this(shooter, bow, arrowItem, projectile, EquipmentSlot.HAND, force, true); diff --git a/patches/api/0139-Inventory-removeItemAnySlot.patch b/patches/api/0139-Inventory-removeItemAnySlot.patch index 9fc8227226..25b79cf6bd 100644 --- a/patches/api/0139-Inventory-removeItemAnySlot.patch +++ b/patches/api/0139-Inventory-removeItemAnySlot.patch @@ -8,7 +8,7 @@ diff --git a/src/main/java/org/bukkit/inventory/Inventory.java b/src/main/java/o index 5576a6a8df8c95164bf2dde45d756ce8b7ec957a..f1a48eab1a357ae64545e1f1dc941c383cff8707 100644 --- a/src/main/java/org/bukkit/inventory/Inventory.java +++ b/src/main/java/org/bukkit/inventory/Inventory.java -@@ -104,7 +104,37 @@ public interface Inventory extends Iterable { +@@ -104,7 +104,9 @@ public interface Inventory extends Iterable { public HashMap addItem(@NotNull ItemStack... items) throws IllegalArgumentException; /** @@ -16,6 +16,25 @@ index 5576a6a8df8c95164bf2dde45d756ce8b7ec957a..f1a48eab1a357ae64545e1f1dc941c38 + * Removes the given ItemStacks from the storage contents of the inventory. + * For removing ItemStacks from the inventories that have other content groups, + * like Player inventories, see {@link #removeItemAnySlot(ItemStack...)}. + *

+ * It will try to remove 'as much as possible' from the types and amounts + * you give as arguments. +@@ -121,10 +123,39 @@ public interface Inventory extends Iterable { + * @param items The ItemStacks to remove + * @return A HashMap containing items that couldn't be removed. + * @throws IllegalArgumentException if items is null ++ * @see #removeItemAnySlot(ItemStack...) + */ + @NotNull + public HashMap removeItem(@NotNull ItemStack... items) throws IllegalArgumentException; + ++ // Paper start ++ /** ++ * Searches all possible inventory slots in order to remove the given ItemStacks. ++ *

++ * Similar to {@link Inventory#removeItem(ItemStack...)} in behavior, except this ++ * method will check all possible slots in the inventory, rather than just the main ++ * storage contents. + *

+ * It will try to remove 'as much as possible' from the types and amounts + * you give as arguments. @@ -32,28 +51,11 @@ index 5576a6a8df8c95164bf2dde45d756ce8b7ec957a..f1a48eab1a357ae64545e1f1dc941c38 + * @param items The ItemStacks to remove + * @return A HashMap containing items that couldn't be removed. + * @throws IllegalArgumentException if items is null -+ * @see #removeItemAnySlot(ItemStack...) + */ + @NotNull -+ public HashMap removeItem(@NotNull ItemStack... items) throws IllegalArgumentException; -+ -+ // Paper start -+ /** -+ * Searches all possible inventory slots in order to remove the given ItemStacks. -+ *

-+ * Similar to {@link Inventory#removeItem(ItemStack...)} in behavior, except this -+ * method will check all possible slots in the inventory, rather than just the main -+ * storage contents. - *

- * It will try to remove 'as much as possible' from the types and amounts - * you give as arguments. -@@ -123,7 +153,8 @@ public interface Inventory extends Iterable { - * @throws IllegalArgumentException if items is null - */ - @NotNull -- public HashMap removeItem(@NotNull ItemStack... items) throws IllegalArgumentException; + public HashMap removeItemAnySlot(@NotNull ItemStack... items) throws IllegalArgumentException; + // Paper end - ++ /** * Returns all ItemStacks from the inventory + * diff --git a/patches/api/0267-Expand-world-key-API.patch b/patches/api/0267-Expand-world-key-API.patch index e49ddc7083..01ab3339ac 100644 --- a/patches/api/0267-Expand-world-key-API.patch +++ b/patches/api/0267-Expand-world-key-API.patch @@ -104,20 +104,16 @@ index cbe6b3a1ba7b04826d97c3558e8eb4e5ba11f92f..cbdcac688afb7c13dd7058fa522bbd2c private final String name; private long seed; private World.Environment environment = World.Environment.NORMAL; -@@ -28,14 +29,81 @@ public class WorldCreator { +@@ -28,13 +29,80 @@ public class WorldCreator { * @param name Name of the world that will be created */ public WorldCreator(@NotNull String name) { - if (name == null) { - throw new IllegalArgumentException("World name cannot be null"); -- } -- -- this.name = name; -- this.seed = (new Random()).nextLong(); + // Paper start + this(name, getWorldKey(name)); - } - ++ } ++ + private static NamespacedKey getWorldKey(String name) { + final String mainLevelName = Bukkit.getUnsafe().getMainLevelName(); + if (name.equals(mainLevelName)) { @@ -128,9 +124,10 @@ index cbe6b3a1ba7b04826d97c3558e8eb4e5ba11f92f..cbdcac688afb7c13dd7058fa522bbd2c + return NamespacedKey.minecraft("the_end"); + } else { + return NamespacedKey.minecraft(name.toLowerCase(java.util.Locale.ENGLISH).replace(" ", "_")); -+ } + } + } -+ + +- this.name = name; + /** + * Creates an empty WorldCreator for the given world name and key + * @@ -142,7 +139,7 @@ index cbe6b3a1ba7b04826d97c3558e8eb4e5ba11f92f..cbdcac688afb7c13dd7058fa522bbd2c + throw new IllegalArgumentException("World name and key cannot be null"); + } + this.name = levelName; -+ this.seed = (new Random()).nextLong(); + this.seed = (new Random()).nextLong(); + this.key = worldKey; + } + @@ -186,9 +183,8 @@ index cbe6b3a1ba7b04826d97c3558e8eb4e5ba11f92f..cbdcac688afb7c13dd7058fa522bbd2c + @NotNull + public static WorldCreator ofKey(@NotNull NamespacedKey worldKey) { + return new WorldCreator(worldKey); -+ } + } + // Paper end -+ + /** * Copies the options from the specified world - * diff --git a/patches/api/0321-Add-more-advancement-API.patch b/patches/api/0321-Add-more-advancement-API.patch index 1fce73dab5..2fd6d7a372 100644 --- a/patches/api/0321-Add-more-advancement-API.patch +++ b/patches/api/0321-Add-more-advancement-API.patch @@ -194,12 +194,8 @@ index 17527c2f7bd5b8a5528388a53f2472bc1869c7f3..3f6b9e59c2ea38031ca74962e02d710f + * recipes. * - * This includes it's name, description and other visible tags. -- * -- * @return a AdvancementDisplay object, or null if not set. + * @return the display info - */ -- @Nullable -- AdvancementDisplay getDisplay(); ++ */ + @org.jetbrains.annotations.Nullable + io.papermc.paper.advancement.AdvancementDisplay getDisplay(); + @@ -209,10 +205,13 @@ index 17527c2f7bd5b8a5528388a53f2472bc1869c7f3..3f6b9e59c2ea38031ca74962e02d710f + * completes the advancement. Will return the same as + * {@link io.papermc.paper.advancement.AdvancementDisplay#displayName()} when an + * {@link io.papermc.paper.advancement.AdvancementDisplay} is present. -+ * + * +- * @return a AdvancementDisplay object, or null if not set. + * @return the display name + * @see io.papermc.paper.advancement.AdvancementDisplay#displayName() -+ */ + */ +- @Nullable +- AdvancementDisplay getDisplay(); + @NotNull net.kyori.adventure.text.Component displayName(); + + /** diff --git a/patches/api/0323-Add-critical-damage-API.patch b/patches/api/0323-Add-critical-damage-API.patch index b8f225d5da..3a9d1f8070 100644 --- a/patches/api/0323-Add-critical-damage-API.patch +++ b/patches/api/0323-Add-critical-damage-API.patch @@ -8,7 +8,7 @@ diff --git a/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.jav index 869bad7405ec7fa67728e90d8b9f2e11b542611f..7ce8f1a26c1b33dd0eb6e6435952fd73abf49879 100644 --- a/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java +++ b/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java -@@ -11,16 +11,41 @@ import org.jetbrains.annotations.NotNull; +@@ -11,15 +11,40 @@ import org.jetbrains.annotations.NotNull; public class EntityDamageByEntityEvent extends EntityDamageEvent { private final Entity damager; @@ -32,8 +32,8 @@ index 869bad7405ec7fa67728e90d8b9f2e11b542611f..7ce8f1a26c1b33dd0eb6e6435952fd73 this.damager = damager; + // Paper start - add critical damage API + this.critical = critical; - } - ++ } ++ + /** + * Shows this damage instance was critical. + * The damage instance can be critical if the attacking player met the respective conditions. @@ -44,9 +44,8 @@ index 869bad7405ec7fa67728e90d8b9f2e11b542611f..7ce8f1a26c1b33dd0eb6e6435952fd73 + */ + public boolean isCritical() { + return this.critical; -+ } + } + // Paper end -+ + /** * Returns the entity that damaged the defender. - * diff --git a/patches/api/0406-Improve-PortalEvents.patch b/patches/api/0406-Improve-PortalEvents.patch index 8c5aa2655d..f7f53b19fc 100644 --- a/patches/api/0406-Improve-PortalEvents.patch +++ b/patches/api/0406-Improve-PortalEvents.patch @@ -8,7 +8,7 @@ diff --git a/src/main/java/org/bukkit/event/entity/EntityPortalEvent.java b/src/ index 67fb9d93e808e907fa980f3004d415ae5d0a53fc..97e36c7f6e09276fbae20eaeee0965566332ca46 100644 --- a/src/main/java/org/bukkit/event/entity/EntityPortalEvent.java +++ b/src/main/java/org/bukkit/event/entity/EntityPortalEvent.java -@@ -15,16 +15,59 @@ import org.jetbrains.annotations.Nullable; +@@ -15,15 +15,58 @@ import org.jetbrains.annotations.Nullable; public class EntityPortalEvent extends EntityTeleportEvent { private static final HandlerList handlers = new HandlerList(); private int searchRadius = 128; @@ -23,8 +23,8 @@ index 67fb9d93e808e907fa980f3004d415ae5d0a53fc..97e36c7f6e09276fbae20eaeee096556 super(entity, from, to); this.searchRadius = searchRadius; + this.type = org.bukkit.PortalType.CUSTOM; // Paper - } - ++ } ++ + // Paper start + public EntityPortalEvent(@NotNull Entity entity, @NotNull Location from, @Nullable Location to, int searchRadius, final @NotNull org.bukkit.PortalType portalType) { + super(entity, from, to); @@ -63,12 +63,11 @@ index 67fb9d93e808e907fa980f3004d415ae5d0a53fc..97e36c7f6e09276fbae20eaeee096556 + @Override + public void setTo(@Nullable final Location to) { + super.setTo(to); -+ } + } + // Paper end -+ + /** * Set the Block radius to search in for available portals. - * diff --git a/src/main/java/org/bukkit/event/player/PlayerPortalEvent.java b/src/main/java/org/bukkit/event/player/PlayerPortalEvent.java index 57eeeafae84f83a939925820e827769749ff27ec..929a997671de8202efb9da97fbf9b4a0bf7c37e8 100644 --- a/src/main/java/org/bukkit/event/player/PlayerPortalEvent.java diff --git a/patches/server/0009-MC-Utils.patch b/patches/server/0009-MC-Utils.patch index fe1c0f306b..cd3303b7f0 100644 --- a/patches/server/0009-MC-Utils.patch +++ b/patches/server/0009-MC-Utils.patch @@ -7674,12 +7674,12 @@ index d2026d218405a40a6949c5f491c04704811b72b5..629178347039893fb9de710810fe8112 + public ChunkAccess getChunkIfLoadedImmediately(int x, int z) { + throw new UnsupportedOperationException("Not supported yet."); + } - ++ + @Override + public BlockState getBlockStateIfLoaded(BlockPos blockposition) { + throw new UnsupportedOperationException("Not supported yet."); + } -+ + + @Override + public FluidState getFluidIfLoaded(BlockPos blockposition) { + throw new UnsupportedOperationException("Not supported yet."); diff --git a/patches/server/0010-Adventure.patch b/patches/server/0010-Adventure.patch index 8c51cf6e6d..65e1b0fe3a 100644 --- a/patches/server/0010-Adventure.patch +++ b/patches/server/0010-Adventure.patch @@ -2322,14 +2322,13 @@ index 000fd11480d783eab80a93fedde48f66e6b1298b..b3b6121dcfb6451d177431d51fa8a3e0 - @Deprecated - public void disconnect(Component reason) { - this.disconnect(CraftChatMessage.fromComponent(reason)); -- } -- // CraftBukkit end -- - public void disconnect(String s) { ++ public void disconnect(String s) { + // Paper start + this.disconnect(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(s)); -+ } -+ + } +- // CraftBukkit end + +- public void disconnect(String s) { + public void disconnect(final Component reason) { + this.disconnect(PaperAdventure.asAdventure(reason)); + } @@ -2810,13 +2809,13 @@ index 059ba63319f6ca04750a7d6b095e6179cae68b4f..cb2dc6db887856c5f60d127f5999a078 } + // Paper start - @Override ++ @Override + public net.kyori.adventure.text.Component shutdownMessage() { + String msg = getShutdownMessage(); + return msg != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(msg) : null; + } + // Paper end -+ @Override + @Override + @Deprecated // Paper public String getShutdownMessage() { return this.configuration.getString("settings.shutdown-message"); @@ -2893,12 +2892,12 @@ index 059ba63319f6ca04750a7d6b095e6179cae68b4f..cb2dc6db887856c5f60d127f5999a078 } + // Paper start - @Override ++ @Override + public Merchant createMerchant(net.kyori.adventure.text.Component title) { + return new org.bukkit.craftbukkit.inventory.CraftMerchantCustom(title == null ? InventoryType.MERCHANT.defaultTitle() : title); + } + // Paper end -+ @Override + @Override + @Deprecated // Paper public Merchant createMerchant(String title) { return new CraftMerchantCustom(title == null ? InventoryType.MERCHANT.getDefaultTitle() : title); diff --git a/patches/server/0016-Starlight.patch b/patches/server/0016-Starlight.patch index 1741b5b0a1..da5f1b8108 100644 --- a/patches/server/0016-Starlight.patch +++ b/patches/server/0016-Starlight.patch @@ -4545,13 +4545,13 @@ index 5b238e41ffa3e374b52ee955cb39087571c6ffc2..275b7f7dd36a2073a3eb9f89f4c83283 + this.hasSkyLight = hasBlockLight; // Nice variable name. + this.theLightEngine = new ca.spottedleaf.starlight.common.light.StarLightInterface(chunkProvider, this.hasSkyLight, this.hasBlockLight, this); + // Paper end - replace light engine impl - } - ++ } ++ + // Paper start - replace light engine impl + protected final ChunkAccess getChunk(final int chunkX, final int chunkZ) { + return ((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().getChunkAtImmediately(chunkX, chunkZ); -+ } -+ + } + + protected long relightCounter; + + public int relight(java.util.Set chunks_param, @@ -5167,13 +5167,13 @@ index aa4f2dc63dd79e6c3d7594d2fd63fa0091df5f53..bca8084f7e76d036378705aa802217cc + } else if (flag1) { + skyNibbles[y - minSection] = new ca.spottedleaf.starlight.common.light.SWMRNibbleArray(null, sectionData.getInt(SKYLIGHT_STATE_TAG)); + // Paper end - rewrite the light engine - } ++ } + + // Paper start - rewrite the light engine + } catch (Exception ex) { + LOGGER.warn("Failed to load light data for chunk " + chunkPos + " in world '" + world.getWorld().getName() + "', light will be regenerated", ex); + flag = false; -+ } + } + // Paper end - rewrite light engine } } diff --git a/patches/server/0018-Rewrite-chunk-system.patch b/patches/server/0018-Rewrite-chunk-system.patch index 028e662121..496406cca1 100644 --- a/patches/server/0018-Rewrite-chunk-system.patch +++ b/patches/server/0018-Rewrite-chunk-system.patch @@ -13176,15 +13176,7 @@ index 30e330cc3a2f51e4ec9555671e3eeb7bb14bdfa3..214e0657035f82e5266de06e31975d6b - entityplayer.connection.send(packet); - }); - } -+ // Paper start - per player view distance -+ // there can be potential desync with player's last mapped section and the view distance map, so use the -+ // view distance map here. -+ com.destroystokyo.paper.util.misc.PlayerAreaMap viewDistanceMap = this.chunkMap.playerChunkManager.broadcastMap; // Paper - replace old player chunk manager -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet players = viewDistanceMap.getObjectsInRange(this.pos); -+ if (players == null) { -+ return; -+ } - +- - public CompletableFuture> getOrScheduleFuture(ChunkStatus targetStatus, ChunkMap chunkStorage) { - int i = targetStatus.getIndex(); - CompletableFuture> completablefuture = (CompletableFuture) this.futures.get(i); @@ -13194,7 +13186,15 @@ index 30e330cc3a2f51e4ec9555671e3eeb7bb14bdfa3..214e0657035f82e5266de06e31975d6b - - if (either == null) { - String s = "value in future for status: " + targetStatus + " was incorrectly set to null at chunk: " + this.pos; -- ++ // Paper start - per player view distance ++ // there can be potential desync with player's last mapped section and the view distance map, so use the ++ // view distance map here. ++ com.destroystokyo.paper.util.misc.PlayerAreaMap viewDistanceMap = this.chunkMap.playerChunkManager.broadcastMap; // Paper - replace old player chunk manager ++ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet players = viewDistanceMap.getObjectsInRange(this.pos); ++ if (players == null) { ++ return; ++ } + - throw chunkStorage.debugFuturesAndCreateReportedException(new IllegalStateException("null value previously set for chunk status"), s); + Object[] backingSet = players.getBackingSet(); + for (int i = 0, len = backingSet.length; i < len; ++i) { @@ -13258,9 +13258,8 @@ index 30e330cc3a2f51e4ec9555671e3eeb7bb14bdfa3..214e0657035f82e5266de06e31975d6b public final int getTicketLevel() { // Paper - final for inline - return this.ticketLevel; -+ return this.newChunkHolder.getTicketLevel(); // Paper - rewrite chunk system - } - +- } +- - public int getQueueLevel() { - return this.queueLevel; - } @@ -13286,8 +13285,9 @@ index 30e330cc3a2f51e4ec9555671e3eeb7bb14bdfa3..214e0657035f82e5266de06e31975d6b - completablefuture1.complete(null); // CraftBukkit - decompile error - }); - }); -- } -- ++ return this.newChunkHolder.getTicketLevel(); // Paper - rewrite chunk system + } + - private void demoteFullChunk(ChunkMap playerchunkmap, ChunkHolder.FullChunkStatus playerchunk_state) { - this.pendingFullStateConfirmation.cancel(false); - playerchunkmap.onFullChunkStatusChange(this.pos, playerchunk_state); @@ -13823,16 +13823,15 @@ index 578849f64de38dc75cdefeb243422c4c89a5c69c..9246ce9f654ad4db6155b026778a83d4 - } finally { - super.close(); - } -- + throw new UnsupportedOperationException("Use ServerChunkCache#close"); // Paper - rewrite chunk system - } ++ } + // Paper start - rewrite chunk system + protected void saveIncrementally() { + this.level.chunkTaskScheduler.chunkHolderManager.autoSave(); // Paper - rewrite chunk system -+ } + } + // Paper end - - rewrite chunk system -+ + protected void saveAllChunks(boolean flush) { - if (flush) { - List list = (List) io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper @@ -14492,25 +14491,21 @@ index 578849f64de38dc75cdefeb243422c4c89a5c69c..9246ce9f654ad4db6155b026778a83d4 - Set set = this.playerMap.getPlayers(chunkPos.toLong()); - Builder builder = ImmutableList.builder(); - Iterator iterator = set.iterator(); -- -- while (iterator.hasNext()) { -- ServerPlayer entityplayer = (ServerPlayer) iterator.next(); -- SectionPos sectionposition = entityplayer.getLastSectionPos(); -- -- if (onlyOnWatchDistanceEdge && ChunkMap.isChunkOnRangeBorder(chunkPos.x, chunkPos.z, sectionposition.x(), sectionposition.z(), this.viewDistance) || !onlyOnWatchDistanceEdge && ChunkMap.isChunkInRange(chunkPos.x, chunkPos.z, sectionposition.x(), sectionposition.z(), this.viewDistance)) { -- builder.add(entityplayer); -- } + // Paper start - per player view distance + // there can be potential desync with player's last mapped section and the view distance map, so use the + // view distance map here. + com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet players = this.playerChunkManager.broadcastMap.getObjectsInRange(chunkPos); + if (players == null) { + return java.util.Collections.emptyList(); - } ++ } -- return builder.build(); +- while (iterator.hasNext()) { +- ServerPlayer entityplayer = (ServerPlayer) iterator.next(); +- SectionPos sectionposition = entityplayer.getLastSectionPos(); + List ret = new java.util.ArrayList<>(players.size()); -+ + +- if (onlyOnWatchDistanceEdge && ChunkMap.isChunkOnRangeBorder(chunkPos.x, chunkPos.z, sectionposition.x(), sectionposition.z(), this.viewDistance) || !onlyOnWatchDistanceEdge && ChunkMap.isChunkInRange(chunkPos.x, chunkPos.z, sectionposition.x(), sectionposition.z(), this.viewDistance)) { +- builder.add(entityplayer); + Object[] backingSet = players.getBackingSet(); + for (int i = 0, len = backingSet.length; i < len; ++i) { + if (!(backingSet[i] instanceof ServerPlayer player)) { @@ -14518,10 +14513,11 @@ index 578849f64de38dc75cdefeb243422c4c89a5c69c..9246ce9f654ad4db6155b026778a83d4 + } + if (!this.playerChunkManager.isChunkSent(player, chunkPos.x, chunkPos.z, onlyOnWatchDistanceEdge)) { + continue; -+ } + } + ret.add(player); -+ } -+ + } + +- return builder.build(); + return ret; + // Paper end - per player view distance } @@ -14887,8 +14883,7 @@ index d38ad1b1eee92a6dbd2b79b4fcdb8959cdb4007d..ffa1e457decf8502c3283352bf5be94d - private void dumpTickets(String path) { - try { - FileOutputStream fileoutputstream = new FileOutputStream(new File(path)); -+ // Paper - rewrite chunk system - +- - try { - ObjectIterator objectiterator = this.tickets.long2ObjectEntrySet().iterator(); - @@ -14909,7 +14904,8 @@ index d38ad1b1eee92a6dbd2b79b4fcdb8959cdb4007d..ffa1e457decf8502c3283352bf5be94d - } catch (Throwable throwable1) { - throwable.addSuppressed(throwable1); - } -- ++ // Paper - rewrite chunk system + - throw throwable; - } - @@ -15129,23 +15125,29 @@ index 28c8a3ba1caddf0ea334a6ef43cae25f982743e4..80d108ae7faf3fdcb024931e93032215 - ChunkHolder.FullChunkStatus oldChunkState = ChunkHolder.getFullChunkStatus(playerchunk.oldTicketLevel); - ChunkHolder.FullChunkStatus currentChunkState = ChunkHolder.getFullChunkStatus(playerchunk.getTicketLevel()); - currentlyUnloading = (oldChunkState.isOrAfter(ChunkHolder.FullChunkStatus.BORDER) && !currentChunkState.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)); -+ boolean needsFullScheduling = leastStatus == ChunkStatus.FULL && (chunkHolder == null || !chunkHolder.getChunkStatus().isOrAfter(ChunkHolder.FullChunkStatus.BORDER)); -+ -+ if ((chunkHolder == null || chunkHolder.getTicketLevel() > minLevel || needsFullScheduling) && !create) { -+ return ChunkHolder.UNLOADED_CHUNK_FUTURE; - } +- } - if (create && !currentlyUnloading) { - // CraftBukkit end - this.distanceManager.addTicket(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair); - if (this.chunkAbsent(playerchunk, l)) { - ProfilerFiller gameprofilerfiller = this.level.getProfiler(); - +- - gameprofilerfiller.push("chunkLoad"); - this.runDistanceManagerUpdates(); - playerchunk = this.getVisibleChunkIfPresent(k); - gameprofilerfiller.pop(); - if (this.chunkAbsent(playerchunk, l)) { - throw (IllegalStateException) Util.pauseInIde(new IllegalStateException("No chunk holder after ticket has been added")); +- } +- } ++ boolean needsFullScheduling = leastStatus == ChunkStatus.FULL && (chunkHolder == null || !chunkHolder.getChunkStatus().isOrAfter(ChunkHolder.FullChunkStatus.BORDER)); ++ ++ if ((chunkHolder == null || chunkHolder.getTicketLevel() > minLevel || needsFullScheduling) && !create) { ++ return ChunkHolder.UNLOADED_CHUNK_FUTURE; + } + +- return this.chunkAbsent(playerchunk, l) ? ChunkHolder.UNLOADED_CHUNK_FUTURE : playerchunk.getOrScheduleFuture(leastStatus, this.chunkMap); +- } + io.papermc.paper.chunk.system.scheduling.NewChunkHolder.ChunkCompletion chunkCompletion = chunkHolder == null ? null : chunkHolder.getLastChunkCompletion(); + if (needsFullScheduling || chunkCompletion == null || !chunkCompletion.genStatus().isOrAfter(leastStatus)) { + // schedule @@ -15155,10 +15157,11 @@ index 28c8a3ba1caddf0ea334a6ef43cae25f982743e4..80d108ae7faf3fdcb024931e93032215 + ret.complete(Either.right(ChunkHolder.ChunkLoadingFailure.UNLOADED)); + } else { + ret.complete(Either.left(chunk)); - } -- } ++ } + }; -+ + +- private boolean chunkAbsent(@Nullable ChunkHolder holder, int maxLevel) { +- return holder == null || holder.oldTicketLevel > maxLevel; // CraftBukkit using oldTicketLevel for isLoaded checks + this.level.chunkTaskScheduler.scheduleChunkLoad( + chunkX, chunkZ, leastStatus, true, + isUrgent ? ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.BLOCKING : ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.NORMAL, @@ -15169,17 +15172,12 @@ index 28c8a3ba1caddf0ea334a6ef43cae25f982743e4..80d108ae7faf3fdcb024931e93032215 + } else { + // can return now + return CompletableFuture.completedFuture(Either.left(chunkCompletion.chunk())); - } -- -- return this.chunkAbsent(playerchunk, l) ? ChunkHolder.UNLOADED_CHUNK_FUTURE : playerchunk.getOrScheduleFuture(leastStatus, this.chunkMap); ++ } + // Paper end - rewrite chunk system } -- private boolean chunkAbsent(@Nullable ChunkHolder holder, int maxLevel) { -- return holder == null || holder.oldTicketLevel > maxLevel; // CraftBukkit using oldTicketLevel for isLoaded checks -- } + // Paper - rewrite chunk system - ++ @Override public boolean hasChunk(int x, int z) { - ChunkHolder playerchunk = this.getVisibleChunkIfPresent((new ChunkPos(x, z)).toLong()); @@ -16534,21 +16532,7 @@ index 69f55f7207b8c03ca886947c57c9d13a8e8eb576..0517c0932b79db1a0e27673654ae8bb5 - if (result.size() >= limit) { - return AbortableIterationConsumer.Continuation.ABORT; - } -+ // Paper start - optimise this call -+ //TODO use limit -+ if (filter instanceof net.minecraft.world.entity.EntityType entityTypeTest) { -+ ((ServerLevel) this).getEntityLookup().getEntities(entityTypeTest, box, result, predicate); -+ } else { -+ Predicate test = (obj) -> { -+ return filter.tryCast(obj) != null; -+ }; -+ predicate = predicate == null ? test : test.and((Predicate) predicate); -+ Class base; -+ if (filter == null || (base = filter.getBaseClass()) == null || base == Entity.class) { -+ ((ServerLevel) this).getEntityLookup().getEntities((Entity) null, box, (List) result, (Predicate)predicate); -+ } else { -+ ((ServerLevel) this).getEntityLookup().getEntities(base, null, box, (List) result, (Predicate)predicate); // Paper - optimise this call - } +- } - - if (entity instanceof EnderDragon) { - EnderDragon entityenderdragon = (EnderDragon) entity; @@ -16566,7 +16550,21 @@ index 69f55f7207b8c03ca886947c57c9d13a8e8eb576..0517c0932b79db1a0e27673654ae8bb5 - } - } - } -- } ++ // Paper start - optimise this call ++ //TODO use limit ++ if (filter instanceof net.minecraft.world.entity.EntityType entityTypeTest) { ++ ((ServerLevel) this).getEntityLookup().getEntities(entityTypeTest, box, result, predicate); ++ } else { ++ Predicate test = (obj) -> { ++ return filter.tryCast(obj) != null; ++ }; ++ predicate = predicate == null ? test : test.and((Predicate) predicate); ++ Class base; ++ if (filter == null || (base = filter.getBaseClass()) == null || base == Entity.class) { ++ ((ServerLevel) this).getEntityLookup().getEntities((Entity) null, box, (List) result, (Predicate)predicate); ++ } else { ++ ((ServerLevel) this).getEntityLookup().getEntities(base, null, box, (List) result, (Predicate)predicate); // Paper - optimise this call + } - - return AbortableIterationConsumer.Continuation.CONTINUE; - }); @@ -16968,15 +16966,15 @@ index bca8084f7e76d036378705aa802217cc1bfdbc7d..f9dd2d9312297a727344d43150c5cab7 } else { ProtoChunk protochunk1 = (ProtoChunk) object1; -@@ -362,10 +388,42 @@ public class ChunkSerializer { +@@ -362,9 +388,41 @@ public class ChunkSerializer { protochunk1.setCarvingMask(worldgenstage_features, new CarvingMask(nbttagcompound4.getLongArray(s1), ((ChunkAccess) object1).getMinBuildHeight())); } - return protochunk1; + return new InProgressChunkHolder(protochunk1, tasksToExecuteOnMain); // Paper - Async chunk loading - } - } - ++ } ++ } ++ + // Paper start - async chunk save for unload + public record AsyncSaveData( + Tag blockTickList, // non-null if we had to go to the server's tick list @@ -16998,7 +16996,7 @@ index bca8084f7e76d036378705aa802217cc1bfdbc7d..f9dd2d9312297a727344d43150c5cab7 + if (blockEntityNbt != null) { + blockEntitiesSerialized.add(blockEntityNbt); + } -+ } + } + + return new AsyncSaveData( + tickLists.get(BLOCK_TICKS_TAG), @@ -17006,12 +17004,11 @@ index bca8084f7e76d036378705aa802217cc1bfdbc7d..f9dd2d9312297a727344d43150c5cab7 + blockEntitiesSerialized, + world.getGameTime() + ); -+ } + } + // Paper end -+ + private static void logErrors(ChunkPos chunkPos, int y, String message) { ChunkSerializer.LOGGER.error("Recoverable errors when loading section [" + chunkPos.x + ", " + y + ", " + chunkPos.z + "]: " + message); - } @@ -381,6 +439,11 @@ public class ChunkSerializer { // CraftBukkit end @@ -17151,11 +17148,11 @@ index ba267f3082607669282a61f013991e1c391a3f09..0747d2d411a85a26bfea08cc1dd29df6 + } catch (Throwable thr) { + return CompletableFuture.failedFuture(thr); + } - } ++ } + @Nullable + public CompoundTag readSync(ChunkPos chunkPos) throws IOException { + return this.regionFileCache.read(chunkPos); -+ } + } + // Paper end - async chunk io - public void write(ChunkPos chunkPos, CompoundTag nbt) { @@ -17242,17 +17239,17 @@ index 98b3909b536f11eda9c481ffd74066ad0cdb0ebc..0ec0be22f7292d57c40da6f1f4575bde - } - }, this.entityDeserializerQueue::tell); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system - copy out read logic into readEntities - } - -- private static ChunkPos readChunkPos(CompoundTag chunkNbt) { ++ } ++ + // Paper start - rewrite chunk system + public static List readEntities(ServerLevel level, CompoundTag compoundTag) { + ListTag listTag = compoundTag.getList("Entities", 10); + List list = EntityType.loadEntitiesRecursive(listTag, level).collect(ImmutableList.toImmutableList()); + return list; -+ } + } + // Paper end - rewrite chunk system -+ + +- private static ChunkPos readChunkPos(CompoundTag chunkNbt) { + public static ChunkPos readChunkPos(CompoundTag chunkNbt) { // Paper - public int[] is = chunkNbt.getIntArray("Position"); return new ChunkPos(is[0], is[1]); @@ -17294,10 +17291,6 @@ index 98b3909b536f11eda9c481ffd74066ad0cdb0ebc..0ec0be22f7292d57c40da6f1f4575bde } } -- @Override -- public void flush(boolean sync) { -- this.worker.synchronize(sync).join(); -- this.entityDeserializerQueue.runAll(); + // Paper start - rewrite chunk system + public static void copyEntities(final CompoundTag from, final CompoundTag into) { + if (from == null) { @@ -17311,9 +17304,8 @@ index 98b3909b536f11eda9c481ffd74066ad0cdb0ebc..0ec0be22f7292d57c40da6f1f4575bde + final ListTag entitiesInto = into.getList("Entities", net.minecraft.nbt.Tag.TAG_COMPOUND); + into.put("Entities", entitiesInto); // this is in case into doesn't have any entities + entitiesInto.addAll(0, entitiesFrom.copy()); // need to copy, this is coming from the save thread - } - -- private CompoundTag upgradeChunkTag(CompoundTag chunkNbt) { ++ } ++ + public static CompoundTag saveEntityChunk(List entities, ChunkPos chunkPos, ServerLevel level) { + return saveEntityChunk0(entities, chunkPos, level, false); + } @@ -17339,11 +17331,14 @@ index 98b3909b536f11eda9c481ffd74066ad0cdb0ebc..0ec0be22f7292d57c40da6f1f4575bde + } + // Paper end - rewrite chunk system + -+ @Override -+ public void flush(boolean sync) { + @Override + public void flush(boolean sync) { +- this.worker.synchronize(sync).join(); +- this.entityDeserializerQueue.runAll(); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system -+ } -+ + } + +- private CompoundTag upgradeChunkTag(CompoundTag chunkNbt) { + public static CompoundTag upgradeChunkTag(CompoundTag chunkNbt) { // Paper - public and static int i = NbtUtils.getDataVersion(chunkNbt, -1); return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.ENTITY_CHUNK, chunkNbt, i, net.minecraft.SharedConstants.getCurrentVersion().getDataVersion().getVersion()); // Paper - route to new converter system diff --git a/patches/server/0030-Player-affects-spawning-API.patch b/patches/server/0030-Player-affects-spawning-API.patch index 8b945d0813..5f1d813eef 100644 --- a/patches/server/0030-Player-affects-spawning-API.patch +++ b/patches/server/0030-Player-affects-spawning-API.patch @@ -145,13 +145,13 @@ index 7b57298ee6c9422fa10dde9cf9441ea10b3443e4..f9cf8b94890be80e383d1e24671aa8b1 public String getLocale() { return this.getHandle().locale; + - } - ++ } ++ + // Paper start + public void setAffectsSpawning(boolean affects) { + this.getHandle().affectsSpawning = affects; -+ } -+ + } + + @Override + public boolean getAffectsSpawning() { + return this.getHandle().affectsSpawning; diff --git a/patches/server/0031-Further-improve-server-tick-loop.patch b/patches/server/0031-Further-improve-server-tick-loop.patch index 8168fa8c75..fd0baf2e6a 100644 --- a/patches/server/0031-Further-improve-server-tick-loop.patch +++ b/patches/server/0031-Further-improve-server-tick-loop.patch @@ -185,10 +185,7 @@ index 4ab81a99f906e3f28e026d0e50b5b943c1bdcfb5..9bede6a26c08ede063c7a38f1149c811 + + for ( int i = 0; i < tps.length; i++) { + tpsAvg[i] = TicksPerSecondCommand.format( tps[i] ); - } -- sender.sendMessage( sb.substring( 0, sb.length() - 2 ) ); -- sender.sendMessage(ChatColor.GOLD + "Current Memory Usage: " + ChatColor.GREEN + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024)) + "/" + (Runtime.getRuntime().totalMemory() / (1024 * 1024)) + " mb (Max: " -- + (Runtime.getRuntime().maxMemory() / (1024 * 1024)) + " mb)"); ++ } + sender.sendMessage(ChatColor.GOLD + "TPS from last 1m, 5m, 15m: " + org.apache.commons.lang.StringUtils.join(tpsAvg, ", ")); + if (args.length > 0 && args[0].equals("mem") && sender.hasPermission("bukkit.command.tpsmemory")) { + sender.sendMessage(ChatColor.GOLD + "Current Memory Usage: " + ChatColor.GREEN + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024)) + "/" + (Runtime.getRuntime().totalMemory() / (1024 * 1024)) + " mb (Max: " + (Runtime.getRuntime().maxMemory() / (1024 * 1024)) + " mb)"); @@ -196,7 +193,10 @@ index 4ab81a99f906e3f28e026d0e50b5b943c1bdcfb5..9bede6a26c08ede063c7a38f1149c811 + sender.sendMessage(ChatColor.RED + "Warning: " + ChatColor.GOLD + " Memory usage on modern garbage collectors is not a stable value and it is perfectly normal to see it reach max. Please do not pay it much attention."); + hasShownMemoryWarning = true; + } -+ } + } +- sender.sendMessage( sb.substring( 0, sb.length() - 2 ) ); +- sender.sendMessage(ChatColor.GOLD + "Current Memory Usage: " + ChatColor.GREEN + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024)) + "/" + (Runtime.getRuntime().totalMemory() / (1024 * 1024)) + " mb (Max: " +- + (Runtime.getRuntime().maxMemory() / (1024 * 1024)) + " mb)"); + // Paper end return true; diff --git a/patches/server/0033-Entity-Origin-API.patch b/patches/server/0033-Entity-Origin-API.patch index cf616bf8a6..66cb388d44 100644 --- a/patches/server/0033-Entity-Origin-API.patch +++ b/patches/server/0033-Entity-Origin-API.patch @@ -37,12 +37,12 @@ index 969fbf3959733200b1dfb98a8520465e358018c5..3cc8426283f68db0a4cbda6934aa6bfd + private org.bukkit.util.Vector origin; + @javax.annotation.Nullable + private UUID originWorld; - ++ + public void setOrigin(@javax.annotation.Nonnull Location location) { + this.origin = location.toVector(); + this.originWorld = location.getWorld().getUID(); + } -+ + + @javax.annotation.Nullable + public org.bukkit.util.Vector getOriginVector() { + return this.origin != null ? this.origin.clone() : null; diff --git a/patches/server/0069-Handle-Item-Meta-Inconsistencies.patch b/patches/server/0069-Handle-Item-Meta-Inconsistencies.patch index fb8484ecf5..9c0c427336 100644 --- a/patches/server/0069-Handle-Item-Meta-Inconsistencies.patch +++ b/patches/server/0069-Handle-Item-Meta-Inconsistencies.patch @@ -130,14 +130,7 @@ index 1e5ec95e19aca0530c141b6415fe6daca4f2d066..da5e660860a46227c59567f6458a9cf4 - ListTag list = CraftItemStack.getEnchantmentList(this.handle), listCopy; - if (list == null) { - return 0; -+ // Paper start - replace entire method -+ int level = getEnchantmentLevel(ench); -+ if (level > 0) { -+ final ItemMeta itemMeta = this.getItemMeta(); -+ if (itemMeta == null) return 0; -+ itemMeta.removeEnchant(ench); -+ this.setItemMeta(itemMeta); - } +- } - int index = Integer.MIN_VALUE; - int level = Integer.MIN_VALUE; - int size = list.size(); @@ -169,7 +162,14 @@ index 1e5ec95e19aca0530c141b6415fe6daca4f2d066..da5e660860a46227c59567f6458a9cf4 - if (i != index) { - listCopy.add(list.get(i)); - } -- } ++ // Paper start - replace entire method ++ int level = getEnchantmentLevel(ench); ++ if (level > 0) { ++ final ItemMeta itemMeta = this.getItemMeta(); ++ if (itemMeta == null) return 0; ++ itemMeta.removeEnchant(ench); ++ this.setItemMeta(itemMeta); + } - this.handle.getTag().put(ENCHANTMENTS.NBT, listCopy); + // Paper end diff --git a/patches/server/0076-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch b/patches/server/0076-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch index 639ad2fd23..b11ae54fff 100644 --- a/patches/server/0076-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch +++ b/patches/server/0076-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch @@ -103,7 +103,7 @@ index 58048d90a66cf3291a31d7c1f13ae66eac04ed64..8775163c42d639516a533559eaf312ee - int k = pos.getZ(); + return this.getBlockStateFinal(pos.getX(), pos.getY(), pos.getZ()); + } - ++ + @Override + public BlockState getBlockState(final int x, final int y, final int z) { + return this.getBlockStateFinal(x, y, z); @@ -116,7 +116,7 @@ index 58048d90a66cf3291a31d7c1f13ae66eac04ed64..8775163c42d639516a533559eaf312ee + } + // Inlined ChunkSection.getType() and DataPaletteBlock.a(int,int,int) + return this.sections[i].states.get((y & 15) << 8 | (z & 15) << 4 | x & 15); -+ + + } + + public BlockState getBlockState_unused(int i, int j, int k) { diff --git a/patches/server/0083-Add-PlayerUseUnknownEntityEvent.patch b/patches/server/0083-Add-PlayerUseUnknownEntityEvent.patch index 561ff802a2..6a873688ae 100644 --- a/patches/server/0083-Add-PlayerUseUnknownEntityEvent.patch +++ b/patches/server/0083-Add-PlayerUseUnknownEntityEvent.patch @@ -25,7 +25,7 @@ diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListener index cf905220ac5bbce62e5e061f0dfc96906fc29328..dfff872200195b90c51b05188b4a3c53e799249d 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2534,9 +2534,38 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2534,8 +2534,37 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic }); } } @@ -48,8 +48,8 @@ index cf905220ac5bbce62e5e061f0dfc96906fc29328..dfff872200195b90c51b05188b4a3c53 + } + }); + } - - } ++ ++ } + private void callPlayerUseUnknownEntityEvent(ServerboundInteractPacket packet, InteractionHand hand) { + this.cserver.getPluginManager().callEvent(new com.destroystokyo.paper.event.player.PlayerUseUnknownEntityEvent( @@ -58,9 +58,8 @@ index cf905220ac5bbce62e5e061f0dfc96906fc29328..dfff872200195b90c51b05188b4a3c53 + packet.getActionType() == ServerboundInteractPacket.ActionType.ATTACK, + hand == InteractionHand.MAIN_HAND ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND + )); -+ } + } + // Paper end -+ + @Override public void handleClientCommand(ServerboundClientCommandPacket packet) { - PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel()); diff --git a/patches/server/0129-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch b/patches/server/0129-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch index a4848f8a17..ff6c38d923 100644 --- a/patches/server/0129-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch +++ b/patches/server/0129-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch @@ -32,7 +32,7 @@ index 5a79b49e321cba352d8e4189dfbfdd0506ec3e5a..f9488311524bb8ff8a5686763973c9ae + public java.util.UUID sourceEntityId; + public java.util.UUID triggerEntityId; + public org.bukkit.entity.ExperienceOrb.SpawnReason spawnReason = org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN; - ++ + private void loadPaperNBT(CompoundTag nbttagcompound) { + if (!nbttagcompound.contains("Paper.ExpData", 10)) { // 10 = compound + return; @@ -66,7 +66,7 @@ index 5a79b49e321cba352d8e4189dfbfdd0506ec3e5a..f9488311524bb8ff8a5686763973c9ae + } + nbttagcompound.put("Paper.ExpData", comp); + } -+ + + @io.papermc.paper.annotation.DoNotUse + @Deprecated public ExperienceOrb(Level world, double x, double y, double z, int amount) { diff --git a/patches/server/0133-Properly-handle-async-calls-to-restart-the-server.patch b/patches/server/0133-Properly-handle-async-calls-to-restart-the-server.patch index c77004f048..f300f0d556 100644 --- a/patches/server/0133-Properly-handle-async-calls-to-restart-the-server.patch +++ b/patches/server/0133-Properly-handle-async-calls-to-restart-the-server.patch @@ -98,10 +98,24 @@ index 94d8ba376cd1f024b244654cac9bb62bb19e3060..a142a56a920e153ed84c08cece993f10 + if ( isRestarting ) { - System.out.println( "Attempting to restart with " + restartScript ); -- ++ System.out.println( "Attempting to restart with " + SpigotConfig.restartScript ); ++ } else ++ { ++ System.out.println( "Startup script '" + SpigotConfig.restartScript + "' does not exist! Stopping server." ); ++ } ++ // Stop the watchdog ++ WatchdogThread.doStop(); + - // Disable Watchdog - WatchdogThread.doStop(); -- ++ shutdownServer( isRestarting ); ++ // Paper end ++ } catch ( Exception ex ) ++ { ++ ex.printStackTrace(); ++ } ++ } + - // Kick all players - for ( ServerPlayer p : (List) MinecraftServer.getServer().getPlayerList().players ) - { @@ -116,73 +130,6 @@ index 94d8ba376cd1f024b244654cac9bb62bb19e3060..a142a56a920e153ed84c08cece993f10 - } - // Close the socket so we can rebind with the new process - MinecraftServer.getServer().getConnection().stop(); -- -- // Give time for it to kick in -- try -- { -- Thread.sleep( 100 ); -- } catch ( InterruptedException ex ) -- { -- } -- -- // Actually shutdown -- try -- { -- MinecraftServer.getServer().close(); -- } catch ( Throwable t ) -- { -- } -- -- // This will be done AFTER the server has completely halted -- Thread shutdownHook = new Thread() -- { -- @Override -- public void run() -- { -- try -- { -- String os = System.getProperty( "os.name" ).toLowerCase(java.util.Locale.ENGLISH); -- if ( os.contains( "win" ) ) -- { -- Runtime.getRuntime().exec( "cmd /c start " + restartScript ); -- } else -- { -- Runtime.getRuntime().exec( "sh " + restartScript ); -- } -- } catch ( Exception e ) -- { -- e.printStackTrace(); -- } -- } -- }; -- -- shutdownHook.setDaemon( true ); -- Runtime.getRuntime().addShutdownHook( shutdownHook ); -+ System.out.println( "Attempting to restart with " + SpigotConfig.restartScript ); - } else - { - System.out.println( "Startup script '" + SpigotConfig.restartScript + "' does not exist! Stopping server." ); -- -- // Actually shutdown -- try -- { -- MinecraftServer.getServer().close(); -- } catch ( Throwable t ) -- { -- } - } -- System.exit( 0 ); -+ // Stop the watchdog -+ WatchdogThread.doStop(); -+ -+ shutdownServer( isRestarting ); -+ // Paper end - } catch ( Exception ex ) - { - ex.printStackTrace(); - } - } -+ + // Paper start - sync copied from above with minor changes, async added + private static void shutdownServer(boolean isRestarting) + { @@ -200,9 +147,23 @@ index 94d8ba376cd1f024b244654cac9bb62bb19e3060..a142a56a920e153ed84c08cece993f10 + } catch ( InterruptedException ex ) + { + } -+ + +- // Give time for it to kick in +- try +- { +- Thread.sleep( 100 ); +- } catch ( InterruptedException ex ) +- { +- } + closeSocket(); -+ + +- // Actually shutdown +- try +- { +- MinecraftServer.getServer().close(); +- } catch ( Throwable t ) +- { +- } + // Actually shutdown + try + { @@ -213,7 +174,9 @@ index 94d8ba376cd1f024b244654cac9bb62bb19e3060..a142a56a920e153ed84c08cece993f10 + + // Actually stop the JVM + System.exit( 0 ); -+ + +- // This will be done AFTER the server has completely halted +- Thread shutdownHook = new Thread() + } else + { + // Mark the server to shutdown at the end of the tick @@ -265,32 +228,63 @@ index 94d8ba376cd1f024b244654cac9bb62bb19e3060..a142a56a920e153ed84c08cece993f10 + { + @Override + public void run() -+ { + { +- @Override +- public void run() + try -+ { + { +- try + String os = System.getProperty( "os.name" ).toLowerCase(java.util.Locale.ENGLISH); + if ( os.contains( "win" ) ) -+ { + { +- String os = System.getProperty( "os.name" ).toLowerCase(java.util.Locale.ENGLISH); +- if ( os.contains( "win" ) ) +- { +- Runtime.getRuntime().exec( "cmd /c start " + restartScript ); +- } else +- { +- Runtime.getRuntime().exec( "sh " + restartScript ); +- } +- } catch ( Exception e ) + Runtime.getRuntime().exec( "cmd /c start " + restartScript ); + } else -+ { + { +- e.printStackTrace(); + Runtime.getRuntime().exec( "sh " + restartScript ); -+ } + } + } catch ( Exception e ) + { + e.printStackTrace(); -+ } -+ } + } +- }; +- +- shutdownHook.setDaemon( true ); +- Runtime.getRuntime().addShutdownHook( shutdownHook ); +- } else +- { +- System.out.println( "Startup script '" + SpigotConfig.restartScript + "' does not exist! Stopping server." ); +- +- // Actually shutdown +- try +- { +- MinecraftServer.getServer().close(); +- } catch ( Throwable t ) +- { + } +- } +- System.exit( 0 ); +- } catch ( Exception ex ) + }; + + shutdownHook.setDaemon( true ); + Runtime.getRuntime().addShutdownHook( shutdownHook ); + return true; + } else -+ { + { +- ex.printStackTrace(); + return false; -+ } -+ } + } + } + // Paper end + } diff --git a/patches/server/0136-Use-TerminalConsoleAppender-for-console-improvements.patch b/patches/server/0136-Use-TerminalConsoleAppender-for-console-improvements.patch index be01e4e5a8..e3e8a1c485 100644 --- a/patches/server/0136-Use-TerminalConsoleAppender-for-console-improvements.patch +++ b/patches/server/0136-Use-TerminalConsoleAppender-for-console-improvements.patch @@ -397,9 +397,8 @@ index 0b4c62387c1093652ac15b64a8703249de4cf088..b996fde481cebbbcce80a6c267591136 if (offers == null) { - return cursor; + return; // Paper - Method returns void - } -- candidates.addAll(offers); - ++ } ++ + // Paper start - JLine update + for (String completion : offers) { + if (completion.isEmpty()) { @@ -407,9 +406,10 @@ index 0b4c62387c1093652ac15b64a8703249de4cf088..b996fde481cebbbcce80a6c267591136 + } + + candidates.add(new Candidate(completion)); -+ } + } +- candidates.addAll(offers); + // Paper end -+ + + // Paper start - JLine handles cursor now + /* final int lastSpace = buffer.lastIndexOf(' '); diff --git a/patches/server/0169-AsyncTabCompleteEvent.patch b/patches/server/0169-AsyncTabCompleteEvent.patch index f970025162..544db3c891 100644 --- a/patches/server/0169-AsyncTabCompleteEvent.patch +++ b/patches/server/0169-AsyncTabCompleteEvent.patch @@ -49,6 +49,12 @@ index bc72f5380c49c0d389e53d270165d4108a3bb901..ec1aa8d5fbfdafc35948a04f4d8d65e8 if (stringreader.canRead() && stringreader.peek() == '/') { stringreader.skip(); } +- +- ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); +- +- this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { +- if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [] from showing for plugins with nothing more to offer +- this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions)); + final String command = packet.getCommand(); + final com.destroystokyo.paper.event.server.AsyncTabCompleteEvent event = new com.destroystokyo.paper.event.server.AsyncTabCompleteEvent(this.getCraftPlayer(), command, true, null); + event.callEvent(); @@ -56,14 +62,10 @@ index bc72f5380c49c0d389e53d270165d4108a3bb901..ec1aa8d5fbfdafc35948a04f4d8d65e8 + // If the event isn't handled, we can assume that we have no completions, and so we'll ask the server + if (!event.isHandled()) { + if (!event.isCancelled()) { - -- ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); ++ + this.server.scheduleOnMain(() -> { // This needs to be on main + ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); - -- this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { -- if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [] from showing for plugins with nothing more to offer -- this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions)); ++ + this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { + if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [] from showing for plugins with nothing more to offer + this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions)); diff --git a/patches/server/0184-Player.setPlayerProfile-API.patch b/patches/server/0184-Player.setPlayerProfile-API.patch index b2cdc45aef..a1238249ae 100644 --- a/patches/server/0184-Player.setPlayerProfile-API.patch +++ b/patches/server/0184-Player.setPlayerProfile-API.patch @@ -127,11 +127,11 @@ index 39ecd1161b2f2636197eaa157a765cfe5d6f6405..5b2322389c2c2f5277a8891c857ba04f + bukkitPlayer.unregisterEntity(self); + } + } - -- server.getPluginManager().callEvent(new PlayerShowEntityEvent(this, entity)); ++ + // Set the game profile here, we should have unregistered the entity via iterating all player entities above. + self.gameProfile = gameProfile; -+ + +- server.getPluginManager().callEvent(new PlayerShowEntityEvent(this, entity)); + // Re-register the game profile for all players + for (ServerPlayer player : players) { + CraftPlayer bukkitPlayer = player.getBukkitEntity(); diff --git a/patches/server/0255-Improve-death-events.patch b/patches/server/0255-Improve-death-events.patch index f39017892c..685d8817a5 100644 --- a/patches/server/0255-Improve-death-events.patch +++ b/patches/server/0255-Improve-death-events.patch @@ -119,13 +119,8 @@ index 7c0e1963383a1a2862930cf77844e5c8c80e70e3..4c1992bcffd629ef53f14c5a0146eab2 + // Paper - moved into if below if (this.level instanceof ServerLevel) { - if (entity == null || entity.wasKilled((ServerLevel) this.level, this)) { -- this.gameEvent(GameEvent.ENTITY_DIE); -- this.dropAllDeathLoot(damageSource); -- this.createWitherRose(entityliving); -- } + // Paper - move below into if for onKill - -- this.level.broadcastEntityEvent(this, (byte) 3); ++ + // Paper start + org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(damageSource); + if (deathEvent == null || !deathEvent.isCancelled()) { @@ -153,11 +148,15 @@ index 7c0e1963383a1a2862930cf77844e5c8c80e70e3..4c1992bcffd629ef53f14c5a0146eab2 + if (entity != null) { + entity.wasKilled((ServerLevel) this.level, this); + } -+ this.gameEvent(GameEvent.ENTITY_DIE); + this.gameEvent(GameEvent.ENTITY_DIE); +- this.dropAllDeathLoot(damageSource); +- this.createWitherRose(entityliving); + } else { + this.dead = false; + this.setHealth((float) deathEvent.getReviveHealth()); -+ } + } +- +- this.level.broadcastEntityEvent(this, (byte) 3); + // Paper end + this.createWitherRose(entityliving); } diff --git a/patches/server/0259-Prevent-chunk-loading-from-Fluid-Flowing.patch b/patches/server/0259-Prevent-chunk-loading-from-Fluid-Flowing.patch index b182635d6d..261d06e792 100644 --- a/patches/server/0259-Prevent-chunk-loading-from-Fluid-Flowing.patch +++ b/patches/server/0259-Prevent-chunk-loading-from-Fluid-Flowing.patch @@ -58,14 +58,15 @@ index f809a19afdfdb7df439e907531f54b2df1baf08c..00516a230073391b31795ec5af2aa7aa short short0 = FlowingFluid.getCacheKey(pos, blockposition1); - Pair pair = (Pair) short2objectmap.computeIfAbsent(short0, (short1) -> { - BlockState iblockdata1 = world.getBlockState(blockposition1); +- +- return Pair.of(iblockdata1, iblockdata1.getFluidState()); +- }); + // Paper start + Pair pair = (Pair) short2objectmap.get(short0); + if (pair == null) { + BlockState iblockdatax = world.getBlockStateIfLoaded(blockposition1); + if (iblockdatax == null) continue; - -- return Pair.of(iblockdata1, iblockdata1.getFluidState()); -- }); ++ + pair = Pair.of(iblockdatax, iblockdatax.getFluidState()); + short2objectmap.put(short0, pair); + } diff --git a/patches/server/0273-Add-more-Witch-API.patch b/patches/server/0273-Add-more-Witch-API.patch index 3f836289e0..a470414cc9 100644 --- a/patches/server/0273-Add-more-Witch-API.patch +++ b/patches/server/0273-Add-more-Witch-API.patch @@ -39,9 +39,9 @@ index abbb077281eb8fc7961cf97ff23bb9822f2727f0..096546d7a97f031060bda7545aa620d5 - if (!this.isSilent()) { - this.level.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.WITCH_DRINK, this.getSoundSource(), 1.0F, 0.8F + this.random.nextFloat() * 0.4F); - } - -- AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED); - +- AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED); + - attributemodifiable.removeModifier(Witch.SPEED_MODIFIER_DRINKING); - attributemodifiable.addTransientModifier(Witch.SPEED_MODIFIER_DRINKING); } diff --git a/patches/server/0301-Optimize-Network-Manager-and-add-advanced-packet-sup.patch b/patches/server/0301-Optimize-Network-Manager-and-add-advanced-packet-sup.patch index ca1dd6295c..f7ccd1df96 100644 --- a/patches/server/0301-Optimize-Network-Manager-and-add-advanced-packet-sup.patch +++ b/patches/server/0301-Optimize-Network-Manager-and-add-advanced-packet-sup.patch @@ -107,22 +107,21 @@ index 62ee5e32ac0f5d244fa55f9fe45d34cf4d2becaa..184f36a137ed5e5cd20797e131801bc2 public void send(Packet packet, @Nullable PacketSendListener callbacks) { - if (this.isConnected()) { - this.flushQueue(); -- this.sendPacket(packet, callbacks); -- } else { -- this.queue.add(new Connection.PacketHolder(packet, callbacks)); + // Paper start - handle oversized packets better + boolean connected = this.isConnected(); + if (!connected && !preparing) { + return; // Do nothing - } ++ } + packet.onPacketDispatch(getPlayer()); + if (connected && (InnerUtil.canSendImmediate(this, packet) || ( + io.papermc.paper.util.MCUtil.isMainThread() && packet.isReady() && this.queue.isEmpty() && + (packet.getExtraPackets() == null || packet.getExtraPackets().isEmpty()) + ))) { -+ this.sendPacket(packet, callbacks); + this.sendPacket(packet, callbacks); +- } else { +- this.queue.add(new Connection.PacketHolder(packet, callbacks)); + return; -+ } + } + // write the packets to the queue, then flush - antixray hooks there already + java.util.List extraPackets = InnerUtil.buildExtraPackets(packet); + boolean hasExtraPackets = extraPackets != null && !extraPackets.isEmpty(); @@ -185,10 +184,6 @@ index 62ee5e32ac0f5d244fa55f9fe45d34cf4d2becaa..184f36a137ed5e5cd20797e131801bc2 } - private void flushQueue() { -- try { // Paper - add pending task queue -- if (this.channel != null && this.channel.isOpen()) { -- Queue queue = this.queue; -- + // Paper start - rewrite this to be safer if ran off main thread + private boolean flushQueue() { // void -> boolean + if (!isConnected()) { @@ -198,20 +193,16 @@ index 62ee5e32ac0f5d244fa55f9fe45d34cf4d2becaa..184f36a137ed5e5cd20797e131801bc2 + return processQueue(); + } else if (isPending) { + // Should only happen during login/status stages - synchronized (this.queue) { -- Connection.PacketHolder networkmanager_queuedpacket; -- -- while ((networkmanager_queuedpacket = (Connection.PacketHolder) this.queue.poll()) != null) { -- this.sendPacket(networkmanager_queuedpacket.packet, networkmanager_queuedpacket.listener); -- } -- ++ synchronized (this.queue) { + return this.processQueue(); - } - } ++ } ++ } + return false; + } + private boolean processQueue() { -+ try { // Paper - add pending task queue + try { // Paper - add pending task queue +- if (this.channel != null && this.channel.isOpen()) { +- Queue queue = this.queue; + if (this.queue.isEmpty()) return true; + // If we are on main, we are safe here in that nothing else should be processing queue off main anymore + // But if we are not on main due to login/status, the parent is synchronized on packetQueue @@ -223,13 +214,17 @@ index 62ee5e32ac0f5d244fa55f9fe45d34cf4d2becaa..184f36a137ed5e5cd20797e131801bc2 + if (queued == null) { + return true; + } -+ + +- synchronized (this.queue) { +- Connection.PacketHolder networkmanager_queuedpacket; + // Paper start - checking isConsumed flag and skipping packet sending + if (queued.isConsumed()) { + continue; + } + // Paper end - checking isConsumed flag and skipping packet sending -+ + +- while ((networkmanager_queuedpacket = (Connection.PacketHolder) this.queue.poll()) != null) { +- this.sendPacket(networkmanager_queuedpacket.packet, networkmanager_queuedpacket.listener); + Packet packet = queued.packet; + if (!packet.isReady()) { + return false; @@ -237,9 +232,10 @@ index 62ee5e32ac0f5d244fa55f9fe45d34cf4d2becaa..184f36a137ed5e5cd20797e131801bc2 + iterator.remove(); + if (queued.tryMarkConsumed()) { // Paper - try to mark isConsumed flag for de-duplicating packet + this.sendPacket(packet, queued.listener); -+ } -+ } -+ } + } +- + } + } + return true; } finally { // Paper start - add pending task queue Runnable r; diff --git a/patches/server/0316-Configurable-Keep-Spawn-Loaded-range-per-world.patch b/patches/server/0316-Configurable-Keep-Spawn-Loaded-range-per-world.patch index baa4080537..991449b110 100644 --- a/patches/server/0316-Configurable-Keep-Spawn-Loaded-range-per-world.patch +++ b/patches/server/0316-Configurable-Keep-Spawn-Loaded-range-per-world.patch @@ -31,18 +31,19 @@ index cbac51a99885f963feede3563b6b2714a4096022..f62cbd8eddee7ea6997797271ce37d31 - // CraftBukkit start - if (worldserver.getWorld().getKeepSpawnInMemory()) { - chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(blockposition), 11, Unit.INSTANCE); +- +- while (chunkproviderserver.getTickingGenerated() != 441) { +- // this.nextTickTime = SystemUtils.getMillis() + 10L; +- this.executeModerately(); +- } +- } + // Paper start - configurable spawn reason + int radiusBlocks = worldserver.paperConfig().spawn.keepSpawnLoadedRange * 16; + int radiusChunks = radiusBlocks / 16 + ((radiusBlocks & 15) != 0 ? 1 : 0); + int totalChunks = ((radiusChunks) * 2 + 1); + totalChunks *= totalChunks; + worldloadlistener.setChunkRadius(radiusBlocks / 16); - -- while (chunkproviderserver.getTickingGenerated() != 441) { -- // this.nextTickTime = SystemUtils.getMillis() + 10L; -- this.executeModerately(); -- } -- } ++ + worldserver.addTicketsForSpawn(radiusBlocks, blockposition); + // Paper end diff --git a/patches/server/0319-Fix-World-isChunkGenerated-calls.patch b/patches/server/0319-Fix-World-isChunkGenerated-calls.patch index efd006efce..c323e2617d 100644 --- a/patches/server/0319-Fix-World-isChunkGenerated-calls.patch +++ b/patches/server/0319-Fix-World-isChunkGenerated-calls.patch @@ -197,6 +197,7 @@ index ba6d74692039c39660ed5e1d960cb090553a82f0..19f711f82386aaa731699f60ddb95ac2 - if (chunk instanceof ImposterProtoChunk) { - // We then cycle through again to get the full chunk immediately, rather than after the ticket addition - chunk = this.world.getChunkSource().getChunk(x, z, ChunkStatus.FULL, true); +- } + if (!generate) { + ChunkAccess immediate = world.getChunkSource().getChunkAtImmediately(x, z); + if (immediate == null) { @@ -210,7 +211,10 @@ index ba6d74692039c39660ed5e1d960cb090553a82f0..19f711f82386aaa731699f60ddb95ac2 + world.getChunk(x, z); // make sure we're at ticket level 32 or lower + return true; + } -+ + +- if (chunk instanceof net.minecraft.world.level.chunk.LevelChunk) { +- this.world.getChunkSource().addRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 1, Unit.INSTANCE); +- return true; + net.minecraft.world.level.chunk.storage.RegionFile file; + try { + file = world.getChunkSource().chunkMap.regionFileCache.getRegionFile(chunkPos, false); @@ -232,11 +236,6 @@ index ba6d74692039c39660ed5e1d960cb090553a82f0..19f711f82386aaa731699f60ddb95ac2 + // we do this so we do not re-read the chunk data on disk } -- if (chunk instanceof net.minecraft.world.level.chunk.LevelChunk) { -- this.world.getChunkSource().addRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 1, Unit.INSTANCE); -- return true; -- } -- - return false; + world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 1, Unit.INSTANCE); + world.getChunkSource().getChunk(x, z, ChunkStatus.FULL, true); diff --git a/patches/server/0341-Entity-Activation-Range-2.0.patch b/patches/server/0341-Entity-Activation-Range-2.0.patch index 2c16c650df..d0148ba278 100644 --- a/patches/server/0341-Entity-Activation-Range-2.0.patch +++ b/patches/server/0341-Entity-Activation-Range-2.0.patch @@ -264,14 +264,14 @@ index caab72b733eabfe6a78c2a75e252817def49cbd0..ece23ee7812ca62ff8e763ffc29cda27 + // Paper start + if (this.getUnhappyCounter() > 0) { + this.setUnhappyCounter(this.getUnhappyCounter() - 1); - } ++ } + if (this.isEffectiveAi()) { + if (level.spigotConfig.tickInactiveVillagers) { + this.customServerAiStep(); + } else { + this.mobTick(true); + } -+ } + } + maybeDecayGossip(); + // Paper end + @@ -569,16 +569,12 @@ index 08bf9f85fe02a3f89640a2f3ae23089a119a394a..f158fc8a151272428a33dc5f6e174287 - public static boolean checkEntityImmunities(Entity entity) + public static int checkEntityImmunities(Entity entity) // Paper - return # of ticks to get immunity { -- // quick checks. -- if ( entity.wasTouchingWater || entity.remainingFireTicks > 0 ) -- { -- return true; + // Paper start + SpigotWorldConfig config = entity.level.spigotConfig; + int inactiveWakeUpImmunity = checkInactiveWakeup(entity); + if (inactiveWakeUpImmunity > -1) { + return inactiveWakeUpImmunity; - } ++ } + if (entity.remainingFireTicks > 0) { + return 2; + } @@ -587,16 +583,18 @@ index 08bf9f85fe02a3f89640a2f3ae23089a119a394a..f158fc8a151272428a33dc5f6e174287 + } + long inactiveFor = MinecraftServer.currentTick - entity.activatedTick; + // Paper end -+ // quick checks. + // quick checks. +- if ( entity.wasTouchingWater || entity.remainingFireTicks > 0 ) + if ( (entity.activationType != ActivationType.WATER && entity.wasTouchingWater && entity.isPushedByFluid()) ) // Paper -+ { + { +- return true; + return 100; // Paper + } + // Paper start + if ( !entity.isOnGround() || entity.getDeltaMovement().horizontalDistanceSqr() > 9.999999747378752E-6D ) + { + return 100; -+ } + } + // Paper end if ( !( entity instanceof AbstractArrow ) ) { @@ -626,8 +624,7 @@ index 08bf9f85fe02a3f89640a2f3ae23089a119a394a..f158fc8a151272428a33dc5f6e174287 { - return true; + return 20; // Paper - } -- if ( entity instanceof Villager && ( (Villager) entity ).canBreed() ) ++ } + // Paper start + if (entity instanceof Bee) { + Bee bee = (Bee)entity; @@ -655,7 +652,8 @@ index 08bf9f85fe02a3f89640a2f3ae23089a119a394a..f158fc8a151272428a33dc5f6e174287 + return config.villagersWorkImmunityFor; + } + } -+ } + } +- if ( entity instanceof Villager && ( (Villager) entity ).canBreed() ) + if ( entity instanceof Llama && ( (Llama) entity ).inCaravan() ) { - return true; @@ -679,11 +677,11 @@ index 08bf9f85fe02a3f89640a2f3ae23089a119a394a..f158fc8a151272428a33dc5f6e174287 if (entity instanceof Creeper && ((Creeper) entity).isIgnited()) { // isExplosive - return true; + return 20; // Paper - } ++ } + // Paper start + if (entity instanceof Mob && ((Mob) entity).targetSelector.hasTasks() ) { + return 0; -+ } + } + if (entity instanceof Pillager) { + Pillager pillager = (Pillager) entity; + // TODO:? diff --git a/patches/server/0343-Anti-Xray.patch b/patches/server/0343-Anti-Xray.patch index ae1500005f..37c6097afd 100644 --- a/patches/server/0343-Anti-Xray.patch +++ b/patches/server/0343-Anti-Xray.patch @@ -1367,7 +1367,7 @@ index cd82985b0aa821dccc0484f328407381d58ec81f..34804dc42c7a18108126c14c1b5f3d5a this.strategy = paletteProvider; this.registry = idList; this.data = this.createOrReuseData((PalettedContainer.Data)null, 0); -@@ -92,12 +131,34 @@ public class PalettedContainer implements PaletteResize, PalettedContainer +@@ -92,11 +131,33 @@ public class PalettedContainer implements PaletteResize, PalettedContainer @Override public int onResize(int newBits, T object) { PalettedContainer.Data data = this.data; @@ -1388,8 +1388,8 @@ index cd82985b0aa821dccc0484f328407381d58ec81f..34804dc42c7a18108126c14c1b5f3d5a + this.addPresetValues(); + return object == null ? -1 : data2.palette.idFor(object); + // Paper end - } - ++ } ++ + // Paper start - Anti-Xray - Add preset values + private void addPresetValues() { + if (this.presetValues != null && this.data.configuration().factory() != PalettedContainer.Strategy.GLOBAL_PALETTE_FACTORY) { @@ -1397,12 +1397,11 @@ index cd82985b0aa821dccc0484f328407381d58ec81f..34804dc42c7a18108126c14c1b5f3d5a + this.data.palette.idFor(presetValue); + } + } -+ } + } + // Paper end -+ + public T getAndSet(int x, int y, int z, T value) { this.acquire(); - @@ -166,25 +227,36 @@ public class PalettedContainer implements PaletteResize, PalettedContainer data.palette.read(buf); buf.readLongArray(data.storage.getRaw()); @@ -1415,10 +1414,10 @@ index cd82985b0aa821dccc0484f328407381d58ec81f..34804dc42c7a18108126c14c1b5f3d5a } + // Paper start - Anti-Xray - Add chunk packet info ++ @Override ++ @Deprecated @io.papermc.paper.annotation.DoNotUse public void write(FriendlyByteBuf buf) { this.write(buf, null, 0); } @Override - public void write(FriendlyByteBuf buf) { -+ @Deprecated @io.papermc.paper.annotation.DoNotUse public void write(FriendlyByteBuf buf) { this.write(buf, null, 0); } -+ @Override + public void write(FriendlyByteBuf buf, @Nullable com.destroystokyo.paper.antixray.ChunkPacketInfo chunkPacketInfo, int bottomBlockY) { this.acquire(); diff --git a/patches/server/0366-Pillager-patrol-spawn-settings-and-per-player-option.patch b/patches/server/0366-Pillager-patrol-spawn-settings-and-per-player-option.patch index 7d052fc8c8..87975fb3cb 100644 --- a/patches/server/0366-Pillager-patrol-spawn-settings-and-per-player-option.patch +++ b/patches/server/0366-Pillager-patrol-spawn-settings-and-per-player-option.patch @@ -44,7 +44,7 @@ index e5918fa3be107ac3a2fc8831fd78733a7506730a..a908652f1ebb426d265ef614746f70cd + // Random player selection moved up for per player spawning and configuration + int j = world.players().size(); + if (j < 1) { -+ return 0; + return 0; + } + + net.minecraft.server.level.ServerPlayer entityhuman = world.players().get(randomsource.nextInt(j)); @@ -56,16 +56,16 @@ index e5918fa3be107ac3a2fc8831fd78733a7506730a..a908652f1ebb426d265ef614746f70cd + if (world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.perPlayer) { + --entityhuman.patrolSpawnDelay; + patrolSpawnDelay = entityhuman.patrolSpawnDelay; -+ } else { + } else { +- this.nextTick += 12000 + randomsource.nextInt(1200); +- long i = world.getDayTime() / 24000L; + this.nextTick--; + patrolSpawnDelay = this.nextTick; + } + + if (patrolSpawnDelay > 0) { - return 0; - } else { -- this.nextTick += 12000 + randomsource.nextInt(1200); -- long i = world.getDayTime() / 24000L; ++ return 0; ++ } else { + long days; + if (world.paperConfig().entities.behavior.pillagerPatrols.start.perPlayer) { + days = entityhuman.getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.PLAY_TIME)) / 24000L; // PLAY_ONE_MINUTE is actually counting in ticks, a misnomer by Mojang diff --git a/patches/server/0374-Optimize-GoalSelector-Goal.Flag-Set-operations.patch b/patches/server/0374-Optimize-GoalSelector-Goal.Flag-Set-operations.patch index a07de75eb9..70dff6f0dc 100644 --- a/patches/server/0374-Optimize-GoalSelector-Goal.Flag-Set-operations.patch +++ b/patches/server/0374-Optimize-GoalSelector-Goal.Flag-Set-operations.patch @@ -74,27 +74,26 @@ index e5995d0db5dcfba59a873ff439601894fdacd556..b738ee2d3801fadfd09313f05ae24593 - this.availableGoals.removeIf((wrappedGoal) -> { - return wrappedGoal.getGoal() == goal; - }); +- } +- +- private static boolean goalContainsAnyFlags(WrappedGoal goal, EnumSet controls) { +- for(Goal.Flag flag : goal.getFlags()) { +- if (controls.contains(flag)) { +- return true; + // Paper start - remove streams from pathfindergoalselector + for (java.util.Iterator iterator = this.availableGoals.iterator(); iterator.hasNext();) { + WrappedGoal goalWrapped = iterator.next(); + if (goalWrapped.getGoal() != goal) { + continue; -+ } + } + if (goalWrapped.isRunning()) { + goalWrapped.stop(); + } + iterator.remove(); -+ } + } + // Paper end - remove streams from pathfindergoalselector - } ++ } -- private static boolean goalContainsAnyFlags(WrappedGoal goal, EnumSet controls) { -- for(Goal.Flag flag : goal.getFlags()) { -- if (controls.contains(flag)) { -- return true; -- } -- } -- - return false; + private static boolean goalContainsAnyFlags(WrappedGoal goal, com.destroystokyo.paper.util.set.OptimizedSmallEnumSet controls) { + return goal.getFlags().hasCommonElements(controls); // Paper diff --git a/patches/server/0375-Improved-Watchdog-Support.patch b/patches/server/0375-Improved-Watchdog-Support.patch index 67ad90d931..f101bc5b5a 100644 --- a/patches/server/0375-Improved-Watchdog-Support.patch +++ b/patches/server/0375-Improved-Watchdog-Support.patch @@ -358,7 +358,7 @@ index 7a0adf528be779241759d1efd818b0e57454a258..d7a98afeadc090281fdb24b27619536f try { options = parser.parse(args); } catch (joptsimple.OptionException ex) { -@@ -273,9 +303,65 @@ public class Main { +@@ -273,8 +303,64 @@ public class Main { } catch (Throwable t) { t.printStackTrace(); } @@ -405,9 +405,9 @@ index 7a0adf528be779241759d1efd818b0e57454a258..d7a98afeadc090281fdb24b27619536f + tryPreloadClass(net.minecraft.world.level.lighting.LayerLightEventListener.class.getName()); + tryPreloadClass(net.minecraft.util.ExceptionCollector.class.getName()); + // Paper end - } - } - ++ } ++ } ++ + // Paper start + private static void tryPreloadClass(String className) { + tryPreloadClass(className, true); @@ -417,13 +417,12 @@ index 7a0adf528be779241759d1efd818b0e57454a258..d7a98afeadc090281fdb24b27619536f + Class.forName(className); + } catch (ClassNotFoundException e) { + if (printError) System.err.println("An expected class " + className + " was not found for preloading: " + e.getMessage()); -+ } -+ } + } + } + // Paper end -+ + private static List asList(String... params) { return Arrays.asList(params); - } diff --git a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java index b4a19d80bbf71591f25729fd0e98590350cb31d0..e948ec5a573b22645664eb53bc3e9932246544e4 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java diff --git a/patches/server/0411-Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch b/patches/server/0411-Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch index 02e1d99f3b..832016ceb0 100644 --- a/patches/server/0411-Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch +++ b/patches/server/0411-Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch @@ -136,17 +136,17 @@ index 1c638f65d33e5890a7a32bf7e89d484ae2afc093..4b7c39595302a738e6d4a1749473ef9c - int chunkRange = level.spigotConfig.mobSpawnRange; - chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange; - chunkRange = (chunkRange > 8) ? 8 : chunkRange; -+ // Paper start - optimise anyPlayerCloseEnoughForSpawning -+ final boolean anyPlayerCloseEnoughForSpawning(ChunkPos chunkcoordintpair, boolean reducedRange) { -+ return this.anyPlayerCloseEnoughForSpawning(this.getUpdatingChunkIfPresent(chunkcoordintpair.toLong()), chunkcoordintpair, reducedRange); -+ } - +- - final int finalChunkRange = chunkRange; // Paper for lambda below - //double blockRange = (reducedRange) ? Math.pow(chunkRange << 4, 2) : 16384.0D; // Paper - use from event - double blockRange = 16384.0D; // Paper - // Spigot end - long i = chunkcoordintpair.toLong(); -- ++ // Paper start - optimise anyPlayerCloseEnoughForSpawning ++ final boolean anyPlayerCloseEnoughForSpawning(ChunkPos chunkcoordintpair, boolean reducedRange) { ++ return this.anyPlayerCloseEnoughForSpawning(this.getUpdatingChunkIfPresent(chunkcoordintpair.toLong()), chunkcoordintpair, reducedRange); ++ } + - if (!this.distanceManager.hasPlayersNearby(i)) { + final boolean anyPlayerCloseEnoughForSpawning(ChunkHolder playerchunk, ChunkPos chunkcoordintpair, boolean reducedRange) { + // this function is so hot that removing the map lookup call can have an order of magnitude impact on its performance @@ -158,11 +158,18 @@ index 1c638f65d33e5890a7a32bf7e89d484ae2afc093..4b7c39595302a738e6d4a1749473ef9c - Iterator iterator = this.playerMap.getPlayers(i).iterator(); - - ServerPlayer entityplayer; -- ++ } ++ Object[] backingSet = playersInRange.getBackingSet(); + - do { - if (!iterator.hasNext()) { - return false; -- } ++ if (reducedRange) { ++ for (int i = 0, len = backingSet.length; i < len; ++i) { ++ Object raw = backingSet[i]; ++ if (!(raw instanceof ServerPlayer player)) { ++ continue; + } - - entityplayer = (ServerPlayer) iterator.next(); - // Paper start - add PlayerNaturallySpawnCreaturesEvent @@ -172,24 +179,14 @@ index 1c638f65d33e5890a7a32bf7e89d484ae2afc093..4b7c39595302a738e6d4a1749473ef9c - event = entityplayer.playerNaturallySpawnedEvent; - if (event == null || event.isCancelled()) return false; - blockRange = (double) ((event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4)); -- } ++ // don't check spectator and whatnot, already handled by mob spawn map update ++ if (euclideanDistanceSquared(chunkcoordintpair, player) < player.lastEntitySpawnRadiusSquared) { ++ return true; // in range + } - // Paper end - } while (!this.playerIsCloseEnoughForSpawning(entityplayer, chunkcoordintpair, blockRange)); // Spigot - - return true; - } -+ Object[] backingSet = playersInRange.getBackingSet(); -+ -+ if (reducedRange) { -+ for (int i = 0, len = backingSet.length; i < len; ++i) { -+ Object raw = backingSet[i]; -+ if (!(raw instanceof ServerPlayer player)) { -+ continue; -+ } -+ // don't check spectator and whatnot, already handled by mob spawn map update -+ if (euclideanDistanceSquared(chunkcoordintpair, player) < player.lastEntitySpawnRadiusSquared) { -+ return true; // in range -+ } + } + } else { + final double range = (DistanceManager.MOB_SPAWN_RANGE * 16) * (DistanceManager.MOB_SPAWN_RANGE * 16); @@ -204,7 +201,7 @@ index 1c638f65d33e5890a7a32bf7e89d484ae2afc093..4b7c39595302a738e6d4a1749473ef9c + return true; // in range + } + } -+ } + } + // no players in range + return false; + // Paper end - optimise anyPlayerCloseEnoughForSpawning diff --git a/patches/server/0431-Add-Plugin-Tickets-to-API-Chunk-Methods.patch b/patches/server/0431-Add-Plugin-Tickets-to-API-Chunk-Methods.patch index 7d53f27e28..c8d93c303e 100644 --- a/patches/server/0431-Add-Plugin-Tickets-to-API-Chunk-Methods.patch +++ b/patches/server/0431-Add-Plugin-Tickets-to-API-Chunk-Methods.patch @@ -47,7 +47,7 @@ diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/jav index efa01ad6ac0757da033f2bdf7729717239e474f2..977004b4b5a294c4eab2995777df6fb1faff4625 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -281,9 +281,22 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -281,8 +281,21 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public Chunk getChunkAt(int x, int z) { @@ -60,17 +60,16 @@ index efa01ad6ac0757da033f2bdf7729717239e474f2..977004b4b5a294c4eab2995777df6fb1 + } + return chunk.bukkitChunk; + // Paper end - } - ++ } ++ + // Paper start + private void addTicket(int x, int z) { + io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> world.getChunkSource().addRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 0, Unit.INSTANCE)); // Paper -+ } + } + // Paper end -+ + @Override public Chunk getChunkAt(Block block) { - Preconditions.checkArgument(block != null, "null block"); @@ -349,7 +362,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { public boolean unloadChunkRequest(int x, int z) { org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot diff --git a/patches/server/0433-Stop-copy-on-write-operations-for-updating-light-dat.patch b/patches/server/0433-Stop-copy-on-write-operations-for-updating-light-dat.patch index 336281d839..c13f70aec1 100644 --- a/patches/server/0433-Stop-copy-on-write-operations-for-updating-light-dat.patch +++ b/patches/server/0433-Stop-copy-on-write-operations-for-updating-light-dat.patch @@ -271,12 +271,13 @@ index 59d2af9f883541518c203302257f03dbe957aa0b..e6c857c8b4e4e65e3cf6a75ce6d844ff protected static final class SkyDataLayerStorageMap extends DataLayerStorageMap { int currentLowestY; - final Long2IntOpenHashMap topSections; -+ private final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int otherData; // Paper - avoid copying light data - +- - public SkyDataLayerStorageMap(Long2ObjectOpenHashMap arrays, Long2IntOpenHashMap columnToTopSection, int minSectionY) { - super(arrays); - this.topSections = columnToTopSection; - columnToTopSection.defaultReturnValue(minSectionY); ++ private final com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int otherData; // Paper - avoid copying light data ++ + // Paper start - avoid copying light data + public SkyDataLayerStorageMap(com.destroystokyo.paper.util.map.QueuedChangesMapLong2Object arrays, com.destroystokyo.paper.util.map.QueuedChangesMapLong2Int columnToTopSection, int minSectionY, boolean isVisible) { + super(arrays, isVisible); diff --git a/patches/server/0484-Fix-for-large-move-vectors-crashing-server.patch b/patches/server/0484-Fix-for-large-move-vectors-crashing-server.patch index 7ce22dca0f..4b010dd3cf 100644 --- a/patches/server/0484-Fix-for-large-move-vectors-crashing-server.patch +++ b/patches/server/0484-Fix-for-large-move-vectors-crashing-server.patch @@ -27,13 +27,14 @@ index ed16292b121aeaee5ad439176af57841281e293d..459403f9c8a784c3911d5ba163a2c90e double d8 = d5 - this.vehicleFirstGoodZ; double d9 = entity.getDeltaMovement().lengthSqr(); - double d10 = d6 * d6 + d7 * d7 + d8 * d8; +- + // Paper start - fix large move vectors killing the server + double currDeltaX = toX - fromX; + double currDeltaY = toY - fromY; + double currDeltaZ = toZ - fromZ; + double d10 = Math.max(d6 * d6 + d7 * d7 + d8 * d8, (currDeltaX * currDeltaX + currDeltaY * currDeltaY + currDeltaZ * currDeltaZ) - 1); + // Paper end - fix large move vectors killing the server - ++ + // Paper start - fix large move vectors killing the server + double otherFieldX = d3 - this.vehicleLastGoodX; + double otherFieldY = d4 - this.vehicleLastGoodY - 1.0E-6D; diff --git a/patches/server/0559-add-DragonEggFormEvent.patch b/patches/server/0559-add-DragonEggFormEvent.patch index c617bc6250..7e39c25a22 100644 --- a/patches/server/0559-add-DragonEggFormEvent.patch +++ b/patches/server/0559-add-DragonEggFormEvent.patch @@ -25,10 +25,10 @@ index 1ee1b757b90ae0d080aa57f4186228a6f4279c1f..abd13cefd3d8409e1ef8ea70d92877f7 + //this.level.setBlockAndUpdate(this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.END_PODIUM_LOCATION), Blocks.DRAGON_EGG.defaultBlockState()); + } else { + eggEvent.setCancelled(true); - } ++ } + if (eggEvent.callEvent()) { + eggEvent.getNewState().update(true); -+ } + } + // Paper end - DragonEggFormEvent this.previouslyKilled = true; diff --git a/patches/server/0563-Allow-adding-items-to-BlockDropItemEvent.patch b/patches/server/0563-Allow-adding-items-to-BlockDropItemEvent.patch index 606f504c05..fb8b16b645 100644 --- a/patches/server/0563-Allow-adding-items-to-BlockDropItemEvent.patch +++ b/patches/server/0563-Allow-adding-items-to-BlockDropItemEvent.patch @@ -31,13 +31,13 @@ index 15b4be18064137d21565434adae97883fb0a8d6a..451fee716b07c8daadcffc9b87973a56 + Entity item = ((org.bukkit.craftbukkit.entity.CraftItem) bukkit).getHandle(); + item.level.addFreshEntity(item); + } - } ++ } + } else { + for (Item bukkit : list) { + if (bukkit.isValid()) { + bukkit.remove(); + } -+ } + } + // Paper end } } diff --git a/patches/server/0613-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch b/patches/server/0613-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch index 4ee9a0b68d..a0f6decc09 100644 --- a/patches/server/0613-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch +++ b/patches/server/0613-Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch @@ -26,7 +26,7 @@ index 98a3f6388712fab9012210241b84def3aca712e2..f2094c52196b45adfd51d8aebcc4c46b if (flag) { ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD); -@@ -228,8 +234,21 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo +@@ -228,7 +234,20 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo public void readAdditionalSaveData(CompoundTag nbt) { super.readAdditionalSaveData(nbt); this.reassessWeaponGoal(); @@ -35,19 +35,18 @@ index 98a3f6388712fab9012210241b84def3aca712e2..f2094c52196b45adfd51d8aebcc4c46b + this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay"); + } + // Paper end - } - ++ } ++ + // Paper start + @Override + public void addAdditionalSaveData(CompoundTag nbt) { + super.addAdditionalSaveData(nbt); + nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); -+ } + } + // Paper end -+ + @Override public void setItemSlot(EquipmentSlot slot, ItemStack stack) { - super.setItemSlot(slot, stack); diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java index 0ada1ba6774e3d0514afb946fd0f104004cc020d..97fb1d2110a51498f6419841081b500b3f190370 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java diff --git a/patches/server/0629-Add-PlayerKickEvent-causes.patch b/patches/server/0629-Add-PlayerKickEvent-causes.patch index 34e4efddd2..f4e7692cf5 100644 --- a/patches/server/0629-Add-PlayerKickEvent-causes.patch +++ b/patches/server/0629-Add-PlayerKickEvent-causes.patch @@ -146,13 +146,13 @@ index c5788a4f0acdd44d55446fd729311db7e72c0d86..db44aa972afa0e6d65c54c35382235c3 public void disconnect(final Component reason) { - this.disconnect(PaperAdventure.asAdventure(reason)); + this.disconnect(PaperAdventure.asAdventure(reason), org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); ++ } ++ ++ public void disconnect(final Component reason, PlayerKickEvent.Cause cause) { ++ this.disconnect(PaperAdventure.asAdventure(reason), cause); } - public void disconnect(net.kyori.adventure.text.Component reason) { -+ public void disconnect(final Component reason, PlayerKickEvent.Cause cause) { -+ this.disconnect(PaperAdventure.asAdventure(reason), cause); -+ } -+ + public void disconnect(net.kyori.adventure.text.Component reason, org.bukkit.event.player.PlayerKickEvent.Cause cause) { // Paper end // CraftBukkit start - fire PlayerKickEvent diff --git a/patches/server/0657-Stinger-API.patch b/patches/server/0657-Stinger-API.patch index a211b4fffd..205b58361d 100644 --- a/patches/server/0657-Stinger-API.patch +++ b/patches/server/0657-Stinger-API.patch @@ -17,12 +17,12 @@ index f217df2d3c7a53b72418fab63cef06dbc107fe0d..cbb6b437358823cd52518682f32dd597 + public int getBeeStingerCooldown() { + return getHandle().removeStingerTime; + } - ++ + @Override + public void setBeeStingerCooldown(int ticks) { + getHandle().removeStingerTime = ticks; + } -+ + + @Override + public int getBeeStingersInBody() { + return getHandle().getStingerCount(); diff --git a/patches/server/0683-Add-more-advancement-API.patch b/patches/server/0683-Add-more-advancement-API.patch index efc54f97d3..776e29d3b7 100644 --- a/patches/server/0683-Add-more-advancement-API.patch +++ b/patches/server/0683-Add-more-advancement-API.patch @@ -137,12 +137,9 @@ index c47cae84f3b6970247d78382f48ae8ddbc202b59..1435251a4fb721b800e6a1f07b50c5f7 - public AdvancementDisplay getDisplay() { - if (this.handle.getDisplay() == null) { - return null; -- } -- -- return new CraftAdvancementDisplay(this.handle.getDisplay()); + public io.papermc.paper.advancement.AdvancementDisplay getDisplay() { + return this.handle.getDisplay() == null ? null : this.handle.getDisplay().paper; - } ++ } + + @Deprecated @io.papermc.paper.annotation.DoNotUse + public AdvancementDisplay getDisplay0() { // May be called by plugins via Commodore @@ -164,10 +161,11 @@ index c47cae84f3b6970247d78382f48ae8ddbc202b59..1435251a4fb721b800e6a1f07b50c5f7 + final var children = com.google.common.collect.ImmutableList.builder(); + for (Advancement advancement : this.handle.getChildren()) { + children.add(advancement.bukkit); -+ } + } + return children.build(); + } -+ + +- return new CraftAdvancementDisplay(this.handle.getDisplay()); + @Override + public org.bukkit.advancement.Advancement getRoot() { + Advancement advancement = this.handle; @@ -175,7 +173,7 @@ index c47cae84f3b6970247d78382f48ae8ddbc202b59..1435251a4fb721b800e6a1f07b50c5f7 + advancement = advancement.getParent(); + } + return advancement.bukkit; -+ } + } + // Paper end } diff --git a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementDisplay.java b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementDisplay.java diff --git a/patches/server/0693-Fix-GameProfileCache-concurrency.patch b/patches/server/0693-Fix-GameProfileCache-concurrency.patch index 82ab6b35cb..8c22da1dde 100644 --- a/patches/server/0693-Fix-GameProfileCache-concurrency.patch +++ b/patches/server/0693-Fix-GameProfileCache-concurrency.patch @@ -105,15 +105,15 @@ index 2456edc11b29a92b1648937cd3dd6a9a05706803..b48650c38751a925b83fb4c19ac02f87 jsonarray.add(GameProfileCache.writeGameProfile(usercache_usercacheentry, dateformat)); }); String s = this.gson.toJson(jsonarray); -@@ -332,9 +349,20 @@ public class GameProfileCache { +@@ -332,8 +349,19 @@ public class GameProfileCache { } private Stream getTopMRUProfiles(int limit) { - return ImmutableList.copyOf(this.profilesByUUID.values()).stream().sorted(Comparator.comparing(GameProfileCache.GameProfileInfo::getLastAccess).reversed()).limit((long) limit); + // Paper start - allow better concurrency + return this.listTopMRUProfiles(limit).stream(); - } - ++ } ++ + private List listTopMRUProfiles(int limit) { + try { + this.stateLock.lock(); @@ -121,9 +121,8 @@ index 2456edc11b29a92b1648937cd3dd6a9a05706803..b48650c38751a925b83fb4c19ac02f87 + } finally { + this.stateLock.unlock(); + } -+ } + } + // Paper end -+ + private static JsonElement writeGameProfile(GameProfileCache.GameProfileInfo entry, DateFormat dateFormat) { JsonObject jsonobject = new JsonObject(); - diff --git a/patches/server/0699-Optimise-chunk-tick-iteration.patch b/patches/server/0699-Optimise-chunk-tick-iteration.patch index ac6f821d60..27fbd41bbe 100644 --- a/patches/server/0699-Optimise-chunk-tick-iteration.patch +++ b/patches/server/0699-Optimise-chunk-tick-iteration.patch @@ -170,13 +170,13 @@ index d1652c237b2b272f0dfe80f774cff16056f39046..b768767b92bf7691a6e57627c69818a1 } + // Paper start - optimise chunk tick iteration + } - } ++ } + + } finally { + if (iterator1 instanceof io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.Iterator safeIterator) { + safeIterator.finishedIterating(); + } -+ } + } + // Paper end - optimise chunk tick iteration this.level.timings.chunkTicks.stopTiming(); // Paper gameprofilerfiller.popPush("customSpawners"); @@ -186,15 +186,15 @@ index d1652c237b2b272f0dfe80f774cff16056f39046..b768767b92bf7691a6e57627c69818a1 } // Paper - timings } - -+ gameprofilerfiller.pop(); -+ // Paper start - use set of chunks requiring updates, rather than iterating every single one loaded - gameprofilerfiller.popPush("broadcast"); +- gameprofilerfiller.popPush("broadcast"); - list.forEach((chunkproviderserver_a1) -> { - this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing - chunkproviderserver_a1.holder.broadcastChanges(chunkproviderserver_a1.chunk); - this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing - }); -- gameprofilerfiller.pop(); + gameprofilerfiller.pop(); ++ // Paper start - use set of chunks requiring updates, rather than iterating every single one loaded ++ gameprofilerfiller.popPush("broadcast"); + this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing + if (!this.chunkMap.needsChangeBroadcasting.isEmpty()) { + ReferenceOpenHashSet copy = this.chunkMap.needsChangeBroadcasting.clone(); diff --git a/patches/server/0701-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch b/patches/server/0701-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch index 9b964553cf..2ea18be595 100644 --- a/patches/server/0701-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch +++ b/patches/server/0701-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch @@ -509,7 +509,7 @@ index cda87a66fe80bf910f629c64e36c1fecbad81d77..9bae47f99336c377beb72c4b50b7f01c } else { - this.usedSectors.force(i1, j1); + //this.usedSectors.force(i1, j1); // Paper - move this down so we can check if it fails to allocate - } ++ } + // Paper start - recalculate header on header corruption + if (offset < 2 || sectorLength <= 0 || ((long)offset * 4096L) > regionFileSize) { + if (canRecalcHeader) { @@ -532,7 +532,7 @@ index cda87a66fe80bf910f629c64e36c1fecbad81d77..9bae47f99336c377beb72c4b50b7f01c + boolean failedToAllocate = !this.usedSectors.tryAllocate(offset, sectorLength); + if (failedToAllocate) { + LOGGER.error("Overlapping allocation by local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") in regionfile " + this.regionFile.toAbsolutePath()); -+ } + } + if (failedToAllocate & !canRecalcHeader) { + // location = chunkX | (chunkZ << 5); + LOGGER.error("Detected invalid header for regionfile " + this.regionFile.toAbsolutePath() + diff --git a/patches/server/0716-Optimise-BlockSoil-nearby-water-lookup.patch b/patches/server/0716-Optimise-BlockSoil-nearby-water-lookup.patch index 38e5222da1..4d0f364a33 100644 --- a/patches/server/0716-Optimise-BlockSoil-nearby-water-lookup.patch +++ b/patches/server/0716-Optimise-BlockSoil-nearby-water-lookup.patch @@ -15,16 +15,17 @@ index e0aa9a57d6a5993d7333b7685b6fa1b50bc11ea0..34d744837e599633a3c2c0b72f253bb0 private static boolean isNearWater(LevelReader world, BlockPos pos) { - Iterator iterator = BlockPos.betweenClosed(pos.offset(-4, 0, -4), pos.offset(4, 1, 4)).iterator(); -+ // Paper start - remove abstract block iteration -+ int xOff = pos.getX(); -+ int yOff = pos.getY(); -+ int zOff = pos.getZ(); - +- - BlockPos blockposition1; - - do { - if (!iterator.hasNext()) { - return false; ++ // Paper start - remove abstract block iteration ++ int xOff = pos.getX(); ++ int yOff = pos.getY(); ++ int zOff = pos.getZ(); ++ + for (int dz = -4; dz <= 4; ++dz) { + int z = dz + zOff; + for (int dx = -4; dx <= 4; ++dx) { diff --git a/patches/server/0717-Optimise-random-block-ticking.patch b/patches/server/0717-Optimise-random-block-ticking.patch index 001fb88c4d..7b9486017d 100644 --- a/patches/server/0717-Optimise-random-block-ticking.patch +++ b/patches/server/0717-Optimise-random-block-ticking.patch @@ -173,14 +173,7 @@ index 1f683d734b9e272c8f4c48d922f3dcd12d0ffd1a..9523f6acd2c86892b390e14aaab628b4 if (randomTickSpeed > 0) { - LevelChunkSection[] achunksection = chunk.getSections(); - int j1 = achunksection.length; -+ LevelChunkSection[] sections = chunk.getSections(); -+ int minSection = io.papermc.paper.util.WorldUtil.getMinSection(this); -+ for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { -+ LevelChunkSection section = sections[sectionIndex]; -+ if (section == null || section.tickingList.size() == 0) { -+ continue; -+ } - +- - for (int k1 = 0; k1 < j1; ++k1) { - LevelChunkSection chunksection = achunksection[k1]; - @@ -192,35 +185,40 @@ index 1f683d734b9e272c8f4c48d922f3dcd12d0ffd1a..9523f6acd2c86892b390e14aaab628b4 - - gameprofilerfiller.push("randomTick"); - BlockState iblockdata3 = chunksection.getBlockState(blockposition2.getX() - j, blockposition2.getY() - l1, blockposition2.getZ() - k); -- ++ LevelChunkSection[] sections = chunk.getSections(); ++ int minSection = io.papermc.paper.util.WorldUtil.getMinSection(this); ++ for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { ++ LevelChunkSection section = sections[sectionIndex]; ++ if (section == null || section.tickingList.size() == 0) { ++ continue; ++ } + - if (iblockdata3.isRandomlyTicking()) { - iblockdata3.randomTick(this, blockposition2, this.random); - } -- -- FluidState fluid = iblockdata3.getFluidState(); -- -- if (fluid.isRandomlyTicking()) { -- fluid.randomTick(this, blockposition2, this.random); -- } -- -- gameprofilerfiller.pop(); + int yPos = (sectionIndex + minSection) << 4; + for (int a = 0; a < randomTickSpeed; ++a) { + int tickingBlocks = section.tickingList.size(); + int index = this.randomTickRandom.nextInt(16 * 16 * 16); + if (index >= tickingBlocks) { + continue; - } -+ ++ } + +- FluidState fluid = iblockdata3.getFluidState(); + long raw = section.tickingList.getRaw(index); + int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); + int randomX = location & 15; + int randomY = ((location >>> (4 + 4)) & 255) | yPos; + int randomZ = (location >>> 4) & 15; -+ + +- if (fluid.isRandomlyTicking()) { +- fluid.randomTick(this, blockposition2, this.random); +- } + BlockPos blockposition2 = blockposition.set(j + randomX, randomY, k + randomZ); + BlockState iblockdata = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); -+ + +- gameprofilerfiller.pop(); +- } + iblockdata.randomTick(this, blockposition2, this.randomTickRandom); + // We drop the fluid tick since LAVA is ALREADY TICKED by the above method (See LiquidBlock). + // TODO CHECK ON UPDATE (ping the Canadian) @@ -379,14 +377,7 @@ index 8c8445af8a2fe684fdbb468f8d8605d44a803758..c7e2796e136ee8fb7d7e438a7fc59826 public void recalcBlockCounts() { - class a implements PalettedContainer.CountConsumer { -+ // Paper start - unfuck this -+ this.tickingList.clear(); -+ this.nonEmptyBlockCount = 0; -+ this.tickingBlockCount = 0; -+ this.tickingFluidCount = 0; -+ this.states.forEachLocation((BlockState iblockdata, int i) -> { -+ FluidState fluid = iblockdata.getFluidState(); - +- - public int nonEmptyBlockCount; - public int tickingBlockCount; - public int tickingFluidCount; @@ -401,31 +392,38 @@ index 8c8445af8a2fe684fdbb468f8d8605d44a803758..c7e2796e136ee8fb7d7e438a7fc59826 - if (iblockdata.isRandomlyTicking()) { - this.tickingBlockCount += i; - } ++ // Paper start - unfuck this ++ this.tickingList.clear(); ++ this.nonEmptyBlockCount = 0; ++ this.tickingBlockCount = 0; ++ this.tickingFluidCount = 0; ++ this.states.forEachLocation((BlockState iblockdata, int i) -> { ++ FluidState fluid = iblockdata.getFluidState(); ++ + if (!iblockdata.isAir()) { + this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + 1); + if (iblockdata.isRandomlyTicking()) { + this.tickingBlockCount = (short)(this.tickingBlockCount + 1); + this.tickingList.add(i, iblockdata); } -- ++ } + - if (!fluid.isEmpty()) { - this.nonEmptyBlockCount += i; - if (fluid.isRandomlyTicking()) { - this.tickingFluidCount += i; - } -- } ++ if (!fluid.isEmpty()) { ++ this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + 1); ++ if (fluid.isRandomlyTicking()) { ++ this.tickingFluidCount = (short) (this.tickingFluidCount + 1); + } - } - } - a a0 = new a(); -+ if (!fluid.isEmpty()) { -+ this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + 1); -+ if (fluid.isRandomlyTicking()) { -+ this.tickingFluidCount = (short) (this.tickingFluidCount + 1); -+ } -+ } - +- - this.states.count(a0); - this.nonEmptyBlockCount = (short) a0.nonEmptyBlockCount; - this.tickingBlockCount = (short) a0.tickingBlockCount; diff --git a/patches/server/0738-Fix-upstreams-block-state-factories.patch b/patches/server/0738-Fix-upstreams-block-state-factories.patch index f518b74909..b6a1321bfd 100644 --- a/patches/server/0738-Fix-upstreams-block-state-factories.patch +++ b/patches/server/0738-Fix-upstreams-block-state-factories.patch @@ -328,21 +328,21 @@ index cf76ca2ebead64d194ce03ee024085d32d02077a..1caa329567b50a962c54bb00c79cc98e private static > void register( - Material blockType, +- Class blockStateType, +- BiFunction blockStateConstructor, +- BiFunction tileEntityConstructor +- ) { +- CraftBlockStates.register(Collections.singletonList(blockType), blockStateType, blockStateConstructor, tileEntityConstructor); +- } +- +- private static > void register( +- List blockTypes, + net.minecraft.world.level.block.entity.BlockEntityType blockEntityType, // Paper Class blockStateType, - BiFunction blockStateConstructor, - BiFunction tileEntityConstructor + BiFunction blockStateConstructor // Paper ) { -- CraftBlockStates.register(Collections.singletonList(blockType), blockStateType, blockStateConstructor, tileEntityConstructor); -- } -- -- private static > void register( -- List blockTypes, -- Class blockStateType, -- BiFunction blockStateConstructor, -- BiFunction tileEntityConstructor -- ) { - BlockStateFactory factory = new BlockEntityStateFactory<>(blockStateType, blockStateConstructor, tileEntityConstructor); - for (Material blockType : blockTypes) { - CraftBlockStates.register(blockType, factory); diff --git a/patches/server/0747-Always-parse-protochunk-light-sources-unless-it-is-m.patch b/patches/server/0747-Always-parse-protochunk-light-sources-unless-it-is-m.patch index 5aa52fec7b..6b5b270d92 100644 --- a/patches/server/0747-Always-parse-protochunk-light-sources-unless-it-is-m.patch +++ b/patches/server/0747-Always-parse-protochunk-light-sources-unless-it-is-m.patch @@ -21,14 +21,10 @@ index 34a1976699571608ae19e20dc1b6020759dad909..0ec80b83a99bfdb1f985045d98a81905 + // Paper start - let's make sure the implementation isn't as slow as possible + int offX = chunkPos.x << 4; + int offZ = chunkPos.z << 4; - -- while (iterator.hasNext()) { -- BlockPos blockposition = (BlockPos) iterator.next(); ++ + int minChunkSection = io.papermc.paper.util.WorldUtil.getMinSection(world); + int maxChunkSection = io.papermc.paper.util.WorldUtil.getMaxSection(world); - -- if (((ChunkAccess) object1).getBlockState(blockposition).getLightEmission() != 0) { -- protochunk.addLight(blockposition); ++ + LevelChunkSection[] sections = achunksection; + for (int sectionY = minChunkSection; sectionY <= maxChunkSection; ++sectionY) { + LevelChunkSection section = sections[sectionY - minChunkSection]; @@ -37,12 +33,16 @@ index 34a1976699571608ae19e20dc1b6020759dad909..0ec80b83a99bfdb1f985045d98a81905 + continue; + } + int offY = sectionY << 4; -+ + +- while (iterator.hasNext()) { +- BlockPos blockposition = (BlockPos) iterator.next(); + for (int index = 0; index < (16 * 16 * 16); ++index) { + if (section.states.get(index).getLightEmission() <= 0) { + continue; + } -+ + +- if (((ChunkAccess) object1).getBlockState(blockposition).getLightEmission() != 0) { +- protochunk.addLight(blockposition); + // index = x | (z << 4) | (y << 8) + protochunk.addLight(new BlockPos(offX | (index & 15), offY | (index >>> 8), offZ | ((index >>> 4) & 15))); } diff --git a/patches/server/0757-Highly-optimise-single-and-multi-AABB-VoxelShapes-an.patch b/patches/server/0757-Highly-optimise-single-and-multi-AABB-VoxelShapes-an.patch index cbf4934d51..03f118416a 100644 --- a/patches/server/0757-Highly-optimise-single-and-multi-AABB-VoxelShapes-an.patch +++ b/patches/server/0757-Highly-optimise-single-and-multi-AABB-VoxelShapes-an.patch @@ -24,7 +24,7 @@ index be668387f65a633c6ac497fca632a4767a1bf3a2..e08f4e39db4ee3fed62e37364d17dcc5 + // Paper start - optimise collisions + static final UnsafeList TEMP_COLLISION_LIST = new UnsafeList<>(1024); + static boolean tempCollisionListInUse; - ++ + public static UnsafeList getTempCollisionList() { + if (!Bukkit.isPrimaryThread() || tempCollisionListInUse) { + return new UnsafeList<>(16); @@ -40,7 +40,7 @@ index be668387f65a633c6ac497fca632a4767a1bf3a2..e08f4e39db4ee3fed62e37364d17dcc5 + ((UnsafeList)list).setSize(0); + tempCollisionListInUse = false; + } -+ + + static final UnsafeList TEMP_GET_ENTITIES_LIST = new UnsafeList<>(1024); + static boolean tempGetEntitiesListInUse; + @@ -1277,26 +1277,29 @@ index 73d475788e23d371c79908c792d8d4dd0ba770ab..182e443e4cd114edeb0c0c6be5dda76d - boolean flag1 = movement.y != vec3d1.y; - boolean flag2 = movement.z != vec3d1.z; - boolean flag3 = this.onGround || flag1 && movement.y < 0.0D; +- +- if (this.maxUpStep() > 0.0F && flag3 && (flag || flag2)) { +- Vec3 vec3d2 = Entity.collideBoundingBox(this, new Vec3(movement.x, (double) this.maxUpStep(), movement.z), axisalignedbb, this.level, list); +- Vec3 vec3d3 = Entity.collideBoundingBox(this, new Vec3(0.0D, (double) this.maxUpStep(), 0.0D), axisalignedbb.expandTowards(movement.x, 0.0D, movement.z), this.level, list); +- +- if (vec3d3.y < (double) this.maxUpStep()) { +- Vec3 vec3d4 = Entity.collideBoundingBox(this, new Vec3(movement.x, 0.0D, movement.z), axisalignedbb.move(vec3d3), this.level, list).add(vec3d3); +- +- if (vec3d4.horizontalDistanceSqr() > vec3d2.horizontalDistanceSqr()) { +- vec3d2 = vec3d4; + // Paper start - optimise collisions + // This is a copy of vanilla's except that it uses strictly AABB math + if (movement.x == 0.0 && movement.y == 0.0 && movement.z == 0.0) { + return movement; + } - -- if (this.maxUpStep() > 0.0F && flag3 && (flag || flag2)) { -- Vec3 vec3d2 = Entity.collideBoundingBox(this, new Vec3(movement.x, (double) this.maxUpStep(), movement.z), axisalignedbb, this.level, list); -- Vec3 vec3d3 = Entity.collideBoundingBox(this, new Vec3(0.0D, (double) this.maxUpStep(), 0.0D), axisalignedbb.expandTowards(movement.x, 0.0D, movement.z), this.level, list); ++ + final Level world = this.level; + final AABB currBoundingBox = this.getBoundingBox(); - -- if (vec3d3.y < (double) this.maxUpStep()) { -- Vec3 vec3d4 = Entity.collideBoundingBox(this, new Vec3(movement.x, 0.0D, movement.z), axisalignedbb.move(vec3d3), this.level, list).add(vec3d3); ++ + if (io.papermc.paper.util.CollisionUtil.isEmpty(currBoundingBox)) { + return movement; + } - -- if (vec3d4.horizontalDistanceSqr() > vec3d2.horizontalDistanceSqr()) { -- vec3d2 = vec3d4; ++ + final List potentialCollisions = io.papermc.paper.util.CachedLists.getTempCollisionList(); + try { + final double stepHeight = (double)this.maxUpStep(); @@ -1323,16 +1326,15 @@ index 73d475788e23d371c79908c792d8d4dd0ba770ab..182e443e4cd114edeb0c0c6be5dda76d - if (vec3d2.horizontalDistanceSqr() > vec3d1.horizontalDistanceSqr()) { - return vec3d2.add(Entity.collideBoundingBox(this, new Vec3(0.0D, -vec3d2.y + movement.y, 0.0D), axisalignedbb.move(vec3d2), this.level, list)); -- } -- } + io.papermc.paper.util.CollisionUtil.getCollisions(world, this, collisionBox, potentialCollisions, false, this.level.paperConfig().chunks.preventMovingIntoUnloadedChunks, + false, false, null, null); - -- return vec3d1; ++ + if (io.papermc.paper.util.CollisionUtil.isCollidingWithBorderEdge(world.getWorldBorder(), collisionBox)) { + io.papermc.paper.util.CollisionUtil.addBoxesToIfIntersects(world.getWorldBorder().getCollisionShape(), collisionBox, potentialCollisions); -+ } -+ + } +- } + +- return vec3d1; + final Vec3 limitedMoveVector = io.papermc.paper.util.CollisionUtil.performCollisions(movement, currBoundingBox, potentialCollisions); + + if (stepHeight > 0.0 diff --git a/patches/server/0793-Implement-regenerateChunk.patch b/patches/server/0793-Implement-regenerateChunk.patch index dcc076bdc3..c2d47675b9 100644 --- a/patches/server/0793-Implement-regenerateChunk.patch +++ b/patches/server/0793-Implement-regenerateChunk.patch @@ -25,6 +25,10 @@ index 8fcc553b6f1bf62fb9febb46402940039c37606a..eeeaaf379c7273c276e1faac5d6c5573 - /* - if (!unloadChunk0(x, z, false)) { - return false; +- } +- +- final long chunkKey = ChunkCoordIntPair.pair(x, z); +- world.getChunkProvider().unloadQueue.remove(chunkKey); + // Paper start - implement regenerateChunk method + final ServerLevel serverLevel = this.world; + final net.minecraft.server.level.ServerChunkCache serverChunkCache = serverLevel.getChunkSource(); @@ -33,10 +37,8 @@ index 8fcc553b6f1bf62fb9febb46402940039c37606a..eeeaaf379c7273c276e1faac5d6c5573 + for (final BlockPos blockPos : BlockPos.betweenClosed(chunkPos.getMinBlockX(), serverLevel.getMinBuildHeight(), chunkPos.getMinBlockZ(), chunkPos.getMaxBlockX(), serverLevel.getMaxBuildHeight() - 1, chunkPos.getMaxBlockZ())) { + levelChunk.removeBlockEntity(blockPos); + serverLevel.setBlock(blockPos, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), 16); - } - -- final long chunkKey = ChunkCoordIntPair.pair(x, z); -- world.getChunkProvider().unloadQueue.remove(chunkKey); ++ } ++ + for (final ChunkStatus chunkStatus : REGEN_CHUNK_STATUSES) { + final List list = new ArrayList<>(); + final int range = Math.max(1, chunkStatus.getRange()); diff --git a/patches/server/0864-More-Teleport-API.patch b/patches/server/0864-More-Teleport-API.patch index eb25b06533..ada5d4dec9 100644 --- a/patches/server/0864-More-Teleport-API.patch +++ b/patches/server/0864-More-Teleport-API.patch @@ -55,14 +55,14 @@ index 7df1eebce5b62214943e55314e9ec98f056fa330..2aee8aacd50431c18ff28af678348ec2 + if (flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS) && this.entity.isVehicle() && location.getWorld() != this.getWorld()) { + return false; + } - -- if (this.entity.isVehicle() || this.entity.isRemoved()) { ++ + // Don't allow to teleport between worlds if remaining on vehicle + if (!dismount && this.entity.isPassenger() && location.getWorld() != this.getWorld()) { + return false; + } + // Paper end -+ + +- if (this.entity.isVehicle() || this.entity.isRemoved()) { + if ((!ignorePassengers && this.entity.isVehicle()) || this.entity.isRemoved()) { // Paper - Teleport passenger API return false; } diff --git a/patches/server/0881-Stop-large-look-changes-from-crashing-the-server.patch b/patches/server/0881-Stop-large-look-changes-from-crashing-the-server.patch index e0405187f0..0396426cae 100644 --- a/patches/server/0881-Stop-large-look-changes-from-crashing-the-server.patch +++ b/patches/server/0881-Stop-large-look-changes-from-crashing-the-server.patch @@ -16,18 +16,17 @@ index 6b1c5b51693b8ae9ece498d4711b4493d0f5543a..80970c877b9e729fc88451745a490f0b - while (this.getYRot() - this.yRotO < -180.0F) { - this.yRotO -= 360.0F; - } -+ // Paper start - stop large pitch and yaw changes from crashing the server -+ this.yRotO += Math.round((this.getYRot() - this.yRotO) / 360.0F) * 360.0F; - +- - while (this.getYRot() - this.yRotO >= 180.0F) { - this.yRotO += 360.0F; - } -+ this.yBodyRotO += Math.round((this.yBodyRot - this.yBodyRotO) / 360.0F) * 360.0F; ++ // Paper start - stop large pitch and yaw changes from crashing the server ++ this.yRotO += Math.round((this.getYRot() - this.yRotO) / 360.0F) * 360.0F; - while (this.yBodyRot - this.yBodyRotO < -180.0F) { - this.yBodyRotO -= 360.0F; - } -+ this.xRotO += Math.round((this.getXRot() - this.xRotO) / 360.0F) * 360.0F; ++ this.yBodyRotO += Math.round((this.yBodyRot - this.yBodyRotO) / 360.0F) * 360.0F; - while (this.yBodyRot - this.yBodyRotO >= 180.0F) { - this.yBodyRotO += 360.0F; @@ -36,7 +35,8 @@ index 6b1c5b51693b8ae9ece498d4711b4493d0f5543a..80970c877b9e729fc88451745a490f0b - while (this.getXRot() - this.xRotO < -180.0F) { - this.xRotO -= 360.0F; - } -- ++ this.xRotO += Math.round((this.getXRot() - this.xRotO) / 360.0F) * 360.0F; + - while (this.getXRot() - this.xRotO >= 180.0F) { - this.xRotO += 360.0F; - } diff --git a/patches/server/0968-Optimize-Hoppers.patch b/patches/server/0968-Optimize-Hoppers.patch index 1116f8be1f..2499ac0ffc 100644 --- a/patches/server/0968-Optimize-Hoppers.patch +++ b/patches/server/0968-Optimize-Hoppers.patch @@ -281,18 +281,10 @@ index 789e5458f4a137694563a22612455506807de51b..cba114f554644a37339c93026630c66c - if (!iinventory.getItem(i).isEmpty()) { - ItemStack itemstack = iinventory.getItem(i).copy(); - // ItemStack itemstack1 = addItem(iinventory, iinventory1, iinventory.removeItem(i, 1), enumdirection); -+ // Paper start - replace logic; MAKE SURE TO CHECK FOR DIFFS ON UPDATES -+ return hopperPush(world, iinventory1, enumdirection, hopper); -+ // for (int i = 0; i < iinventory.getContainerSize(); ++i) { -+ // if (!iinventory.getItem(i).isEmpty()) { -+ // ItemStack itemstack = iinventory.getItem(i).copy(); -+ // // ItemStack itemstack1 = addItem(iinventory, iinventory1, iinventory.removeItem(i, 1), enumdirection); - +- - // CraftBukkit start - Call event when pushing items into other inventories - CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot -+ // // CraftBukkit start - Call event when pushing items into other inventories -+ // CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot - +- - Inventory destinationInventory; - // Have to special case large chests as they work oddly - if (iinventory1 instanceof CompoundContainer) { @@ -302,16 +294,7 @@ index 789e5458f4a137694563a22612455506807de51b..cba114f554644a37339c93026630c66c - } else { - destinationInventory = new CraftInventory(iinventory); - } -+ // Inventory destinationInventory; -+ // // Have to special case large chests as they work oddly -+ // if (iinventory1 instanceof CompoundContainer) { -+ // destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory1); -+ // } else if (iinventory1.getOwner() != null) { -+ // destinationInventory = iinventory1.getOwner().getInventory(); -+ // } else { -+ // destinationInventory = new CraftInventory(iinventory); -+ // } - +- - InventoryMoveItemEvent event = new InventoryMoveItemEvent(iinventory.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true); - world.getCraftServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { @@ -321,6 +304,26 @@ index 789e5458f4a137694563a22612455506807de51b..cba114f554644a37339c93026630c66c - } - int origCount = event.getItem().getAmount(); // Spigot - ItemStack itemstack1 = HopperBlockEntity.addItem(iinventory, iinventory1, CraftItemStack.asNMSCopy(event.getItem()), enumdirection); ++ // Paper start - replace logic; MAKE SURE TO CHECK FOR DIFFS ON UPDATES ++ return hopperPush(world, iinventory1, enumdirection, hopper); ++ // for (int i = 0; i < iinventory.getContainerSize(); ++i) { ++ // if (!iinventory.getItem(i).isEmpty()) { ++ // ItemStack itemstack = iinventory.getItem(i).copy(); ++ // // ItemStack itemstack1 = addItem(iinventory, iinventory1, iinventory.removeItem(i, 1), enumdirection); ++ ++ // // CraftBukkit start - Call event when pushing items into other inventories ++ // CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot ++ ++ // Inventory destinationInventory; ++ // // Have to special case large chests as they work oddly ++ // if (iinventory1 instanceof CompoundContainer) { ++ // destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory1); ++ // } else if (iinventory1.getOwner() != null) { ++ // destinationInventory = iinventory1.getOwner().getInventory(); ++ // } else { ++ // destinationInventory = new CraftInventory(iinventory); ++ // } ++ + // InventoryMoveItemEvent event = new InventoryMoveItemEvent(iinventory.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true); + // world.getCraftServer().getPluginManager().callEvent(event); + // if (event.isCancelled()) { @@ -408,14 +411,7 @@ index 789e5458f4a137694563a22612455506807de51b..cba114f554644a37339c93026630c66c - // ItemStack itemstack2 = addItem(iinventory, ihopper, iinventory.removeItem(i, 1), (EnumDirection) null); - // CraftBukkit start - Call event on collection of items from inventories into the hopper - CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot -+ // Paper start - replace pull logic; MAKE SURE TO CHECK FOR DIFFS WHEN UPDATING -+ if (!itemstack.isEmpty() && HopperBlockEntity.canTakeItemFromContainer(ihopper, iinventory, itemstack, i, enumdirection)) { // If this logic changes, update above. this is left unused incase reflective plugins -+ return hopperPull(world, ihopper, iinventory, itemstack, i); -+ // ItemStack itemstack1 = itemstack.copy(); -+ // // ItemStack itemstack2 = addItem(iinventory, ihopper, iinventory.removeItem(i, 1), (EnumDirection) null); -+ // // CraftBukkit start - Call event on collection of items from inventories into the hopper -+ // CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot - +- - Inventory sourceInventory; - // Have to special case large chests as they work oddly - if (iinventory instanceof CompoundContainer) { @@ -425,6 +421,38 @@ index 789e5458f4a137694563a22612455506807de51b..cba114f554644a37339c93026630c66c - } else { - sourceInventory = new CraftInventory(iinventory); - } +- +- InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack.clone(), ihopper.getOwner().getInventory(), false); +- +- Bukkit.getServer().getPluginManager().callEvent(event); +- if (event.isCancelled()) { +- iinventory.setItem(i, itemstack1); +- +- if (ihopper instanceof HopperBlockEntity) { +- ((HopperBlockEntity) ihopper).setCooldown(world.spigotConfig.hopperTransfer); // Spigot +- } +- +- return false; +- } +- int origCount = event.getItem().getAmount(); // Spigot +- ItemStack itemstack2 = HopperBlockEntity.addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null); +- // CraftBukkit end +- +- if (itemstack2.isEmpty()) { +- iinventory.setChanged(); +- return true; +- } +- +- itemstack1.shrink(origCount - itemstack2.getCount()); // Spigot +- iinventory.setItem(i, itemstack1); ++ // Paper start - replace pull logic; MAKE SURE TO CHECK FOR DIFFS WHEN UPDATING ++ if (!itemstack.isEmpty() && HopperBlockEntity.canTakeItemFromContainer(ihopper, iinventory, itemstack, i, enumdirection)) { // If this logic changes, update above. this is left unused incase reflective plugins ++ return hopperPull(world, ihopper, iinventory, itemstack, i); ++ // ItemStack itemstack1 = itemstack.copy(); ++ // // ItemStack itemstack2 = addItem(iinventory, ihopper, iinventory.removeItem(i, 1), (EnumDirection) null); ++ // // CraftBukkit start - Call event on collection of items from inventories into the hopper ++ // CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot ++ + // Inventory sourceInventory; + // // Have to special case large chests as they work oddly + // if (iinventory instanceof CompoundContainer) { @@ -434,46 +462,28 @@ index 789e5458f4a137694563a22612455506807de51b..cba114f554644a37339c93026630c66c + // } else { + // sourceInventory = new CraftInventory(iinventory); + // } - -- InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack.clone(), ihopper.getOwner().getInventory(), false); ++ + // InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack.clone(), ihopper.getOwner().getInventory(), false); - -- Bukkit.getServer().getPluginManager().callEvent(event); -- if (event.isCancelled()) { -- iinventory.setItem(i, itemstack1); ++ + // Bukkit.getServer().getPluginManager().callEvent(event); + // if (event.isCancelled()) { + // iinventory.setItem(i, itemstack1); - -- if (ihopper instanceof HopperBlockEntity) { -- ((HopperBlockEntity) ihopper).setCooldown(world.spigotConfig.hopperTransfer); // Spigot -- } ++ + // if (ihopper instanceof HopperBlockEntity) { + // ((HopperBlockEntity) ihopper).setCooldown(world.spigotConfig.hopperTransfer); // Spigot + // } - -- return false; -- } -- int origCount = event.getItem().getAmount(); // Spigot -- ItemStack itemstack2 = HopperBlockEntity.addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null); -- // CraftBukkit end ++ + // return false; + // } + // int origCount = event.getItem().getAmount(); // Spigot + // ItemStack itemstack2 = HopperBlockEntity.addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null); + // // CraftBukkit end - -- if (itemstack2.isEmpty()) { -- iinventory.setChanged(); -- return true; -- } ++ + // if (itemstack2.isEmpty()) { + // iinventory.setChanged(); + // return true; + // } - -- itemstack1.shrink(origCount - itemstack2.getCount()); // Spigot -- iinventory.setItem(i, itemstack1); ++ + // itemstack1.shrink(origCount - itemstack2.getCount()); // Spigot + // iinventory.setItem(i, itemstack1); + // Paper end