All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bukkit.util.ChatPaginator Maven / Gradle / Ivy

The newest version!
package org.bukkit.util;

import org.bukkit.ChatColor;

import java.util.LinkedList;
import java.util.List;

/**
 * The ChatPaginator takes a raw string of arbitrary length and breaks it down
 * into an array of strings appropriate for displaying on the Minecraft player
 * console.
 */
public class ChatPaginator {
  public static final int GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH = 55; // Will never wrap, even with the largest characters
  public static final int AVERAGE_CHAT_PAGE_WIDTH = 65; // Will typically not wrap using an average character distribution
  public static final int UNBOUNDED_PAGE_WIDTH = Integer.MAX_VALUE;
  public static final int OPEN_CHAT_PAGE_HEIGHT = 20; // The height of an expanded chat window
  public static final int CLOSED_CHAT_PAGE_HEIGHT = 10; // The height of the default chat window
  public static final int UNBOUNDED_PAGE_HEIGHT = Integer.MAX_VALUE;

  /**
   * Breaks a raw string up into pages using the default width and height.
   *
   * @param unpaginatedString The raw string to break.
   * @param pageNumber        The page number to fetch.
   * @return A single chat page.
   */
  public static ChatPage paginate(String unpaginatedString, int pageNumber) {
    return paginate(unpaginatedString, pageNumber, GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH, CLOSED_CHAT_PAGE_HEIGHT);
  }

  /**
   * Breaks a raw string up into pages using a provided width and height.
   *
   * @param unpaginatedString The raw string to break.
   * @param pageNumber        The page number to fetch.
   * @param lineLength        The desired width of a chat line.
   * @param pageHeight        The desired number of lines in a page.
   * @return A single chat page.
   */
  public static ChatPage paginate(String unpaginatedString, int pageNumber, int lineLength, int pageHeight) {
    String[] lines = wordWrap(unpaginatedString, lineLength);

    int totalPages = lines.length / pageHeight + (lines.length % pageHeight == 0 ? 0 : 1);
    int actualPageNumber = pageNumber <= totalPages ? pageNumber : totalPages;

    int from = (actualPageNumber - 1) * pageHeight;
    int to = from + pageHeight <= lines.length ? from + pageHeight : lines.length;
    String[] selectedLines = Java15Compat.Arrays_copyOfRange(lines, from, to);

    return new ChatPage(selectedLines, actualPageNumber, totalPages);
  }

  /**
   * Breaks a raw string up into a series of lines. Words are wrapped using
   * spaces as decimeters and the newline character is respected.
   *
   * @param rawString  The raw string to break.
   * @param lineLength The length of a line of text.
   * @return An array of word-wrapped lines.
   */
  public static String[] wordWrap(String rawString, int lineLength) {
    // A null string is a single line
    if (rawString == null) {
      return new String[]{""};
    }

    // A string shorter than the lineWidth is a single line
    if (rawString.length() <= lineLength && !rawString.contains("\n")) {
      return new String[]{rawString};
    }

    char[] rawChars = (rawString + ' ').toCharArray(); // add a trailing space to trigger pagination
    StringBuilder word = new StringBuilder();
    StringBuilder line = new StringBuilder();
    List lines = new LinkedList();
    int lineColorChars = 0;

    for (int i = 0; i < rawChars.length; i++) {
      char c = rawChars[i];

      // skip chat color modifiers
      if (c == ChatColor.COLOR_CHAR) {
        word.append(ChatColor.getByChar(rawChars[i + 1]));
        lineColorChars += 2;
        i++; // Eat the next character as we have already processed it
        continue;
      }

      if (c == ' ' || c == '\n') {
        if (line.length() == 0 && word.length() > lineLength) { // special case: extremely long word begins a line
          for (String partialWord : word.toString().split("(?<=\\G.{" + lineLength + "})")) {
            lines.add(partialWord);
          }
        } else if (line.length() + word.length() - lineColorChars == lineLength) { // Line exactly the correct length...newline
          line.append(word);
          lines.add(line.toString());
          line = new StringBuilder();
          lineColorChars = 0;
        } else if (line.length() + 1 + word.length() - lineColorChars > lineLength) { // Line too long...break the line
          for (String partialWord : word.toString().split("(?<=\\G.{" + lineLength + "})")) {
            lines.add(line.toString());
            line = new StringBuilder(partialWord);
          }
          lineColorChars = 0;
        } else {
          if (line.length() > 0) {
            line.append(' ');
          }
          line.append(word);
        }
        word = new StringBuilder();

        if (c == '\n') { // Newline forces the line to flush
          lines.add(line.toString());
          line = new StringBuilder();
        }
      } else {
        word.append(c);
      }
    }

    if (line.length() > 0) { // Only add the last line if there is anything to add
      lines.add(line.toString());
    }

    // Iterate over the wrapped lines, applying the last color from one line to the beginning of the next
    if (lines.get(0).length() == 0 || lines.get(0).charAt(0) != ChatColor.COLOR_CHAR) {
      lines.set(0, ChatColor.WHITE + lines.get(0));
    }
    for (int i = 1; i < lines.size(); i++) {
      final String pLine = lines.get(i - 1);
      final String subLine = lines.get(i);

      char color = pLine.charAt(pLine.lastIndexOf(ChatColor.COLOR_CHAR) + 1);
      if (subLine.length() == 0 || subLine.charAt(0) != ChatColor.COLOR_CHAR) {
        lines.set(i, ChatColor.getByChar(color) + subLine);
      }
    }

    return lines.toArray(new String[lines.size()]);
  }

  public static class ChatPage {

    private final String[] lines;
    private final int pageNumber;
    private final int totalPages;

    public ChatPage(String[] lines, int pageNumber, int totalPages) {
      this.lines = lines;
      this.pageNumber = pageNumber;
      this.totalPages = totalPages;
    }

    public int getPageNumber() {
      return pageNumber;
    }

    public int getTotalPages() {
      return totalPages;
    }

    public String[] getLines() {

      return lines;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy