From 0adc18baf80c8b3292c836cbdbc04b3dd0c4df15 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Thu, 23 Mar 2023 14:57:03 -0700 Subject: [PATCH] [ci skip] rebuild patches --- .../Ability-to-apply-mending-to-XP-API.patch | 20 +- patches/api/Add-critical-damage-API.patch | 9 +- patches/api/Add-more-advancement-API.patch | 13 +- patches/api/Adventure.patch | 1059 ++++++++--------- ...ityRegainHealthEvent-isFastRegen-API.patch | 9 +- ...ent-consumeArrow-and-getArrowItem-AP.patch | 4 +- patches/api/Expand-world-key-API.patch | 20 +- patches/api/Improve-PortalEvents.patch | 9 +- patches/api/Inventory-removeItemAnySlot.patch | 40 +- patches/api/Paper-Plugins.patch | 4 +- patches/api/Test-changes.patch | 6 +- patches/api/Timings-v2.patch | 50 +- .../server/Add-PlayerKickEvent-causes.patch | 8 +- .../Add-PlayerUseUnknownEntityEvent.patch | 9 +- ...-Plugin-Tickets-to-API-Chunk-Methods.patch | 9 +- ...n-in-sunlight-API-for-Phantoms-and-S.patch | 9 +- patches/server/Add-more-Witch-API.patch | 4 +- patches/server/Add-more-advancement-API.patch | 12 +- patches/server/Adventure.patch | 19 +- ...w-adding-items-to-BlockDropItemEvent.patch | 4 +- ...tochunk-light-sources-unless-it-is-m.patch | 16 +- patches/server/Anti-Xray.patch | 13 +- patches/server/AsyncTabCompleteEvent.patch | 14 +- ...culate-regionfile-header-if-it-is-co.patch | 4 +- ...le-Keep-Spawn-Loaded-range-per-world.patch | 13 +- .../server/Entity-Activation-Range-2.0.patch | 28 +- patches/server/Entity-Origin-API.patch | 4 +- ...PI-for-Reason-Source-Triggering-play.patch | 4 +- .../Fix-GameProfileCache-concurrency.patch | 9 +- .../Fix-World-isChunkGenerated-calls.patch | 11 +- ...r-large-move-vectors-crashing-server.patch | 3 +- .../Fix-upstreams-block-state-factories.patch | 18 +- .../Further-improve-server-tick-loop.patch | 10 +- .../Handle-Item-Meta-Inconsistencies.patch | 18 +- ...single-and-multi-AABB-VoxelShapes-an.patch | 38 +- .../server/Implement-regenerateChunk.patch | 10 +- patches/server/Improve-death-events.patch | 15 +- .../server/Improved-Watchdog-Support.patch | 13 +- patches/server/MC-Utils.patch | 4 +- patches/server/More-Teleport-API.patch | 6 +- ...timise-BlockSoil-nearby-water-lookup.patch | 11 +- .../Optimise-chunk-tick-iteration.patch | 12 +- .../Optimise-random-block-ticking.patch | 74 +- ...oalSelector-Goal.Flag-Set-operations.patch | 19 +- patches/server/Optimize-Hoppers.patch | 114 +- ...-Manager-and-add-advanced-packet-sup.patch | 46 +- ...erCloseEnoughForSpawning-to-use-dist.patch | 43 +- ...ldBounds-and-getBlockState-for-inlin.patch | 4 +- ...spawn-settings-and-per-player-option.patch | 12 +- .../server/Player-affects-spawning-API.patch | 8 +- .../server/Player.setPlayerProfile-API.patch | 6 +- ...ent-chunk-loading-from-Fluid-Flowing.patch | 7 +- ...le-async-calls-to-restart-the-server.patch | 158 ++- patches/server/Rewrite-chunk-system.patch | 181 ++- patches/server/Starlight.patch | 12 +- patches/server/Stinger-API.patch | 4 +- ...te-operations-for-updating-light-dat.patch | 5 +- ...ook-changes-from-crashing-the-server.patch | 12 +- ...oleAppender-for-console-improvements.patch | 10 +- patches/server/add-DragonEggFormEvent.patch | 4 +- 60 files changed, 1113 insertions(+), 1197 deletions(-) diff --git a/patches/api/Ability-to-apply-mending-to-XP-API.patch b/patches/api/Ability-to-apply-mending-to-XP-API.patch index 9101d291d7..d654150ccb 100644 --- a/patches/api/Ability-to-apply-mending-to-XP-API.patch +++ b/patches/api/Ability-to-apply-mending-to-XP-API.patch @@ -18,21 +18,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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/Add-critical-damage-API.patch b/patches/api/Add-critical-damage-API.patch index 7cd516955a..28032187e0 100644 --- a/patches/api/Add-critical-damage-API.patch +++ b/patches/api/Add-critical-damage-API.patch @@ -32,8 +32,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + */ + public boolean isCritical() { + return this.critical; -+ } + } + // Paper end -+ + /** * Returns the entity that damaged the defender. - * diff --git a/patches/api/Add-more-advancement-API.patch b/patches/api/Add-more-advancement-API.patch index 70abec7df8..27753aceae 100644 --- a/patches/api/Add-more-advancement-API.patch +++ b/patches/api/Add-more-advancement-API.patch @@ -194,12 +194,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * 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/Adventure.patch b/patches/api/Adventure.patch index 6dc37b19a0..e562bb6ea3 100644 --- a/patches/api/Adventure.patch +++ b/patches/api/Adventure.patch @@ -939,21 +939,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + // 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() { @@ -1238,16 +1238,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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. -@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * 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. +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 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(); @@ -1521,49 +1523,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 * 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. -@@ -0,0 +0,0 @@ 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. -@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @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(); + + /** +@@ -0,0 +0,0 @@ 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; + + /** +@@ -0,0 +0,0 @@ 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; @@ -2137,24 +2132,42 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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. -@@ -0,0 +0,0 @@ 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 -@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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. +@@ -0,0 +0,0 @@ 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; + + /** +@@ -0,0 +0,0 @@ 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; @@ -2269,6 +2264,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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. + *

