From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Techcable <Techcable@outlook.com>
Date: Mon, 29 Feb 2016 20:02:40 -0600
Subject: [PATCH] Player Tab List and Title APIs

Co-authored-by: Fruxz <cedricspitzer@outlook.de>

diff --git a/src/main/java/com/destroystokyo/paper/Title.java b/src/main/java/com/destroystokyo/paper/Title.java
new file mode 100644
index 0000000000000000000000000000000000000000..9e90c3df567a65b48a0b9341f784eb902cb35d8c
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/Title.java
@@ -0,0 +1,420 @@
+package com.destroystokyo.paper;
+
+import net.md_5.bungee.api.chat.BaseComponent;
+import net.md_5.bungee.api.chat.TextComponent;
+
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * Represents a title to may be sent to a {@link Player}.
+ *
+ * <p>A title can be sent without subtitle text.</p>
+ *
+ * @deprecated use {@link net.kyori.adventure.title.Title}
+ */
+@Deprecated
+public final class Title {
+
+    /**
+     * The default number of ticks for the title to fade in.
+     */
+    public static final int DEFAULT_FADE_IN = 20;
+    /**
+     * The default number of ticks for the title to stay.
+     */
+    public static final int DEFAULT_STAY = 200;
+    /**
+     * The default number of ticks for the title to fade out.
+     */
+    public static final int DEFAULT_FADE_OUT = 20;
+
+    private final BaseComponent[] title;
+    private final BaseComponent[] subtitle;
+    private final int fadeIn;
+    private final int stay;
+    private final int fadeOut;
+
+    /**
+     * Create a title with the default time values and no subtitle.
+     *
+     * <p>Times use default values.</p>
+     *
+     * @param title the main text of the title
+     * @throws NullPointerException if the title is null
+     */
+    public Title(@NotNull BaseComponent title) {
+        this(title, null);
+    }
+
+    /**
+     * Create a title with the default time values and no subtitle.
+     *
+     * <p>Times use default values.</p>
+     *
+     * @param title the main text of the title
+     * @throws NullPointerException if the title is null
+     */
+    public Title(@NotNull BaseComponent[] title) {
+        this(title, null);
+    }
+
+    /**
+     * Create a title with the default time values and no subtitle.
+     *
+     * <p>Times use default values.</p>
+     *
+     * @param title the main text of the title
+     * @throws NullPointerException if the title is null
+     */
+    public Title(@NotNull String title) {
+        this(title, null);
+    }
+
+    /**
+     * Create a title with the default time values.
+     *
+     * <p>Times use default values.</p>
+     *
+     * @param title    the main text of the title
+     * @param subtitle the secondary text of the title
+     */
+    public Title(@NotNull BaseComponent title, @Nullable BaseComponent subtitle) {
+        this(title, subtitle, DEFAULT_FADE_IN, DEFAULT_STAY, DEFAULT_FADE_OUT);
+    }
+
+    /**
+     * Create a title with the default time values.
+     *
+     * <p>Times use default values.</p>
+     *
+     * @param title    the main text of the title
+     * @param subtitle the secondary text of the title
+     */
+    public Title(@NotNull BaseComponent[] title, @Nullable BaseComponent[] subtitle) {
+        this(title, subtitle, DEFAULT_FADE_IN, DEFAULT_STAY, DEFAULT_FADE_OUT);
+    }
+
+    /**
+     * Create a title with the default time values.
+     *
+     * <p>Times use default values.</p>
+     *
+     * @param title    the main text of the title
+     * @param subtitle the secondary text of the title
+     */
+    public Title(@NotNull String title, @Nullable String subtitle) {
+        this(title, subtitle, DEFAULT_FADE_IN, DEFAULT_STAY, DEFAULT_FADE_OUT);
+    }
+
+    /**
+     * Creates a new title.
+     *
+     * @param title    the main text of the title
+     * @param subtitle the secondary text of the title
+     * @param fadeIn   the number of ticks for the title to fade in
+     * @param stay     the number of ticks for the title to stay on screen
+     * @param fadeOut  the number of ticks for the title to fade out
+     * @throws IllegalArgumentException if any of the times are negative
+     */
+    public Title(@NotNull BaseComponent title, @Nullable BaseComponent subtitle, int fadeIn, int stay, int fadeOut) {
+        this(
+                new BaseComponent[]{checkNotNull(title, "title")},
+                subtitle == null ? null : new BaseComponent[]{subtitle},
+                fadeIn,
+                stay,
+                fadeOut
+        );
+    }
+
+    /**
+     * Creates a new title.
+     *
+     * @param title    the main text of the title
+     * @param subtitle the secondary text of the title
+     * @param fadeIn   the number of ticks for the title to fade in
+     * @param stay     the number of ticks for the title to stay on screen
+     * @param fadeOut  the number of ticks for the title to fade out
+     * @throws IllegalArgumentException if any of the times are negative
+     */
+    public Title(@Nullable BaseComponent[] title, @NotNull BaseComponent[] subtitle, int fadeIn, int stay, int fadeOut) {
+        checkArgument(fadeIn >= 0, "Negative fadeIn: %s", fadeIn);
+        checkArgument(stay >= 0, "Negative stay: %s", stay);
+        checkArgument(fadeOut >= 0, "Negative fadeOut: %s", fadeOut);
+        this.title = checkNotNull(title, "title");
+        this.subtitle = subtitle;
+        this.fadeIn = fadeIn;
+        this.stay = stay;
+        this.fadeOut = fadeOut;
+    }
+
+    /**
+     * Creates a new title.
+     *
+     * <p>It is recommended to the {@link BaseComponent} constrctors.</p>
+     *
+     * @param title    the main text of the title
+     * @param subtitle the secondary text of the title
+     * @param fadeIn   the number of ticks for the title to fade in
+     * @param stay     the number of ticks for the title to stay on screen
+     * @param fadeOut  the number of ticks for the title to fade out
+     */
+    public Title(@NotNull String title, @Nullable String subtitle, int fadeIn, int stay, int fadeOut) {
+        this(
+                TextComponent.fromLegacyText(checkNotNull(title, "title")),
+                subtitle == null ? null : TextComponent.fromLegacyText(subtitle),
+                fadeIn,
+                stay,
+                fadeOut
+        );
+    }
+
+    /**
+     * Gets the text of this title
+     *
+     * @return the text
+     */
+    @NotNull
+    public BaseComponent[] getTitle() {
+        return this.title;
+    }
+
+    /**
+     * Gets the text of this title's subtitle
+     *
+     * @return the text
+     */
+    @Nullable
+    public BaseComponent[] getSubtitle() {
+        return this.subtitle;
+    }
+
+    /**
+     * Gets the number of ticks to fade in.
+     *
+     * <p>The returned value is never negative.</p>
+     *
+     * @return the number of ticks to fade in
+     */
+    public int getFadeIn() {
+        return this.fadeIn;
+    }
+
+    /**
+     * Gets the number of ticks to stay.
+     *
+     * <p>The returned value is never negative.</p>
+     *
+     * @return the number of ticks to stay
+     */
+    public int getStay() {
+        return this.stay;
+    }
+
+    /**
+     * Gets the number of ticks to fade out.
+     *
+     * <p>The returned value is never negative.</p>
+     *
+     * @return the number of ticks to fade out
+     */
+    public int getFadeOut() {
+        return this.fadeOut;
+    }
+
+    /**
+     * Sends the title directly to an player
+     *
+     * @param player the receiver of the title
+     */
+    public void send(@NotNull Player player) {
+        player.sendTitle(this);
+    }
+
+    /**
+     * Sends the title directly to the defined players
+     *
+     * @param players the receivers of the title
+     */
+    public void send(@NotNull Collection<? extends Player> players) {
+        for (Player player : players) {
+            player.sendTitle(this);
+        }
+    }
+
+    /**
+     * Sends the title directly to the defined players
+     *
+     * @param players the receivers of the title
+     */
+    public void send(@NotNull Player[] players) {
+        for (Player player : players) {
+            player.sendTitle(this);
+        }
+    }
+
+    /**
+     * Sends the title directly to all online players
+     */
+    public void broadcast() {
+        send(Bukkit.getOnlinePlayers());
+    }
+
+    @NotNull
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * A builder for creating titles
+     */
+    public static final class Builder {
+
+        private BaseComponent[] title;
+        private BaseComponent[] subtitle;
+        private int fadeIn = DEFAULT_FADE_IN;
+        private int stay = DEFAULT_STAY;
+        private int fadeOut = DEFAULT_FADE_OUT;
+
+        /**
+         * Sets the title to the given text.
+         *
+         * @param title the title text
+         * @return this builder instance
+         * @throws NullPointerException if the title is null
+         */
+        @NotNull
+        public Builder title(@NotNull BaseComponent title) {
+            return this.title(new BaseComponent[]{checkNotNull(title, "title")});
+        }
+
+        /**
+         * Sets the title to the given text.
+         *
+         * @param title the title text
+         * @return this builder instance
+         * @throws NullPointerException if the title is null
+         */
+        @NotNull
+        public Builder title(@NotNull BaseComponent[] title) {
+            this.title = checkNotNull(title, "title");
+            return this;
+        }
+
+        /**
+         * Sets the title to the given text.
+         *
+         * <p>It is recommended to the {@link BaseComponent} methods.</p>
+         *
+         * @param title the title text
+         * @return this builder instance
+         * @throws NullPointerException if the title is null
+         */
+        @NotNull
+        public Builder title(@NotNull String title) {
+            return this.title(TextComponent.fromLegacyText(checkNotNull(title, "title")));
+        }
+
+        /**
+         * Sets the subtitle to the given text.
+         *
+         * @param subtitle the title text
+         * @return this builder instance
+         */
+        @NotNull
+        public Builder subtitle(@Nullable BaseComponent subtitle) {
+            return this.subtitle(subtitle == null ? null : new BaseComponent[]{subtitle});
+        }
+
+        /**
+         * Sets the subtitle to the given text.
+         *
+         * @param subtitle the title text
+         * @return this builder instance
+         */
+        @NotNull
+        public Builder subtitle(@Nullable BaseComponent[] subtitle) {
+            this.subtitle = subtitle;
+            return this;
+        }
+
+        /**
+         * Sets the subtitle to the given text.
+         *
+         * <p>It is recommended to the {@link BaseComponent} methods.</p>
+         *
+         * @param subtitle the title text
+         * @return this builder instance
+         */
+        @NotNull
+        public Builder subtitle(@Nullable String subtitle) {
+            return this.subtitle(subtitle == null ? null : TextComponent.fromLegacyText(subtitle));
+        }
+
+        /**
+         * Sets the number of ticks for the title to fade in
+         *
+         * @param fadeIn the number of ticks to fade in
+         * @return this builder instance
+         * @throws IllegalArgumentException if it is negative
+         */
+        @NotNull
+        public Builder fadeIn(int fadeIn) {
+            checkArgument(fadeIn >= 0, "Negative fadeIn: %s", fadeIn);
+            this.fadeIn = fadeIn;
+            return this;
+        }
+
+
+        /**
+         * Sets the number of ticks for the title to stay.
+         *
+         * @param stay the number of ticks to stay
+         * @return this builder instance
+         * @throws IllegalArgumentException if it is negative
+         */
+        @NotNull
+        public Builder stay(int stay) {
+            checkArgument(stay >= 0, "Negative stay: %s", stay);
+            this.stay = stay;
+            return this;
+        }
+
+        /**
+         * Sets the number of ticks for the title to fade out.
+         *
+         * @param fadeOut the number of ticks to fade out
+         * @return this builder instance
+         * @throws IllegalArgumentException if it is negative
+         */
+        @NotNull
+        public Builder fadeOut(int fadeOut) {
+            checkArgument(fadeOut >= 0, "Negative fadeOut: %s", fadeOut);
+            this.fadeOut = fadeOut;
+            return this;
+        }
+
+        /**
+         * Create a title based on the values in the builder.
+         *
+         * @return a title from the values in this builder
+         * @throws IllegalStateException if title isn't specified
+         */
+        @NotNull
+        public Title build() {
+            checkState(title != null, "Title not specified");
+            return new Title(this.title, this.subtitle, this.fadeIn, this.stay, this.fadeOut);
+        }
+    }
+}
diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java
index 77a3bb82f90a7779f98246ceecc150d4417043e7..8c7c7ce6bf12d14300067cc64cbdeb9e7d984629 100644
--- a/src/main/java/org/bukkit/entity/Player.java
+++ b/src/main/java/org/bukkit/entity/Player.java
@@ -2,6 +2,7 @@ package org.bukkit.entity;
 
 import java.net.InetSocketAddress;
 import java.util.UUID;
