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 d654150ccb..9101d291d7 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 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 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, boolean applyMending); + + /** diff --git a/patches/api/Add-PlayerKickEvent-causes.patch b/patches/api/Add-PlayerKickEvent-causes.patch index 406316c463..20755a687a 100644 --- a/patches/api/Add-PlayerKickEvent-causes.patch +++ b/patches/api/Add-PlayerKickEvent-causes.patch @@ -11,7 +11,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * @param message kick message */ - void kick(final @Nullable net.kyori.adventure.text.Component message); + void kick(final net.kyori.adventure.text.@Nullable Component message); + + /** + * Kicks player with custom kick message and cause. @@ -19,7 +19,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @param message kick message + * @param cause kick cause + */ -+ void kick(final @Nullable net.kyori.adventure.text.Component message, @NotNull org.bukkit.event.player.PlayerKickEvent.Cause cause); ++ void kick(final net.kyori.adventure.text.@Nullable Component message, org.bukkit.event.player.PlayerKickEvent.@NotNull Cause cause); // Paper end /** diff --git a/patches/api/Add-critical-damage-API.patch b/patches/api/Add-critical-damage-API.patch index 28032187e0..7cd516955a 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,8 +44,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + */ + public boolean isCritical() { + return this.critical; - } ++ } + // Paper end - ++ /** * Returns the entity that damaged the defender. + * diff --git a/patches/api/Add-getI18NDisplayName-API.patch b/patches/api/Add-getI18NDisplayName-API.patch index e63e7aefec..bd2a30410e 100644 --- a/patches/api/Add-getI18NDisplayName-API.patch +++ b/patches/api/Add-getI18NDisplayName-API.patch @@ -36,7 +36,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/org/bukkit/inventory/ItemStack.java +++ b/src/main/java/org/bukkit/inventory/ItemStack.java @@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat - public @NotNull net.kyori.adventure.text.Component displayName() { + public net.kyori.adventure.text.@NotNull Component displayName() { return Bukkit.getServer().getItemFactory().displayName(this); } + diff --git a/patches/api/Add-more-advancement-API.patch b/patches/api/Add-more-advancement-API.patch index 27753aceae..70abec7df8 100644 --- a/patches/api/Add-more-advancement-API.patch +++ b/patches/api/Add-more-advancement-API.patch @@ -194,8 +194,12 @@ 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(); + @@ -205,13 +209,10 @@ 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 384b08e275..6dc37b19a0 100644 --- a/patches/api/Adventure.patch +++ b/patches/api/Adventure.patch @@ -164,14 +164,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; -+import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; + +sealed class ViewerUnawareImpl implements ChatRenderer, ChatRenderer.ViewerUnaware permits ViewerUnawareImpl.Default { -+ + private final ViewerUnaware unaware; -+ -+ private @MonotonicNonNull Component message; ++ private @Nullable Component message; + + ViewerUnawareImpl(final ViewerUnaware unaware) { + this.unaware = unaware; @@ -191,7 +189,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + static final class Default extends ViewerUnawareImpl implements ChatRenderer.Default { -+ + Default(final ViewerUnaware unaware) { + super(unaware); + } @@ -779,7 +776,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @param message the message + * @return the number of players + */ -+ public static int broadcast(@NotNull net.kyori.adventure.text.Component message) { ++ public static int broadcast(net.kyori.adventure.text.@NotNull Component message) { + return server.broadcast(message); + } /** @@ -789,7 +786,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 * permissibles} must have to receive the broadcast * @return number of message recipients */ -+ public static int broadcast(@NotNull net.kyori.adventure.text.Component message, @NotNull String permission) { ++ public static int broadcast(net.kyori.adventure.text.@NotNull Component message, @NotNull String permission) { + return server.broadcast(message, permission); + } + // Paper end @@ -819,7 +816,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 * @see InventoryType#isCreatable() */ @NotNull -+ public static Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, @NotNull net.kyori.adventure.text.Component title) { ++ public static Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, net.kyori.adventure.text.@NotNull Component title) { + return server.createInventory(owner, type, title); + } + // Paper end @@ -866,7 +863,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 * @throws IllegalArgumentException if the size is not a multiple of 9 */ @NotNull -+ public static Inventory createInventory(@Nullable InventoryHolder owner, int size, @NotNull net.kyori.adventure.text.Component title) throws IllegalArgumentException { ++ public static Inventory createInventory(@Nullable InventoryHolder owner, int size, net.kyori.adventure.text.@NotNull Component title) throws IllegalArgumentException { + return server.createInventory(owner, size, title); + } + // Paper end @@ -897,7 +894,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 * when the merchant inventory is viewed * @return a new merchant */ -+ public static @NotNull Merchant createMerchant(@Nullable net.kyori.adventure.text.Component title) { ++ public static @NotNull Merchant createMerchant(net.kyori.adventure.text.@Nullable Component title) { + return server.createMerchant(title); + } + // Paper start @@ -942,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 @Nullable net.kyori.adventure.text.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() { @@ -1008,7 +1005,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @return the custom name + */ -+ @Nullable net.kyori.adventure.text.Component customName(); ++ net.kyori.adventure.text.@Nullable Component customName(); + + /** + * Sets the custom name. @@ -1021,7 +1018,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @param customName the custom name to set + */ -+ void customName(final @Nullable net.kyori.adventure.text.Component customName); ++ void customName(final net.kyori.adventure.text.@Nullable Component customName); + // Paper end + /** @@ -1175,7 +1172,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @param message the message + * @return the number of players + */ -+ int broadcast(@NotNull net.kyori.adventure.text.Component message); ++ int broadcast(net.kyori.adventure.text.@NotNull Component message); + + /** + * Broadcasts the specified message to every user with the given @@ -1186,7 +1183,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * permissibles} must have to receive the broadcast + * @return number of message recipients + */ -+ int broadcast(@NotNull net.kyori.adventure.text.Component message, @NotNull String permission); ++ int broadcast(net.kyori.adventure.text.@NotNull Component message, @NotNull String permission); + // Paper end /** @@ -1203,7 +1200,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 * @see InventoryType#isCreatable() */ @NotNull -+ Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, @NotNull net.kyori.adventure.text.Component title); ++ Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, net.kyori.adventure.text.@NotNull Component title); + // Paper end + + /** @@ -1241,6 +1238,16 @@ 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. @@ -1251,22 +1258,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * viewed + * @return a new inventory + * @throws IllegalArgumentException if the size is not a multiple of 9 -+ */ -+ @NotNull -+ Inventory createInventory(@Nullable InventoryHolder owner, int size, @NotNull net.kyori.adventure.text.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 ++ @NotNull Inventory createInventory(@Nullable InventoryHolder owner, int size, @NotNull String title) throws IllegalArgumentException; + // Paper start @@ -1277,7 +1272,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 * when the merchant inventory is viewed * @return a new merchant */ -+ @NotNull Merchant createMerchant(@Nullable net.kyori.adventure.text.Component title); ++ @NotNull Merchant createMerchant(net.kyori.adventure.text.@Nullable Component title); + // Paper start + /** + * Creates an empty merchant. @@ -1302,7 +1297,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @return the server's MOTD + */ -+ @NotNull net.kyori.adventure.text.Component motd(); ++ net.kyori.adventure.text.@NotNull Component motd(); + // Paper end + /** @@ -1316,19 +1311,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 String getMotd(); + // Paper start -+ /** -+ * Gets the default message that is displayed when the server is stopped. -+ * -+ * @return the shutdown message -+ */ -+ @Nullable net.kyori.adventure.text.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(); @@ -1373,9 +1368,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + + // Paper start -+ @NotNull + @Override -+ public net.kyori.adventure.key.@org.checkerframework.checker.nullness.qual.NonNull Key key() { ++ public net.kyori.adventure.key.@NotNull Key key() { + return this.key; + } + // Paper end @@ -1507,7 +1501,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @return Name of this CommandBlock. + */ -+ public @NotNull net.kyori.adventure.text.Component name(); ++ public net.kyori.adventure.text.@NotNull Component name(); + + /** + * Sets the name of this CommandBlock. The name is used with commands @@ -1516,7 +1510,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @param name New name for this CommandBlock. + */ -+ public void name(@Nullable net.kyori.adventure.text.Component name); ++ public void name(net.kyori.adventure.text.@Nullable Component name); + // Paper end } diff --git a/src/main/java/org/bukkit/block/Sign.java b/src/main/java/org/bukkit/block/Sign.java @@ -1527,14 +1521,49 @@ 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 -+ public java.util.List lines(); ++ @Deprecated // Paper ++ public String[] getLines(); + + /** + * Gets the line of text at the specified index. @@ -1542,11 +1571,13 @@ 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 -+ * @throws IndexOutOfBoundsException Thrown when the line does not exist + * @return Text on the given line ++ * @throws IndexOutOfBoundsException Thrown when the line does not exist ++ * @deprecated in favour of {@link #line(int)} + */ + @NotNull -+ public net.kyori.adventure.text.Component line(int index) throws IndexOutOfBoundsException; ++ @Deprecated // Paper ++ public String getLine(int index) throws IndexOutOfBoundsException; + + /** + * Sets the line of text at the specified index. @@ -1557,38 +1588,8 @@ 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 -+ */ -+ public void line(int index, @NotNull net.kyori.adventure.text.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; @@ -1659,7 +1660,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @return the permission message + */ -+ public @Nullable net.kyori.adventure.text.Component permissionMessage() { ++ public net.kyori.adventure.text.@Nullable Component permissionMessage() { + return this.permissionMessage; + } + @@ -1668,7 +1669,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @param permissionMessage the permission message + */ -+ public void permissionMessage(@Nullable net.kyori.adventure.text.Component permissionMessage) { ++ public void permissionMessage(net.kyori.adventure.text.@Nullable Component permissionMessage) { + this.permissionMessage = permissionMessage; + } + // Paper end @@ -1683,11 +1684,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + broadcastCommandMessage(source, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message), sendToSource); + } + -+ public static void broadcastCommandMessage(@NotNull CommandSender source, @NotNull net.kyori.adventure.text.Component message) { ++ public static void broadcastCommandMessage(@NotNull CommandSender source, net.kyori.adventure.text.@NotNull Component message) { + broadcastCommandMessage(source, message, true); + } + -+ public static void broadcastCommandMessage(@NotNull CommandSender source, @NotNull net.kyori.adventure.text.Component message, boolean sendToSource) { ++ public static void broadcastCommandMessage(@NotNull CommandSender source, net.kyori.adventure.text.@NotNull Component message, boolean sendToSource) { + net.kyori.adventure.text.TextComponent.Builder result = net.kyori.adventure.text.Component.text() + .color(net.kyori.adventure.text.format.NamedTextColor.WHITE) + .decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false) @@ -1806,10 +1807,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @return Name of the sender + */ -+ public @NotNull net.kyori.adventure.text.Component name(); ++ public net.kyori.adventure.text.@NotNull Component name(); + + @Override -+ default void sendMessage(final @NotNull net.kyori.adventure.identity.Identity identity, final @NotNull net.kyori.adventure.text.Component message, final @NotNull net.kyori.adventure.audience.MessageType type) { ++ default void sendMessage(final net.kyori.adventure.identity.@NotNull Identity identity, final net.kyori.adventure.text.@NotNull Component message, final net.kyori.adventure.audience.@NotNull MessageType type) { + this.sendMessage(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(message)); + } + @@ -1867,7 +1868,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + @Override -+ default void sendMessage(final @NotNull net.kyori.adventure.identity.Identity source, final @NotNull net.kyori.adventure.text.Component message, final @NotNull net.kyori.adventure.audience.MessageType type) { ++ default void sendMessage(final net.kyori.adventure.identity.@NotNull Identity source, final net.kyori.adventure.text.@NotNull Component message, final net.kyori.adventure.audience.@NotNull MessageType type) { + net.kyori.adventure.audience.ForwardingAudience.Single.super.sendMessage(source, message, type); + } + @@ -1897,7 +1898,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @param level the level of the enchantment to show + * @return the name of the enchantment with {@code level} applied + */ -+ public abstract @NotNull net.kyori.adventure.text.Component displayName(int level); ++ public abstract net.kyori.adventure.text.@NotNull Component displayName(int level); + // Paper end @Override @@ -1943,7 +1944,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @return the team display name + */ -+ @NotNull net.kyori.adventure.text.Component teamDisplayName(); ++ net.kyori.adventure.text.@NotNull Component teamDisplayName(); + + @NotNull + @Override @@ -1965,7 +1966,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + // Paper start + @Override -+ default @NotNull net.kyori.adventure.identity.Identity identity() { ++ default net.kyori.adventure.identity.@NotNull Identity identity() { + return net.kyori.adventure.identity.Identity.identity(this.getUniqueId()); + } + @@ -1974,14 +1975,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @return the display name + */ -+ @NotNull net.kyori.adventure.text.Component displayName(); ++ net.kyori.adventure.text.@NotNull Component displayName(); + + /** + * Sets the "friendly" name to display of this player. + * + * @param displayName the display name to set + */ -+ void displayName(final @Nullable net.kyori.adventure.text.Component displayName); ++ void displayName(final net.kyori.adventure.text.@Nullable Component displayName); + // Paper end /** @@ -2013,28 +2014,28 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @param name new player list name + */ -+ void playerListName(@Nullable net.kyori.adventure.text.Component name); ++ void playerListName(net.kyori.adventure.text.@Nullable Component name); + + /** + * Gets the name that is shown on the in-game player list. + * + * @return the player list name + */ -+ @NotNull net.kyori.adventure.text.Component playerListName(); ++ net.kyori.adventure.text.@NotNull Component playerListName(); + + /** + * Gets the currently displayed player list header for this player. + * + * @return player list header or null + */ -+ @Nullable net.kyori.adventure.text.Component playerListHeader(); ++ net.kyori.adventure.text.@Nullable Component playerListHeader(); + + /** + * Gets the currently displayed player list footer for this player. + * + * @return player list footer or null + */ -+ @Nullable net.kyori.adventure.text.Component playerListFooter(); ++ net.kyori.adventure.text.@Nullable Component playerListFooter(); + // Paper end /** * Gets the name that is shown on the player list. @@ -2125,7 +2126,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @param message kick message + */ -+ void kick(final @Nullable net.kyori.adventure.text.Component message); ++ void kick(final net.kyori.adventure.text.@Nullable Component message); + // Paper end + /** @@ -2136,42 +2137,24 @@ 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. -+ * 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 + * @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; + 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 -+ * 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 -+ */ + + /** + * 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 + */ + default void sendSignChange(@NotNull Location loc, @Nullable java.util.List lines, @NotNull DyeColor dyeColor) throws IllegalArgumentException { + this.sendSignChange(loc, lines, dyeColor, false); + } @@ -2219,25 +2202,43 @@ 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. -@@ -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 ++ /** ++ * 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 + * @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; - - /** -@@ -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 ++ 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 + * @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; @@ -2268,25 +2269,6 @@ 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. + *

