mirror of
				https://github.com/PlaceholderAPI/PlaceholderAPI
				synced 2025-10-31 18:22:27 +01:00 
			
		
		
		
	updated managers to make more sense, removed old
This commit is contained in:
		| @@ -20,25 +20,18 @@ | |||||||
|  */ |  */ | ||||||
| package me.clip.placeholderapi; | package me.clip.placeholderapi; | ||||||
|  |  | ||||||
| import com.google.common.collect.ImmutableMap; |  | ||||||
| import com.google.common.collect.ImmutableSet; | import com.google.common.collect.ImmutableSet; | ||||||
| import me.clip.placeholderapi.events.ExpansionRegisterEvent; |  | ||||||
| import me.clip.placeholderapi.events.ExpansionUnregisterEvent; |  | ||||||
| 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.CharsReplacer; | ||||||
| import me.clip.placeholderapi.replacer.Replacer; | import me.clip.placeholderapi.replacer.Replacer; | ||||||
| import me.clip.placeholderapi.replacer.Replacer.Closure; | import me.clip.placeholderapi.replacer.Replacer.Closure; | ||||||
| import me.clip.placeholderapi.util.Msg; | import me.clip.placeholderapi.util.Msg; | ||||||
| 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.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
|  |  | ||||||
| import java.util.HashMap; |  | ||||||
| import java.util.HashSet; | import java.util.HashSet; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| @@ -53,8 +46,6 @@ public final class PlaceholderAPI | |||||||
| 	private static final Replacer REPLACER_PERCENT = new CharsReplacer(Closure.PERCENT); | 	private static final Replacer REPLACER_PERCENT = new CharsReplacer(Closure.PERCENT); | ||||||
| 	private static final Replacer REPLACER_BRACKET = new CharsReplacer(Closure.BRACKET); | 	private static final Replacer REPLACER_BRACKET = new CharsReplacer(Closure.BRACKET); | ||||||
|  |  | ||||||
| 	private static final Map<String, PlaceholderHook> PLACEHOLDERS = new HashMap<>(); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@Deprecated | 	@Deprecated | ||||||
| 	private static final Pattern PLACEHOLDER_PATTERN            = Pattern.compile("[%]([^%]+)[%]"); | 	private static final Pattern PLACEHOLDER_PATTERN            = Pattern.compile("[%]([^%]+)[%]"); | ||||||
| @@ -82,7 +73,7 @@ public final class PlaceholderAPI | |||||||
| 	@NotNull | 	@NotNull | ||||||
| 	public static String setPlaceholders(@Nullable final OfflinePlayer player, @NotNull final String text) | 	public static String setPlaceholders(@Nullable final OfflinePlayer player, @NotNull final String text) | ||||||
| 	{ | 	{ | ||||||
| 		return REPLACER_PERCENT.apply(text, player, PLACEHOLDERS::get); | 		return REPLACER_PERCENT.apply(text, player, PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -105,13 +96,12 @@ public final class PlaceholderAPI | |||||||
| 	 * | 	 * | ||||||
| 	 * @param player Player to parse the placeholders against | 	 * @param player Player to parse the placeholders against | ||||||
| 	 * @param text   Text to set the placeholder values in | 	 * @param text   Text to set the placeholder values in | ||||||
| 	 * |  | ||||||
| 	 * @return String containing all translated placeholders | 	 * @return String containing all translated placeholders | ||||||
| 	 */ | 	 */ | ||||||
| 	@NotNull | 	@NotNull | ||||||
| 	public static String setBracketPlaceholders(@Nullable final OfflinePlayer player, @NotNull final String text) | 	public static String setBracketPlaceholders(@Nullable final OfflinePlayer player, @NotNull final String text) | ||||||
| 	{ | 	{ | ||||||
| 		return REPLACER_BRACKET.apply(text, player, PLACEHOLDERS::get); | 		return REPLACER_BRACKET.apply(text, player, PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -120,7 +110,6 @@ public final class PlaceholderAPI | |||||||
| 	 * | 	 * | ||||||
| 	 * @param player Player to parse the placeholders against | 	 * @param player Player to parse the placeholders against | ||||||
| 	 * @param text   List of Strings to set the placeholder values in | 	 * @param text   List of Strings to set the placeholder values in | ||||||
| 	 * |  | ||||||
| 	 * @return String containing all translated placeholders | 	 * @return String containing all translated placeholders | ||||||
| 	 */ | 	 */ | ||||||
| 	@NotNull | 	@NotNull | ||||||
| @@ -138,43 +127,7 @@ public final class PlaceholderAPI | |||||||
| 	 */ | 	 */ | ||||||
| 	public static boolean isRegistered(@NotNull final String identifier) | 	public static boolean isRegistered(@NotNull final String identifier) | ||||||
| 	{ | 	{ | ||||||
| 		return PLACEHOLDERS.containsKey(identifier.toLowerCase()); | 		return PlaceholderAPIPlugin.getInstance().getLocalExpansionManager().findExpansionByIdentifier(identifier).isPresent(); | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Register a new placeholder hook |  | ||||||
| 	 * |  | ||||||
| 	 * @param identifier      Identifier of the placeholder -> "%(identifier)_(args...)% |  | ||||||
| 	 * @param placeholderHook Implementing class that contains the onPlaceholderRequest method which |  | ||||||
| 	 *                        is called when a value is needed for the specific placeholder |  | ||||||
| 	 * @return true if the hook was successfully registered, false if there is already a hook |  | ||||||
| 	 * registered for the specified identifier |  | ||||||
| 	 */ |  | ||||||
| 	public static boolean registerPlaceholderHook(@NotNull final String identifier, @NotNull final PlaceholderHook placeholderHook) |  | ||||||
| 	{ |  | ||||||
| 		return PLACEHOLDERS.putIfAbsent(identifier.toLowerCase(), placeholderHook) == null; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public static boolean registerPlaceholderHook(@NotNull final Plugin plugin, @NotNull final PlaceholderHook placeholderHook) |  | ||||||
| 	{ |  | ||||||
| 		return registerPlaceholderHook(plugin.getName(), placeholderHook); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Unregister a placeholder hook by identifier |  | ||||||
| 	 * |  | ||||||
| 	 * @param identifier The identifier for the placeholder hook to unregister |  | ||||||
| 	 * @return true if the placeholder hook was successfully unregistered, false if there was no |  | ||||||
| 	 * placeholder hook registered for the identifier specified |  | ||||||
| 	 */ |  | ||||||
| 	public static boolean unregisterPlaceholderHook(@NotNull final String identifier) |  | ||||||
| 	{ |  | ||||||
| 		return PLACEHOLDERS.remove(identifier.toLowerCase()) != null; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public static boolean unregisterPlaceholderHook(@NotNull final Plugin plugin) |  | ||||||
| 	{ |  | ||||||
| 		return unregisterPlaceholderHook(plugin.getName()); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -186,7 +139,7 @@ public final class PlaceholderAPI | |||||||
| 	@NotNull | 	@NotNull | ||||||
| 	public static Set<String> getRegisteredIdentifiers() | 	public static Set<String> getRegisteredIdentifiers() | ||||||
| 	{ | 	{ | ||||||
| 		return ImmutableSet.copyOf(PLACEHOLDERS.keySet()); | 		return ImmutableSet.copyOf(PlaceholderAPIPlugin.getInstance().getLocalExpansionManager().getIdentifiers()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -195,69 +148,11 @@ public final class PlaceholderAPI | |||||||
| 	 * @return Copy of the internal placeholder map | 	 * @return Copy of the internal placeholder map | ||||||
| 	 */ | 	 */ | ||||||
| 	@NotNull | 	@NotNull | ||||||
|  | 	@Deprecated | ||||||
| 	public static Map<String, PlaceholderHook> getPlaceholders() | 	public static Map<String, PlaceholderHook> getPlaceholders() | ||||||
| 	{ | 	{ | ||||||
| 		return ImmutableMap.copyOf(PLACEHOLDERS); | 		throw new UnsupportedOperationException("PlaceholderAPI no longer provides a view of the placeholder's map!\n" + | ||||||
| 	} | 												"Use: PlaceholderAPIPlugin.getInstance().getLocalExpansionManager().findExpansionByIdentifier(String)"); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * 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; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -512,7 +407,7 @@ public final class PlaceholderAPI | |||||||
| 			return null; | 			return null; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (PLACEHOLDERS.isEmpty()) | 		if (PlaceholderAPIPlugin.getInstance().getLocalExpansionManager().getExpansionsCount() == 0) | ||||||
| 		{ | 		{ | ||||||
| 			return colorize ? Msg.color(text) : text; | 			return colorize ? Msg.color(text) : text; | ||||||
| 		} | 		} | ||||||
| @@ -608,7 +503,8 @@ public final class PlaceholderAPI | |||||||
| 	 * @deprecated Will be removed in a future release. | 	 * @deprecated Will be removed in a future release. | ||||||
| 	 */ | 	 */ | ||||||
| 	@Deprecated | 	@Deprecated | ||||||
| 	public static String setPlaceholders(Player player, String text) { | 	public static String setPlaceholders(Player player, String text) | ||||||
|  | 	{ | ||||||
| 		return setPlaceholders(((OfflinePlayer) player), text); | 		return setPlaceholders(((OfflinePlayer) player), text); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -22,11 +22,10 @@ package me.clip.placeholderapi; | |||||||
|  |  | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommandRouter; | import me.clip.placeholderapi.commands.PlaceholderCommandRouter; | ||||||
| import me.clip.placeholderapi.configuration.PlaceholderAPIConfig; | import me.clip.placeholderapi.configuration.PlaceholderAPIConfig; | ||||||
| import me.clip.placeholderapi.expansion.ExpansionManager; |  | ||||||
| import me.clip.placeholderapi.expansion.PlaceholderExpansion; | import me.clip.placeholderapi.expansion.PlaceholderExpansion; | ||||||
| import me.clip.placeholderapi.expansion.Version; | import me.clip.placeholderapi.expansion.Version; | ||||||
| import me.clip.placeholderapi.expansion.cloud.ExpansionCloudManager; | import me.clip.placeholderapi.expansion.manager.CloudExpansionManager; | ||||||
| import me.clip.placeholderapi.listeners.PlaceholderListener; | import me.clip.placeholderapi.expansion.manager.LocalExpansionManager; | ||||||
| import me.clip.placeholderapi.listeners.ServerLoadEventListener; | import me.clip.placeholderapi.listeners.ServerLoadEventListener; | ||||||
| import me.clip.placeholderapi.updatechecker.UpdateChecker; | import me.clip.placeholderapi.updatechecker.UpdateChecker; | ||||||
| import me.clip.placeholderapi.util.Msg; | import me.clip.placeholderapi.util.Msg; | ||||||
| @@ -52,18 +51,35 @@ public final class PlaceholderAPIPlugin extends JavaPlugin | |||||||
| { | { | ||||||
|  |  | ||||||
| 	@NotNull | 	@NotNull | ||||||
| 	private static final Version version = resolveServerVersion(); | 	private static final Version VERSION; | ||||||
|  |  | ||||||
|  | 	static | ||||||
|  | 	{ | ||||||
|  | 		final String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; | ||||||
|  |  | ||||||
|  | 		boolean isSpigot; | ||||||
|  | 		try | ||||||
|  | 		{ | ||||||
|  | 			Class.forName("org.spigotmc.SpigotConfig"); | ||||||
|  | 			isSpigot = true; | ||||||
|  | 		} | ||||||
|  | 		catch (final ExceptionInInitializerError | ClassNotFoundException ignored) | ||||||
|  | 		{ | ||||||
|  | 			isSpigot = false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		VERSION = new Version(version, isSpigot); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	private static PlaceholderAPIPlugin instance; | 	private static PlaceholderAPIPlugin instance; | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull | 	@NotNull | ||||||
| 	private final PlaceholderAPIConfig config = new PlaceholderAPIConfig(this); | 	private final PlaceholderAPIConfig config = new PlaceholderAPIConfig(this); | ||||||
|  |  | ||||||
| 	@NotNull | 	@NotNull | ||||||
| 	private final ExpansionCloudManager cloud   = new ExpansionCloudManager(this); | 	private final LocalExpansionManager localExpansionManager = new LocalExpansionManager(this); | ||||||
| 	@NotNull | 	@NotNull | ||||||
| 	private final ExpansionManager      manager = new ExpansionManager(this); | 	private final CloudExpansionManager cloudExpansionManager = new CloudExpansionManager(this); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| @@ -81,11 +97,9 @@ public final class PlaceholderAPIPlugin extends JavaPlugin | |||||||
| 		setupMetrics(); | 		setupMetrics(); | ||||||
| 		setupExpansions(); | 		setupExpansions(); | ||||||
|  |  | ||||||
| 		new PlaceholderListener(this); |  | ||||||
|  |  | ||||||
| 		if (config.isCloudEnabled()) | 		if (config.isCloudEnabled()) | ||||||
| 		{ | 		{ | ||||||
| 			enableCloud(); | 			getCloudExpansionManager().load(); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (config.checkUpdates()) | 		if (config.checkUpdates()) | ||||||
| @@ -97,11 +111,11 @@ public final class PlaceholderAPIPlugin extends JavaPlugin | |||||||
| 	@Override | 	@Override | ||||||
| 	public void onDisable() | 	public void onDisable() | ||||||
| 	{ | 	{ | ||||||
| 		disableCloud(); | 		getCloudExpansionManager().kill(); | ||||||
|  | 		getLocalExpansionManager().kill(); | ||||||
| 		PlaceholderAPI.unregisterAll(); |  | ||||||
|  |  | ||||||
| 		HandlerList.unregisterAll(this); | 		HandlerList.unregisterAll(this); | ||||||
|  |  | ||||||
| 		Bukkit.getScheduler().cancelTasks(this); | 		Bukkit.getScheduler().cancelTasks(this); | ||||||
|  |  | ||||||
| 		instance = null; | 		instance = null; | ||||||
| @@ -110,34 +124,36 @@ public final class PlaceholderAPIPlugin extends JavaPlugin | |||||||
|  |  | ||||||
| 	public void reloadConf(@NotNull final CommandSender sender) | 	public void reloadConf(@NotNull final CommandSender sender) | ||||||
| 	{ | 	{ | ||||||
| 		PlaceholderAPI.unregisterAllProvidedExpansions(); | 		getLocalExpansionManager().kill(); | ||||||
|  |  | ||||||
| 		reloadConfig(); | 		reloadConfig(); | ||||||
|  |  | ||||||
| 		manager.registerAllExpansions(); | 		getLocalExpansionManager().load(); | ||||||
|  |  | ||||||
| 		if (config.isCloudEnabled()) | 		if (config.isCloudEnabled()) | ||||||
| 		{ | 		{ | ||||||
| 			enableCloud(); | 			getCloudExpansionManager().load(); | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| 			disableCloud(); | 			getCloudExpansionManager().kill(); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		Msg.msg(sender, | 		Msg.msg(sender, | ||||||
| 				PlaceholderAPI.getRegisteredIdentifiers().size() + " &aplaceholder hooks successfully registered!"); | 				getLocalExpansionManager().getIdentifiers().size() + " &aplaceholder hooks successfully registered!"); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public void enableCloud() |  | ||||||
|  | 	@NotNull | ||||||
|  | 	public LocalExpansionManager getLocalExpansionManager() | ||||||
| 	{ | 	{ | ||||||
| 		disableCloud(); | 		return localExpansionManager; | ||||||
| 		cloud.fetch(config.cloudAllowUnverifiedExpansions()); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public void disableCloud() | 	@NotNull | ||||||
|  | 	public CloudExpansionManager getCloudExpansionManager() | ||||||
| 	{ | 	{ | ||||||
| 		cloud.clean(); | 		return cloudExpansionManager; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -152,18 +168,6 @@ public final class PlaceholderAPIPlugin extends JavaPlugin | |||||||
| 		return config; | 		return config; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	public ExpansionManager getExpansionManager() |  | ||||||
| 	{ |  | ||||||
| 		return manager; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	public ExpansionCloudManager getExpansionCloud() |  | ||||||
| 	{ |  | ||||||
| 		return cloud; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	private void setupCommand() | 	private void setupCommand() | ||||||
| 	{ | 	{ | ||||||
| @@ -181,12 +185,18 @@ public final class PlaceholderAPIPlugin extends JavaPlugin | |||||||
| 	private void setupMetrics() | 	private void setupMetrics() | ||||||
| 	{ | 	{ | ||||||
| 		final Metrics metrics = new Metrics(this); | 		final Metrics metrics = new Metrics(this); | ||||||
| 		metrics.addCustomChart(new Metrics.SimplePie("using_expansion_cloud", () -> getPlaceholderAPIConfig().isCloudEnabled() ? "yes" : "no")); | 		metrics.addCustomChart( | ||||||
|  | 				new Metrics.SimplePie( | ||||||
|  | 						"using_expansion_cloud", | ||||||
|  | 						() -> getPlaceholderAPIConfig().isCloudEnabled() ? "yes" : "no")); | ||||||
|  |  | ||||||
| 		metrics.addCustomChart(new Metrics.SimplePie("using_spigot", () -> getServerVersion().isSpigot() ? "yes" : "no")); | 		metrics.addCustomChart( | ||||||
|  | 				new Metrics.SimplePie("using_spigot", () -> getServerVersion().isSpigot() ? "yes" : "no")); | ||||||
| 		metrics.addCustomChart(new Metrics.AdvancedPie("expansions_used", () -> { |  | ||||||
|  |  | ||||||
|  | 		metrics.addCustomChart( | ||||||
|  | 				new Metrics.AdvancedPie( | ||||||
|  | 						"expansions_used", | ||||||
|  | 						() -> { | ||||||
| 							Map<String, Integer>         map   = new HashMap<>(); | 							Map<String, Integer>         map   = new HashMap<>(); | ||||||
| 							Map<String, PlaceholderHook> hooks = PlaceholderAPI.getPlaceholders(); | 							Map<String, PlaceholderHook> hooks = PlaceholderAPI.getPlaceholders(); | ||||||
|  |  | ||||||
| @@ -198,7 +208,11 @@ public final class PlaceholderAPIPlugin extends JavaPlugin | |||||||
| 									if (hook instanceof PlaceholderExpansion) | 									if (hook instanceof PlaceholderExpansion) | ||||||
| 									{ | 									{ | ||||||
| 										PlaceholderExpansion expansion = (PlaceholderExpansion) hook; | 										PlaceholderExpansion expansion = (PlaceholderExpansion) hook; | ||||||
| 						map.put(expansion.getRequiredPlugin() == null ? expansion.getIdentifier() : expansion.getRequiredPlugin(), 1); | 										map.put( | ||||||
|  | 												expansion.getRequiredPlugin() == null | ||||||
|  | 												? expansion.getIdentifier() | ||||||
|  | 												: expansion.getRequiredPlugin(), | ||||||
|  | 												1); | ||||||
| 									} | 									} | ||||||
| 								} | 								} | ||||||
| 							} | 							} | ||||||
| @@ -209,14 +223,16 @@ public final class PlaceholderAPIPlugin extends JavaPlugin | |||||||
|  |  | ||||||
| 	private void setupExpansions() | 	private void setupExpansions() | ||||||
| 	{ | 	{ | ||||||
|  | 		Bukkit.getPluginManager().registerEvents(getLocalExpansionManager(), this); | ||||||
|  |  | ||||||
| 		try | 		try | ||||||
| 		{ | 		{ | ||||||
| 			Class.forName("org.bukkit.event.server.ServerLoadEvent"); | 			Class.forName("org.bukkit.event.server.ServerLoadEvent"); | ||||||
| 			new ServerLoadEventListener(this); | 			new ServerLoadEventListener(this); | ||||||
| 		} | 		} | ||||||
| 		catch (final ExceptionInInitializerError | ClassNotFoundException exception) | 		catch (final ExceptionInInitializerError | ClassNotFoundException ignored) | ||||||
| 		{ | 		{ | ||||||
| 			Bukkit.getScheduler().runTaskLater(this, getExpansionManager()::initializeExpansions, 1); | 			Bukkit.getScheduler().runTaskLater(this, getLocalExpansionManager()::load, 1); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -235,28 +251,6 @@ public final class PlaceholderAPIPlugin extends JavaPlugin | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Get the configurable {@linkplain SimpleDateFormat} object that is used to parse time for |  | ||||||
| 	 * generic time based placeholders |  | ||||||
| 	 * |  | ||||||
| 	 * @return date format |  | ||||||
| 	 */ |  | ||||||
| 	@NotNull |  | ||||||
| 	public static SimpleDateFormat getDateFormat() |  | ||||||
| 	{ |  | ||||||
| 		try |  | ||||||
| 		{ |  | ||||||
| 			return new SimpleDateFormat(getInstance().getPlaceholderAPIConfig().dateFormat()); |  | ||||||
| 		} |  | ||||||
| 		catch (final IllegalArgumentException ex) |  | ||||||
| 		{ |  | ||||||
|  |  | ||||||
| 			getInstance().getLogger().log(Level.WARNING, "configured date format is invalid", ex); |  | ||||||
|  |  | ||||||
| 			return new SimpleDateFormat("MM/dd/yy HH:mm:ss"); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Get the configurable {@linkplain String} value that should be returned when a boolean is true | 	 * Get the configurable {@linkplain String} value that should be returned when a boolean is true | ||||||
| 	 * | 	 * | ||||||
| @@ -279,28 +273,30 @@ public final class PlaceholderAPIPlugin extends JavaPlugin | |||||||
| 		return getInstance().getPlaceholderAPIConfig().booleanFalse(); | 		return getInstance().getPlaceholderAPIConfig().booleanFalse(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Get the configurable {@linkplain SimpleDateFormat} object that is used to parse time for | ||||||
|  | 	 * generic time based placeholders | ||||||
|  | 	 * | ||||||
|  | 	 * @return date format | ||||||
|  | 	 */ | ||||||
|  | 	@NotNull | ||||||
|  | 	public static SimpleDateFormat getDateFormat() | ||||||
|  | 	{ | ||||||
|  | 		try | ||||||
|  | 		{ | ||||||
|  | 			return new SimpleDateFormat(getInstance().getPlaceholderAPIConfig().dateFormat()); | ||||||
|  | 		} | ||||||
|  | 		catch (final IllegalArgumentException ex) | ||||||
|  | 		{ | ||||||
|  | 			getInstance().getLogger().log(Level.WARNING, "configured date format is invalid", ex); | ||||||
|  | 			return new SimpleDateFormat("MM/dd/yy HH:mm:ss"); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public static Version getServerVersion() | 	public static Version getServerVersion() | ||||||
| 	{ | 	{ | ||||||
| 		return version; | 		return VERSION; | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	private static Version resolveServerVersion() |  | ||||||
| 	{ |  | ||||||
| 		final String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; |  | ||||||
|  |  | ||||||
| 		boolean isSpigot; |  | ||||||
| 		try |  | ||||||
| 		{ |  | ||||||
| 			Class.forName("org.spigotmc.SpigotConfig"); |  | ||||||
| 			isSpigot = true; |  | ||||||
| 		} |  | ||||||
| 		catch (final ExceptionInInitializerError | ClassNotFoundException ignored) |  | ||||||
| 		{ |  | ||||||
| 			isSpigot = false; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return new Version(version, isSpigot); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ public final class CommandECloudClear extends PlaceholderCommand | |||||||
| 	@Override | 	@Override | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) | 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) | ||||||
| 	{ | 	{ | ||||||
| 		plugin.getExpansionCloud().clean(); | 		plugin.getCloudExpansionManager().clean(); | ||||||
| 		Msg.msg(sender, | 		Msg.msg(sender, | ||||||
| 				"&aThe eCloud cache has been cleared!"); | 				"&aThe eCloud cache has been cleared!"); | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -30,7 +30,7 @@ public final class CommandECloudDownload extends PlaceholderCommand | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		final CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(params.get(0)).orElse(null); | 		final CloudExpansion expansion = plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)).orElse(null); | ||||||
| 		if (expansion == null) | 		if (expansion == null) | ||||||
| 		{ | 		{ | ||||||
| 			Msg.msg(sender, | 			Msg.msg(sender, | ||||||
| @@ -61,7 +61,7 @@ public final class CommandECloudDownload extends PlaceholderCommand | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		plugin.getExpansionCloud().downloadExpansion(expansion, version).whenComplete((file, exception) -> { | 		plugin.getCloudExpansionManager().downloadExpansion(expansion, version).whenComplete((file, exception) -> { | ||||||
| 			if (exception != null) | 			if (exception != null) | ||||||
| 			{ | 			{ | ||||||
| 				Msg.msg(sender, | 				Msg.msg(sender, | ||||||
| @@ -72,8 +72,8 @@ public final class CommandECloudDownload extends PlaceholderCommand | |||||||
| 			Msg.msg(sender, | 			Msg.msg(sender, | ||||||
| 					"&aSuccessfully downloaded expansion to file: &e" + file.getName()); | 					"&aSuccessfully downloaded expansion to file: &e" + file.getName()); | ||||||
|  |  | ||||||
| 			plugin.getExpansionCloud().clean(); | 			plugin.getCloudExpansionManager().clean(); | ||||||
| 			plugin.getExpansionCloud().fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); | 			plugin.getCloudExpansionManager().fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -87,12 +87,12 @@ public final class CommandECloudDownload extends PlaceholderCommand | |||||||
|  |  | ||||||
| 		if (params.size() <= 1) | 		if (params.size() <= 1) | ||||||
| 		{ | 		{ | ||||||
| 			final Stream<String> names = plugin.getExpansionCloud().getCloudExpansions().values().stream().map(CloudExpansion::getName).map(name -> name.replace(' ', '_')); | 			final Stream<String> names = plugin.getCloudExpansionManager().getCloudExpansions().values().stream().map(CloudExpansion::getName).map(name -> name.replace(' ', '_')); | ||||||
| 			suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); | 			suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		final Optional<CloudExpansion> expansion = plugin.getExpansionCloud().getCloudExpansion(params.get(0)); | 		final Optional<CloudExpansion> expansion = plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)); | ||||||
| 		if (!expansion.isPresent()) | 		if (!expansion.isPresent()) | ||||||
| 		{ | 		{ | ||||||
| 			return; | 			return; | ||||||
|   | |||||||
| @@ -30,7 +30,7 @@ public final class CommandECloudExpansionInfo extends PlaceholderCommand | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		final CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(params.get(0)).orElse(null); | 		final CloudExpansion expansion = plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)).orElse(null); | ||||||
| 		if (expansion == null) | 		if (expansion == null) | ||||||
| 		{ | 		{ | ||||||
| 			Msg.msg(sender, | 			Msg.msg(sender, | ||||||
| @@ -99,12 +99,12 @@ public final class CommandECloudExpansionInfo extends PlaceholderCommand | |||||||
|  |  | ||||||
| 		if (params.size() <= 1) | 		if (params.size() <= 1) | ||||||
| 		{ | 		{ | ||||||
| 			final Stream<String> names = plugin.getExpansionCloud().getCloudExpansions().values().stream().map(CloudExpansion::getName).map(name -> name.replace(' ', '_')); | 			final Stream<String> names = plugin.getCloudExpansionManager().getCloudExpansions().values().stream().map(CloudExpansion::getName).map(name -> name.replace(' ', '_')); | ||||||
| 			suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); | 			suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		final Optional<CloudExpansion> expansion = plugin.getExpansionCloud().getCloudExpansion(params.get(0)); | 		final Optional<CloudExpansion> expansion = plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)); | ||||||
| 		if (!expansion.isPresent()) | 		if (!expansion.isPresent()) | ||||||
| 		{ | 		{ | ||||||
| 			return; | 			return; | ||||||
|   | |||||||
| @@ -1,19 +1,25 @@ | |||||||
| package me.clip.placeholderapi.commands.impl.cloud; | package me.clip.placeholderapi.commands.impl.cloud; | ||||||
|  |  | ||||||
| import com.google.common.collect.ImmutableSet; | import com.google.common.collect.ImmutableSet; | ||||||
|  | import com.google.common.collect.Lists; | ||||||
| import com.google.common.collect.Sets; | import com.google.common.collect.Sets; | ||||||
| import com.google.common.primitives.Ints; | import com.google.common.primitives.Ints; | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| import me.clip.placeholderapi.expansion.cloud.CloudExpansion; | import me.clip.placeholderapi.expansion.cloud.CloudExpansion; | ||||||
| import me.clip.placeholderapi.util.Msg; | import me.clip.placeholderapi.util.Msg; | ||||||
|  | import me.rayzr522.jsonmessage.JSONMessage; | ||||||
|  | import org.bukkit.ChatColor; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
|  | import org.bukkit.entity.Player; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
|  | import java.text.SimpleDateFormat; | ||||||
|  | import java.util.Collection; | ||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
|  | import java.util.Comparator; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Map; |  | ||||||
| import java.util.Objects; | import java.util.Objects; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
| @@ -22,7 +28,7 @@ import java.util.stream.IntStream; | |||||||
| public final class CommandECloudExpansionList extends PlaceholderCommand | public final class CommandECloudExpansionList extends PlaceholderCommand | ||||||
| { | { | ||||||
|  |  | ||||||
| 	private static final int PAGE_SIZE = 3; | 	private static final int PAGE_SIZE = 10; | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@Unmodifiable | 	@Unmodifiable | ||||||
| @@ -34,6 +40,90 @@ public final class CommandECloudExpansionList extends PlaceholderCommand | |||||||
| 		super("list"); | 		super("list"); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private static List<CloudExpansion> getPage(@NotNull final List<CloudExpansion> expansions, final int page, final int pageSize) | ||||||
|  | 	{ | ||||||
|  | 		if (expansions.isEmpty()) | ||||||
|  | 		{ | ||||||
|  | 			return Collections.emptyList(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		final int head = (page * pageSize); | ||||||
|  | 		final int tail = Math.min(expansions.size(), head + pageSize); | ||||||
|  |  | ||||||
|  | 		if (expansions.size() < head) | ||||||
|  | 		{ | ||||||
|  | 			return Collections.emptyList(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return IntStream.range(head, tail).mapToObj(expansions::get).filter(Objects::nonNull).collect(Collectors.toList()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private static Collection<CloudExpansion> getExpansions(@NotNull final String target, @NotNull final PlaceholderAPIPlugin plugin) | ||||||
|  | 	{ | ||||||
|  | 		switch (target.toLowerCase()) | ||||||
|  | 		{ | ||||||
|  | 			case "all": | ||||||
|  | 				return plugin.getCloudExpansionManager().getCloudExpansions().values(); | ||||||
|  | 			case "installed": | ||||||
|  | 				return plugin.getCloudExpansionManager().getCloudExpansionsInstalled().values(); | ||||||
|  | 			default: | ||||||
|  | 				return plugin.getCloudExpansionManager().getCloudExpansionsByAuthor(target).values(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private static JSONMessage getMessage(@NotNull final List<CloudExpansion> expansions, final int page) | ||||||
|  | 	{ | ||||||
|  | 		final SimpleDateFormat format = PlaceholderAPIPlugin.getDateFormat(); | ||||||
|  |  | ||||||
|  | 		final StringBuilder tooltip = new StringBuilder(); | ||||||
|  | 		final JSONMessage   message = JSONMessage.create(); | ||||||
|  |  | ||||||
|  | 		int index = ((page - 1) * PAGE_SIZE) + 1; | ||||||
|  | 		for (int i = 0; i < expansions.size(); i++) | ||||||
|  | 		{ | ||||||
|  | 			final CloudExpansion expansion = expansions.get(i); | ||||||
|  | 			tooltip.append("&bClick to download this expansion!") | ||||||
|  | 				   .append('\n') | ||||||
|  | 				   .append('\n') | ||||||
|  | 				   .append("&bAuthor: &f") | ||||||
|  | 				   .append(expansion.getAuthor()) | ||||||
|  | 				   .append('\n') | ||||||
|  | 				   .append("&bVerified: ") | ||||||
|  | 				   .append(expansion.isVerified() ? "&a&l✔&r" : "&c&l❌&r") | ||||||
|  | 				   .append('\n') | ||||||
|  | 				   .append("&bLatest Version: &f") | ||||||
|  | 				   .append(expansion.getLatestVersion()) | ||||||
|  | 				   .append('\n') | ||||||
|  | 				   .append("&bReleased: &f") | ||||||
|  | 				   .append(format.format(expansion.getLastUpdate())); | ||||||
|  |  | ||||||
|  | 			final String description = expansion.getDescription(); | ||||||
|  | 			if (description != null && !description.isEmpty()) | ||||||
|  | 			{ | ||||||
|  | 				tooltip.append('\n') | ||||||
|  | 					   .append('\n') | ||||||
|  | 					   .append("&f") | ||||||
|  | 					   .append(description.replace("\r", "").trim()); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			message.then(Msg.color("&8" + (index++) + ".&r " + (expansion.shouldUpdate() ? "&6" : expansion.hasExpansion() ? "&a" : "&7") + expansion.getName())); | ||||||
|  |  | ||||||
|  | 			message.tooltip(Msg.color(tooltip.toString())); | ||||||
|  | 			message.suggestCommand("/papi ecloud download " + expansion.getName()); | ||||||
|  |  | ||||||
|  | 			if (i < expansions.size() - 1) | ||||||
|  | 			{ | ||||||
|  | 				message.newline(); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			tooltip.setLength(0); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return message; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) | 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) | ||||||
| @@ -45,8 +135,7 @@ public final class CommandECloudExpansionList extends PlaceholderCommand | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		final List<CloudExpansion> expansions = Lists.newArrayList(getExpansions(params.get(0), plugin)); | ||||||
| 		@Unmodifiable final Map<Integer, CloudExpansion> expansions = getExpansions(params.get(0), plugin); |  | ||||||
|  |  | ||||||
| 		final int page; | 		final int page; | ||||||
|  |  | ||||||
| @@ -77,6 +166,7 @@ public final class CommandECloudExpansionList extends PlaceholderCommand | |||||||
| 			page = parsed; | 			page = parsed; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		expansions.sort(Comparator.comparing(CloudExpansion::getLastUpdate).reversed()); | ||||||
|  |  | ||||||
| 		final StringBuilder        builder = new StringBuilder(); | 		final StringBuilder        builder = new StringBuilder(); | ||||||
| 		final List<CloudExpansion> values  = getPage(expansions, page - 1, PAGE_SIZE); | 		final List<CloudExpansion> values  = getPage(expansions, page - 1, PAGE_SIZE); | ||||||
| @@ -100,13 +190,47 @@ public final class CommandECloudExpansionList extends PlaceholderCommand | |||||||
| 			   .append(page) | 			   .append(page) | ||||||
| 			   .append('\n'); | 			   .append('\n'); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		if (sender instanceof Player) | ||||||
|  | 		{ | ||||||
|  | 			Msg.msg(sender, builder.toString()); | ||||||
|  |  | ||||||
|  | 			final int limit = (int) Math.ceil((double) expansions.size() / PAGE_SIZE); | ||||||
|  |  | ||||||
|  | 			final JSONMessage message = getMessage(values, page); | ||||||
|  |  | ||||||
|  | 			if (limit > 1) | ||||||
|  | 			{ | ||||||
|  | 				message.newline(); | ||||||
|  |  | ||||||
|  | 				message.then("◀") | ||||||
|  | 					   .color(page <= 1 ? ChatColor.GRAY : ChatColor.DARK_GRAY); | ||||||
|  | 				if (page > 1) | ||||||
|  | 				{ | ||||||
|  | 					message.runCommand("/papi ecloud list " + params.get(0) + " " + (page - 1)); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				message.then(" " + page + " ").color(ChatColor.GREEN); | ||||||
|  |  | ||||||
|  | 				message.then("▶") | ||||||
|  | 					   .color(page >= limit ? ChatColor.GRAY : ChatColor.DARK_GRAY); | ||||||
|  | 				if (page < limit) | ||||||
|  | 				{ | ||||||
|  | 					message.runCommand("/papi ecloud list " + params.get(0) + " " + (page + 1)); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			message.send(((Player) sender)); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
| 			int index = ((page - 1) * PAGE_SIZE) + 1; | 			int index = ((page - 1) * PAGE_SIZE) + 1; | ||||||
| 			for (final CloudExpansion expansion : values) | 			for (final CloudExpansion expansion : values) | ||||||
| 			{ | 			{ | ||||||
| 				builder.append("&8") | 				builder.append("&8") | ||||||
| 					   .append(index++) | 					   .append(index++) | ||||||
| 					   .append(". ") | 					   .append(". ") | ||||||
| 				   .append(expansion.shouldUpdate() ? "&e" : "&a") | 					   .append((expansion.shouldUpdate() ? "&6" : expansion.hasExpansion() ? "&a" : "&7")) | ||||||
| 					   .append(expansion.getName()) | 					   .append(expansion.getName()) | ||||||
| 					   .append('\n') | 					   .append('\n') | ||||||
| 					   .append("    &bAuthor: &f") | 					   .append("    &bAuthor: &f") | ||||||
| @@ -123,6 +247,8 @@ public final class CommandECloudExpansionList extends PlaceholderCommand | |||||||
| 			Msg.msg(sender, builder.toString()); | 			Msg.msg(sender, builder.toString()); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public void complete(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) | 	public void complete(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) | ||||||
| 	{ | 	{ | ||||||
| @@ -133,42 +259,11 @@ public final class CommandECloudExpansionList extends PlaceholderCommand | |||||||
|  |  | ||||||
| 		if (params.size() <= 1) | 		if (params.size() <= 1) | ||||||
| 		{ | 		{ | ||||||
| 			suggestByParameter(Sets.union(OPTIONS, plugin.getExpansionCloud().getCloudAuthorNames()).stream(), suggestions, params.isEmpty() ? null : params.get(0)); | 			suggestByParameter(Sets.union(OPTIONS, plugin.getCloudExpansionManager().getCloudExpansionAuthors()).stream(), suggestions, params.isEmpty() ? null : params.get(0)); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		final Map<Integer, CloudExpansion> expansions = getExpansions(params.get(0), plugin); | 		suggestByParameter(IntStream.rangeClosed(1, (int) Math.ceil((double) getExpansions(params.get(0), plugin).size() / PAGE_SIZE)).mapToObj(Objects::toString), suggestions, params.get(1)); | ||||||
|  |  | ||||||
| 		suggestByParameter(IntStream.rangeClosed(1, (int) Math.ceil((double) expansions.size() / PAGE_SIZE)).mapToObj(Objects::toString), suggestions, params.get(1)); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	private static List<CloudExpansion> getPage(@NotNull final Map<Integer, CloudExpansion> expansions, final int page, final int pageSize) |  | ||||||
| 	{ |  | ||||||
| 		if (expansions.isEmpty()) |  | ||||||
| 		{ |  | ||||||
| 			return Collections.emptyList(); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final int head = (page * pageSize); |  | ||||||
| 		final int tail = (head + pageSize); |  | ||||||
|  |  | ||||||
| 		return IntStream.range(head, tail).mapToObj(expansions::get).filter(Objects::nonNull).collect(Collectors.toList()); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	private static Map<Integer, CloudExpansion> getExpansions(@NotNull final String target, @NotNull final PlaceholderAPIPlugin plugin) |  | ||||||
| 	{ |  | ||||||
| 		switch (target.toLowerCase()) |  | ||||||
| 		{ |  | ||||||
| 			case "all": |  | ||||||
| 				return plugin.getExpansionCloud().getCloudExpansions(); |  | ||||||
| 			case "installed": |  | ||||||
| 				return plugin.getExpansionCloud().getAllInstalled(); |  | ||||||
| 			default: |  | ||||||
| 				return plugin.getExpansionCloud().getAllByAuthor(target); |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -31,7 +31,7 @@ public final class CommandECloudExpansionPlaceholders extends PlaceholderCommand | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		final CloudExpansion expansion = plugin.getExpansionCloud().getCloudExpansion(params.get(0)).orElse(null); | 		final CloudExpansion expansion = plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0)).orElse(null); | ||||||
| 		if (expansion == null) | 		if (expansion == null) | ||||||
| 		{ | 		{ | ||||||
| 			Msg.msg(sender, | 			Msg.msg(sender, | ||||||
| @@ -63,7 +63,13 @@ public final class CommandECloudExpansionPlaceholders extends PlaceholderCommand | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		final Stream<String> names = plugin.getExpansionCloud().getCloudExpansions().values().stream().map(CloudExpansion::getName).map(name -> name.replace(' ', '_')); | 		final Stream<String> names = plugin.getCloudExpansionManager() | ||||||
|  | 										   .getCloudExpansions() | ||||||
|  | 										   .values() | ||||||
|  | 										   .stream() | ||||||
|  | 										   .map(CloudExpansion::getName) | ||||||
|  | 										   .map(name -> name.replace(' ', '_')); | ||||||
|  |  | ||||||
| 		suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); | 		suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0)); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,8 +20,8 @@ public final class CommandECloudRefresh extends PlaceholderCommand | |||||||
| 	@Override | 	@Override | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) | 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) | ||||||
| 	{ | 	{ | ||||||
| 		plugin.getExpansionCloud().clean(); | 		plugin.getCloudExpansionManager().clean(); | ||||||
| 		plugin.getExpansionCloud().fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); | 		plugin.getCloudExpansionManager().fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); | ||||||
|  |  | ||||||
| 		Msg.msg(sender, | 		Msg.msg(sender, | ||||||
| 				"&aThe eCloud Manager has been refreshed!"); | 				"&aThe eCloud Manager has been refreshed!"); | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ package me.clip.placeholderapi.commands.impl.cloud; | |||||||
|  |  | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| import me.clip.placeholderapi.expansion.cloud.ExpansionCloudManager; | import me.clip.placeholderapi.expansion.manager.CloudExpansionManager; | ||||||
| import me.clip.placeholderapi.util.Msg; | import me.clip.placeholderapi.util.Msg; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| @@ -21,10 +21,10 @@ public final class CommandECloudStatus extends PlaceholderCommand | |||||||
| 	@Override | 	@Override | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) | 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) | ||||||
| 	{ | 	{ | ||||||
| 		final ExpansionCloudManager manager = plugin.getExpansionCloud(); | 		final CloudExpansionManager manager = plugin.getCloudExpansionManager(); | ||||||
|  |  | ||||||
| 		final int updateCount    = manager.getCloudUpdateCount(); | 		final int updateCount    = manager.getCloudUpdateCount(); | ||||||
| 		final int authorCount    = manager.getCloudAuthorCount(); | 		final int authorCount    = manager.getCloudExpansionAuthorCount(); | ||||||
| 		final int expansionCount = manager.getCloudExpansions().size(); | 		final int expansionCount = manager.getCloudExpansions().size(); | ||||||
|  |  | ||||||
| 		final StringBuilder builder = new StringBuilder(); | 		final StringBuilder builder = new StringBuilder(); | ||||||
|   | |||||||
| @@ -17,7 +17,6 @@ public final class CommandECloudToggle extends PlaceholderCommand | |||||||
| 		super("toggle", "enable", "disable"); | 		super("toggle", "enable", "disable"); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) | 	public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, @NotNull final CommandSender sender, @NotNull final String alias, @NotNull @Unmodifiable final List<String> params) | ||||||
| 	{ | 	{ | ||||||
| @@ -39,8 +38,7 @@ public final class CommandECloudToggle extends PlaceholderCommand | |||||||
|  |  | ||||||
| 		if (desiredState == currentState) | 		if (desiredState == currentState) | ||||||
| 		{ | 		{ | ||||||
| 			Msg.msg(sender, | 			Msg.msg(sender, "&7The eCloud Manager is already " + (desiredState ? "enabled" : "disabled")); | ||||||
| 					"&7The eCloud Manager is already " + (desiredState ? "enabled" : "disabled")); |  | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -48,15 +46,14 @@ public final class CommandECloudToggle extends PlaceholderCommand | |||||||
|  |  | ||||||
| 		if (desiredState) | 		if (desiredState) | ||||||
| 		{ | 		{ | ||||||
| 			plugin.enableCloud(); | 			plugin.getCloudExpansionManager().load(); | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| 			plugin.disableCloud(); | 			plugin.getCloudExpansionManager().kill(); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		Msg.msg(sender, | 		Msg.msg(sender, "&aThe eCloud Manager has been " + (desiredState ? "enabled" : "disabled")); | ||||||
| 				"&aThe eCloud Manager has been " + (desiredState ? "enabled" : "disabled")); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,13 +3,17 @@ package me.clip.placeholderapi.commands.impl.local; | |||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
| import me.clip.placeholderapi.commands.PlaceholderCommand; | import me.clip.placeholderapi.commands.PlaceholderCommand; | ||||||
| import me.clip.placeholderapi.expansion.PlaceholderExpansion; | import me.clip.placeholderapi.expansion.PlaceholderExpansion; | ||||||
|  | import me.clip.placeholderapi.expansion.manager.LocalExpansionManager; | ||||||
| import me.clip.placeholderapi.util.Msg; | import me.clip.placeholderapi.util.Msg; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| import org.jetbrains.annotations.NotNull; | import org.jetbrains.annotations.NotNull; | ||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
|  | import java.io.File; | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Optional; | ||||||
|  | import java.util.logging.Level; | ||||||
|  |  | ||||||
| public final class CommandExpansionRegister extends PlaceholderCommand | public final class CommandExpansionRegister extends PlaceholderCommand | ||||||
| { | { | ||||||
| @@ -29,8 +33,36 @@ public final class CommandExpansionRegister extends PlaceholderCommand | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		final PlaceholderExpansion expansion = plugin.getExpansionManager().registerExpansion(params.get(0)); |  | ||||||
| 		if (expansion == null) | 		final LocalExpansionManager manager = plugin.getLocalExpansionManager(); | ||||||
|  |  | ||||||
|  | 		final File file = new File(manager.getExpansionsFolder(), params.get(0)); | ||||||
|  | 		if (!file.exists()) | ||||||
|  | 		{ | ||||||
|  | 			Msg.msg(sender, | ||||||
|  | 					"&cThe file &f" + file.getName() + "&c doesn't exist!"); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		manager.findExpansionsInFile(file).whenCompleteAsync((classes, exception) -> { | ||||||
|  | 			if (exception != null) | ||||||
|  | 			{ | ||||||
|  | 				Msg.msg(sender, | ||||||
|  | 						"&cFailed to find expansion in file: &f" + file); | ||||||
|  |  | ||||||
|  | 				plugin.getLogger().log(Level.WARNING, "failed to find expansion in file: " + file, exception); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (classes.isEmpty()) | ||||||
|  | 			{ | ||||||
|  | 				Msg.msg(sender, | ||||||
|  | 						"&cNo expansion class found in file: &f" + file); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			final Optional<PlaceholderExpansion> expansion = manager.register(classes.get(0)); | ||||||
|  | 			if (!expansion.isPresent()) | ||||||
| 			{ | 			{ | ||||||
| 				Msg.msg(sender, | 				Msg.msg(sender, | ||||||
| 						"&cFailed to register expansion from &f" + params.get(0)); | 						"&cFailed to register expansion from &f" + params.get(0)); | ||||||
| @@ -38,7 +70,8 @@ public final class CommandExpansionRegister extends PlaceholderCommand | |||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			Msg.msg(sender, | 			Msg.msg(sender, | ||||||
| 				"&aSuccessfully registered expansion: &f" + expansion.getName()); | 					"&aSuccessfully registered expansion: &f" + expansion.get().getName()); | ||||||
|  | 		}); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| @@ -49,7 +82,7 @@ public final class CommandExpansionRegister extends PlaceholderCommand | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		final String[] fileNames = plugin.getExpansionManager().getFolder().list((dir, name) -> name.endsWith(".jar")); | 		final String[] fileNames = plugin.getLocalExpansionManager().getExpansionsFolder().list((dir, name) -> name.endsWith(".jar")); | ||||||
| 		if (fileNames == null || fileNames.length == 0) | 		if (fileNames == null || fileNames.length == 0) | ||||||
| 		{ | 		{ | ||||||
| 			return; | 			return; | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ import org.jetbrains.annotations.NotNull; | |||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Optional; | ||||||
|  |  | ||||||
| public final class CommandExpansionUnregister extends PlaceholderCommand | public final class CommandExpansionUnregister extends PlaceholderCommand | ||||||
| { | { | ||||||
| @@ -29,8 +30,8 @@ public final class CommandExpansionUnregister extends PlaceholderCommand | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		final PlaceholderExpansion expansion = plugin.getExpansionManager().getRegisteredExpansion(params.get(0)); | 		final Optional<PlaceholderExpansion> expansion = plugin.getLocalExpansionManager().findExpansionByName(params.get(0)); | ||||||
| 		if (expansion == null) | 		if (!expansion.isPresent()) | ||||||
| 		{ | 		{ | ||||||
| 			Msg.msg(sender, | 			Msg.msg(sender, | ||||||
| 					"&cThere is no expansion loaded with the identifier: &f" + params.get(0)); | 					"&cThere is no expansion loaded with the identifier: &f" + params.get(0)); | ||||||
| @@ -38,11 +39,11 @@ public final class CommandExpansionUnregister extends PlaceholderCommand | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  |  | ||||||
| 		final String message = !PlaceholderAPI.unregisterExpansion(expansion) ? | 		final String message = !plugin.getLocalExpansionManager().unregister(expansion.get()) ? | ||||||
| 							   "&cFailed to unregister expansion: &f" : | 							   "&cFailed to unregister expansion: &f" : | ||||||
| 							   "&aSuccessfully unregistered expansion: &f"; | 							   "&aSuccessfully unregistered expansion: &f"; | ||||||
|  |  | ||||||
| 		Msg.msg(sender, message + expansion.getName()); | 		Msg.msg(sender, message + expansion.get().getName()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ import org.jetbrains.annotations.NotNull; | |||||||
| import org.jetbrains.annotations.Unmodifiable; | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Optional; | ||||||
|  |  | ||||||
| public final class CommandInfo extends PlaceholderCommand | public final class CommandInfo extends PlaceholderCommand | ||||||
| { | { | ||||||
| @@ -29,7 +30,7 @@ public final class CommandInfo extends PlaceholderCommand | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		final PlaceholderExpansion expansion = plugin.getExpansionManager().getRegisteredExpansion(params.get(0)); | 		final PlaceholderExpansion expansion = plugin.getLocalExpansionManager().findExpansionByName(params.get(0)).orElse(null); | ||||||
| 		if (expansion == null) | 		if (expansion == null) | ||||||
| 		{ | 		{ | ||||||
| 			Msg.msg(sender, | 			Msg.msg(sender, | ||||||
|   | |||||||
| @@ -1,255 +0,0 @@ | |||||||
| /* |  | ||||||
|  * |  | ||||||
|  * PlaceholderAPI |  | ||||||
|  * Copyright (C) 2019 Ryan McCarthy |  | ||||||
|  * |  | ||||||
|  * This program is free software: you can redistribute it and/or modify |  | ||||||
|  * it under the terms of the GNU General Public License as published by |  | ||||||
|  * the Free Software Foundation, either version 3 of the License, or |  | ||||||
|  * (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  * This program is distributed in the hope that it will be useful, |  | ||||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
|  * GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  * You should have received a copy of the GNU General Public License |  | ||||||
|  * along with this program. If not, see <http://www.gnu.org/licenses/>. |  | ||||||
|  * |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| package me.clip.placeholderapi.expansion; |  | ||||||
|  |  | ||||||
| import me.clip.placeholderapi.PlaceholderAPI; |  | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; |  | ||||||
| import me.clip.placeholderapi.PlaceholderHook; |  | ||||||
| import me.clip.placeholderapi.expansion.cloud.CloudExpansion; |  | ||||||
| import me.clip.placeholderapi.util.FileUtil; |  | ||||||
| import org.bukkit.Bukkit; |  | ||||||
| import org.bukkit.configuration.file.FileConfiguration; |  | ||||||
| import org.bukkit.event.Listener; |  | ||||||
| import org.jetbrains.annotations.NotNull; |  | ||||||
| import org.jetbrains.annotations.Nullable; |  | ||||||
|  |  | ||||||
| import java.io.File; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.Map.Entry; |  | ||||||
| import java.util.logging.Level; |  | ||||||
|  |  | ||||||
| public final class ExpansionManager |  | ||||||
| { |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	private final File                 folder; |  | ||||||
| 	@NotNull |  | ||||||
| 	private final PlaceholderAPIPlugin plugin; |  | ||||||
|  |  | ||||||
| 	public ExpansionManager(@NotNull final PlaceholderAPIPlugin plugin) |  | ||||||
| 	{ |  | ||||||
| 		this.plugin = plugin; |  | ||||||
| 		this.folder = new File(plugin.getDataFolder(), "expansions"); |  | ||||||
|  |  | ||||||
| 		if (!this.folder.exists() && !folder.mkdirs()) |  | ||||||
| 		{ |  | ||||||
| 			plugin.getLogger().log(Level.WARNING, "failed to create expansions folder!"); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	public File getFolder() |  | ||||||
| 	{ |  | ||||||
| 		return folder; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public void initializeExpansions() |  | ||||||
| 	{ |  | ||||||
| 		plugin.getLogger().info("Placeholder expansion registration initializing..."); |  | ||||||
|  |  | ||||||
| 		final Map<String, PlaceholderHook> registered = PlaceholderAPI.getPlaceholders(); |  | ||||||
| 		registerAllExpansions(); |  | ||||||
|  |  | ||||||
| 		if (!registered.isEmpty()) { |  | ||||||
| 			registered.forEach(PlaceholderAPI::registerPlaceholderHook); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public PlaceholderExpansion getRegisteredExpansion(String name) |  | ||||||
| 	{ |  | ||||||
| 		for (Entry<String, PlaceholderHook> hook : PlaceholderAPI.getPlaceholders().entrySet()) |  | ||||||
| 		{ |  | ||||||
| 			if (hook.getValue() instanceof PlaceholderExpansion) |  | ||||||
| 			{ |  | ||||||
| 				if (name.equalsIgnoreCase(hook.getKey())) |  | ||||||
| 				{ |  | ||||||
| 					return (PlaceholderExpansion) hook.getValue(); |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return null; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public boolean registerExpansion(@NotNull final PlaceholderExpansion expansion) |  | ||||||
| 	{ |  | ||||||
| 		if (expansion.getIdentifier() == null) |  | ||||||
| 		{ |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (expansion instanceof Configurable) |  | ||||||
| 		{ |  | ||||||
| 			Map<String, Object> defaults = ((Configurable) expansion).getDefaults(); |  | ||||||
| 			String              pre      = "expansions." + expansion.getIdentifier() + "."; |  | ||||||
| 			FileConfiguration   cfg      = plugin.getConfig(); |  | ||||||
| 			boolean             save     = false; |  | ||||||
|  |  | ||||||
| 			if (defaults != null) |  | ||||||
| 			{ |  | ||||||
| 				for (Entry<String, Object> entries : defaults.entrySet()) |  | ||||||
| 				{ |  | ||||||
| 					if (entries.getKey() == null || entries.getKey().isEmpty()) |  | ||||||
| 					{ |  | ||||||
| 						continue; |  | ||||||
| 					} |  | ||||||
|  |  | ||||||
| 					if (entries.getValue() == null) |  | ||||||
| 					{ |  | ||||||
| 						if (cfg.contains(pre + entries.getKey())) |  | ||||||
| 						{ |  | ||||||
| 							save = true; |  | ||||||
| 							cfg.set(pre + entries.getKey(), null); |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 					else |  | ||||||
| 					{ |  | ||||||
| 						if (!cfg.contains(pre + entries.getKey())) |  | ||||||
| 						{ |  | ||||||
| 							save = true; |  | ||||||
| 							cfg.set(pre + entries.getKey(), entries.getValue()); |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if (save) |  | ||||||
| 			{ |  | ||||||
| 				plugin.saveConfig(); |  | ||||||
| 				plugin.reloadConfig(); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (expansion instanceof VersionSpecific) |  | ||||||
| 		{ |  | ||||||
| 			VersionSpecific nms = (VersionSpecific) expansion; |  | ||||||
| 			if (!nms.isCompatibleWith(PlaceholderAPIPlugin.getServerVersion())) |  | ||||||
| 			{ |  | ||||||
| 				plugin.getLogger() |  | ||||||
| 					  .info( |  | ||||||
| 							  "Your server version is not compatible with expansion: " + expansion.getIdentifier() |  | ||||||
| 							  + " version: " + expansion.getVersion()); |  | ||||||
| 				return false; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (!expansion.canRegister() || !expansion.register()) |  | ||||||
| 		{ |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (expansion instanceof Listener) |  | ||||||
| 		{ |  | ||||||
| 			Bukkit.getPluginManager().registerEvents(((Listener) expansion), plugin); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		plugin.getLogger().info("Successfully registered expansion: " + expansion.getIdentifier()); |  | ||||||
|  |  | ||||||
| 		if (expansion instanceof Taskable) |  | ||||||
| 		{ |  | ||||||
| 			((Taskable) expansion).start(); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (plugin.getPlaceholderAPIConfig().isCloudEnabled()) |  | ||||||
| 		{ |  | ||||||
| 			final CloudExpansion cloudExpansion = plugin.getExpansionCloud().getCloudExpansion(expansion.getIdentifier()).orElse(null); |  | ||||||
|  |  | ||||||
| 			if (cloudExpansion != null) |  | ||||||
| 			{ |  | ||||||
| 				cloudExpansion.setHasExpansion(true); |  | ||||||
| 				if (!cloudExpansion.getLatestVersion().equals(expansion.getVersion())) |  | ||||||
| 				{ |  | ||||||
| 					cloudExpansion.setShouldUpdate(true); |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return true; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@Nullable |  | ||||||
| 	public PlaceholderExpansion registerExpansion(@NotNull final String fileName) |  | ||||||
| 	{ |  | ||||||
| 		final List<Class<? extends PlaceholderExpansion>> subs = FileUtil.getClasses(folder, PlaceholderExpansion.class, fileName); |  | ||||||
| 		if (subs.isEmpty()) |  | ||||||
| 		{ |  | ||||||
| 			return null; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// only register the first instance found as an expansion jar should only have 1 class |  | ||||||
| 		// extending PlaceholderExpansion |  | ||||||
| 		final PlaceholderExpansion expansion = createInstance(subs.get(0)); |  | ||||||
| 		if (expansion != null && registerExpansion(expansion)) |  | ||||||
| 		{ |  | ||||||
| 			return expansion; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return null; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public void registerAllExpansions() |  | ||||||
| 	{ |  | ||||||
| 		final List<@NotNull Class<? extends PlaceholderExpansion>> subs = FileUtil.getClasses(folder, PlaceholderExpansion.class); |  | ||||||
| 		if (subs.isEmpty()) |  | ||||||
| 		{ |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		for (final Class<? extends PlaceholderExpansion> clazz : subs) |  | ||||||
| 		{ |  | ||||||
| 			final PlaceholderExpansion expansion = createInstance(clazz); |  | ||||||
| 			if (expansion == null) |  | ||||||
| 			{ |  | ||||||
| 				continue; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			try |  | ||||||
| 			{ |  | ||||||
| 				registerExpansion(expansion); |  | ||||||
| 			} |  | ||||||
| 			catch (final Exception ex) |  | ||||||
| 			{ |  | ||||||
| 				plugin.getLogger().log(Level.WARNING, "Couldn't register " + expansion.getIdentifier() + " expansion", ex); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Nullable |  | ||||||
| 	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; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -108,8 +108,7 @@ public abstract class PlaceholderExpansion extends PlaceholderHook { | |||||||
|      * @return true if this hook meets all the requirements to register |      * @return true if this hook meets all the requirements to register | ||||||
|      */ |      */ | ||||||
|     public boolean canRegister() { |     public boolean canRegister() { | ||||||
|         return getRequiredPlugin() == null |         return getRequiredPlugin() == null || Bukkit.getPluginManager().getPlugin(getRequiredPlugin()) != null; | ||||||
|                 || Bukkit.getPluginManager().getPlugin(getRequiredPlugin()) != null; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -119,7 +118,7 @@ public abstract class PlaceholderExpansion extends PlaceholderHook { | |||||||
|      */ |      */ | ||||||
|     public boolean register() { |     public boolean register() { | ||||||
|         Validate.notNull(getIdentifier(), "Placeholder identifier can not be null!"); |         Validate.notNull(getIdentifier(), "Placeholder identifier can not be null!"); | ||||||
|         return PlaceholderAPI.registerExpansion(this); |         return canRegister() && getPlaceholderAPI().getLocalExpansionManager().register(this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|   | |||||||
| @@ -1,283 +0,0 @@ | |||||||
| /* |  | ||||||
|  * |  | ||||||
|  * PlaceholderAPI |  | ||||||
|  * Copyright (C) 2019 Ryan McCarthy |  | ||||||
|  * |  | ||||||
|  * This program is free software: you can redistribute it and/or modify |  | ||||||
|  * it under the terms of the GNU General Public License as published by |  | ||||||
|  * the Free Software Foundation, either version 3 of the License, or |  | ||||||
|  * (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  * This program is distributed in the hope that it will be useful, |  | ||||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
|  * GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  * You should have received a copy of the GNU General Public License |  | ||||||
|  * along with this program. If not, see <http://www.gnu.org/licenses/>. |  | ||||||
|  * |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| package me.clip.placeholderapi.expansion.cloud; |  | ||||||
|  |  | ||||||
| import com.google.common.collect.ImmutableMap; |  | ||||||
| import com.google.common.collect.ImmutableSet; |  | ||||||
| import com.google.gson.Gson; |  | ||||||
| import com.google.gson.reflect.TypeToken; |  | ||||||
| import me.clip.placeholderapi.PlaceholderAPI; |  | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; |  | ||||||
| import me.clip.placeholderapi.expansion.PlaceholderExpansion; |  | ||||||
| import org.jetbrains.annotations.NotNull; |  | ||||||
| import org.jetbrains.annotations.Unmodifiable; |  | ||||||
|  |  | ||||||
| import java.io.BufferedReader; |  | ||||||
| import java.io.File; |  | ||||||
| import java.io.FileOutputStream; |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.io.InputStreamReader; |  | ||||||
| import java.net.URL; |  | ||||||
| import java.nio.channels.Channels; |  | ||||||
| import java.nio.channels.ReadableByteChannel; |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.Collections; |  | ||||||
| import java.util.Comparator; |  | ||||||
| import java.util.HashMap; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.Optional; |  | ||||||
| import java.util.Set; |  | ||||||
| import java.util.TreeMap; |  | ||||||
| import java.util.concurrent.CompletableFuture; |  | ||||||
| import java.util.concurrent.CompletionException; |  | ||||||
| import java.util.concurrent.atomic.AtomicInteger; |  | ||||||
| import java.util.function.Function; |  | ||||||
| import java.util.logging.Level; |  | ||||||
| import java.util.stream.Collectors; |  | ||||||
|  |  | ||||||
| public final class ExpansionCloudManager |  | ||||||
| { |  | ||||||
|  |  | ||||||
| 	private static final String API_URL = "http://api.extendedclip.com/v2/"; |  | ||||||
| 	private static final Gson   GSON    = new Gson(); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	private final File                 folder; |  | ||||||
| 	@NotNull |  | ||||||
| 	private final PlaceholderAPIPlugin plugin; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	private final Map<Integer, CloudExpansion>                 expansions  = new TreeMap<>(); |  | ||||||
| 	@NotNull |  | ||||||
| 	private final Map<CloudExpansion, CompletableFuture<File>> downloading = new HashMap<>(); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public ExpansionCloudManager(@NotNull final PlaceholderAPIPlugin plugin) |  | ||||||
| 	{ |  | ||||||
| 		this.plugin = plugin; |  | ||||||
| 		this.folder = new File(plugin.getDataFolder(), "expansions"); |  | ||||||
|  |  | ||||||
| 		if (!this.folder.exists() && !this.folder.mkdirs()) |  | ||||||
| 		{ |  | ||||||
| 			plugin.getLogger().severe("Failed to create expansions directory!"); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	@Unmodifiable |  | ||||||
| 	public Map<Integer, CloudExpansion> getCloudExpansions() |  | ||||||
| 	{ |  | ||||||
| 		return ImmutableMap.copyOf(expansions); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	@Unmodifiable |  | ||||||
| 	public Set<String> getCloudAuthorNames() |  | ||||||
| 	{ |  | ||||||
| 		return ImmutableSet.copyOf(expansions.values().stream().map(CloudExpansion::getAuthor).collect(Collectors.toSet())); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public int getCloudAuthorCount() |  | ||||||
| 	{ |  | ||||||
| 		return expansions.values() |  | ||||||
| 						 .stream() |  | ||||||
| 						 .collect(Collectors.groupingBy(CloudExpansion::getAuthor, Collectors.counting())) |  | ||||||
| 						 .size(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	public Optional<CloudExpansion> getCloudExpansion(String name) |  | ||||||
| 	{ |  | ||||||
| 		return expansions.values() |  | ||||||
| 						 .stream() |  | ||||||
| 						 .filter(ex -> ex.getName().replace(' ', '_').equalsIgnoreCase(name.replace(' ', '_'))) |  | ||||||
| 						 .findFirst(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public int getCloudUpdateCount() |  | ||||||
| 	{ |  | ||||||
| 		return ((int) PlaceholderAPI.getExpansions() |  | ||||||
| 									.stream() |  | ||||||
| 									.filter(ex -> getCloudExpansion(ex.getName()).map(CloudExpansion::shouldUpdate).isPresent()) |  | ||||||
| 									.count()); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	@Unmodifiable |  | ||||||
| 	public Map<Integer, CloudExpansion> getAllByAuthor(@NotNull final String author) |  | ||||||
| 	{ |  | ||||||
| 		if (expansions.isEmpty()) |  | ||||||
| 		{ |  | ||||||
| 			return Collections.emptyMap(); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final AtomicInteger index = new AtomicInteger(); |  | ||||||
|  |  | ||||||
| 		return expansions.values() |  | ||||||
| 						 .stream() |  | ||||||
| 						 .filter(expansion -> author.equalsIgnoreCase(expansion.getAuthor())) |  | ||||||
| 						 .collect(Collectors.toMap(($) -> index.incrementAndGet(), Function.identity())); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	@Unmodifiable |  | ||||||
| 	public Map<Integer, CloudExpansion> getAllInstalled() |  | ||||||
| 	{ |  | ||||||
| 		if (expansions.isEmpty()) |  | ||||||
| 		{ |  | ||||||
| 			return Collections.emptyMap(); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final AtomicInteger index = new AtomicInteger(); |  | ||||||
|  |  | ||||||
| 		return expansions.values() |  | ||||||
| 						 .stream() |  | ||||||
| 						 .filter(CloudExpansion::hasExpansion) |  | ||||||
| 						 .collect(Collectors.toMap(($) -> index.incrementAndGet(), Function.identity())); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public void clean() |  | ||||||
| 	{ |  | ||||||
| 		expansions.clear(); |  | ||||||
|  |  | ||||||
| 		downloading.values().forEach(future -> future.cancel(true)); |  | ||||||
| 		downloading.clear(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public void fetch(boolean allowUnverified) |  | ||||||
| 	{ |  | ||||||
| 		plugin.getLogger().info("Fetching available expansion information..."); |  | ||||||
|  |  | ||||||
| 		plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { |  | ||||||
| 			final Map<String, CloudExpansion> data = new HashMap<>(); |  | ||||||
|  |  | ||||||
| 			try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(API_URL).openStream()))) |  | ||||||
| 			{ |  | ||||||
| 				data.putAll(GSON.fromJson(reader, new TypeToken<Map<String, CloudExpansion>>() |  | ||||||
| 				{ |  | ||||||
| 				}.getType())); |  | ||||||
| 			} |  | ||||||
| 			catch (Exception ex) |  | ||||||
| 			{ |  | ||||||
| 				if (plugin.getPlaceholderAPIConfig().isDebugMode()) |  | ||||||
| 				{ |  | ||||||
| 					ex.printStackTrace(); |  | ||||||
| 				} |  | ||||||
| 				else |  | ||||||
| 				{ |  | ||||||
| 					plugin.getLogger().warning("Unable to fetch expansions!\nThere was an error with the server host connecting to the PlaceholderAPI eCloud (https://api.extendedclip.com/v2/)"); |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			final List<CloudExpansion> unsorted = new ArrayList<>(); |  | ||||||
|  |  | ||||||
| 			data.forEach((name, cexp) -> { |  | ||||||
| 				if ((allowUnverified || cexp.isVerified()) && cexp.getLatestVersion() != null && cexp.getVersion(cexp.getLatestVersion()) != null) |  | ||||||
| 				{ |  | ||||||
| 					cexp.setName(name); |  | ||||||
|  |  | ||||||
| 					PlaceholderExpansion ex = plugin.getExpansionManager().getRegisteredExpansion(cexp.getName()); |  | ||||||
|  |  | ||||||
| 					if (ex != null && ex.isRegistered()) |  | ||||||
| 					{ |  | ||||||
| 						cexp.setHasExpansion(true); |  | ||||||
| 						if (!ex.getVersion().equals(cexp.getLatestVersion())) |  | ||||||
| 						{ |  | ||||||
| 							cexp.setShouldUpdate(true); |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
|  |  | ||||||
| 					unsorted.add(cexp); |  | ||||||
| 				} |  | ||||||
| 			}); |  | ||||||
|  |  | ||||||
| 			unsorted.sort(Comparator.comparing(CloudExpansion::getLastUpdate).reversed()); |  | ||||||
|  |  | ||||||
| 			int count = 0; |  | ||||||
| 			for (CloudExpansion e : unsorted) |  | ||||||
| 			{ |  | ||||||
| 				expansions.put(count++, e); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			plugin.getLogger().info(count + " placeholder expansions are available on the cloud."); |  | ||||||
|  |  | ||||||
| 			long updates = getCloudUpdateCount(); |  | ||||||
|  |  | ||||||
| 			if (updates > 0) |  | ||||||
| 			{ |  | ||||||
| 				plugin.getLogger().info(updates + " installed expansions have updates available."); |  | ||||||
| 			} |  | ||||||
| 		}); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	public boolean isDownloading(@NotNull final CloudExpansion expansion) |  | ||||||
| 	{ |  | ||||||
| 		return downloading.containsKey(expansion); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@NotNull |  | ||||||
| 	public CompletableFuture<@NotNull File> downloadExpansion(@NotNull final CloudExpansion expansion, @NotNull final CloudExpansion.Version version) |  | ||||||
| 	{ |  | ||||||
| 		final CompletableFuture<File> previous = downloading.get(expansion); |  | ||||||
| 		if (previous != null) |  | ||||||
| 		{ |  | ||||||
| 			return previous; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		final File file = new File(folder, "Expansion-" + expansion.getName() + ".jar"); |  | ||||||
|  |  | ||||||
| 		final CompletableFuture<File> download = CompletableFuture.supplyAsync(() -> { |  | ||||||
|  |  | ||||||
| 			try (final ReadableByteChannel source = Channels.newChannel(new URL(version.getUrl()).openStream()); final FileOutputStream target = new FileOutputStream(file)) |  | ||||||
| 			{ |  | ||||||
| 				target.getChannel().transferFrom(source, 0, Long.MAX_VALUE); |  | ||||||
| 			} |  | ||||||
| 			catch (final IOException ex) |  | ||||||
| 			{ |  | ||||||
| 				throw new CompletionException(ex); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			return file; |  | ||||||
| 		}); |  | ||||||
|  |  | ||||||
| 		download.whenCompleteAsync((value, exception) -> { |  | ||||||
| 			downloading.remove(expansion); |  | ||||||
|  |  | ||||||
| 			if (exception != null) |  | ||||||
| 			{ |  | ||||||
| 				plugin.getLogger().log(Level.SEVERE, "failed to download " + expansion.getName() + ":" + version.getVersion(), exception); |  | ||||||
| 			} |  | ||||||
| 		}); |  | ||||||
|  |  | ||||||
| 		downloading.put(expansion, download); |  | ||||||
|  |  | ||||||
| 		return download; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -0,0 +1,266 @@ | |||||||
|  | package me.clip.placeholderapi.expansion.manager; | ||||||
|  |  | ||||||
|  | import com.google.common.collect.ImmutableMap; | ||||||
|  | import com.google.common.io.Resources; | ||||||
|  | import com.google.gson.Gson; | ||||||
|  | import com.google.gson.reflect.TypeToken; | ||||||
|  | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
|  | import me.clip.placeholderapi.expansion.PlaceholderExpansion; | ||||||
|  | import me.clip.placeholderapi.expansion.cloud.CloudExpansion; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
|  | import java.io.File; | ||||||
|  | import java.io.FileOutputStream; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.lang.reflect.Type; | ||||||
|  | import java.net.URL; | ||||||
|  | import java.nio.channels.Channels; | ||||||
|  | import java.nio.channels.ReadableByteChannel; | ||||||
|  | import java.nio.charset.StandardCharsets; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.Optional; | ||||||
|  | import java.util.Set; | ||||||
|  | import java.util.concurrent.CompletableFuture; | ||||||
|  | import java.util.concurrent.CompletionException; | ||||||
|  | import java.util.concurrent.ConcurrentHashMap; | ||||||
|  | import java.util.function.Function; | ||||||
|  | import java.util.logging.Level; | ||||||
|  | import java.util.stream.Collector; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  |  | ||||||
|  | public final class CloudExpansionManager | ||||||
|  | { | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private static final String API_URL = "http://api.extendedclip.com/v2/"; | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private static final Gson GSON = new Gson(); | ||||||
|  | 	@NotNull | ||||||
|  | 	private static final Type TYPE = new TypeToken<Map<String, CloudExpansion>>() {}.getType(); | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private final Collector<CloudExpansion, ?, Map<String, CloudExpansion>> INDEXED_NAME_COLLECTOR = Collectors.toMap(CloudExpansionManager::toIndexName, Function.identity()); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private final PlaceholderAPIPlugin plugin; | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private final Map<String, CloudExpansion>          cache = new HashMap<>(); | ||||||
|  | 	@NotNull | ||||||
|  | 	private final Map<String, CompletableFuture<File>> await = new ConcurrentHashMap<>(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	public CloudExpansionManager(@NotNull final PlaceholderAPIPlugin plugin) | ||||||
|  | 	{ | ||||||
|  | 		this.plugin = plugin; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	public void load() | ||||||
|  | 	{ | ||||||
|  | 		clean(); | ||||||
|  | 		fetch(plugin.getPlaceholderAPIConfig().cloudAllowUnverifiedExpansions()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public void kill() | ||||||
|  | 	{ | ||||||
|  | 		clean(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	@Unmodifiable | ||||||
|  | 	public Map<String, CloudExpansion> getCloudExpansions() | ||||||
|  | 	{ | ||||||
|  | 		return ImmutableMap.copyOf(cache); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	@Unmodifiable | ||||||
|  | 	public Map<String, CloudExpansion> getCloudExpansionsInstalled() | ||||||
|  | 	{ | ||||||
|  | 		if (cache.isEmpty()) | ||||||
|  | 		{ | ||||||
|  | 			return Collections.emptyMap(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return cache.values() | ||||||
|  | 					.stream() | ||||||
|  | 					.filter(CloudExpansion::hasExpansion) | ||||||
|  | 					.collect(INDEXED_NAME_COLLECTOR); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	@Unmodifiable | ||||||
|  | 	public Map<String, CloudExpansion> getCloudExpansionsByAuthor(@NotNull final String author) | ||||||
|  | 	{ | ||||||
|  | 		if (cache.isEmpty()) | ||||||
|  | 		{ | ||||||
|  | 			return Collections.emptyMap(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return cache.values() | ||||||
|  | 					.stream() | ||||||
|  | 					.filter(expansion -> author.equalsIgnoreCase(expansion.getAuthor())) | ||||||
|  | 					.collect(INDEXED_NAME_COLLECTOR); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	@Unmodifiable | ||||||
|  | 	public Set<String> getCloudExpansionAuthors() | ||||||
|  | 	{ | ||||||
|  | 		return cache.values().stream().map(CloudExpansion::getAuthor).collect(Collectors.toSet()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	public int getCloudExpansionAuthorCount() | ||||||
|  | 	{ | ||||||
|  | 		return getCloudExpansionAuthors().size(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public int getCloudUpdateCount() | ||||||
|  | 	{ | ||||||
|  | 		return ((int) plugin.getLocalExpansionManager() | ||||||
|  | 							.getExpansions() | ||||||
|  | 							.stream() | ||||||
|  | 							.filter(expansion -> findCloudExpansionByName(expansion.getName()).map(CloudExpansion::shouldUpdate).orElse(false)) | ||||||
|  | 							.count()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	public Optional<CloudExpansion> findCloudExpansionByName(@NotNull final String name) | ||||||
|  | 	{ | ||||||
|  | 		return Optional.ofNullable(cache.get(toIndexName(name))); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	public void clean() | ||||||
|  | 	{ | ||||||
|  | 		cache.clear(); | ||||||
|  |  | ||||||
|  | 		await.values().forEach(future -> future.cancel(true)); | ||||||
|  | 		await.clear(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public void fetch(final boolean allowUnverified) | ||||||
|  | 	{ | ||||||
|  | 		plugin.getLogger().info("Fetching available expansion information..."); | ||||||
|  |  | ||||||
|  | 		CompletableFuture<Map<String, CloudExpansion>> future = CompletableFuture.supplyAsync(() -> { | ||||||
|  | 			final Map<String, CloudExpansion> values = new HashMap<>(); | ||||||
|  |  | ||||||
|  | 			try | ||||||
|  | 			{ | ||||||
|  | 				//noinspection UnstableApiUsage | ||||||
|  | 				final String json = Resources.toString(new URL(API_URL), StandardCharsets.UTF_8); | ||||||
|  | 				values.putAll(GSON.fromJson(json, TYPE)); | ||||||
|  | 			} | ||||||
|  | 			catch (final IOException ex) | ||||||
|  | 			{ | ||||||
|  | 				throw new CompletionException(ex); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			values.values().removeIf(value -> value.getLatestVersion() == null || value.getVersion(value.getLatestVersion()) == null); | ||||||
|  |  | ||||||
|  | 			return values; | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		if (!allowUnverified) | ||||||
|  | 		{ | ||||||
|  | 			future = future.thenApplyAsync((values) -> { | ||||||
|  | 				values.values().removeIf(expansion -> !expansion.isVerified()); | ||||||
|  | 				return values; | ||||||
|  | 			}); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		future = future.thenApplyAsync((values) -> { | ||||||
|  |  | ||||||
|  | 			values.forEach((name, expansion) -> { | ||||||
|  | 				expansion.setName(name); | ||||||
|  |  | ||||||
|  | 				final Optional<PlaceholderExpansion> local = plugin.getLocalExpansionManager().findExpansionByName(name); | ||||||
|  | 				if (local.isPresent() && local.get().isRegistered()) | ||||||
|  | 				{ | ||||||
|  | 					expansion.setHasExpansion(true); | ||||||
|  | 					expansion.setShouldUpdate(!local.get().getVersion().equals(expansion.getLatestVersion())); | ||||||
|  | 				} | ||||||
|  | 			}); | ||||||
|  |  | ||||||
|  | 			return values; | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		future.whenComplete((expansions, exception) -> { | ||||||
|  |  | ||||||
|  | 			if (exception != null) | ||||||
|  | 			{ | ||||||
|  | 				plugin.getLogger().log(Level.WARNING, "failed to download expansion information", exception); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			this.cache.putAll(expansions); | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public boolean isDownloading(@NotNull final CloudExpansion expansion) | ||||||
|  | 	{ | ||||||
|  | 		return await.containsKey(toIndexName(expansion)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	public CompletableFuture<File> downloadExpansion(@NotNull final CloudExpansion expansion, @NotNull final CloudExpansion.Version version) | ||||||
|  | 	{ | ||||||
|  | 		final CompletableFuture<File> previous = await.get(toIndexName(expansion)); | ||||||
|  | 		if (previous != null) | ||||||
|  | 		{ | ||||||
|  | 			return previous; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		final File file = new File(plugin.getLocalExpansionManager().getExpansionsFolder(), "Expansion-" + toIndexName(expansion) + ".jar"); | ||||||
|  |  | ||||||
|  | 		final CompletableFuture<File> download = CompletableFuture.supplyAsync(() -> { | ||||||
|  | 			try (final ReadableByteChannel source = Channels.newChannel(new URL(version.getUrl()).openStream()); final FileOutputStream target = new FileOutputStream(file)) | ||||||
|  | 			{ | ||||||
|  | 				target.getChannel().transferFrom(source, 0, Long.MAX_VALUE); | ||||||
|  | 			} | ||||||
|  | 			catch (final IOException ex) | ||||||
|  | 			{ | ||||||
|  | 				throw new CompletionException(ex); | ||||||
|  | 			} | ||||||
|  | 			return file; | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		download.whenCompleteAsync((value, exception) -> { | ||||||
|  | 			await.remove(toIndexName(expansion)); | ||||||
|  |  | ||||||
|  | 			if (exception != null) | ||||||
|  | 			{ | ||||||
|  | 				plugin.getLogger().log(Level.SEVERE, "failed to download " + expansion.getName() + ":" + version.getVersion(), exception); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		await.put(toIndexName(expansion), download); | ||||||
|  |  | ||||||
|  | 		return download; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private static String toIndexName(@NotNull final String name) | ||||||
|  | 	{ | ||||||
|  | 		return name.toLowerCase().replace(' ', '_'); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private static String toIndexName(@NotNull final CloudExpansion expansion) | ||||||
|  | 	{ | ||||||
|  | 		return toIndexName(expansion.getName()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,385 @@ | |||||||
|  | package me.clip.placeholderapi.expansion.manager; | ||||||
|  |  | ||||||
|  | import com.google.common.collect.ImmutableSet; | ||||||
|  | import com.google.common.collect.Sets; | ||||||
|  | import me.clip.placeholderapi.PlaceholderAPIPlugin; | ||||||
|  | import me.clip.placeholderapi.events.ExpansionRegisterEvent; | ||||||
|  | import me.clip.placeholderapi.events.ExpansionUnregisterEvent; | ||||||
|  | import me.clip.placeholderapi.expansion.Cacheable; | ||||||
|  | import me.clip.placeholderapi.expansion.Cleanable; | ||||||
|  | import me.clip.placeholderapi.expansion.Configurable; | ||||||
|  | import me.clip.placeholderapi.expansion.PlaceholderExpansion; | ||||||
|  | import me.clip.placeholderapi.expansion.Taskable; | ||||||
|  | import me.clip.placeholderapi.expansion.VersionSpecific; | ||||||
|  | import me.clip.placeholderapi.expansion.cloud.CloudExpansion; | ||||||
|  | import me.clip.placeholderapi.util.FileUtil; | ||||||
|  | import org.bukkit.Bukkit; | ||||||
|  | import org.bukkit.configuration.file.FileConfiguration; | ||||||
|  | import org.bukkit.event.EventHandler; | ||||||
|  | import org.bukkit.event.EventPriority; | ||||||
|  | import org.bukkit.event.HandlerList; | ||||||
|  | import org.bukkit.event.Listener; | ||||||
|  | import org.bukkit.event.player.PlayerQuitEvent; | ||||||
|  | import org.bukkit.event.server.PluginDisableEvent; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
|  | import org.jetbrains.annotations.Unmodifiable; | ||||||
|  |  | ||||||
|  | import java.io.File; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.Optional; | ||||||
|  | import java.util.concurrent.CompletableFuture; | ||||||
|  | import java.util.concurrent.CompletionException; | ||||||
|  | import java.util.logging.Level; | ||||||
|  |  | ||||||
|  | public final class LocalExpansionManager implements Listener | ||||||
|  | { | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private static final String EXPANSIONS_FOLDER_NAME = "expansions"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private final File                 folder; | ||||||
|  | 	@NotNull | ||||||
|  | 	private final PlaceholderAPIPlugin plugin; | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	private final Map<String, PlaceholderExpansion> expansions = new HashMap<>(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	public LocalExpansionManager(@NotNull final PlaceholderAPIPlugin plugin) | ||||||
|  | 	{ | ||||||
|  | 		this.plugin = plugin; | ||||||
|  | 		this.folder = new File(plugin.getDataFolder(), EXPANSIONS_FOLDER_NAME); | ||||||
|  |  | ||||||
|  | 		if (!this.folder.exists() && !folder.mkdirs()) | ||||||
|  | 		{ | ||||||
|  | 			plugin.getLogger().log(Level.WARNING, "failed to create expansions folder!"); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public void load() | ||||||
|  | 	{ | ||||||
|  | 		registerAll(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public void kill() | ||||||
|  | 	{ | ||||||
|  | 		unregisterAll(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	public File getExpansionsFolder() | ||||||
|  | 	{ | ||||||
|  | 		return folder; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public int getExpansionsCount() | ||||||
|  | 	{ | ||||||
|  | 		return expansions.size(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	@Unmodifiable | ||||||
|  | 	public Collection<String> getIdentifiers() | ||||||
|  | 	{ | ||||||
|  | 		return ImmutableSet.copyOf(expansions.keySet()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	@Unmodifiable | ||||||
|  | 	public Collection<PlaceholderExpansion> getExpansions() | ||||||
|  | 	{ | ||||||
|  | 		return ImmutableSet.copyOf(expansions.values()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	@Nullable | ||||||
|  | 	public PlaceholderExpansion getExpansion(@NotNull final String identifier) | ||||||
|  | 	{ | ||||||
|  | 		return expansions.get(identifier.toLowerCase()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	public Optional<PlaceholderExpansion> findExpansionByName(@NotNull final String name) | ||||||
|  | 	{ | ||||||
|  | 		return expansions.values().stream().filter(expansion -> name.equalsIgnoreCase(expansion.getName())).findFirst(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	public Optional<PlaceholderExpansion> findExpansionByIdentifier(@NotNull final String identifier) | ||||||
|  | 	{ | ||||||
|  | 		return Optional.ofNullable(getExpansion(identifier)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Do not call this method yourself, use {@link PlaceholderExpansion#register()} | ||||||
|  | 	 */ | ||||||
|  | 	public boolean register(@NotNull final PlaceholderExpansion expansion) | ||||||
|  | 	{ | ||||||
|  | 		final String identifier = expansion.getIdentifier(); | ||||||
|  | 		if (identifier == null) | ||||||
|  | 		{ | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (expansion instanceof Configurable) | ||||||
|  | 		{ | ||||||
|  | 			Map<String, Object> defaults = ((Configurable) expansion).getDefaults(); | ||||||
|  | 			String              pre      = "expansions." + expansion.getIdentifier() + "."; | ||||||
|  | 			FileConfiguration   cfg      = plugin.getConfig(); | ||||||
|  | 			boolean             save     = false; | ||||||
|  |  | ||||||
|  | 			if (defaults != null) | ||||||
|  | 			{ | ||||||
|  | 				for (Map.Entry<String, Object> entries : defaults.entrySet()) | ||||||
|  | 				{ | ||||||
|  | 					if (entries.getKey() == null || entries.getKey().isEmpty()) | ||||||
|  | 					{ | ||||||
|  | 						continue; | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					if (entries.getValue() == null) | ||||||
|  | 					{ | ||||||
|  | 						if (cfg.contains(pre + entries.getKey())) | ||||||
|  | 						{ | ||||||
|  | 							save = true; | ||||||
|  | 							cfg.set(pre + entries.getKey(), null); | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					else | ||||||
|  | 					{ | ||||||
|  | 						if (!cfg.contains(pre + entries.getKey())) | ||||||
|  | 						{ | ||||||
|  | 							save = true; | ||||||
|  | 							cfg.set(pre + entries.getKey(), entries.getValue()); | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (save) | ||||||
|  | 			{ | ||||||
|  | 				plugin.saveConfig(); | ||||||
|  | 				plugin.reloadConfig(); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (expansion instanceof VersionSpecific) | ||||||
|  | 		{ | ||||||
|  | 			VersionSpecific nms = (VersionSpecific) expansion; | ||||||
|  | 			if (!nms.isCompatibleWith(PlaceholderAPIPlugin.getServerVersion())) | ||||||
|  | 			{ | ||||||
|  | 				plugin.getLogger().info("Your server version is not compatible with expansion: " + expansion.getIdentifier() + " version: " + expansion.getVersion()); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		final ExpansionRegisterEvent event = new ExpansionRegisterEvent(expansion); | ||||||
|  | 		Bukkit.getPluginManager().callEvent(event); | ||||||
|  |  | ||||||
|  | 		if (event.isCancelled() || expansions.put(expansion.getIdentifier(), expansion) != null) | ||||||
|  | 		{ | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (expansion instanceof Listener) | ||||||
|  | 		{ | ||||||
|  | 			Bukkit.getPluginManager().registerEvents(((Listener) expansion), plugin); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		plugin.getLogger().info("Successfully registered expansion: " + expansion.getIdentifier()); | ||||||
|  |  | ||||||
|  | 		if (expansion instanceof Taskable) | ||||||
|  | 		{ | ||||||
|  | 			((Taskable) expansion).start(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (plugin.getPlaceholderAPIConfig().isCloudEnabled()) | ||||||
|  | 		{ | ||||||
|  | 			final Optional<CloudExpansion> cloudExpansion = plugin.getCloudExpansionManager().findCloudExpansionByName(identifier); | ||||||
|  | 			if (cloudExpansion.isPresent()) | ||||||
|  | 			{ | ||||||
|  | 				cloudExpansion.get().setHasExpansion(true); | ||||||
|  | 				cloudExpansion.get().setShouldUpdate(!cloudExpansion.get().getLatestVersion().equals(expansion.getVersion())); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public Optional<PlaceholderExpansion> register(@NotNull final Class<? extends PlaceholderExpansion> clazz) | ||||||
|  | 	{ | ||||||
|  | 		final PlaceholderExpansion expansion = createExpansionInstance(clazz); | ||||||
|  | 		if (expansion == null || !expansion.register()) | ||||||
|  | 		{ | ||||||
|  | 			return Optional.empty(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return Optional.of(expansion); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public boolean unregister(@NotNull final PlaceholderExpansion expansion) | ||||||
|  | 	{ | ||||||
|  | 		if (expansions.remove(expansion.getIdentifier()) == null) | ||||||
|  | 		{ | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		Bukkit.getPluginManager().callEvent(new ExpansionUnregisterEvent(expansion)); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		if (expansion instanceof Listener) | ||||||
|  | 		{ | ||||||
|  | 			HandlerList.unregisterAll((Listener) expansion); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (expansion instanceof Taskable) | ||||||
|  | 		{ | ||||||
|  | 			((Taskable) expansion).stop(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (expansion instanceof Cacheable) | ||||||
|  | 		{ | ||||||
|  | 			((Cacheable) expansion).clear(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (plugin.getPlaceholderAPIConfig().isCloudEnabled()) | ||||||
|  | 		{ | ||||||
|  | 			plugin.getCloudExpansionManager().findCloudExpansionByName(expansion.getName()).ifPresent(cloud -> { | ||||||
|  | 				cloud.setHasExpansion(false); | ||||||
|  | 				cloud.setShouldUpdate(false); | ||||||
|  | 			}); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	private void registerAll() | ||||||
|  | 	{ | ||||||
|  | 		plugin.getLogger().info("Placeholder expansion registration initializing..."); | ||||||
|  |  | ||||||
|  | 		findExpansionsOnDisk().whenCompleteAsync((classes, exception) -> { | ||||||
|  | 			if (exception != null) | ||||||
|  | 			{ | ||||||
|  | 				plugin.getLogger().log(Level.SEVERE, "failed to load class files of expansions", exception); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			Bukkit.getScheduler().runTask(plugin, () -> classes.forEach(this::register)); | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private void unregisterAll() | ||||||
|  | 	{ | ||||||
|  | 		for (final PlaceholderExpansion expansion : Sets.newHashSet(expansions.values())) | ||||||
|  | 		{ | ||||||
|  | 			if (expansion.persist()) | ||||||
|  | 			{ | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			unregister(expansion); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	public CompletableFuture<List<Class<? extends PlaceholderExpansion>>> findExpansionsOnDisk() | ||||||
|  | 	{ | ||||||
|  | 		return CompletableFuture.supplyAsync(() -> { | ||||||
|  | 			try | ||||||
|  | 			{ | ||||||
|  | 				return FileUtil.getClasses(getExpansionsFolder(), PlaceholderExpansion.class); | ||||||
|  | 			} | ||||||
|  | 			catch (final IOException | ClassNotFoundException ex) | ||||||
|  | 			{ | ||||||
|  | 				throw new CompletionException(ex); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@NotNull | ||||||
|  | 	public CompletableFuture<List<Class<? extends PlaceholderExpansion>>> findExpansionsInFile(@NotNull final File file) | ||||||
|  | 	{ | ||||||
|  | 		return CompletableFuture.supplyAsync(() -> { | ||||||
|  | 			try | ||||||
|  | 			{ | ||||||
|  | 				final List<@NotNull Class<? extends PlaceholderExpansion>> classes = FileUtil.getClasses(getExpansionsFolder(), PlaceholderExpansion.class, file.getName()); | ||||||
|  | 				if (classes.size() > 1) | ||||||
|  | 				{ | ||||||
|  | 					throw new IllegalStateException("multiple expansion classes in one file!"); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				return classes; | ||||||
|  | 			} | ||||||
|  | 			catch (final Exception ex) | ||||||
|  | 			{ | ||||||
|  | 				throw new CompletionException(ex); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	@Nullable | ||||||
|  | 	public PlaceholderExpansion createExpansionInstance(@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; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	@EventHandler | ||||||
|  | 	public void onQuit(@NotNull final PlayerQuitEvent event) | ||||||
|  | 	{ | ||||||
|  | 		for (final PlaceholderExpansion expansion : getExpansions()) | ||||||
|  | 		{ | ||||||
|  | 			if (!(expansion instanceof Cleanable)) | ||||||
|  | 			{ | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			((Cleanable) expansion).cleanup(event.getPlayer()); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@EventHandler(priority = EventPriority.HIGH) | ||||||
|  | 	public void onPluginDisable(@NotNull final PluginDisableEvent event) | ||||||
|  | 	{ | ||||||
|  | 		final String name = event.getPlugin().getName(); | ||||||
|  | 		if (name.equals(plugin.getName())) | ||||||
|  | 		{ | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		for (final PlaceholderExpansion expansion : getExpansions()) | ||||||
|  | 		{ | ||||||
|  | 			if (!name.equalsIgnoreCase(expansion.getRequiredPlugin())) | ||||||
|  | 			{ | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			unregister(expansion); | ||||||
|  | 			plugin.getLogger().info("Unregistered placeholder expansion: " + expansion.getName()); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -1,120 +0,0 @@ | |||||||
| /* |  | ||||||
|  * |  | ||||||
|  * PlaceholderAPI |  | ||||||
|  * Copyright (C) 2019 Ryan McCarthy |  | ||||||
|  * |  | ||||||
|  * This program is free software: you can redistribute it and/or modify |  | ||||||
|  * it under the terms of the GNU General Public License as published by |  | ||||||
|  * the Free Software Foundation, either version 3 of the License, or |  | ||||||
|  * (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  * This program is distributed in the hope that it will be useful, |  | ||||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
|  * GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  * You should have received a copy of the GNU General Public License |  | ||||||
|  * along with this program. If not, see <http://www.gnu.org/licenses/>. |  | ||||||
|  * |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| package me.clip.placeholderapi.listeners; |  | ||||||
|  |  | ||||||
| import me.clip.placeholderapi.PlaceholderAPI; |  | ||||||
| import me.clip.placeholderapi.PlaceholderAPIPlugin; |  | ||||||
| import me.clip.placeholderapi.PlaceholderHook; |  | ||||||
| import me.clip.placeholderapi.events.ExpansionUnregisterEvent; |  | ||||||
| import me.clip.placeholderapi.expansion.Cacheable; |  | ||||||
| import me.clip.placeholderapi.expansion.Cleanable; |  | ||||||
| import me.clip.placeholderapi.expansion.PlaceholderExpansion; |  | ||||||
| import me.clip.placeholderapi.expansion.Taskable; |  | ||||||
| import me.clip.placeholderapi.expansion.cloud.CloudExpansion; |  | ||||||
| import org.bukkit.Bukkit; |  | ||||||
| import org.bukkit.event.EventHandler; |  | ||||||
| import org.bukkit.event.EventPriority; |  | ||||||
| import org.bukkit.event.HandlerList; |  | ||||||
| import org.bukkit.event.Listener; |  | ||||||
| import org.bukkit.event.player.PlayerQuitEvent; |  | ||||||
| import org.bukkit.event.server.PluginDisableEvent; |  | ||||||
|  |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.Map.Entry; |  | ||||||
| import java.util.Set; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| public class PlaceholderListener implements Listener { |  | ||||||
|  |  | ||||||
|     private final PlaceholderAPIPlugin plugin; |  | ||||||
|  |  | ||||||
|     public PlaceholderListener(PlaceholderAPIPlugin instance) { |  | ||||||
|         plugin = instance; |  | ||||||
|         Bukkit.getPluginManager().registerEvents(this, instance); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @EventHandler |  | ||||||
|     public void onExpansionUnregister(ExpansionUnregisterEvent event) { |  | ||||||
|         if (event.getExpansion() instanceof Listener) { |  | ||||||
|             HandlerList.unregisterAll((Listener) event.getExpansion()); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (event.getExpansion() instanceof Taskable) { |  | ||||||
|             ((Taskable) event.getExpansion()).stop(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (event.getExpansion() instanceof Cacheable) { |  | ||||||
|             ((Cacheable) event.getExpansion()).clear(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (plugin.getPlaceholderAPIConfig().isCloudEnabled()) { |  | ||||||
|             CloudExpansion ex = plugin.getExpansionCloud().getCloudExpansion(event.getExpansion().getName()).orElse(null); |  | ||||||
|             if (ex != null) { |  | ||||||
|                 ex.setHasExpansion(false); |  | ||||||
|                 ex.setShouldUpdate(false); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @EventHandler(priority = EventPriority.HIGH) |  | ||||||
|     public void onPluginUnload(PluginDisableEvent e) { |  | ||||||
|         String n = e.getPlugin().getName(); |  | ||||||
|  |  | ||||||
|         if (n.equals(plugin.getName())) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Map<String, PlaceholderHook> hooks = PlaceholderAPI.getPlaceholders(); |  | ||||||
|  |  | ||||||
|         for (Entry<String, PlaceholderHook> entry : hooks.entrySet()) { |  | ||||||
|             PlaceholderHook hook = entry.getValue(); |  | ||||||
|  |  | ||||||
|             if (hook instanceof PlaceholderExpansion) { |  | ||||||
|                 PlaceholderExpansion expansion = (PlaceholderExpansion) hook; |  | ||||||
|  |  | ||||||
|                 if (expansion.getRequiredPlugin() == null) { |  | ||||||
|                     continue; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 if (expansion.getRequiredPlugin().equalsIgnoreCase(n)) { |  | ||||||
|                     if (PlaceholderAPI.unregisterExpansion(expansion)) { |  | ||||||
|                         plugin.getLogger().info("Unregistered placeholder expansion: " + expansion.getIdentifier()); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @EventHandler |  | ||||||
|     public void onQuit(PlayerQuitEvent e) { |  | ||||||
|         Set<PlaceholderExpansion> expansions = PlaceholderAPI.getExpansions(); |  | ||||||
|  |  | ||||||
|         if (expansions.isEmpty()) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         for (PlaceholderExpansion ex : expansions) { |  | ||||||
|             if (ex instanceof Cleanable) { |  | ||||||
|                 ((Cleanable) ex).cleanup(e.getPlayer()); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -55,7 +55,7 @@ public final class ServerLoadEventListener implements Listener | |||||||
| 	public void onServerLoad(@NotNull final ServerLoadEvent event) | 	public void onServerLoad(@NotNull final ServerLoadEvent event) | ||||||
| 	{ | 	{ | ||||||
|         HandlerList.unregisterAll(this); |         HandlerList.unregisterAll(this); | ||||||
| 		plugin.getExpansionManager().initializeExpansions(); |         plugin.getLocalExpansionManager().load(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -38,25 +38,20 @@ public class FileUtil | |||||||
| { | { | ||||||
|  |  | ||||||
| 	@NotNull | 	@NotNull | ||||||
| 	public static <T> List<@NotNull Class<? extends T>> getClasses(@NotNull final File folder, @NotNull final Class<T> clazz) | 	public static <T> List<@NotNull Class<? extends T>> getClasses(@NotNull final File folder, @NotNull final Class<T> clazz) throws IOException, ClassNotFoundException | ||||||
| 	{ | 	{ | ||||||
| 		return getClasses(folder, clazz, null); | 		return getClasses(folder, clazz, null); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@NotNull | 	@NotNull | ||||||
| 	public static <T> List<@NotNull Class<? extends T>> getClasses(@NotNull final File folder, @NotNull final Class<T> clazz, @Nullable final String target) | 	public static <T> List<@NotNull Class<? extends T>> getClasses(@NotNull final File folder, @NotNull final Class<T> clazz, @Nullable final String target) throws IOException, ClassNotFoundException | ||||||
| 	{ | 	{ | ||||||
| 		if (!folder.exists()) | 		if (!folder.exists()) | ||||||
| 		{ | 		{ | ||||||
| 			return Collections.emptyList(); | 			return Collections.emptyList(); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		try | 		final File[] jars = folder.listFiles((dir, name) -> name.endsWith(".jar") && (target == null || name.replace(".jar", "").equalsIgnoreCase(target.replace(".jar", "")))); | ||||||
| 		{ |  | ||||||
| 			final FilenameFilter filter = |  | ||||||
| 					(dir, name) -> name.endsWith(".jar") && (target == null || name.replace(".jar", "").equalsIgnoreCase(target.replace(".jar", ""))); |  | ||||||
|  |  | ||||||
| 			final File[] jars = folder.listFiles(filter); |  | ||||||
| 		if (jars == null) | 		if (jars == null) | ||||||
| 		{ | 		{ | ||||||
| 			return Collections.emptyList(); | 			return Collections.emptyList(); | ||||||
| @@ -64,20 +59,13 @@ public class FileUtil | |||||||
|  |  | ||||||
| 		final List<@NotNull Class<? extends T>> list = new ArrayList<>(); | 		final List<@NotNull Class<? extends T>> list = new ArrayList<>(); | ||||||
|  |  | ||||||
| 			for (File file : jars) | 		for (final File file : jars) | ||||||
| 		{ | 		{ | ||||||
| 			gather(file.toURI().toURL(), clazz, list); | 			gather(file.toURI().toURL(), clazz, list); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		return list; | 		return list; | ||||||
| 	} | 	} | ||||||
| 		catch (final Throwable ex) |  | ||||||
| 		{ |  | ||||||
| 			ex.printStackTrace(); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return Collections.emptyList(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	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 | 	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 | ||||||
| 	{ | 	{ | ||||||
| @@ -101,7 +89,8 @@ public class FileUtil | |||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 				catch (final NoClassDefFoundError ignored) | 				catch (final NoClassDefFoundError ignored) | ||||||
| 				{ } | 				{ | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user