From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Riley Park <rileysebastianpark@gmail.com> Date: Fri, 29 Jan 2021 17:21:55 +0100 Subject: [PATCH] Adventure Co-authored-by: zml <zml@stellardrift.ca> Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com> Co-authored-by: Yannick Lamprecht <yannicklamprecht@live.de> diff --git a/build.gradle.kts b/build.gradle.kts index 1a80f7c7e7f4ae9857b732897dc2ee7cfc187626..f57827e724bff2bf586b468cc4e5ba6a1901bd57 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,6 +11,18 @@ java { val annotationsVersion = "24.1.0" val bungeeCordChatVersion = "1.20-R0.2" +val adventureVersion = "4.17.0" +val apiAndDocs: Configuration by configurations.creating { + attributes { + attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.DOCUMENTATION)) + attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL)) + attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType.SOURCES)) + attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME)) + } +} +configurations.api { + extendsFrom(apiAndDocs) +} // Paper start - configure mockito agent that is needed in newer java versions val mockitoAgent = configurations.register("mockitoAgent") @@ -28,7 +40,11 @@ dependencies { // api dependencies are listed transitively to API consumers api("com.google.guava:guava:32.1.2-jre") api("com.google.code.gson:gson:2.10.1") - api("net.md-5:bungeecord-chat:$bungeeCordChatVersion") + // Paper start - adventure + api("net.md-5:bungeecord-chat:$bungeeCordChatVersion-deprecated+build.18") { + exclude("com.google.guava", "guava") + } + // Paper - adventure api("org.yaml:snakeyaml:2.2") api("org.joml:joml:1.10.5") // Paper start @@ -36,6 +52,13 @@ dependencies { isTransitive = false // includes junit } api("it.unimi.dsi:fastutil:8.5.6") + apiAndDocs(platform("net.kyori:adventure-bom:$adventureVersion")) + apiAndDocs("net.kyori:adventure-api") + apiAndDocs("net.kyori:adventure-text-minimessage") + apiAndDocs("net.kyori:adventure-text-serializer-gson") + apiAndDocs("net.kyori:adventure-text-serializer-legacy") + apiAndDocs("net.kyori:adventure-text-serializer-plain") + apiAndDocs("net.kyori:adventure-text-logger-slf4j") // Paper end compileOnly("org.apache.maven:maven-resolver-provider:3.9.6") @@ -113,15 +136,32 @@ tasks.withType<Javadoc> { "https://guava.dev/releases/32.1.2-jre/api/docs/", "https://javadoc.io/doc/org.yaml/snakeyaml/2.2/", "https://javadoc.io/doc/org.jetbrains/annotations/$annotationsVersion/", // Paper - we don't want Java 5 annotations - "https://javadoc.io/doc/net.md-5/bungeecord-chat/$bungeeCordChatVersion/", + // "https://javadoc.io/doc/net.md-5/bungeecord-chat/$bungeeCordChatVersion/", // Paper - don't link to bungee chat // Paper start - add missing javadoc links "https://javadoc.io/doc/org.joml/joml/1.10.5/index.html", "https://www.javadoc.io/doc/com.google.code.gson/gson/2.10.1", "https://jspecify.dev/docs/api/", // Paper end + // Paper start + "https://jd.advntr.dev/api/$adventureVersion/", + "https://jd.advntr.dev/key/$adventureVersion/", + "https://jd.advntr.dev/text-minimessage/$adventureVersion/", + "https://jd.advntr.dev/text-serializer-gson/$adventureVersion/", + "https://jd.advntr.dev/text-serializer-legacy/$adventureVersion/", + "https://jd.advntr.dev/text-serializer-plain/$adventureVersion/", + "https://jd.advntr.dev/text-logger-slf4j/$adventureVersion/", + // Paper end ) options.tags("apiNote:a:API Note:") + inputs.files(apiAndDocs).ignoreEmptyDirectories().withPropertyName(apiAndDocs.name + "-configuration") + doFirst { + options.addStringOption( + "sourcepath", + apiAndDocs.resolvedConfiguration.files.joinToString(separator = File.pathSeparator, transform = File::getPath) + ) + } + // workaround for https://github.com/gradle/gradle/issues/4046 inputs.dir("src/main/javadoc").withPropertyName("javadoc-sourceset") doLast { diff --git a/src/main/java/io/papermc/paper/chat/ChatRenderer.java b/src/main/java/io/papermc/paper/chat/ChatRenderer.java new file mode 100644 index 0000000000000000000000000000000000000000..1288cdeafe587e9e78e7c5087742ea054ba8423d --- /dev/null +++ b/src/main/java/io/papermc/paper/chat/ChatRenderer.java @@ -0,0 +1,70 @@ +package io.papermc.paper.chat; + +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * A chat renderer is responsible for rendering chat messages sent by {@link Player}s to the server. + */ +@NullMarked +@FunctionalInterface +public interface ChatRenderer { + + /** + * Renders a chat message. This will be called once for each receiving {@link Audience}. + * + * @param source the message source + * @param sourceDisplayName the display name of the source player + * @param message the chat message + * @param viewer the receiving {@link Audience} + * @return a rendered chat message + */ + @ApiStatus.OverrideOnly + Component render(Player source, Component sourceDisplayName, Component message, Audience viewer); + + /** + * Create a new instance of the default {@link ChatRenderer}. + * + * @return a new {@link ChatRenderer} + */ + static ChatRenderer defaultRenderer() { + return new ViewerUnawareImpl.Default((source, sourceDisplayName, message) -> Component.translatable("chat.type.text", sourceDisplayName, message)); + } + + @ApiStatus.Internal + sealed interface Default extends ChatRenderer, ViewerUnaware permits ViewerUnawareImpl.Default { + } + + /** + * Creates a new viewer-unaware {@link ChatRenderer}, which will render the chat message a single time, + * displaying the same rendered message to every viewing {@link Audience}. + * + * @param renderer the viewer unaware renderer + * @return a new {@link ChatRenderer} + */ + static ChatRenderer viewerUnaware(final ViewerUnaware renderer) { + return new ViewerUnawareImpl(renderer); + } + + /** + * Similar to {@link ChatRenderer}, but without knowledge of the message viewer. + * + * @see ChatRenderer#viewerUnaware(ViewerUnaware) + */ + interface ViewerUnaware { + + /** + * Renders a chat message. + * + * @param source the message source + * @param sourceDisplayName the display name of the source player + * @param message the chat message + * @return a rendered chat message + */ + @ApiStatus.OverrideOnly + Component render(Player source, Component sourceDisplayName, Component message); + } +} diff --git a/src/main/java/io/papermc/paper/chat/ViewerUnawareImpl.java b/src/main/java/io/papermc/paper/chat/ViewerUnawareImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..e1ef23b4bdf60a299d6d37099cef777b3de13ac7 --- /dev/null +++ b/src/main/java/io/papermc/paper/chat/ViewerUnawareImpl.java @@ -0,0 +1,38 @@ +package io.papermc.paper.chat; + +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@ApiStatus.Internal +@NullMarked +sealed class ViewerUnawareImpl implements ChatRenderer, ChatRenderer.ViewerUnaware permits ViewerUnawareImpl.Default { + private final ViewerUnaware unaware; + private @Nullable Component message; + + ViewerUnawareImpl(final ViewerUnaware unaware) { + this.unaware = unaware; + } + + @Override + public Component render(final Player source, final Component sourceDisplayName, final Component message, final Audience viewer) { + return this.render(source, sourceDisplayName, message); + } + + @Override + public Component render(final Player source, final Component sourceDisplayName, final Component message) { + if (this.message == null) { + this.message = this.unaware.render(source, sourceDisplayName, message); + } + return this.message; + } + + static final class Default extends ViewerUnawareImpl implements ChatRenderer.Default { + Default(final ViewerUnaware unaware) { + super(unaware); + } + } +} diff --git a/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java b/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..9a95d203151d2c91b0eec494e3674f0facfaa305 --- /dev/null +++ b/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java @@ -0,0 +1,122 @@ +package io.papermc.paper.event.player; + +import io.papermc.paper.chat.ChatRenderer; +import java.util.Set; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.chat.SignedMessage; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.player.PlayerEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +import static java.util.Objects.requireNonNull; + +/** + * An abstract implementation of a chat event, handling shared logic. + */ +@ApiStatus.NonExtendable +@NullMarked +public abstract class AbstractChatEvent extends PlayerEvent implements Cancellable { + + private final Set<Audience> viewers; + private final Component originalMessage; + private final SignedMessage signedMessage; + private ChatRenderer renderer; + private Component message; + + private boolean cancelled; + + AbstractChatEvent(final boolean async, final Player player, final Set<Audience> viewers, final ChatRenderer renderer, final Component message, final Component originalMessage, final SignedMessage signedMessage) { + super(player, async); + this.viewers = viewers; + this.renderer = renderer; + this.message = message; + this.originalMessage = originalMessage; + this.signedMessage = signedMessage; + } + + /** + * Gets a set of {@link Audience audiences} that this chat message will be displayed to. + * + * <p>The set returned may auto-populate on access. Any listener accessing the returned set should be aware that + * it may reduce performance for a lazy set implementation.</p> + * + * @return a mutable set of {@link Audience audiences} who will receive the chat message + */ + public final Set<Audience> viewers() { + return this.viewers; + } + + /** + * Sets the chat renderer. + * + * @param renderer the chat renderer + * @throws NullPointerException if {@code renderer} is {@code null} + */ + public final void renderer(final ChatRenderer renderer) { + this.renderer = requireNonNull(renderer, "renderer"); + } + + /** + * Gets the chat renderer. + * + * @return the chat renderer + */ + public final ChatRenderer renderer() { + return this.renderer; + } + + /** + * Gets the user-supplied message. + * The return value will reflect changes made using {@link #message(Component)}. + * + * @return the user-supplied message + */ + public final Component message() { + return this.message; + } + + /** + * Sets the user-supplied message. + * + * @param message the user-supplied message + * @throws NullPointerException if {@code message} is {@code null} + */ + public final void message(final Component message) { + this.message = requireNonNull(message, "message"); + } + + /** + * Gets the original and unmodified user-supplied message. + * The return value will <b>not</b> reflect changes made using + * {@link #message(Component)}. + * + * @return the original user-supplied message + */ + public final Component originalMessage() { + return this.originalMessage; + } + + /** + * Gets the signed message. + * Changes made in this event will <b>not</b> update + * the signed message. + * + * @return the signed message + */ + public final SignedMessage signedMessage() { + return this.signedMessage; + } + + @Override + public final boolean isCancelled() { + return this.cancelled; + } + + @Override + public final void setCancelled(final boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/src/main/java/io/papermc/paper/event/player/AsyncChatCommandDecorateEvent.java b/src/main/java/io/papermc/paper/event/player/AsyncChatCommandDecorateEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..ddd4c90f83b5cb8f069ff53760abb3c4adfd1168 --- /dev/null +++ b/src/main/java/io/papermc/paper/event/player/AsyncChatCommandDecorateEvent.java @@ -0,0 +1,29 @@ +package io.papermc.paper.event.player; + +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@ApiStatus.Experimental +@NullMarked +public class AsyncChatCommandDecorateEvent extends AsyncChatDecorateEvent { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + @ApiStatus.Internal + public AsyncChatCommandDecorateEvent(final @Nullable Player player, final Component originalMessage) { + super(player, originalMessage); + } + + @Override + public HandlerList getHandlers() { + return HANDLER_LIST; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } +} diff --git a/src/main/java/io/papermc/paper/event/player/AsyncChatDecorateEvent.java b/src/main/java/io/papermc/paper/event/player/AsyncChatDecorateEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..9e5ea0cd006bd9744b84923620841f07fa40c2cb --- /dev/null +++ b/src/main/java/io/papermc/paper/event/player/AsyncChatDecorateEvent.java @@ -0,0 +1,105 @@ +package io.papermc.paper.event.player; + +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.server.ServerEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +/** + * This event is fired when the server decorates a component for chat purposes. This is called + * before {@link AsyncChatEvent} and the other chat events. It is recommended that you modify the + * message here, and use the chat events for modifying receivers and later the chat type. If you + * want to keep the message as "signed" for the clients who get it, be sure to include the entire + * original message somewhere in the final message. + * <br> + * See {@link AsyncChatCommandDecorateEvent} for the decoration of messages sent via commands + */ +@ApiStatus.Experimental +@NullMarked +public class AsyncChatDecorateEvent extends ServerEvent implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final @Nullable Player player; + private final Component originalMessage; + private Component result; + + private boolean cancelled; + + @ApiStatus.Internal + public AsyncChatDecorateEvent(final @Nullable Player player, final Component originalMessage) { + super(true); + this.player = player; + this.originalMessage = originalMessage; + this.result = originalMessage; + } + + /** + * Gets the player (if available) associated with this event. + * <p> + * Certain commands request decorations without a player context + * which is why this is possibly null. + * + * @return the player or {@code null} + */ + public @Nullable Player player() { + return this.player; + } + + /** + * Gets the original decoration input + * + * @return the input + */ + public Component originalMessage() { + return this.originalMessage; + } + + /** + * Gets the decoration result. This may already be different from + * {@link #originalMessage()} if some other listener to this event + * changed the result. + * + * @return the result + */ + public Component result() { + return this.result; + } + + /** + * Sets the resulting decorated component. + * + * @param result the result + */ + public void result(final Component result) { + this.result = result; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + /** + * A cancelled decorating event means that no changes to the result component + * will have any effect. The decorated component will be equal to the original + * component. + */ + @Override + public void setCancelled(final boolean cancel) { + this.cancelled = cancel; + } + + @Override + public HandlerList getHandlers() { + return HANDLER_LIST; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } +} diff --git a/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java b/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..50c3e117dec63811823b4e6395bf4f090692ee8c --- /dev/null +++ b/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java @@ -0,0 +1,44 @@ +package io.papermc.paper.event.player; + +import io.papermc.paper.chat.ChatRenderer; +import java.util.Set; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.chat.SignedMessage; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * An event fired when a {@link Player} sends a chat message to the server. + * <p> + * This event will sometimes fire synchronously, depending on how it was + * triggered. + * <p> + * If a player is the direct cause of this event by an incoming packet, this + * event will be asynchronous. If a plugin triggers this event by compelling a + * player to chat, this event will be synchronous. + * <p> + * Care should be taken to check {@link #isAsynchronous()} and treat the event + * appropriately. + */ +@NullMarked +public final class AsyncChatEvent extends AbstractChatEvent { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + @ApiStatus.Internal + public AsyncChatEvent(final boolean async, final Player player, final Set<Audience> viewers, final ChatRenderer renderer, final Component message, final Component originalMessage, final SignedMessage signedMessage) { + super(async, player, viewers, renderer, message, originalMessage, signedMessage); + } + + @Override + public HandlerList getHandlers() { + return HANDLER_LIST; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } +} diff --git a/src/main/java/io/papermc/paper/event/player/ChatEvent.java b/src/main/java/io/papermc/paper/event/player/ChatEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..42a82ce2316a4aad2883d24c7e2ff95d95f5881a --- /dev/null +++ b/src/main/java/io/papermc/paper/event/player/ChatEvent.java @@ -0,0 +1,40 @@ +package io.papermc.paper.event.player; + +import io.papermc.paper.chat.ChatRenderer; +import java.util.Set; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.chat.SignedMessage; +import net.kyori.adventure.text.Component; +import org.bukkit.Warning; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * An event fired when a {@link Player} sends a chat message to the server. + * + * @deprecated Listening to this event forces chat to wait for the main thread, delaying chat messages. + * It is recommended to use {@link AsyncChatEvent} instead, wherever possible. + */ +@Deprecated +@Warning(reason = "Listening to this event forces chat to wait for the main thread, delaying chat messages.") +@NullMarked +public final class ChatEvent extends AbstractChatEvent { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + @ApiStatus.Internal + public ChatEvent(final Player player, final Set<Audience> viewers, final ChatRenderer renderer, final Component message, final Component originalMessage, final SignedMessage signedMessage) { + super(false, player, viewers, renderer, message, originalMessage, signedMessage); + } + + @Override + public HandlerList getHandlers() { + return HANDLER_LIST; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } +} diff --git a/src/main/java/io/papermc/paper/text/PaperComponents.java b/src/main/java/io/papermc/paper/text/PaperComponents.java new file mode 100644 index 0000000000000000000000000000000000000000..934d1d3ca490a8e25c438bc8c57eb6bde50e0147 --- /dev/null +++ b/src/main/java/io/papermc/paper/text/PaperComponents.java @@ -0,0 +1,180 @@ +package io.papermc.paper.text; + +import java.io.IOException; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.flattener.ComponentFlattener; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Entity; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +/** + * Paper API-specific methods for working with {@link Component}s and related. + */ +@NullMarked +public final class PaperComponents { + + private PaperComponents() { + throw new RuntimeException("PaperComponents is not to be instantiated!"); + } + + /** + * Resolves a component with a specific command sender and subject. + * <p> + * Note that in Vanilla, elevated permissions are usually required to use + * '@' selectors in various component types, but this method should not + * check such permissions from the sender. + * <p> + * A {@link CommandSender} argument is required to resolve: + * <ul> + * <li>{@link net.kyori.adventure.text.NBTComponent}</li> + * <li>{@link net.kyori.adventure.text.ScoreComponent}</li> + * <li>{@link net.kyori.adventure.text.SelectorComponent}</li> + * </ul> + * A {@link Entity} argument is optional to help resolve: + * <ul> + * <li>{@link net.kyori.adventure.text.ScoreComponent}</li> + * </ul> + * {@link net.kyori.adventure.text.TranslatableComponent}s don't require any extra arguments. + * + * @param input the component to resolve + * @param context the command sender to resolve with + * @param scoreboardSubject the scoreboard subject to use (for use with {@link net.kyori.adventure.text.ScoreComponent}s) + * @return the resolved component + * @throws IOException if a syntax error tripped during resolving + */ + public static Component resolveWithContext(final Component input, final @Nullable CommandSender context, final @Nullable Entity scoreboardSubject) throws IOException { + return resolveWithContext(input, context, scoreboardSubject, true); + } + + /** + * Resolves a component with a specific command sender and subject. + * <p> + * Note that in Vanilla, elevated permissions are required to use + * '@' selectors in various component types. If the boolean {@code bypassPermissions} + * argument is {@code false}, the {@link CommandSender} argument will be used to query + * those permissions. + * <p> + * A {@link CommandSender} argument is required to resolve: + * <ul> + * <li>{@link net.kyori.adventure.text.NBTComponent}</li> + * <li>{@link net.kyori.adventure.text.ScoreComponent}</li> + * <li>{@link net.kyori.adventure.text.SelectorComponent}</li> + * </ul> + * A {@link Entity} argument is optional to help resolve: + * <ul> + * <li>{@link net.kyori.adventure.text.ScoreComponent}</li> + * </ul> + * {@link net.kyori.adventure.text.TranslatableComponent}s don't require any extra arguments. + * + * @param input the component to resolve + * @param context the command sender to resolve with + * @param scoreboardSubject the scoreboard subject to use (for use with {@link net.kyori.adventure.text.ScoreComponent}s) + * @param bypassPermissions true to bypass permissions checks for resolving components + * @return the resolved component + * @throws IOException if a syntax error tripped during resolving + */ + @SuppressWarnings("deprecation") // using unsafe as a bridge + public static Component resolveWithContext(final Component input, final @Nullable CommandSender context, final @Nullable Entity scoreboardSubject, final boolean bypassPermissions) throws IOException { + return Bukkit.getUnsafe().resolveWithContext(input, context, scoreboardSubject, bypassPermissions); + } + + /** + * Return a component flattener that can use game data to resolve extra information about components. + * + * @return a component flattener + */ + @SuppressWarnings("deprecation") // using unsafe as a bridge + public static ComponentFlattener flattener() { + return Bukkit.getUnsafe().componentFlattener(); + } + + /** + * Get a serializer for {@link Component}s that will convert components to + * a plain-text string. + * + * <p>Implementations may provide a serializer capable of processing any + * information that requires access to implementation details.</p> + * + * @return a serializer to plain text + * @deprecated will be removed in adventure 5.0.0, use {@link PlainTextComponentSerializer#plainText()} + */ + @Deprecated(forRemoval = true, since = "1.18.1") + public static PlainComponentSerializer plainSerializer() { + return Bukkit.getUnsafe().plainComponentSerializer(); + } + + /** + * Get a serializer for {@link Component}s that will convert components to + * a plain-text string. + * + * <p>Implementations may provide a serializer capable of processing any + * information that requires access to implementation details.</p> + * + * @return a serializer to plain text + * @deprecated use {@link PlainTextComponentSerializer#plainText()} + */ + @Deprecated(forRemoval = true, since = "1.18.2") + public static PlainTextComponentSerializer plainTextSerializer() { + return Bukkit.getUnsafe().plainTextSerializer(); + } + + /** + * Get a serializer for {@link Component}s that will convert to and from the + * standard JSON serialization format using Gson. + * + * <p>Implementations may provide a serializer capable of processing any + * information that requires implementation details, such as legacy + * (pre-1.16) hover events.</p> + * + * @return a json component serializer + * @deprecated use {@link GsonComponentSerializer#gson()} + */ + @Deprecated(forRemoval = true, since = "1.18.2") + public static GsonComponentSerializer gsonSerializer() { + return Bukkit.getUnsafe().gsonComponentSerializer(); + } + + /** + * Get a serializer for {@link Component}s that will convert to and from the + * standard JSON serialization format using Gson, downsampling any RGB colors + * to their nearest {@link NamedTextColor} counterpart. + * + * <p>Implementations may provide a serializer capable of processing any + * information that requires implementation details, such as legacy + * (pre-1.16) hover events.</p> + * + * @return a json component serializer + * @deprecated use {@link GsonComponentSerializer#colorDownsamplingGson()} + */ + @Deprecated(forRemoval = true, since = "1.18.2") + public static GsonComponentSerializer colorDownsamplingGsonSerializer() { + return Bukkit.getUnsafe().colorDownsamplingGsonComponentSerializer(); + } + + /** + * Get a serializer for {@link Component}s that will convert to and from the + * legacy component format used by Bukkit. This serializer uses the + * {@link LegacyComponentSerializer.Builder#useUnusualXRepeatedCharacterHexFormat()} + * option to match upstream behavior. + * + * <p>This legacy serializer uses the standard section symbol to mark + * formatting characters.</p> + * + * <p>Implementations may provide a serializer capable of processing any + * information that requires access to implementation details.</p> + * + * @return a section serializer + * @deprecated use {@link LegacyComponentSerializer#legacySection()} + */ + @Deprecated(forRemoval = true, since = "1.18.2") + public static LegacyComponentSerializer legacySectionSerializer() { + return Bukkit.getUnsafe().legacyComponentSerializer(); + } +} diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java index a485d590242b814e85aa2a1d54f0926017cfd2b5..fed32ada5a5ba6906c0f8e854ad71fd691fe5811 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java @@ -423,7 +423,9 @@ public final class Bukkit { * * @param message the message * @return the number of players + * @deprecated in favour of {@link Server#broadcast(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public static int broadcastMessage(@NotNull String message) { return server.broadcastMessage(message); } @@ -1227,6 +1229,19 @@ public final class Bukkit { server.shutdown(); } + // Paper start + /** + * Broadcast a message to all players. + * <p> + * This is the same as calling {@link #broadcast(net.kyori.adventure.text.Component, + * java.lang.String)} with the {@link Server#BROADCAST_CHANNEL_USERS} permission. + * + * @param message the message + * @return the number of players + */ + public static int broadcast(net.kyori.adventure.text.@NotNull Component message) { + return server.broadcast(message); + } /** * Broadcasts the specified message to every user with the given * permission name. @@ -1236,6 +1251,21 @@ public final class Bukkit { * permissibles} must have to receive the broadcast * @return number of message recipients */ + public static int broadcast(net.kyori.adventure.text.@NotNull Component message, @NotNull String permission) { + return server.broadcast(message, permission); + } + // Paper end + /** + * Broadcasts the specified message to every user with the given + * permission name. + * + * @param message message to broadcast + * @param permission the required permission {@link Permissible + * permissibles} must have to receive the broadcast + * @return number of message recipients + * @deprecated in favour of {@link #broadcast(net.kyori.adventure.text.Component, String)} + */ + @Deprecated // Paper public static int broadcast(@NotNull String message, @NotNull String permission) { return server.broadcast(message, permission); } @@ -1497,6 +1527,7 @@ public final class Bukkit { return server.createInventory(owner, type); } + // Paper start /** * Creates an empty inventory with the specified type and title. If the type * is {@link InventoryType#CHEST}, the new inventory has a size of 27; @@ -1522,6 +1553,38 @@ public final class Bukkit { * @see InventoryType#isCreatable() */ @NotNull + 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 + + /** + * Creates an empty inventory with the specified type and title. If the type + * is {@link InventoryType#CHEST}, the new inventory has a size of 27; + * otherwise the new inventory has the normal size for its type.<br> + * It should be noted that some inventory types do not support titles and + * may not render with said titles on the Minecraft client. + * <br> + * {@link InventoryType#WORKBENCH} will not process crafting recipes if + * created with this method. Use + * {@link Player#openWorkbench(Location, boolean)} instead. + * <br> + * {@link InventoryType#ENCHANTING} will not process {@link ItemStack}s + * for possible enchanting results. Use + * {@link Player#openEnchanting(Location, boolean)} instead. + * + * @param owner The holder of the inventory; can be null if there's no holder. + * @param type The type of inventory to create. + * @param title The title of the inventory, to be displayed when it is viewed. + * @return The new inventory. + * @throws IllegalArgumentException if the {@link InventoryType} cannot be + * viewed. + * @deprecated in favour of {@link #createInventory(InventoryHolder, InventoryType, net.kyori.adventure.text.Component)} + * + * @see InventoryType#isCreatable() + */ + @Deprecated // Paper + @NotNull public static Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, @NotNull String title) { return server.createInventory(owner, type, title); } @@ -1540,6 +1603,7 @@ public final class Bukkit { return server.createInventory(owner, size); } + // Paper start /** * Creates an empty inventory of type {@link InventoryType#CHEST} with the * specified size and title. @@ -1552,10 +1616,30 @@ public final class Bukkit { * @throws IllegalArgumentException if the size is not a multiple of 9 */ @NotNull + 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 + + /** + * Creates an empty inventory of type {@link InventoryType#CHEST} with the + * specified size and title. + * + * @param owner the holder of the inventory, or null to indicate no holder + * @param size a multiple of 9 as the size of inventory to create + * @param title the title of the inventory, displayed when inventory is + * viewed + * @return a new inventory + * @throws IllegalArgumentException if the size is not a multiple of 9 + * @deprecated in favour of {@link #createInventory(InventoryHolder, InventoryType, net.kyori.adventure.text.Component)} + */ + @Deprecated // Paper + @NotNull public static Inventory createInventory(@Nullable InventoryHolder owner, int size, @NotNull String title) throws IllegalArgumentException { return server.createInventory(owner, size, title); } + // Paper start /** * Creates an empty merchant. * @@ -1563,7 +1647,20 @@ public final class Bukkit { * when the merchant inventory is viewed * @return a new merchant */ + public static @NotNull Merchant createMerchant(net.kyori.adventure.text.@Nullable Component title) { + return server.createMerchant(title); + } + // Paper start + /** + * Creates an empty merchant. + * + * @param title the title of the corresponding merchant inventory, displayed + * when the merchant inventory is viewed + * @return a new merchant + * @deprecated in favour of {@link #createMerchant(net.kyori.adventure.text.Component)} + */ @NotNull + @Deprecated // Paper public static Merchant createMerchant(@Nullable String title) { return server.createMerchant(title); } @@ -1680,12 +1777,43 @@ public final class Bukkit { return server.isPrimaryThread(); } + // Paper start + /** + * Gets the message that is displayed on the server list. + * + * @return the server's MOTD + */ + @NotNull public static net.kyori.adventure.text.Component motd() { + return server.motd(); + } + + /** + * Set the message that is displayed on the server list. + * + * @param motd The message to be displayed + */ + public static void motd(final net.kyori.adventure.text.@NotNull Component motd) { + server.motd(motd); + } + + /** + * Gets the default message that is displayed when the server is stopped. + * + * @return the shutdown message + */ + public static net.kyori.adventure.text.@Nullable Component shutdownMessage() { + return server.shutdownMessage(); + } + // Paper end + /** * Gets the message that is displayed on the server list. * * @return the servers MOTD + * @deprecated in favour of {@link #motd()} */ @NotNull + @Deprecated // Paper public static String getMotd() { return server.getMotd(); } @@ -1694,7 +1822,9 @@ public final class Bukkit { * Set the message that is displayed on the server list. * * @param motd The message to be displayed + * @deprecated in favour of {@link #motd(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public static void setMotd(@NotNull String motd) { server.setMotd(motd); } @@ -1714,8 +1844,10 @@ public final class Bukkit { * 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() { return server.getShutdownMessage(); } diff --git a/src/main/java/org/bukkit/ChatColor.java b/src/main/java/org/bukkit/ChatColor.java index e3f185dc982d1c38195a4e01ddd485c13ffa58c0..918a045165cdcde264bc24082b7afebb407271de 100644 --- a/src/main/java/org/bukkit/ChatColor.java +++ b/src/main/java/org/bukkit/ChatColor.java @@ -10,7 +10,9 @@ import org.jetbrains.annotations.Nullable; /** * All supported color values for chat + * @deprecated ChatColor has been deprecated in favor of <a href="https://docs.advntr.dev/text.html">Adventure</a> API. See {@link net.kyori.adventure.text.format.NamedTextColor} for the adventure equivalent of pre-defined text colors */ +@Deprecated // Paper public enum ChatColor { /** * Represents black diff --git a/src/main/java/org/bukkit/JukeboxSong.java b/src/main/java/org/bukkit/JukeboxSong.java index 5872188c2f3c610ab220a30cf60f45c1eba1b372..c6feb13c735fabbd08676fa8828ce0b9fd54da32 100644 --- a/src/main/java/org/bukkit/JukeboxSong.java +++ b/src/main/java/org/bukkit/JukeboxSong.java @@ -33,4 +33,14 @@ public interface JukeboxSong extends Keyed, Translatable { private static JukeboxSong get(@NotNull String key) { return Registry.JUKEBOX_SONG.getOrThrow(NamespacedKey.minecraft(key)); } + + // Paper start - adventure + /** + * @deprecated this method assumes that jukebox song description will + * always be a translatable component which is not guaranteed. + */ + @Override + @Deprecated(forRemoval = true) + @org.jetbrains.annotations.NotNull String getTranslationKey(); + // Paper end - adventure } diff --git a/src/main/java/org/bukkit/Keyed.java b/src/main/java/org/bukkit/Keyed.java index 32c92621c2c15eec14c50965f5ecda00c46e6c80..e076d447da62445764a9776ee2554c077637d270 100644 --- a/src/main/java/org/bukkit/Keyed.java +++ b/src/main/java/org/bukkit/Keyed.java @@ -5,7 +5,7 @@ import org.jetbrains.annotations.NotNull; /** * Represents an object which has a {@link NamespacedKey} attached to it. */ -public interface Keyed { +public interface Keyed extends net.kyori.adventure.key.Keyed { // Paper -- extend Adventure Keyed /** * Return the namespaced identifier for this object. @@ -14,4 +14,16 @@ public interface Keyed { */ @NotNull NamespacedKey getKey(); + + // Paper start + /** + * Returns the unique identifier for this object. + * + * @return this object's key + */ + @Override + default net.kyori.adventure.key.@NotNull Key key() { + return this.getKey(); + } + // Paper end } diff --git a/src/main/java/org/bukkit/Nameable.java b/src/main/java/org/bukkit/Nameable.java index b79daa857fc686f00ac06b8851e0ab68d83ae949..45d996878ba8d314a47078589b6da59dc84d589e 100644 --- a/src/main/java/org/bukkit/Nameable.java +++ b/src/main/java/org/bukkit/Nameable.java @@ -7,6 +7,30 @@ import org.jetbrains.annotations.Nullable; */ public interface Nameable { + // Paper start + /** + * Gets the custom name. + * + * <p>This value has no effect on players, they will always use their real name.</p> + * + * @return the custom name + */ + net.kyori.adventure.text.@Nullable Component customName(); + + /** + * Sets the custom name. + * + * <p>This name will be used in death messages and can be sent to the client as a nameplate over the mob.</p> + * + * <p>Setting the name to {@code null} will clear it.</p> + * + * <p>This value has no effect on players, they will always use their real name.</p> + * + * @param customName the custom name to set + */ + void customName(final net.kyori.adventure.text.@Nullable Component customName); + // Paper end + /** * Gets the custom name on a mob or block. If there is no name this method * will return null. @@ -14,8 +38,10 @@ public interface Nameable { * This value has no effect on players, they will always use their real * name. * + * @deprecated in favour of {@link #customName()} * @return name of the mob/block or null */ + @Deprecated // Paper @Nullable public String getCustomName(); @@ -28,7 +54,9 @@ public interface Nameable { * This value has no effect on players, they will always use their real * name. * + * @deprecated in favour of {@link #customName(net.kyori.adventure.text.Component)} * @param name the name to set */ + @Deprecated // Paper public void setCustomName(@Nullable String name); } diff --git a/src/main/java/org/bukkit/NamespacedKey.java b/src/main/java/org/bukkit/NamespacedKey.java index 9562fcd522b2e2b24ec57fbf18ddeebba3e50abf..9b61129c3ef83d0bfceba54aba2effa12bc90678 100644 --- a/src/main/java/org/bukkit/NamespacedKey.java +++ b/src/main/java/org/bukkit/NamespacedKey.java @@ -19,7 +19,7 @@ import org.jetbrains.annotations.Nullable; * underscores, hyphens, and forward slashes. * */ -public final class NamespacedKey { +public final class NamespacedKey implements net.kyori.adventure.key.Key { // Paper - implement Key /** * The namespace representing all inbuilt keys. @@ -130,10 +130,11 @@ public final class NamespacedKey { @Override public int hashCode() { - int hash = 5; - hash = 47 * hash + this.namespace.hashCode(); - hash = 47 * hash + this.key.hashCode(); - return hash; + // Paper start + int result = this.namespace.hashCode(); + result = (31 * result) + this.key.hashCode(); + return result; + // Paper end } @Override @@ -141,11 +142,10 @@ public final class NamespacedKey { if (obj == null) { return false; } - if (getClass() != obj.getClass()) { - return false; - } - final NamespacedKey other = (NamespacedKey) obj; - return this.namespace.equals(other.namespace) && this.key.equals(other.key); + // Paper start + if (!(obj instanceof net.kyori.adventure.key.Key key)) return false; + return this.namespace.equals(key.namespace()) && this.key.equals(key.value()); + // Paper end } @Override @@ -248,4 +248,24 @@ public final class NamespacedKey { public static NamespacedKey fromString(@NotNull String key) { return fromString(key, null); } + + // Paper start + @NotNull + @Override + public String namespace() { + return this.getNamespace(); + } + + @NotNull + @Override + public String value() { + return this.getKey(); + } + + @NotNull + @Override + public String asString() { + return this.namespace + ':' + this.key; + } + // Paper end } diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java index 533f20092e7cf61250f5f88f6628a380c852a8e5..862f18d72deb1cb56de3f3f31275297a03d9ba0a 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java @@ -66,13 +66,13 @@ import org.jetbrains.annotations.Nullable; /** * Represents a server implementation. */ -public interface Server extends PluginMessageRecipient { +public interface Server extends PluginMessageRecipient, net.kyori.adventure.audience.ForwardingAudience { // Paper /** * Used for all administrative messages, such as an operator using a * command. * <p> - * For use in {@link #broadcast(java.lang.String, java.lang.String)}. + * For use in {@link #broadcast(net.kyori.adventure.text.Component, java.lang.String)}. */ public static final String BROADCAST_CHANNEL_ADMINISTRATIVE = "bukkit.broadcast.admin"; @@ -80,7 +80,7 @@ public interface Server extends PluginMessageRecipient { * Used for all announcement messages, such as informing users that a * player has joined. * <p> - * For use in {@link #broadcast(java.lang.String, java.lang.String)}. + * For use in {@link #broadcast(net.kyori.adventure.text.Component, java.lang.String)}. */ public static final String BROADCAST_CHANNEL_USERS = "bukkit.broadcast.user"; @@ -356,7 +356,9 @@ public interface Server extends PluginMessageRecipient { * * @param message the message * @return the number of players + * @deprecated use {@link #broadcast(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public int broadcastMessage(@NotNull String message); /** @@ -1053,8 +1055,33 @@ public interface Server extends PluginMessageRecipient { * @param permission the required permission {@link Permissible * permissibles} must have to receive the broadcast * @return number of message recipients + * @deprecated in favour of {@link #broadcast(net.kyori.adventure.text.Component, String)} */ + @Deprecated // Paper public int broadcast(@NotNull String message, @NotNull String permission); + // Paper start + /** + * Broadcast a message to all players. + * <p> + * This is the same as calling {@link #broadcast(net.kyori.adventure.text.Component, + * java.lang.String)} with the {@link #BROADCAST_CHANNEL_USERS} permission. + * + * @param message the message + * @return the number of players + */ + int broadcast(net.kyori.adventure.text.@NotNull Component message); + + /** + * Broadcasts the specified message to every user with the given + * permission name. + * + * @param message message to broadcast + * @param permission the required permission {@link Permissible + * permissibles} must have to receive the broadcast + * @return number of message recipients + */ + int broadcast(net.kyori.adventure.text.@NotNull Component message, @NotNull String permission); + // Paper end /** * Gets the player by the given name, regardless if they are offline or @@ -1271,6 +1298,35 @@ public interface Server extends PluginMessageRecipient { @NotNull Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type); + // Paper start + /** + * Creates an empty inventory with the specified type and title. If the type + * is {@link InventoryType#CHEST}, the new inventory has a size of 27; + * otherwise the new inventory has the normal size for its type.<br> + * It should be noted that some inventory types do not support titles and + * may not render with said titles on the Minecraft client. + * <br> + * {@link InventoryType#WORKBENCH} will not process crafting recipes if + * created with this method. Use + * {@link Player#openWorkbench(Location, boolean)} instead. + * <br> + * {@link InventoryType#ENCHANTING} will not process {@link ItemStack}s + * for possible enchanting results. Use + * {@link Player#openEnchanting(Location, boolean)} instead. + * + * @param owner The holder of the inventory; can be null if there's no holder. + * @param type The type of inventory to create. + * @param title The title of the inventory, to be displayed when it is viewed. + * @return The new inventory. + * @throws IllegalArgumentException if the {@link InventoryType} cannot be + * viewed. + * + * @see InventoryType#isCreatable() + */ + @NotNull + Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, net.kyori.adventure.text.@NotNull Component title); + // Paper end + /** * Creates an empty inventory with the specified type and title. If the type * is {@link InventoryType#CHEST}, the new inventory has a size of 27; @@ -1292,9 +1348,11 @@ public interface Server extends PluginMessageRecipient { * @return The new inventory. * @throws IllegalArgumentException if the {@link InventoryType} cannot be * viewed. + * @deprecated in favour of {@link #createInventory(InventoryHolder, InventoryType, net.kyori.adventure.text.Component)} * * @see InventoryType#isCreatable() */ + @Deprecated // Paper @NotNull Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, @NotNull String title); @@ -1310,6 +1368,22 @@ public interface Server extends PluginMessageRecipient { @NotNull Inventory createInventory(@Nullable InventoryHolder owner, int size) throws IllegalArgumentException; + // Paper start + /** + * Creates an empty inventory of type {@link InventoryType#CHEST} with the + * specified size and title. + * + * @param owner the holder of the inventory, or null to indicate no holder + * @param size a multiple of 9 as the size of inventory to create + * @param title the title of the inventory, displayed when inventory is + * viewed + * @return a new inventory + * @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. @@ -1320,18 +1394,32 @@ public interface Server extends PluginMessageRecipient { * viewed * @return a new inventory * @throws IllegalArgumentException if the size is not a multiple of 9 + * @deprecated in favour of {@link #createInventory(InventoryHolder, int, net.kyori.adventure.text.Component)} */ + @Deprecated // Paper @NotNull Inventory createInventory(@Nullable InventoryHolder owner, int size, @NotNull String title) throws IllegalArgumentException; + // Paper start + /** + * Creates an empty merchant. + * + * @param title the title of the corresponding merchant inventory, displayed + * when the merchant inventory is viewed + * @return a new merchant + */ + @NotNull Merchant createMerchant(net.kyori.adventure.text.@Nullable Component title); + // Paper start /** * Creates an empty merchant. * * @param title the title of the corresponding merchant inventory, displayed * when the merchant inventory is viewed * @return a new merchant + * @deprecated in favour of {@link #createMerchant(net.kyori.adventure.text.Component)} */ @NotNull + @Deprecated // Paper Merchant createMerchant(@Nullable String title); /** @@ -1427,19 +1515,46 @@ public interface Server extends PluginMessageRecipient { */ boolean isPrimaryThread(); + // Paper start + /** + * Gets the message that is displayed on the server list. + * + * @return the server's MOTD + */ + net.kyori.adventure.text.@NotNull Component motd(); + + /** + * Set the message that is displayed on the server list. + * + * @param motd The message to be displayed + */ + void motd(final net.kyori.adventure.text.@NotNull Component motd); + + /** + * Gets the default message that is displayed when the server is stopped. + * + * @return the shutdown message + */ + net.kyori.adventure.text.@Nullable Component shutdownMessage(); + // Paper end + /** * Gets the message that is displayed on the server list. * * @return the servers MOTD + * @deprecated in favour of {@link #motd()} */ @NotNull + @Deprecated // Paper String getMotd(); /** * Set the message that is displayed on the server list. * * @param motd The message to be displayed + * @deprecated in favour of {@link #motd(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper void setMotd(@NotNull String motd); /** @@ -1455,8 +1570,10 @@ public interface Server extends PluginMessageRecipient { * 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(); /** @@ -1865,7 +1982,9 @@ public interface Server extends PluginMessageRecipient { * Sends the component to the player * * @param component the components to send + * @deprecated use {@link #broadcast(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void broadcast(@NotNull net.md_5.bungee.api.chat.BaseComponent component) { throw new UnsupportedOperationException("Not supported yet."); } @@ -1874,7 +1993,9 @@ public interface Server extends PluginMessageRecipient { * Sends an array of components as a single message to the player * * @param components the components to send + * @deprecated use {@link #broadcast(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void broadcast(@NotNull net.md_5.bungee.api.chat.BaseComponent... components) { throw new UnsupportedOperationException("Not supported yet."); } diff --git a/src/main/java/org/bukkit/ServerLinks.java b/src/main/java/org/bukkit/ServerLinks.java index 18a53194483410c4d5ad35f901c90d44efaeef60..aff43d77f31d81b82e5fc5fea6272dda24506562 100644 --- a/src/main/java/org/bukkit/ServerLinks.java +++ b/src/main/java/org/bukkit/ServerLinks.java @@ -50,13 +50,27 @@ public interface ServerLinks { @NotNull ServerLink addLink(@NotNull Type type, @NotNull URI url); + // Paper start - Adventure + /** + * Adds the given link to the list of links. + * + * @param displayName link name / display text Component + * @param url link url + * @return the added link + */ + @NotNull + ServerLink addLink(@NotNull net.kyori.adventure.text.Component displayName, @NotNull URI url); + // Paper end - Adventure + /** * Adds the given link to the list of links. * * @param displayName link name / display text * @param url link url * @return the added link + * @deprecated in favour of {@link ServerLinks#addLink(net.kyori.adventure.text.Component, URI)} */ + @Deprecated // Paper - Adventure @NotNull ServerLink addLink(@NotNull String displayName, @NotNull URI url); @@ -89,11 +103,23 @@ public interface ServerLinks { @Nullable Type getType(); + // Paper start - Adventure + /** + * Gets the display name/text Component of this link. + * + * @return display name Component + */ + @NotNull + net.kyori.adventure.text.Component displayName(); + // Paper end - Adventure + /** * Gets the display name/text of this link. * * @return display name + * @deprecated in favour of {@link ServerLink#displayName()} */ + @Deprecated // Paper - Adventure @NotNull String getDisplayName(); diff --git a/src/main/java/org/bukkit/Sound.java b/src/main/java/org/bukkit/Sound.java index 4204a7dac18c60f177a5f70693388cd4ddc3bc0c..04e890be72b18259f1af2833879b4d9af51b1f02 100644 --- a/src/main/java/org/bukkit/Sound.java +++ b/src/main/java/org/bukkit/Sound.java @@ -20,7 +20,7 @@ import org.jetbrains.annotations.NotNull; * guarantee values will not be removed from this interface. As such, you should not * depend on the ordinal values of this class. */ -public interface Sound extends OldEnum<Sound>, Keyed { +public interface Sound extends OldEnum<Sound>, Keyed, net.kyori.adventure.sound.Sound.Type { // Paper - implement Sound.Type Sound AMBIENT_BASALT_DELTAS_ADDITIONS = getSound("ambient.basalt_deltas.additions"); Sound AMBIENT_BASALT_DELTAS_LOOP = getSound("ambient.basalt_deltas.loop"); @@ -1698,4 +1698,11 @@ public interface Sound extends OldEnum<Sound>, Keyed { static Sound[] values() { return Lists.newArrayList(Registry.SOUNDS).toArray(new Sound[0]); } + + // Paper start + @Override + default net.kyori.adventure.key.@NotNull Key key() { + return this.getKey(); + } + // Paper end } diff --git a/src/main/java/org/bukkit/SoundCategory.java b/src/main/java/org/bukkit/SoundCategory.java index ac5e263d737973af077e3406a84a84baca4370db..2d91924b7f5ef16a91d40cdc1bfc3d68e0fda38d 100644 --- a/src/main/java/org/bukkit/SoundCategory.java +++ b/src/main/java/org/bukkit/SoundCategory.java @@ -3,7 +3,7 @@ package org.bukkit; /** * An Enum of categories for sounds. */ -public enum SoundCategory { +public enum SoundCategory implements net.kyori.adventure.sound.Sound.Source.Provider { // Paper - implement Sound.Source.Provider MASTER, MUSIC, @@ -15,4 +15,22 @@ public enum SoundCategory { PLAYERS, AMBIENT, VOICE; + + // Paper start - implement Sound.Source.Provider + @Override + public net.kyori.adventure.sound.Sound.@org.jetbrains.annotations.NotNull Source soundSource() { + return switch (this) { + case MASTER -> net.kyori.adventure.sound.Sound.Source.MASTER; + case MUSIC -> net.kyori.adventure.sound.Sound.Source.MUSIC; + case RECORDS -> net.kyori.adventure.sound.Sound.Source.RECORD; + case WEATHER -> net.kyori.adventure.sound.Sound.Source.WEATHER; + case BLOCKS -> net.kyori.adventure.sound.Sound.Source.BLOCK; + case HOSTILE -> net.kyori.adventure.sound.Sound.Source.HOSTILE; + case NEUTRAL -> net.kyori.adventure.sound.Sound.Source.NEUTRAL; + case PLAYERS -> net.kyori.adventure.sound.Sound.Source.PLAYER; + case AMBIENT -> net.kyori.adventure.sound.Sound.Source.AMBIENT; + case VOICE -> net.kyori.adventure.sound.Sound.Source.VOICE; + }; + } + // Paper end } diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java index 752fef0205d7edc09a7072e4ca63152b12eb28ec..1ed3f8dae84c10cb3245d08fa776396a695b5c2f 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java @@ -31,6 +31,15 @@ import org.jetbrains.annotations.Nullable; */ @Deprecated public interface UnsafeValues { + // Paper start + net.kyori.adventure.text.flattener.ComponentFlattener componentFlattener(); + @Deprecated(forRemoval = true) net.kyori.adventure.text.serializer.plain.PlainComponentSerializer plainComponentSerializer(); + @Deprecated(forRemoval = true) net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer plainTextSerializer(); + @Deprecated(forRemoval = true) net.kyori.adventure.text.serializer.gson.GsonComponentSerializer gsonComponentSerializer(); + @Deprecated(forRemoval = true) net.kyori.adventure.text.serializer.gson.GsonComponentSerializer colorDownsamplingGsonComponentSerializer(); + @Deprecated(forRemoval = true) net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer legacyComponentSerializer(); + net.kyori.adventure.text.Component resolveWithContext(net.kyori.adventure.text.Component component, org.bukkit.command.CommandSender context, org.bukkit.entity.Entity scoreboardSubject, boolean bypassPermissions) throws java.io.IOException; + // Paper end Material toLegacy(Material material); diff --git a/src/main/java/org/bukkit/Warning.java b/src/main/java/org/bukkit/Warning.java index 0208fc2bcd5c99c60b37419b92248db76681fc1e..5c1dda6888561a7eba0fbf9ba6ca7d7fe856eb53 100644 --- a/src/main/java/org/bukkit/Warning.java +++ b/src/main/java/org/bukkit/Warning.java @@ -68,6 +68,7 @@ public @interface Warning { * </ul> */ public boolean printFor(@Nullable Warning warning) { + if (Boolean.getBoolean("paper.alwaysPrintWarningState")) return true; // Paper if (this == DEFAULT) { return warning == null || warning.value(); } diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java index c0479a8da773b2f8db29f190ddc0e4961fb9f107..9732929b666b0a5e1a2a41c8e8794cc4f2535e41 100644 --- a/src/main/java/org/bukkit/World.java +++ b/src/main/java/org/bukkit/World.java @@ -47,7 +47,7 @@ import org.jetbrains.annotations.Nullable; /** * Represents a world, which may contain entities, chunks and blocks */ -public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable, PersistentDataHolder, Keyed { +public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient, Metadatable, PersistentDataHolder, Keyed, net.kyori.adventure.audience.ForwardingAudience { // Paper /** * Gets the {@link Block} at the given coordinates @@ -644,6 +644,14 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient @NotNull public List<Player> getPlayers(); + // Paper start + @NotNull + @Override + default Iterable<? extends net.kyori.adventure.audience.Audience> audiences() { + return this.getPlayers(); + } + // Paper end + /** * Returns a list of entities within a bounding box centered around a * Location. diff --git a/src/main/java/org/bukkit/block/CommandBlock.java b/src/main/java/org/bukkit/block/CommandBlock.java index 372c0bd5a4d7800a11c24c95e39fe376a96232bf..9c88be68b4f403d0500cb607394b3a1646675ef7 100644 --- a/src/main/java/org/bukkit/block/CommandBlock.java +++ b/src/main/java/org/bukkit/block/CommandBlock.java @@ -33,7 +33,9 @@ public interface CommandBlock extends TileState { * by default is "@". * * @return Name of this CommandBlock. + * @deprecated in favour of {@link #name()} */ + @Deprecated // Paper @NotNull public String getName(); @@ -43,6 +45,28 @@ public interface CommandBlock extends TileState { * same as setting it to "@". * * @param name New name for this CommandBlock. + * @deprecated in favour of {@link #name(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void setName(@Nullable String name); + + // Paper start + /** + * Gets the name of this CommandBlock. The name is used with commands + * that this CommandBlock executes. This name will never be null, and + * by default is a {@link net.kyori.adventure.text.TextComponent} containing {@code @}. + * + * @return Name of this CommandBlock. + */ + public net.kyori.adventure.text.@NotNull Component name(); + + /** + * Sets the name of this CommandBlock. The name is used with commands + * that this CommandBlock executes. Setting the name to null is the + * same as setting it to a {@link net.kyori.adventure.text.TextComponent} containing {@code @}. + * + * @param name New name for this CommandBlock. + */ + 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 index d9fae47539a382bf87e4265111b7e6c2a1819caf..1fdb1144949adc3a2b5cbc3aca94d2f8e0c6d9ee 100644 --- a/src/main/java/org/bukkit/block/Sign.java +++ b/src/main/java/org/bukkit/block/Sign.java @@ -12,12 +12,51 @@ import org.jetbrains.annotations.Nullable; * 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 the {@link Side#FRONT} of this sign. + * + * @return List of components containing each line of text + * @deprecated A sign may have multiple writable sides now. Use {@link Sign#getSide(Side)} and {@link SignSide#lines()}. + */ + @NotNull + @Deprecated + public java.util.List<net.kyori.adventure.text.Component> lines(); + + /** + * Gets the line of text at the specified index on the {@link Side#FRONT}. + * <p> + * 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 + * @deprecated A sign may have multiple writable sides now. Use {@link #getSide(Side)} and {@link SignSide#line(int)}. + */ + @NotNull + @Deprecated + public net.kyori.adventure.text.Component line(int index) throws IndexOutOfBoundsException; + + /** + * Sets the line of text at the specified index on the {@link Side#FRONT}. + * <p> + * For example, setLine(0, "Line One") will set the first line of text to + * "Line One". + * + * @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 A sign may have multiple writable sides now. Use {@link #getSide(Side)} and {@link SignSide#line(int, net.kyori.adventure.text.Component)}. + */ + @Deprecated + public void line(int index, net.kyori.adventure.text.@NotNull Component line) throws IndexOutOfBoundsException; + // Paper end /** * Gets all the lines of text currently on the {@link Side#FRONT} of this sign. * * @return Array of Strings containing each line of text - * @deprecated A sign may have multiple writable sides now. Use {@link Sign#getSide(Side)} and {@link SignSide#getLines()}. + * @deprecated A sign may have multiple writable sides now. Use {@link Sign#getSide(Side)} and {@link SignSide#lines()}. */ @Deprecated @NotNull @@ -31,7 +70,7 @@ 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 A sign may have multiple writable sides now. Use {@link #getSide(Side)} and {@link SignSide#getLine(int)}. + * @deprecated A sign may have multiple writable sides now. Use {@link #getSide(Side)} and {@link SignSide#line(int)}. */ @Deprecated @NotNull @@ -46,7 +85,7 @@ 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 A sign may have multiple writable sides now. Use {@link #getSide(Side)} and {@link SignSide#setLine(int, String)}. + * @deprecated A sign may have multiple writable sides now. Use {@link #getSide(Side)} and {@link SignSide#line(int, net.kyori.adventure.text.Component)}. */ @Deprecated public void setLine(int index, @NotNull String line) throws IndexOutOfBoundsException; diff --git a/src/main/java/org/bukkit/block/sign/SignSide.java b/src/main/java/org/bukkit/block/sign/SignSide.java index 0f4ae7bd2ad379b5edb40f49f93de9e18c38f415..575e545a69b5279b90067d7ebee08b7b59288496 100644 --- a/src/main/java/org/bukkit/block/sign/SignSide.java +++ b/src/main/java/org/bukkit/block/sign/SignSide.java @@ -7,13 +7,48 @@ import org.jetbrains.annotations.NotNull; * Represents a side of a sign. */ public interface SignSide extends Colorable { + // Paper start + /** + * Gets all the lines of text currently on the sign. + * + * @return List of components containing each line of text + */ + @NotNull + public java.util.List<net.kyori.adventure.text.Component> lines(); + + /** + * Gets the line of text at the specified index. + * <p> + * 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 + */ + @NotNull + public net.kyori.adventure.text.Component line(int index) throws IndexOutOfBoundsException; + + /** + * Sets the line of text at the specified index. + * <p> + * For example, setLine(0, "Line One") will set the first line of text to + * "Line One". + * + * @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, net.kyori.adventure.text.@NotNull Component line) throws IndexOutOfBoundsException; + // Paper end /** * Gets all the lines of text currently on this side of the sign. * * @return Array of Strings containing each line of text + * @deprecated in favour of {@link #lines()} */ @NotNull + @Deprecated // Paper public String[] getLines(); /** @@ -24,8 +59,10 @@ public interface SignSide extends Colorable { * @param index Line number to get the text from, starting at 0 * @return Text on the given line * @throws IndexOutOfBoundsException Thrown when the line does not exist + * @deprecated in favour of {@link #line(int)} */ @NotNull + @Deprecated // Paper public String getLine(int index) throws IndexOutOfBoundsException; /** @@ -37,7 +74,9 @@ public interface SignSide extends 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; /** diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java index ac89f041dc983485174a174e79cd21159fdfba1e..f3cdf13f22aa789ee8cc235b61fda4035b254219 100644 --- a/src/main/java/org/bukkit/command/Command.java +++ b/src/main/java/org/bukkit/command/Command.java @@ -32,7 +32,7 @@ public abstract class Command { protected String description; protected String usageMessage; private String permission; - private String permissionMessage; + private net.kyori.adventure.text.Component permissionMessage; // Paper public org.spigotmc.CustomTimingsHandler timings; // Spigot protected Command(@NotNull String name) { @@ -186,10 +186,10 @@ public abstract class Command { if (permissionMessage == null) { target.sendMessage(ChatColor.RED + "I'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is a mistake."); - } else if (permissionMessage.length() != 0) { - for (String line : permissionMessage.replace("<permission>", permission).split("\n")) { - target.sendMessage(line); - } + // Paper start - use components for permissionMessage + } else if (!permissionMessage.equals(net.kyori.adventure.text.Component.empty())) { + target.sendMessage(permissionMessage.replaceText(net.kyori.adventure.text.TextReplacementConfig.builder().matchLiteral("<permission>").replacement(permission).build())); + // Paper end } return false; @@ -327,7 +327,7 @@ public abstract class Command { @Deprecated @Nullable public String getPermissionMessage() { - return permissionMessage; + return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serializeOrNull(permissionMessage); // Paper } /** @@ -398,7 +398,7 @@ public abstract class Command { @Deprecated @NotNull public Command setPermissionMessage(@Nullable String permissionMessage) { - this.permissionMessage = permissionMessage; + this.permissionMessage = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserializeOrNull(permissionMessage); // Paper return this; } @@ -413,13 +413,61 @@ public abstract class Command { this.usageMessage = (usage == null) ? "" : usage; return this; } + // Paper start + /** + * Gets the permission message. + * + * @return the permission message + * @deprecated permission messages have not worked for player-executed + * commands since 1.13 as clients without permission to execute a command + * are unaware of its existence and therefore will not send an unknown + * command execution to the server. This message will only ever be shown to + * consoles or when this command is executed with + * {@link Bukkit#dispatchCommand(CommandSender, String)}. + */ + @Deprecated + public net.kyori.adventure.text.@Nullable Component permissionMessage() { + return this.permissionMessage; + } + + /** + * Sets the permission message. + * + * @param permissionMessage the permission message + * @deprecated permission messages have not worked for player-executed + * commands since 1.13 as clients without permission to execute a command + * are unaware of its existence and therefore will not send an unknown + * command execution to the server. This message will only ever be shown to + * consoles or when this command is executed with + * {@link Bukkit#dispatchCommand(CommandSender, String)}. + */ + @Deprecated + public void permissionMessage(net.kyori.adventure.text.@Nullable Component permissionMessage) { + this.permissionMessage = permissionMessage; + } + // Paper end public static void broadcastCommandMessage(@NotNull CommandSender source, @NotNull String message) { broadcastCommandMessage(source, message, true); } public static void broadcastCommandMessage(@NotNull CommandSender source, @NotNull String message, boolean sendToSource) { - String result = source.getName() + ": " + message; + // Paper start + broadcastCommandMessage(source, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message), sendToSource); + } + + 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, 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) + .append(source.name()) + .append(net.kyori.adventure.text.Component.text(": ")) + .append(message); + // Paper end if (source instanceof BlockCommandSender) { BlockCommandSender blockCommandSender = (BlockCommandSender) source; @@ -438,7 +486,12 @@ public abstract class Command { } Set<Permissible> users = Bukkit.getPluginManager().getPermissionSubscriptions(Server.BROADCAST_CHANNEL_ADMINISTRATIVE); - String colored = ChatColor.GRAY + "" + ChatColor.ITALIC + "[" + result + ChatColor.GRAY + ChatColor.ITALIC + "]"; + // Paper start + net.kyori.adventure.text.TextComponent.Builder colored = net.kyori.adventure.text.Component.text() + .color(net.kyori.adventure.text.format.NamedTextColor.GRAY) + .decorate(net.kyori.adventure.text.format.TextDecoration.ITALIC) + .append(net.kyori.adventure.text.Component.text("["), result, net.kyori.adventure.text.Component.text("]")); + // Paper end if (sendToSource && !(source instanceof ConsoleCommandSender)) { source.sendMessage(message); diff --git a/src/main/java/org/bukkit/command/CommandSender.java b/src/main/java/org/bukkit/command/CommandSender.java index 284be63a125624a8ae43d2c164aede810ce6bfe5..70fec73328227725f519af845ecbdce8be2fa4e2 100644 --- a/src/main/java/org/bukkit/command/CommandSender.java +++ b/src/main/java/org/bukkit/command/CommandSender.java @@ -6,20 +6,28 @@ import org.bukkit.permissions.Permissible; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public interface CommandSender extends Permissible { +public interface CommandSender extends net.kyori.adventure.audience.Audience, Permissible { // Paper /** * Sends this sender a message * * @param message Message to be displayed + * @see #sendMessage(net.kyori.adventure.text.Component) + * @see #sendPlainMessage(String) + * @see #sendRichMessage(String) */ + @org.jetbrains.annotations.ApiStatus.Obsolete // Paper public void sendMessage(@NotNull String message); /** * Sends this sender multiple messages * * @param messages An array of messages to be displayed + * @see #sendMessage(net.kyori.adventure.text.Component) + * @see #sendPlainMessage(String) + * @see #sendRichMessage(String) */ + @org.jetbrains.annotations.ApiStatus.Obsolete // Paper public void sendMessage(@NotNull String... messages); /** @@ -27,7 +35,10 @@ public interface CommandSender extends Permissible { * * @param message Message to be displayed * @param sender The sender of this message + * @see #sendMessage(net.kyori.adventure.identity.Identified, net.kyori.adventure.text.Component) + * @deprecated sender UUID is ignored */ + @Deprecated // Paper public void sendMessage(@Nullable UUID sender, @NotNull String message); /** @@ -35,7 +46,10 @@ public interface CommandSender extends Permissible { * * @param messages An array of messages to be displayed * @param sender The sender of this message + * @see #sendMessage(net.kyori.adventure.identity.Identified, net.kyori.adventure.text.Component) + * @deprecated sender UUID is ignored */ + @Deprecated // Paper public void sendMessage(@Nullable UUID sender, @NotNull String... messages); /** @@ -61,7 +75,9 @@ public interface CommandSender extends Permissible { * Sends this sender a chat component. * * @param component the components to send + * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} */ + @Deprecated // Paper public void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent component) { throw new UnsupportedOperationException("Not supported yet."); } @@ -70,7 +86,9 @@ public interface CommandSender extends Permissible { * Sends an array of components as a single message to the sender. * * @param components the components to send + * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} */ + @Deprecated // Paper public void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent... components) { throw new UnsupportedOperationException("Not supported yet."); } @@ -80,7 +98,9 @@ public interface CommandSender extends Permissible { * * @param component the components to send * @param sender the sender of the message + * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} */ + @Deprecated // Paper public void sendMessage(@Nullable UUID sender, @NotNull net.md_5.bungee.api.chat.BaseComponent component) { throw new UnsupportedOperationException("Not supported yet."); } @@ -90,7 +110,9 @@ public interface CommandSender extends Permissible { * * @param components the components to send * @param sender the sender of the message + * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} */ + @Deprecated // Paper public void sendMessage(@Nullable UUID sender, @NotNull net.md_5.bungee.api.chat.BaseComponent... components) { throw new UnsupportedOperationException("Not supported yet."); } @@ -99,4 +121,52 @@ public interface CommandSender extends Permissible { @NotNull Spigot spigot(); // Spigot end + + // Paper start + /** + * Gets the name of this command sender + * + * @return Name of the sender + */ + public net.kyori.adventure.text.@NotNull Component name(); + + @Override + 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)); + } + + /** + * Sends a message with the MiniMessage format to the command sender. + * <p> + * See <a href="https://docs.advntr.dev/minimessage/">MiniMessage docs</a> + * for more information on the format. + * + * @param message MiniMessage content + */ + default void sendRichMessage(final @NotNull String message) { + this.sendMessage(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(message)); + } + + /** + * Sends a message with the MiniMessage format to the command sender. + * <p> + * See <a href="https://docs.advntr.dev/minimessage/">MiniMessage docs</a> and <a href="https://docs.advntr.dev/minimessage/dynamic-replacements">MiniMessage Placeholders docs</a> + * for more information on the format. + * + * @param message MiniMessage content + * @param resolvers resolvers to use + */ + default void sendRichMessage(final @NotNull String message, final net.kyori.adventure.text.minimessage.tag.resolver.@NotNull TagResolver... resolvers) { + this.sendMessage(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(message, resolvers)); + } + + /** + * Sends a plain message to the command sender. + * + * @param message plain message + */ + default void sendPlainMessage(final @NotNull String message) { + this.sendMessage(net.kyori.adventure.text.Component.text(message)); + } + // Paper end } diff --git a/src/main/java/org/bukkit/command/PluginCommandYamlParser.java b/src/main/java/org/bukkit/command/PluginCommandYamlParser.java index a542c4bb3c973bbe4b976642feccde6a4d90cb7b..ef870b864c1e36032b54b31f3f85707edc06d764 100644 --- a/src/main/java/org/bukkit/command/PluginCommandYamlParser.java +++ b/src/main/java/org/bukkit/command/PluginCommandYamlParser.java @@ -67,7 +67,7 @@ public class PluginCommandYamlParser { } if (permissionMessage != null) { - newCmd.setPermissionMessage(permissionMessage.toString()); + newCmd.permissionMessage(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(permissionMessage.toString())); // Paper } pluginCmds.add(newCmd); diff --git a/src/main/java/org/bukkit/command/ProxiedCommandSender.java b/src/main/java/org/bukkit/command/ProxiedCommandSender.java index fcc34b640265f4dccb46b9f09466ab8e1d96043e..5c813ac024f675951159a59d88d8baa0d49840e9 100644 --- a/src/main/java/org/bukkit/command/ProxiedCommandSender.java +++ b/src/main/java/org/bukkit/command/ProxiedCommandSender.java @@ -3,7 +3,7 @@ package org.bukkit.command; import org.jetbrains.annotations.NotNull; -public interface ProxiedCommandSender extends CommandSender { +public interface ProxiedCommandSender extends CommandSender, net.kyori.adventure.audience.ForwardingAudience.Single { // Paper /** * Returns the CommandSender which triggered this proxied command @@ -21,4 +21,16 @@ public interface ProxiedCommandSender extends CommandSender { @NotNull CommandSender getCallee(); + // Paper start + @Override + 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); + } + + @NotNull + @Override + default net.kyori.adventure.audience.Audience audience() { + return this.getCaller(); + } + // Paper end } diff --git a/src/main/java/org/bukkit/configuration/ConfigurationSection.java b/src/main/java/org/bukkit/configuration/ConfigurationSection.java index b6b00af08f12f838411845e4f4e29e62826dfc7f..d168b1e58b4b4ad00466fab60232d516551668e0 100644 --- a/src/main/java/org/bukkit/configuration/ConfigurationSection.java +++ b/src/main/java/org/bukkit/configuration/ConfigurationSection.java @@ -1058,4 +1058,98 @@ public interface ConfigurationSection { * one line. */ public void setInlineComments(@NotNull String path, @Nullable List<String> comments); + + // Paper start - add rich message component support to configuration + /** + * Gets the requested MiniMessage formatted String as Component by path. + * <p> + * If the Component does not exist but a default value has been specified, + * this will return the default value. If the Component does not exist and no + * default value was specified, this will return null. + * + * @param path Path of the Component to get. + * @return Requested Component. + */ + default net.kyori.adventure.text.@Nullable Component getRichMessage(final @NotNull String path) { + return this.getRichMessage(path, null); + } + + /** + * Gets the requested MiniMessage formatted String as Component by path. + * <p> + * If the Component does not exist but a default value has been specified, + * this will return the default value. If the Component does not exist and no + * default value was specified, this will return null. + * + * @param path Path of the Component to get. + * @param fallback component that will be used as fallback + * @return Requested Component. + */ + @Contract("_, !null -> !null") + default net.kyori.adventure.text.@Nullable Component getRichMessage(final @NotNull String path, final net.kyori.adventure.text.@Nullable Component fallback) { + return this.getComponent(path, net.kyori.adventure.text.minimessage.MiniMessage.miniMessage(), fallback); + } + + /** + * Sets the specified path to the given value. + * <p> + * If value is null, the entry will be removed. Any existing entry will be + * replaced, regardless of what the new value is. + * + * @param path Path of the object to set. + * @param value New value to set the path to. + */ + default void setRichMessage(final @NotNull String path, final net.kyori.adventure.text.@Nullable Component value) { + this.setComponent(path, net.kyori.adventure.text.minimessage.MiniMessage.miniMessage(), value); + } + + /** + * Gets the requested formatted String as Component by path deserialized by the ComponentDecoder. + * <p> + * If the Component does not exist but a default value has been specified, + * this will return the default value. If the Component does not exist and no + * default value was specified, this will return null. + * + * @param path Path of the Component to get. + * @param decoder ComponentDecoder instance used for deserialization + * @return Requested Component. + */ + default <C extends net.kyori.adventure.text.Component> @Nullable C getComponent(final @NotNull String path, final net.kyori.adventure.text.serializer.@NotNull ComponentDecoder<? super String, C> decoder) { + return this.getComponent(path, decoder, null); + } + + /** + * Gets the requested formatted String as Component by path deserialized by the ComponentDecoder. + * <p> + * If the Component does not exist but a default value has been specified, + * this will return the default value. If the Component does not exist and no + * default value was specified, this will return null. + * + * @param path Path of the Component to get. + * @param decoder ComponentDecoder instance used for deserialization + * @param fallback component that will be used as fallback + * @return Requested Component. + */ + @Contract("_, _, !null -> !null") + default <C extends net.kyori.adventure.text.Component> @Nullable C getComponent(final @NotNull String path, final net.kyori.adventure.text.serializer.@NotNull ComponentDecoder<? super String, C> decoder, final @Nullable C fallback) { + java.util.Objects.requireNonNull(decoder, "decoder"); + final String value = this.getString(path); + return decoder.deserializeOr(value, fallback); + } + + /** + * Sets the specified path to the given value. + * <p> + * If value is null, the entry will be removed. Any existing entry will be + * replaced, regardless of what the new value is. + * + * @param path Path of the object to set. + * @param encoder the encoder used to transform the value + * @param value New value to set the path to. + */ + default <C extends net.kyori.adventure.text.Component> void setComponent(final @NotNull String path, final net.kyori.adventure.text.serializer.@NotNull ComponentEncoder<C, String> encoder, final @Nullable C value) { + java.util.Objects.requireNonNull(encoder, "encoder"); + this.set(path, encoder.serializeOrNull(value)); + } + // Paper end - add rich message component support to configuration } diff --git a/src/main/java/org/bukkit/conversations/Conversable.java b/src/main/java/org/bukkit/conversations/Conversable.java index b7d8dd30360a38dbdc7bbce40c8e6ced7261f833..0817f2395c2b18828565435568ce651f5ba99a99 100644 --- a/src/main/java/org/bukkit/conversations/Conversable.java +++ b/src/main/java/org/bukkit/conversations/Conversable.java @@ -55,6 +55,7 @@ public interface Conversable { * * @param message Message to be displayed */ + @org.jetbrains.annotations.ApiStatus.Obsolete // Paper public void sendRawMessage(@NotNull String message); /** @@ -62,6 +63,8 @@ public interface Conversable { * * @param message Message to be displayed * @param sender The sender of this message + * @deprecated sender UUID is ignored */ + @Deprecated // Paper public void sendRawMessage(@Nullable UUID sender, @NotNull String message); } diff --git a/src/main/java/org/bukkit/enchantments/Enchantment.java b/src/main/java/org/bukkit/enchantments/Enchantment.java index 241bc2ea6157c29d6d5428c413ea14ac3822e3f7..378ef178bdcf0d71b5d80fc5028ce738437f9391 100644 --- a/src/main/java/org/bukkit/enchantments/Enchantment.java +++ b/src/main/java/org/bukkit/enchantments/Enchantment.java @@ -310,6 +310,19 @@ public abstract class Enchantment implements Keyed, Translatable { * @return True if the enchantment may be applied, otherwise False */ public abstract boolean canEnchantItem(@NotNull ItemStack item); + // Paper start + /** + * Get the name of the enchantment with its applied level. + * <p> + * If the given {@code level} is either less than the {@link #getStartLevel()} or greater than the {@link #getMaxLevel()}, + * the level may not be shown in the numeral format one may otherwise expect. + * </p> + * + * @param level the level of the enchantment to show + * @return the name of the enchantment with {@code level} applied + */ + public abstract net.kyori.adventure.text.@NotNull Component displayName(int level); + // Paper end /** * Gets the Enchantment at the specified key diff --git a/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java b/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java index 7ad7bcf9a9333c8d6d1d7cab53a6d457ec20bbf6..c4f86ba1037f3f0e5d697a0962d71d6f8c7c1fbe 100644 --- a/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java +++ b/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java @@ -20,4 +20,11 @@ public abstract class EnchantmentWrapper extends Enchantment { public Enchantment getEnchantment() { return this; } + // Paper start + @NotNull + @Override + public net.kyori.adventure.text.Component displayName(int level) { + return getEnchantment().displayName(level); + } + // Paper end } diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java index 558fe6e23f562ee873fc84112f930c6ea19a09f4..c78fb359bd28b8dc1ba242642ec612e856525993 100644 --- a/src/main/java/org/bukkit/entity/Entity.java +++ b/src/main/java/org/bukkit/entity/Entity.java @@ -30,7 +30,7 @@ import org.jetbrains.annotations.Nullable; * Not all methods are guaranteed to work/may have side effects when * {@link #isInWorld()} is false. */ -public interface Entity extends Metadatable, CommandSender, Nameable, PersistentDataHolder { +public interface Entity extends Metadatable, CommandSender, Nameable, PersistentDataHolder, net.kyori.adventure.text.event.HoverEventSource<net.kyori.adventure.text.event.HoverEvent.ShowEntity>, net.kyori.adventure.sound.Sound.Emitter { // Paper /** * Gets the entity's current position @@ -776,4 +776,20 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent @Override Spigot spigot(); // Spigot end + + // Paper start + /** + * Gets the entity's display name formatted with their team prefix/suffix and + * the entity's default hover/click events. + * + * @return the team display name + */ + net.kyori.adventure.text.@NotNull Component teamDisplayName(); + + @NotNull + @Override + default net.kyori.adventure.text.event.HoverEvent<net.kyori.adventure.text.event.HoverEvent.ShowEntity> asHoverEvent(final @NotNull java.util.function.UnaryOperator<net.kyori.adventure.text.event.HoverEvent.ShowEntity> op) { + return net.kyori.adventure.text.event.HoverEvent.showEntity(op.apply(net.kyori.adventure.text.event.HoverEvent.ShowEntity.of(this.getType().getKey(), this.getUniqueId(), this.customName()))); + } + // Paper end } diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java index d87115c4315f544b5f6f3e03957b2014762b754a..cab45a41e54599588007c9b02a23d1b148dd89f1 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java @@ -58,7 +58,41 @@ import org.jetbrains.annotations.Nullable; /** * Represents a player, connected or not */ -public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginMessageRecipient { +public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginMessageRecipient, net.kyori.adventure.identity.Identified, net.kyori.adventure.bossbar.BossBarViewer { // Paper + + // Paper start + @Override + default net.kyori.adventure.identity.@NotNull Identity identity() { + return net.kyori.adventure.identity.Identity.identity(this.getUniqueId()); + } + + /** + * Gets an unmodifiable view of all known currently active bossbars. + * <p> + * <b>This currently only returns bossbars shown to the player via + * {@link #showBossBar(net.kyori.adventure.bossbar.BossBar)} and does not contain bukkit + * {@link org.bukkit.boss.BossBar} instances shown to the player.</b> + * + * @return an unmodifiable view of all known currently active bossbars + * @since 4.14.0 + */ + @Override + @org.jetbrains.annotations.UnmodifiableView @NotNull Iterable<? extends net.kyori.adventure.bossbar.BossBar> activeBossBars(); + + /** + * Gets the "friendly" name to display of this player. + * + * @return the display name + */ + 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 net.kyori.adventure.text.@Nullable Component displayName); + // Paper end /** * {@inheritDoc} @@ -75,7 +109,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * places defined by plugins. * * @return the friendly name + * @deprecated in favour of {@link #displayName()} */ + @Deprecated // Paper @NotNull public String getDisplayName(); @@ -87,15 +123,50 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * places defined by plugins. * * @param name The new display name. + * @deprecated in favour of {@link #displayName(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void setDisplayName(@Nullable String name); + // Paper start + /** + * Sets the name that is shown on the in-game player list. + * <p> + * If the value is null, the name will be identical to {@link #getName()}. + * + * @param name new player list 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 + */ + net.kyori.adventure.text.@NotNull Component playerListName(); + + /** + * Gets the currently displayed player list header for this player. + * + * @return player list header or null + */ + net.kyori.adventure.text.@Nullable Component playerListHeader(); + + /** + * Gets the currently displayed player list footer for this player. + * + * @return player list footer or null + */ + net.kyori.adventure.text.@Nullable Component playerListFooter(); + // Paper end /** * Gets the name that is shown on the player list. * * @return the player list name + * @deprecated in favour of {@link #playerListName()} */ @NotNull + @Deprecated // Paper public String getPlayerListName(); /** @@ -104,7 +175,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * If the value is null, the name will be identical to {@link #getName()}. * * @param name new player list name + * @deprecated in favour of {@link #playerListName(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void setPlayerListName(@Nullable String name); /** @@ -126,7 +199,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * Gets the currently displayed player list header for this player. * * @return player list header or null + * @deprecated in favour of {@link #playerListHeader()} */ + @Deprecated // Paper @Nullable public String getPlayerListHeader(); @@ -134,7 +209,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * Gets the currently displayed player list footer for this player. * * @return player list header or null + * @deprecated in favour of {@link #playerListFooter()} */ + @Deprecated // Paper @Nullable public String getPlayerListFooter(); @@ -142,14 +219,18 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * Sets the currently displayed player list header for this player. * * @param header player list header, null for empty + * @deprecated in favour of {@link #sendPlayerListHeader(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void setPlayerListHeader(@Nullable String header); /** * Sets the currently displayed player list footer for this player. * * @param footer player list footer, null for empty + * @deprecated in favour of {@link #sendPlayerListFooter(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void setPlayerListFooter(@Nullable String footer); /** @@ -158,7 +239,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * * @param header player list header, null for empty * @param footer player list footer, null for empty + * @deprecated in favour of {@link #sendPlayerListHeaderAndFooter(net.kyori.adventure.text.Component, net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void setPlayerListHeaderFooter(@Nullable String header, @Nullable String footer); /** @@ -235,9 +318,25 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * Kicks player with custom kick message. * * @param message kick message + * @deprecated in favour of {@link #kick(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void kickPlayer(@Nullable String message); + // Paper start + /** + * Kicks the player with the default kick message. + * @see #kick(net.kyori.adventure.text.Component) + */ + void kick(); + /** + * Kicks player with custom kick message. + * + * @param message kick message + */ + void kick(final net.kyori.adventure.text.@Nullable Component message); + // Paper end + /** * Adds this user to the {@link ProfileBanList}. If a previous ban exists, this will * update the entry. @@ -924,6 +1023,106 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM */ public void sendEquipmentChange(@NotNull LivingEntity entity, @NotNull Map<EquipmentSlot, ItemStack> 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)}. + * <p> + * 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 Use {@link #sendBlockUpdate(Location, TileState)} by creating a new virtual + * {@link org.bukkit.block.Sign} block state via {@link BlockData#createBlockState()} + * (constructed e.g. via {@link Material#createBlockData()}) + */ + @Deprecated + default void sendSignChange(@NotNull Location loc, @Nullable java.util.List<? extends net.kyori.adventure.text.Component> 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)}. + * <p> + * 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 Use {@link #sendBlockUpdate(Location, TileState)} by creating a new virtual + * {@link org.bukkit.block.Sign} block state via {@link BlockData#createBlockState()} + * (constructed e.g. via {@link Material#createBlockData()}) + */ + @Deprecated + default void sendSignChange(@NotNull Location loc, @Nullable java.util.List<? extends net.kyori.adventure.text.Component> lines, @NotNull DyeColor dyeColor) throws IllegalArgumentException { + this.sendSignChange(loc, lines, dyeColor, false); + } + + /** + * 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)}. + * <p> + * 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 hasGlowingText whether the text of the sign should glow as if dyed with a glowing ink sac + * @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 Use {@link #sendBlockUpdate(Location, TileState)} by creating a new virtual + * {@link org.bukkit.block.Sign} block state via {@link BlockData#createBlockState()} + * (constructed e.g. via {@link Material#createBlockData()}) + */ + @Deprecated + default void sendSignChange(@NotNull Location loc, @Nullable java.util.List<? extends net.kyori.adventure.text.Component> lines, boolean hasGlowingText) throws IllegalArgumentException { + this.sendSignChange(loc, lines, DyeColor.BLACK, hasGlowingText); + } + + /** + * 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)}. + * <p> + * 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 + * @param hasGlowingText whether the text of the sign should glow as if dyed with a glowing ink sac + * @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 Use {@link #sendBlockUpdate(Location, TileState)} by creating a new virtual + * {@link org.bukkit.block.Sign} block state via {@link BlockData#createBlockState()} + * (constructed e.g. via {@link Material#createBlockData()}) + */ + @Deprecated + void sendSignChange(@NotNull Location loc, @Nullable java.util.List<? extends net.kyori.adventure.text.Component> lines, @NotNull DyeColor dyeColor, boolean hasGlowingText) + 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. @@ -941,7 +1140,11 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * @param lines the new text on the sign or null to clear it * @throws IllegalArgumentException if location is null * @throws IllegalArgumentException if lines is non-null and has a length less than 4 + * @deprecated Use {@link #sendBlockUpdate(Location, TileState)} by creating a new virtual + * {@link org.bukkit.block.Sign} block state via {@link BlockData#createBlockState()} + * (constructed e.g. via {@link Material#createBlockData()}) */ + @Deprecated // Paper public void sendSignChange(@NotNull Location loc, @Nullable String[] lines) throws IllegalArgumentException; /** @@ -963,7 +1166,11 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * @throws IllegalArgumentException if location is null * @throws IllegalArgumentException if dyeColor is null * @throws IllegalArgumentException if lines is non-null and has a length less than 4 + * @deprecated Use {@link #sendBlockUpdate(Location, TileState)} by creating a new virtual + * {@link org.bukkit.block.Sign} block state via {@link BlockData#createBlockState()} + * (constructed e.g. via {@link Material#createBlockData()}) */ + @Deprecated // Paper public void sendSignChange(@NotNull Location loc, @Nullable String[] lines, @NotNull DyeColor dyeColor) throws IllegalArgumentException; /** @@ -986,7 +1193,11 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * @throws IllegalArgumentException if location is null * @throws IllegalArgumentException if dyeColor is null * @throws IllegalArgumentException if lines is non-null and has a length less than 4 + * @deprecated Use {@link #sendBlockUpdate(Location, TileState)} by creating a new virtual + * {@link org.bukkit.block.Sign} block state via {@link BlockData#createBlockState()} + * (constructed e.g. via {@link Material#createBlockData()}) */ + @Deprecated // Paper public void sendSignChange(@NotNull Location loc, @Nullable String[] lines, @NotNull DyeColor dyeColor, boolean hasGlowingText) throws IllegalArgumentException; /** @@ -1461,7 +1672,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * @throws IllegalArgumentException Thrown if the URL is null. * @throws IllegalArgumentException Thrown if the URL is too long. * @deprecated Minecraft no longer uses textures packs. Instead you - * should use {@link #setResourcePack(String)}. + * should use {@link #setResourcePack(UUID, String, byte[], net.kyori.adventure.text.Component, boolean)}. */ @Deprecated public void setTexturePack(@NotNull String url); @@ -1497,7 +1708,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * @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. + * @deprecated in favour of {@link #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest)} */ + @Deprecated // Paper - adventure public void setResourcePack(@NotNull String url); /** @@ -1529,6 +1742,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * pack correctly. * </ul> * + * @deprecated in favour of {@link #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest)} * @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. @@ -1541,6 +1755,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * @throws IllegalArgumentException Thrown if the hash is not 20 bytes * long. */ + @Deprecated // Paper - adventure public void setResourcePack(@NotNull String url, @Nullable byte[] hash); /** @@ -1565,12 +1780,13 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * {@link PlayerResourcePackStatusEvent} to figure out whether or not * the player loaded the pack! * <li>To remove a resource pack you can use - * {@link #removeResourcePack(UUID)} or {@link #removeResourcePacks()}. + * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. * <li>The request is sent with empty string as the hash when the hash is * not provided. This might result in newer versions not loading the * pack correctly. * </ul> * + * @deprecated in favour of {@link #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest)} * @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. @@ -1584,8 +1800,10 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * @throws IllegalArgumentException Thrown if the hash is not 20 bytes * long. */ + @Deprecated // Paper - adventure 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. * <p> @@ -1608,7 +1826,54 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * {@link PlayerResourcePackStatusEvent} to figure out whether or not * the player loaded the pack! * <li>To remove a resource pack you can use - * {@link #removeResourcePack(UUID)} or {@link #removeResourcePacks()}. + * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. + * <li>The request is sent with empty string as the hash when the hash is + * not provided. This might result in newer versions not loading the + * pack correctly. + * </ul> + * + * @param url The URL from which the client will download the resource + * pack. The string must contain only US-ASCII characters and should + * be encoded as per RFC 1738. + * @param hash The sha1 hash sum of the resource pack file which is used + * to apply a cached version of the pack directly without downloading + * if it is available. Hast to be 20 bytes long! + * @param prompt The optional custom prompt message to be shown to client. + * @throws IllegalArgumentException Thrown if the URL is null. + * @throws IllegalArgumentException Thrown if the URL is too long. The + * length restriction is an implementation specific arbitrary value. + * @throws IllegalArgumentException Thrown if the hash is not 20 bytes + * long. + * @see #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest) + */ + default void setResourcePack(final @NotNull String url, final byte @Nullable [] hash, final 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. + * <p> + * The player's client will download the new resource pack asynchronously + * in the background, and will automatically switch to it once the + * download is complete. If the client has downloaded and cached a + * resource pack with the same hash in the past it will not download but + * directly apply the cached pack. If the hash is null and the client has + * downloaded and cached the same resource pack in the past, it will + * perform a file size check against the response content to determine if + * the resource pack has changed and needs to be downloaded again. When + * this request is sent for the very first time from a given server, the + * client will first display a confirmation GUI to the player before + * proceeding with the download. + * <p> + * Notes: + * <ul> + * <li>Players can disable server resources on their client, in which + * case this method will have no affect on them. Use the + * {@link PlayerResourcePackStatusEvent} to figure out whether or not + * the player loaded the pack! + * <li>To remove a resource pack you can use + * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. * <li>The request is sent with empty string as the hash when the hash is * not provided. This might result in newer versions not loading the * pack correctly. @@ -1627,7 +1892,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * length restriction is an implementation specific arbitrary value. * @throws IllegalArgumentException Thrown if the hash is not 20 bytes * long. + * @deprecated in favour of {@link #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest)} */ + @Deprecated // Paper - adventure public void setResourcePack(@NotNull String url, @Nullable byte[] hash, boolean force); /** @@ -1652,7 +1919,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * {@link PlayerResourcePackStatusEvent} to figure out whether or not * the player loaded the pack! * <li>To remove a resource pack you can use - * {@link #removeResourcePack(UUID)} or {@link #removeResourcePacks()}. + * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. * <li>The request is sent with empty string as the hash when the hash is * not provided. This might result in newer versions not loading the * pack correctly. @@ -1672,9 +1939,61 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * length restriction is an implementation specific arbitrary value. * @throws IllegalArgumentException Thrown if the hash is not 20 bytes * long. + * @deprecated in favour of {@link #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest)} */ + @Deprecated // Paper public void setResourcePack(@NotNull String url, @Nullable byte[] hash, @Nullable String prompt, boolean force); + // Paper start + /** + * Request that the player's client download and switch resource packs. + * <p> + * The player's client will download the new resource pack asynchronously + * in the background, and will automatically switch to it once the + * download is complete. If the client has downloaded and cached a + * resource pack with the same hash in the past it will not download but + * directly apply the cached pack. If the hash is null and the client has + * downloaded and cached the same resource pack in the past, it will + * perform a file size check against the response content to determine if + * the resource pack has changed and needs to be downloaded again. When + * this request is sent for the very first time from a given server, the + * client will first display a confirmation GUI with a custom prompt + * to the player before proceeding with the download. + * <p> + * Notes: + * <ul> + * <li>Players can disable server resources on their client, in which + * case this method will have no affect on them. Use the + * {@link PlayerResourcePackStatusEvent} to figure out whether or not + * the player loaded the pack! + * <li>To remove a resource pack you can use + * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. + * <li>The request is sent with empty string as the hash when the hash is + * not provided. This might result in newer versions not loading the + * pack correctly. + * </ul> + * + * @param url The URL from which the client will download the resource + * pack. The string must contain only US-ASCII characters and should + * be encoded as per RFC 1738. + * @param hash The sha1 hash sum of the resource pack file which is used + * to apply a cached version of the pack directly without downloading + * if it is available. Hast to be 20 bytes long! + * @param prompt The optional custom prompt message to be shown to client. + * @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. + * @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. + * @see #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest) + */ + default void setResourcePack(final @NotNull String url, final byte @Nullable [] hash, final net.kyori.adventure.text.@Nullable Component prompt, final boolean force) { + this.setResourcePack(UUID.nameUUIDFromBytes(url.getBytes(java.nio.charset.StandardCharsets.UTF_8)), url, hash, prompt, force); + } + // Paper end + /** * Request that the player's client download and switch resource packs. * <p> @@ -1697,7 +2016,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * {@link PlayerResourcePackStatusEvent} to figure out whether or not * the player loaded the pack! * <li>To remove a resource pack you can use - * {@link #removeResourcePack(UUID)} or {@link #removeResourcePacks()}. + * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. * <li>The request is sent with empty string as the hash when the hash is * not provided. This might result in newer versions not loading the * pack correctly. @@ -1718,9 +2037,60 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * length restriction is an implementation specific arbitrary value. * @throws IllegalArgumentException Thrown if the hash is not 20 bytes * long. + * @deprecated in favour of {@link #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest)} */ + @Deprecated // Paper - adventure public void setResourcePack(@NotNull UUID id, @NotNull String url, @Nullable byte[] hash, @Nullable String prompt, boolean force); + // Paper start + /** + * Request that the player's client download and switch resource packs. + * <p> + * The player's client will download the new resource pack asynchronously + * in the background, and will automatically switch to it once the + * download is complete. If the client has downloaded and cached a + * resource pack with the same hash in the past it will not download but + * directly apply the cached pack. If the hash is null and the client has + * downloaded and cached the same resource pack in the past, it will + * perform a file size check against the response content to determine if + * the resource pack has changed and needs to be downloaded again. When + * this request is sent for the very first time from a given server, the + * client will first display a confirmation GUI to the player before + * proceeding with the download. + * <p> + * Notes: + * <ul> + * <li>Players can disable server resources on their client, in which + * case this method will have no affect on them. Use the + * {@link PlayerResourcePackStatusEvent} to figure out whether or not + * the player loaded the pack! + * <li>To remove a resource pack you can use + * {@link #removeResourcePacks(UUID, UUID...)} or {@link #clearResourcePacks()}. + * <li>The request is sent with empty string as the hash when the hash is + * not provided. This might result in newer versions not loading the + * pack correctly. + * </ul> + * + * @param uuid Unique resource pack ID. + * @param url The URL from which the client will download the resource + * pack. The string must contain only US-ASCII characters and should + * be encoded as per RFC 1738. + * @param hash The sha1 hash sum of the resource pack file which is used + * to apply a cached version of the pack directly without downloading + * if it is available. Hast to be 20 bytes long! + * @param prompt The optional custom prompt message to be shown to client. + * @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. + * @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. + * @see #sendResourcePacks(net.kyori.adventure.resource.ResourcePackRequest) + */ + void setResourcePack(@NotNull UUID uuid, @NotNull String url, byte @Nullable [] hash, net.kyori.adventure.text.@Nullable Component prompt, boolean force); + // Paper end + /** * Request that the player's client download and include another resource pack. * <p> @@ -1773,12 +2143,14 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * * @param id the id of the resource pack. * @throws IllegalArgumentException If the ID is null. + * @see #removeResourcePacks(UUID, UUID...) */ public void removeResourcePack(@NotNull UUID id); /** * Request that the player's client remove all loaded resource pack sent by * the server. + * @see #clearResourcePacks() */ public void removeResourcePacks(); @@ -1916,7 +2288,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * * @param title Title text * @param subtitle Subtitle text - * @deprecated API behavior subject to change + * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} */ @Deprecated public void sendTitle(@Nullable String title, @Nullable String subtitle); @@ -1935,7 +2307,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * @param fadeIn time in ticks for titles to fade in. Defaults to 10. * @param stay time in ticks for titles to stay. Defaults to 70. * @param fadeOut time in ticks for titles to fade out. Defaults to 20. + * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)} */ + @Deprecated // Paper - Adventure public void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int stay, int fadeOut); /** @@ -2210,6 +2584,14 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM */ public int getClientViewDistance(); + // Paper start + /** + * Gets the player's current locale. + * + * @return the player's locale + */ + @NotNull java.util.Locale locale(); + // Paper end /** * Gets the player's estimated ping in milliseconds. * @@ -2235,8 +2617,10 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * they wish. * * @return the player's locale + * @deprecated in favour of {@link #locale()} */ @NotNull + @Deprecated // Paper public String getLocale(); /** @@ -2288,6 +2672,14 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM */ public boolean isAllowingServerListings(); + // Paper start + @NotNull + @Override + default net.kyori.adventure.text.event.HoverEvent<net.kyori.adventure.text.event.HoverEvent.ShowEntity> asHoverEvent(final @NotNull java.util.function.UnaryOperator<net.kyori.adventure.text.event.HoverEvent.ShowEntity> op) { + return net.kyori.adventure.text.event.HoverEvent.showEntity(op.apply(net.kyori.adventure.text.event.HoverEvent.ShowEntity.of(this.getType().getKey(), this.getUniqueId(), this.displayName()))); + } + // Paper end + // Spigot start public class Spigot extends Entity.Spigot { @@ -2319,11 +2711,13 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM throw new UnsupportedOperationException("Not supported yet."); } + @Deprecated // Paper @Override public void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent component) { throw new UnsupportedOperationException("Not supported yet."); } + @Deprecated // Paper @Override public void sendMessage(@NotNull net.md_5.bungee.api.chat.BaseComponent... components) { throw new UnsupportedOperationException("Not supported yet."); @@ -2334,7 +2728,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * * @param position the screen position * @param component the components to send + * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} */ + @Deprecated // Paper public void sendMessage(@NotNull net.md_5.bungee.api.ChatMessageType position, @NotNull net.md_5.bungee.api.chat.BaseComponent component) { throw new UnsupportedOperationException("Not supported yet."); } @@ -2344,7 +2740,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * * @param position the screen position * @param components the components to send + * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} */ + @Deprecated // Paper public void sendMessage(@NotNull net.md_5.bungee.api.ChatMessageType position, @NotNull net.md_5.bungee.api.chat.BaseComponent... components) { throw new UnsupportedOperationException("Not supported yet."); } @@ -2355,7 +2753,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * @param position the screen position * @param sender the sender of the message * @param component the components to send + * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} */ + @Deprecated // Paper public void sendMessage(@NotNull net.md_5.bungee.api.ChatMessageType position, @Nullable java.util.UUID sender, @NotNull net.md_5.bungee.api.chat.BaseComponent component) { throw new UnsupportedOperationException("Not supported yet."); } @@ -2366,7 +2766,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * @param position the screen position * @param sender the sender of the message * @param components the components to send + * @deprecated use {@code sendMessage} methods that accept {@link net.kyori.adventure.text.Component} */ + @Deprecated // Paper 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."); } diff --git a/src/main/java/org/bukkit/entity/TextDisplay.java b/src/main/java/org/bukkit/entity/TextDisplay.java index bbce00a6d84aaad4a0ec892ec5cb1b995a0a5a05..a8277270e81bc3d9bbc64c029fe11e3d11e1d9ac 100644 --- a/src/main/java/org/bukkit/entity/TextDisplay.java +++ b/src/main/java/org/bukkit/entity/TextDisplay.java @@ -13,17 +13,37 @@ public interface TextDisplay extends Display { * Gets the displayed text. * * @return the displayed text. + * @deprecated in favour of {@link #text()} */ @Nullable + @Deprecated // Paper String getText(); /** * Sets the displayed text. * * @param text the new text + * @deprecated in favour of {@link #text(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper void setText(@Nullable String text); + // Paper start + /** + * Gets the displayed text. + * + * @return the displayed text + */ + net.kyori.adventure.text.@NotNull Component text(); + + /** + * Sets the displayed text. + * + * @param text the new text + */ + void text(net.kyori.adventure.text.@Nullable Component text); + // Paper end + /** * Gets the maximum line width before wrapping. * diff --git a/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java b/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java index 63c80b4ee1f7adc8a9efc3b607993104b1991f90..91cab8b13d5bba34007f124838b32a1df58c5ac7 100644 --- a/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java +++ b/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java @@ -32,7 +32,9 @@ public interface CommandMinecart extends Minecart { * same as setting it to "@". * * @param name New name for this CommandMinecart. + * @deprecated in favour of {@link #customName(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void setName(@Nullable String name); } diff --git a/src/main/java/org/bukkit/event/block/SignChangeEvent.java b/src/main/java/org/bukkit/event/block/SignChangeEvent.java index f4ac033ff8794a61c82a49dc6c3f863f3291455d..d944d67f544494355f03c5bc9afd8ea7726e6412 100644 --- a/src/main/java/org/bukkit/event/block/SignChangeEvent.java +++ b/src/main/java/org/bukkit/event/block/SignChangeEvent.java @@ -17,18 +17,38 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { private static final HandlerList handlers = new HandlerList(); private boolean cancel = false; private final Player player; - private final String[] lines; + private final java.util.List<net.kyori.adventure.text.Component> adventure$lines; // Paper private final Side side; + // Paper start + public SignChangeEvent(@NotNull final Block theBlock, @NotNull final Player player, @NotNull final java.util.List<net.kyori.adventure.text.Component> adventure$lines, @NotNull Side side) { + super(theBlock); + this.player = player; + this.adventure$lines = adventure$lines; + this.side = side; + } + + @Deprecated + public SignChangeEvent(@NotNull final Block theBlock, @NotNull final Player player, @NotNull final java.util.List<net.kyori.adventure.text.Component> adventure$lines) { + this(theBlock, player, adventure$lines, Side.FRONT); + } + // Paper end + @Deprecated public SignChangeEvent(@NotNull final Block theBlock, @NotNull final Player thePlayer, @NotNull final String[] theLines) { this(theBlock, thePlayer, theLines, Side.FRONT); } + @Deprecated // Paper public SignChangeEvent(@NotNull final Block theBlock, @NotNull final Player thePlayer, @NotNull final String[] theLines, @NotNull Side side) { super(theBlock); this.player = thePlayer; - this.lines = theLines; + // Paper start + this.adventure$lines = new java.util.ArrayList<>(); + for (String theLine : theLines) { + this.adventure$lines.add(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(theLine)); + } + // Paper end this.side = side; } @@ -42,14 +62,52 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { return player; } + // Paper start + /** + * Gets all of the lines of text from the sign involved in this event. + * + * @return the String array for the sign's lines new text + */ + public @NotNull java.util.List<net.kyori.adventure.text.Component> lines() { + return this.adventure$lines; + } + + /** + * Gets a single line of text from the sign involved in this event. + * + * @param index index of the line to get + * @return the String containing the line of text associated with the + * provided index + * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 + * or < 0} + */ + public net.kyori.adventure.text.@Nullable Component line(int index) throws IndexOutOfBoundsException { + return this.adventure$lines.get(index); + } + + /** + * Sets a single line for the sign involved in this event + * + * @param index index of the line to set + * @param line text to set + * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 + * or < 0} + */ + public void line(int index, net.kyori.adventure.text.@Nullable Component line) throws IndexOutOfBoundsException { + this.adventure$lines.set(index, line); + } + // Paper end + /** * Gets all of the lines of text from the sign involved in this event. * * @return the String array for the sign's lines new text + * @deprecated in favour of {@link #lines()} */ @NotNull + @Deprecated // Paper public String[] getLines() { - return lines; + return adventure$lines.stream().map(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection()::serialize).toArray(String[]::new); // Paper } /** @@ -60,10 +118,12 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { * provided index * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 * or < 0} + * @deprecated in favour of {@link #line(int)} */ @Nullable + @Deprecated // Paper public String getLine(int index) throws IndexOutOfBoundsException { - return lines[index]; + return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.adventure$lines.get(index)); // Paper } /** @@ -73,9 +133,11 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { * @param line text to set * @throws IndexOutOfBoundsException thrown when the provided index is {@literal > 3 * or < 0} + * @deprecated in favour of {@link #line(int, net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void setLine(int index, @Nullable String line) throws IndexOutOfBoundsException { - lines[index] = line; + adventure$lines.set(index, line != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(line) : null); // Paper } /** diff --git a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java index 133760be6c73436512ba684a3ac77a514b2d8765..9473303bd8ab1f6b63b6999a5f5ff3eca1cc23d6 100644 --- a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java +++ b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java @@ -12,26 +12,49 @@ import org.jetbrains.annotations.Nullable; */ public class PlayerDeathEvent extends EntityDeathEvent { private int newExp = 0; - private String deathMessage = ""; + private net.kyori.adventure.text.Component deathMessage; // Paper - adventure private int newLevel = 0; private int newTotalExp = 0; private boolean keepLevel = false; private boolean keepInventory = false; + // Paper start - adventure + @org.jetbrains.annotations.ApiStatus.Internal + public PlayerDeathEvent(final @NotNull Player player, final @NotNull DamageSource damageSource, final @NotNull List<ItemStack> drops, final int droppedExp, final @Nullable net.kyori.adventure.text.Component deathMessage) { + this(player, damageSource, drops, droppedExp, 0, deathMessage); + } + + @org.jetbrains.annotations.ApiStatus.Internal + public PlayerDeathEvent(final @NotNull Player player, final @NotNull DamageSource damageSource, final @NotNull List<ItemStack> drops, final int droppedExp, final int newExp, final @Nullable net.kyori.adventure.text.Component deathMessage) { + this(player, damageSource, drops, droppedExp, newExp, 0, 0, deathMessage); + } + + @org.jetbrains.annotations.ApiStatus.Internal + public PlayerDeathEvent(final @NotNull Player player, final @NotNull DamageSource damageSource, final @NotNull List<ItemStack> drops, final int droppedExp, final int newExp, final int newTotalExp, final int newLevel, final @Nullable net.kyori.adventure.text.Component deathMessage) { + super(player, damageSource, drops, droppedExp); + this.newExp = newExp; + this.newTotalExp = newTotalExp; + this.newLevel = newLevel; + this.deathMessage = deathMessage; + } + // Paper end - adventure + @Deprecated // Paper public PlayerDeathEvent(@NotNull final Player player, @NotNull DamageSource damageSource, @NotNull final List<ItemStack> drops, final int droppedExp, @Nullable final String deathMessage) { this(player, damageSource, drops, droppedExp, 0, deathMessage); } + @Deprecated // Paper public PlayerDeathEvent(@NotNull final Player player, @NotNull DamageSource damageSource, @NotNull final List<ItemStack> drops, final int droppedExp, final int newExp, @Nullable final String deathMessage) { this(player, damageSource, drops, droppedExp, newExp, 0, 0, deathMessage); } + @Deprecated // Paper public PlayerDeathEvent(@NotNull final Player player, @NotNull DamageSource damageSource, @NotNull final List<ItemStack> drops, final int droppedExp, final int newExp, final int newTotalExp, final int newLevel, @Nullable final String deathMessage) { super(player, damageSource, drops, droppedExp); this.newExp = newExp; this.newTotalExp = newTotalExp; this.newLevel = newLevel; - this.deathMessage = deathMessage; + this.deathMessage = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserializeOrNull(deathMessage); // Paper } @NotNull @@ -40,25 +63,49 @@ public class PlayerDeathEvent extends EntityDeathEvent { return (Player) entity; } + // Paper start - adventure + /** + * Set the death message that will appear to everyone on the server. + * + * @param deathMessage Component message to appear to other players on the server. + */ + public void deathMessage(final net.kyori.adventure.text.@Nullable Component deathMessage) { + this.deathMessage = deathMessage; + } + + /** + * Get the death message that will appear to everyone on the server. + * + * @return Component message to appear to other players on the server. + */ + public net.kyori.adventure.text.@Nullable Component deathMessage() { + return this.deathMessage; + } + // Paper end - adventure + /** * 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.deathMessage = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserializeOrNull(deathMessage); // 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 deathMessage; + return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serializeOrNull(this.deathMessage); // Paper } - + // Paper end /** * Gets how much EXP the Player should have at respawn. * <p> diff --git a/src/main/java/org/bukkit/event/inventory/InventoryType.java b/src/main/java/org/bukkit/event/inventory/InventoryType.java index 094963b16eccc303fb1a10b1e052feebe4a4d68b..3e6ac5beb137efd8ecd80e2e9b17015cb38e8a0a 100644 --- a/src/main/java/org/bukkit/event/inventory/InventoryType.java +++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java @@ -163,7 +163,18 @@ public enum InventoryType { private final String title; private final MenuType menuType; private final boolean isCreatable; + // Paper start + private final net.kyori.adventure.text.Component defaultTitleComponent; + /** + * Gets the inventory's default title. + * + * @return the inventory's default title + */ + public net.kyori.adventure.text.@NotNull Component defaultTitle() { + return defaultTitleComponent; + } + // Paper end private InventoryType(int defaultSize, /*@NotNull*/ String defaultTitle, @Nullable MenuType type) { this(defaultSize, defaultTitle, type, true); } @@ -173,6 +184,7 @@ public enum InventoryType { title = defaultTitle; this.menuType = type; this.isCreatable = isCreatable; + this.defaultTitleComponent = net.kyori.adventure.text.Component.text(defaultTitle); // Paper - Adventure } public int getDefaultSize() { @@ -180,6 +192,7 @@ public enum InventoryType { } @NotNull + @Deprecated // Paper public String getDefaultTitle() { return title; } diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerChatEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerChatEvent.java index 9c68c3f2d61500479f48b80264f625aaae2f3204..399afcd19fcb6acd24857ed6ab48cf0d105a01a3 100644 --- a/src/main/java/org/bukkit/event/player/AsyncPlayerChatEvent.java +++ b/src/main/java/org/bukkit/event/player/AsyncPlayerChatEvent.java @@ -22,7 +22,11 @@ import org.jetbrains.annotations.NotNull; * <p> * Care should be taken to check {@link #isAsynchronous()} and treat the event * appropriately. + * + * @deprecated use {@link io.papermc.paper.event.player.AsyncChatEvent} instead */ +@Deprecated // Paper +@org.bukkit.Warning(value = false, reason = "Don't nag on old event yet") // Paper public class AsyncPlayerChatEvent extends PlayerEvent implements Cancellable { private static final HandlerList handlers = new HandlerList(); private boolean cancel = false; diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java index 7ca90f318a013786931043c9a10a93cf6aede199..004f1fd55c143e6c21be74d0a6b9ee8b2e12cc59 100644 --- a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java +++ b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java @@ -10,11 +10,18 @@ import org.jetbrains.annotations.NotNull; * Stores details for players attempting to log in. * <p> * This event is asynchronous, and not run using main thread. + * <p> + * When this event is fired, the player's locale is not + * available. Therefore, any translatable component will be + * rendered with the default locale, {@link java.util.Locale#US}. + * <p> + * Consider rendering any translatable yourself with {@link net.kyori.adventure.translation.GlobalTranslator#render} + * if the client's language is known. */ public class AsyncPlayerPreLoginEvent extends Event { private static final HandlerList handlers = new HandlerList(); private Result result; - private String message; + private net.kyori.adventure.text.Component message; // Paper private final String name; private final InetAddress ipAddress; private final UUID uniqueId; @@ -33,7 +40,7 @@ public class AsyncPlayerPreLoginEvent extends Event { public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final UUID uniqueId, boolean transferred) { super(true); this.result = Result.ALLOWED; - this.message = ""; + this.message = net.kyori.adventure.text.Component.empty(); // Paper this.name = name; this.ipAddress = ipAddress; this.uniqueId = uniqueId; @@ -86,6 +93,7 @@ public class AsyncPlayerPreLoginEvent extends Event { this.result = result == null ? null : Result.valueOf(result.name()); } + // Paper start /** * Gets the current kick message that will be used if getResult() != * Result.ALLOWED @@ -93,7 +101,7 @@ public class AsyncPlayerPreLoginEvent extends Event { * @return Current kick message */ @NotNull - public String getKickMessage() { + public net.kyori.adventure.text.Component kickMessage() { return message; } @@ -102,16 +110,66 @@ public class AsyncPlayerPreLoginEvent extends Event { * * @param message New kick message */ - public void setKickMessage(@NotNull final String message) { + public void kickMessage(@NotNull final net.kyori.adventure.text.Component message) { + this.message = message; + } + + /** + * Disallows the player from logging in, with the given reason + * + * @param result New result for disallowing the player + * @param message Kick message to display to the user + */ + public void disallow(@NotNull final Result result, @NotNull final net.kyori.adventure.text.Component message) { + this.result = result; this.message = message; } + /** + * 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 This method uses a deprecated enum from {@link + * PlayerPreLoginEvent} + * @see #disallow(Result, String) + */ + @Deprecated + public void disallow(@NotNull final PlayerPreLoginEvent.Result result, @NotNull final net.kyori.adventure.text.Component message) { + this.result = result == null ? null : Result.valueOf(result.name()); + this.message = message; + } + // Paper end + /** + * Gets the current kick message that will be used if getResult() != + * Result.ALLOWED + * + * @return Current kick message + * @deprecated in favour of {@link #kickMessage()} + */ + @NotNull + @Deprecated // Paper + public String getKickMessage() { + return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.message); // Paper + } + + /** + * Sets the kick message to display if getResult() != Result.ALLOWED + * + * @param message New kick message + * @deprecated in favour of {@link #kickMessage(net.kyori.adventure.text.Component)} + */ + @Deprecated // Paper + public void setKickMessage(@NotNull final String message) { + this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper + } + /** * Allows the player to log in */ public void allow() { result = Result.ALLOWED; - message = ""; + message = net.kyori.adventure.text.Component.empty(); // Paper } /** @@ -119,10 +177,12 @@ public class AsyncPlayerPreLoginEvent extends Event { * * @param result New result for disallowing the player * @param message Kick message to display to the user + * @deprecated in favour of {@link #disallow(org.bukkit.event.player.AsyncPlayerPreLoginEvent.Result, net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void disallow(@NotNull final Result result, @NotNull final String message) { this.result = result; - this.message = message; + this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper } /** @@ -137,7 +197,7 @@ public class AsyncPlayerPreLoginEvent extends Event { @Deprecated public void disallow(@NotNull final PlayerPreLoginEvent.Result result, @NotNull final String message) { this.result = result == null ? null : Result.valueOf(result.name()); - this.message = message; + this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper } /** diff --git a/src/main/java/org/bukkit/event/player/PlayerChatEvent.java b/src/main/java/org/bukkit/event/player/PlayerChatEvent.java index a1f4261eaa1497554f1e51d1d5a072c2eb9226df..2c021bc2ff18f0b3af5feb9dafc8ccebd604f8b5 100644 --- a/src/main/java/org/bukkit/event/player/PlayerChatEvent.java +++ b/src/main/java/org/bukkit/event/player/PlayerChatEvent.java @@ -12,12 +12,7 @@ import org.jetbrains.annotations.NotNull; /** * Holds information for player chat and commands * - * @deprecated This event will fire from the main thread and allows the use of - * all of the Bukkit API, unlike the {@link AsyncPlayerChatEvent}. - * <p> - * Listening to this event forces chat to wait for the main thread which - * causes delays for chat. {@link AsyncPlayerChatEvent} is the encouraged - * alternative for thread safe implementations. + * @deprecated Listening to this event forces chat to wait for the main thread, delaying chat messages. It is recommended to use {@link io.papermc.paper.event.player.AsyncChatEvent} instead, wherever possible. */ @Deprecated @Warning(reason = "Listening to this event forces chat to wait for the main thread, delaying chat messages.") diff --git a/src/main/java/org/bukkit/event/player/PlayerEvent.java b/src/main/java/org/bukkit/event/player/PlayerEvent.java index 793b661b6d2d05de3d7f4fc26a4c018a2af58e62..f6d3b817de3001f04ea4554c7c39a1290af3fd6d 100644 --- a/src/main/java/org/bukkit/event/player/PlayerEvent.java +++ b/src/main/java/org/bukkit/event/player/PlayerEvent.java @@ -14,7 +14,7 @@ public abstract class PlayerEvent extends Event { player = who; } - PlayerEvent(@NotNull final Player who, boolean async) { + public PlayerEvent(@NotNull final Player who, boolean async) { // Paper - public super(async); player = who; diff --git a/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java b/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java index d06684aba7688ce06777dbd837a46856a9d7767f..3e1e7cd0415509da4dd887db59efa55011b1dab4 100644 --- a/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java +++ b/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java @@ -10,30 +10,60 @@ import org.jetbrains.annotations.Nullable; */ public class PlayerJoinEvent extends PlayerEvent { private static final HandlerList handlers = new HandlerList(); - private 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; + } + @Deprecated // Paper end 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 + */ + public net.kyori.adventure.text.@Nullable Component joinMessage() { + return this.joinMessage; + } + + /** + * Sets the join message to send to all online players + * + * @param joinMessage join message. If null, no message will be sent + */ + public void joinMessage(net.kyori.adventure.text.@Nullable Component joinMessage) { this.joinMessage = joinMessage; } + // Paper end /** * Gets the join message to send to all online players * * @return string join message. Can be null + * @deprecated in favour of {@link #joinMessage()} */ @Nullable + @Deprecated // Paper public String getJoinMessage() { - return joinMessage; + return this.joinMessage == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.joinMessage); // Paper } /** * Sets the join message to send to all online players * * @param joinMessage join message. If null, no message will be sent + * @deprecated in favour of {@link #joinMessage(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void setJoinMessage(@Nullable String joinMessage) { - this.joinMessage = joinMessage; + this.joinMessage = joinMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(joinMessage) : null; // Paper } @NotNull diff --git a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java b/src/main/java/org/bukkit/event/player/PlayerKickEvent.java index 2f6ca42330675733b2b4132cbb66e433788d05d5..997b06c19a5277656521e0e298f2958c209f1da1 100644 --- a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java +++ b/src/main/java/org/bukkit/event/player/PlayerKickEvent.java @@ -10,35 +10,84 @@ import org.jetbrains.annotations.NotNull; */ public class PlayerKickEvent extends PlayerEvent implements Cancellable { private static final HandlerList handlers = new HandlerList(); - private String leaveMessage; - private String kickReason; + private net.kyori.adventure.text.Component leaveMessage; // Paper + private net.kyori.adventure.text.Component kickReason; // Paper private boolean cancel; + @Deprecated // Paper public PlayerKickEvent(@NotNull final Player playerKicked, @NotNull final String kickReason, @NotNull final String leaveMessage) { + super(playerKicked); + this.kickReason = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(kickReason); // Paper + this.leaveMessage = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(leaveMessage); // Paper + this.cancel = false; + } + // Paper start + public PlayerKickEvent(@NotNull final Player playerKicked, @NotNull final net.kyori.adventure.text.Component kickReason, @NotNull final net.kyori.adventure.text.Component leaveMessage) { super(playerKicked); this.kickReason = kickReason; this.leaveMessage = leaveMessage; this.cancel = false; } + /** + * Gets the leave message send to all online players + * + * @return string kick reason + */ + public net.kyori.adventure.text.@NotNull Component leaveMessage() { + return this.leaveMessage; + } + + /** + * Sets the leave message send to all online players + * + * @param leaveMessage leave message + */ + public void leaveMessage(net.kyori.adventure.text.@NotNull Component leaveMessage) { + this.leaveMessage = leaveMessage; + } + /** * Gets the reason why the player is getting kicked * * @return string kick reason */ + public net.kyori.adventure.text.@NotNull Component reason() { + return this.kickReason; + } + + /** + * Sets the reason why the player is getting kicked + * + * @param kickReason kick reason + */ + public void reason(net.kyori.adventure.text.@NotNull Component kickReason) { + this.kickReason = kickReason; + } + // Paper end + + /** + * Gets the reason why the player is getting kicked + * + * @return string kick reason + * @deprecated in favour of {@link #reason()} + */ @NotNull + @Deprecated // Paper public String getReason() { - return kickReason; + return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.kickReason); // Paper } /** * Gets the leave message send to all online players * * @return string kick reason + * @deprecated in favour of {@link #leaveMessage()} */ @NotNull + @Deprecated // Paper public String getLeaveMessage() { - return leaveMessage; + return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.leaveMessage); // Paper } @Override @@ -55,18 +104,22 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable { * Sets the reason why the player is getting kicked * * @param kickReason kick reason + * @deprecated in favour of {@link #reason(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void setReason(@NotNull String kickReason) { - this.kickReason = kickReason; + this.kickReason = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(kickReason); // Paper } /** * Sets the leave message send to all online players * * @param leaveMessage leave message + * @deprecated in favour of {@link #leaveMessage(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void setLeaveMessage(@NotNull String leaveMessage) { - this.leaveMessage = leaveMessage; + this.leaveMessage = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(leaveMessage); // Paper } @NotNull diff --git a/src/main/java/org/bukkit/event/player/PlayerLocaleChangeEvent.java b/src/main/java/org/bukkit/event/player/PlayerLocaleChangeEvent.java index 36b436e145a7215682b692a87ab894df25752c1d..dc6b41950570c3a8b02415dd9017b2336e6e7f0c 100644 --- a/src/main/java/org/bukkit/event/player/PlayerLocaleChangeEvent.java +++ b/src/main/java/org/bukkit/event/player/PlayerLocaleChangeEvent.java @@ -12,17 +12,31 @@ public class PlayerLocaleChangeEvent extends PlayerEvent { private static final HandlerList handlers = new HandlerList(); // private final String locale; + // Paper start + private final java.util.Locale adventure$locale; + /** + * @see Player#locale() + * + * @return the player's new locale + */ + public @NotNull java.util.Locale locale() { + return this.adventure$locale; + } + // Paper end public PlayerLocaleChangeEvent(@NotNull Player who, @NotNull String locale) { super(who); this.locale = locale; + this.adventure$locale = java.util.Objects.requireNonNullElse(net.kyori.adventure.translation.Translator.parseLocale(locale), java.util.Locale.US); // Paper start } /** * @return the player's new locale * @see Player#getLocale() + * @deprecated in favour of {@link #locale()} */ @NotNull + @Deprecated // Paper public String getLocale() { return locale; } diff --git a/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java b/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java index 2bc81b0aa73f7f5b0352121f6bf18fa63acf7a83..eaa0548cf430bf5b58ff84e0a4403c451699db28 100644 --- a/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java +++ b/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java @@ -18,7 +18,7 @@ public class PlayerLoginEvent extends PlayerEvent { private final InetAddress realAddress; private final String hostname; private Result result = Result.ALLOWED; - private String message = ""; + private net.kyori.adventure.text.Component message = net.kyori.adventure.text.Component.empty(); /** * This constructor defaults message to an empty string, and result to @@ -60,13 +60,53 @@ public class PlayerLoginEvent extends PlayerEvent { * @param result The result status for this event * @param message The message to be displayed if result denies login * @param realAddress the actual, unspoofed connecting address + * @deprecated in favour of {@link #PlayerLoginEvent(Player, String, InetAddress, Result, net.kyori.adventure.text.Component, InetAddress)} */ + @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) { this(player, hostname, address, realAddress); this.result = result; + this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper + } + + // Paper start + /** + * This constructor pre-configures the event with a result and message + * + * @param player The {@link Player} for this event + * @param hostname The hostname that was used to connect to the server + * @param address The address the player used to connect, provided for + * timing issues + * @param result The result status for this event + * @param message The message to be displayed if result denies login + * @param realAddress the actual, unspoofed connecting address + */ + 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) { + 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 net.kyori.adventure.text.@NotNull Component kickMessage() { + return this.message; + } + + /** + * Sets the kick message to display if getResult() != Result.ALLOWED + * + * @param message New kick message + */ + public void kickMessage(net.kyori.adventure.text.@NotNull Component message) { + this.message = message; + } + // Paper end + /** * Gets the current result of the login, as an enum * @@ -91,19 +131,23 @@ public class PlayerLoginEvent extends PlayerEvent { * Result.ALLOWED * * @return Current kick message + * @deprecated in favour of {@link #kickMessage()} */ @NotNull + @Deprecated // Paper public String getKickMessage() { - return message; + return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.message); // Paper } /** * Sets the kick message to display if getResult() != Result.ALLOWED * * @param message New kick message + * @deprecated in favour of {@link #kickMessage(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void setKickMessage(@NotNull final String message) { - this.message = message; + this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper } /** @@ -122,7 +166,7 @@ public class PlayerLoginEvent extends PlayerEvent { */ public void allow() { result = Result.ALLOWED; - message = ""; + message = net.kyori.adventure.text.Component.empty(); // Paper } /** @@ -130,8 +174,21 @@ public class PlayerLoginEvent extends PlayerEvent { * * @param result New result for disallowing the player * @param message Kick message to display to the user + * @deprecated in favour of {@link #disallow(Result, net.kyori.adventure.text.Component)} */ + @Deprecated // Paper start 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); + } + /** + * Disallows the player from logging in, with the given reason + * + * @param result New result for disallowing the player + * @param message Kick message to display to the user + */ + public void disallow(@NotNull final Result result, @NotNull final net.kyori.adventure.text.Component message) { + // Paper end this.result = result; this.message = message; } diff --git a/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java index fb066251f793ec3b41bfc075b9478901b15ee549..175ed12dd1698f4d153c9acdac8340c15a427ea5 100644 --- a/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java +++ b/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java @@ -9,6 +9,13 @@ import org.jetbrains.annotations.NotNull; /** * Stores details for players attempting to log in + * <p> + * When this event is fired, the player's locale is not + * available. Therefore, any translatable component will be + * rendered with the default locale, {@link java.util.Locale#US}. + * <p> + * Consider rendering any translatable yourself with {@link net.kyori.adventure.translation.GlobalTranslator#render} + * if the client's language is known. * * @deprecated This event causes synchronization from the login thread; {@link * AsyncPlayerPreLoginEvent} is preferred to keep the secondary threads @@ -19,7 +26,7 @@ import org.jetbrains.annotations.NotNull; public class PlayerPreLoginEvent extends Event { private static final HandlerList handlers = new HandlerList(); private Result result; - private String message; + private net.kyori.adventure.text.Component message; // Paper private final String name; private final InetAddress ipAddress; private final UUID uniqueId; @@ -31,7 +38,7 @@ public class PlayerPreLoginEvent extends Event { public PlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final UUID uniqueId) { this.result = Result.ALLOWED; - this.message = ""; + this.message = net.kyori.adventure.text.Component.empty(); // Paper this.name = name; this.ipAddress = ipAddress; this.uniqueId = uniqueId; @@ -56,6 +63,7 @@ public class PlayerPreLoginEvent extends Event { this.result = result; } + // Paper start /** * Gets the current kick message that will be used if getResult() != * Result.ALLOWED @@ -63,7 +71,7 @@ public class PlayerPreLoginEvent extends Event { * @return Current kick message */ @NotNull - public String getKickMessage() { + public net.kyori.adventure.text.Component kickMessage() { return message; } @@ -72,16 +80,51 @@ public class PlayerPreLoginEvent extends Event { * * @param message New kick message */ - public void setKickMessage(@NotNull final String message) { + public void kickMessage(@NotNull final net.kyori.adventure.text.Component message) { this.message = message; } + /** + * Disallows the player from logging in, with the given reason + * + * @param result New result for disallowing the player + * @param message Kick message to display to the user + */ + public void disallow(@NotNull final Result result, @NotNull final net.kyori.adventure.text.Component message) { + this.result = result; + this.message = message; + } + // Paper end + /** + * Gets the current kick message that will be used if getResult() != + * Result.ALLOWED + * + * @return Current kick message + * @deprecated in favour of {@link #kickMessage()} + */ + @Deprecated // Paper + @NotNull + public String getKickMessage() { + return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.message); // Paper + } + + /** + * Sets the kick message to display if getResult() != Result.ALLOWED + * + * @param message New kick message + * @deprecated in favour of {@link #kickMessage(net.kyori.adventure.text.Component)} + */ + @Deprecated // Paper + public void setKickMessage(@NotNull final String message) { + this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper + } + /** * Allows the player to log in */ public void allow() { result = Result.ALLOWED; - message = ""; + message = net.kyori.adventure.text.Component.empty(); // Paper } /** @@ -89,10 +132,12 @@ public class PlayerPreLoginEvent extends Event { * * @param result New result for disallowing the player * @param message Kick message to display to the user + * @deprecated in favour of {@link #disallow(org.bukkit.event.player.PlayerPreLoginEvent.Result, net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void disallow(@NotNull final Result result, @NotNull final String message) { this.result = result; - this.message = message; + this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper } /** diff --git a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java index d70c25f404e994766a9ebce89a917c8d0719777c..14b27eaaf744736b3e56bb1383481df98a218c43 100644 --- a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java +++ b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java @@ -10,30 +10,59 @@ import org.jetbrains.annotations.Nullable; */ public class PlayerQuitEvent extends PlayerEvent { private static final HandlerList handlers = new HandlerList(); - private String quitMessage; + private net.kyori.adventure.text.Component quitMessage; // Paper + @Deprecated // Paper public PlayerQuitEvent(@NotNull final Player who, @Nullable final String quitMessage) { 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; + } + + /** + * Gets the quit message to send to all online players + * + * @return string quit message + */ + public net.kyori.adventure.text.@Nullable Component quitMessage() { + return quitMessage; + } + + /** + * Sets the quit message to send to all online players + * + * @param quitMessage quit message + */ + public void quitMessage(net.kyori.adventure.text.@Nullable Component quitMessage) { this.quitMessage = quitMessage; } + // Paper end /** * Gets the quit message to send to all online players * * @return string quit message + * @deprecated in favour of {@link #quitMessage()} */ @Nullable + @Deprecated // Paper public String getQuitMessage() { - return quitMessage; + return this.quitMessage == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.quitMessage); // Paper } /** * Sets the quit message to send to all online players * * @param quitMessage quit message + * @deprecated in favour of {@link #quitMessage(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void setQuitMessage(@Nullable String quitMessage) { - this.quitMessage = quitMessage; + this.quitMessage = quitMessage != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(quitMessage) : null; // Paper } @NotNull diff --git a/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java b/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java index 03bfca9d368bbe4b7c1353d52c883e756bf69bda..25c0fe98489d903fdf77cbdd181c95593bd7f727 100644 --- a/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java +++ b/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java @@ -9,16 +9,16 @@ import org.jetbrains.annotations.NotNull; /** * Event triggered for server broadcast messages such as from - * {@link org.bukkit.Server#broadcast(String, String)}. + * {@link org.bukkit.Server#broadcast(net.kyori.adventure.text.Component)} (String, String)}. * - * <b>This event behaves similarly to {@link AsyncPlayerChatEvent} in that it + * <b>This event behaves similarly to {@link io.papermc.paper.event.player.AsyncChatEvent} in that it * should be async if fired from an async thread. Please see that event for * further information.</b> */ public class BroadcastMessageEvent extends ServerEvent implements Cancellable { private static final HandlerList handlers = new HandlerList(); - private String message; + private net.kyori.adventure.text.Component message; // Paper private final Set<CommandSender> recipients; private boolean cancelled = false; @@ -27,29 +27,66 @@ public class BroadcastMessageEvent extends ServerEvent implements Cancellable { this(false, message, recipients); } + @Deprecated // Paper public BroadcastMessageEvent(boolean isAsync, @NotNull String message, @NotNull Set<CommandSender> recipients) { + // Paper start + super(isAsync); + this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); + this.recipients = recipients; + } + + @Deprecated + public BroadcastMessageEvent(net.kyori.adventure.text.@NotNull Component message, @NotNull Set<CommandSender> recipients) { + this(false, message, recipients); + } + + public BroadcastMessageEvent(boolean isAsync, net.kyori.adventure.text.@NotNull Component message, @NotNull Set<CommandSender> recipients) { + // Paper end super(isAsync); this.message = message; this.recipients = recipients; } + // Paper start + /** + * Get the broadcast message. + * + * @return Message to broadcast + */ + public net.kyori.adventure.text.@NotNull Component message() { + return this.message; + } + + /** + * Set the broadcast message. + * + * @param message New message to broadcast + */ + public void message(net.kyori.adventure.text.@NotNull Component message) { + this.message = message; + } + // Paper end /** * Get the message to broadcast. * * @return Message to broadcast + * @deprecated in favour of {@link #message()} */ @NotNull + @Deprecated // Paper public String getMessage() { - return message; + return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.message); // Paper } /** * Set the message to broadcast. * * @param message New message to broadcast + * @deprecated in favour of {@link #message(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void setMessage(@NotNull String message) { - this.message = message; + this.message = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(message); // Paper } /** diff --git a/src/main/java/org/bukkit/event/server/ServerListPingEvent.java b/src/main/java/org/bukkit/event/server/ServerListPingEvent.java index 5adbe0514129abf3cfbc4b29a213f522359fe2e1..72ebc29db42d08d1d0361dba462fc8a573fbf918 100644 --- a/src/main/java/org/bukkit/event/server/ServerListPingEvent.java +++ b/src/main/java/org/bukkit/event/server/ServerListPingEvent.java @@ -22,7 +22,7 @@ public class ServerListPingEvent extends ServerEvent implements Iterable<Player> private static final HandlerList handlers = new HandlerList(); private final String hostname; private final InetAddress address; - private String motd; + private net.kyori.adventure.text.Component motd; // Paper private final int numPlayers; private int maxPlayers; @@ -31,7 +31,7 @@ public class ServerListPingEvent extends ServerEvent implements Iterable<Player> Preconditions.checkArgument(numPlayers >= 0, "Cannot have negative number of players online", numPlayers); this.hostname = hostname; this.address = address; - this.motd = motd; + this.motd = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(motd); // Paper this.numPlayers = numPlayers; this.maxPlayers = maxPlayers; } @@ -45,15 +45,80 @@ public class ServerListPingEvent extends ServerEvent implements Iterable<Player> * @param address the address of the pinger * @param motd the message of the day * @param maxPlayers the max number of players + * @deprecated in favour of {@link #ServerListPingEvent(String, java.net.InetAddress, net.kyori.adventure.text.Component, int)} */ + @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.motd = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(motd); // Paper + this.maxPlayers = maxPlayers; + } + // Paper start + @Deprecated + public ServerListPingEvent(@NotNull final InetAddress address, @NotNull final net.kyori.adventure.text.Component motd, final int numPlayers, final int maxPlayers) { + this("", address, motd, numPlayers, maxPlayers); + } + public ServerListPingEvent(@NotNull final String hostname, @NotNull final InetAddress address, @NotNull final net.kyori.adventure.text.Component motd, final int numPlayers, final int maxPlayers) { + super(true); + Preconditions.checkArgument(numPlayers >= 0, "Cannot have negative number of players online (%s)", numPlayers); + this.hostname = hostname; + this.address = address; this.motd = motd; + this.numPlayers = numPlayers; this.maxPlayers = maxPlayers; } + /** + * This constructor is intended for implementations that provide the + * {@link #iterator()} method, thus provided the {@link #getNumPlayers()} + * count. + * + * @param address the address of the pinger + * @param motd the message of the day + * @param maxPlayers the max number of players + * @deprecated in favour of {@link #ServerListPingEvent(String, java.net.InetAddress, net.kyori.adventure.text.Component, int)} + */ + @Deprecated + protected ServerListPingEvent(@NotNull final InetAddress address, @NotNull final net.kyori.adventure.text.Component motd, final int maxPlayers) { + this("", address, motd, maxPlayers); + } + + /** + * This constructor is intended for implementations that provide the + * {@link #iterator()} method, thus provided the {@link #getNumPlayers()} + * count. + * + * @param hostname The hostname that was used to connect to the server + * @param address the address of the pinger + * @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 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 net.kyori.adventure.text.@NotNull Component motd() { + return motd; + } + /** + * Change the message of the day message. + * + * @param motd the message of the day + */ + public void motd(net.kyori.adventure.text.@NotNull Component motd) { + this.motd = motd; + } + // Paper end /** * Gets the hostname that the player used to connect to the server, or @@ -80,19 +145,23 @@ public class ServerListPingEvent extends ServerEvent implements Iterable<Player> * Get the message of the day message. * * @return the message of the day + * @deprecated in favour of {@link #motd()} */ @NotNull + @Deprecated // Paper public String getMotd() { - return motd; + return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.motd); // Paper } /** * Change the message of the day message. * * @param motd the message of the day + * @deprecated in favour of {@link #motd(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void setMotd(@NotNull String motd) { - this.motd = motd; + this.motd = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(motd); // Paper } /** diff --git a/src/main/java/org/bukkit/inventory/InventoryView.java b/src/main/java/org/bukkit/inventory/InventoryView.java index 278259e211b926283ee6dfef6f96e11ddbcbf275..ebc14022c9ef9b0b3331ee53e96a32667e4762e0 100644 --- a/src/main/java/org/bukkit/inventory/InventoryView.java +++ b/src/main/java/org/bukkit/inventory/InventoryView.java @@ -269,12 +269,26 @@ public interface InventoryView { */ public boolean setProperty(@NotNull Property prop, int value); + // Paper start /** * Get the title of this inventory window. * * @return The title. */ @NotNull + default net.kyori.adventure.text.Component title() { + return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(this.getTitle()); + } + // Paper end + + /** + * Get the title of this inventory window. + * + * @return The title. + * @deprecated in favour of {@link #title()} + */ + @Deprecated // Paper + @NotNull public String getTitle(); /** diff --git a/src/main/java/org/bukkit/inventory/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java index aa7fcae0de70aa5c10a331dfb076efd2f2c64065..d5342258086066d3b9ef404916bad8440f0cf0cd 100644 --- a/src/main/java/org/bukkit/inventory/ItemFactory.java +++ b/src/main/java/org/bukkit/inventory/ItemFactory.java @@ -200,4 +200,24 @@ public interface ItemFactory { */ @NotNull ItemStack enchantItem(@NotNull final ItemStack item, final int level, final boolean allowTreasures); + + // Paper start - Adventure + /** + * Creates a hover event for the given item. + * + * @param item The item + * @return A hover event + */ + @NotNull + net.kyori.adventure.text.event.HoverEvent<net.kyori.adventure.text.event.HoverEvent.ShowItem> asHoverEvent(final @NotNull ItemStack item, final @NotNull java.util.function.UnaryOperator<net.kyori.adventure.text.event.HoverEvent.ShowItem> op); + + /** + * Get the formatted display name of the {@link ItemStack}. + * + * @param itemStack the {@link ItemStack} + * @return display name of the {@link ItemStack} + */ + @NotNull + net.kyori.adventure.text.Component displayName(@NotNull ItemStack itemStack); + // Paper end - Adventure } diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java index eade62328895133c026e7e678e648e1fc846f5ee..730c42eddd38acec1cdbb19dfc8c675795d1e68d 100644 --- a/src/main/java/org/bukkit/inventory/ItemStack.java +++ b/src/main/java/org/bukkit/inventory/ItemStack.java @@ -26,7 +26,7 @@ import org.jetbrains.annotations.Nullable; * use this class to encapsulate Materials for which {@link Material#isItem()} * returns false.</b> */ -public class ItemStack implements Cloneable, ConfigurationSerializable, Translatable { +public class ItemStack implements Cloneable, ConfigurationSerializable, Translatable, net.kyori.adventure.text.event.HoverEventSource<net.kyori.adventure.text.event.HoverEvent.ShowItem> { // Paper private Material type = Material.AIR; private int amount = 0; private MaterialData data = null; @@ -626,4 +626,21 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat public String getTranslationKey() { return Bukkit.getUnsafe().getTranslationKey(this); } + + // Paper start + @NotNull + @Override + public net.kyori.adventure.text.event.HoverEvent<net.kyori.adventure.text.event.HoverEvent.ShowItem> asHoverEvent(final @NotNull java.util.function.UnaryOperator<net.kyori.adventure.text.event.HoverEvent.ShowItem> op) { + return org.bukkit.Bukkit.getServer().getItemFactory().asHoverEvent(this, op); + } + + /** + * Get the formatted display name of the {@link ItemStack}. + * + * @return display name of the {@link ItemStack} + */ + public net.kyori.adventure.text.@NotNull Component displayName() { + return Bukkit.getServer().getItemFactory().displayName(this); + } + // Paper end } diff --git a/src/main/java/org/bukkit/inventory/MenuType.java b/src/main/java/org/bukkit/inventory/MenuType.java index 45d3889206fb3b7a7303490b8d4e67ede2aae7a4..34d45a105da72481a7c4f2e3831f5d2a676c91c6 100644 --- a/src/main/java/org/bukkit/inventory/MenuType.java +++ b/src/main/java/org/bukkit/inventory/MenuType.java @@ -145,11 +145,45 @@ public interface MenuType extends Keyed { * @param player the player the view belongs to * @param title the title of the view * @return the created {@link InventoryView} + * @deprecated Use {@link #create(HumanEntity, net.kyori.adventure.text.Component)} instead. */ @NotNull + @Deprecated(since = "1.21") // Paper - adventure V create(@NotNull HumanEntity player, @NotNull String title); + + // Paper start - adventure + /** + * Creates a view of the specified menu type. + * <p> + * The player provided to create this view must be the player the view + * is opened for. See {@link HumanEntity#openInventory(InventoryView)} + * for more information. + * + * @param player the player the view belongs to + * @param title the title of the view + * @return the created {@link InventoryView} + */ + @NotNull + V create(@NotNull HumanEntity player, @NotNull net.kyori.adventure.text.Component title); + // Paper end - adventure } + // Paper start - adventure + /** + * Creates a view of the specified menu type. + * <p> + * The player provided to create this view must be the player the view + * is opened for. See {@link HumanEntity#openInventory(InventoryView)} + * for more information. + * + * @param player the player the view belongs to + * @param title the title of the view + * @return the created {@link InventoryView} + */ + @NotNull + InventoryView create(@NotNull HumanEntity player, @NotNull net.kyori.adventure.text.Component title); + // Paper end - adventure + /** * Yields this MenuType as a typed version of itself with a plain * {@link InventoryView} representing it. diff --git a/src/main/java/org/bukkit/inventory/meta/BookMeta.java b/src/main/java/org/bukkit/inventory/meta/BookMeta.java index 9bab73c3c2ca759b8e1c7d07d98cc593c961666a..f0c6943da3f783101ca647b75b3230fae3a310da 100644 --- a/src/main/java/org/bukkit/inventory/meta/BookMeta.java +++ b/src/main/java/org/bukkit/inventory/meta/BookMeta.java @@ -7,10 +7,15 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** - * Represents a {@link Material#WRITTEN_BOOK}) that can have a title, an author, + * Represents a {@link Material#WRITTEN_BOOK} that can have a title, an author, * and pages. + * <p> + * Before using this type, make sure to check the itemstack's material with + * {@link org.bukkit.inventory.ItemStack#getType()}. {@code instanceof} on + * the meta instance is not sufficient due to unusual inheritance + * with relation to {@link WritableBookMeta}. */ -public interface BookMeta extends WritableBookMeta { +public interface BookMeta extends WritableBookMeta, net.kyori.adventure.inventory.Book { // Paper - adventure /** * Represents the generation (or level of copying) of a written book @@ -116,6 +121,153 @@ public interface BookMeta extends WritableBookMeta { @NotNull BookMeta clone(); + // Paper start - adventure + //<editor-fold desc="deprecations" defaultstate="collapsed"> + /** + * @deprecated use {@link #page(int)} + */ + @Deprecated + @Override + @NotNull String getPage(int page); + + /** + * @deprecated use {@link #page(int, net.kyori.adventure.text.Component)} + */ + @Deprecated + @Override + void setPage(int page, @NotNull String data); + + /** + * @deprecated use {@link #pages()} + */ + @Deprecated + @Override + @NotNull List<String> getPages(); + + /** + * @deprecated use {@link #pages(List)} + */ + @Deprecated + @Override + void setPages(@NotNull List<String> pages); + + /** + * @deprecated use {@link #pages(net.kyori.adventure.text.Component...)} + */ + @Deprecated + @Override + void setPages(@NotNull String... pages); + + /** + * @deprecated use {@link #addPages(net.kyori.adventure.text.Component...)} + */ + @Deprecated + @Override + void addPage(@NotNull String... pages); + //</editor-fold> + + /** + * Gets the title of the book. + * <p> + * Plugins should check that hasTitle() returns true before calling this + * method. + * + * @return the title of the book + */ + @Override + net.kyori.adventure.text.@Nullable Component title(); + + /** + * Sets the title of the book. + * <p> + * Limited to 32 characters. Removes title when given null. + * + * @param title the title to set + * @return the same {@link BookMeta} instance + */ + @org.jetbrains.annotations.Contract(value = "_ -> this", pure = false) + @Override + @NotNull BookMeta title(net.kyori.adventure.text.@Nullable Component title); + + /** + * Gets the author of the book. + * <p> + * Plugins should check that hasAuthor() returns true before calling this + * method. + * + * @return the author of the book + */ + @Override + net.kyori.adventure.text.@Nullable Component author(); + + /** + * Sets the author of the book. Removes author when given null. + * + * @param author the author to set + * @return the same {@link BookMeta} instance + */ + @org.jetbrains.annotations.Contract(value = "_ -> this", pure = false) + @Override + @NotNull BookMeta author(net.kyori.adventure.text.@Nullable Component author); + + + /** + * Gets the specified page in the book. The page must exist. + * <p> + * Pages are 1-indexed. + * + * @param page the page number to get, in range [1, getPageCount()] + * @return the page from the book + */ + net.kyori.adventure.text.@NotNull Component page(int page); + + /** + * Sets the specified page in the book. Pages of the book must be + * contiguous. + * <p> + * The data can be up to 1024 characters in length, additional characters + * are truncated. + * <p> + * Pages are 1-indexed. + * + * @param page the page number to set, in range [1, getPageCount()] + * @param data the data to set for that page + */ + void page(int page, net.kyori.adventure.text.@NotNull Component data); + + /** + * Adds new pages to the end of the book. Up to a maximum of 100 pages with + * 1024 characters per page. + * + * @param pages A list of strings, each being a page + */ + void addPages(net.kyori.adventure.text.@NotNull Component @NotNull ... pages); + + interface BookMetaBuilder extends net.kyori.adventure.inventory.Book.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<net.kyori.adventure.text.Component> pages); + + @Override + @NotNull BookMeta build(); + } + + @Override + @NotNull BookMetaBuilder toBuilder(); + // Paper end + // Spigot start public class Spigot { @@ -124,8 +276,10 @@ public interface BookMeta extends WritableBookMeta { * * @param page the page number to get * @return the page from the book + * @deprecated in favour of {@link #page(int)} */ @NotNull + @Deprecated // Paper public BaseComponent[] getPage(int page) { throw new UnsupportedOperationException("Not supported yet."); } @@ -139,7 +293,9 @@ public interface BookMeta extends WritableBookMeta { * * @param page the page number to set * @param data the data to set for that page + * @deprecated in favour of {@link #page(int, net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void setPage(int page, @Nullable BaseComponent... data) { throw new UnsupportedOperationException("Not supported yet."); } @@ -148,8 +304,10 @@ public interface BookMeta extends WritableBookMeta { * 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 public List<BaseComponent[]> getPages() { throw new UnsupportedOperationException("Not supported yet."); } @@ -159,7 +317,9 @@ public interface BookMeta extends WritableBookMeta { * pages. Maximum 50 pages with 256 characters per page. * * @param pages A list of pages to set the book to use + * @deprecated in favour of {@link #pages(java.util.List)} */ + @Deprecated // Paper public void setPages(@NotNull List<BaseComponent[]> pages) { throw new UnsupportedOperationException("Not supported yet."); } @@ -169,7 +329,9 @@ public interface BookMeta extends WritableBookMeta { * pages. Maximum 50 pages with 256 characters per page. * * @param pages A list of component arrays, each being a page + * @deprecated in favour of {@link #pages(net.kyori.adventure.text.Component...)} */ + @Deprecated // Paper public void setPages(@NotNull BaseComponent[]... pages) { throw new UnsupportedOperationException("Not supported yet."); } @@ -179,7 +341,9 @@ public interface BookMeta extends WritableBookMeta { * with 256 characters per page. * * @param pages A list of component arrays, each being a page + * @deprecated in favour of {@link #addPages(net.kyori.adventure.text.Component...)} */ + @Deprecated // Paper public void addPage(@NotNull BaseComponent[]... pages) { throw new UnsupportedOperationException("Not supported yet."); } diff --git a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java index 1d810042652dac9c35dd358f9d87e3dd2cebc48e..fabddfe3763e143b5a769764cb324f97876ccb1c 100644 --- a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java +++ b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java @@ -44,6 +44,24 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste */ boolean hasDisplayName(); + // Paper start + /** + * Gets the display name. + * + * <p>Plugins should check that {@link #hasDisplayName()} returns <code>true</code> before calling this method.</p> + * + * @return the display name + */ + net.kyori.adventure.text.@Nullable Component displayName(); + + /** + * Sets the display name. + * + * @param displayName the display name to set + */ + void displayName(final net.kyori.adventure.text.@Nullable Component displayName); + // Paper end + /** * Gets the display name that is set. * <p> @@ -51,7 +69,9 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste * before calling this method. * * @return the display name that is set + * @deprecated in favour of {@link #displayName()} */ + @Deprecated // Paper @NotNull String getDisplayName(); @@ -59,7 +79,9 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste * Sets the display name. * * @param name the name to set + * @deprecated in favour of {@link #displayName(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper void setDisplayName(@Nullable String name); /** @@ -72,6 +94,32 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste */ boolean hasItemName(); + // Paper start + /** + * Gets the item name component that is set. + * <br> + * Item name differs from display name in that it is cannot be edited by an + * anvil, is not styled with italics, and does not show labels. + * <p> + * Plugins should check that {@link #hasItemName()} returns <code>true</code> before + * calling this method. + * + * @return the item name that is set + * @see #hasItemName() + */ + @org.jetbrains.annotations.NotNull + Component itemName(); + + /** + * Sets the item name. + * <br> + * Item name differs from display name in that it is cannot be edited by an + * anvil, is not styled with italics, and does not show labels. + * + * @param name the name to set, null to remove it + */ + void itemName(@Nullable final Component name); + // Paper end /** * Gets the item name that is set. * <br> @@ -82,7 +130,9 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste * calling this method. * * @return the item name that is set + * @deprecated in favour of {@link #itemName()} */ + @Deprecated // Paper @NotNull String getItemName(); @@ -93,7 +143,9 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste * anvil, is not styled with italics, and does not show labels. * * @param name the name to set + * @deprecated in favour of {@link #itemName(Component)} */ + @Deprecated // Paper void setItemName(@Nullable String name); /** @@ -134,6 +186,24 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste */ boolean hasLore(); + // Paper start + /** + * Gets the lore. + * + * <p>Plugins should check that {@link #hasLore()} returns <code>true</code> before calling this method.</p> + * + * @return the lore + */ + @Nullable List<net.kyori.adventure.text.Component> lore(); + + /** + * Sets the lore. + * + * @param lore the lore to set + */ + void lore(final @Nullable List<? extends net.kyori.adventure.text.Component> lore); + // Paper end + /** * Gets the lore that is set. * <p> @@ -141,7 +211,9 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste * calling this method. * * @return a list of lore that is set + * @deprecated in favour of {@link #lore()} */ + @Deprecated // Paper @Nullable List<String> getLore(); @@ -150,7 +222,9 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste * Removes lore when given null. * * @param lore the lore that will be set + * @deprecated in favour of {@link #lore(List)} */ + @Deprecated // Paper void setLore(@Nullable List<String> lore); /** diff --git a/src/main/java/org/bukkit/inventory/meta/WritableBookMeta.java b/src/main/java/org/bukkit/inventory/meta/WritableBookMeta.java index 12595536080ffe09df2b6ecdb83d846f50100d38..9fc47c879ee6b8edf2503f20e4736c2997d2de2e 100644 --- a/src/main/java/org/bukkit/inventory/meta/WritableBookMeta.java +++ b/src/main/java/org/bukkit/inventory/meta/WritableBookMeta.java @@ -5,8 +5,14 @@ import org.bukkit.Material; import org.jetbrains.annotations.NotNull; /** - * Represents a book ({@link Material#WRITABLE_BOOK} or {@link - * Material#WRITTEN_BOOK}) that can have pages. + * Represents a book ({@link Material#WRITABLE_BOOK}) that can have pages. + * <p> + * For {@link Material#WRITTEN_BOOK}, use {@link BookMeta}. + * <p> + * Before using this type, make sure to check the itemstack's material with + * {@link org.bukkit.inventory.ItemStack#getType()}. {@code instanceof} on + * the meta instance is not sufficient due to unusual inheritance + * with relation to {@link BookMeta}. */ public interface WritableBookMeta extends ItemMeta { diff --git a/src/main/java/org/bukkit/inventory/meta/trim/TrimMaterial.java b/src/main/java/org/bukkit/inventory/meta/trim/TrimMaterial.java index 5fc9aaac8baaf185d8e0d4fa7012dc4e13e485b3..804cb7162b34225d5dd84aada283de568d7d6592 100644 --- a/src/main/java/org/bukkit/inventory/meta/trim/TrimMaterial.java +++ b/src/main/java/org/bukkit/inventory/meta/trim/TrimMaterial.java @@ -57,4 +57,21 @@ public interface TrimMaterial extends Keyed, Translatable { private static TrimMaterial getTrimMaterial(@NotNull String key) { return Registry.TRIM_MATERIAL.getOrThrow(NamespacedKey.minecraft(key)); } + + // Paper start - adventure + /** + * Get the description of this {@link TrimMaterial}. + * + * @return the description + */ + net.kyori.adventure.text.@org.jetbrains.annotations.NotNull Component description(); + + /** + * @deprecated this method assumes that {@link #description()} will + * always be a translatable component which is not guaranteed. + */ + @Override + @Deprecated(forRemoval = true) + @org.jetbrains.annotations.NotNull String getTranslationKey(); + // Paper end - adventure } diff --git a/src/main/java/org/bukkit/inventory/meta/trim/TrimPattern.java b/src/main/java/org/bukkit/inventory/meta/trim/TrimPattern.java index e8e0786467bfcea14d30b352489b7bfb1a06addc..56cfe665daba1754e41f633d7c18172bebf87028 100644 --- a/src/main/java/org/bukkit/inventory/meta/trim/TrimPattern.java +++ b/src/main/java/org/bukkit/inventory/meta/trim/TrimPattern.java @@ -89,4 +89,21 @@ public interface TrimPattern extends Keyed, Translatable { private static TrimPattern getTrimPattern(@NotNull String key) { return Registry.TRIM_PATTERN.getOrThrow(NamespacedKey.minecraft(key)); } + + // Paper start - adventure + /** + * Get the description of this {@link TrimPattern}. + * + * @return the description + */ + net.kyori.adventure.text.@org.jetbrains.annotations.NotNull Component description(); + + /** + * @deprecated this method assumes that {@link #description()} will + * always be a translatable component which is not guaranteed. + */ + @Override + @Deprecated(forRemoval = true) + @org.jetbrains.annotations.NotNull String getTranslationKey(); + // Paper end - adventure } diff --git a/src/main/java/org/bukkit/map/MapCursor.java b/src/main/java/org/bukkit/map/MapCursor.java index a37e6419fcb116afbbfe8c5895b9c226a3a010dc..871adbf2f9015dffac9edc3ce35aa6acd3b75526 100644 --- a/src/main/java/org/bukkit/map/MapCursor.java +++ b/src/main/java/org/bukkit/map/MapCursor.java @@ -17,7 +17,7 @@ public final class MapCursor { private byte x, y; private byte direction; private boolean visible; - private String caption; + private net.kyori.adventure.text.Component caption; // Paper private Type type; /** @@ -32,7 +32,7 @@ public final class MapCursor { */ @Deprecated public MapCursor(byte x, byte y, byte direction, byte type, boolean visible) { - this(x, y, direction, type, visible, null); + this(x, y, direction, type, visible, (String) null); // Paper } /** @@ -45,7 +45,7 @@ public final class MapCursor { * @param visible Whether the cursor is visible by default. */ public MapCursor(byte x, byte y, byte direction, @NotNull Type type, boolean visible) { - this(x, y, direction, type, visible, null); + this(x, y, direction, type, visible, (String) null); // Paper } /** @@ -57,7 +57,7 @@ public final class MapCursor { * @param type The type (color/style) of the map cursor. * @param visible Whether the cursor is visible by default. * @param caption cursor caption - * @deprecated Magic value, use {@link #MapCursor(byte, byte, byte, Type, boolean, String)} + * @deprecated Magic value. Use {@link #MapCursor(byte, byte, byte, Type, boolean, net.kyori.adventure.text.Component)} */ @Deprecated public MapCursor(byte x, byte y, byte direction, byte type, boolean visible, @Nullable String caption) { @@ -66,8 +66,42 @@ public final class MapCursor { setDirection(direction); setRawType(type); this.visible = visible; - this.caption = caption; + this.caption = caption == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(caption); // Paper + } + // Paper start + /** + * Initialize the map cursor. + * + * @param x The x coordinate, from -128 to 127. + * @param y The y coordinate, from -128 to 127. + * @param direction The facing of the cursor, from 0 to 15. + * @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 + 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); } + /** + * Initialize the map cursor. + * + * @param x The x coordinate, from -128 to 127. + * @param y The y coordinate, from -128 to 127. + * @param direction The facing of the cursor, from 0 to 15. + * @param type The type (color/style) of the map cursor. + * @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, net.kyori.adventure.text.@Nullable Component caption) { + this.x = x; this.y = y; this.visible = visible; this.caption = caption; + setDirection(direction); + setType(type); + } + // Paper end /** * Initialize the map cursor. @@ -85,7 +119,7 @@ public final class MapCursor { setDirection(direction); this.type = type; this.visible = visible; - this.caption = caption; + this.caption = caption == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(caption); // Paper } /** @@ -204,23 +238,45 @@ public final class MapCursor { this.visible = visible; } + // Paper start /** * Gets the caption on this cursor. * * @return caption */ + public net.kyori.adventure.text.@Nullable Component caption() { + return this.caption; + } + /** + * Sets the caption on this cursor. + * + * @param caption new caption + */ + public void caption(net.kyori.adventure.text.@Nullable Component caption) { + this.caption = caption; + } + // Paper end + /** + * Gets the caption on this cursor. + * + * @return caption + * @deprecated in favour of {@link #caption()} + */ @Nullable + @Deprecated // Paper public String getCaption() { - return caption; + return this.caption == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.caption); // Paper } /** * Sets the caption on this cursor. * * @param caption new caption + * @deprecated in favour of {@link #caption(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper public void setCaption(@Nullable String caption) { - this.caption = caption; + this.caption = caption == null ? null : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(caption); // Paper } /** diff --git a/src/main/java/org/bukkit/map/MapCursorCollection.java b/src/main/java/org/bukkit/map/MapCursorCollection.java index 4dba721aefe4fc6699b3b4bfa7ecb0b19c2a2a1a..6bc28d000f538ecbf249467ff3e87e3f4fea963e 100644 --- a/src/main/java/org/bukkit/map/MapCursorCollection.java +++ b/src/main/java/org/bukkit/map/MapCursorCollection.java @@ -117,4 +117,22 @@ public final class MapCursorCollection { public MapCursor addCursor(int x, int y, byte direction, byte type, boolean visible, @Nullable String caption) { return addCursor(new MapCursor((byte) x, (byte) y, direction, type, visible, caption)); } + // Paper start + /** + * Add a cursor to the collection. + * + * @param x The x coordinate, from -128 to 127. + * @param y The y coordinate, from -128 to 127. + * @param direction The facing of the cursor, from 0 to 15. + * @param type The type (color/style) of the map cursor. + * @param visible Whether the cursor is visible. + * @param caption banner caption + * @return The newly added MapCursor. + * @deprecated Magic value + */ + @Deprecated + 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 } diff --git a/src/main/java/org/bukkit/permissions/Permissible.java b/src/main/java/org/bukkit/permissions/Permissible.java index 228421154913116069c20323afb519bdde2134df..26791db3c267670d5782f1d2b67ff7d5b55b9dac 100644 --- a/src/main/java/org/bukkit/permissions/Permissible.java +++ b/src/main/java/org/bukkit/permissions/Permissible.java @@ -126,4 +126,34 @@ public interface Permissible extends ServerOperator { */ @NotNull public Set<PermissionAttachmentInfo> getEffectivePermissions(); + + // Paper start - add TriState permission checks + /** + * Checks if this object has a permission set and, if it is set, the value of the permission. + * + * @param permission the permission to check + * @return a tri-state of if the permission is set and, if it is set, it's value + */ + default net.kyori.adventure.util.@NotNull TriState permissionValue(final @NotNull Permission permission) { + if (this.isPermissionSet(permission)) { + return net.kyori.adventure.util.TriState.byBoolean(this.hasPermission(permission)); + } else { + return net.kyori.adventure.util.TriState.NOT_SET; + } + } + + /** + * Checks if this object has a permission set and, if it is set, the value of the permission. + * + * @param permission the permission to check + * @return a tri-state of if the permission is set and, if it is set, it's value + */ + default net.kyori.adventure.util.@NotNull TriState permissionValue(final @NotNull String permission) { + if (this.isPermissionSet(permission)) { + return net.kyori.adventure.util.TriState.byBoolean(this.hasPermission(permission)); + } else { + return net.kyori.adventure.util.TriState.NOT_SET; + } + } + // Paper end } diff --git a/src/main/java/org/bukkit/plugin/Plugin.java b/src/main/java/org/bukkit/plugin/Plugin.java index 03ca87a1cbace2459174bb7bb8847bda766e80c5..b37938745f916b5f0111b07b1a1c97527f026e9d 100644 --- a/src/main/java/org/bukkit/plugin/Plugin.java +++ b/src/main/java/org/bukkit/plugin/Plugin.java @@ -179,6 +179,13 @@ public interface Plugin extends TabExecutor { @NotNull public Logger getLogger(); + // Paper start - Adventure component logger + @NotNull + default net.kyori.adventure.text.logger.slf4j.ComponentLogger getComponentLogger() { + return net.kyori.adventure.text.logger.slf4j.ComponentLogger.logger(getLogger().getName()); + } + // Paper end + /** * Returns the name of the plugin. * <p> diff --git a/src/main/java/org/bukkit/scoreboard/Objective.java b/src/main/java/org/bukkit/scoreboard/Objective.java index 78fd35e6115072c6bc2ff5a899ffc2edb8f45801..22b1dc5fd4d453161a5ee520072f8e8f955b3a80 100644 --- a/src/main/java/org/bukkit/scoreboard/Objective.java +++ b/src/main/java/org/bukkit/scoreboard/Objective.java @@ -20,13 +20,35 @@ public interface Objective { @NotNull String getName(); + // Paper start - Adventure + /** + * Gets the display name for this objective + * + * @return this objective's display name + * @throws IllegalStateException if this objective has been unregistered + */ + net.kyori.adventure.text.@NotNull Component displayName(); + /** + * Sets the name displayed to players for this objective. + * + * @param displayName Display name to set + * @throws IllegalStateException if this objective has been unregistered + * @throws IllegalArgumentException if displayName is null + * @throws IllegalArgumentException if displayName is longer than 128 + * characters. + */ + void displayName(net.kyori.adventure.text.@Nullable Component displayName); + // Paper end - Adventure + /** * 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(); /** @@ -34,7 +56,9 @@ public interface Objective { * * @param displayName Display name to set * @throws IllegalStateException if this objective has been unregistered + * @deprecated in favour of {@link #displayName(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper void setDisplayName(@NotNull String displayName); /** diff --git a/src/main/java/org/bukkit/scoreboard/Scoreboard.java b/src/main/java/org/bukkit/scoreboard/Scoreboard.java index bf52375e9ed9ec172eca1d27c06c379e3fc216bc..3377511e1a6dd4aeb78871e47169d5bd9456c1aa 100644 --- a/src/main/java/org/bukkit/scoreboard/Scoreboard.java +++ b/src/main/java/org/bukkit/scoreboard/Scoreboard.java @@ -26,6 +26,71 @@ public interface Scoreboard { @NotNull Objective registerNewObjective(@NotNull String name, @NotNull String criteria); + // Paper start - Adventure + /** + * Registers an Objective on this Scoreboard + * + * @param name Name of the Objective + * @param criteria Criteria for the Objective + * @param displayName display name for the Objective. + * @return The registered Objective + * @throws IllegalArgumentException if name is longer than 32767 + * characters. + * @throws IllegalArgumentException if an objective by that name already + * exists + * @deprecated use {@link #registerNewObjective(String, Criteria, net.kyori.adventure.text.Component)} + */ + @NotNull + @Deprecated + Objective registerNewObjective(@NotNull String name, @NotNull String criteria, net.kyori.adventure.text.@Nullable Component displayName); + /** + * Registers an Objective on this Scoreboard + * + * @param name Name of the Objective + * @param criteria Criteria for the Objective + * @param displayName Name displayed to players for the Objective. + * @param renderType Manner of rendering the Objective + * @return The registered Objective + * @throws IllegalArgumentException if name is longer than 32767 + * characters. + * @throws IllegalArgumentException if an objective by that name already + * exists + * @deprecated use {@link #registerNewObjective(String, Criteria, net.kyori.adventure.text.Component, RenderType)} + */ + @NotNull + @Deprecated + 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 + * + * @param name Name of the Objective + * @param criteria Criteria for the Objective + * @param displayName Name displayed to players for the Objective. + * @return The registered Objective + * @throws IllegalArgumentException if name is longer than 32767 + * characters. + * @throws IllegalArgumentException if an objective by that name already + * exists + */ + @NotNull + Objective registerNewObjective(@NotNull String name, @NotNull Criteria criteria, net.kyori.adventure.text.@Nullable Component displayName) throws IllegalArgumentException; + /** + * Registers an Objective on this Scoreboard + * + * @param name Name of the Objective + * @param criteria Criteria for the Objective + * @param displayName Name displayed to players for the Objective. + * @param renderType Manner of rendering the Objective + * @return The registered Objective + * @throws IllegalArgumentException if name is longer than 32767 + * characters. + * @throws IllegalArgumentException if an objective by that name already + * exists + */ + @NotNull + Objective registerNewObjective(@NotNull String name, @NotNull Criteria criteria, net.kyori.adventure.text.@Nullable Component displayName, @NotNull RenderType renderType) throws IllegalArgumentException; + // Paper end - Adventure + /** * Registers an Objective on this Scoreboard * @@ -37,7 +102,7 @@ public interface Scoreboard { * characters. * @throws IllegalArgumentException if an objective by that name already * exists - * @deprecated use {@link #registerNewObjective(String, Criteria, String)} + * @deprecated use {@link #registerNewObjective(String, Criteria, net.kyori.adventure.text.Component)} */ @Deprecated @NotNull @@ -55,7 +120,7 @@ public interface Scoreboard { * characters. * @throws IllegalArgumentException if an objective by that name already * exists - * @deprecated use {@link #registerNewObjective(String, Criteria, String, RenderType)} + * @deprecated use {@link #registerNewObjective(String, Criteria, net.kyori.adventure.text.Component, RenderType)} */ @Deprecated @NotNull @@ -72,8 +137,10 @@ public interface Scoreboard { * characters. * @throws IllegalArgumentException if an objective by that name already * exists + * @deprecated in favour of {@link #registerNewObjective(String, Criteria, net.kyori.adventure.text.Component)} */ @NotNull + @Deprecated // Paper Objective registerNewObjective(@NotNull String name, @NotNull Criteria criteria, @NotNull String displayName); /** @@ -88,8 +155,10 @@ public interface Scoreboard { * characters. * @throws IllegalArgumentException if an objective by that name already * exists + * @deprecated in favour of {@link #registerNewObjective(String, Criteria, net.kyori.adventure.text.Component, RenderType)} */ @NotNull + @Deprecated // Paper Objective registerNewObjective(@NotNull String name, @NotNull Criteria criteria, @NotNull String displayName, @NotNull RenderType renderType); /** diff --git a/src/main/java/org/bukkit/scoreboard/Team.java b/src/main/java/org/bukkit/scoreboard/Team.java index 7b9a7890b25ca4bd95ab81f3181288bf79ed649c..52e8be769d2e9b69e9833bc9a7fe39afd10c5095 100644 --- a/src/main/java/org/bukkit/scoreboard/Team.java +++ b/src/main/java/org/bukkit/scoreboard/Team.java @@ -12,7 +12,7 @@ import org.jetbrains.annotations.Nullable; * properties. This team is only relevant to the display of the associated * {@link #getScoreboard() scoreboard}. */ -public interface Team { +public interface Team extends net.kyori.adventure.audience.ForwardingAudience { // Paper - Make Team extend ForwardingAudience /** * Gets the name of this Team @@ -23,13 +23,96 @@ public interface Team { @NotNull String getName(); + // Paper start - Adventure + /** + * Gets the display name for this team + * + * @return Team display name + * @throws IllegalStateException if this team has been unregistered + */ + net.kyori.adventure.text.@NotNull Component displayName(); + + /** + * Sets the name displayed to entries for this team + * + * @param displayName New display name + * @throws IllegalStateException if this team has been unregistered + */ + void displayName(net.kyori.adventure.text.@Nullable Component displayName); + + /** + * Gets the prefix prepended to the display of entries on this team. + * + * @return Team prefix + * @throws IllegalStateException if this team has been unregistered + */ + net.kyori.adventure.text.@NotNull Component prefix(); + + /** + * Sets the prefix prepended to the display of entries on this team. + * + * @param prefix New prefix + * @throws IllegalStateException if this team has been unregistered + */ + void prefix(net.kyori.adventure.text.@Nullable Component prefix); + + /** + * Gets the suffix appended to the display of entries on this team. + * + * @return the team's current suffix + * @throws IllegalStateException if this team has been unregistered + */ + net.kyori.adventure.text.@NotNull Component suffix(); + + /** + * Sets the suffix appended to the display of entries on this team. + * + * @param suffix the new suffix for this team. + * @throws IllegalStateException if this team has been unregistered + */ + void suffix(net.kyori.adventure.text.@Nullable Component suffix); + + /** + * Checks if the team has a color specified + * + * @return true if it has a <b>color</b> + * @throws IllegalStateException if this team has been unregistered + */ + boolean hasColor(); + + /** + * Gets the color of the team. + * <br> + * This only sets the team outline, other occurrences of colors such as in + * names are handled by prefixes / suffixes. + * + * @return team color + * @throws IllegalStateException if this team has been unregistered + * @throws IllegalStateException if the team doesn't have a color + * @see #hasColor() + */ + net.kyori.adventure.text.format.@NotNull TextColor color(); + + /** + * Sets the color of the team. + * <br> + * This only sets the team outline, other occurrences of colors such as in + * names are handled by prefixes / suffixes. + * + * @param color new color, null for no color + */ + void color(net.kyori.adventure.text.format.@Nullable NamedTextColor color); + // Paper end - Adventure + /** * 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(); /** @@ -37,7 +120,9 @@ public interface Team { * * @param displayName New display name * @throws IllegalStateException if this team has been unregistered + * @deprecated in favour of {@link #displayName(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper void setDisplayName(@NotNull String displayName); /** @@ -45,8 +130,10 @@ public interface Team { * * @return Team prefix * @throws IllegalStateException if this team has been unregistered + * @deprecated in favour of {@link #prefix()} */ @NotNull + @Deprecated // Paper String getPrefix(); /** @@ -54,7 +141,9 @@ public interface Team { * * @param prefix New prefix * @throws IllegalStateException if this team has been unregistered + * @deprecated in favour of {@link #prefix(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper void setPrefix(@NotNull String prefix); /** @@ -62,8 +151,10 @@ public interface Team { * * @return the team's current suffix * @throws IllegalStateException if this team has been unregistered + * @deprecated in favour of {@link #suffix()} */ @NotNull + @Deprecated // Paper String getSuffix(); /** @@ -71,7 +162,9 @@ public interface Team { * * @param suffix the new suffix for this team. * @throws IllegalStateException if this team has been unregistered + * @deprecated in favour of {@link #suffix(net.kyori.adventure.text.Component)} */ + @Deprecated // Paper void setSuffix(@NotNull String suffix); /** @@ -82,8 +175,10 @@ public interface Team { * * @return team color, defaults to {@link ChatColor#RESET} * @throws IllegalStateException if this team has been unregistered + * @deprecated in favour of {@link #color()} */ @NotNull + @Deprecated // Paper ChatColor getColor(); /** @@ -94,7 +189,9 @@ public interface Team { * * @param color new color, must be non-null. Use {@link ChatColor#RESET} for * no color + * @deprecated in favour of {@link #color(net.kyori.adventure.text.format.NamedTextColor)} */ + @Deprecated // Paper void setColor(@NotNull ChatColor color); /** diff --git a/src/test/java/io/papermc/paper/adventure/KeyTest.java b/src/test/java/io/papermc/paper/adventure/KeyTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7ede17d60358e0e3a04f3166ea9657e5239e0d8f --- /dev/null +++ b/src/test/java/io/papermc/paper/adventure/KeyTest.java @@ -0,0 +1,31 @@ +package io.papermc.paper.adventure; + +import java.util.HashSet; +import java.util.Set; +import net.kyori.adventure.key.Key; +import org.bukkit.NamespacedKey; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class KeyTest { + + @Test + public void equalsTest() { + Key key = new NamespacedKey("test", "key"); + Key key1 = Key.key("test", "key"); + assertEquals(key, key1); + assertEquals(key1, key); + } + + @Test + public void setTest() { + Key key = new NamespacedKey("test", "key"); + Key key1 = Key.key("test", "key"); + Set<Key> set = new HashSet<>(Set.of(key)); + Set<Key> set1 = new HashSet<>(Set.of(key1)); + assertTrue(set.contains(key1)); + assertTrue(set1.contains(key)); + } +}