+@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * 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. - *

-@@ -0,0 +0,0 @@ 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. @@ -0,0 +0,0 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * @throws IllegalArgumentException Thrown if the hash is not 20 bytes * long. @@ -2592,50 +2587,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + // 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; - } - - /** -@@ -0,0 +0,0 @@ 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); - } - - /** -@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @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 + } + + /** +@@ -0,0 +0,0 @@ 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 + } + + /** +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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; @@ -2728,54 +2721,51 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + // 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; - } - - /** -@@ -0,0 +0,0 @@ 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); @@ -2884,26 +2874,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 */ - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 + } + + /** +@@ -0,0 +0,0 @@ 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 + } + + /** @@ -0,0 +0,0 @@ public class AsyncPlayerPreLoginEvent extends Event { @Deprecated public void disallow(@NotNull final PlayerPreLoginEvent.Result result, @NotNull final String message) { @@ -3013,70 +2994,65 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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; - } - - /** -@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java @@ -3252,8 +3228,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 */ + @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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @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. @@ -0,0 +0,0 @@ public class PlayerLoginEvent extends PlayerEvent { * Result.ALLOWED * @@ -3403,25 +3378,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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,29 +3413,30 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 -+ } + } + + /** +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java @@ -3483,59 +3450,60 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + @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; - } -@@ -0,0 +0,0 @@ public class PlayerQuitEvent extends PlayerEvent { - * - * @return string quit message - */ -- @Nullable -- public String getQuitMessage() { -+ public net.kyori.adventure.text.@Nullable Component quitMessage() { - return quitMessage; - } - -@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java @@ -3649,9 +3617,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + @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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @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. + * @@ -3859,8 +3827,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + /** + * 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 -@@ -0,0 +0,0 @@ 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 -@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + // 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. + *