+import com.destroystokyo.paper.Title; // Paper
 import org.bukkit.DyeColor;
 import org.bukkit.Effect;
 import org.bukkit.GameMode;
@@ -767,6 +768,131 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
     public default void sendMessage(net.md_5.bungee.api.ChatMessageType position, net.md_5.bungee.api.chat.BaseComponent... components) {
         spigot().sendMessage(position, components);
     }
+
+    /**
+     * Set the text displayed in the player list header and footer for this player
+     *
+     * @param header content for the top of the player list
+     * @param footer content for the bottom of the player list
+     * @deprecated in favour of {@link #sendPlayerListHeaderAndFooter(net.kyori.adventure.text.Component, net.kyori.adventure.text.Component)}
+     */
+    @Deprecated
+    public void setPlayerListHeaderFooter(@Nullable net.md_5.bungee.api.chat.BaseComponent[] header, @Nullable net.md_5.bungee.api.chat.BaseComponent[] footer);
+
+    /**
+     * Set the text displayed in the player list header and footer for this player
+     *
+     * @param header content for the top of the player list
+     * @param footer content for the bottom of the player list
+     * @deprecated in favour of {@link #sendPlayerListHeaderAndFooter(net.kyori.adventure.text.Component, net.kyori.adventure.text.Component)}
+     */
+    @Deprecated
+    public void setPlayerListHeaderFooter(@Nullable net.md_5.bungee.api.chat.BaseComponent header, @Nullable net.md_5.bungee.api.chat.BaseComponent footer);
+
+    /**
+     * Update the times for titles displayed to the player
+     *
+     * @param fadeInTicks  ticks to fade-in
+     * @param stayTicks    ticks to stay visible
+     * @param fadeOutTicks ticks to fade-out
+     * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)}
+     */
+    @Deprecated
+    public void setTitleTimes(int fadeInTicks, int stayTicks, int fadeOutTicks);
+
+    /**
+     * Update the subtitle of titles displayed to the player
+     *
+     * @param subtitle Subtitle to set
+     * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)}
+     */
+    @Deprecated
+    public void setSubtitle(net.md_5.bungee.api.chat.BaseComponent[] subtitle);
+
+    /**
+     * Update the subtitle of titles displayed to the player
+     *
+     * @param subtitle Subtitle to set
+     * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)}
+     */
+    @Deprecated
+    public void setSubtitle(net.md_5.bungee.api.chat.BaseComponent subtitle);
+
+    /**
+     * Show the given title to the player, along with the last subtitle set, using the last set times
+     *
+     * @param title Title to set
+     * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)}
+     */
+    @Deprecated
+    public void showTitle(@Nullable net.md_5.bungee.api.chat.BaseComponent[] title);
+
+    /**
+     * Show the given title to the player, along with the last subtitle set, using the last set times
+     *
+     * @param title Title to set
+     * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)}
+     */
+    @Deprecated
+    public void showTitle(@Nullable net.md_5.bungee.api.chat.BaseComponent title);
+
+    /**
+     * Show the given title and subtitle to the player using the given times
+     *
+     * @param title        big text
+     * @param subtitle     little text under it
+     * @param fadeInTicks  ticks to fade-in
+     * @param stayTicks    ticks to stay visible
+     * @param fadeOutTicks ticks to fade-out
+     * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)}
+     */
+    @Deprecated
+    public void showTitle(@Nullable net.md_5.bungee.api.chat.BaseComponent[] title, @Nullable net.md_5.bungee.api.chat.BaseComponent[] subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks);
+
+    /**
+     * Show the given title and subtitle to the player using the given times
+     *
+     * @param title        big text
+     * @param subtitle     little text under it
+     * @param fadeInTicks  ticks to fade-in
+     * @param stayTicks    ticks to stay visible
+     * @param fadeOutTicks ticks to fade-out
+     * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)}
+     */
+    @Deprecated
+    public void showTitle(@Nullable net.md_5.bungee.api.chat.BaseComponent title, @Nullable net.md_5.bungee.api.chat.BaseComponent subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks);
+
+    /**
+     * Show the title to the player, overriding any previously displayed title.
+     *
+     * <p>This method overrides any previous title, use {@link #updateTitle(Title)} to change the existing one.</p>
+     *
+     * @param title the title to send
+     * @throws NullPointerException if the title is null
+     * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)}
+     */
+    @Deprecated
+    void sendTitle(@NotNull Title title);
+
+    /**
+     * Show the title to the player, overriding any previously displayed title.
+     *
+     * <p>This method doesn't override previous titles, but changes their values.</p>
+     *
+     * @param title the title to send
+     * @throws NullPointerException if title is null
+     * @deprecated Use {@link #showTitle(net.kyori.adventure.title.Title)} or {@link #sendTitlePart(net.kyori.adventure.title.TitlePart, Object)}
+     */
+    @Deprecated
+    void updateTitle(@NotNull Title title);
+
+    /**
+     * Hide any title that is currently visible to the player
+     *
+     * @deprecated use {@link #clearTitle()}
+     */
+    @Deprecated
+    public void hideTitle();
     // Paper end
 
     /**
