From 980f9ac25c1f8dc154fe38beabc6cd5a1e50a411 Mon Sep 17 00:00:00 2001
From: XiaoMoMi <70987828+Xiao-MoMi@users.noreply.github.com>
Date: Tue, 24 May 2022 13:04:38 +0800
Subject: [PATCH] no change
---
.../customcrops/Libs/minedown/MineDown.java | 499 -------
.../Libs/minedown/MineDownParser.java | 1241 -----------------
.../Libs/minedown/MineDownStringifier.java | 423 ------
.../customcrops/Libs/minedown/Replacer.java | 471 -------
.../customcrops/Libs/minedown/Util.java | 590 --------
5 files changed, 3224 deletions(-)
delete mode 100644 src/main/java/net/momirealms/customcrops/Libs/minedown/MineDown.java
delete mode 100644 src/main/java/net/momirealms/customcrops/Libs/minedown/MineDownParser.java
delete mode 100644 src/main/java/net/momirealms/customcrops/Libs/minedown/MineDownStringifier.java
delete mode 100644 src/main/java/net/momirealms/customcrops/Libs/minedown/Replacer.java
delete mode 100644 src/main/java/net/momirealms/customcrops/Libs/minedown/Util.java
diff --git a/src/main/java/net/momirealms/customcrops/Libs/minedown/MineDown.java b/src/main/java/net/momirealms/customcrops/Libs/minedown/MineDown.java
deleted file mode 100644
index 1e0847a..0000000
--- a/src/main/java/net/momirealms/customcrops/Libs/minedown/MineDown.java
+++ /dev/null
@@ -1,499 +0,0 @@
-package net.momirealms.customcrops.Libs.minedown;
-
-/*
- * Copyright (c) 2017 Max Lee (https://github.com/Phoenix616)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import net.md_5.bungee.api.ChatColor;
-import net.md_5.bungee.api.chat.BaseComponent;
-import net.md_5.bungee.api.chat.ClickEvent;
-import net.md_5.bungee.api.chat.HoverEvent;
-
-import java.util.Map;
-
-/**
- *
MineDown
- * A MarkDown inspired markup for Minecraft chat components
- *
- * This lets you convert string messages into chat components by using a custom mark up syntax
- * which is loosely based on MarkDown while still supporting legacy formatting codes.
- *
- *
- * Inline Formatting
- * Color legacy &6Text {@link ChatColor} codes
- * Color &gold&Text {@link ChatColor} codes
- * RGB Hex Color &ff00ff&Text Full hexadecimal format
- * RGB Hex Color &f0f&Text Short format (equivalent to long one)
- * Bold **Text**
- * Italic ##Text##
- * Underlined __Text__
- * Strikethrough ~~Text~~
- * Obfuscated ??Text??
- *
- *
- * Events
- * You can define click and hover events with the commonly used MarkDown link syntax.
- *
- *
- * Simple Syntax
- * General syntax [Text](text-color text-formatting... link hover text)
- * Simple Link [Text](https://example.com)
- * Simple Command [Text](/command to run)
- * Link + Hover [Text](https://example.com Hover Text)
- * Text formatting + Link + Hover [Text](blue underline https://example.com Hover Text)
- *
- *
- *
- * Advanced Syntax
- * General syntax [Text](action=value) {@link ClickEvent.Action}, {@link HoverEvent.Action}
- * Link [Text](open_url=https://example.com)
- * Color [Text](color=red)
- * RGB Hex Color [Text](color=#ff00ff) Full hexadecimal format
- * RGB Hex Color [Text](color=#f0f) Short format (equivalent to long one)
- * Formatting [Text](format=underline,bold)
- * Font [Text](format=underline,bold)
- * Run Command [Text](run_command=/command string)
- * Suggest Command [Text](suggest_command=/command)
- * Simple Hover [Text](hover=Hover Text)
- * Hover Text [Text](show_text=Hover Text)
- * Hover Entity Info [Text](show_entity=uuid:pig Name)
- * Hover Item Info [Text](show_item=stone*2 nbt...)
- *
- *
- * All advanced settings can be chained/included in a event definition.
- * You can't however add multiple different colors or click and hover actions!
- */
-public class MineDown {
- public static final String FONT_PREFIX = "font=";
- public static final String COLOR_PREFIX = "color=";
- public static final String FORMAT_PREFIX = "format=";
- public static final String HOVER_PREFIX = "hover=";
- public static final String INSERTION_PREFIX = "insert=";
-
- private String message;
- private final Replacer replacer = new Replacer();
- private final MineDownParser parser = new MineDownParser();
- private BaseComponent[] baseComponents = null;
- private boolean replaceFirst = Boolean.getBoolean("de.themoep.minedown.replacefirst");
-
- /**
- * Create a new MineDown builder with a certain message
- * @param message The message to parse
- */
- public MineDown(String message) {
- this.message = message;
- }
-
- /**
- * Parse a MineDown string to components
- * @param message The message to translate
- * @param replacements Optional placeholder replacements
- * @return The parsed components
- */
- public static BaseComponent[] parse(String message, String... replacements) {
- return new MineDown(message).replace(replacements).toComponent();
- }
-
- /**
- * Convert components to a MineDown string
- * @param components The components to convert
- * @return The components represented as a MineDown string
- */
- public static String stringify(BaseComponent[] components) {
- return new MineDownStringifier().stringify(components);
- }
-
- /**
- * Parse and convert the message to the component
- * @return The parsed component message
- */
- public BaseComponent[] toComponent() {
- if (baseComponents() == null) {
- if (replaceFirst()) {
- Replacer componentReplacer = new Replacer();
- for (Map.Entry entry : replacer().componentReplacements().entrySet()) {
- componentReplacer.replace(entry.getKey(), stringify(entry.getValue()));
- }
- baseComponents = parser().parse(componentReplacer.replaceIn(replacer().replaceIn(message()))).create();
- } else {
- baseComponents = replacer().replaceIn(parser().parse(message()).create());
- }
- }
- return baseComponents();
- }
-
- /**
- * Remove a cached component and re-parse the next time {@link #toComponent} is called
- */
- private void reset() {
- baseComponents = null;
- }
-
- /**
- * Set whether or not replacements should be replaced before or after the components are created.
- * When replacing first it will not replace any placeholders with component replacement values!
- * Default is after. (replaceFirst = false)
- * @param replaceFirst Whether or not to replace first or parse first
- * @return The MineDown instance
- */
- public MineDown replaceFirst(boolean replaceFirst) {
- reset();
- this.replaceFirst = replaceFirst;
- return this;
- }
-
- /**
- * Get whether or not replacements should be replaced before or after the components are created.
- * When replacing first it will not replace any placeholders with component replacement values!
- * Default is after. (replaceFirst = false)
- * @return Whether or not to replace first or parse first
- */
- public boolean replaceFirst() {
- return replaceFirst;
- }
-
- /**
- * Add an array with placeholders and values that should get replaced in the message
- * @param replacements The replacements, nth element is the placeholder, n+1th the value
- * @return The MineDown instance
- */
- public MineDown replace(String... replacements) {
- reset();
- replacer().replace(replacements);
- return this;
- }
-
- /**
- * Add a map with placeholders and values that should get replaced in the message
- * @param replacements The replacements mapped placeholder to value
- * @return The MineDown instance
- */
- public MineDown replace(Map replacements) {
- reset();
- replacer().replace(replacements);
- return this;
- }
-
- /**
- * Add a placeholder to component mapping that should get replaced in the message
- * @param placeholder The placeholder to replace
- * @param replacement The replacement components
- * @return The Replacer instance
- */
- public MineDown replace(String placeholder, BaseComponent... replacement) {
- reset();
- replacer().replace(placeholder,replacement);
- return this;
- }
-
- /**
- * Set the placeholder indicator for both prefix and suffix
- * @param placeholderIndicator The character to use as a placeholder indicator
- * @return The MineDown instance
- */
- public MineDown placeholderIndicator(String placeholderIndicator) {
- placeholderPrefix(placeholderIndicator);
- placeholderSuffix(placeholderIndicator);
- return this;
- }
-
- /**
- * Set the placeholder indicator's prefix character
- * @param placeholderPrefix The character to use as the placeholder indicator's prefix
- * @return The MineDown instance
- */
- public MineDown placeholderPrefix(String placeholderPrefix) {
- reset();
- replacer().placeholderPrefix(placeholderPrefix);
- return this;
- }
-
- /**
- * Get the placeholder indicator's prefix character
- * @return The placeholder indicator's prefix character
- */
- public String placeholderPrefix() {
- return replacer().placeholderPrefix();
- }
-
- /**
- * Set the placeholder indicator's suffix character
- * @param placeholderSuffix The character to use as the placeholder indicator's suffix
- * @return The MineDown instance
- */
- public MineDown placeholderSuffix(String placeholderSuffix) {
- reset();
- replacer().placeholderSuffix(placeholderSuffix);
- return this;
- }
-
- /**
- * Get the placeholder indicator's suffix character
- * @return The placeholder indicator's suffix character
- */
- public String placeholderSuffix() {
- return replacer().placeholderSuffix();
- }
-
- /**
- * Set whether or not the case of the placeholder should be ignored when replacing
- * @param ignorePlaceholderCase Whether or not to ignore the case of the placeholders
- * @return The MineDown instance
- */
- public MineDown ignorePlaceholderCase(boolean ignorePlaceholderCase) {
- reset();
- replacer().ignorePlaceholderCase(ignorePlaceholderCase);
- return this;
- }
-
- /**
- * Get whether or not the case of the placeholder should be ignored when replacing
- * @return Whether or not to ignore the case of the placeholders
- */
- public boolean ignorePlaceholderCase() {
- return replacer().ignorePlaceholderCase();
- }
-
- /**
- * Enable or disable the translation of legacy color codes
- * @param translateLegacyColors Whether or not to translate legacy color codes (Default: true)
- * @return The MineDown instance
- * @deprecated Use {@link #enable(MineDownParser.Option)} and {@link #disable(MineDownParser.Option)}
- */
- @Deprecated
- public MineDown translateLegacyColors(boolean translateLegacyColors) {
- reset();
- parser().translateLegacyColors(translateLegacyColors);
- return this;
- }
-
- /**
- * Detect urls in strings and add events to them? (Default: true)
- * @param enabled Whether or not to detect URLs and add events to them
- * @return The MineDown instance
- */
- public MineDown urlDetection(boolean enabled) {
- reset();
- parser().urlDetection(enabled);
- return this;
- }
-
- /**
- * Automatically add http to values of open_url when there doesn't exist any? (Default: true)
- * @param enabled Whether or not to automatically add http when missing
- * @return The MineDown instance
- */
- public MineDown autoAddUrlPrefix(boolean enabled) {
- reset();
- parser().autoAddUrlPrefix(enabled);
- return this;
- }
-
- /**
- * The text to display when hovering over an URL
- * @param text The text to display when hovering over an URL
- * @return The MineDown instance
- */
- public MineDown urlHoverText(String text) {
- reset();
- parser().urlHoverText(text);
- return this;
- }
-
- /**
- * Set the max width the hover text should have.
- * Minecraft itself will wrap after 60 characters.
- * Won't apply if the text already includes new lines.
- * @param hoverTextWidth The url hover text length
- * @return The MineDown instance
- */
- public MineDown hoverTextWidth(int hoverTextWidth) {
- reset();
- parser().hoverTextWidth(hoverTextWidth);
- return this;
- }
-
- /**
- * Enable an option. Unfilter it if you filtered it before.
- * @param option The option to enable
- * @return The MineDown instance
- */
- public MineDown enable(MineDownParser.Option option) {
- reset();
- parser().enable(option);
- return this;
- }
-
- /**
- * Disable an option. Disabling an option will stop the parser from replacing
- * this option's chars in the string. Use {@link #filter(MineDownParser.Option)} to completely
- * remove the characters used by this option from the message instead.
- * @param option The option to disable
- * @return The MineDown instance
- */
- public MineDown disable(MineDownParser.Option option) {
- reset();
- parser().disable(option);
- return this;
- }
-
- /**
- * Filter an option. This completely removes the characters of this option from
- * the string ignoring whether the option is enabled or not.
- * @param option The option to add to the filter
- * @return The MineDown instance
- */
- public MineDown filter(MineDownParser.Option option) {
- reset();
- parser().filter(option);
- return this;
- }
-
- /**
- * Unfilter an option. Does not enable it!
- * @param option The option to remove from the filter
- * @return The MineDown instance
- */
- public MineDown unfilter(MineDownParser.Option option) {
- reset();
- parser().unfilter(option);
- return this;
- }
-
- /**
- * Set a special character to replace color codes by if translating legacy colors is enabled.
- * @param colorChar The character to use as a special color code. (Default: ampersand &)
- * @return The MineDown instance
- */
- public MineDown colorChar(char colorChar) {
- reset();
- parser().colorChar(colorChar);
- return this;
- }
-
- /**
- * Get the set message that is to be parsed
- * @return The to be parsed message
- */
- public String message() {
- return this.message;
- }
-
- /**
- * Set the message that is to be parsed
- * @param message The message to be parsed
- * @return The MineDown instance
- */
- public MineDown message(String message) {
- this.message = message;
- reset();
- return this;
- }
-
- /**
- * Get the replacer instance that is currently used
- * @return The currently used replacer instance
- */
- public Replacer replacer() {
- return this.replacer;
- }
-
- /**
- * Get the parser instance that is currently used
- * @return The currently used parser instance
- */
- public MineDownParser parser() {
- return this.parser;
- }
-
- protected BaseComponent[] baseComponents() {
- return this.baseComponents;
- }
-
- /**
- * Copy all MineDown settings to a new instance
- * @return The new MineDown instance with all settings copied
- */
- public MineDown copy() {
- return new MineDown(message()).copy(this);
- }
-
- /**
- * Copy all MineDown settings from another one
- * @param from The MineDown to copy from
- * @return This MineDown instance
- */
- public MineDown copy(MineDown from) {
- replacer().copy(from.replacer());
- parser().copy(from.parser());
- return this;
- }
-
- /**
- * Get the string that represents the format in MineDown
- * @param format The format
- * @return The MineDown string or an empty one if it's not a format
- */
- public static String getFormatString(ChatColor format) {
- if (format == ChatColor.BOLD) {
- return "**";
- } else if (format == ChatColor.ITALIC) {
- return "##";
- } else if (format == ChatColor.UNDERLINE) {
- return "__";
- } else if (format == ChatColor.STRIKETHROUGH) {
- return "~~";
- } else if (format == ChatColor.MAGIC) {
- return "??";
- }
- return "";
- }
-
- /**
- * Get the ChatColor format from a MineDown string
- * @param c The character
- * @return The ChatColor of that format or null it none was found
- */
- public static ChatColor getFormatFromChar(char c) {
- switch (c) {
- case '~':
- return ChatColor.STRIKETHROUGH;
- case '_':
- return ChatColor.UNDERLINE;
- case '*':
- return ChatColor.BOLD;
- case '#':
- return ChatColor.ITALIC;
- case '?':
- return ChatColor.MAGIC;
- }
- return null;
- }
-
- /**
- * Escape all MineDown formatting in a string. This will escape backslashes too!
- * @param string The string to escape in
- * @return The string with formatting escaped
- */
- public static String escape(String string) {
- return new MineDown(string).parser().escape(string);
- }
-}
diff --git a/src/main/java/net/momirealms/customcrops/Libs/minedown/MineDownParser.java b/src/main/java/net/momirealms/customcrops/Libs/minedown/MineDownParser.java
deleted file mode 100644
index 5751122..0000000
--- a/src/main/java/net/momirealms/customcrops/Libs/minedown/MineDownParser.java
+++ /dev/null
@@ -1,1241 +0,0 @@
-package net.momirealms.customcrops.Libs.minedown;
-
-/*
- * Copyright (c) 2017 Max Lee (https://github.com/Phoenix616)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import net.md_5.bungee.api.ChatColor;
-import net.md_5.bungee.api.chat.BaseComponent;
-import net.md_5.bungee.api.chat.ClickEvent;
-import net.md_5.bungee.api.chat.ComponentBuilder;
-import net.md_5.bungee.api.chat.HoverEvent;
-import net.md_5.bungee.api.chat.ItemTag;
-import net.md_5.bungee.api.chat.TextComponent;
-import net.md_5.bungee.api.chat.hover.content.Entity;
-import net.md_5.bungee.api.chat.hover.content.Item;
-import net.md_5.bungee.api.chat.hover.content.Text;
-
-import java.awt.Color;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.PrimitiveIterator;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-import static net.momirealms.customcrops.Libs.minedown.MineDown.COLOR_PREFIX;
-import static net.momirealms.customcrops.Libs.minedown.MineDown.FONT_PREFIX;
-import static net.momirealms.customcrops.Libs.minedown.MineDown.FORMAT_PREFIX;
-import static net.momirealms.customcrops.Libs.minedown.MineDown.HOVER_PREFIX;
-import static net.momirealms.customcrops.Libs.minedown.MineDown.INSERTION_PREFIX;
-
-public class MineDownParser {
- private static final String RAINBOW = "rainbow";
-
- private static final boolean HAS_APPEND_SUPPORT = Util.hasMethod(ComponentBuilder.class, "append", BaseComponent[].class);
- private static final boolean HAS_RGB_SUPPORT = Util.hasMethod(ChatColor.class, "of", String.class);
- private static final boolean HAS_FONT_SUPPORT = Util.hasMethod(ComponentBuilder.class, "font", String.class);
- private static final boolean HAS_INSERTION_SUPPORT = Util.hasMethod(ComponentBuilder.class, "insertion", String.class);
- private static final boolean HAS_HOVER_CONTENT_SUPPORT = Util.hasMethod(HoverEvent.class, "getContents");
-
- /**
- * The character to use as a special color code. (Default: ampersand &)
- */
- private char colorChar = '&';
-
- /**
- * All enabled options
- */
- private Set enabledOptions = EnumSet.of(
- Option.LEGACY_COLORS,
- Option.SIMPLE_FORMATTING,
- Option.ADVANCED_FORMATTING
- );
-
- /**
- * All filters
- */
- private Set filteredOptions = EnumSet.noneOf(Option.class);
-
- /**
- * Whether to accept malformed strings or not (Default: false)
- */
- private boolean lenient = false;
-
- /**
- * Should the parser try to detect if RGB/font/insertion support is available?
- */
- private boolean backwardsCompatibility = true;
-
- /**
- * Detect urls in strings and add events to them? (Default: true)
- */
- private boolean urlDetection = true;
-
- /**
- * The text to display when hovering over an URL. Has a %url% placeholder.
- */
- private String urlHoverText = "Click to open url";
-
- /**
- * Automatically add http to values of open_url when there doesn't exist any? (Default: true)
- */
- private boolean autoAddUrlPrefix = true;
-
- /**
- * The max width the hover text should have.
- * Minecraft itself will wrap after 60 characters.
- * Won't apply if the text already includes new lines.
- */
- private int hoverTextWidth = 60;
-
- public static final Pattern URL_PATTERN = Pattern.compile("^(?:(https?)://)?([-\\w_\\.]{2,}\\.[a-z]{2,4})(/\\S*)?$");
-
- private ComponentBuilder builder;
- private StringBuilder value;
- private String font;
- private String insertion;
- private Integer rainbowPhase;
- private Map colors;
- private Map format;
- private boolean formattingIsLegacy = false;
- private ClickEvent clickEvent;
- private HoverEvent hoverEvent;
-
- public MineDownParser() {
- reset();
- }
-
- /**
- * Create a ComponentBuilder by parsing a {@link MineDown} message
- * @param message The message to parse
- * @return The parsed ComponentBuilder
- * @throws IllegalArgumentException Thrown when a parsing error occurs and lenient is set to false
- */
- public ComponentBuilder parse(String message) throws IllegalArgumentException {
- Matcher urlMatcher = urlDetection() ? URL_PATTERN.matcher(message) : null;
- boolean escaped = false;
- for (int i = 0; i < message.length(); i++) {
- char c = message.charAt(i);
-
- boolean isEscape = c == '\\' && i + 1 < message.length();
- boolean isColorCode = isEnabled(Option.LEGACY_COLORS)
- && i + 1 < message.length() && (c == ChatColor.COLOR_CHAR || c == colorChar());
- boolean isEvent = false;
- if (isEnabled(Option.ADVANCED_FORMATTING) && c == '[') {
- int nextEventClose = Util.indexOfNotEscaped(message, "](", i + 1);
- if (nextEventClose != -1 && nextEventClose + 2 < message.length()) {
- int nextDefClose = Util.indexOfNotEscaped(message, ")", i + 2);
- if (nextDefClose != -1) {
- int depth = 1;
- isEvent = true;
- boolean innerEscaped = false;
- for (int j = i + 1; j < nextEventClose; j++) {
- if (innerEscaped) {
- innerEscaped = false;
- } else if (message.charAt(j) == '\\') {
- innerEscaped = true;
- } else if (message.charAt(j) == '[') {
- depth++;
- } else if (message.charAt(j) == ']') {
- depth--;
- }
- if (depth == 0) {
- isEvent = false;
- break;
- }
- }
- }
- }
- }
- boolean isFormatting = isEnabled(Option.SIMPLE_FORMATTING)
- && (c == '_' || c == '*' || c == '~' || c == '?' || c == '#') && Util.isDouble(message, i)
- && message.indexOf(String.valueOf(c) + String.valueOf(c), i + 2) != -1;
-
- if (escaped) {
- escaped = false;
-
- // Escaping
- } else if (isEscape) {
- escaped = true;
- continue;
-
- // Legacy color codes
- } else if (isColorCode) {
- i++;
- char code = message.charAt(i);
- if (code >= 'A' && code <= 'Z') {
- code += 32;
- }
- boolean isLegacyHex = code == 'x';
- if (isLegacyHex) {
- i = i + 2;
- }
- Integer rainbowPhase = null;
- Map encoded = null;
- Option filterOption = null;
- StringBuilder colorString = new StringBuilder();
- for (int j = i; j < message.length(); j++) {
- char c1 = message.charAt(j);
- // Check if we have reached another indicator char and have a color string that isn't just one char
- if (c1 == c) {
- if (isLegacyHex) {
- continue;
- } else if (colorString.length() > 1) {
- String colorStr = colorString.toString();
- rainbowPhase = parseRainbow(colorStr, "", lenient());
- if (rainbowPhase == null && !colorStr.contains("=")) {
- encoded = parseColor(colorStr, "", true, backwardsCompatibility());
- if (encoded.isEmpty()) {
- encoded = null;
- } else {
- filterOption = Option.SIMPLE_FORMATTING;
- i = j;
- }
- } else {
- filterOption = Option.SIMPLE_FORMATTING;
- i = j;
- }
- break;
- }
- }
- if (!isLegacyHex && c1 != '_' && c1 != '#' && c1 != '-' && c1 != ',' && c1 != ':' &
- (c1 < 'A' || c1 > 'Z') && (c1 < 'a' || c1 > 'z') && (c1 < '0' || c1 > '9')) {
- break;
- }
- if (!isLegacyHex || c1 != 'x') {
- colorString.append(c1);
- if (isLegacyHex && colorString.length() == 6) {
- encoded = parseColor("#" + colorString.toString(), "", true, backwardsCompatibility());
- if (encoded.isEmpty()) {
- encoded = null;
- } else {
- filterOption = Option.LEGACY_COLORS;
- i = j;
- }
- break;
- }
- }
- }
- if (rainbowPhase == null && encoded == null) {
- ChatColor byChar = ChatColor.getByChar(code);
- if (byChar != null) {
- filterOption = Option.LEGACY_COLORS;
- encoded = new LinkedHashMap<>();
- encoded.put(byChar, true);
- }
- }
-
- if (rainbowPhase != null || encoded != null) {
- if (!isFiltered(filterOption)) {
- if (encoded != null && encoded.size() == 1) {
- Map.Entry single = encoded.entrySet().iterator().next();
- if (single.getKey() == ChatColor.RESET) {
- appendValue();
- colors(new LinkedHashMap<>());
- rainbowPhase(null);
- Util.applyFormat(builder(), format());
- format(new HashMap<>());
- } else if (!Util.isFormat(single.getKey())) {
- if (value().length() > 0) {
- appendValue();
- }
- colors(new LinkedHashMap<>());
- colors().put(single.getKey(), single.getValue());
- rainbowPhase(null);
- if (formattingIsLegacy()) {
- format(new HashMap<>());
- }
- } else {
- if (value().length() > 0) {
- appendValue();
- }
- formattingIsLegacy(true);
- format().put(single.getKey(), single.getValue());
- }
- } else {
- if (value().length() > 0) {
- appendValue();
- }
- rainbowPhase(rainbowPhase);
- colors(encoded);
- if (formattingIsLegacy()) {
- format(new HashMap<>());
- }
- }
- }
- } else {
- value().append(c).append(code);
- }
- continue;
-
- // Events
- } else if (isEvent) {
- int index = Util.indexOfNotEscaped(message, "](", i + 1);
- int endIndex = Util.indexOfNotEscaped(message, ")", index + 2);
- appendValue();
- if (!isFiltered(Option.ADVANCED_FORMATTING)) {
- append(parseEvent(message.substring(i + 1, index), message.substring(index + 2, endIndex)));
- } else {
- append(copy(true).parse(message.substring(i + 1, index)));
- }
- i = endIndex;
- continue;
-
- // Simple formatting
- } else if (isFormatting) {
- int endIndex = message.indexOf(String.valueOf(c) + String.valueOf(c), i + 2);
- Map formats = new HashMap<>(format());
- if (!isFiltered(Option.SIMPLE_FORMATTING)) {
- formats.put(MineDown.getFormatFromChar(c), true);
- }
- formattingIsLegacy(false);
- appendValue();
- append(copy(true).format(formats).parse(message.substring(i + 2, endIndex)));
- i = endIndex + 1;
- continue;
- }
-
- // URL
- if (urlDetection() && urlMatcher != null) {
- int urlEnd = message.indexOf(' ', i);
- if (urlEnd == -1) {
- urlEnd = message.length();
- }
- if (urlMatcher.region(i, urlEnd).find()) {
- appendValue();
- value(new StringBuilder(message.substring(i, urlEnd)));
- appendValue();
- i = urlEnd - 1;
- continue;
- }
- }
-
- // It's normal text, just append the character
- value().append(message.charAt(i));
- }
- if (escaped) {
- value().append('\\');
- }
- appendValue();
- if (builder() == null) {
- builder(new ComponentBuilder(""));
- }
- return builder();
- }
-
- private void append(ComponentBuilder builder) {
- append(builder.create());
- }
-
- private void append(BaseComponent[] components) {
- if (this.builder == null) {
- if (components.length > 0) {
- this.builder = new ComponentBuilder(components[0]);
- for (int i = 1; i < components.length; i++) {
- builder.append(components[i]);
- }
- } else {
- this.builder = new ComponentBuilder("");
- }
- } else {
- if (HAS_APPEND_SUPPORT) {
- this.builder.append(components);
- } else {
- // Older versions didn't have ComponentBuilder#append(BaseComponent[])
- // Recreating it with reflections. That might be slower but they should just update anyways...
- if (components.length > 0) {
- try {
- Field fCurrent = this.builder.getClass().getDeclaredField("current");
- fCurrent.setAccessible(true);
- BaseComponent previous = (BaseComponent) fCurrent.get(this.builder);
- Field fParts = this.builder.getClass().getDeclaredField("parts");
- fParts.setAccessible(true);
- List parts = (List) fParts.get(this.builder);
-
- for (BaseComponent component : components) {
- parts.add(previous);
- fCurrent.set(this.builder, component.duplicate());
- }
- } catch (NoSuchFieldException | IllegalAccessException e1) {
- e1.printStackTrace();
- }
- }
- }
- }
- }
-
- private void appendValue() {
- ComponentBuilder builder;
- List applicableColors;
- long valueCodepointLength = value().length();
- if (rainbowPhase != null) {
- // Rainbow colors
- valueCodepointLength = value().codePoints().count();
- applicableColors = Util.createRainbow(valueCodepointLength, rainbowPhase, HAS_RGB_SUPPORT);
- } else if (colors != null) {
- if (colors.size() > 1) {
- valueCodepointLength = value().codePoints().count();
- applicableColors = Util.createGradient(
- valueCodepointLength,
- colors.entrySet().stream().filter(Map.Entry::getValue).map(Map.Entry::getKey).collect(Collectors.toList()),
- HAS_RGB_SUPPORT);
- } else {
- applicableColors = new ArrayList<>(colors.keySet());
- }
- } else {
- applicableColors = new ArrayList<>();
- }
-
- if (applicableColors.size() > 1) {
- // Colors need to have a gradient/rainbow applied
- builder = new ComponentBuilder();
- } else {
- // Single color mode
- if (this.builder == null) {
- builder = new ComponentBuilder(value.toString());
- } else {
- builder = this.builder.append(value.toString(), ComponentBuilder.FormatRetention.NONE);
- }
- if (applicableColors.size() == 1) {
- builder.color(applicableColors.get(0));
- }
- }
-
- if (!backwardsCompatibility || HAS_FONT_SUPPORT) {
- builder.font(font);
- }
- if (!backwardsCompatibility || HAS_INSERTION_SUPPORT) {
- builder.insertion(insertion);
- }
- Util.applyFormat(builder, format);
- if (urlDetection() && URL_PATTERN.matcher(value).matches()) {
- String v = value.toString();
- if (!v.startsWith("http://") && !v.startsWith("https://")) {
- v = "http://" + v;
- }
- builder.event(new ClickEvent(ClickEvent.Action.OPEN_URL, v));
- if (urlHoverText() != null && !urlHoverText().isEmpty()) {
- builder.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
- new MineDown(urlHoverText()).replace("url", value.toString()).toComponent()
- ));
- }
- }
- if (clickEvent != null) {
- builder.event(clickEvent);
- }
- if (hoverEvent != null) {
- builder.event(hoverEvent);
- }
-
- if (applicableColors.size() > 1) {
- int stepLength = (int) Math.round((double) valueCodepointLength / applicableColors.size());
- TextComponent component = new TextComponent();
-
- StringBuilder sb = new StringBuilder();
- int colorIndex = 0;
- int steps = 0;
-
- for (PrimitiveIterator.OfInt it = value().codePoints().iterator(); it.hasNext(); ) {
- sb.appendCodePoint(it.next());
- if (++steps == stepLength) {
- steps = 0;
- TextComponent c = new TextComponent(sb.toString());
- c.setColor(applicableColors.get(colorIndex++));
- component.addExtra(c);
- sb = new StringBuilder();
- }
- }
- builder.append(component);
- if (this.builder == null) {
- this.builder = builder;
- } else {
- this.builder.append(builder.create());
- }
- } else {
- this.builder = builder;
- }
- value = new StringBuilder();
- }
-
- /**
- * Parse a {@link MineDown} event string
- * @param text The display text
- * @param definitions The event definition string
- * @return The parsed ComponentBuilder for this string
- */
- public ComponentBuilder parseEvent(String text, String definitions) {
- List defParts = new ArrayList<>();
- if (definitions.startsWith(" ")) {
- defParts.add("");
- }
- Collections.addAll(defParts, definitions.split(" "));
- if (definitions.endsWith(" ")) {
- defParts.add("");
- }
- String font = null;
- String insertion = null;
- Integer rainbowPhase = null;
- Map colors = null;
- Map formats = new HashMap<>();
- ClickEvent clickEvent = null;
- HoverEvent hoverEvent = null;
-
- int formatEnd = -1;
-
- for (AtomicInteger i = new AtomicInteger(0); i.get() < defParts.size(); i.incrementAndGet()) {
- String definition = defParts.get(i.get());
-
- Integer parsedRainbowPhase = parseRainbow(definition, "", lenient());
- if (parsedRainbowPhase != null) {
- rainbowPhase = parsedRainbowPhase;
- continue;
- } else if (!definition.contains("=")) {
- Map parsed = parseColor(definition, "", true, backwardsCompatibility());
- if (!parsed.isEmpty()) {
- for (Map.Entry e : parsed.entrySet()) {
- if (Util.isFormat(e.getKey())) {
- formats.put(e.getKey(), e.getValue());
- } else {
- if (colors == null) {
- colors = new LinkedHashMap<>();
- }
- colors.put(e.getKey(), e.getValue());
- }
- }
- formatEnd = i.get();
- continue;
- }
- }
-
- if (definition.toLowerCase(Locale.ROOT).startsWith(FONT_PREFIX)) {
- font = definition.substring(FONT_PREFIX.length());
- continue;
- }
-
- if (definition.toLowerCase(Locale.ROOT).startsWith(INSERTION_PREFIX)) {
- insertion = getValue(i, definition.substring(INSERTION_PREFIX.length()), defParts, true);
- continue;
- }
-
- if (definition.toLowerCase(Locale.ROOT).startsWith(COLOR_PREFIX)) {
- rainbowPhase = parseRainbow(definition, COLOR_PREFIX, lenient());
- if (rainbowPhase == null) {
- colors = parseColor(definition, COLOR_PREFIX, lenient(), backwardsCompatibility());
- if (!lenient()) {
- for (Map.Entry e : colors.entrySet()) {
- if (Util.isFormat(e.getKey())) {
- throw new IllegalArgumentException(e + " is a format and not a color!");
- }
- }
- }
- }
- formatEnd = i.get();
- continue;
- }
-
- if (definition.toLowerCase(Locale.ROOT).startsWith(FORMAT_PREFIX)) {
- Map parsed = parseColor(definition, FORMAT_PREFIX, lenient(), backwardsCompatibility());
- for (Map.Entry e : parsed.entrySet()) {
- if (Util.isFormat(e.getKey())) {
- formats.put(e.getKey(), e.getValue());
- } else {
- if (!lenient()) {
- throw new IllegalArgumentException(e + " is a color and not a format!");
- }
- }
- }
- formatEnd = i.get();
- continue;
- }
-
- if (i.get() == formatEnd + 1 && URL_PATTERN.matcher(definition).matches()) {
- if (!definition.startsWith("http://") && !definition.startsWith("https://")) {
- definition = "http://" + definition;
- }
- clickEvent = new ClickEvent(ClickEvent.Action.OPEN_URL, definition);
- continue;
- }
-
- ClickEvent.Action clickAction = definition.startsWith("/") ? ClickEvent.Action.RUN_COMMAND : null;
- HoverEvent.Action hoverAction = null;
- if (definition.toLowerCase(Locale.ROOT).startsWith(HOVER_PREFIX)) {
- hoverAction = HoverEvent.Action.SHOW_TEXT;
- }
- String[] parts = definition.split("=", 2);
- try {
- hoverAction = HoverEvent.Action.valueOf(parts[0].toUpperCase(Locale.ROOT));
- } catch (IllegalArgumentException ignored) {
- }
- try {
- clickAction = ClickEvent.Action.valueOf(parts[0].toUpperCase(Locale.ROOT));
- } catch (IllegalArgumentException ignored) {
- }
-
- String valueStr = getValue(i, parts.length > 1 ? parts[1] : "", defParts, clickAction != null || hoverAction != null);
- if (clickAction != null) {
- if (autoAddUrlPrefix() && clickAction == ClickEvent.Action.OPEN_URL && !valueStr.startsWith("http://") && !valueStr.startsWith("https://")) {
- valueStr = "http://" + valueStr;
- }
- clickEvent = new ClickEvent(clickAction, valueStr);
- } else if (hoverAction == null) {
- hoverAction = HoverEvent.Action.SHOW_TEXT;
- }
- if (hoverAction != null) {
- if (!HAS_HOVER_CONTENT_SUPPORT) {
- hoverEvent = new HoverEvent(hoverAction, copy(false).urlDetection(false).parse(
- hoverAction == HoverEvent.Action.SHOW_TEXT ? Util.wrap(valueStr, hoverTextWidth()) : valueStr
- ).create());
- } else if (hoverAction == HoverEvent.Action.SHOW_TEXT) {
- hoverEvent = new HoverEvent(hoverAction, new Text(copy(false).urlDetection(false).parse(
- Util.wrap(valueStr, hoverTextWidth())
- ).create()));
- } else if (hoverAction == HoverEvent.Action.SHOW_ENTITY) {
- String[] valueParts = valueStr.split(":", 2);
- try {
- String[] additionalParts = valueParts[1].split(" ", 2);
- if (!additionalParts[0].contains(":")) {
- additionalParts[0] = "minecraft:" + additionalParts[0];
- }
- hoverEvent = new HoverEvent(hoverAction, new Entity(
- additionalParts[0], valueParts[0],
- additionalParts.length > 1 && additionalParts[1] != null ?
- new TextComponent(copy(false).urlDetection(false).parse(additionalParts[1]).create()) : null
- ));
- } catch (Exception e) {
- if (!lenient()) {
- if (valueParts.length < 2) {
- throw new IllegalArgumentException("Invalid entity definition. Needs to be of format uuid:id or uuid:namespace:id!");
- }
- throw new IllegalArgumentException(e.getMessage());
- }
- }
- } else if (hoverAction == HoverEvent.Action.SHOW_ITEM) {
- String[] valueParts = valueStr.split(" ", 2);
- String id = valueParts[0];
- if (!id.contains(":")) {
- id = "minecraft:" + id;
- }
- int count = 1;
- int countIndex = valueParts[0].indexOf('*');
- if (countIndex > 0 && countIndex + 1 < valueParts[0].length()) {
- try {
- count = Integer.parseInt(valueParts[0].substring(countIndex + 1));
- id = valueParts[0].substring(0, countIndex);
- } catch (NumberFormatException e) {
- if (!lenient()) {
- throw new IllegalArgumentException(e.getMessage());
- }
- }
- }
- ItemTag tag = null;
- if (valueParts.length > 1 && valueParts[1] != null) {
- tag = ItemTag.ofNbt(valueParts[1]);
- }
-
- hoverEvent = new HoverEvent(hoverAction, new Item(
- id, count, tag
- ));
- }
- }
- }
-
- if (clickEvent != null && hoverEvent == null) {
- hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT,
- new ComponentBuilder(clickEvent.getAction().toString().toLowerCase(Locale.ROOT).replace('_', ' ')).color(ChatColor.BLUE)
- .append(" " + clickEvent.getValue()).color(ChatColor.WHITE)
- .create());
- }
-
- return copy()
- .urlDetection(false)
- .font(font)
- .insertion(insertion)
- .rainbowPhase(rainbowPhase)
- .colors(colors)
- .format(formats)
- .clickEvent(clickEvent)
- .hoverEvent(hoverEvent)
- .parse(text);
- }
-
- private String getValue(AtomicInteger i, String firstPart, List defParts, boolean hasAction) {
- int bracketDepth = !firstPart.isEmpty() && firstPart.startsWith("{") && hasAction ? 1 : 0;
-
- StringBuilder value = new StringBuilder();
- if (!firstPart.isEmpty() && hasAction) {
- if (bracketDepth > 0) {
- value.append(firstPart.substring(1));
- } else {
- value.append(firstPart);
- }
- } else {
- value.append(defParts.get(i.get()));
- }
-
- for (i.incrementAndGet(); i.get() < defParts.size(); i.incrementAndGet()) {
- String part = defParts.get(i.get());
- if (bracketDepth == 0) {
- int equalsIndex = part.indexOf('=');
- if (equalsIndex > 0 && !Util.isEscaped(part, equalsIndex)) {
- i.decrementAndGet();
- break;
- }
- }
- value.append(" ");
- if (bracketDepth > 0) {
- int startBracketIndex = part.indexOf("={");
- if (startBracketIndex > 0 && !Util.isEscaped(part, startBracketIndex) && !Util.isEscaped(part, startBracketIndex + 1)) {
- bracketDepth++;
- }
- if (part.endsWith("}") && !Util.isEscaped(part, part.length() - 1)) {
- bracketDepth--;
- if (bracketDepth == 0) {
- value.append(part, 0, part.length() - 1);
- break;
- }
- }
- }
- value.append(part);
- }
-
- return value.toString();
- }
-
- protected ComponentBuilder builder() {
- return this.builder;
- }
-
- protected MineDownParser builder(ComponentBuilder builder) {
- this.builder = builder;
- return this;
- }
-
- protected MineDownParser value(StringBuilder value) {
- this.value = value;
- return this;
- }
-
- protected StringBuilder value() {
- return this.value;
- }
-
- private MineDownParser font(String font) {
- this.font = font;
- return this;
- }
-
- protected String font() {
- return this.font;
- }
-
- private MineDownParser insertion(String insertion) {
- this.insertion = insertion;
- return this;
- }
-
- protected String insertion() {
- return this.insertion;
- }
-
- protected MineDownParser rainbowPhase(Integer rainbowPhase) {
- this.rainbowPhase = rainbowPhase;
- return this;
- }
-
- protected Integer rainbowPhase() {
- return this.rainbowPhase;
- }
-
- protected MineDownParser colors(Map colors) {
- this.colors = colors;
- return this;
- }
-
- protected Map colors() {
- return this.colors;
- }
-
- protected MineDownParser format(Map format) {
- this.format = format;
- return this;
- }
-
- protected Map format() {
- return this.format;
- }
-
- protected MineDownParser formattingIsLegacy(boolean formattingIsLegacy) {
- this.formattingIsLegacy = formattingIsLegacy;
- return this;
- }
-
- protected boolean formattingIsLegacy() {
- return formattingIsLegacy;
- }
-
- protected MineDownParser clickEvent(ClickEvent clickEvent) {
- this.clickEvent = clickEvent;
- return this;
- }
-
- protected ClickEvent clickEvent() {
- return this.clickEvent;
- }
-
- protected MineDownParser hoverEvent(HoverEvent hoverEvent) {
- this.hoverEvent = hoverEvent;
- return this;
- }
-
- protected HoverEvent hoverEvent() {
- return this.hoverEvent;
- }
-
- private static Integer parseRainbow(String colorString, String prefix, boolean lenient) {
- if (colorString.substring(prefix.length()).toLowerCase(Locale.ROOT).startsWith(RAINBOW)) {
- if (colorString.length() > prefix.length() + RAINBOW.length() + 1) {
- try {
- return Integer.parseInt(colorString.substring(prefix.length() + RAINBOW.length() + 1));
- } catch (NumberFormatException e) {
- if (!lenient) throw e;
- }
- } else {
- return 0;
- }
- }
- return null;
- }
-
- private static Map parseColor(String colorString, String prefix, boolean lenient, boolean backwardsCompatibility) {
- Map colors = new LinkedHashMap<>();
- if (prefix.length() + 1 == colorString.length()) {
- ChatColor color = ChatColor.getByChar(colorString.charAt(prefix.length()));
- if (color == null && !lenient) {
- throw new IllegalArgumentException(colorString.charAt(prefix.length()) + " is not a valid " + prefix + " char!");
- }
- colors.put(color, true);
- } else {
- for (String part : colorString.substring(prefix.length()).split("[\\-,]")) {
- boolean negated = part.charAt(0) == '!';
- if (negated) {
- part = part.substring(1);
- }
- if (part.charAt(0) == '#') {
- if (part.length() == 4) {
- StringBuilder sb = new StringBuilder("#");
- for (int i = 1; i < 4; i++) {
- sb.append(part.charAt(i)).append(part.charAt(i));
- }
- part = sb.toString();
- }
- ChatColor color = null;
- if (!backwardsCompatibility || HAS_RGB_SUPPORT) {
- try {
- color = ChatColor.of(part);
- } catch (IllegalArgumentException e) {
- if (!lenient) throw e;
- }
- } else {
- color = Util.getClosestLegacy(new Color(Integer.parseInt(part.substring(1), 16)));
- }
- if (color != null) {
- colors.put(color, !negated);
- }
- } else {
- try {
- colors.put(ChatColor.valueOf(part.toUpperCase(Locale.ROOT)), !negated);
- } catch (IllegalArgumentException e) {
- if (!lenient) throw e;
- }
- }
- }
- }
- return colors;
- }
-
- /**
- * Copy all the parser's setting to a new instance
- * @return The new parser instance with all settings copied
- */
- public MineDownParser copy() {
- return copy(false);
- }
-
- /**
- * Copy all the parser's setting to a new instance
- * @param formatting Should the formatting be copied too?
- * @return The new parser instance with all settings copied
- */
- public MineDownParser copy(boolean formatting) {
- return new MineDownParser().copy(this, formatting);
- }
-
- /**
- * Copy all the parser's settings from another parser.
- * @param from The parser to copy from
- * @return This parser's instance
- */
- public MineDownParser copy(MineDownParser from) {
- return copy(from, false);
- }
-
- /**
- * Copy all the parser's settings from another parser.
- * @param from The parser to copy from
- * @param formatting Should the formatting be copied too?
- * @return This parser's instance
- */
- public MineDownParser copy(MineDownParser from, boolean formatting) {
- lenient(from.lenient());
- urlDetection(from.urlDetection());
- urlHoverText(from.urlHoverText());
- autoAddUrlPrefix(from.autoAddUrlPrefix());
- hoverTextWidth(from.hoverTextWidth());
- enabledOptions(from.enabledOptions());
- filteredOptions(from.filteredOptions());
- colorChar(from.colorChar());
- if (formatting) {
- format(from.format());
- formattingIsLegacy(from.formattingIsLegacy());
- colors(from.colors());
- font(from.font());
- insertion(from.insertion());
- clickEvent(from.clickEvent());
- hoverEvent(from.hoverEvent());
- }
- return this;
- }
-
- /**
- * Reset the parser state to the start
- * @return The parser's instance
- */
- public MineDownParser reset() {
- builder = null;
- value = new StringBuilder();
- font = null;
- insertion = null;
- colors = null;
- format = new HashMap<>();
- clickEvent = null;
- hoverEvent = null;
- return this;
- }
-
- /**
- * Whether or not to translate legacy color codes (Default: true)
- * @return Whether or not to translate legacy color codes (Default: true)
- * @deprecated Use {@link #isEnabled(Option)} instead
- */
- @Deprecated
- public boolean translateLegacyColors() {
- return isEnabled(Option.LEGACY_COLORS);
- }
-
- /**
- * Whether or not to translate legacy color codes
- * @return The parser
- * @deprecated Use {@link #enable(Option)} and {@link #disable(Option)} instead
- */
- @Deprecated
- public MineDownParser translateLegacyColors(boolean enabled) {
- return enabled ? enable(Option.LEGACY_COLORS) : disable(Option.LEGACY_COLORS);
- }
-
- /**
- * Check whether or not an option is enabled
- * @param option The option to check for
- * @return true if it's enabled; false if not
- */
- public boolean isEnabled(Option option) {
- return enabledOptions().contains(option);
- }
-
- /**
- * Enable an option.
- * @param option The option to enable
- * @return The parser instace
- */
- public MineDownParser enable(Option option) {
- enabledOptions().add(option);
- return this;
- }
-
- /**
- * Disable an option. Disabling an option will stop the parser from replacing
- * this option's chars in the string. Use {@link #filter(Option)} to completely
- * remove the characters used by this option from the message instead.
- * @param option The option to disable
- * @return The parser instace
- */
- public MineDownParser disable(Option option) {
- enabledOptions().remove(option);
- return this;
- }
-
- /**
- * Check whether or not an option is filtered
- * @param option The option to check for
- * @return true if it's enabled; false if not
- */
- public boolean isFiltered(Option option) {
- return filteredOptions().contains(option);
- }
-
- /**
- * Filter an option. This enables the parsing of an option and completely
- * removes the characters of this option from the string.
- * @param option The option to add to the filter
- * @return The parser instance
- */
- public MineDownParser filter(Option option) {
- filteredOptions().add(option);
- enabledOptions().add(option);
- return this;
- }
-
- /**
- * Unfilter an option. Does not enable it!
- * @param option The option to remove from the filter
- * @return The parser instance
- */
- public MineDownParser unfilter(Option option) {
- filteredOptions().remove(option);
- return this;
- }
-
- /**
- * Escape formatting in the string depending on this parser's options. This will escape backslashes too!
- * @param string The string to escape
- * @return The string with all formatting of this parser escaped
- */
- public String escape(String string) {
- StringBuilder value = new StringBuilder();
- for (int i = 0; i < string.length(); i++) {
- char c = string.charAt(i);
-
- boolean isEscape = c == '\\';
- boolean isColorCode = isEnabled(Option.LEGACY_COLORS)
- && i + 1 < string.length() && (c == ChatColor.COLOR_CHAR || c == colorChar());
- boolean isEvent = isEnabled(Option.ADVANCED_FORMATTING)
- && c == '[';
- boolean isFormatting = isEnabled(Option.SIMPLE_FORMATTING)
- && (c == '_' || c == '*' || c == '~' || c == '?' || c == '#') && Util.isDouble(string, i);
-
- if (isEscape || isColorCode || isEvent || isFormatting) {
- value.append('\\');
- }
- value.append(c);
- }
- return value.toString();
- }
-
- public enum Option {
- /**
- * Translate simple, in-line MineDown formatting in strings? (Default: true)
- */
- SIMPLE_FORMATTING,
- /**
- * Translate advanced MineDown formatting (e.g. events) in strings? (Default: true)
- */
- ADVANCED_FORMATTING,
- /**
- * Whether or not to translate legacy color codes (Default: true)
- */
- LEGACY_COLORS
- }
-
- /**
- * Get The character to use as a special color code.
- * @return The color character (Default: ampersand &)
- */
- public char colorChar() {
- return this.colorChar;
- }
-
- /**
- * Set the character to use as a special color code.
- * @param colorChar The color char (Default: ampersand &)
- * @return The MineDownParser instance
- */
- public MineDownParser colorChar(char colorChar) {
- this.colorChar = colorChar;
- return this;
- }
-
- /**
- * Get all enabled options that will be used when parsing
- * @return a modifiable set of options
- */
- public Set enabledOptions() {
- return this.enabledOptions;
- }
-
- /**
- * Set all enabled options that will be used when parsing at once, replaces any existing options
- * @param enabledOptions The enabled options
- * @return The MineDownParser instance
- */
- public MineDownParser enabledOptions(Set enabledOptions) {
- this.enabledOptions = enabledOptions;
- return this;
- }
-
- /**
- * Get all filtered options that will be parsed and then removed from the string
- * @return a modifiable set of options
- */
- public Set filteredOptions() {
- return this.filteredOptions;
- }
-
- /**
- * Set all filtered options that will be parsed and then removed from the string at once,
- * replaces any existing options
- * @param filteredOptions The filtered options
- * @return The MineDownParser instance
- */
- public MineDownParser filteredOptions(Set filteredOptions) {
- this.filteredOptions = filteredOptions;
- return this;
- }
-
- /**
- * Get whether to accept malformed strings or not
- * @return whether or not the accept malformed strings (Default: false)
- */
- public boolean lenient() {
- return this.lenient;
- }
-
- /**
- * Set whether to accept malformed strings or not
- * @param lenient Set whether or not to accept malformed string (Default: false)
- * @return The MineDownParser instance
- */
- public MineDownParser lenient(boolean lenient) {
- this.lenient = lenient;
- return this;
- }
-
- /**
- * Get whether the parser should try to detect if RGB/font support is available
- * @return whether the parser should try to detect if RGB/font support is available (Default: true)
- */
- public boolean backwardsCompatibility() {
- return this.backwardsCompatibility;
- }
-
- /**
- * Set whether the parser should try to detect if RGB/font support is available
- * @param backwardsCompatibility Set whether the parser should try to detect if RGB/font support is available (Default: true)
- * @return The MineDownParser instance
- */
- public MineDownParser backwardsCompatibility(boolean backwardsCompatibility) {
- this.backwardsCompatibility = backwardsCompatibility;
- return this;
- }
-
- /**
- * Get whether or not urls in strings are detected and get events added to them?
- * @return whether or not urls are detected (Default: true)
- */
- public boolean urlDetection() {
- return this.urlDetection;
- }
-
- /**
- * Set whether or not to detect urls in strings and add events to them?
- * @param urlDetection Whether or not to detect urls in strings (Default: true)
- * @return The MineDownParser instance
- */
- public MineDownParser urlDetection(boolean urlDetection) {
- this.urlDetection = urlDetection;
- return this;
- }
-
- /**
- * Get the text to display when hovering over an URL. Has a %url% placeholder.
- */
- public String urlHoverText() {
- return this.urlHoverText;
- }
-
- /**
- * Set the text to display when hovering over an URL. Has a %url% placeholder.
- * @param urlHoverText The url hover text
- * @return The MineDownParser instance
- */
- public MineDownParser urlHoverText(String urlHoverText) {
- this.urlHoverText = urlHoverText;
- return this;
- }
-
- /**
- * Get whether or not to automatically add http to values of open_url when there doesn't exist any?
- * @return whether or not to automatically add http to values of open_url when there doesn't exist any? (Default: true)
- */
- public boolean autoAddUrlPrefix() {
- return this.autoAddUrlPrefix;
- }
-
- /**
- * Set whether or not to automatically add http to values of open_url when there doesn't exist any?
- * @param autoAddUrlPrefix Whether or not automatically add http to values of open_url when there doesn't exist any? (Default: true)
- * @return The MineDownParser instance
- */
- public MineDownParser autoAddUrlPrefix(boolean autoAddUrlPrefix) {
- this.autoAddUrlPrefix = autoAddUrlPrefix;
- return this;
- }
-
- /**
- * Get the max width the hover text should have.
- * Minecraft itself will wrap after 60 characters.
- * Won't apply if the text already includes new lines.
- */
- public int hoverTextWidth() {
- return this.hoverTextWidth;
- }
-
- /**
- * Set the max width the hover text should have.
- * Minecraft itself will wrap after 60 characters.
- * Won't apply if the text already includes new lines.
- * @param hoverTextWidth The url hover text length
- * @return The MineDownParser instance
- */
- public MineDownParser hoverTextWidth(int hoverTextWidth) {
- this.hoverTextWidth = hoverTextWidth;
- return this;
- }
-
-}
diff --git a/src/main/java/net/momirealms/customcrops/Libs/minedown/MineDownStringifier.java b/src/main/java/net/momirealms/customcrops/Libs/minedown/MineDownStringifier.java
deleted file mode 100644
index 1bbeb92..0000000
--- a/src/main/java/net/momirealms/customcrops/Libs/minedown/MineDownStringifier.java
+++ /dev/null
@@ -1,423 +0,0 @@
-package net.momirealms.customcrops.Libs.minedown;
-
-/*
- * Copyright (c) 2017 Max Lee (https://github.com/Phoenix616)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import net.md_5.bungee.api.ChatColor;
-import net.md_5.bungee.api.chat.BaseComponent;
-import net.md_5.bungee.api.chat.ClickEvent;
-import net.md_5.bungee.api.chat.HoverEvent;
-import net.md_5.bungee.api.chat.TextComponent;
-import net.md_5.bungee.api.chat.hover.content.Content;
-import net.md_5.bungee.api.chat.hover.content.Entity;
-import net.md_5.bungee.api.chat.hover.content.Item;
-import net.md_5.bungee.api.chat.hover.content.Text;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Deque;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-
-import static net.momirealms.customcrops.Libs.minedown.MineDown.COLOR_PREFIX;
-import static net.momirealms.customcrops.Libs.minedown.MineDown.FONT_PREFIX;
-import static net.momirealms.customcrops.Libs.minedown.MineDown.FORMAT_PREFIX;
-import static net.momirealms.customcrops.Libs.minedown.MineDown.HOVER_PREFIX;
-import static net.momirealms.customcrops.Libs.minedown.MineDown.INSERTION_PREFIX;
-
-public class MineDownStringifier {
-
- private static final boolean HAS_FONT_SUPPORT = Util.hasMethod(BaseComponent.class, "getFontRaw");
- private static final boolean HAS_INSERTION_SUPPORT = Util.hasMethod(BaseComponent.class, "getInsertion");
- private static final boolean HAS_HOVER_CONTENT_SUPPORT = Util.hasMethod(HoverEvent.class, "getContents");
- private static final Method HOVER_GET_VALUE = Util.getMethod(HoverEvent.class, "getValue");
-
- /**
- * Whether or not to use legacy color codes (Default: false)
- */
- private boolean useLegacyColors = false;
-
- /**
- * Whether or not to translate legacy formatting codes over Minedown ones (Default: false)
- */
- private boolean useLegacyFormatting = false;
-
- /**
- * Whether or not to use simple event definitions or specific ones (Default: true)
- */
- private boolean preferSimpleEvents = true;
-
- /**
- * Whether or not to put formatting in event definitions (Default: false)
- */
- private boolean formattingInEventDefinition = false;
-
- /**
- * Whether or not to put colors in event definitions (Default: true)
- */
- private boolean colorInEventDefinition = true;
-
- /**
- * The character to use as a special color code. (Default: ampersand &)
- */
- private char colorChar = '&';
-
- private StringBuilder value = new StringBuilder();
-
- private ChatColor color = null;
- private ClickEvent clickEvent = null;
- private HoverEvent hoverEvent = null;
- private Set formats = new LinkedHashSet<>();
-
- /**
- * Create a {@link MineDown} string from a component message
- * @param components The components to generate a MineDown string from
- * @return The MineDown string
- */
- public String stringify(BaseComponent... components) {
- StringBuilder sb = new StringBuilder();
- for (BaseComponent component : components) {
- if (!component.hasFormatting()) {
- appendText(sb, component);
- continue;
- }
- boolean hasEvent = component.getFontRaw() != null || component.getInsertion() != null
- || component.getClickEvent() != clickEvent || component.getHoverEvent() != hoverEvent;
- if (hasEvent) {
- sb.append('[');
- if (!formattingInEventDefinition()) {
- appendFormat(sb, component);
- }
- if (!colorInEventDefinition()) {
- appendColor(sb, component.getColor());
- }
- } else if (component.getColorRaw() != null) {
- appendFormat(sb, component);
- appendColor(sb, component.getColor());
- } else {
- appendFormat(sb, component);
- }
-
- appendText(sb, component);
-
- if (component.getExtra() != null && !component.getExtra().isEmpty()) {
- sb.append(copy().stringify(component.getExtra().toArray(new BaseComponent[0])));
- }
-
- if (hasEvent) {
- clickEvent = component.getClickEvent();
- hoverEvent = component.getHoverEvent();
- if (!formattingInEventDefinition()) {
- appendFormatSuffix(sb, component);
- }
- sb.append("](");
- List definitions = new ArrayList<>();
- if (colorInEventDefinition()) {
- StringBuilder sbi = new StringBuilder();
- if (!preferSimpleEvents()) {
- sbi.append(COLOR_PREFIX);
- }
- sbi.append(component.getColor().getName().toLowerCase(Locale.ROOT));
- definitions.add(sbi.toString());
- }
- if (formattingInEventDefinition()) {
- StringBuilder sbi = new StringBuilder();
- if (!preferSimpleEvents) {
- sbi.append(FORMAT_PREFIX);
- }
- sbi.append(Util.getFormats(component, true).stream().map(c -> c.getName().toLowerCase(Locale.ROOT)).collect(Collectors.joining(" ")));
- definitions.add(sbi.toString());
- }
- if (HAS_FONT_SUPPORT && component.getFontRaw() != null) {
- definitions.add(FONT_PREFIX + component.getFontRaw());
- }
- if (HAS_INSERTION_SUPPORT && component.getInsertion() != null) {
- if (component.getInsertion().contains(" ")) {
- definitions.add(INSERTION_PREFIX + "{" + component.getInsertion() + "}");
- } else {
- definitions.add(INSERTION_PREFIX + component.getInsertion());
- }
- }
- if (component.getClickEvent() != null) {
- if (preferSimpleEvents() && component.getClickEvent().getAction() == ClickEvent.Action.OPEN_URL) {
- definitions.add(component.getClickEvent().getValue());
- } else {
- definitions.add(component.getClickEvent().getAction().toString().toLowerCase(Locale.ROOT) + "=" + component.getClickEvent().getValue());
- }
- }
- if (component.getHoverEvent() != null) {
- StringBuilder sbi = new StringBuilder();
- if (preferSimpleEvents() && component.getHoverEvent().getAction() == HoverEvent.Action.SHOW_TEXT &&
- (component.getClickEvent() == null || component.getClickEvent().getAction() != ClickEvent.Action.OPEN_URL)) {
- sbi.append(HOVER_PREFIX);
- } else {
- sbi.append(component.getHoverEvent().getAction().toString().toLowerCase(Locale.ROOT)).append('=');
- }
- if (HAS_HOVER_CONTENT_SUPPORT) {
- sbi.append(copy().stringify(component.getHoverEvent().getContents()));
- } else if (HOVER_GET_VALUE != null) {
- try {
- sbi.append(copy().stringify((BaseComponent[]) HOVER_GET_VALUE.invoke(component.getHoverEvent())));
- } catch (IllegalAccessException | InvocationTargetException e) {
- e.printStackTrace();
- }
- }
- definitions.add(sbi.toString());
- }
- sb.append(definitions.stream().collect(Collectors.joining(" ")));
- sb.append(')');
- } else {
- appendFormatSuffix(sb, component);
- }
- }
- return sb.toString();
- }
-
- private StringBuilder stringify(List contents) {
- StringBuilder sb = new StringBuilder();
- for (Content content : contents) {
- if (content instanceof Text) {
- Object value = ((Text) content).getValue();
- if (value instanceof BaseComponent[]) {
- sb.append(stringify((BaseComponent[]) value));
- } else {
- sb.append(value);
- }
- } else if (content instanceof Entity) {
- Entity contentEntity = (Entity) content;
- sb.append(contentEntity.getId());
- if (contentEntity.getType() != null) {
- sb.append(":").append(contentEntity.getType());
- }
- if (contentEntity.getName() != null) {
- sb.append(" ").append(stringify(contentEntity.getName()));
- }
- } else if (content instanceof Item) {
- Item contentItem = (Item) content;
- sb.append(contentItem.getId());
- if (contentItem.getCount() > 0) {
- sb.append("*").append(contentItem.getCount());
- }
- if (contentItem.getTag() != null) {
- sb.append(" ").append(contentItem.getTag().getNbt());
- }
- }
- }
- return sb;
- }
-
- private void appendText(StringBuilder sb, BaseComponent component) {
- if (component instanceof TextComponent) {
- sb.append(((TextComponent) component).getText());
- } else {
- throw new UnsupportedOperationException("Cannot stringify " + component.getClass().getTypeName() + " yet! Only TextComponents are supported right now. Sorry. :(");
- }
- }
-
- private void appendColor(StringBuilder sb, ChatColor color) {
- if (this.color != color) {
- this.color = color;
- if (useLegacyColors()) {
- sb.append(colorChar()).append(color.toString().substring(1));
- } else {
- sb.append(colorChar()).append(color.getName()).append(colorChar());
- }
- }
- }
-
- private void appendFormat(StringBuilder sb, BaseComponent component) {
- Set formats = Util.getFormats(component, true);
- if (!formats.containsAll(this.formats)) {
- if (useLegacyFormatting()) {
- sb.append(colorChar()).append(ChatColor.RESET.toString().charAt(1));
- } else {
- Deque formatDeque = new ArrayDeque<>(this.formats);
- while (!formatDeque.isEmpty()) {
- ChatColor format = formatDeque.pollLast();
- if (!formats.contains(format)) {
- sb.append(MineDown.getFormatString(format));
- }
- }
- }
- } else {
- formats.removeAll(this.formats);
- }
- for (ChatColor format : formats) {
- if (useLegacyFormatting()) {
- sb.append(colorChar()).append(format.toString().charAt(1));
- } else {
- sb.append(MineDown.getFormatString(format));
- }
- }
- this.formats.clear();
- this.formats.addAll(formats);
- }
-
- private void appendFormatSuffix(StringBuilder sb, BaseComponent component) {
- if (!useLegacyFormatting()) {
- Set formats = Util.getFormats(component, true);
- for (ChatColor format : formats) {
- sb.append(MineDown.getFormatString(format));
- }
- this.formats.removeAll(formats);
- }
- }
-
- /**
- * Copy all the parser's setting to a new instance
- * @return The new parser instance with all settings copied
- */
- public MineDownStringifier copy() {
- return new MineDownStringifier().copy(this);
- }
-
- /**
- * Copy all the parser's settings from another parser
- * @param from The stringifier to copy from
- * @return This stringifier's instance
- */
- public MineDownStringifier copy(MineDownStringifier from) {
- MineDownStringifier copy = new MineDownStringifier();
- useLegacyColors(from.useLegacyColors());
- useLegacyFormatting(from.useLegacyFormatting());
- preferSimpleEvents(from.preferSimpleEvents());
- formattingInEventDefinition(from.formattingInEventDefinition());
- colorInEventDefinition(from.colorInEventDefinition());
- colorChar(from.colorChar());
- return copy;
- }
-
- /**
- * Get whether or not to use legacy color codes
- * @return whether or not to use legacy color codes when possible (Default: true)
- */
- public boolean useLegacyColors() {
- return this.useLegacyColors;
- }
-
- /**
- * Set whether or not to use legacy color codes
- * @param useLegacyColors Whether or not to use legacy colors (Default: true)
- * @return The MineDownStringifier instance
- */
- public MineDownStringifier useLegacyColors(boolean useLegacyColors) {
- this.useLegacyColors = useLegacyColors;
- return this;
- }
-
- /**
- * Get whether or not to translate legacy formatting codes over MineDown ones
- * @return whether or not to use legacy formatting codes (Default: false)
- */
- public boolean useLegacyFormatting() {
- return this.useLegacyFormatting;
- }
-
- /**
- * Set whether or not to translate legacy formatting codes over MineDown ones
- * @param useLegacyFormatting Whether or not to translate legacy formatting codes (Default: false)
- * @return The MineDownStringifier instance
- */
- public MineDownStringifier useLegacyFormatting(boolean useLegacyFormatting) {
- this.useLegacyFormatting = useLegacyFormatting;
- return this;
- }
-
- /**
- * Get whether or not to use simple event definitions or specific ones (Default: true)
- * @return whether or not to use simple events
- */
- public boolean preferSimpleEvents() {
- return this.preferSimpleEvents;
- }
-
- /**
- * Set whether or not to use simple event definitions or specific ones
- * @param preferSimpleEvents Whether or not to prefer simple events (Default: true)
- * @return The MineDownStringifier instance
- */
- public MineDownStringifier preferSimpleEvents(boolean preferSimpleEvents) {
- this.preferSimpleEvents = preferSimpleEvents;
- return this;
- }
-
- /**
- * Get whether or not to put colors in event definitions or use inline color definitions
- * @return whether or not to put colors in event definitions (Default: false)
- */
- public boolean colorInEventDefinition() {
- return this.colorInEventDefinition;
- }
-
- /**
- * Set whether or not to put colors in event definitions or use inline color definitions
- * @param colorInEventDefinition Whether or not to put colors in event definitions (Default: false)
- * @return The MineDownStringifier instance
- */
- public MineDownStringifier colorInEventDefinition(boolean colorInEventDefinition) {
- this.colorInEventDefinition = colorInEventDefinition;
- return this;
- }
-
- /**
- * Get whether or not to put formatting in event definitions or use inline formatting definitions
- * @return whether or not to put formatting in event definitions (Default: false)
- */
- public boolean formattingInEventDefinition() {
- return this.formattingInEventDefinition;
- }
-
- /**
- * Set whether or not to put formatting in event definitions or use inline formatting definitions
- * @param formattingInEventDefinition Whether or not to put formatting in event definitions (Default: false)
- * @return The MineDownStringifier instance
- */
- public MineDownStringifier formattingInEventDefinition(boolean formattingInEventDefinition) {
- this.formattingInEventDefinition = formattingInEventDefinition;
- return this;
- }
-
- /**
- * Get the character to use as a special color code. (Default: ampersand &)
- * @return the color character
- */
- public char colorChar() {
- return this.colorChar;
- }
-
- /**
- * Set the character to use as a special color code.
- * @param colorChar The character to be used as the color char (for legacy and MineDown colors, default: ampersand &)
- * @return The MineDownStringifier instance
- */
- public MineDownStringifier colorChar(char colorChar) {
- this.colorChar = colorChar;
- return this;
- }
-
-}
diff --git a/src/main/java/net/momirealms/customcrops/Libs/minedown/Replacer.java b/src/main/java/net/momirealms/customcrops/Libs/minedown/Replacer.java
deleted file mode 100644
index 4412c67..0000000
--- a/src/main/java/net/momirealms/customcrops/Libs/minedown/Replacer.java
+++ /dev/null
@@ -1,471 +0,0 @@
-package net.momirealms.customcrops.Libs.minedown;
-
-/*
- * Copyright (c) 2017 Max Lee (https://github.com/Phoenix616)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import net.md_5.bungee.api.ChatColor;
-import net.md_5.bungee.api.chat.BaseComponent;
-import net.md_5.bungee.api.chat.ClickEvent;
-import net.md_5.bungee.api.chat.HoverEvent;
-import net.md_5.bungee.api.chat.ItemTag;
-import net.md_5.bungee.api.chat.KeybindComponent;
-import net.md_5.bungee.api.chat.TextComponent;
-import net.md_5.bungee.api.chat.TranslatableComponent;
-import net.md_5.bungee.api.chat.hover.content.Content;
-import net.md_5.bungee.api.chat.hover.content.Entity;
-import net.md_5.bungee.api.chat.hover.content.Item;
-import net.md_5.bungee.api.chat.hover.content.Text;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Function;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * This class offers the ability to replace placeholders with values in strings and components.
- * It also lets you define which placeholders indicators (prefix and suffix) should be used.
- * By default these are the % character.
- */
-public class Replacer {
-
- private static final boolean HAS_KEYBIND_SUPPORT = Util.hasClass("net.md_5.bungee.api.chat.KeybindComponent");
- private static final boolean HAS_INSERTION_SUPPORT = Util.hasMethod(BaseComponent.class, "getInsertion");
- private static final boolean HAS_HOVER_CONTENT_SUPPORT = Util.hasMethod(HoverEvent.class, "getContents");
- private static final Method HOVER_GET_VALUE = Util.getMethod(HoverEvent.class, "getValue");
-
- /**
- * A cache of compiled replacement patterns
- */
- private static final Map PATTERN_CACHE = new ConcurrentHashMap<>();
-
- /**
- * The creator of the patterns for the pattern cache
- */
- private static final Function PATTERN_CREATOR = p -> Pattern.compile(p, Pattern.LITERAL);
-
- /**
- * The map of placeholders with their string replacements
- */
- private final Map replacements = new LinkedHashMap<>();
-
- /**
- * The map of placeholders with their component array replacements
- */
- private final Map componentReplacements = new LinkedHashMap<>();
-
- /**
- * The placeholder indicator's prefix character
- */
- private String placeholderPrefix = "%";
-
- /**
- * The placeholder indicator's suffix character
- */
- private String placeholderSuffix = "%";
-
- /**
- * Replace the placeholder no matter what the case of it is
- */
- private boolean ignorePlaceholderCase = true;
-
- /**
- * Replace certain placeholders with values in string.
- * This uses the % character as placeholder indicators (suffix and prefix)
- * @param message The string to replace in
- * @param replacements The replacements, nth element is the placeholder, n+1th the value
- * @return The string with all the placeholders replaced
- */
- public static String replaceIn(String message, String... replacements) {
- return new Replacer().replace(replacements).replaceIn(message);
- }
-
- /**
- * Replace certain placeholders with values in a component array.
- * This uses the % character as placeholder indicators (suffix and prefix)
- * @param message The BaseComponent array to replace in
- * @param replacements The replacements, nth element is the placeholder, n+1th the value
- * @return A copy of the BaseComponent array with all the placeholders replaced
- */
- public static BaseComponent[] replaceIn(BaseComponent[] message, String... replacements) {
- return new Replacer().replace(replacements).replaceIn(message);
- }
-
- /**
- * Replace a certain placeholder with a component array in a component array.
- * This uses the % character as placeholder indicators (suffix and prefix)
- * @param message The BaseComponent array to replace in
- * @param placeholder The placeholder to replace
- * @param replacement The replacement components
- * @return A copy of the BaseComponent array with all the placeholders replaced
- */
- public static BaseComponent[] replaceIn(BaseComponent[] message, String placeholder, BaseComponent... replacement) {
- return new Replacer().replace(placeholder, replacement).replaceIn(message);
- }
-
- /**
- * Add an array with placeholders and values that should get replaced in the message
- * @param replacements The replacements, nth element is the placeholder, n+1th the value
- * @return The Replacer instance
- */
- public Replacer replace(String... replacements) {
- Util.validate(replacements.length % 2 == 0, "The replacement length has to be even, " +
- "mapping i % 2 == 0 to the placeholder and i % 2 = 1 to the placeholder's value");
- Map replacementMap = new LinkedHashMap<>();
- for (int i = 0; i + 1 < replacements.length; i += 2) {
- replacementMap.put(replacements[i], replacements[i + 1]);
- }
- return replace(replacementMap);
- }
-
- /**
- * Add a map with placeholders and values that should get replaced in the message
- * @param replacements The replacements mapped placeholder to value
- * @return The Replacer instance
- */
- public Replacer replace(Map replacements) {
- if (replacements != null && !replacements.isEmpty()) {
- Object any = replacements.values().stream().filter(Objects::nonNull).findAny().orElse(null);
- if (any instanceof String) {
- replacements().putAll((Map) replacements);
- } else if (any != null && any.getClass().isArray() && BaseComponent.class.isAssignableFrom(any.getClass().getComponentType())) {
- componentReplacements().putAll((Map) replacements);
- } else {
- for (Map.Entry entry : replacements.entrySet()) {
- replacements().put(entry.getKey(), String.valueOf(entry.getValue()));
- }
- }
- }
- return this;
- }
-
- /**
- * Add a placeholder to component mapping that should get replaced in the message
- * @param placeholder The placeholder to replace
- * @param replacement The replacement components
- * @return The Replacer instance
- */
- public Replacer replace(String placeholder, BaseComponent... replacement) {
- componentReplacements().put(placeholder, replacement);
- return this;
- }
-
- /**
- * Set the placeholder indicator for both prefix and suffix
- * @param placeholderIndicator The character to use as a placeholder indicator
- * @return The Replacer instance
- */
- public Replacer placeholderIndicator(String placeholderIndicator) {
- placeholderPrefix(placeholderIndicator);
- placeholderSuffix(placeholderIndicator);
- return this;
- }
-
- /**
- * Replace the placeholders in a component array
- * @param components The BaseComponent array to replace in
- * @return A copy of the array with the placeholders replaced
- */
- public BaseComponent[] replaceIn(BaseComponent... components) {
- return replaceIn(Arrays.asList(components));
- }
-
- /**
- * Replace the placeholders in a component list
- * @param components The BaseComponent list to replace in
- * @return A copy of the array with the placeholders replaced
- */
- public BaseComponent[] replaceIn(List components) {
- List returnList = new ArrayList<>();
- // String replacements:
- for (int i = 0; i < components.size(); i++) {
- BaseComponent component = components.get(i).duplicate();
- if (HAS_KEYBIND_SUPPORT && component instanceof KeybindComponent) {
- ((KeybindComponent) component).setKeybind(replaceIn(((KeybindComponent) component).getKeybind()));
- }
- if (component instanceof TextComponent) {
- String replaced = replaceIn(((TextComponent) component).getText());
- int sectionIndex = replaced.indexOf(ChatColor.COLOR_CHAR);
- if (sectionIndex > -1 && replaced.length() > sectionIndex + 1
- && ChatColor.getByChar(replaced.charAt(sectionIndex + 1)) != null) {
- // replacement contain legacy code, parse to components and append them as extra
- BaseComponent[] replacedComponent = TextComponent.fromLegacyText(replaced);
- ((TextComponent) component).setText("");
- List extra = new ArrayList<>();
- Collections.addAll(extra, replacedComponent);
- if (component.getExtra() != null) {
- Collections.addAll(extra, replaceIn(component.getExtra()));
- }
- component.setExtra(extra);
- } else {
- ((TextComponent) component).setText(replaced);
- if (component.getExtra() != null) {
- component.setExtra(Arrays.asList(replaceIn(component.getExtra())));
- }
- }
- } else if (component.getExtra() != null) {
- component.setExtra(Arrays.asList(replaceIn(component.getExtra())));
- }
- if (component instanceof TranslatableComponent) {
- ((TranslatableComponent) component).setTranslate(replaceIn(((TranslatableComponent) component).getTranslate()));
- ((TranslatableComponent) component).setWith(Arrays.asList(replaceIn(((TranslatableComponent) component).getWith())));
- }
- if (HAS_INSERTION_SUPPORT && component.getInsertion() != null) {
- component.setInsertion(replaceIn(component.getInsertion()));
- }
- if (component.getClickEvent() != null) {
- component.setClickEvent(new ClickEvent(
- component.getClickEvent().getAction(),
- replaceIn(component.getClickEvent().getValue())
- ));
- }
- if (component.getHoverEvent() != null) {
- if (HAS_HOVER_CONTENT_SUPPORT) {
- component.setHoverEvent(new HoverEvent(
- component.getHoverEvent().getAction(),
- replaceInContents(component.getHoverEvent().getContents())
- ));
- } else if (HOVER_GET_VALUE != null) {
- try {
- component.setHoverEvent(new HoverEvent(
- component.getHoverEvent().getAction(),
- replaceIn((BaseComponent[]) HOVER_GET_VALUE.invoke(component.getHoverEvent()))
- ));
- } catch (IllegalAccessException | InvocationTargetException e) {
- e.printStackTrace();
- }
- }
- }
-
- // Component replacements
- List replacedComponents = new ArrayList<>();
- replacedComponents.add(component);
-
- for (Map.Entry replacement : componentReplacements().entrySet()) {
- List newReplacedComponents = new ArrayList<>();
-
- for (BaseComponent replaceComponent : replacedComponents) {
- if (replaceComponent instanceof TextComponent) {
- TextComponent textComponent = (TextComponent) replaceComponent;
- String placeHolder = placeholderPrefix()
- + (ignorePlaceholderCase() ? replacement.getKey().toLowerCase(Locale.ROOT) : replacement.getKey())
- + placeholderSuffix();
- String text = ignorePlaceholderCase() ? textComponent.getText().toLowerCase(Locale.ROOT) : textComponent.getText();
- int index = text.indexOf(placeHolder);
- if (index > -1) {
- do {
- TextComponent startComponent = new TextComponent(textComponent);
- if (index > 0) {
- startComponent.setText(textComponent.getText().substring(0, index));
- } else {
- startComponent.setText("");
- }
- startComponent.setExtra(Arrays.asList(replacement.getValue()));
- newReplacedComponents.add(startComponent);
-
- if (index + placeHolder.length() < textComponent.getText().length()) {
- textComponent.setText(textComponent.getText().substring(index + placeHolder.length()));
- } else {
- textComponent.setText("");
- }
- text = ignorePlaceholderCase() ? textComponent.getText().toLowerCase(Locale.ROOT) : textComponent.getText();
- newReplacedComponents.add(textComponent);
- } while (!text.isEmpty() && (index = text.indexOf(placeHolder)) > -1);
- continue;
- }
- }
-
- // Nothing was replaced, just add it
- newReplacedComponents.add(replaceComponent);
- }
- replacedComponents = newReplacedComponents;
- }
- returnList.addAll(replacedComponents);
- }
- return returnList.toArray(new BaseComponent[0]);
- }
-
- private List replaceInContents(List contents) {
- List replacedContents = new ArrayList<>();
- for (Content content : contents) {
- if (content instanceof Text) {
- Object value = ((Text) content).getValue();
- if (value instanceof BaseComponent[]) {
- replacedContents.add(new Text(replaceIn((BaseComponent[]) value)));
- } else if (value instanceof String) {
- replacedContents.add(new Text(replaceIn((String) value)));
- } else {
- throw new UnsupportedOperationException("Cannot replace in " + value.getClass() + "!");
- }
- } else if (content instanceof Entity) {
- Entity entity = (Entity) content;
- String id = replaceIn(entity.getId());
- String type;
- if (entity.getType() != null) {
- type = replaceIn(entity.getType());
- } else {
- type = "minecraft:pig"; // Meh
- }
- BaseComponent name = null;
- if (entity.getName() != null) {
- name = new TextComponent(replaceIn(TextComponent.toLegacyText(entity.getName())));
- }
- replacedContents.add(new Entity(type, id, name));
- } else if (content instanceof Item) {
- Item item = (Item) content;
- String id = replaceIn(item.getId());
- ItemTag itemTag = item.getTag() != null ? ItemTag.ofNbt(replaceIn(item.getTag().getNbt())) : null;
- replacedContents.add(new Item(id, item.getCount(), itemTag));
- } else {
- replacedContents.add(content); // TODO: Find a good way to clone this
- }
- }
- return replacedContents;
- }
-
- /**
- * Replace the placeholders in a string. Does not replace component replacements!
- * @param string The String list to replace in
- * @return The string with the placeholders replaced
- */
- public String replaceIn(String string) {
- for (Map.Entry replacement : replacements().entrySet()) {
- String replValue = replacement.getValue() != null ? replacement.getValue() : "null";
- if (ignorePlaceholderCase()) {
- String placeholder = placeholderPrefix() + replacement.getKey().toLowerCase(Locale.ROOT) + placeholderSuffix();
- int nextStart = 0;
- int startIndex;
- while (nextStart < string.length() && (startIndex = string.toLowerCase(Locale.ROOT).indexOf(placeholder, nextStart)) > -1) {
- nextStart = startIndex + replValue.length();
- string = string.substring(0, startIndex) + replValue + string.substring(startIndex + placeholder.length());
- }
- } else {
- String placeholder = placeholderPrefix() + replacement.getKey() + placeholderSuffix();
- Pattern pattern = PATTERN_CACHE.computeIfAbsent(placeholder, PATTERN_CREATOR);
- string = pattern.matcher(string).replaceAll(Matcher.quoteReplacement(replValue));
- }
- }
- return string;
- }
-
- /**
- * Create a copy of this Replacer
- * @return A copy of this Replacer
- */
- public Replacer copy() {
- return new Replacer().copy(this);
- }
-
- /**
- * Copy all the values of another Replacer
- * @param from The replacer to copy
- * @return The Replacer instance
- */
- public Replacer copy(Replacer from) {
- replacements().clear();
- replacements().putAll(from.replacements());
- componentReplacements().clear();
- componentReplacements().putAll(from.componentReplacements());
- placeholderPrefix(from.placeholderPrefix());
- placeholderSuffix(from.placeholderSuffix());
- return this;
- }
-
- /**
- * Get the map of placeholders with their string replacements
- * @return the replacement map
- */
- public Map replacements() {
- return this.replacements;
- }
-
- /**
- * Get the map of placeholders with their component array replacements
- * @return the replacement map
- */
- public Map componentReplacements() {
- return this.componentReplacements;
- }
-
- /**
- * Get the placeholder indicator's prefix string
- * @return the prefix characters
- */
- public String placeholderPrefix() {
- return this.placeholderPrefix;
- }
-
- /**
- * Set the placeholder indicator's prefix string
- * @param placeholderPrefix The placeholder prefix string
- * @return the instance of this Replacer
- */
- public Replacer placeholderPrefix(String placeholderPrefix) {
- this.placeholderPrefix = placeholderPrefix;
- return this;
- }
-
- /**
- * Get the placeholder indicator's suffix string
- * @return the suffix characters
- */
- public String placeholderSuffix() {
- return this.placeholderSuffix;
- }
-
- /**
- * Set the placeholder indicator's suffix string
- * @param placeholderSuffix The placeholder suffix string
- * @return the instance of this Replacer
- */
- public Replacer placeholderSuffix(String placeholderSuffix) {
- this.placeholderSuffix = placeholderSuffix;
- return this;
- }
-
- /**
- * Replace the placeholder no matter what the case of it is
- * @return whether or not to ignore the placeholder case (Default: true)
- */
- public boolean ignorePlaceholderCase() {
- return this.ignorePlaceholderCase;
- }
-
- /**
- * Set whether or not the placeholder should be replaced no matter what the case of it is
- * @param ignorePlaceholderCase Whether or not to ignore the case in placeholders (Default: true)
- * @return the instance of this Replacer
- */
- public Replacer ignorePlaceholderCase(boolean ignorePlaceholderCase) {
- this.ignorePlaceholderCase = ignorePlaceholderCase;
- return this;
- }
-}
diff --git a/src/main/java/net/momirealms/customcrops/Libs/minedown/Util.java b/src/main/java/net/momirealms/customcrops/Libs/minedown/Util.java
deleted file mode 100644
index a7472b5..0000000
--- a/src/main/java/net/momirealms/customcrops/Libs/minedown/Util.java
+++ /dev/null
@@ -1,590 +0,0 @@
-package net.momirealms.customcrops.Libs.minedown;
-
-/*
- * Copyright (c) 2017 Max Lee (https://github.com/Phoenix616)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import net.md_5.bungee.api.ChatColor;
-import net.md_5.bungee.api.chat.BaseComponent;
-import net.md_5.bungee.api.chat.ComponentBuilder;
-
-import java.awt.Color;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-public class Util {
-
- private static final Pattern WRAP_PATTERN = Pattern.compile(" ", Pattern.LITERAL);
-
- /**
- * Utility method to throw an IllegalArgumentException if the value is false
- * @param value The value to validate
- * @param message The message for the exception
- * @throws IllegalArgumentException Thrown if the value is false
- */
- public static void validate(boolean value, String message) throws IllegalArgumentException {
- if (!value) {
- throw new IllegalArgumentException(message);
- }
- }
-
- /**
- * Apply a collection of colors/formats to a component
- * @param component The BaseComponent
- * @param formats The collection of ChatColor formats to apply
- * @return The component that was modified
- */
- public static BaseComponent applyFormat(BaseComponent component, Collection formats) {
- for (ChatColor format : formats) {
- if (format == ChatColor.BOLD) {
- component.setBold(true);
- } else if (format == ChatColor.ITALIC) {
- component.setItalic(true);
- } else if (format == ChatColor.UNDERLINE) {
- component.setUnderlined(true);
- } else if (format == ChatColor.STRIKETHROUGH) {
- component.setStrikethrough(true);
- } else if (format == ChatColor.MAGIC) {
- component.setObfuscated(true);
- } else if (format == ChatColor.RESET) {
- component.setBold(false);
- component.setItalic(false);
- component.setUnderlined(false);
- component.setStrikethrough(false);
- component.setObfuscated(false);
- component.setColor(ChatColor.WHITE);
- } else {
- component.setColor(format);
- }
- }
- if (component.getExtra() != null) {
- for (BaseComponent extra : component.getExtra()) {
- applyFormat(extra, formats);
- }
- }
- return component;
- }
-
- /**
- * Apply a collection of colors/formats to a component builder
- * @param builder The ComponentBuilder
- * @param formats The collection of ChatColor formats to apply
- * @return The component builder that was modified
- * @deprecated Use {@link #applyFormat(BaseComponent, Collection)}
- */
- @Deprecated
- public static ComponentBuilder applyFormat(ComponentBuilder builder, Set formats) {
- Map formatMap = new HashMap<>();
- for (ChatColor format : formats) {
- formatMap.put(format, true);
- }
- return applyFormat(builder, formatMap);
- }
-
- /**
- * Apply a collection of colors/formats to a component builder
- * @param builder The ComponentBuilder
- * @param formats The collection of ChatColor formats to apply
- * @return The component builder that was modified
- */
- public static ComponentBuilder applyFormat(ComponentBuilder builder, Map formats) {
- for (Map.Entry e : formats.entrySet()) {
- if (e.getKey() == ChatColor.BOLD) {
- builder.bold(e.getValue());
- } else if (e.getKey() == ChatColor.ITALIC) {
- builder.italic(e.getValue());
- } else if (e.getKey() == ChatColor.UNDERLINE) {
- builder.underlined(e.getValue());
- } else if (e.getKey() == ChatColor.STRIKETHROUGH) {
- builder.strikethrough(e.getValue());
- } else if (e.getKey() == ChatColor.MAGIC) {
- builder.obfuscated(e.getValue());
- } else if (e.getKey() == ChatColor.RESET) {
- builder.bold(!e.getValue());
- builder.italic(!e.getValue());
- builder.underlined(!e.getValue());
- builder.strikethrough(!e.getValue());
- builder.obfuscated(!e.getValue());
- builder.color(ChatColor.WHITE);
- } else if (e.getValue()) {
- builder.color(e.getKey());
- } else if (builder.getCurrentComponent().getColor() == e.getKey()) {
- builder.color(null);
- }
- }
- return builder;
- }
-
- /**
- * Check whether or not a character at a certain index of a string repeats itself
- * @param string The string to check
- * @param index The index at which to check the character
- * @return Whether or not the character at that index repeated itself
- */
- public static boolean isDouble(String string, int index) {
- return index + 1 < string.length() && string.charAt(index) == string.charAt(index + 1);
- }
-
- /**
- * Check whether a certain ChatColor is formatting or not
- * @param format The ChatColor to check
- * @return true if it's a format, false if it's a color
- */
- public static boolean isFormat(ChatColor format) {
- return !MineDown.getFormatString(format).isEmpty();
- }
-
- /**
- * Get a set of ChatColor formats all formats that a component includes
- * @param component The component to get the formats from
- * @param ignoreParent Whether or not to include the parent's format
- * @return A set of all the format ChatColors that the component includes
- */
- public static Set getFormats(BaseComponent component, boolean ignoreParent) {
- Set formats = new LinkedHashSet<>();
- if ((!ignoreParent && component.isBold()) || (component.isBoldRaw() != null && component.isBoldRaw())) {
- formats.add(ChatColor.BOLD);
- }
- if ((!ignoreParent && component.isItalic()) || (component.isItalicRaw() != null && component.isItalicRaw())) {
- formats.add(ChatColor.ITALIC);
- }
- if ((!ignoreParent && component.isUnderlined()) || (component.isUnderlinedRaw() != null && component.isUnderlinedRaw())) {
- formats.add(ChatColor.UNDERLINE);
- }
- if ((!ignoreParent && component.isStrikethrough()) || (component.isStrikethroughRaw() != null && component.isStrikethroughRaw())) {
- formats.add(ChatColor.STRIKETHROUGH);
- }
- if ((!ignoreParent && component.isObfuscated()) || (component.isObfuscatedRaw() != null && component.isObfuscatedRaw())) {
- formats.add(ChatColor.MAGIC);
- }
- return formats;
- }
-
- /**
- * Get the index of the first occurrences of a not escaped character
- * @param string The string to search
- * @param chars The characters to search for
- * @return The first unescaped index or -1 if not found
- */
- public static int indexOfNotEscaped(String string, String chars) {
- return indexOfNotEscaped(string, chars, 0);
- }
-
- /**
- * Get the index of the first occurrences of a not escaped character
- * @param string The string to search
- * @param chars The characters to search for
- * @param fromIndex Start searching from that index
- * @return The first unescaped index or {@code -1} if not found
- */
- public static int indexOfNotEscaped(String string, String chars, int fromIndex) {
- for (int i = fromIndex; i < string.length(); i++) {
- int index = string.indexOf(chars, i);
- if (index == -1) {
- return -1;
- }
- if (!isEscaped(string, index)) {
- return index;
- }
- }
- return -1;
- }
-
- /**
- * Check if a character at a certain index is escaped
- * @param string The string to check
- * @param index The index of the character in the string to check
- * @return Whether or not the character is escaped (uneven number of backslashes in front of char mains it is escaped)
- * @throws IndexOutOfBoundsException if the {@code index} argument is not less than the length of this string.
- */
- public static boolean isEscaped(String string, int index) {
- if (index - 1 > string.length()) {
- return false;
- }
- int e = 0;
- while (index > e && string.charAt(index - e - 1) == '\\') {
- e++;
- }
- return e % 2 != 0;
- }
-
- /**
- * Wrap a string if it is longer than the line length and contains no new line.
- * Will try to wrap at spaces between words.
- * @param string The string to wrap
- * @param lineLength The max length of a line
- * @return The wrapped string
- */
- public static String wrap(String string, int lineLength) {
- if (string.length() <= lineLength || string.contains("\n")) {
- return string;
- }
-
- List lines = new ArrayList<>();
- StringBuilder currentLine = new StringBuilder();
- for (String s : WRAP_PATTERN.split(string)) {
- if (currentLine.length() + s.length() + 1 > lineLength) {
- int rest = lineLength - currentLine.length() - 1;
- if (rest > lineLength / 4 && s.length() > Math.min(rest * 2, lineLength / 4)) {
- currentLine.append(" ").append(s, 0, rest);
- } else {
- rest = 0;
- }
- lines.add(currentLine.toString());
- String restString = s.substring(rest);
- while (restString.length() >= lineLength) {
- lines.add(restString.substring(0, lineLength));
- restString = restString.substring(lineLength);
- }
- currentLine = new StringBuilder(restString);
- } else {
- if (currentLine.length() > 0) {
- currentLine.append(" ");
- }
- currentLine.append(s);
- }
- }
- if (currentLine.length() > 0) {
- lines.add(currentLine.toString());
- }
- return String.join("\n", lines);
- }
-
- private static Map legacyColors = new LinkedHashMap<>();
-
- static {
- legacyColors.put(ChatColor.BLACK, new Color(0x000000));
- legacyColors.put(ChatColor.DARK_BLUE, new Color(0x0000AA));
- legacyColors.put(ChatColor.DARK_GREEN, new Color(0x00AA00));
- legacyColors.put(ChatColor.DARK_AQUA, new Color(0x00AAAA));
- legacyColors.put(ChatColor.DARK_RED, new Color(0xAA0000));
- legacyColors.put(ChatColor.DARK_PURPLE, new Color(0xAA00AA));
- legacyColors.put(ChatColor.GOLD, new Color(0xFFAA00));
- legacyColors.put(ChatColor.GRAY, new Color(0xAAAAAA));
- legacyColors.put(ChatColor.DARK_GRAY, new Color(0x555555));
- legacyColors.put(ChatColor.BLUE, new Color(0x05555FF));
- legacyColors.put(ChatColor.GREEN, new Color(0x55FF55));
- legacyColors.put(ChatColor.AQUA, new Color(0x55FFFF));
- legacyColors.put(ChatColor.RED, new Color(0xFF5555));
- legacyColors.put(ChatColor.LIGHT_PURPLE, new Color(0xFF55FF));
- legacyColors.put(ChatColor.YELLOW, new Color(0xFFFF55));
- legacyColors.put(ChatColor.WHITE, new Color(0xFFFFFF));
- }
-
- /**
- * Utility method to remove RGB colors from components. This modifies the input array!
- * @param components The components to remove the rgb colors from
- * @return The modified components (same as input).
- */
- public static BaseComponent[] rgbColorsToLegacy(BaseComponent[] components) {
- for (BaseComponent component : components) {
- if (component.getColorRaw() != null && component.getColorRaw().getName().startsWith("#")) {
- component.setColor(getClosestLegacy(new Color(Integer.parseInt(component.getColorRaw().getName().substring(1), 16))));
- }
- if (component.getExtra() != null) {
- rgbColorsToLegacy(component.getExtra().toArray(new BaseComponent[0]));
- }
- }
- return components;
- }
-
- /**
- * Get the legacy color closest to a certain RGB color
- * @param color The color to get the closest legacy color for
- * @return The closest legacy color
- */
- public static ChatColor getClosestLegacy(Color color) {
- ChatColor closest = null;
- double smallestDistance = Double.MAX_VALUE;
- for (Map.Entry legacy : legacyColors.entrySet()) {
- double distance = distance(color, legacy.getValue());
- if (distance < smallestDistance) {
- smallestDistance = distance;
- closest = legacy.getKey();
- }
- }
- return closest;
- }
-
- /**
- * Get the distance between two colors
- * @param c1 Color A
- * @param c2 Color B
- * @return The distance or 0 if they are equal
- */
- public static double distance(Color c1, Color c2) {
- if (c1.getRGB() == c2.getRGB()) {
- return 0;
- }
- return Math.sqrt(Math.pow(c1.getRed() - c2.getRed(), 2) + Math.pow(c1.getGreen() - c2.getGreen(), 2) + Math.pow(c1.getBlue() - c2.getBlue(), 2));
- }
-
- /*
- * createRainbow is adapted from the net.kyori.adventure.text.minimessage.fancy.Rainbow class
- * in adventure-text-minimessage, licensed under the MIT License.
- *
- * Copyright (c) 2018-2020 KyoriPowered
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
- /**
- * Generate a rainbow with a certain length and phase
- * @param length The length of the rainbow
- * @param phase The phase of the rainbow.
- * @param rgb Whether or not to use RGB colors
- * @return the colors in the rainbow
- * @deprecated Use {@link #createRainbow(long, int, boolean)}
- */
- @Deprecated
- public static List createRainbow(int length, int phase, boolean rgb) {
- return createRainbow((long) length, phase, rgb);
- }
-
- /**
- * Generate a rainbow with a certain length and phase
- * @param length The length of the rainbow
- * @param phase The phase of the rainbow.
- * @param rgb Whether or not to use RGB colors
- * @return the colors in the rainbow
- */
- public static List createRainbow(long length, int phase, boolean rgb) {
- List colors = new ArrayList<>();
-
- float fPhase = phase / 10f;
-
- float center = 128;
- float width = 127;
- double frequency = Math.PI * 2 / length;
-
- for (int i = 0; i < length; i++) {
- Color color = new Color(
- (int) (Math.sin(frequency * i + 2 + fPhase) * width + center),
- (int) (Math.sin(frequency * i + 0 + fPhase) * width + center),
- (int) (Math.sin(frequency * i + 4 + fPhase) * width + center)
- );
- if (rgb) {
- colors.add(ChatColor.of(color));
- } else {
- ChatColor chatColor = getClosestLegacy(color);
- if (colors.isEmpty() || chatColor != colors.get(colors.size() - 1)) {
- colors.add(chatColor);
- }
- }
- }
- return colors;
- }
-
- /*
- * createGradient is adapted from the net.kyori.adventure.text.minimessage.fancy.Gradient class
- * in adventure-text-minimessage, licensed under the MIT License.
- *
- * Copyright (c) 2018-2020 KyoriPowered
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
- /**
- * Generate a gradient with certain colors
- * @param length The length of the gradient
- * @param gradient The colors of the gradient.
- * @param rgb Whether or not to use RGB colors
- * @return the colors in the gradient
- * @deprecated Use {@link #createRainbow(long, int, boolean)}
- */
- @Deprecated
- public static List createGradient(int length, List gradient, boolean rgb) {
- return createGradient((long) length, gradient, rgb);
- }
-
- /**
- * Generate a gradient with certain colors
- * @param length The length of the gradient
- * @param gradient The colors of the gradient.
- * @param rgb Whether or not to use RGB colors
- * @return the colors in the gradient
- */
- public static List createGradient(long length, List gradient, boolean rgb) {
- List colors = new ArrayList<>();
- if (gradient.size() < 2 || length < 2) {
- if (gradient.isEmpty()) {
- return gradient;
- }
- return Collections.singletonList(gradient.get(0));
- }
-
- float fPhase = 0;
-
- float sectorLength = (float) (length - 1) / (gradient.size() - 1);
- float factorStep = 1.0f / (sectorLength);
-
- long index = 0;
-
- int colorIndex = 0;
-
- for (long i = 0; i < length; i++) {
-
- if (factorStep * index > 1) {
- colorIndex++;
- index = 0;
- }
-
- float factor = factorStep * (index++ + fPhase);
- // loop around if needed
- if (factor > 1) {
- factor = 1 - (factor - 1);
- }
-
- Color color = interpolate(
- getColor(gradient.get(colorIndex), rgb),
- getColor(gradient.get(Math.min(gradient.size() - 1, colorIndex + 1)), rgb),
- factor
- );
-
- if (color != null) {
- if (rgb) {
- colors.add(ChatColor.of(color));
- } else {
- ChatColor chatColor = getClosestLegacy(color);
- if (colors.isEmpty() || chatColor != colors.get(colors.size() - 1)) {
- colors.add(chatColor);
- }
- }
- }
- }
-
- return colors;
- }
-
- private static Color getColor(ChatColor color, boolean rgb) {
- if (legacyColors.containsKey(color)) {
- return legacyColors.get(color);
- }
-
- if (color.getName().startsWith("#")) {
- Color c = new Color(Integer.parseInt(color.getName().substring(1), 16));
- if (rgb) {
- return c;
- } else {
- return legacyColors.get(getClosestLegacy(c));
- }
- } else if (rgb) {
- return color.getColor();
- }
-
- return null;
- }
-
- private static Color interpolate(Color color1, Color color2, float factor) {
- if (color1 == null || color2 == null) {
- return null;
- }
- return new Color(
- Math.round(color1.getRed() + factor * (color2.getRed() - color1.getRed())),
- Math.round(color1.getGreen() + factor * (color2.getGreen() - color1.getGreen())),
- Math.round(color1.getBlue() + factor * (color2.getBlue() - color1.getBlue()))
- );
- }
-
- /**
- * Check if a certain class exists. See {@link Class#forName(String)}
- * @param className The class name to check
- * @return true if the class exists, false if not
- */
- public static boolean hasClass(String className) {
- try {
- Class.forName(className);
- return true;
- } catch (ClassNotFoundException classDoesntExist) {
- return false;
- }
- }
-
- /**
- * Check if a class has a certain method. See {@link Class#getMethod(String, Class[])}
- * @param clazz The class to check
- * @param method The method to check for
- * @param parameter Method parameter types
- * @return true if the class has the method, false if not
- */
- public static boolean hasMethod(Class> clazz, String method, Class>... parameter) {
- try {
- clazz.getMethod(method, parameter);
- return true;
- } catch (NoSuchMethodException methodDoesntExist) {
- return false;
- }
- }
-
- /**
- * Get a method from a class if it exists. See {@link Class#getMethod(String, Class[])}
- * @param clazz The class
- * @param method The method name to get
- * @param parameter Method parameter types
- * @return the method, null if it doesn't exist
- */
- public static Method getMethod(Class> clazz, String method, Class>... parameter) {
- try {
- return clazz.getMethod(method, parameter);
- } catch (NoSuchMethodException methodDoesntExist) {
- return null;
- }
- }
-}