@@ -2316,16 +2298,35 @@ 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 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. ++ * @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. @@ -0,0 +0,0 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * @throws IllegalArgumentException Thrown if the hash is not 20 bytes * long. @@ -2527,14 +2528,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @return the displayed text + */ -+ @NotNull net.kyori.adventure.text.Component text(); ++ net.kyori.adventure.text.@NotNull Component text(); + + /** + * Sets the displayed text. + * + * @param text the new text + */ -+ void text(@Nullable net.kyori.adventure.text.Component text); ++ void text(net.kyori.adventure.text.@Nullable Component text); + // Paper end + /** @@ -2591,13 +2592,50 @@ 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()} + */ -+ public @NotNull java.util.List lines() { -+ return this.adventure$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 + } + + /** @@ -2608,9 +2646,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * provided index + * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 + * or < 0} ++ * @deprecated in favour of {@link #line(int)} + */ -+ public @Nullable net.kyori.adventure.text.Component line(int index) throws IndexOutOfBoundsException { -+ return this.adventure$lines.get(index); ++ @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 + } + + /** @@ -2620,46 +2661,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @param line text to set + * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 + * or < 0} -+ */ -+ public void line(int index, @Nullable net.kyori.adventure.text.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; @@ -2684,11 +2687,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; @@ -2725,51 +2728,54 @@ 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 deathMessage(@Nullable net.kyori.adventure.text.Component deathMessage) { -+ this.deathMessage = null; -+ this.adventure$deathMessage = deathMessage; -+ } -+ -+ /** -+ * Get the death message that will appear to everyone on the server. -+ * -+ * @return Message to appear to other players on the server. -+ */ -+ public @Nullable net.kyori.adventure.text.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. -+ * @deprecated in favour of {@link #deathMessage(net.kyori.adventure.text.Component)} */ -+ @Deprecated // Paper - 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 +- public void setDeathMessage(@Nullable String deathMessage) { +- this.deathMessage = deathMessage; ++ public void deathMessage(net.kyori.adventure.text.@Nullable Component deathMessage) { ++ this.deathMessage = null; ++ this.adventure$deathMessage = deathMessage; } /** - * Get the death message that will appear to everyone on the server. +@@ -0,0 +0,0 @@ public class PlayerDeathEvent extends EntityDeathEvent { * * @return Message to appear to other players on the server. -+ * @deprecated in favour of {@link #deathMessage()} */ - @Nullable -+ @Deprecated // Paper - public String getDeathMessage() { +- @Nullable +- public String getDeathMessage() { - return deathMessage; -+ return this.deathMessage != null ? this.deathMessage : (this.adventure$deathMessage != null ? getDeathMessageString(this.adventure$deathMessage) : null); // Paper ++ 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. ++ * @deprecated in favour of {@link #deathMessage(net.kyori.adventure.text.Component)} ++ */ ++ @Deprecated // Paper ++ 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. ++ * @deprecated in favour of {@link #deathMessage()} ++ */ ++ @Nullable ++ @Deprecated // Paper ++ public String getDeathMessage() { ++ 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); @@ -2794,7 +2800,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @return the inventory's default title + */ -+ public @NotNull net.kyori.adventure.text.Component defaultTitle() { ++ public net.kyori.adventure.text.@NotNull Component defaultTitle() { + return defaultTitleComponent; + } + // Paper end @@ -2878,17 +2884,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 */ - public void setKickMessage(@NotNull final String message) { + public void kickMessage(@NotNull final net.kyori.adventure.text.Component 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 -+ */ + 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) { + public void disallow(@NotNull final Result result, @NotNull final net.kyori.adventure.text.Component message) { -+ this.result = result; + this.result = result; this.message = message; } @@ -2931,30 +2946,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; -- message = ""; ++ /** ++ * Allows the player to log in ++ */ ++ public void allow() { ++ result = Result.ALLOWED; + 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 ++ } ++ ++ /** ++ * 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 = message; ++ 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 + * @@ -0,0 +0,0 @@ public class AsyncPlayerPreLoginEvent extends Event { @Deprecated public void disallow(@NotNull final PlayerPreLoginEvent.Result result, @NotNull final String message) { @@ -2998,65 +3013,70 @@ 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()} + */ -+ public @Nullable net.kyori.adventure.text.Component joinMessage() { -+ return this.joinMessage; ++ @Nullable ++ @Deprecated // Paper ++ public String getJoinMessage() { ++ 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 -+ */ -+ public void joinMessage(@Nullable net.kyori.adventure.text.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 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; ++ public void setJoinMessage(@Nullable String 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 @@ -3091,7 +3111,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @return string kick reason + */ -+ public @NotNull net.kyori.adventure.text.Component leaveMessage() { ++ public net.kyori.adventure.text.@NotNull Component leaveMessage() { + return this.leaveMessage; + } + @@ -3100,7 +3120,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @param leaveMessage leave message + */ -+ public void leaveMessage(@NotNull net.kyori.adventure.text.Component leaveMessage) { ++ public void leaveMessage(net.kyori.adventure.text.@NotNull Component leaveMessage) { + this.leaveMessage = leaveMessage; + } + @@ -3109,7 +3129,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 * * @return string kick reason */ -+ public @NotNull net.kyori.adventure.text.Component reason() { ++ public net.kyori.adventure.text.@NotNull Component reason() { + return this.kickReason; + } + @@ -3118,7 +3138,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @param kickReason kick reason + */ -+ public void reason(@NotNull net.kyori.adventure.text.Component kickReason) { ++ public void reason(net.kyori.adventure.text.@NotNull Component kickReason) { + this.kickReason = kickReason; + } + // Paper end @@ -3232,8 +3252,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 + } + @@ -3250,18 +3270,18 @@ 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 + * + * @return Current kick message + */ -+ public @NotNull net.kyori.adventure.text.Component kickMessage() { ++ public net.kyori.adventure.text.@NotNull Component kickMessage() { + return this.message; + } + @@ -3270,13 +3290,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @param message New kick message + */ -+ public void kickMessage(@NotNull net.kyori.adventure.text.Component message) { - this.message = message; - } ++ public void kickMessage(net.kyori.adventure.text.@NotNull Component 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 * @@ -3382,16 +3403,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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 -+ */ +- /** +- * 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) { + 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() != @@ -3417,30 +3447,29 @@ 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; -- message = ""; ++ /** ++ * Allows the player to log in ++ */ ++ public void allow() { ++ result = Result.ALLOWED; + message = net.kyori.adventure.text.Component.empty(); // 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 ++ } ++ ++ /** ++ * 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 = message; ++ 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 - } ++ } /** + * 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 @@ -3454,60 +3483,59 @@ 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; -+ } + 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 + + /** + * Gets the quit message to send to all online players + * + * @return string quit message ++ * @deprecated in favour of {@link #quitMessage()} + */ -+ public @Nullable net.kyori.adventure.text.Component quitMessage() { -+ return quitMessage; ++ @Nullable ++ @Deprecated // Paper ++ public String getQuitMessage() { ++ 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 -+ */ -+ public void quitMessage(@Nullable net.kyori.adventure.text.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 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; ++ public void setQuitMessage(@Nullable String 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 @@ -3534,11 +3562,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + @Deprecated -+ public BroadcastMessageEvent(@NotNull net.kyori.adventure.text.Component message, @NotNull Set recipients) { ++ public BroadcastMessageEvent(net.kyori.adventure.text.@NotNull Component message, @NotNull Set recipients) { + this(false, message, recipients); + } + -+ public BroadcastMessageEvent(boolean isAsync, @NotNull net.kyori.adventure.text.Component message, @NotNull Set recipients) { ++ public BroadcastMessageEvent(boolean isAsync, net.kyori.adventure.text.@NotNull Component message, @NotNull Set recipients) { + // Paper end super(isAsync); this.message = message; @@ -3550,7 +3578,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @return Message to broadcast + */ -+ public @NotNull net.kyori.adventure.text.Component message() { ++ public net.kyori.adventure.text.@NotNull Component message() { + return this.message; + } + @@ -3559,7 +3587,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @param message New message to broadcast + */ -+ public void message(@NotNull net.kyori.adventure.text.Component message) { ++ public void message(net.kyori.adventure.text.@NotNull Component message) { + this.message = message; + } + // Paper end @@ -3621,9 +3649,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; + } @@ -3637,10 +3665,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()} @@ -3666,19 +3694,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @param motd the message of the day + * @param maxPlayers the max number of players + */ -+ protected ServerListPingEvent(final @NotNull String hostname, final @NotNull InetAddress address, final @NotNull net.kyori.adventure.text.Component motd, final int maxPlayers) { -+ this.numPlayers = MAGIC_PLAYER_COUNT; -+ this.hostname = hostname; -+ this.address = address; -+ this.motd = motd; -+ this.maxPlayers = maxPlayers; -+ } ++ 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; + } + /** + * Get the message of the day message. + * + * @return the message of the day + */ -+ public @NotNull net.kyori.adventure.text.Component motd() { ++ public net.kyori.adventure.text.@NotNull Component motd() { + return motd; + } + /** @@ -3686,7 +3714,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @param motd the message of the day + */ -+ public void motd(@NotNull net.kyori.adventure.text.Component motd) { ++ public void motd(net.kyori.adventure.text.@NotNull Component motd) { + this.motd = motd; + } + // Paper end @@ -3808,7 +3836,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @return display name of the {@link ItemStack} + */ -+ public @NotNull net.kyori.adventure.text.Component displayName() { ++ public net.kyori.adventure.text.@NotNull Component displayName() { + return Bukkit.getServer().getItemFactory().displayName(this); + } + // Paper end @@ -3831,7 +3859,8 @@ 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 @@ -3839,9 +3868,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @return the title of the book + */ -+ @Nullable + @Override -+ net.kyori.adventure.text.Component title(); ++ net.kyori.adventure.text.@Nullable Component title(); + + /** + * Sets the title of the book. @@ -3851,9 +3879,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @param title the title to set + * @return the same {@link BookMeta} instance + */ -+ @NotNull ++ @org.jetbrains.annotations.Contract(value = "_ -> this", pure = false) + @Override -+ @org.checkerframework.common.returnsreceiver.qual.This BookMeta title(@Nullable net.kyori.adventure.text.Component title); ++ @NotNull BookMeta title(net.kyori.adventure.text.@Nullable Component title); + + /** + * Gets the author of the book. @@ -3863,9 +3891,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @return the author of the book + */ -+ @Nullable + @Override -+ net.kyori.adventure.text.Component author(); ++ net.kyori.adventure.text.@Nullable Component author(); + + /** + * Sets the author of the book. Removes author when given null. @@ -3873,19 +3900,101 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @param author the author to set + * @return the same {@link BookMeta} instance + */ -+ @NotNull ++ @org.jetbrains.annotations.Contract(value = "_ -> this", pure = false) + @Override -+ @org.checkerframework.common.returnsreceiver.qual.This BookMeta author(@Nullable net.kyori.adventure.text.Component author); ++ @NotNull BookMeta author(net.kyori.adventure.text.@Nullable Component author); + + /** + * 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); ++ 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); ++ 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 + */ ++ void addPages(net.kyori.adventure.text.@NotNull Component @NotNull ... pages); ++ ++ interface BookMetaBuilder extends Builder { ++ ++ @Override ++ @NotNull BookMetaBuilder title(net.kyori.adventure.text.@Nullable Component title); ++ ++ @Override ++ @NotNull BookMetaBuilder author(net.kyori.adventure.text.@Nullable Component author); ++ ++ @Override ++ @NotNull BookMetaBuilder addPage(net.kyori.adventure.text.@NotNull Component page); ++ ++ @Override ++ @NotNull BookMetaBuilder pages(net.kyori.adventure.text.@NotNull Component @NotNull ... pages); ++ ++ @Override ++ @NotNull BookMetaBuilder pages(java.util.@NotNull Collection pages); ++ ++ @Override ++ @NotNull BookMeta build(); ++ } ++ ++ @Override ++ @NotNull BookMetaBuilder toBuilder(); ++ ++ // 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 ++ * @deprecated in favour of {@link #page(int)} + */ -+ @NotNull net.kyori.adventure.text.Component page(int page); ++ @NotNull ++ @Deprecated // Paper ++ String getPage(int page); + + /** + * Sets the specified page in the book. Pages of the book must be @@ -3898,110 +4007,48 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @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)} + */ -+ void page(int page, @NotNull net.kyori.adventure.text.Component data); ++ @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 ++ * @deprecated in favour of {@link #pages()} ++ */ ++ @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 ++ * @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 ++ * @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 addPages(@NotNull net.kyori.adventure.text.Component... pages); -+ -+ interface BookMetaBuilder extends Builder { -+ -+ @NotNull -+ @Override -+ BookMetaBuilder title(@Nullable net.kyori.adventure.text.Component title); -+ -+ @NotNull -+ @Override -+ BookMetaBuilder author(@Nullable net.kyori.adventure.text.Component author); -+ -+ @NotNull -+ @Override -+ BookMetaBuilder addPage(@NotNull net.kyori.adventure.text.Component page); -+ -+ @NotNull -+ @Override -+ BookMetaBuilder pages(@NotNull net.kyori.adventure.text.Component... pages); -+ -+ @NotNull -+ @Override -+ BookMetaBuilder pages(@NotNull java.util.Collection pages); -+ -+ @NotNull -+ @Override -+ BookMeta build(); -+ } -+ -+ @Override -+ @org.checkerframework.checker.nullness.qual.NonNull -+ BookMetaBuilder toBuilder(); -+ -+ // Paper end -+ - /** - * 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 -+ @Deprecated // Paper - 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 -+ * @deprecated in favour of {@link #pages()} - */ - @NotNull -+ @Deprecated // Paper - 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); - - /** -@@ -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); - - /** -@@ -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); @@ -4084,14 +4131,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @return the display name + */ -+ @Nullable net.kyori.adventure.text.Component displayName(); ++ net.kyori.adventure.text.@Nullable Component displayName(); + + /** + * Sets the display name. + * + * @param displayName the display name to set + */ -+ void displayName(final @Nullable net.kyori.adventure.text.Component displayName); ++ void displayName(final net.kyori.adventure.text.@Nullable Component displayName); + // Paper end + /** @@ -4192,24 +4239,6 @@ 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. + * @@ -4219,14 +4248,35 @@ 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 ++ * @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 net.kyori.adventure.text.Component caption) { -+ this.x = x; this.y = y; this.visible = visible; this.caption = caption; ++ 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; + } + /** + * Initialize the map cursor. + * @@ -4237,7 +4287,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @param visible Whether the cursor is visible by default. + * @param caption cursor caption + */ -+ public MapCursor(byte x, byte y, byte direction, @NotNull Type type, boolean visible, @Nullable net.kyori.adventure.text.Component caption) { ++ public MapCursor(byte x, byte y, byte direction, @NotNull Type type, boolean visible, net.kyori.adventure.text.@Nullable Component caption) { + this.x = x; this.y = y; this.visible = visible; this.caption = caption; + setDirection(direction); + setType(type); @@ -4260,12 +4310,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + // Paper start -+ /** -+ * Gets the caption on this cursor. -+ * -+ * @return caption -+ */ -+ public @Nullable net.kyori.adventure.text.Component caption() { + /** + * Gets the caption on this cursor. + * + * @return caption + */ ++ public net.kyori.adventure.text.@Nullable Component caption() { + return this.caption; + } + /** @@ -4273,16 +4323,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @param caption new caption + */ -+ public void caption(@Nullable net.kyori.adventure.text.Component caption) { ++ public void caption(net.kyori.adventure.text.@Nullable Component caption) { + 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() { @@ -4325,7 +4375,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @deprecated Magic value + */ + @Deprecated -+ public @NotNull MapCursor addCursor(int x, int y, byte direction, byte type, boolean visible, @Nullable net.kyori.adventure.text.Component caption) { ++ public @NotNull MapCursor addCursor(int x, int y, byte direction, byte type, boolean visible, net.kyori.adventure.text.@Nullable Component caption) { + return addCursor(new MapCursor((byte) x, (byte) y, direction, type, visible, caption)); + } + // Paper end @@ -4395,14 +4445,15 @@ 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 -+ */ -+ @NotNull net.kyori.adventure.text.Component displayName() throws IllegalStateException; + /** + * 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. + * @@ -4412,16 +4463,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @throws IllegalArgumentException if displayName is longer than 128 + * characters. + */ -+ void displayName(@Nullable net.kyori.adventure.text.Component displayName) throws IllegalStateException, IllegalArgumentException; ++ 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; @@ -4466,7 +4517,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + */ + @NotNull + @Deprecated -+ Objective registerNewObjective(@NotNull String name, @NotNull String criteria, @Nullable net.kyori.adventure.text.Component displayName) throws IllegalArgumentException; ++ Objective registerNewObjective(@NotNull String name, @NotNull String criteria, net.kyori.adventure.text.@Nullable Component displayName) throws IllegalArgumentException; + /** + * Registers an Objective on this Scoreboard + * @@ -4489,7 +4540,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + */ + @NotNull + @Deprecated -+ Objective registerNewObjective(@NotNull String name, @NotNull String criteria, @Nullable net.kyori.adventure.text.Component displayName, @NotNull RenderType renderType) throws IllegalArgumentException; ++ Objective registerNewObjective(@NotNull String name, @NotNull String criteria, net.kyori.adventure.text.@Nullable Component displayName, @NotNull RenderType renderType) throws IllegalArgumentException; + /** + * Registers an Objective on this Scoreboard + * @@ -4508,7 +4559,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * exists + */ + @NotNull -+ Objective registerNewObjective(@NotNull String name, @NotNull Criteria criteria, @Nullable net.kyori.adventure.text.Component displayName) throws IllegalArgumentException; ++ Objective registerNewObjective(@NotNull String name, @NotNull Criteria criteria, net.kyori.adventure.text.@Nullable Component displayName) throws IllegalArgumentException; + /** + * Registers an Objective on this Scoreboard + * @@ -4529,7 +4580,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * exists + */ + @NotNull -+ Objective registerNewObjective(@NotNull String name, @NotNull Criteria criteria, @Nullable net.kyori.adventure.text.Component displayName, @NotNull RenderType renderType) throws IllegalArgumentException; ++ Objective registerNewObjective(@NotNull String name, @NotNull Criteria criteria, net.kyori.adventure.text.@Nullable Component displayName, @NotNull RenderType renderType) throws IllegalArgumentException; + // Paper end /** @@ -4580,14 +4631,15 @@ 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 -+ */ -+ @NotNull net.kyori.adventure.text.Component displayName() throws IllegalStateException; + /** + * 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; + + /** + * Sets the name displayed to entries for this team @@ -4595,7 +4647,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @param displayName New display name + * @throws IllegalStateException if this team has been unregistered + */ -+ void displayName(@Nullable net.kyori.adventure.text.Component displayName) throws IllegalStateException, IllegalArgumentException; ++ void displayName(net.kyori.adventure.text.@Nullable Component displayName) throws IllegalStateException, IllegalArgumentException; + + /** + * Gets the prefix prepended to the display of entries on this team. @@ -4603,7 +4655,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @return Team prefix + * @throws IllegalStateException if this team has been unregistered + */ -+ @NotNull net.kyori.adventure.text.Component prefix() throws IllegalStateException; ++ net.kyori.adventure.text.@NotNull Component prefix() throws IllegalStateException; + + /** + * Sets the prefix prepended to the display of entries on this team. @@ -4613,7 +4665,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * characters + * @throws IllegalStateException if this team has been unregistered + */ -+ void prefix(@Nullable net.kyori.adventure.text.Component prefix) throws IllegalStateException, IllegalArgumentException; ++ void prefix(net.kyori.adventure.text.@Nullable Component prefix) throws IllegalStateException, IllegalArgumentException; + + /** + * Gets the suffix appended to the display of entries on this team. @@ -4621,7 +4673,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @return the team's current suffix + * @throws IllegalStateException if this team has been unregistered + */ -+ @NotNull net.kyori.adventure.text.Component suffix() throws IllegalStateException; ++ net.kyori.adventure.text.@NotNull Component suffix() throws IllegalStateException; + + /** + * Sets the suffix appended to the display of entries on this team. @@ -4631,7 +4683,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * characters + * @throws IllegalStateException if this team has been unregistered + */ -+ void suffix(@Nullable net.kyori.adventure.text.Component suffix) throws IllegalStateException, IllegalArgumentException; ++ void suffix(net.kyori.adventure.text.@Nullable Component suffix) throws IllegalStateException, IllegalArgumentException; + + /** + * Checks if the team has a color specified @@ -4652,7 +4704,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * @throws IllegalStateException if the team doesn't have a color + * @see #hasColor() + */ -+ @NotNull net.kyori.adventure.text.format.TextColor color() throws IllegalStateException; ++ net.kyori.adventure.text.format.@NotNull TextColor color() throws IllegalStateException; + + /** + * Sets the color of the team. @@ -4662,16 +4714,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + * + * @param color new color, null for no color + */ -+ void color(@Nullable net.kyori.adventure.text.format.NamedTextColor color); ++ 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; @@ -4787,29 +4839,3 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + assertTrue(set1.contains(key)); + } +} -diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/test/java/org/bukkit/AnnotationTest.java -+++ b/src/test/java/org/bukkit/AnnotationTest.java -@@ -0,0 +0,0 @@ import org.objectweb.asm.tree.ParameterNode; - public class AnnotationTest { - - private static final String[] ACCEPTED_ANNOTATIONS = { -+ // Paper start -+ "Lorg/checkerframework/checker/nullness/qual/Nullable;", -+ "Lorg/checkerframework/checker/nullness/qual/NonNull;", -+ "Lorg/checkerframework/checker/nullness/qual/PolyNull;", -+ "Lorg/checkerframework/checker/nullness/qual/MonotonicNonNull;", -+ // Paper end - "Lorg/jetbrains/annotations/Nullable;", - "Lorg/jetbrains/annotations/NotNull;", - "Lorg/jetbrains/annotations/Contract;", -@@ -0,0 +0,0 @@ public class AnnotationTest { - if (method.invisibleTypeAnnotations != null) { - for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.invisibleTypeAnnotations) { - final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef); -- if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_FORMAL_PARAMETER && ref.getTypeParameterIndex() == i && java.util.Arrays.binarySearch(ACCEPTED_ANNOTATIONS, invisibleTypeAnnotation.desc) >= 0) { -+ if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_FORMAL_PARAMETER && ref.getTypeParameterIndex() == i && java.util.Arrays.asList(ACCEPTED_ANNOTATIONS).contains(invisibleTypeAnnotation.desc)) { - continue dancing; - } - } diff --git a/patches/api/EntityRegainHealthEvent-isFastRegen-API.patch b/patches/api/EntityRegainHealthEvent-isFastRegen-API.patch index 626f262300..90bb66c279 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,8 +35,9 @@ 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 7798907f76..eb2a965cd6 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 070f843b12..d72f764b2b 100644 --- a/patches/api/Expand-world-key-API.patch +++ b/patches/api/Expand-world-key-API.patch @@ -110,10 +110,14 @@ 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)) { @@ -124,10 +128,9 @@ 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 + * @@ -139,7 +142,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; + } + @@ -183,8 +186,9 @@ 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 fd6fea0745..8556fa47eb 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,11 +63,12 @@ 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 f4d1e8431f..6d6b95a34f 100644 --- a/patches/api/Inventory-removeItemAnySlot.patch +++ b/patches/api/Inventory-removeItemAnySlot.patch @@ -16,25 +16,6 @@ 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. @@ -51,11 +32,28 @@ 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/More-Enchantment-API.patch b/patches/api/More-Enchantment-API.patch index d12cb75332..1c654591a7 100644 --- a/patches/api/More-Enchantment-API.patch +++ b/patches/api/More-Enchantment-API.patch @@ -53,7 +53,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public abstract class Enchantment implements Keyed, net.kyori.adventure.translat * @return the name of the enchantment with {@code level} applied */ - public abstract @NotNull net.kyori.adventure.text.Component displayName(int level); + public abstract net.kyori.adventure.text.@NotNull Component displayName(int level); + + /** + * Checks if this enchantment can be found in villager trades. diff --git a/patches/api/Paper-Plugins.patch b/patches/api/Paper-Plugins.patch index d4b3dba87f..71587d11eb 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 362859abbb..8606c8ae36 100644 --- a/patches/api/Test-changes.patch +++ b/patches/api/Test-changes.patch @@ -8,6 +8,7 @@ Subject: [PATCH] Test changes - Ignore package-private methods for nullability annotations - Add excludes for classes which don't pass +Co-authored-by: Riley Park Co-authored-by: Jake Potrebic diff --git a/build.gradle.kts b/build.gradle.kts @@ -146,6 +147,21 @@ diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bu index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/test/java/org/bukkit/AnnotationTest.java +++ b/src/test/java/org/bukkit/AnnotationTest.java +@@ -0,0 +0,0 @@ public class AnnotationTest { + "Lorg/jetbrains/annotations/Nullable;", + "Lorg/jetbrains/annotations/NotNull;", + "Lorg/jetbrains/annotations/Contract;", +- "Lorg/bukkit/UndefinedNullability;" ++ "Lorg/bukkit/UndefinedNullability;", ++ // Paper start ++ "Lorg/checkerframework/checker/nullness/qual/MonotonicNonNull;", ++ "Lorg/checkerframework/checker/nullness/qual/NonNull;", ++ "Lorg/checkerframework/checker/nullness/qual/Nullable;", ++ "Lorg/checkerframework/checker/nullness/qual/PolyNull;", ++ // Paper end + }; + + private static final String[] EXCLUDED_CLASSES = { @@ -0,0 +0,0 @@ public class AnnotationTest { "org/bukkit/util/io/Wrapper", "org/bukkit/plugin/java/PluginClassLoader", @@ -176,7 +192,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } else if (method.invisibleTypeAnnotations != null) { + dance: for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.invisibleTypeAnnotations) { + final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef); -+ if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_RETURN && java.util.Arrays.binarySearch(ACCEPTED_ANNOTATIONS, invisibleTypeAnnotation.desc) >= 0) { ++ if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_RETURN && java.util.Arrays.asList(ACCEPTED_ANNOTATIONS).contains(invisibleTypeAnnotation.desc)) { + warn = false; + break dance; // cha cha real smooth + } @@ -197,7 +213,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (method.invisibleTypeAnnotations != null) { + for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.invisibleTypeAnnotations) { + final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef); -+ if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_FORMAL_PARAMETER && ref.getTypeParameterIndex() == i && java.util.Arrays.binarySearch(ACCEPTED_ANNOTATIONS, invisibleTypeAnnotation.desc) >= 0) { ++ if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_FORMAL_PARAMETER && ref.getTypeParameterIndex() == i && java.util.Arrays.asList(ACCEPTED_ANNOTATIONS).contains(invisibleTypeAnnotation.desc)) { + continue dancing; + } + } @@ -272,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 6b1c3bc64a..3ea0a26aac 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,7 +3611,8 @@ 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; @@ -3634,7 +3635,16 @@ 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; @@ -3644,8 +3654,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - printStream.println("# Entities " + entities); - printStream.println("# LivingEntities " + livingEntities); -- } -- ++ handler = timing; + } + - /** - * Resets all timings. - */ @@ -3657,7 +3668,9 @@ 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. @@ -3673,8 +3686,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - } - } -+ Timing timing; - +- - /** - * Starts timing to track a section of code. - */ @@ -3685,19 +3697,9 @@ 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. - */ @@ -3716,9 +3718,7 @@ 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 5f617fe18c..896f0a7985 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 5c15202c7d..4f805e11af 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,8 +58,9 @@ 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 cbb6022325..75f9234a3f 100644 --- a/patches/server/Add-Plugin-Tickets-to-API-Chunk-Methods.patch +++ b/patches/server/Add-Plugin-Tickets-to-API-Chunk-Methods.patch @@ -60,16 +60,17 @@ 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 3497a939e3..6e0d522f02 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,18 +35,19 @@ 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 e521347307..d2bc35cd11 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 2650b5ff1d..7aac2ff3a3 100644 --- a/patches/server/Add-more-advancement-API.patch +++ b/patches/server/Add-more-advancement-API.patch @@ -137,9 +137,12 @@ 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 @@ -161,11 +164,10 @@ 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; @@ -173,7 +175,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 e32d01bff3..d843cdee26 100644 --- a/patches/server/Adventure.patch +++ b/patches/server/Adventure.patch @@ -2322,13 +2322,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - @Deprecated - public void disconnect(Component reason) { - this.disconnect(CraftChatMessage.fromComponent(reason)); -+ public void disconnect(String s) { +- } +- // CraftBukkit end +- + 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)); + } @@ -2809,13 +2810,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"); @@ -2892,12 +2893,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 4367155fda..5666d16b45 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 26076c8d0f..addcc42cca 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,10 +21,14 @@ 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]; @@ -33,16 +37,12 @@ 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 570bfe23b2..7ee5261208 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,11 +1397,12 @@ 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()); @@ -1414,10 +1415,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 d88698d78a..b2eec8b74f 100644 --- a/patches/server/AsyncTabCompleteEvent.patch +++ b/patches/server/AsyncTabCompleteEvent.patch @@ -49,12 +49,6 @@ 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(); @@ -62,10 +56,14 @@ 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 e56d40017e..2f43f9b6a1 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 4482a894c8..01ee3a8a64 100644 --- a/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch +++ b/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch @@ -31,19 +31,18 @@ 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 2b0b6da9ca..cf39a011f3 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,12 +569,16 @@ 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; + } @@ -583,18 +587,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + long inactiveFor = MinecraftServer.currentTick - entity.activatedTick; + // Paper end - // quick checks. -- if ( entity.wasTouchingWater || entity.remainingFireTicks > 0 ) ++ // quick checks. + 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 ) ) { @@ -624,7 +626,8 @@ 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; @@ -652,8 +655,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return config.villagersWorkImmunityFor; + } + } - } -- if ( entity instanceof Villager && ( (Villager) entity ).canBreed() ) ++ } + if ( entity instanceof Llama && ( (Llama) entity ).inCaravan() ) { - return true; @@ -677,11 +679,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 f8faf46245..df175f257c 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 0c3033c257..b8bfcade0a 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 02c7fbd628..d6654c804d 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,8 +121,9 @@ 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 87217f196a..fc71f0fbf1 100644 --- a/patches/server/Fix-World-isChunkGenerated-calls.patch +++ b/patches/server/Fix-World-isChunkGenerated-calls.patch @@ -197,7 +197,6 @@ 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) { @@ -211,10 +210,7 @@ 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); @@ -236,6 +232,11 @@ 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 58915421d8..2f3fbcaddd 100644 --- a/patches/server/Fix-for-large-move-vectors-crashing-server.patch +++ b/patches/server/Fix-for-large-move-vectors-crashing-server.patch @@ -27,14 +27,13 @@ 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 645a2542e3..e0abbd47a5 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 bd90305098..50fd471e5c 100644 --- a/patches/server/Further-improve-server-tick-loop.patch +++ b/patches/server/Further-improve-server-tick-loop.patch @@ -185,7 +185,10 @@ 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)"); @@ -193,10 +196,7 @@ 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 f20e245e8f..80e9871245 100644 --- a/patches/server/Handle-Item-Meta-Inconsistencies.patch +++ b/patches/server/Handle-Item-Meta-Inconsistencies.patch @@ -130,7 +130,14 @@ 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(); @@ -162,14 +169,7 @@ 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 eee71069e2..04571c41c5 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,29 +1277,26 @@ 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(); @@ -1326,15 +1323,16 @@ 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); -+ -+ if (io.papermc.paper.util.CollisionUtil.isCollidingWithBorderEdge(world.getWorldBorder(), collisionBox)) { -+ io.papermc.paper.util.CollisionUtil.addBoxesToIfIntersects(world.getWorldBorder().getCollisionShape(), collisionBox, potentialCollisions); - } -- } - return vec3d1; ++ if (io.papermc.paper.util.CollisionUtil.isCollidingWithBorderEdge(world.getWorldBorder(), collisionBox)) { ++ io.papermc.paper.util.CollisionUtil.addBoxesToIfIntersects(world.getWorldBorder().getCollisionShape(), collisionBox, potentialCollisions); ++ } ++ + 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 0e3c7e2c5f..d09e54ae62 100644 --- a/patches/server/Implement-regenerateChunk.patch +++ b/patches/server/Implement-regenerateChunk.patch @@ -25,10 +25,6 @@ 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(); @@ -37,8 +33,10 @@ 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 546f3fd86d..c93a2d9844 100644 --- a/patches/server/Improve-death-events.patch +++ b/patches/server/Improve-death-events.patch @@ -119,8 +119,13 @@ 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()) { @@ -148,15 +153,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (entity != null) { + entity.wasKilled((ServerLevel) this.level, this); + } - this.gameEvent(GameEvent.ENTITY_DIE); -- this.dropAllDeathLoot(damageSource); -- this.createWitherRose(entityliving); ++ this.gameEvent(GameEvent.ENTITY_DIE); + } 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 f8e0d113f0..754dc3ce10 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,12 +417,13 @@ 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 53b32292e3..b8bfb9dd99 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 cb558468a8..917c224c0c 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 7f10504b90..8d5ba6cdb8 100644 --- a/patches/server/Optimise-BlockSoil-nearby-water-lookup.patch +++ b/patches/server/Optimise-BlockSoil-nearby-water-lookup.patch @@ -15,17 +15,16 @@ 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 61aa1b9543..f6c8c98675 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.popPush("broadcast"); ++ gameprofilerfiller.pop(); ++ // Paper start - use set of chunks requiring updates, rather than iterating every single one loaded + 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(); -+ // Paper start - use set of chunks requiring updates, rather than iterating every single one loaded -+ gameprofilerfiller.popPush("broadcast"); +- gameprofilerfiller.pop(); + 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 2702d153e0..7c8e6d63f2 100644 --- a/patches/server/Optimise-random-block-ticking.patch +++ b/patches/server/Optimise-random-block-ticking.patch @@ -173,7 +173,14 @@ 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]; - @@ -185,40 +192,35 @@ 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) @@ -377,7 +379,14 @@ 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; @@ -392,38 +401,31 @@ 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 fc27b5d667..cd37697cd3 100644 --- a/patches/server/Optimize-GoalSelector-Goal.Flag-Set-operations.patch +++ b/patches/server/Optimize-GoalSelector-Goal.Flag-Set-operations.patch @@ -74,26 +74,27 @@ 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 091074c67f..35eed1c2eb 100644 --- a/patches/server/Optimize-Hoppers.patch +++ b/patches/server/Optimize-Hoppers.patch @@ -281,10 +281,18 @@ 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) { @@ -294,26 +302,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } else { - destinationInventory = new CraftInventory(iinventory); - } -- -- InventoryMoveItemEvent event = new InventoryMoveItemEvent(iinventory.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true); -- world.getCraftServer().getPluginManager().callEvent(event); -- if (event.isCancelled()) { -- hopper.setItem(i, itemstack); -- hopper.setCooldown(world.spigotConfig.hopperTransfer); // Spigot -- return false; -- } -- 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) { @@ -323,7 +311,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // } else { + // destinationInventory = new CraftInventory(iinventory); + // } -+ + +- InventoryMoveItemEvent event = new InventoryMoveItemEvent(iinventory.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true); +- world.getCraftServer().getPluginManager().callEvent(event); +- if (event.isCancelled()) { +- hopper.setItem(i, itemstack); +- hopper.setCooldown(world.spigotConfig.hopperTransfer); // Spigot +- return false; +- } +- int origCount = event.getItem().getAmount(); // Spigot +- ItemStack itemstack1 = HopperBlockEntity.addItem(iinventory, iinventory1, CraftItemStack.asNMSCopy(event.getItem()), enumdirection); + // InventoryMoveItemEvent event = new InventoryMoveItemEvent(iinventory.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true); + // world.getCraftServer().getPluginManager().callEvent(event); + // if (event.isCancelled()) { @@ -411,7 +408,14 @@ 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) { @@ -421,38 +425,6 @@ 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) { @@ -462,28 +434,46 @@ 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 9c6d5cc03f..9740ab4edf 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,21 +107,22 @@ 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); -- } else { -- this.queue.add(new Connection.PacketHolder(packet, callbacks)); ++ this.sendPacket(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(); @@ -184,6 +185,10 @@ 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()) { @@ -193,16 +198,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return processQueue(); + } else if (isPending) { + // Should only happen during login/status stages -+ synchronized (this.queue) { + synchronized (this.queue) { +- Connection.PacketHolder networkmanager_queuedpacket; +- +- while ((networkmanager_queuedpacket = (Connection.PacketHolder) this.queue.poll()) != null) { +- this.sendPacket(networkmanager_queuedpacket.packet, networkmanager_queuedpacket.listener); +- } +- + return this.processQueue(); -+ } -+ } + } + } + return false; + } + private boolean processQueue() { - try { // Paper - add pending task queue -- if (this.channel != null && this.channel.isOpen()) { -- Queue queue = this.queue; ++ try { // Paper - add pending task 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 @@ -214,17 +223,13 @@ 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; @@ -232,10 +237,9 @@ 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 40ab4c05ab..ae100f8b12 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; -- -- 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); + } +- 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(); +- - 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,18 +158,11 @@ 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 @@ -179,14 +172,24 @@ 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); @@ -201,7 +204,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 cf327b7ac5..f459c0ed43 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/Paper-command.patch b/patches/server/Paper-command.patch index 0cafa9e63b..ef99d3a52b 100644 --- a/patches/server/Paper-command.patch +++ b/patches/server/Paper-command.patch @@ -1,8 +1,9 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zach Brown <1254957+zachbr@users.noreply.github.com> +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Mon, 29 Feb 2016 21:02:09 -0600 Subject: [PATCH] Paper command +Co-authored-by: Zach Brown <1254957+zachbr@users.noreply.github.com> diff --git a/src/main/java/io/papermc/paper/command/CommandUtil.java b/src/main/java/io/papermc/paper/command/CommandUtil.java new file mode 100644 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 bc6257ed45..7b047766ac 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 { -- this.nextTick += 12000 + randomsource.nextInt(1200); -- long i = world.getDayTime() / 24000L; ++ } else { + this.nextTick--; + patrolSpawnDelay = this.nextTick; + } + + if (patrolSpawnDelay > 0) { -+ return 0; -+ } else { + return 0; + } else { +- this.nextTick += 12000 + randomsource.nextInt(1200); +- long i = world.getDayTime() / 24000L; + 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 1877634781..6e3de69ebc 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 b99f6cde4d..25c5cf4948 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); + } + } -+ -+ // 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)); ++ // Set the game profile here, we should have unregistered the entity via iterating all player entities above. ++ self.gameProfile = gameProfile; ++ + // 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 9fb4af40fa..0c7904e1e2 100644 --- a/patches/server/Prevent-chunk-loading-from-Fluid-Flowing.patch +++ b/patches/server/Prevent-chunk-loading-from-Fluid-Flowing.patch @@ -58,15 +58,14 @@ 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 545abd0049..7533f2eb02 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,24 +98,10 @@ 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 ) - { @@ -130,6 +116,73 @@ 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) + { @@ -147,23 +200,9 @@ 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 + { @@ -174,9 +213,7 @@ 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 @@ -228,63 +265,32 @@ 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 c502969c88..757e14f19d 100644 --- a/patches/server/Rewrite-chunk-system.patch +++ b/patches/server/Rewrite-chunk-system.patch @@ -13176,16 +13176,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - entityplayer.connection.send(packet); - }); - } -- -- public CompletableFuture> getOrScheduleFuture(ChunkStatus targetStatus, ChunkMap chunkStorage) { -- int i = targetStatus.getIndex(); -- CompletableFuture> completablefuture = (CompletableFuture) this.futures.get(i); -- -- if (completablefuture != null) { -- Either either = (Either) completablefuture.getNow(ChunkHolder.NOT_DONE_YET); -- -- 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. @@ -13195,6 +13185,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return; + } +- public CompletableFuture> getOrScheduleFuture(ChunkStatus targetStatus, ChunkMap chunkStorage) { +- int i = targetStatus.getIndex(); +- CompletableFuture> completablefuture = (CompletableFuture) this.futures.get(i); +- +- if (completablefuture != null) { +- Either either = (Either) completablefuture.getNow(ChunkHolder.NOT_DONE_YET); +- +- if (either == null) { +- String s = "value in future for status: " + targetStatus + " was incorrectly set to null at chunk: " + this.pos; +- - 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,8 +13258,9 @@ 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; - } @@ -13285,9 +13286,8 @@ 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,15 +13823,16 @@ 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 @@ -14491,21 +14492,25 @@ 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(); -+ } + } -- while (iterator.hasNext()) { -- ServerPlayer entityplayer = (ServerPlayer) iterator.next(); -- SectionPos sectionposition = entityplayer.getLastSectionPos(); +- return builder.build(); + 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)) { @@ -14513,11 +14518,10 @@ 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 } @@ -14883,7 +14887,8 @@ 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(); - @@ -14904,8 +14909,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } catch (Throwable throwable1) { - throwable.addSuppressed(throwable1); - } -+ // Paper - rewrite chunk system - +- - throw throwable; - } - @@ -15125,29 +15129,23 @@ 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 @@ -15157,11 +15155,10 @@ 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, @@ -15172,12 +15169,17 @@ 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()); @@ -16532,7 +16534,21 @@ 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; @@ -16550,21 +16566,7 @@ 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; - }); @@ -16972,9 +16974,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 @@ -16996,7 +16998,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (blockEntityNbt != null) { + blockEntitiesSerialized.add(blockEntityNbt); + } - } ++ } + + return new AsyncSaveData( + tickLists.get(BLOCK_TICKS_TAG), @@ -17004,11 +17006,12 @@ 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 @@ -17148,11 +17151,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) { @@ -17239,17 +17242,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]); @@ -17291,6 +17294,10 @@ 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) { @@ -17304,8 +17311,9 @@ 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); + } @@ -17331,14 +17339,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end - rewrite chunk system + - @Override - public void flush(boolean sync) { -- this.worker.synchronize(sync).join(); -- this.entityDeserializerQueue.runAll(); ++ @Override ++ public void flush(boolean sync) { + 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 68e8f830e9..da37862087 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 a0b14cfb94..c8353e290b 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 7302583027..e8b618a3b1 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,13 +271,12 @@ 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 c39710f4e1..3ac2871e0d 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,17 +16,18 @@ 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; - } -+ // Paper start - stop large pitch and yaw changes from crashing the server -+ this.yRotO += Math.round((this.getYRot() - this.yRotO) / 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; - } -+ this.yBodyRotO += Math.round((this.yBodyRot - this.yBodyRotO) / 360.0F) * 360.0F; ++ this.xRotO += Math.round((this.getXRot() - this.xRotO) / 360.0F) * 360.0F; - while (this.yBodyRot - this.yBodyRotO >= 180.0F) { - this.yBodyRotO += 360.0F; @@ -35,8 +36,7 @@ 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 3f2fd691de..fe9cd30794 100644 --- a/patches/server/Use-TerminalConsoleAppender-for-console-improvements.patch +++ b/patches/server/Use-TerminalConsoleAppender-for-console-improvements.patch @@ -397,8 +397,9 @@ 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()) { @@ -406,10 +407,9 @@ 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 7f2d18df5a..d149a50f84 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;