mirror of
				https://github.com/PlaceholderAPI/PlaceholderAPI
				synced 2025-10-31 06:12:28 +01:00 
			
		
		
		
	Merge branch 'master' into gradle
# Conflicts: # pom.xml
This commit is contained in:
		| @@ -27,40 +27,118 @@ import me.clip.placeholderapi.events.ExpansionUnregisterEvent; | |||||||
| import me.clip.placeholderapi.expansion.Cacheable; | import me.clip.placeholderapi.expansion.Cacheable; | ||||||
| import me.clip.placeholderapi.expansion.PlaceholderExpansion; | import me.clip.placeholderapi.expansion.PlaceholderExpansion; | ||||||
| import me.clip.placeholderapi.expansion.Relational; | import me.clip.placeholderapi.expansion.Relational; | ||||||
|  | import me.clip.placeholderapi.replacer.CharsReplacer; | ||||||
|  | import me.clip.placeholderapi.replacer.Replacer; | ||||||
|  | import me.clip.placeholderapi.replacer.Replacer.Closure; | ||||||
| import me.clip.placeholderapi.util.Msg; | import me.clip.placeholderapi.util.Msg; | ||||||
| import org.apache.commons.lang.Validate; |  | ||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.OfflinePlayer; | import org.bukkit.OfflinePlayer; | ||||||
| import org.bukkit.entity.Player; | import org.bukkit.entity.Player; | ||||||
| import org.bukkit.plugin.Plugin; | import org.bukkit.plugin.Plugin; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
| import java.util.*; | import java.util.HashMap; | ||||||
|  | import java.util.HashSet; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.Set; | ||||||
| import java.util.regex.Matcher; | import java.util.regex.Matcher; | ||||||
| import java.util.regex.Pattern; | import java.util.regex.Pattern; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
|  |  | ||||||
| import static me.clip.placeholderapi.util.Msg.color; | public final class PlaceholderAPI | ||||||
|  | { | ||||||
|  |  | ||||||
| public class PlaceholderAPI { | 	private static final Replacer REPLACER_PERCENT = new CharsReplacer(Closure.PERCENT); | ||||||
|  | 	private static final Replacer REPLACER_BRACKET = new CharsReplacer(Closure.BRACKET); | ||||||
|  |  | ||||||
|  | 	private static final Map<String, PlaceholderHook> PLACEHOLDERS = new HashMap<>(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	@Deprecated | ||||||
| 	private static final Pattern PLACEHOLDER_PATTERN            = Pattern.compile("[%]([^%]+)[%]"); | 	private static final Pattern PLACEHOLDER_PATTERN            = Pattern.compile("[%]([^%]+)[%]"); | ||||||
|  | 	@Deprecated | ||||||
| 	private static final Pattern BRACKET_PLACEHOLDER_PATTERN    = Pattern.compile("[{]([^{}]+)[}]"); | 	private static final Pattern BRACKET_PLACEHOLDER_PATTERN    = Pattern.compile("[{]([^{}]+)[}]"); | ||||||
|  | 	@Deprecated | ||||||
| 	private static final Pattern RELATIONAL_PLACEHOLDER_PATTERN = Pattern.compile("[%](rel_)([^%]+)[%]"); | 	private static final Pattern RELATIONAL_PLACEHOLDER_PATTERN = Pattern.compile("[%](rel_)([^%]+)[%]"); | ||||||
|     private static final Map<String, PlaceholderHook> placeholders = new HashMap<>(); |  | ||||||
|  |  | ||||||
|     private PlaceholderAPI() { |  | ||||||
|  | 	private PlaceholderAPI() | ||||||
|  | 	{ | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	// === Current API === | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Translates all placeholders into their corresponding values. | ||||||
|  | 	 * <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}. | ||||||
|  | 	 * | ||||||
|  | 	 * @param player Player to parse the placeholders against | ||||||
|  | 	 * @param text   Text to set the placeholder values in | ||||||
|  | 	 * @return String containing all translated placeholders | ||||||
|  | 	 */ | ||||||
|  | 	@NotNull | ||||||
|  | 	public static String setPlaceholders(@Nullable final OfflinePlayer player, @NotNull final String text) | ||||||
|  | 	{ | ||||||
|  | 		return REPLACER_PERCENT.apply(text, player, PLACEHOLDERS::get); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Translates all placeholders into their corresponding values. | ||||||
|  | 	 * <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}. | ||||||
|  | 	 * | ||||||
|  | 	 * @param player Player to parse the placeholders against | ||||||
|  | 	 * @param text   List of Strings to set the placeholder values in | ||||||
|  | 	 * @return String containing all translated placeholders | ||||||
|  | 	 */ | ||||||
|  | 	@NotNull | ||||||
|  | 	public static List<String> setPlaceholders(@Nullable final OfflinePlayer player, @NotNull final List<@NotNull String> text) | ||||||
|  | 	{ | ||||||
|  | 		return text.stream().map(line -> setPlaceholders(player, line)).collect(Collectors.toList()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Translates all placeholders into their corresponding values. | ||||||
|  | 	 * <br>The pattern of a valid placeholder is {@literal {<identifier>_<params>}}. | ||||||
|  | 	 * | ||||||
|  | 	 * @param player Player to parse the placeholders against | ||||||
|  | 	 * @param text   Text to set the placeholder values in | ||||||
|  | 	 * | ||||||
|  | 	 * @return String containing all translated placeholders | ||||||
|  | 	 */ | ||||||
|  | 	@NotNull | ||||||
|  | 	public static String setBracketPlaceholders(@Nullable final OfflinePlayer player, @NotNull final String text) | ||||||
|  | 	{ | ||||||
|  | 		return REPLACER_BRACKET.apply(text, player, PLACEHOLDERS::get); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Translates all placeholders into their corresponding values. | ||||||
|  | 	 * <br>The pattern of a valid placeholder is {@literal {<identifier>_<params>}}. | ||||||
|  | 	 * | ||||||
|  | 	 * @param player Player to parse the placeholders against | ||||||
|  | 	 * @param text   List of Strings to set the placeholder values in | ||||||
|  | 	 * | ||||||
|  | 	 * @return String containing all translated placeholders | ||||||
|  | 	 */ | ||||||
|  | 	@NotNull | ||||||
|  | 	public static List<String> setBracketPlaceholders(@Nullable final OfflinePlayer player, @NotNull final List<@NotNull String> text) | ||||||
|  | 	{ | ||||||
|  | 		return text.stream().map(line -> setBracketPlaceholders(player, line)).collect(Collectors.toList()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Check if a specific placeholder identifier is currently registered | 	 * Check if a specific placeholder identifier is currently registered | ||||||
| 	 * | 	 * | ||||||
| 	 * @param identifier The identifier to check | 	 * @param identifier The identifier to check | ||||||
| 	 * @return true if identifier is already registered | 	 * @return true if identifier is already registered | ||||||
| 	 */ | 	 */ | ||||||
|     public static boolean isRegistered(String identifier) { | 	public static boolean isRegistered(@NotNull final String identifier) | ||||||
|         return getRegisteredIdentifiers().stream() | 	{ | ||||||
|                 .filter(id -> id.equalsIgnoreCase(identifier)) | 		return PLACEHOLDERS.containsKey(identifier.toLowerCase()); | ||||||
|                 .findFirst().orElse(null) != null; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -72,17 +150,14 @@ public class PlaceholderAPI { | |||||||
| 	 * @return true if the hook was successfully registered, false if there is already a hook | 	 * @return true if the hook was successfully registered, false if there is already a hook | ||||||
| 	 * registered for the specified identifier | 	 * registered for the specified identifier | ||||||
| 	 */ | 	 */ | ||||||
|     public static boolean registerPlaceholderHook(String identifier, PlaceholderHook placeholderHook) { | 	public static boolean registerPlaceholderHook(@NotNull final String identifier, @NotNull final PlaceholderHook placeholderHook) | ||||||
|         Validate.notNull(identifier, "Identifier can not be null"); | 	{ | ||||||
|         Validate.notNull(placeholderHook, "Placeholderhook can not be null"); | 		return PLACEHOLDERS.putIfAbsent(identifier.toLowerCase(), placeholderHook) == null; | ||||||
|  |  | ||||||
|         if (isRegistered(identifier)) { |  | ||||||
|             return false; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|         placeholders.put(identifier.toLowerCase(), placeholderHook); | 	public static boolean registerPlaceholderHook(@NotNull final Plugin plugin, @NotNull final PlaceholderHook placeholderHook) | ||||||
|  | 	{ | ||||||
|         return true; | 		return registerPlaceholderHook(plugin.getName(), placeholderHook); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -92,18 +167,26 @@ public class PlaceholderAPI { | |||||||
| 	 * @return true if the placeholder hook was successfully unregistered, false if there was no | 	 * @return true if the placeholder hook was successfully unregistered, false if there was no | ||||||
| 	 * placeholder hook registered for the identifier specified | 	 * placeholder hook registered for the identifier specified | ||||||
| 	 */ | 	 */ | ||||||
|     public static boolean unregisterPlaceholderHook(String identifier) { | 	public static boolean unregisterPlaceholderHook(@NotNull final String identifier) | ||||||
|         Validate.notNull(identifier, "Identifier can not be null"); | 	{ | ||||||
|         return placeholders.remove(identifier.toLowerCase()) != null; | 		return PLACEHOLDERS.remove(identifier.toLowerCase()) != null; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	public static boolean unregisterPlaceholderHook(@NotNull final Plugin plugin) | ||||||
|  | 	{ | ||||||
|  | 		return unregisterPlaceholderHook(plugin.getName()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Get all registered placeholder identifiers | 	 * Get all registered placeholder identifiers | ||||||
| 	 * | 	 * | ||||||
| 	 * @return All registered placeholder identifiers | 	 * @return All registered placeholder identifiers | ||||||
| 	 */ | 	 */ | ||||||
|     public static Set<String> getRegisteredIdentifiers() { | 	@NotNull | ||||||
|         return ImmutableSet.copyOf(placeholders.keySet()); | 	public static Set<String> getRegisteredIdentifiers() | ||||||
|  | 	{ | ||||||
|  | 		return ImmutableSet.copyOf(PLACEHOLDERS.keySet()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -111,11 +194,116 @@ public class PlaceholderAPI { | |||||||
| 	 * | 	 * | ||||||
| 	 * @return Copy of the internal placeholder map | 	 * @return Copy of the internal placeholder map | ||||||
| 	 */ | 	 */ | ||||||
|     public static Map<String, PlaceholderHook> getPlaceholders() { | 	@NotNull | ||||||
|         return ImmutableMap.copyOf(placeholders); | 	public static Map<String, PlaceholderHook> getPlaceholders() | ||||||
|  | 	{ | ||||||
|  | 		return ImmutableMap.copyOf(PLACEHOLDERS); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     public static Set<PlaceholderExpansion> getExpansions() { |  | ||||||
|  | 	/** | ||||||
|  | 	 * Unregister ALL placeholder hooks that are currently registered | ||||||
|  | 	 */ | ||||||
|  | 	protected static void unregisterAll() | ||||||
|  | 	{ | ||||||
|  | 		unregisterAllProvidedExpansions(); | ||||||
|  | 		PLACEHOLDERS.clear(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Unregister all expansions provided by PlaceholderAPI | ||||||
|  | 	 */ | ||||||
|  | 	public static void unregisterAllProvidedExpansions() | ||||||
|  | 	{ | ||||||
|  | 		final Set<PlaceholderHook> set = new HashSet<>(PLACEHOLDERS.values()); | ||||||
|  |  | ||||||
|  | 		for (PlaceholderHook hook : set) | ||||||
|  | 		{ | ||||||
|  | 			if (hook instanceof PlaceholderExpansion) | ||||||
|  | 			{ | ||||||
|  | 				final PlaceholderExpansion expansion = (PlaceholderExpansion) hook; | ||||||
|  |  | ||||||
|  | 				if (!expansion.persist()) | ||||||
|  | 				{ | ||||||
|  | 					unregisterExpansion(expansion); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (hook instanceof Cacheable) | ||||||
|  | 			{ | ||||||
|  | 				((Cacheable) hook).clear(); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static boolean registerExpansion(@NotNull final PlaceholderExpansion expansion) | ||||||
|  | 	{ | ||||||
|  | 		final ExpansionRegisterEvent event = new ExpansionRegisterEvent(expansion); | ||||||
|  | 		Bukkit.getPluginManager().callEvent(event); | ||||||
|  |  | ||||||
|  | 		if (event.isCancelled()) | ||||||
|  | 		{ | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return registerPlaceholderHook(expansion.getIdentifier(), expansion); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static boolean unregisterExpansion(@NotNull final PlaceholderExpansion expansion) | ||||||
|  | 	{ | ||||||
|  | 		if (unregisterPlaceholderHook(expansion.getIdentifier())) | ||||||
|  | 		{ | ||||||
|  | 			Bukkit.getPluginManager().callEvent(new ExpansionUnregisterEvent(expansion)); | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	// === Deprecated API === | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Translates all placeholders into their corresponding values. | ||||||
|  | 	 * <br>You set the pattern yourself through this method. | ||||||
|  | 	 * | ||||||
|  | 	 * @param player   Player to parse the placeholders against | ||||||
|  | 	 * @param text     Text to set the placeholder values in | ||||||
|  | 	 * @param pattern  The pattern to match placeholders to. Capture group 1 must contain an underscore separating the | ||||||
|  | 	 *                 identifier from the params | ||||||
|  | 	 * @param colorize If color codes (&[0-1a-fk-o]) should be translated | ||||||
|  | 	 * @return The text containing the parsed placeholders | ||||||
|  | 	 * @deprecated Please use {@link #setPlaceholders(OfflinePlayer, String)} instead | ||||||
|  | 	 */ | ||||||
|  | 	@NotNull | ||||||
|  | 	@Deprecated | ||||||
|  | 	public static String setPlaceholders(@Nullable final OfflinePlayer player, @NotNull final String text, @NotNull final Pattern pattern, final boolean colorize) | ||||||
|  | 	{ | ||||||
|  | 		return setPlaceholders(player, text); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Translates all placeholders into their corresponding values. | ||||||
|  | 	 * <br>You set the pattern yourself through this method. | ||||||
|  | 	 * | ||||||
|  | 	 * @param player   Player to parse the placeholders against | ||||||
|  | 	 * @param text     List of Strings to set the placeholder values in | ||||||
|  | 	 * @param pattern  The pattern to match placeholders to. Capture group 1 must contain an underscore separating the | ||||||
|  | 	 *                 identifier from the params | ||||||
|  | 	 * @param colorize If color codes (&[0-1a-fk-o]) should be translated | ||||||
|  | 	 * @return String containing all translated placeholders | ||||||
|  | 	 * @deprecated Please use {@link #setPlaceholders(OfflinePlayer, List)} instead | ||||||
|  | 	 */ | ||||||
|  | 	@NotNull | ||||||
|  | 	@Deprecated | ||||||
|  | 	public static List<String> setPlaceholders(@Nullable final OfflinePlayer player, @NotNull final List<String> text, @NotNull final Pattern pattern, final boolean colorize) | ||||||
|  | 	{ | ||||||
|  | 		return setPlaceholders(player, text); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Deprecated | ||||||
|  | 	public static Set<PlaceholderExpansion> getExpansions() | ||||||
|  | 	{ | ||||||
| 		Set<PlaceholderExpansion> set = getPlaceholders().values().stream() | 		Set<PlaceholderExpansion> set = getPlaceholders().values().stream() | ||||||
| 														 .filter(PlaceholderExpansion.class::isInstance).map(PlaceholderExpansion.class::cast) | 														 .filter(PlaceholderExpansion.class::isInstance).map(PlaceholderExpansion.class::cast) | ||||||
| 														 .collect(Collectors.toCollection(HashSet::new)); | 														 .collect(Collectors.toCollection(HashSet::new)); | ||||||
| @@ -128,8 +316,11 @@ public class PlaceholderAPI { | |||||||
| 	 * | 	 * | ||||||
| 	 * @param text String to check | 	 * @param text String to check | ||||||
| 	 * @return true if String contains any registered placeholder identifiers, false otherwise | 	 * @return true if String contains any registered placeholder identifiers, false otherwise | ||||||
|  | 	 * @deprecated Will be removed in a future release. | ||||||
| 	 */ | 	 */ | ||||||
|     public static boolean containsPlaceholders(String text) { | 	@Deprecated | ||||||
|  | 	public static boolean containsPlaceholders(String text) | ||||||
|  | 	{ | ||||||
| 		return text != null && PLACEHOLDER_PATTERN.matcher(text).find(); | 		return text != null && PLACEHOLDER_PATTERN.matcher(text).find(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -138,23 +329,14 @@ public class PlaceholderAPI { | |||||||
| 	 * | 	 * | ||||||
| 	 * @param text String to check | 	 * @param text String to check | ||||||
| 	 * @return true if String contains any registered placeholder identifiers, false otherwise | 	 * @return true if String contains any registered placeholder identifiers, false otherwise | ||||||
|  | 	 * @deprecated Will be removed in a future release. | ||||||
| 	 */ | 	 */ | ||||||
|     public static boolean containsBracketPlaceholders(String text) { | 	@Deprecated | ||||||
|  | 	public static boolean containsBracketPlaceholders(String text) | ||||||
|  | 	{ | ||||||
| 		return text != null && BRACKET_PLACEHOLDER_PATTERN.matcher(text).find(); | 		return text != null && BRACKET_PLACEHOLDER_PATTERN.matcher(text).find(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Translates all placeholders into their corresponding values. |  | ||||||
|      * <br>The pattern of a valid placeholder is {@literal {<identifier>_<params>}}. |  | ||||||
|      * |  | ||||||
|      * @param player Player to parse the placeholders against |  | ||||||
|      * @param text   List of Strings to set the placeholder values in |  | ||||||
|      * @return String containing all translated placeholders |  | ||||||
|      */ |  | ||||||
|     public static List<String> setBracketPlaceholders(OfflinePlayer player, List<String> text) { |  | ||||||
|         return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, true); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Translates all placeholders into their corresponding values. | 	 * Translates all placeholders into their corresponding values. | ||||||
| 	 * <br>The pattern of a valid placeholder is {@literal {<identifier>_<params>}}. | 	 * <br>The pattern of a valid placeholder is {@literal {<identifier>_<params>}}. | ||||||
| @@ -163,23 +345,14 @@ public class PlaceholderAPI { | |||||||
| 	 * @param text     List of Strings to set the placeholder values in | 	 * @param text     List of Strings to set the placeholder values in | ||||||
| 	 * @param colorize If color codes (&[0-1a-fk-o]) should be translated | 	 * @param colorize If color codes (&[0-1a-fk-o]) should be translated | ||||||
| 	 * @return String containing all translated placeholders | 	 * @return String containing all translated placeholders | ||||||
|  | 	 * @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead. | ||||||
| 	 */ | 	 */ | ||||||
|     public static List<String> setBracketPlaceholders(OfflinePlayer player, List<String> text, boolean colorize) { | 	@Deprecated | ||||||
|  | 	public static List<String> setBracketPlaceholders(OfflinePlayer player, List<String> text, boolean colorize) | ||||||
|  | 	{ | ||||||
| 		return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, colorize); | 		return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, colorize); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Translates all placeholders into their corresponding values. |  | ||||||
|      * <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}. |  | ||||||
|      * |  | ||||||
|      * @param player Player to parse the placeholders against |  | ||||||
|      * @param text   List of Strings to set the placeholder values in |  | ||||||
|      * @return String containing all translated placeholders |  | ||||||
|      */ |  | ||||||
|     public static List<String> setPlaceholders(OfflinePlayer player, List<String> text) { |  | ||||||
|         return setPlaceholders(player, text, PLACEHOLDER_PATTERN, true); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Translates all placeholders into their corresponding values. | 	 * Translates all placeholders into their corresponding values. | ||||||
| 	 * <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}. | 	 * <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}. | ||||||
| @@ -188,8 +361,11 @@ public class PlaceholderAPI { | |||||||
| 	 * @param text     List of Strings to set the placeholder values in | 	 * @param text     List of Strings to set the placeholder values in | ||||||
| 	 * @param colorize If color codes (&[0-1a-fk-o]) should be translated | 	 * @param colorize If color codes (&[0-1a-fk-o]) should be translated | ||||||
| 	 * @return String containing all translated placeholders | 	 * @return String containing all translated placeholders | ||||||
|  | 	 * @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead. | ||||||
| 	 */ | 	 */ | ||||||
|     public static List<String> setPlaceholders(OfflinePlayer player, List<String> text, boolean colorize) { | 	@Deprecated | ||||||
|  | 	public static List<String> setPlaceholders(OfflinePlayer player, List<String> text, boolean colorize) | ||||||
|  | 	{ | ||||||
| 		return setPlaceholders(player, text, PLACEHOLDER_PATTERN, colorize); | 		return setPlaceholders(player, text, PLACEHOLDER_PATTERN, colorize); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -202,43 +378,14 @@ public class PlaceholderAPI { | |||||||
| 	 * @param pattern The pattern to match placeholders to. Capture group 1 must contain an underscore separating the | 	 * @param pattern The pattern to match placeholders to. Capture group 1 must contain an underscore separating the | ||||||
| 	 *                identifier from the params | 	 *                identifier from the params | ||||||
| 	 * @return String containing all translated placeholders | 	 * @return String containing all translated placeholders | ||||||
|  | 	 * @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead. | ||||||
| 	 */ | 	 */ | ||||||
|     public static List<String> setPlaceholders(OfflinePlayer player, List<String> text, Pattern pattern) { | 	@Deprecated | ||||||
|  | 	public static List<String> setPlaceholders(OfflinePlayer player, List<String> text, Pattern pattern) | ||||||
|  | 	{ | ||||||
| 		return setPlaceholders(player, text, pattern, true); | 		return setPlaceholders(player, text, pattern, true); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Translates all placeholders into their corresponding values. |  | ||||||
|      * <br>You set the pattern yourself through this method. |  | ||||||
|      * |  | ||||||
|      * @param player   Player to parse the placeholders against |  | ||||||
|      * @param text     List of Strings to set the placeholder values in |  | ||||||
|      * @param pattern  The pattern to match placeholders to. Capture group 1 must contain an underscore separating the |  | ||||||
|      *                 identifier from the params |  | ||||||
|      * @param colorize If color codes (&[0-1a-fk-o]) should be translated |  | ||||||
|      * @return String containing all translated placeholders |  | ||||||
|      */ |  | ||||||
|     public static List<String> setPlaceholders(OfflinePlayer player, List<String> text, Pattern pattern, boolean colorize) { |  | ||||||
|         if (text == null) { |  | ||||||
|             return null; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return text.stream() |  | ||||||
|                 .map(line -> setPlaceholders(player, line, pattern, colorize)) |  | ||||||
|                 .collect(Collectors.toList()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Translates all placeholders into their corresponding values. |  | ||||||
|      * <br>The pattern of a valid placeholder is {@literal {<identifier>_<params>}}. |  | ||||||
|      * |  | ||||||
|      * @param player Player to parse the placeholders against |  | ||||||
|      * @param text   Text to set the placeholder values in |  | ||||||
|      * @return String containing all translated placeholders |  | ||||||
|      */ |  | ||||||
|     public static String setBracketPlaceholders(OfflinePlayer player, String text) { |  | ||||||
|         return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, true); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Translates all placeholders into their corresponding values. | 	 * Translates all placeholders into their corresponding values. | ||||||
| @@ -248,23 +395,14 @@ public class PlaceholderAPI { | |||||||
| 	 * @param text     Text to set the placeholder values in | 	 * @param text     Text to set the placeholder values in | ||||||
| 	 * @param colorize If color codes (&[0-1a-fk-o]) should be translated | 	 * @param colorize If color codes (&[0-1a-fk-o]) should be translated | ||||||
| 	 * @return String containing all translated placeholders | 	 * @return String containing all translated placeholders | ||||||
|  | 	 * @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead. | ||||||
| 	 */ | 	 */ | ||||||
|     public static String setBracketPlaceholders(OfflinePlayer player, String text, boolean colorize) { | 	@Deprecated | ||||||
|  | 	public static String setBracketPlaceholders(OfflinePlayer player, String text, boolean colorize) | ||||||
|  | 	{ | ||||||
| 		return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, colorize); | 		return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, colorize); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Translates all placeholders into their corresponding values. |  | ||||||
|      * <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}. |  | ||||||
|      * |  | ||||||
|      * @param player Player to parse the placeholders against |  | ||||||
|      * @param text   Text to set the placeholder values in |  | ||||||
|      * @return String containing all translated placeholders |  | ||||||
|      */ |  | ||||||
|     public static String setPlaceholders(OfflinePlayer player, String text) { |  | ||||||
|         return setPlaceholders(player, text, PLACEHOLDER_PATTERN); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Translates all placeholders into their corresponding values. | 	 * Translates all placeholders into their corresponding values. | ||||||
| 	 * <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}. | 	 * <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}. | ||||||
| @@ -273,8 +411,11 @@ public class PlaceholderAPI { | |||||||
| 	 * @param text     Text to parse the placeholders in | 	 * @param text     Text to parse the placeholders in | ||||||
| 	 * @param colorize If color codes (&[0-1a-fk-o]) should be translated | 	 * @param colorize If color codes (&[0-1a-fk-o]) should be translated | ||||||
| 	 * @return The text containing the parsed placeholders | 	 * @return The text containing the parsed placeholders | ||||||
|  | 	 * @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead. | ||||||
| 	 */ | 	 */ | ||||||
|     public static String setPlaceholders(OfflinePlayer player, String text, boolean colorize) { | 	@Deprecated | ||||||
|  | 	public static String setPlaceholders(OfflinePlayer player, String text, boolean colorize) | ||||||
|  | 	{ | ||||||
| 		return setPlaceholders(player, text, PLACEHOLDER_PATTERN, colorize); | 		return setPlaceholders(player, text, PLACEHOLDER_PATTERN, colorize); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -287,60 +428,14 @@ public class PlaceholderAPI { | |||||||
| 	 * @param pattern The pattern to match placeholders to. Capture group 1 must contain an underscore separating the | 	 * @param pattern The pattern to match placeholders to. Capture group 1 must contain an underscore separating the | ||||||
| 	 *                identifier from the params | 	 *                identifier from the params | ||||||
| 	 * @return The text containing the parsed placeholders | 	 * @return The text containing the parsed placeholders | ||||||
|  | 	 * @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead. | ||||||
| 	 */ | 	 */ | ||||||
|     public static String setPlaceholders(OfflinePlayer player, String text, Pattern pattern) { | 	@Deprecated | ||||||
|  | 	public static String setPlaceholders(OfflinePlayer player, String text, Pattern pattern) | ||||||
|  | 	{ | ||||||
| 		return setPlaceholders(player, text, pattern, true); | 		return setPlaceholders(player, text, pattern, true); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Translates all placeholders into their corresponding values. |  | ||||||
|      * <br>You set the pattern yourself through this method. |  | ||||||
|      * |  | ||||||
|      * @param player   Player to parse the placeholders against |  | ||||||
|      * @param text     Text to set the placeholder values in |  | ||||||
|      * @param pattern  The pattern to match placeholders to. Capture group 1 must contain an underscore separating the |  | ||||||
|      *                 identifier from the params |  | ||||||
|      * @param colorize If color codes (&[0-1a-fk-o]) should be translated |  | ||||||
|      * @return The text containing the parsed placeholders |  | ||||||
|      */ |  | ||||||
|     public static String setPlaceholders(OfflinePlayer player, String text, Pattern pattern, boolean colorize) { |  | ||||||
|         if (text == null) { |  | ||||||
|             return null; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (placeholders.isEmpty()) { |  | ||||||
|             return colorize ? color(text) : text; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         final Matcher matcher = pattern.matcher(text); |  | ||||||
|         final Map<String, PlaceholderHook> hooks = getPlaceholders(); |  | ||||||
|  |  | ||||||
|         while (matcher.find()) { |  | ||||||
|             final String format = matcher.group(1); |  | ||||||
|             final int index = format.indexOf("_"); |  | ||||||
|  |  | ||||||
|             if (index <= 0 || index >= format.length()) { |  | ||||||
|                 continue; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             final String identifier = format.substring(0, index).toLowerCase(); |  | ||||||
|             final String params = format.substring(index + 1); |  | ||||||
|             final PlaceholderHook hook = hooks.get(identifier); |  | ||||||
|  |  | ||||||
|             if (hook == null) { |  | ||||||
|                 continue; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             final String value = hook.onRequest(player, params); |  | ||||||
|  |  | ||||||
|             if (value != null) { |  | ||||||
|                 text = text.replaceAll(Pattern.quote(matcher.group()), Matcher.quoteReplacement(value)); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return colorize ? color(text) : text; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Translate placeholders in the provided List based on the relation of the two provided players. | 	 * Translate placeholders in the provided List based on the relation of the two provided players. | ||||||
| 	 * <br>The pattern of a valid placeholder is {@literal %rel_<identifier>_<param>%}. | 	 * <br>The pattern of a valid placeholder is {@literal %rel_<identifier>_<param>%}. | ||||||
| @@ -349,8 +444,11 @@ public class PlaceholderAPI { | |||||||
| 	 * @param two  Player to compare | 	 * @param two  Player to compare | ||||||
| 	 * @param text text to parse the placeholder values to | 	 * @param text text to parse the placeholder values to | ||||||
| 	 * @return The text containing the parsed relational placeholders | 	 * @return The text containing the parsed relational placeholders | ||||||
|  | 	 * @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead. | ||||||
| 	 */ | 	 */ | ||||||
|     public static List<String> setRelationalPlaceholders(Player one, Player two, List<String> text) { | 	@Deprecated | ||||||
|  | 	public static List<String> setRelationalPlaceholders(Player one, Player two, List<String> text) | ||||||
|  | 	{ | ||||||
| 		return setRelationalPlaceholders(one, two, text, true); | 		return setRelationalPlaceholders(one, two, text, true); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -363,9 +461,13 @@ public class PlaceholderAPI { | |||||||
| 	 * @param text     Text to parse the placeholders in | 	 * @param text     Text to parse the placeholders in | ||||||
| 	 * @param colorize If color codes (&[0-1a-fk-o]) should be translated | 	 * @param colorize If color codes (&[0-1a-fk-o]) should be translated | ||||||
| 	 * @return The text containing the parsed relational placeholders | 	 * @return The text containing the parsed relational placeholders | ||||||
|  | 	 * @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead. | ||||||
| 	 */ | 	 */ | ||||||
|     public static List<String> setRelationalPlaceholders(Player one, Player two, List<String> text, boolean colorize) { | 	@Deprecated | ||||||
|         if (text == null) { | 	public static List<String> setRelationalPlaceholders(Player one, Player two, List<String> text, boolean colorize) | ||||||
|  | 	{ | ||||||
|  | 		if (text == null) | ||||||
|  | 		{ | ||||||
| 			return null; | 			return null; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -382,8 +484,11 @@ public class PlaceholderAPI { | |||||||
| 	 * @param two  Second player to compare | 	 * @param two  Second player to compare | ||||||
| 	 * @param text Text to parse the placeholders in | 	 * @param text Text to parse the placeholders in | ||||||
| 	 * @return The text containing the parsed relational placeholders | 	 * @return The text containing the parsed relational placeholders | ||||||
|  | 	 * @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead. | ||||||
| 	 */ | 	 */ | ||||||
|     public static String setRelationalPlaceholders(Player one, Player two, String text) { | 	@Deprecated | ||||||
|  | 	public static String setRelationalPlaceholders(Player one, Player two, String text) | ||||||
|  | 	{ | ||||||
| 		return setRelationalPlaceholders(one, two, text, true); | 		return setRelationalPlaceholders(one, two, text, true); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -396,25 +501,32 @@ public class PlaceholderAPI { | |||||||
| 	 * @param text     Text to parse the placeholders in | 	 * @param text     Text to parse the placeholders in | ||||||
| 	 * @param colorize If color codes (&[0-1a-fk-o]) should be translated | 	 * @param colorize If color codes (&[0-1a-fk-o]) should be translated | ||||||
| 	 * @return The text containing the parsed relational placeholders | 	 * @return The text containing the parsed relational placeholders | ||||||
|  | 	 * @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead. | ||||||
| 	 */ | 	 */ | ||||||
|  | 	@Deprecated | ||||||
| 	@SuppressWarnings("DuplicatedCode") | 	@SuppressWarnings("DuplicatedCode") | ||||||
|     public static String setRelationalPlaceholders(Player one, Player two, String text, boolean colorize) { | 	public static String setRelationalPlaceholders(Player one, Player two, String text, boolean colorize) | ||||||
|         if (text == null) { | 	{ | ||||||
|  | 		if (text == null) | ||||||
|  | 		{ | ||||||
| 			return null; | 			return null; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|         if (placeholders.isEmpty()) { | 		if (PLACEHOLDERS.isEmpty()) | ||||||
|  | 		{ | ||||||
| 			return colorize ? Msg.color(text) : text; | 			return colorize ? Msg.color(text) : text; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		final Matcher                      matcher = RELATIONAL_PLACEHOLDER_PATTERN.matcher(text); | 		final Matcher                      matcher = RELATIONAL_PLACEHOLDER_PATTERN.matcher(text); | ||||||
| 		final Map<String, PlaceholderHook> hooks   = getPlaceholders(); | 		final Map<String, PlaceholderHook> hooks   = getPlaceholders(); | ||||||
|  |  | ||||||
|         while (matcher.find()) { | 		while (matcher.find()) | ||||||
|  | 		{ | ||||||
| 			final String format = matcher.group(2); | 			final String format = matcher.group(2); | ||||||
| 			final int    index  = format.indexOf("_"); | 			final int    index  = format.indexOf("_"); | ||||||
|  |  | ||||||
|             if (index <= 0 || index >= format.length()) { | 			if (index <= 0 || index >= format.length()) | ||||||
|  | 			{ | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @@ -422,13 +534,15 @@ public class PlaceholderAPI { | |||||||
| 			String                params     = format.substring(index + 1); | 			String                params     = format.substring(index + 1); | ||||||
| 			final PlaceholderHook hook       = hooks.get(identifier); | 			final PlaceholderHook hook       = hooks.get(identifier); | ||||||
|  |  | ||||||
|             if (!(hook instanceof Relational)) { | 			if (!(hook instanceof Relational)) | ||||||
|  | 			{ | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			final String value = ((Relational) hook).onPlaceholderRequest(one, two, params); | 			final String value = ((Relational) hook).onPlaceholderRequest(one, two, params); | ||||||
|  |  | ||||||
|             if (value != null) { | 			if (value != null) | ||||||
|  | 			{ | ||||||
| 				text = text.replaceAll(Pattern.quote(matcher.group()), Matcher.quoteReplacement(value)); | 				text = text.replaceAll(Pattern.quote(matcher.group()), Matcher.quoteReplacement(value)); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -436,60 +550,15 @@ public class PlaceholderAPI { | |||||||
| 		return colorize ? Msg.color(text) : text; | 		return colorize ? Msg.color(text) : text; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Unregister ALL placeholder hooks that are currently registered |  | ||||||
|      */ |  | ||||||
|     protected static void unregisterAll() { |  | ||||||
|         unregisterAllProvidedExpansions(); |  | ||||||
|         placeholders.clear(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Unregister all expansions provided by PlaceholderAPI |  | ||||||
|      */ |  | ||||||
|     public static void unregisterAllProvidedExpansions() { |  | ||||||
|         final Set<PlaceholderHook> set = new HashSet<>(placeholders.values()); |  | ||||||
|  |  | ||||||
|         for (PlaceholderHook hook : set) { |  | ||||||
|             if (hook instanceof PlaceholderExpansion) { |  | ||||||
|                 final PlaceholderExpansion expansion = (PlaceholderExpansion) hook; |  | ||||||
|  |  | ||||||
|                 if (!expansion.persist()) { |  | ||||||
|                     unregisterExpansion(expansion); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (hook instanceof Cacheable) { |  | ||||||
|                 ((Cacheable) hook).clear(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public static boolean registerExpansion(PlaceholderExpansion ex) { |  | ||||||
|         ExpansionRegisterEvent ev = new ExpansionRegisterEvent(ex); |  | ||||||
|         Bukkit.getPluginManager().callEvent(ev); |  | ||||||
|         if (ev.isCancelled()) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return registerPlaceholderHook(ex.getIdentifier(), ex); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public static boolean unregisterExpansion(PlaceholderExpansion ex) { |  | ||||||
|         if (unregisterPlaceholderHook(ex.getIdentifier())) { |  | ||||||
|             Bukkit.getPluginManager().callEvent(new ExpansionUnregisterEvent(ex)); |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Gets the placeholder pattern for the default placeholders. | 	 * Gets the placeholder pattern for the default placeholders. | ||||||
| 	 * | 	 * | ||||||
| 	 * @return The pattern for {@literal %<identifier>_<params>%} | 	 * @return The pattern for {@literal %<identifier>_<params>%} | ||||||
|  | 	 * @deprecated Will be removed in a future release. | ||||||
| 	 */ | 	 */ | ||||||
|     public static Pattern getPlaceholderPattern() { | 	@Deprecated | ||||||
|  | 	public static Pattern getPlaceholderPattern() | ||||||
|  | 	{ | ||||||
| 		return PLACEHOLDER_PATTERN; | 		return PLACEHOLDER_PATTERN; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -497,8 +566,11 @@ public class PlaceholderAPI { | |||||||
| 	 * Gets the placeholder pattern for the bracket placeholders. | 	 * Gets the placeholder pattern for the bracket placeholders. | ||||||
| 	 * | 	 * | ||||||
| 	 * @return The pattern for {@literal {<identifier>_<params>}} | 	 * @return The pattern for {@literal {<identifier>_<params>}} | ||||||
|  | 	 * @deprecated Will be removed in a future release. | ||||||
| 	 */ | 	 */ | ||||||
|     public static Pattern getBracketPlaceholderPattern() { | 	@Deprecated | ||||||
|  | 	public static Pattern getBracketPlaceholderPattern() | ||||||
|  | 	{ | ||||||
| 		return BRACKET_PLACEHOLDER_PATTERN; | 		return BRACKET_PLACEHOLDER_PATTERN; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -506,60 +578,93 @@ public class PlaceholderAPI { | |||||||
| 	 * Gets the placeholder pattern for the relational placeholders. | 	 * Gets the placeholder pattern for the relational placeholders. | ||||||
| 	 * | 	 * | ||||||
| 	 * @return The pattern for {@literal %rel_<identifier>_<params>%} | 	 * @return The pattern for {@literal %rel_<identifier>_<params>%} | ||||||
|  | 	 * @deprecated Will be removed in a future release. | ||||||
| 	 */ | 	 */ | ||||||
|     public static Pattern getRelationalPlaceholderPattern() { | 	@Deprecated | ||||||
|  | 	public static Pattern getRelationalPlaceholderPattern() | ||||||
|  | 	{ | ||||||
| 		return RELATIONAL_PLACEHOLDER_PATTERN; | 		return RELATIONAL_PLACEHOLDER_PATTERN; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @deprecated Will be removed in a future release. | ||||||
|  | 	 */ | ||||||
| 	@Deprecated | 	@Deprecated | ||||||
|     public static Set<String> getRegisteredPlaceholderPlugins() { | 	public static Set<String> getRegisteredPlaceholderPlugins() | ||||||
|  | 	{ | ||||||
| 		return getRegisteredIdentifiers(); | 		return getRegisteredIdentifiers(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @deprecated Will be removed in a future release. | ||||||
|  | 	 */ | ||||||
| 	@Deprecated | 	@Deprecated | ||||||
|     public static Set<String> getExternalPlaceholderPlugins() { | 	public static Set<String> getExternalPlaceholderPlugins() | ||||||
|  | 	{ | ||||||
| 		return null; | 		return null; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @deprecated Will be removed in a future release. | ||||||
|  | 	 */ | ||||||
| 	@Deprecated | 	@Deprecated | ||||||
|     public static boolean registerPlaceholderHook(Plugin plugin, PlaceholderHook placeholderHook) { | 	public static String setPlaceholders(Player player, String text, boolean colorize) | ||||||
|         return plugin != null && registerPlaceholderHook(plugin.getName(), placeholderHook); | 	{ | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Deprecated |  | ||||||
|     public static boolean unregisterPlaceholderHook(Plugin plugin) { |  | ||||||
|         return plugin != null && unregisterPlaceholderHook(plugin.getName()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public static String setPlaceholders(Player player, String text) { |  | ||||||
|         return setPlaceholders(player, text, PLACEHOLDER_PATTERN, true); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public static String setPlaceholders(Player player, String text, boolean colorize) { |  | ||||||
| 		return setPlaceholders(player, text, PLACEHOLDER_PATTERN, colorize); | 		return setPlaceholders(player, text, PLACEHOLDER_PATTERN, colorize); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     public static List<String> setPlaceholders(Player player, List<String> text) { | 	/** | ||||||
|  | 	 * @deprecated Will be removed in a future release. | ||||||
|  | 	 */ | ||||||
|  | 	@Deprecated | ||||||
|  | 	public static List<String> setPlaceholders(Player player, List<String> text) | ||||||
|  | 	{ | ||||||
| 		return setPlaceholders(player, text, PLACEHOLDER_PATTERN, true); | 		return setPlaceholders(player, text, PLACEHOLDER_PATTERN, true); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     public static List<String> setPlaceholders(Player player, List<String> text, boolean colorize) { | 	/** | ||||||
|  | 	 * @deprecated Will be removed in a future release. | ||||||
|  | 	 */ | ||||||
|  | 	@Deprecated | ||||||
|  | 	public static List<String> setPlaceholders(Player player, List<String> text, boolean colorize) | ||||||
|  | 	{ | ||||||
| 		return setPlaceholders(player, text, PLACEHOLDER_PATTERN, colorize); | 		return setPlaceholders(player, text, PLACEHOLDER_PATTERN, colorize); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     public static String setBracketPlaceholders(Player player, String text) { | 	/** | ||||||
|  | 	 * @deprecated Will be removed in a future release. | ||||||
|  | 	 */ | ||||||
|  | 	@Deprecated | ||||||
|  | 	public static String setBracketPlaceholders(Player player, String text) | ||||||
|  | 	{ | ||||||
| 		return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, true); | 		return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, true); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     public static String setBracketPlaceholders(Player player, String text, boolean colorize) { | 	/** | ||||||
|  | 	 * @deprecated Will be removed in a future release. | ||||||
|  | 	 */ | ||||||
|  | 	@Deprecated | ||||||
|  | 	public static String setBracketPlaceholders(Player player, String text, boolean colorize) | ||||||
|  | 	{ | ||||||
| 		return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, colorize); | 		return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, colorize); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     public static List<String> setBracketPlaceholders(Player player, List<String> text) { | 	/** | ||||||
|  | 	 * @deprecated Will be removed in a future release. | ||||||
|  | 	 */ | ||||||
|  | 	@Deprecated | ||||||
|  | 	public static List<String> setBracketPlaceholders(Player player, List<String> text) | ||||||
|  | 	{ | ||||||
| 		return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, true); | 		return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, true); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     public static List<String> setBracketPlaceholders(Player player, List<String> text, boolean colorize) { | 	/** | ||||||
|  | 	 * @deprecated Will be removed in a future release. | ||||||
|  | 	 */ | ||||||
|  | 	@Deprecated | ||||||
|  | 	public static List<String> setBracketPlaceholders(Player player, List<String> text, boolean colorize) | ||||||
|  | 	{ | ||||||
| 		return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, colorize); | 		return setPlaceholders(player, text, BRACKET_PLACEHOLDER_PATTERN, colorize); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,8 +22,11 @@ package me.clip.placeholderapi; | |||||||
|  |  | ||||||
| import org.bukkit.OfflinePlayer; | import org.bukkit.OfflinePlayer; | ||||||
| import org.bukkit.entity.Player; | import org.bukkit.entity.Player; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
| public abstract class PlaceholderHook { | public abstract class PlaceholderHook | ||||||
|  | { | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * called when a placeholder value is requested from this hook | 	 * called when a placeholder value is requested from this hook | ||||||
| @@ -33,8 +36,11 @@ public abstract class PlaceholderHook { | |||||||
| 	 * @param params String passed to the hook to determine what value to return | 	 * @param params String passed to the hook to determine what value to return | ||||||
| 	 * @return value for the requested player and params | 	 * @return value for the requested player and params | ||||||
| 	 */ | 	 */ | ||||||
|     public String onRequest(OfflinePlayer player, String params) { | 	@Nullable | ||||||
|         if (player != null && player.isOnline()) { | 	public String onRequest(@Nullable final OfflinePlayer player, @NotNull final String params) | ||||||
|  | 	{ | ||||||
|  | 		if (player != null && player.isOnline()) | ||||||
|  | 		{ | ||||||
| 			return onPlaceholderRequest((Player) player, params); | 			return onPlaceholderRequest((Player) player, params); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -48,7 +54,11 @@ public abstract class PlaceholderHook { | |||||||
| 	 * @param params String passed to the hook to determine what value to return | 	 * @param params String passed to the hook to determine what value to return | ||||||
| 	 * @return value for the requested player and params | 	 * @return value for the requested player and params | ||||||
| 	 */ | 	 */ | ||||||
|     public String onPlaceholderRequest(Player player, String params) { | 	@Nullable | ||||||
|  | 	@Deprecated | ||||||
|  | 	public String onPlaceholderRequest(@Nullable final Player player, @NotNull final String params) | ||||||
|  | 	{ | ||||||
| 		return null; | 		return null; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -28,29 +28,42 @@ import me.clip.placeholderapi.util.FileUtil; | |||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.configuration.file.FileConfiguration; | import org.bukkit.configuration.file.FileConfiguration; | ||||||
| import org.bukkit.event.Listener; | import org.bukkit.event.Listener; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.lang.reflect.Constructor; |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.Map.Entry; | import java.util.Map.Entry; | ||||||
|  | import java.util.logging.Level; | ||||||
|  |  | ||||||
| public final class ExpansionManager { | public final class ExpansionManager | ||||||
|  | { | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private final File                 folder; | ||||||
|  | 	@NotNull | ||||||
| 	private final PlaceholderAPIPlugin plugin; | 	private final PlaceholderAPIPlugin plugin; | ||||||
|  |  | ||||||
|     public ExpansionManager(PlaceholderAPIPlugin instance) { | 	public ExpansionManager(@NotNull final PlaceholderAPIPlugin plugin) | ||||||
|         plugin = instance; | 	{ | ||||||
|  | 		this.plugin = plugin; | ||||||
|  | 		this.folder = new File(plugin.getDataFolder(), "expansions"); | ||||||
|  |  | ||||||
|         File f = new File(PlaceholderAPIPlugin.getInstance().getDataFolder(), "expansions"); | 		if (!this.folder.exists() && !folder.mkdirs()) | ||||||
|         if (!f.exists()) { | 		{ | ||||||
|             f.mkdirs(); | 			plugin.getLogger().log(Level.WARNING, "failed to create expansions folder!"); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     public PlaceholderExpansion getRegisteredExpansion(String name) { | 	public PlaceholderExpansion getRegisteredExpansion(String name) | ||||||
|         for (Entry<String, PlaceholderHook> hook : PlaceholderAPI.getPlaceholders().entrySet()) { | 	{ | ||||||
|             if (hook.getValue() instanceof PlaceholderExpansion) { | 		for (Entry<String, PlaceholderHook> hook : PlaceholderAPI.getPlaceholders().entrySet()) | ||||||
|                 if (name.equalsIgnoreCase(hook.getKey())) { | 		{ | ||||||
|  | 			if (hook.getValue() instanceof PlaceholderExpansion) | ||||||
|  | 			{ | ||||||
|  | 				if (name.equalsIgnoreCase(hook.getKey())) | ||||||
|  | 				{ | ||||||
| 					return (PlaceholderExpansion) hook.getValue(); | 					return (PlaceholderExpansion) hook.getValue(); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| @@ -59,30 +72,41 @@ public final class ExpansionManager { | |||||||
| 		return null; | 		return null; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     public boolean registerExpansion(PlaceholderExpansion expansion) { | 	public boolean registerExpansion(@NotNull final PlaceholderExpansion expansion) | ||||||
|         if (expansion == null || expansion.getIdentifier() == null) { | 	{ | ||||||
|  | 		if (expansion.getIdentifier() == null) | ||||||
|  | 		{ | ||||||
| 			return false; | 			return false; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|         if (expansion instanceof Configurable) { | 		if (expansion instanceof Configurable) | ||||||
|  | 		{ | ||||||
| 			Map<String, Object> defaults = ((Configurable) expansion).getDefaults(); | 			Map<String, Object> defaults = ((Configurable) expansion).getDefaults(); | ||||||
| 			String              pre      = "expansions." + expansion.getIdentifier() + "."; | 			String              pre      = "expansions." + expansion.getIdentifier() + "."; | ||||||
| 			FileConfiguration   cfg      = plugin.getConfig(); | 			FileConfiguration   cfg      = plugin.getConfig(); | ||||||
| 			boolean             save     = false; | 			boolean             save     = false; | ||||||
|  |  | ||||||
|             if (defaults != null) { | 			if (defaults != null) | ||||||
|                 for (Entry<String, Object> entries : defaults.entrySet()) { | 			{ | ||||||
|                     if (entries.getKey() == null || entries.getKey().isEmpty()) { | 				for (Entry<String, Object> entries : defaults.entrySet()) | ||||||
|  | 				{ | ||||||
|  | 					if (entries.getKey() == null || entries.getKey().isEmpty()) | ||||||
|  | 					{ | ||||||
| 						continue; | 						continue; | ||||||
| 					} | 					} | ||||||
|  |  | ||||||
|                     if (entries.getValue() == null) { | 					if (entries.getValue() == null) | ||||||
|                         if (cfg.contains(pre + entries.getKey())) { | 					{ | ||||||
|  | 						if (cfg.contains(pre + entries.getKey())) | ||||||
|  | 						{ | ||||||
| 							save = true; | 							save = true; | ||||||
| 							cfg.set(pre + entries.getKey(), null); | 							cfg.set(pre + entries.getKey(), null); | ||||||
| 						} | 						} | ||||||
|                     } else { | 					} | ||||||
|                         if (!cfg.contains(pre + entries.getKey())) { | 					else | ||||||
|  | 					{ | ||||||
|  | 						if (!cfg.contains(pre + entries.getKey())) | ||||||
|  | 						{ | ||||||
| 							save = true; | 							save = true; | ||||||
| 							cfg.set(pre + entries.getKey(), entries.getValue()); | 							cfg.set(pre + entries.getKey(), entries.getValue()); | ||||||
| 						} | 						} | ||||||
| @@ -90,15 +114,18 @@ public final class ExpansionManager { | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|             if (save) { | 			if (save) | ||||||
|  | 			{ | ||||||
| 				plugin.saveConfig(); | 				plugin.saveConfig(); | ||||||
| 				plugin.reloadConfig(); | 				plugin.reloadConfig(); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|         if (expansion instanceof VersionSpecific) { | 		if (expansion instanceof VersionSpecific) | ||||||
|  | 		{ | ||||||
| 			VersionSpecific nms = (VersionSpecific) expansion; | 			VersionSpecific nms = (VersionSpecific) expansion; | ||||||
|             if (!nms.isCompatibleWith(PlaceholderAPIPlugin.getServerVersion())) { | 			if (!nms.isCompatibleWith(PlaceholderAPIPlugin.getServerVersion())) | ||||||
|  | 			{ | ||||||
| 				plugin.getLogger() | 				plugin.getLogger() | ||||||
| 					  .info( | 					  .info( | ||||||
| 							  "Your server version is not compatible with expansion: " + expansion.getIdentifier() | 							  "Your server version is not compatible with expansion: " + expansion.getIdentifier() | ||||||
| @@ -107,32 +134,33 @@ public final class ExpansionManager { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|         if (!expansion.canRegister()) { | 		if (!expansion.canRegister() || !expansion.register()) | ||||||
|  | 		{ | ||||||
| 			return false; | 			return false; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|         if (!expansion.register()) { | 		if (expansion instanceof Listener) | ||||||
|             return false; | 		{ | ||||||
|         } | 			Bukkit.getPluginManager().registerEvents(((Listener) expansion), plugin); | ||||||
|  |  | ||||||
|         if (expansion instanceof Listener) { |  | ||||||
|             Listener l = (Listener) expansion; |  | ||||||
|             Bukkit.getPluginManager().registerEvents(l, plugin); |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		plugin.getLogger().info("Successfully registered expansion: " + expansion.getIdentifier()); | 		plugin.getLogger().info("Successfully registered expansion: " + expansion.getIdentifier()); | ||||||
|  |  | ||||||
|         if (expansion instanceof Taskable) { | 		if (expansion instanceof Taskable) | ||||||
|  | 		{ | ||||||
| 			((Taskable) expansion).start(); | 			((Taskable) expansion).start(); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|         if (plugin.getExpansionCloud() != null) { | 		if (plugin.getExpansionCloud() != null) | ||||||
|             CloudExpansion ce = plugin.getExpansionCloud().getCloudExpansion(expansion.getIdentifier()); | 		{ | ||||||
|  | 			final CloudExpansion cloudExpansion = plugin.getExpansionCloud().getCloudExpansion(expansion.getIdentifier()); | ||||||
|  |  | ||||||
|             if (ce != null) { | 			if (cloudExpansion != null) | ||||||
|                 ce.setHasExpansion(true); | 			{ | ||||||
|                 if (!ce.getLatestVersion().equals(expansion.getVersion())) { | 				cloudExpansion.setHasExpansion(true); | ||||||
|                     ce.setShouldUpdate(true); | 				if (!cloudExpansion.getLatestVersion().equals(expansion.getVersion())) | ||||||
|  | 				{ | ||||||
|  | 					cloudExpansion.setShouldUpdate(true); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -141,73 +169,66 @@ public final class ExpansionManager { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|     public PlaceholderExpansion registerExpansion(String fileName) { | 	@Nullable | ||||||
|         List<Class<?>> subs = FileUtil.getClasses("expansions", fileName, PlaceholderExpansion.class); | 	public PlaceholderExpansion registerExpansion(@NotNull final String fileName) | ||||||
|         if (subs == null || subs.isEmpty()) { | 	{ | ||||||
|  | 		final List<Class<? extends PlaceholderExpansion>> subs = FileUtil.getClasses(folder, PlaceholderExpansion.class, fileName); | ||||||
|  | 		if (subs.isEmpty()) | ||||||
|  | 		{ | ||||||
| 			return null; | 			return null; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// only register the first instance found as an expansion jar should only have 1 class | 		// only register the first instance found as an expansion jar should only have 1 class | ||||||
| 		// extending PlaceholderExpansion | 		// extending PlaceholderExpansion | ||||||
|         PlaceholderExpansion ex = createInstance(subs.get(0)); | 		final PlaceholderExpansion expansion = createInstance(subs.get(0)); | ||||||
|         if (registerExpansion(ex)) { | 		if (expansion != null && registerExpansion(expansion)) | ||||||
|             return ex; | 		{ | ||||||
|  | 			return expansion; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		return null; | 		return null; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     public void registerAllExpansions() { | 	public void registerAllExpansions() | ||||||
|         if (plugin == null) { | 	{ | ||||||
|  | 		final List<@NotNull Class<? extends PlaceholderExpansion>> subs = FileUtil.getClasses(folder, PlaceholderExpansion.class); | ||||||
|  | 		if (subs.isEmpty()) | ||||||
|  | 		{ | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|         List<Class<?>> subs = FileUtil.getClasses("expansions", null, PlaceholderExpansion.class); | 		for (final Class<? extends PlaceholderExpansion> clazz : subs) | ||||||
|         if (subs == null || subs.isEmpty()) { | 		{ | ||||||
|             return; | 			final PlaceholderExpansion expansion = createInstance(clazz); | ||||||
|  | 			if (expansion == null) | ||||||
|  | 			{ | ||||||
|  | 				continue; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|         for (Class<?> klass : subs) { | 			try | ||||||
|             PlaceholderExpansion ex = createInstance(klass); | 			{ | ||||||
|             if (ex != null) { | 				registerExpansion(expansion); | ||||||
|                 try { |  | ||||||
|                     registerExpansion(ex); |  | ||||||
|                 } catch (Exception e) { |  | ||||||
|                     plugin.getLogger().info("Couldn't register " + ex.getIdentifier() + " expansion"); |  | ||||||
|                     e.printStackTrace(); |  | ||||||
| 			} | 			} | ||||||
|  | 			catch (final Exception ex) | ||||||
|  | 			{ | ||||||
|  | 				plugin.getLogger().log(Level.WARNING, "Couldn't register " + expansion.getIdentifier() + " expansion", ex); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     private PlaceholderExpansion createInstance(Class<?> klass) { | 	@Nullable | ||||||
|         if (klass == null) { | 	private PlaceholderExpansion createInstance(@NotNull final Class<? extends PlaceholderExpansion> clazz) | ||||||
|  | 	{ | ||||||
|  | 		try | ||||||
|  | 		{ | ||||||
|  | 			return clazz.getDeclaredConstructor().newInstance(); | ||||||
|  | 		} | ||||||
|  | 		catch (final Throwable ex) | ||||||
|  | 		{ | ||||||
|  | 			plugin.getLogger().log(Level.SEVERE, "Failed to load placeholder expansion from class: " + clazz.getName(), ex); | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		return null; | 		return null; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|         PlaceholderExpansion ex = null; |  | ||||||
|         if (!PlaceholderExpansion.class.isAssignableFrom(klass)) { |  | ||||||
|             return null; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         try { |  | ||||||
|             Constructor<?>[] c = klass.getConstructors(); |  | ||||||
|             if (c.length == 0) { |  | ||||||
|                 ex = (PlaceholderExpansion) klass.newInstance(); |  | ||||||
|             } else { |  | ||||||
|                 for (Constructor<?> con : c) { |  | ||||||
|                     if (con.getParameterTypes().length == 0) { |  | ||||||
|                         ex = (PlaceholderExpansion) klass.newInstance(); |  | ||||||
|                         break; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } catch (Throwable t) { |  | ||||||
|             plugin.getLogger() |  | ||||||
|                     .severe("Failed to init placeholder expansion from class: " + klass.getName()); |  | ||||||
|             plugin.getLogger().severe(t.getMessage()); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return ex; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										129
									
								
								src/main/java/me/clip/placeholderapi/replacer/CharsReplacer.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								src/main/java/me/clip/placeholderapi/replacer/CharsReplacer.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,129 @@ | |||||||
|  | package me.clip.placeholderapi.replacer; | ||||||
|  |  | ||||||
|  | import me.clip.placeholderapi.PlaceholderHook; | ||||||
|  | import org.bukkit.OfflinePlayer; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
|  | import java.util.function.Function; | ||||||
|  |  | ||||||
|  | public final class CharsReplacer implements Replacer | ||||||
|  | { | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private final Closure closure; | ||||||
|  |  | ||||||
|  | 	public CharsReplacer(@NotNull final Closure closure) | ||||||
|  | 	{ | ||||||
|  | 		this.closure = closure; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	@Override | ||||||
|  | 	public @NotNull String apply(@NotNull final String text, @Nullable final OfflinePlayer player, @NotNull final Function<String, @Nullable PlaceholderHook> lookup) | ||||||
|  | 	{ | ||||||
|  | 		final char[]        chars   = text.toCharArray(); | ||||||
|  | 		final StringBuilder builder = new StringBuilder(text.length()); | ||||||
|  |  | ||||||
|  | 		final StringBuilder identifier = new StringBuilder(); | ||||||
|  | 		final StringBuilder parameters = new StringBuilder(); | ||||||
|  |  | ||||||
|  | 		for (int i = 0; i < chars.length; i++) | ||||||
|  | 		{ | ||||||
|  | 			final char l = chars[i]; | ||||||
|  |  | ||||||
|  | 			if (l == '&' && ++i < chars.length) | ||||||
|  | 			{ | ||||||
|  | 				final char c = chars[i]; | ||||||
|  |  | ||||||
|  | 				if (c != '0' && c != '1' && c != '2' && c != '3' && c != '4' && c != '5' && c != '6' && c != '7' && c != '8' && c != '9' && c != 'a' && c != 'b' && c != 'c' && c != 'd' && c != 'e' && c != 'f' && c != 'k' && c != 'l' && c != 'm' && c != 'o' && c != 'r' && c != 'x') | ||||||
|  | 				{ | ||||||
|  | 					builder.append(l).append(c); | ||||||
|  | 				} | ||||||
|  | 				else | ||||||
|  | 				{ | ||||||
|  | 					builder.append('§').append(c); | ||||||
|  | 				} | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (l != closure.head || i + 1 >= chars.length) | ||||||
|  | 			{ | ||||||
|  | 				builder.append(l); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			boolean identified = false; | ||||||
|  | 			boolean oopsitsbad = false; | ||||||
|  |  | ||||||
|  | 			while (++i < chars.length) | ||||||
|  | 			{ | ||||||
|  | 				final char p = chars[i]; | ||||||
|  |  | ||||||
|  | 				if (p == closure.tail) | ||||||
|  | 				{ | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if (p == ' ') | ||||||
|  | 				{ | ||||||
|  | 					oopsitsbad = true; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if (p == '_' && !identified) | ||||||
|  | 				{ | ||||||
|  | 					identified = true; | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if (identified) | ||||||
|  | 				{ | ||||||
|  | 					parameters.append(p); | ||||||
|  | 				} | ||||||
|  | 				else | ||||||
|  | 				{ | ||||||
|  | 					identifier.append(p); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			final String identifierString = identifier.toString(); | ||||||
|  | 			final String parametersString = parameters.toString(); | ||||||
|  |  | ||||||
|  | 			identifier.setLength(0); | ||||||
|  | 			parameters.setLength(0); | ||||||
|  |  | ||||||
|  | 			if (oopsitsbad) | ||||||
|  | 			{ | ||||||
|  | 				builder.append(closure.head).append(identifierString); | ||||||
|  |  | ||||||
|  | 				if (identified) | ||||||
|  | 				{ | ||||||
|  | 					builder.append('_').append(parametersString); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				builder.append(' '); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			final PlaceholderHook placeholder = lookup.apply(identifierString); | ||||||
|  | 			if (placeholder == null) | ||||||
|  | 			{ | ||||||
|  | 				builder.append(closure.head).append(identifierString).append('_').append(parametersString).append(closure.tail); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			final String replacement = placeholder.onRequest(player, parametersString); | ||||||
|  | 			if (replacement == null) | ||||||
|  | 			{ | ||||||
|  | 				builder.append(closure.head).append(identifierString).append('_').append(parametersString).append(closure.tail); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			builder.append(replacement); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return builder.toString(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,55 @@ | |||||||
|  | package me.clip.placeholderapi.replacer; | ||||||
|  |  | ||||||
|  | import me.clip.placeholderapi.PlaceholderHook; | ||||||
|  | import org.bukkit.ChatColor; | ||||||
|  | import org.bukkit.OfflinePlayer; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
|  | import java.util.function.Function; | ||||||
|  | import java.util.regex.Matcher; | ||||||
|  | import java.util.regex.Pattern; | ||||||
|  |  | ||||||
|  | public final class RegexReplacer implements Replacer | ||||||
|  | { | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private final Pattern pattern; | ||||||
|  |  | ||||||
|  | 	public RegexReplacer(@NotNull final Closure closure) | ||||||
|  | 	{ | ||||||
|  | 		this.pattern = Pattern.compile(String.format("\\%s((?<identifier>[a-zA-Z0-9]+)_)(?<parameters>[^%s%s]+)\\%s", closure.head, closure.head, closure.tail, closure.tail)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	@Override | ||||||
|  | 	public @NotNull String apply(@NotNull final String text, @Nullable final OfflinePlayer player, @NotNull final Function<String, @Nullable PlaceholderHook> lookup) | ||||||
|  | 	{ | ||||||
|  | 		final Matcher matcher = pattern.matcher(text); | ||||||
|  | 		if (!matcher.find()) | ||||||
|  | 		{ | ||||||
|  | 			return text; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		final StringBuffer builder = new StringBuffer(); | ||||||
|  |  | ||||||
|  | 		do | ||||||
|  | 		{ | ||||||
|  | 			final String identifier = matcher.group("identifier"); | ||||||
|  | 			final String parameters = matcher.group("parameters"); | ||||||
|  |  | ||||||
|  | 			final PlaceholderHook hook = lookup.apply(identifier); | ||||||
|  | 			if (hook == null) | ||||||
|  | 			{ | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			final String requested = hook.onRequest(player, parameters); | ||||||
|  | 			matcher.appendReplacement(builder, requested != null ? requested : matcher.group(0)); | ||||||
|  | 		} | ||||||
|  | 		while (matcher.find()); | ||||||
|  |  | ||||||
|  | 		return ChatColor.translateAlternateColorCodes('&', matcher.appendTail(builder).toString()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								src/main/java/me/clip/placeholderapi/replacer/Replacer.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/main/java/me/clip/placeholderapi/replacer/Replacer.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | package me.clip.placeholderapi.replacer; | ||||||
|  |  | ||||||
|  | import me.clip.placeholderapi.PlaceholderHook; | ||||||
|  | import org.bukkit.OfflinePlayer; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
|  | import java.util.function.Function; | ||||||
|  |  | ||||||
|  | public interface Replacer | ||||||
|  | { | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	String apply(@NotNull final String text, @Nullable final OfflinePlayer player, @NotNull final Function<String, @Nullable PlaceholderHook> lookup); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	enum Closure | ||||||
|  | 	{ | ||||||
|  | 		BRACKET('{', '}'), | ||||||
|  | 		PERCENT('%', '%'); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		public final char head, tail; | ||||||
|  |  | ||||||
|  | 		Closure(final char head, final char tail) | ||||||
|  | 		{ | ||||||
|  | 			this.head = head; | ||||||
|  | 			this.tail = tail; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -20,89 +20,85 @@ | |||||||
|  */ |  */ | ||||||
| package me.clip.placeholderapi.util; | package me.clip.placeholderapi.util; | ||||||
|  |  | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.io.FilenameFilter; | import java.io.FilenameFilter; | ||||||
|  | import java.io.IOException; | ||||||
| import java.net.URL; | import java.net.URL; | ||||||
| import java.net.URLClassLoader; | import java.net.URLClassLoader; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
|  | import java.util.Collections; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.jar.JarEntry; | import java.util.jar.JarEntry; | ||||||
| import java.util.jar.JarInputStream; | import java.util.jar.JarInputStream; | ||||||
|  |  | ||||||
| public class FileUtil { | public class FileUtil | ||||||
|  | { | ||||||
|  |  | ||||||
|     public static List<Class<?>> getClasses(String folder, Class<?> type) { | 	@NotNull | ||||||
|         return getClasses(folder, null, type); | 	public static <T> List<@NotNull Class<? extends T>> getClasses(@NotNull final File folder, @NotNull final Class<T> clazz) | ||||||
|  | 	{ | ||||||
|  | 		return getClasses(folder, clazz, null); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     public static List<Class<?>> getClasses(String folder, String fileName, Class<?> type) { | 	@NotNull | ||||||
|         List<Class<?>> list = new ArrayList<>(); | 	public static <T> List<@NotNull Class<? extends T>> getClasses(@NotNull final File folder, @NotNull final Class<T> clazz, @Nullable final String target) | ||||||
|  | 	{ | ||||||
|         try { | 		if (!folder.exists()) | ||||||
|             File f = new File(PlaceholderAPIPlugin.getInstance().getDataFolder(), folder); | 		{ | ||||||
|             if (!f.exists()) { | 			return Collections.emptyList(); | ||||||
|                 return list; |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|             FilenameFilter fileNameFilter = (dir, name) -> { | 		try | ||||||
|                 if (fileName != null) { | 		{ | ||||||
|                     return name.endsWith(".jar") && name.replace(".jar", "") | 			final FilenameFilter filter = | ||||||
|                             .equalsIgnoreCase(fileName.replace(".jar", "")); | 					(dir, name) -> name.endsWith(".jar") && (target == null || name.replace(".jar", "").equalsIgnoreCase(target.replace(".jar", ""))); | ||||||
|  |  | ||||||
|  | 			final File[] jars = folder.listFiles(filter); | ||||||
|  | 			if (jars == null) | ||||||
|  | 			{ | ||||||
|  | 				return Collections.emptyList(); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|                 return name.endsWith(".jar"); | 			final List<@NotNull Class<? extends T>> list = new ArrayList<>(); | ||||||
|             }; |  | ||||||
|  |  | ||||||
|             File[] jars = f.listFiles(fileNameFilter); | 			for (File file : jars) | ||||||
|             if (jars == null) { | 			{ | ||||||
|                 return list; | 				gather(file.toURI().toURL(), clazz, list); | ||||||
|             } |  | ||||||
|  |  | ||||||
|             for (File file : jars) { |  | ||||||
|                 list = gather(file.toURI().toURL(), list, type); |  | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			return list; | 			return list; | ||||||
|         } catch (Throwable t) { | 		} | ||||||
|  | 		catch (Throwable t) | ||||||
|  | 		{ | ||||||
|  | 			// THIS SHOULD NOT BE EATEN LIKE THIS. | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|         return null; | 		return Collections.emptyList(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     private static List<Class<?>> gather(URL jar, List<Class<?>> list, Class<?> clazz) { | 	private static <T> void gather(@NotNull final URL jar, @NotNull final Class<T> clazz, @NotNull final List<@NotNull Class<? extends T>> list) throws IOException, ClassNotFoundException | ||||||
|         if (list == null) { | 	{ | ||||||
|             list = new ArrayList<>(); | 		try (final URLClassLoader loader = new URLClassLoader(new URL[]{jar}, clazz.getClassLoader()); final JarInputStream stream = new JarInputStream(jar.openStream())) | ||||||
|         } | 		{ | ||||||
|  | 			JarEntry entry; | ||||||
|         try (URLClassLoader cl = new URLClassLoader(new URL[]{jar}, clazz.getClassLoader()); | 			while ((entry = stream.getNextJarEntry()) != null) | ||||||
|              JarInputStream jis = new JarInputStream(jar.openStream())) { | 			{ | ||||||
|  | 				final String name = entry.getName(); | ||||||
|             while (true) { | 				if (name == null || name.isEmpty() || !name.endsWith(".class")) | ||||||
|                 JarEntry j = jis.getNextJarEntry(); | 				{ | ||||||
|                 if (j == null) { |  | ||||||
|                     break; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 String name = j.getName(); |  | ||||||
|                 if (name == null || name.isEmpty()) { |  | ||||||
| 					continue; | 					continue; | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
|                 if (name.endsWith(".class")) { | 				final Class<?> loaded = loader.loadClass(name.substring(0, name.lastIndexOf('.')).replace('/', '.')); | ||||||
|                     name = name.replace("/", "."); | 				if (clazz.isAssignableFrom(loaded)) | ||||||
|                     String cname = name.substring(0, name.lastIndexOf(".class")); | 				{ | ||||||
|  | 					list.add(loaded.asSubclass(clazz)); | ||||||
|                     Class<?> c = cl.loadClass(cname); |  | ||||||
|                     if (clazz.isAssignableFrom(c)) { |  | ||||||
|                         list.add(c); |  | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|         } catch (Throwable t) { |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|         return list; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -23,21 +23,37 @@ package me.clip.placeholderapi.util; | |||||||
| import org.bukkit.Bukkit; | import org.bukkit.Bukkit; | ||||||
| import org.bukkit.ChatColor; | import org.bukkit.ChatColor; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  |  | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| import java.util.Objects; |  | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
|  |  | ||||||
| public final class Msg { | public final class Msg | ||||||
|     public static void msg(CommandSender s, String... msg) { | { | ||||||
|         s.sendMessage(Arrays.stream(msg).filter(Objects::nonNull).map(Msg::color).collect(Collectors.joining("\n"))); |  | ||||||
|  | 	public static void msg(@NotNull final CommandSender sender, @NotNull final String... messages) | ||||||
|  | 	{ | ||||||
|  | 		if (messages.length == 0) | ||||||
|  | 		{ | ||||||
|  | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|     public static void broadcast(String... msg) { | 		sender.sendMessage(Arrays.stream(messages).map(Msg::color).collect(Collectors.joining("\n"))); | ||||||
|         Arrays.stream(msg).filter(Objects::nonNull).map(Msg::color).forEach(Bukkit::broadcastMessage); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     public static String color(String text) { | 	public static void broadcast(@NotNull final String... messages) | ||||||
|  | 	{ | ||||||
|  | 		if (messages.length == 0) | ||||||
|  | 		{ | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		Bukkit.broadcastMessage(Arrays.stream(messages).map(Msg::color).collect(Collectors.joining("\n"))); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static String color(@NotNull final String text) | ||||||
|  | 	{ | ||||||
| 		return ChatColor.translateAlternateColorCodes('&', text); | 		return ChatColor.translateAlternateColorCodes('&', text); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										187
									
								
								src/test/java/me/clip/placeholderapi/Values.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								src/test/java/me/clip/placeholderapi/Values.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,187 @@ | |||||||
|  | package me.clip.placeholderapi; | ||||||
|  |  | ||||||
|  | import com.google.common.collect.ImmutableMap; | ||||||
|  | import com.google.common.collect.ImmutableSet; | ||||||
|  | import me.clip.placeholderapi.replacer.CharsReplacer; | ||||||
|  | import me.clip.placeholderapi.replacer.RegexReplacer; | ||||||
|  | import me.clip.placeholderapi.replacer.Replacer; | ||||||
|  | import org.bukkit.ChatColor; | ||||||
|  | import org.bukkit.OfflinePlayer; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
|  | import java.util.Set; | ||||||
|  | import java.util.function.Function; | ||||||
|  |  | ||||||
|  | public interface Values | ||||||
|  | { | ||||||
|  |  | ||||||
|  | 	String SMALL_TEXT = "My name is %player_name%"; | ||||||
|  | 	String LARGE_TEXT = "My name is %player_name% and my location is (%player_x%, %player_y%, %player_z%), this placeholder is invalid %server_name%"; | ||||||
|  |  | ||||||
|  | 	ImmutableMap<String, PlaceholderHook> PLACEHOLDERS = ImmutableMap.<String, PlaceholderHook>builder() | ||||||
|  | 			.put("player", new MockPlayerPlaceholderHook()) | ||||||
|  | 			.build(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	Replacer CHARS_REPLACER = new CharsReplacer(Replacer.Closure.PERCENT); | ||||||
|  | 	Replacer REGEX_REPLACER = new RegexReplacer(Replacer.Closure.PERCENT); | ||||||
|  | 	Replacer TESTS_REPLACER = new Replacer() | ||||||
|  | 	{ | ||||||
|  | 		private final Set<Character> COLOR_CODES = ImmutableSet.of('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', | ||||||
|  | 																		  'a', 'b', 'c', 'd', 'e', 'f', 'k', 'l', 'm', 'o', 'r', 'x'); | ||||||
|  |  | ||||||
|  | 		private final boolean colorize = true; | ||||||
|  | 		private final Replacer.Closure closure = Replacer.Closure.PERCENT; | ||||||
|  |  | ||||||
|  | 		@Override | ||||||
|  | 		public @NotNull String apply(final @NotNull String text, final @Nullable OfflinePlayer player, final @NotNull Function<String, @Nullable PlaceholderHook> lookup) | ||||||
|  | 		{ | ||||||
|  | 			char[]        chars   = text.toCharArray(); | ||||||
|  | 			StringBuilder builder = new StringBuilder(chars.length); | ||||||
|  |  | ||||||
|  | 			// This won't cause memory leaks. It's inside a method. And we want to use setLength instead of | ||||||
|  | 			// creating a new string builder to use the maximum capacity and avoid initializing new objects. | ||||||
|  | 			StringBuilder   identifier = new StringBuilder(50); | ||||||
|  | 			PlaceholderHook handler    = null; | ||||||
|  |  | ||||||
|  | 			// Stages: | ||||||
|  | 			//   Stage -1: Look for the color code in the next character. | ||||||
|  | 			//   Stage 0: No closures detected, or the detected identifier is invalid. We're going forward while appending the characters normally. | ||||||
|  | 			//   Stage 1: The closure has been detected, looking for the placeholder identifier... | ||||||
|  | 			//   Stage 2: Detected the identifier and the parameter. Translating the placeholder... | ||||||
|  | 			int stage = 0; | ||||||
|  |  | ||||||
|  | 			for (char ch : chars) | ||||||
|  | 			{ | ||||||
|  | 				if (stage == -1 && COLOR_CODES.contains(ch)) | ||||||
|  | 				{ | ||||||
|  | 					builder.append(ChatColor.COLOR_CHAR).append(ch); | ||||||
|  | 					stage = 0; | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				// Check if the placeholder starts or ends. | ||||||
|  | 				if (ch == closure.head || ch == closure.tail) | ||||||
|  | 				{ | ||||||
|  | 					// If the placeholder ends. | ||||||
|  | 					if (stage == 2) | ||||||
|  | 					{ | ||||||
|  | 						String parameter  = identifier.toString(); | ||||||
|  | 						String translated = handler.onRequest(player, parameter); | ||||||
|  |  | ||||||
|  | 						if (translated == null) | ||||||
|  | 						{ | ||||||
|  | 							String name = ""; | ||||||
|  | 							builder.append(closure.head).append(name).append('_').append(parameter).append(closure.tail); | ||||||
|  | 						} | ||||||
|  | 						else | ||||||
|  | 						{ | ||||||
|  | 							builder.append(translated); | ||||||
|  | 						} | ||||||
|  |  | ||||||
|  | 						identifier.setLength(0); | ||||||
|  | 						stage = 0; | ||||||
|  | 						continue; | ||||||
|  | 					} | ||||||
|  | 					else if (stage == 1) | ||||||
|  | 					{ // If it just started | Double closures | If it's still hasn't detected the indentifier, reset. | ||||||
|  | 						builder.append(closure.head).append(identifier); | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					identifier.setLength(0); | ||||||
|  | 					stage = 1; | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				// Placeholder identifier started. | ||||||
|  | 				if (stage == 1) | ||||||
|  | 				{ | ||||||
|  | 					// Compare the current character with the idenfitier's. | ||||||
|  | 					// We reached the end of our identifier. | ||||||
|  | 					if (ch == '_') | ||||||
|  | 					{ | ||||||
|  | 						handler = lookup.apply(identifier.toString()); | ||||||
|  | 						if (handler == null) | ||||||
|  | 						{ | ||||||
|  | 							builder.append(closure.head).append(identifier).append('_'); | ||||||
|  | 							stage = 0; | ||||||
|  | 						} | ||||||
|  | 						else | ||||||
|  | 						{ | ||||||
|  | 							identifier.setLength(0); | ||||||
|  | 							stage = 2; | ||||||
|  | 						} | ||||||
|  | 						continue; | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					// Keep building the identifier name. | ||||||
|  | 					identifier.append(ch); | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				// Building the placeholder parameter. | ||||||
|  | 				if (stage == 2) | ||||||
|  | 				{ | ||||||
|  | 					identifier.append(ch); | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				// Nothing placeholder related was found. | ||||||
|  | 				if (colorize && ch == '&') | ||||||
|  | 				{ | ||||||
|  | 					stage = -1; | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 				builder.append(ch); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (identifier != null) | ||||||
|  | 			{ | ||||||
|  | 				if (stage > 0) | ||||||
|  | 				{ | ||||||
|  | 					builder.append(closure.tail); | ||||||
|  | 				} | ||||||
|  | 				builder.append(identifier); | ||||||
|  | 			} | ||||||
|  | 			return builder.toString(); | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	final class MockPlayerPlaceholderHook extends PlaceholderHook | ||||||
|  | 	{ | ||||||
|  |  | ||||||
|  | 		public static final String PLAYER_X    = String.valueOf(10); | ||||||
|  | 		public static final String PLAYER_Y    = String.valueOf(20); | ||||||
|  | 		public static final String PLAYER_Z    = String.valueOf(30); | ||||||
|  | 		public static final String PLAYER_NAME = "Sxtanna"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		@Override | ||||||
|  | 		public String onRequest(final OfflinePlayer player, final String params) | ||||||
|  | 		{ | ||||||
|  | 			final String[] parts = params.split("_"); | ||||||
|  | 			if (parts.length == 0) | ||||||
|  | 			{ | ||||||
|  | 				return null; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			switch (parts[0]) | ||||||
|  | 			{ | ||||||
|  | 				case "name": | ||||||
|  | 					return PLAYER_NAME; | ||||||
|  | 				case "x": | ||||||
|  | 					return PLAYER_X; | ||||||
|  | 				case "y": | ||||||
|  | 					return PLAYER_Y; | ||||||
|  | 				case "z": | ||||||
|  | 					return PLAYER_Z; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,45 @@ | |||||||
|  | package me.clip.placeholderapi.replacer; | ||||||
|  |  | ||||||
|  | import me.clip.placeholderapi.Values; | ||||||
|  | import org.openjdk.jmh.annotations.Benchmark; | ||||||
|  |  | ||||||
|  | public class ReplacerBenchmarks | ||||||
|  | { | ||||||
|  |  | ||||||
|  | 	@Benchmark | ||||||
|  | 	public void measureCharsReplacerSmallText() | ||||||
|  | 	{ | ||||||
|  | 		Values.CHARS_REPLACER.apply(Values.SMALL_TEXT, null, Values.PLACEHOLDERS::get); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Benchmark | ||||||
|  | 	public void measureRegexReplacerSmallText() | ||||||
|  | 	{ | ||||||
|  | 		Values.REGEX_REPLACER.apply(Values.SMALL_TEXT, null, Values.PLACEHOLDERS::get); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Benchmark | ||||||
|  | 	public void measureCharsReplacerLargeText() | ||||||
|  | 	{ | ||||||
|  | 		Values.CHARS_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Benchmark | ||||||
|  | 	public void measureRegexReplacerLargeText() | ||||||
|  | 	{ | ||||||
|  | 		Values.REGEX_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Benchmark | ||||||
|  | 	public void measureTestsReplacerSmallText() | ||||||
|  | 	{ | ||||||
|  | 		Values.TESTS_REPLACER.apply(Values.SMALL_TEXT, null, Values.PLACEHOLDERS::get); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Benchmark | ||||||
|  | 	public void measureTestsReplacerLargeText() | ||||||
|  | 	{ | ||||||
|  | 		Values.TESTS_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,67 @@ | |||||||
|  | package me.clip.placeholderapi.replacer; | ||||||
|  |  | ||||||
|  | import me.clip.placeholderapi.Values; | ||||||
|  | import org.junit.jupiter.api.Test; | ||||||
|  |  | ||||||
|  | import static me.clip.placeholderapi.Values.MockPlayerPlaceholderHook.PLAYER_NAME; | ||||||
|  | import static me.clip.placeholderapi.Values.MockPlayerPlaceholderHook.PLAYER_X; | ||||||
|  | import static me.clip.placeholderapi.Values.MockPlayerPlaceholderHook.PLAYER_Y; | ||||||
|  | import static me.clip.placeholderapi.Values.MockPlayerPlaceholderHook.PLAYER_Z; | ||||||
|  | import static org.junit.jupiter.api.Assertions.assertEquals; | ||||||
|  |  | ||||||
|  | public final class ReplacerUnitTester | ||||||
|  | { | ||||||
|  |  | ||||||
|  | 	@Test | ||||||
|  | 	void testCharsReplacerProducesExpectedSingleValue() | ||||||
|  | 	{ | ||||||
|  | 		assertEquals(PLAYER_NAME, Values.CHARS_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Test | ||||||
|  | 	void testRegexReplacerProducesExpectedSingleValue() | ||||||
|  | 	{ | ||||||
|  | 		assertEquals(PLAYER_NAME, Values.REGEX_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Test | ||||||
|  | 	void testCharsReplacerProducesExpectedSentence() | ||||||
|  | 	{ | ||||||
|  | 		assertEquals(String.format("My name is %s and my location is (%s, %s, %s), this placeholder is invalid %%server_name%%", PLAYER_NAME, PLAYER_X, PLAYER_Y, PLAYER_Z), Values.CHARS_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Test | ||||||
|  | 	void testRegexReplacerProducesExpectedSentence() | ||||||
|  | 	{ | ||||||
|  | 		assertEquals(String.format("My name is %s and my location is (%s, %s, %s), this placeholder is invalid %%server_name%%", PLAYER_NAME, PLAYER_X, PLAYER_Y, PLAYER_Z), Values.REGEX_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Test | ||||||
|  | 	void testResultsAreTheSameAsReplacement() | ||||||
|  | 	{ | ||||||
|  | 		final String resultChars = Values.CHARS_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get); | ||||||
|  | 		final String resultRegex = Values.REGEX_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get); | ||||||
|  |  | ||||||
|  | 		assertEquals(resultChars, resultRegex); | ||||||
|  |  | ||||||
|  | 		assertEquals(PLAYER_NAME, resultChars); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Test | ||||||
|  | 	void testResultsAreTheSameNoReplacement() | ||||||
|  | 	{ | ||||||
|  | 		final String resultChars = Values.CHARS_REPLACER.apply("%player_location%", null, Values.PLACEHOLDERS::get); | ||||||
|  | 		final String resultRegex = Values.REGEX_REPLACER.apply("%player_location%", null, Values.PLACEHOLDERS::get); | ||||||
|  |  | ||||||
|  | 		assertEquals(resultChars, resultRegex); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Test | ||||||
|  | 	void testCharsReplacerIgnoresMalformed() | ||||||
|  | 	{ | ||||||
|  | 		final String text = "10% and %hello world 15%"; | ||||||
|  |  | ||||||
|  | 		assertEquals(text, Values.CHARS_REPLACER.apply(text, null, Values.PLACEHOLDERS::get)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user