+@@ -0,0 +0,0 @@ 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); + + /** +@@ -0,0 +0,0 @@ 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(); + + /** +@@ -0,0 +0,0 @@ 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); + + /** +@@ -0,0 +0,0 @@ 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); + + /** +@@ -0,0 +0,0 @@ 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); @@ -4239,6 +4179,24 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this(x, y, direction, type, visible, (String) null); // Paper } + /** +@@ -0,0 +0,0 @@ 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) { +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @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. - * -@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + // 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 */ @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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + */ + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 */ @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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + */ + 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/EntityRegainHealthEvent-isFastRegen-API.patch b/patches/api/EntityRegainHealthEvent-isFastRegen-API.patch index 90bb66c279..626f262300 100644 --- a/patches/api/EntityRegainHealthEvent-isFastRegen-API.patch +++ b/patches/api/EntityRegainHealthEvent-isFastRegen-API.patch @@ -25,8 +25,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + */ + public boolean isFastRegen() { + return isFastRegen; -+ } + } + // Paper end -+ + /** * Gets the amount of regained health - * diff --git a/patches/api/EntityShootBowEvent-consumeArrow-and-getArrowItem-AP.patch b/patches/api/EntityShootBowEvent-consumeArrow-and-getArrowItem-AP.patch index eb2a965cd6..7798907f76 100644 --- a/patches/api/EntityShootBowEvent-consumeArrow-and-getArrowItem-AP.patch +++ b/patches/api/EntityShootBowEvent-consumeArrow-and-getArrowItem-AP.patch @@ -18,7 +18,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public void setConsumeArrow(boolean consumeArrow) { + this.setConsumeItem(consumeArrow); + } - ++ + @Deprecated + public boolean getConsumeArrow() { + return this.shouldConsumeItem(); @@ -33,7 +33,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/Expand-world-key-API.patch b/patches/api/Expand-world-key-API.patch index d72f764b2b..070f843b12 100644 --- a/patches/api/Expand-world-key-API.patch +++ b/patches/api/Expand-world-key-API.patch @@ -110,14 +110,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + @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/Improve-PortalEvents.patch b/patches/api/Improve-PortalEvents.patch index 8556fa47eb..fd6fea0745 100644 --- a/patches/api/Improve-PortalEvents.patch +++ b/patches/api/Improve-PortalEvents.patch @@ -23,8 +23,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + @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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/event/player/PlayerPortalEvent.java diff --git a/patches/api/Inventory-removeItemAnySlot.patch b/patches/api/Inventory-removeItemAnySlot.patch index 6d6b95a34f..f4d1e8431f 100644 --- a/patches/api/Inventory-removeItemAnySlot.patch +++ b/patches/api/Inventory-removeItemAnySlot.patch @@ -16,6 +16,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * 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. +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @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. -@@ -0,0 +0,0 @@ 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/Paper-Plugins.patch b/patches/api/Paper-Plugins.patch index 71587d11eb..d4b3dba87f 100644 --- a/patches/api/Paper-Plugins.patch +++ b/patches/api/Paper-Plugins.patch @@ -2194,7 +2194,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/Test-changes.patch b/patches/api/Test-changes.patch index 8606c8ae36..c96d72c436 100644 --- a/patches/api/Test-changes.patch +++ b/patches/api/Test-changes.patch @@ -288,12 +288,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/Timings-v2.patch b/patches/api/Timings-v2.patch index 3ea0a26aac..6b1c3bc64a 100644 --- a/patches/api/Timings-v2.patch +++ b/patches/api/Timings-v2.patch @@ -3400,12 +3400,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - printStream.println("# Entities " + entities); - printStream.println("# LivingEntities " + livingEntities); -+ handler = timing; - } - +- } +- - /** - * Resets all timings. - */ @@ -3668,9 +3657,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - } - } -- ++ Timing timing; + - /** - * Starts timing to track a section of code. - */ @@ -3697,9 +3685,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - } - } -- ++ public void startTiming() { handler.startTiming(); } ++ public void stopTiming() { handler.stopTiming(); } + - /** - * Reset this timer, setting all values to zero. - */ diff --git a/patches/server/Add-PlayerKickEvent-causes.patch b/patches/server/Add-PlayerKickEvent-causes.patch index 896f0a7985..5f617fe18c 100644 --- a/patches/server/Add-PlayerKickEvent-causes.patch +++ b/patches/server/Add-PlayerKickEvent-causes.patch @@ -146,13 +146,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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/Add-PlayerUseUnknownEntityEvent.patch b/patches/server/Add-PlayerUseUnknownEntityEvent.patch index 4f805e11af..5c15202c7d 100644 --- a/patches/server/Add-PlayerUseUnknownEntityEvent.patch +++ b/patches/server/Add-PlayerUseUnknownEntityEvent.patch @@ -48,8 +48,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + }); + } - - } ++ ++ } + private void callPlayerUseUnknownEntityEvent(ServerboundInteractPacket packet, InteractionHand hand) { + this.cserver.getPluginManager().callEvent(new com.destroystokyo.paper.event.player.PlayerUseUnknownEntityEvent( @@ -58,9 +58,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/Add-Plugin-Tickets-to-API-Chunk-Methods.patch b/patches/server/Add-Plugin-Tickets-to-API-Chunk-Methods.patch index 75f9234a3f..cbb6022325 100644 --- a/patches/server/Add-Plugin-Tickets-to-API-Chunk-Methods.patch +++ b/patches/server/Add-Plugin-Tickets-to-API-Chunk-Methods.patch @@ -60,17 +60,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + 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"); @@ -0,0 +0,0 @@ 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/Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch b/patches/server/Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch index 6e0d522f02..3497a939e3 100644 --- a/patches/server/Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch +++ b/patches/server/Add-a-should-burn-in-sunlight-API-for-Phantoms-and-S.patch @@ -35,19 +35,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java diff --git a/patches/server/Add-more-Witch-API.patch b/patches/server/Add-more-Witch-API.patch index d2bc35cd11..e521347307 100644 --- a/patches/server/Add-more-Witch-API.patch +++ b/patches/server/Add-more-Witch-API.patch @@ -39,9 +39,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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/Add-more-advancement-API.patch b/patches/server/Add-more-advancement-API.patch index 7aac2ff3a3..2650b5ff1d 100644 --- a/patches/server/Add-more-advancement-API.patch +++ b/patches/server/Add-more-advancement-API.patch @@ -137,12 +137,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/Adventure.patch b/patches/server/Adventure.patch index d843cdee26..e32d01bff3 100644 --- a/patches/server/Adventure.patch +++ b/patches/server/Adventure.patch @@ -2322,14 +2322,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - @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 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + // 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + // 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/Allow-adding-items-to-BlockDropItemEvent.patch b/patches/server/Allow-adding-items-to-BlockDropItemEvent.patch index 5666d16b45..4367155fda 100644 --- a/patches/server/Allow-adding-items-to-BlockDropItemEvent.patch +++ b/patches/server/Allow-adding-items-to-BlockDropItemEvent.patch @@ -31,13 +31,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/Always-parse-protochunk-light-sources-unless-it-is-m.patch b/patches/server/Always-parse-protochunk-light-sources-unless-it-is-m.patch index addcc42cca..26076c8d0f 100644 --- a/patches/server/Always-parse-protochunk-light-sources-unless-it-is-m.patch +++ b/patches/server/Always-parse-protochunk-light-sources-unless-it-is-m.patch @@ -21,14 +21,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/Anti-Xray.patch b/patches/server/Anti-Xray.patch index 7ee5261208..570bfe23b2 100644 --- a/patches/server/Anti-Xray.patch +++ b/patches/server/Anti-Xray.patch @@ -1388,8 +1388,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.data.palette.idFor(presetValue); + } + } -+ } + } + // Paper end -+ + public T getAndSet(int x, int y, int z, T value) { this.acquire(); - @@ -0,0 +0,0 @@ public class PalettedContainer implements PaletteResize, PalettedContainer data.palette.read(buf); buf.readLongArray(data.storage.getRaw()); @@ -1415,10 +1414,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + // 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/AsyncTabCompleteEvent.patch b/patches/server/AsyncTabCompleteEvent.patch index b2eec8b74f..d88698d78a 100644 --- a/patches/server/AsyncTabCompleteEvent.patch +++ b/patches/server/AsyncTabCompleteEvent.patch @@ -49,6 +49,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // 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/Attempt-to-recalculate-regionfile-header-if-it-is-co.patch b/patches/server/Attempt-to-recalculate-regionfile-header-if-it-is-co.patch index 2f43f9b6a1..e56d40017e 100644 --- a/patches/server/Attempt-to-recalculate-regionfile-header-if-it-is-co.patch +++ b/patches/server/Attempt-to-recalculate-regionfile-header-if-it-is-co.patch @@ -509,7 +509,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/Configurable-Keep-Spawn-Loaded-range-per-world.patch b/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch index 01ee3a8a64..4482a894c8 100644 --- a/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch +++ b/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch @@ -31,18 +31,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - // 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/Entity-Activation-Range-2.0.patch b/patches/server/Entity-Activation-Range-2.0.patch index cf39a011f3..2b0b6da9ca 100644 --- a/patches/server/Entity-Activation-Range-2.0.patch +++ b/patches/server/Entity-Activation-Range-2.0.patch @@ -264,14 +264,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 { - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return config.villagersWorkImmunityFor; + } + } -+ } + } +- if ( entity instanceof Villager && ( (Villager) entity ).canBreed() ) + if ( entity instanceof Llama && ( (Llama) entity ).inCaravan() ) { - return true; @@ -679,11 +677,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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/Entity-Origin-API.patch b/patches/server/Entity-Origin-API.patch index df175f257c..f8faf46245 100644 --- a/patches/server/Entity-Origin-API.patch +++ b/patches/server/Entity-Origin-API.patch @@ -37,12 +37,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch b/patches/server/ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch index b8bfcade0a..0c3033c257 100644 --- a/patches/server/ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch +++ b/patches/server/ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch @@ -32,7 +32,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + 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/Fix-GameProfileCache-concurrency.patch b/patches/server/Fix-GameProfileCache-concurrency.patch index d6654c804d..02c7fbd628 100644 --- a/patches/server/Fix-GameProfileCache-concurrency.patch +++ b/patches/server/Fix-GameProfileCache-concurrency.patch @@ -112,8 +112,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } finally { + this.stateLock.unlock(); + } -+ } + } + // Paper end -+ + private static JsonElement writeGameProfile(GameProfileCache.GameProfileInfo entry, DateFormat dateFormat) { JsonObject jsonobject = new JsonObject(); - diff --git a/patches/server/Fix-World-isChunkGenerated-calls.patch b/patches/server/Fix-World-isChunkGenerated-calls.patch index fc71f0fbf1..87217f196a 100644 --- a/patches/server/Fix-World-isChunkGenerated-calls.patch +++ b/patches/server/Fix-World-isChunkGenerated-calls.patch @@ -197,6 +197,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // 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/Fix-for-large-move-vectors-crashing-server.patch b/patches/server/Fix-for-large-move-vectors-crashing-server.patch index 2f3fbcaddd..58915421d8 100644 --- a/patches/server/Fix-for-large-move-vectors-crashing-server.patch +++ b/patches/server/Fix-for-large-move-vectors-crashing-server.patch @@ -27,13 +27,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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/Fix-upstreams-block-state-factories.patch b/patches/server/Fix-upstreams-block-state-factories.patch index e0abbd47a5..645a2542e3 100644 --- a/patches/server/Fix-upstreams-block-state-factories.patch +++ b/patches/server/Fix-upstreams-block-state-factories.patch @@ -328,21 +328,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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/Further-improve-server-tick-loop.patch b/patches/server/Further-improve-server-tick-loop.patch index 50fd471e5c..bd90305098 100644 --- a/patches/server/Further-improve-server-tick-loop.patch +++ b/patches/server/Further-improve-server-tick-loop.patch @@ -185,10 +185,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/Handle-Item-Meta-Inconsistencies.patch b/patches/server/Handle-Item-Meta-Inconsistencies.patch index 80e9871245..f20e245e8f 100644 --- a/patches/server/Handle-Item-Meta-Inconsistencies.patch +++ b/patches/server/Handle-Item-Meta-Inconsistencies.patch @@ -130,14 +130,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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/Highly-optimise-single-and-multi-AABB-VoxelShapes-an.patch b/patches/server/Highly-optimise-single-and-multi-AABB-VoxelShapes-an.patch index 04571c41c5..eee71069e2 100644 --- a/patches/server/Highly-optimise-single-and-multi-AABB-VoxelShapes-an.patch +++ b/patches/server/Highly-optimise-single-and-multi-AABB-VoxelShapes-an.patch @@ -24,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + ((UnsafeList)list).setSize(0); + tempCollisionListInUse = false; + } -+ + + static final UnsafeList TEMP_GET_ENTITIES_LIST = new UnsafeList<>(1024); + static boolean tempGetEntitiesListInUse; + @@ -1277,26 +1277,29 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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/Implement-regenerateChunk.patch b/patches/server/Implement-regenerateChunk.patch index d09e54ae62..0e3c7e2c5f 100644 --- a/patches/server/Implement-regenerateChunk.patch +++ b/patches/server/Implement-regenerateChunk.patch @@ -25,6 +25,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - /* - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/Improve-death-events.patch b/patches/server/Improve-death-events.patch index c93a2d9844..546f3fd86d 100644 --- a/patches/server/Improve-death-events.patch +++ b/patches/server/Improve-death-events.patch @@ -119,13 +119,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/Improved-Watchdog-Support.patch b/patches/server/Improved-Watchdog-Support.patch index 754dc3ce10..f8e0d113f0 100644 --- a/patches/server/Improved-Watchdog-Support.patch +++ b/patches/server/Improved-Watchdog-Support.patch @@ -405,9 +405,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java diff --git a/patches/server/MC-Utils.patch b/patches/server/MC-Utils.patch index b8bfb9dd99..53b32292e3 100644 --- a/patches/server/MC-Utils.patch +++ b/patches/server/MC-Utils.patch @@ -7674,12 +7674,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/More-Teleport-API.patch b/patches/server/More-Teleport-API.patch index 917c224c0c..cb558468a8 100644 --- a/patches/server/More-Teleport-API.patch +++ b/patches/server/More-Teleport-API.patch @@ -55,14 +55,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/Optimise-BlockSoil-nearby-water-lookup.patch b/patches/server/Optimise-BlockSoil-nearby-water-lookup.patch index 8d5ba6cdb8..7f10504b90 100644 --- a/patches/server/Optimise-BlockSoil-nearby-water-lookup.patch +++ b/patches/server/Optimise-BlockSoil-nearby-water-lookup.patch @@ -15,16 +15,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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/Optimise-chunk-tick-iteration.patch b/patches/server/Optimise-chunk-tick-iteration.patch index f6c8c98675..61aa1b9543 100644 --- a/patches/server/Optimise-chunk-tick-iteration.patch +++ b/patches/server/Optimise-chunk-tick-iteration.patch @@ -170,13 +170,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + // 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 } // 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/Optimise-random-block-ticking.patch b/patches/server/Optimise-random-block-ticking.patch index 7c8e6d63f2..2702d153e0 100644 --- a/patches/server/Optimise-random-block-ticking.patch +++ b/patches/server/Optimise-random-block-ticking.patch @@ -173,14 +173,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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/Optimize-GoalSelector-Goal.Flag-Set-operations.patch b/patches/server/Optimize-GoalSelector-Goal.Flag-Set-operations.patch index cd37697cd3..fc27b5d667 100644 --- a/patches/server/Optimize-GoalSelector-Goal.Flag-Set-operations.patch +++ b/patches/server/Optimize-GoalSelector-Goal.Flag-Set-operations.patch @@ -74,27 +74,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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/Optimize-Hoppers.patch b/patches/server/Optimize-Hoppers.patch index 35eed1c2eb..091074c67f 100644 --- a/patches/server/Optimize-Hoppers.patch +++ b/patches/server/Optimize-Hoppers.patch @@ -281,18 +281,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - // 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // } 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 diff --git a/patches/server/Optimize-Network-Manager-and-add-advanced-packet-sup.patch b/patches/server/Optimize-Network-Manager-and-add-advanced-packet-sup.patch index 9740ab4edf..9c6d5cc03f 100644 --- a/patches/server/Optimize-Network-Manager-and-add-advanced-packet-sup.patch +++ b/patches/server/Optimize-Network-Manager-and-add-advanced-packet-sup.patch @@ -107,22 +107,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch b/patches/server/Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch index ae100f8b12..40ab4c05ab 100644 --- a/patches/server/Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch +++ b/patches/server/Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch @@ -136,17 +136,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return true; // in range + } + } -+ } + } + // no players in range + return false; + // Paper end - optimise anyPlayerCloseEnoughForSpawning diff --git a/patches/server/Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch b/patches/server/Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch index f459c0ed43..cf327b7ac5 100644 --- a/patches/server/Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch +++ b/patches/server/Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch @@ -103,7 +103,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // 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/Pillager-patrol-spawn-settings-and-per-player-option.patch b/patches/server/Pillager-patrol-spawn-settings-and-per-player-option.patch index 7b047766ac..bc6257ed45 100644 --- a/patches/server/Pillager-patrol-spawn-settings-and-per-player-option.patch +++ b/patches/server/Pillager-patrol-spawn-settings-and-per-player-option.patch @@ -44,7 +44,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/Player-affects-spawning-API.patch b/patches/server/Player-affects-spawning-API.patch index 6e3de69ebc..1877634781 100644 --- a/patches/server/Player-affects-spawning-API.patch +++ b/patches/server/Player-affects-spawning-API.patch @@ -145,13 +145,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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/Player.setPlayerProfile-API.patch b/patches/server/Player.setPlayerProfile-API.patch index 25c5cf4948..b99f6cde4d 100644 --- a/patches/server/Player.setPlayerProfile-API.patch +++ b/patches/server/Player.setPlayerProfile-API.patch @@ -127,11 +127,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/Prevent-chunk-loading-from-Fluid-Flowing.patch b/patches/server/Prevent-chunk-loading-from-Fluid-Flowing.patch index 0c7904e1e2..9fb4af40fa 100644 --- a/patches/server/Prevent-chunk-loading-from-Fluid-Flowing.patch +++ b/patches/server/Prevent-chunk-loading-from-Fluid-Flowing.patch @@ -58,14 +58,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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/Properly-handle-async-calls-to-restart-the-server.patch b/patches/server/Properly-handle-async-calls-to-restart-the-server.patch index 7533f2eb02..545abd0049 100644 --- a/patches/server/Properly-handle-async-calls-to-restart-the-server.patch +++ b/patches/server/Properly-handle-async-calls-to-restart-the-server.patch @@ -98,10 +98,24 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - // 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + // 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + { + @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/Rewrite-chunk-system.patch b/patches/server/Rewrite-chunk-system.patch index 757e14f19d..c502969c88 100644 --- a/patches/server/Rewrite-chunk-system.patch +++ b/patches/server/Rewrite-chunk-system.patch @@ -13176,15 +13176,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } catch (Throwable throwable1) { - throwable.addSuppressed(throwable1); - } -- ++ // Paper - rewrite chunk system + - throw throwable; - } - @@ -15129,23 +15125,29 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - } - } -- } ++ // 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; - }); @@ -16974,9 +16972,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (blockEntityNbt != null) { + blockEntitiesSerialized.add(blockEntityNbt); + } -+ } + } + + return new AsyncSaveData( + tickLists.get(BLOCK_TICKS_TAG), @@ -17006,12 +17004,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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); - } @@ -0,0 +0,0 @@ public class ChunkSerializer { // CraftBukkit end @@ -17151,11 +17148,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - }, 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 } } -- @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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // 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/Starlight.patch b/patches/server/Starlight.patch index da37862087..68e8f830e9 100644 --- a/patches/server/Starlight.patch +++ b/patches/server/Starlight.patch @@ -4545,13 +4545,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } 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/Stinger-API.patch b/patches/server/Stinger-API.patch index c8353e290b..a0b14cfb94 100644 --- a/patches/server/Stinger-API.patch +++ b/patches/server/Stinger-API.patch @@ -17,12 +17,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/Stop-copy-on-write-operations-for-updating-light-dat.patch b/patches/server/Stop-copy-on-write-operations-for-updating-light-dat.patch index e8b618a3b1..7302583027 100644 --- a/patches/server/Stop-copy-on-write-operations-for-updating-light-dat.patch +++ b/patches/server/Stop-copy-on-write-operations-for-updating-light-dat.patch @@ -271,12 +271,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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/Stop-large-look-changes-from-crashing-the-server.patch b/patches/server/Stop-large-look-changes-from-crashing-the-server.patch index 3ac2871e0d..c39710f4e1 100644 --- a/patches/server/Stop-large-look-changes-from-crashing-the-server.patch +++ b/patches/server/Stop-large-look-changes-from-crashing-the-server.patch @@ -16,18 +16,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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/Use-TerminalConsoleAppender-for-console-improvements.patch b/patches/server/Use-TerminalConsoleAppender-for-console-improvements.patch index fe9cd30794..3f2fd691de 100644 --- a/patches/server/Use-TerminalConsoleAppender-for-console-improvements.patch +++ b/patches/server/Use-TerminalConsoleAppender-for-console-improvements.patch @@ -397,9 +397,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + 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/add-DragonEggFormEvent.patch b/patches/server/add-DragonEggFormEvent.patch index d149a50f84..7f2d18df5a 100644 --- a/patches/server/add-DragonEggFormEvent.patch +++ b/patches/server/add-DragonEggFormEvent.patch @@ -25,10 +25,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + //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;