Merge branch 'master' into 1.18

This commit is contained in:
PiggyPiglet 2021-12-03 13:01:02 +08:00 committed by GitHub
commit 511717a8d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 215 additions and 41 deletions

View File

@ -27,8 +27,11 @@ import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* Indicates that a {@link PlaceholderExpansion} has been registered by * This event indicates that a <b>single</b> {@link PlaceholderExpansion PlaceholderExpansion} has
* PlaceholderAPI. * been registered in PlaceholderAPI.
*
* <p>To know when <b>all</b> Expansions have been registered, use the
* {@link me.clip.placeholderapi.events.ExpansionsLoadedEvent ExpansionsLoadedEvent} instead.
*/ */
public final class ExpansionRegisterEvent extends Event implements Cancellable { public final class ExpansionRegisterEvent extends Event implements Cancellable {
@ -48,15 +51,25 @@ public final class ExpansionRegisterEvent extends Event implements Cancellable {
} }
/** /**
* The {@link PlaceholderExpansion expansion} that was registered. * The {@link PlaceholderExpansion PlaceholderExpansion} that was registered in PlaceholderAPI.
* <br>The PlaceholderExpansion will be available for use when the event
* {@link #isCancelled() was not cancelled}!
* *
* @return The {@link PlaceholderExpansion} instance. * @return Current instance of the registered {@link PlaceholderExpansion PlaceholderExpansion}
*/ */
@NotNull @NotNull
public PlaceholderExpansion getExpansion() { public PlaceholderExpansion getExpansion() {
return expansion; return expansion;
} }
/**
* Indicates if this event was cancelled or not.
* <br>A cancelled Event will result in the {@link #getExpansion() PlaceholderExpansion} NOT
* being added to PlaceholderAPI's internal list and will therefore be considered not registered
* anymore.
*
* @return Whether the event has been cancelled or not.
*/
@Override @Override
public boolean isCancelled() { public boolean isCancelled() {
return cancelled; return cancelled;

View File

@ -26,15 +26,19 @@ import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* Indicates that a {@link PlaceholderExpansion} had been unregistered by * This event indicates that a {@link PlaceholderExpansion PlaceholderExpansion} has been
* PlaceholderAPI. * unregistered by PlaceholderAPI.
*
* <p>Note that this event is triggered <b>before</b> the PlaceholderExpansion is completely
* removed.
* <br>This includes removing any Listeners, stopping active tasks and clearing the cache of
* the PlaceholderExpansion.
*/ */
public final class ExpansionUnregisterEvent extends Event { public final class ExpansionUnregisterEvent extends Event {
@NotNull @NotNull
private static final HandlerList HANDLERS = new HandlerList(); private static final HandlerList HANDLERS = new HandlerList();
@NotNull @NotNull
private final PlaceholderExpansion expansion; private final PlaceholderExpansion expansion;
@ -48,9 +52,9 @@ public final class ExpansionUnregisterEvent extends Event {
} }
/** /**
* The {@link PlaceholderExpansion expansion} that was unregistered. * The {@link PlaceholderExpansion PlaceholderExpansion} that was unregistered.
* *
* @return The {@link PlaceholderExpansion} instance. * @return The {@link PlaceholderExpansion PlaceholderExpansion} instance.
*/ */
@NotNull @NotNull
public PlaceholderExpansion getExpansion() { public PlaceholderExpansion getExpansion() {

View File

@ -21,18 +21,42 @@
package me.clip.placeholderapi.events; package me.clip.placeholderapi.events;
import java.util.Collections;
import java.util.List;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* Indicates that <b>all</b> {@link me.clip.placeholderapi.expansion.PlaceholderExpansion PlayceholderExpansions} * This event indicated that <b>all</b> {@link PlaceholderExpansion PlaceholderExpansions} have
* have been loaded. * been registered in PlaceholderAPI and can now be used.
* <br/>This event is fired on Server load and when reloading the * <br>This even will also be triggered whenever PlaceholderAPI gets reloaded.
* confiuration. *
* <p>All PlaceholderExpansions, except for those loaded by plugins, are loaded
* after Spigot triggered its ServerLoadEvent (1.13+), or after PlaceholderAPI has been enabled.
*/ */
public class ExpansionsLoadedEvent extends Event { public class ExpansionsLoadedEvent extends Event {
private final List<PlaceholderExpansion> expansions;
public ExpansionsLoadedEvent(List<PlaceholderExpansion> expansions) {
this.expansions = Collections.unmodifiableList(expansions);
}
/**
* Returns a unmodifiable list of {@link PlaceholderExpansion PlaceholderExpansions} that
* have been registered by PlaceholderAPI.
*
* <p><b>This list does not include manually registered PlaceholderExpansions.</b>
*
* @return List of {@link PlaceholderExpansion registered PlaceholderExpansions}.
*/
@NotNull
public final List<PlaceholderExpansion> getExpansions(){
return expansions;
}
@NotNull @NotNull
private static final HandlerList HANDLERS = new HandlerList(); private static final HandlerList HANDLERS = new HandlerList();

View File

@ -21,9 +21,11 @@
package me.clip.placeholderapi.expansion; package me.clip.placeholderapi.expansion;
/** /**
* This interface allows a class which extends a {@link PlaceholderExpansion} to have the clear * Classes implementing this interface will have a {@link #clear() clear void} that is called
* method called when the implementing expansion is unregistered from PlaceholderAPI. This is useful * by PlaceholderAPI whenever the {@link me.clip.placeholderapi.expansion.PlaceholderExpansion PlaceholderExpansion}
* if we want to do things when the implementing hook is unregistered * is unregistered.
*
* <p>This allows you to execute things such as clearing internal caches, saving data to files, etc.
* *
* @author Ryan McCarthy * @author Ryan McCarthy
*/ */

View File

@ -23,9 +23,11 @@ package me.clip.placeholderapi.expansion;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
/** /**
* This interface allows a class which extends a {@link PlaceholderExpansion} to have the cleanup * Classes implementing this interface will have a {@link #cleanup(Player) cleanup void} that is
* method called every time a player leaves the server. This is useful if we want to clean up after * called by PlaceholderAPI whenever a Player leaves the server.
* the player *
* <p>This can be useful for cases where you keep data of the player in a cache or similar
* and want to free up space whenever they leave.
* *
* @author Ryan McCarthy * @author Ryan McCarthy
*/ */

View File

@ -23,18 +23,32 @@ package me.clip.placeholderapi.expansion;
import java.util.Map; import java.util.Map;
/** /**
* Any {@link PlaceholderExpansion} class which implements configurable will have any options listed * Implementing this interface allows {@link me.clip.placeholderapi.expansion.PlaceholderExpansion PlaceholderExpansions}
* in the {@link #getDefaults()} map automatically added to the PlaceholderAPI config.yml file * to set a list of default configuration values through the {@link #getDefaults() getDefaults method}
* that should be added to the config.yml of PlaceholderAPI.
*
* <p>The entries will be added under {@code expansions} as their own section.
* <h2>Example:</h2>
* returning a Map with key {@code foo} and value {@code bar} will result in the following config entry:
*
* <pre><code>
* expansions:
* myexpansion:
* foo: "bar"
* </code></pre>
*
* <p><b>The configuration is set before the PlaceholderExpansion is registered!</b>
* *
* @author Ryan McCarthy * @author Ryan McCarthy
*/ */
public interface Configurable { public interface Configurable {
/** /**
* This method will be called before the implementing class is registered to obtain a map of * The map returned by this method will be used to set config options in PlaceholderAPI's config.yml.
* configuration options that the implementing class needs These paths and values will be added to *
* the PlaceholderAPI config.yml in the configuration section expansions.(placeholder * <p>The key and value pairs are set under a section named after your
* identifier).(your key): (your value) * {@link me.clip.placeholderapi.expansion.PlaceholderExpansion PlaceholderExpansion} in the
* {@code expansions} section of the config.
* *
* @return Map of config path / values which need to be added / removed from the PlaceholderAPI * @return Map of config path / values which need to be added / removed from the PlaceholderAPI
* config.yml file * config.yml file

View File

@ -22,6 +22,7 @@ package me.clip.placeholderapi.expansion;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.logging.Level;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.PlaceholderHook; import me.clip.placeholderapi.PlaceholderHook;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -275,7 +276,6 @@ public abstract class PlaceholderExpansion extends PlaceholderHook {
* @param def The default boolean to return when the ConfigurationSection is null * @param def The default boolean to return when the ConfigurationSection is null
* @return boolean from the provided path or the default one provided * @return boolean from the provided path or the default one provided
*/ */
@NotNull
public final boolean getBoolean(@NotNull final String path, final boolean def) { public final boolean getBoolean(@NotNull final String path, final boolean def) {
final ConfigurationSection section = getConfigSection(); final ConfigurationSection section = getConfigSection();
return section == null ? def : section.getBoolean(path, def); return section == null ? def : section.getBoolean(path, def);
@ -294,6 +294,71 @@ public abstract class PlaceholderExpansion extends PlaceholderHook {
return section != null && section.contains(path); return section != null && section.contains(path);
} }
/**
* Logs the provided message with the provided Level in the console.
* <br>The message will be prefixed with {@link #getName() <code>[&lt;expansion name&gt;]</code>}
*
* @param level The Level at which the message should be logged with
* @param msg The message to log
*/
public void log(Level level, String msg) {
getPlaceholderAPI().getLogger().log(level, "[" + getName() + "] " + msg);
}
/**
* Logs the provided message and Throwable with the provided Level in the console.
* <br>The message will be prefixed with {@link #getName() <code>[&lt;expansion name&gt;]</code>}
*
* @param level The Level at which the message should be logged with
* @param msg The message to log
* @param throwable The Throwable to log
*/
public void log(Level level, String msg, Throwable throwable) {
getPlaceholderAPI().getLogger().log(level, "[" + getName() + "] " + msg, throwable);
}
/**
* Logs the provided message with Level "info".
* <br>The message will be prefixed with {@link #getName() <code>[&lt;expansion name&gt;]</code>}
*
* @param msg The message to log
*/
public void info(String msg) {
log(Level.INFO, msg);
}
/**
* Logs the provided message with Level "warning".
* <br>The message will be prefixed with {@link #getName() <code>[&lt;expansion name&gt;]</code>}
*
* @param msg The message to log
*/
public void warning(String msg) {
log(Level.WARNING, msg);
}
/**
* Logs the provided message with Level "severe" (error).
* <br>The message will be prefixed with {@link #getName() <code>[&lt;expansion name&gt;]</code>}
*
* @param msg The message to log
*/
public void severe(String msg) {
log(Level.SEVERE, msg);
}
/**
* Logs the provided message and Throwable with Level "severe" (error).
* <br>The message will be prefixed with {@link #getName() <code>[&lt;expansion name&gt;]</code>}
*
* @param msg The message to log
* @param throwable The Throwable to log
*/
public void severe(String msg, Throwable throwable) {
log(Level.SEVERE, msg, throwable);
}
/** /**
* Whether the provided Object is an instance of this PlaceholderExpansion. * Whether the provided Object is an instance of this PlaceholderExpansion.
* <br>This method will perform the following checks in order: * <br>This method will perform the following checks in order:

View File

@ -22,7 +22,22 @@ package me.clip.placeholderapi.expansion;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
/**
* Implementing this interface allows your {@link me.clip.placeholderapi.expansion.PlaceholderExpansion PlaceholderExpansion}
* to be used as a relational placeholder expansion.
*
* <p>Relational placeholders take two Players as input and are always prefixed with {@code rel_},
* so {@code %foo_bar%} becomes {@code %rel_foo_bar%}
*/
public interface Relational { public interface Relational {
/**
* This method is called whenever a placeholder starting with {@code rel_} is called.
*
* @param one The first player used for the placeholder.
* @param two The second player used for the placeholder.
* @param identifier The text right after the expansion's name (%expansion_<b>identifier</b>%)
* @return Parsed String from the expansion.
*/
String onPlaceholderRequest(Player one, Player two, String identifier); String onPlaceholderRequest(Player one, Player two, String identifier);
} }

View File

@ -20,18 +20,24 @@
package me.clip.placeholderapi.expansion; package me.clip.placeholderapi.expansion;
/**
* Implementing this interface adds the {@link #start() start} and {@link #stop() stop} void
* methods to your {@link me.clip.placeholderapi.expansion.PlaceholderExpansion PlaceholderExpansion}.
*
* <p>This can be used to execute methods and tasks whenever the PlaceholderExpansion has been
* successfully (un)registered.
*/
public interface Taskable { public interface Taskable {
/** /**
* Called when the implementing class has successfully been registered to the placeholder map * Called when the implementing class has successfully been registered to the placeholder map.
* Tasks that need to be performed when this expansion is registered should go here * <br>Tasks that need to be performed when this expansion is registered should go here
*/ */
void start(); void start();
/** /**
* Called when the implementing class has been unregistered from PlaceholderAPI Tasks that need to * Called when the implementing class has been unregistered from PlaceholderAPI.
* be performed when this expansion has unregistered should go here * <br>Tasks that need to be performed when this expansion has unregistered should go here
*/ */
void stop(); void stop();
} }

View File

@ -161,6 +161,10 @@ public final class LocalExpansionManager implements Listener {
try { try {
final PlaceholderExpansion expansion = createExpansionInstance(clazz); final PlaceholderExpansion expansion = createExpansionInstance(clazz);
if(expansion == null){
return Optional.empty();
}
Objects.requireNonNull(expansion.getAuthor(), "The expansion author is null!"); Objects.requireNonNull(expansion.getAuthor(), "The expansion author is null!");
Objects.requireNonNull(expansion.getIdentifier(), "The expansion identifier is null!"); Objects.requireNonNull(expansion.getIdentifier(), "The expansion identifier is null!");
Objects.requireNonNull(expansion.getVersion(), "The expansion version is null!"); Objects.requireNonNull(expansion.getVersion(), "The expansion version is null!");
@ -259,7 +263,8 @@ public final class LocalExpansionManager implements Listener {
Bukkit.getPluginManager().registerEvents(((Listener) expansion), plugin); Bukkit.getPluginManager().registerEvents(((Listener) expansion), plugin);
} }
plugin.getLogger().info("Successfully registered expansion: " + expansion.getIdentifier()); plugin.getLogger().info("Successfully registered expansion: " + expansion.getIdentifier() +
" [" + expansion.getVersion() + "]");
if (expansion instanceof Taskable) { if (expansion instanceof Taskable) {
((Taskable) expansion).start(); ((Taskable) expansion).start();
@ -320,17 +325,36 @@ public final class LocalExpansionManager implements Listener {
return; return;
} }
final long registered = classes.stream() final List<PlaceholderExpansion> registered = classes.stream()
.filter(Objects::nonNull) .filter(Objects::nonNull)
.map(this::register) .map(this::register)
.filter(Optional::isPresent) .filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
final long needsUpdate = registered.stream()
.map(expansion -> plugin.getCloudExpansionManager().findCloudExpansionByName(expansion.getName()).orElse(null))
.filter(Objects::nonNull)
.filter(CloudExpansion::shouldUpdate)
.count(); .count();
Msg.msg(sender, StringBuilder message = new StringBuilder(registered.size() == 0 ? "&6" : "&a")
registered == 0 ? "&6No expansions were registered!" .append(registered.size())
: registered + "&a placeholder hooks successfully registered!"); .append(' ')
.append("placeholder hook(s) registered!");
Bukkit.getPluginManager().callEvent(new ExpansionsLoadedEvent()); if (needsUpdate > 0) {
message.append(' ')
.append("&6")
.append(needsUpdate)
.append(' ')
.append("placeholder hook(s) have an update available.");
}
Msg.msg(sender, message.toString());
Bukkit.getPluginManager().callEvent(new ExpansionsLoadedEvent(registered));
}); });
} }
@ -346,7 +370,12 @@ public final class LocalExpansionManager implements Listener {
@NotNull @NotNull
public CompletableFuture<@NotNull List<@Nullable Class<? extends PlaceholderExpansion>>> findExpansionsOnDisk() { public CompletableFuture<@NotNull List<@Nullable Class<? extends PlaceholderExpansion>>> findExpansionsOnDisk() {
return Arrays.stream(folder.listFiles((dir, name) -> name.endsWith(".jar"))) File[] files = folder.listFiles((dir, name) -> name.endsWith(".jar"));
if(files == null){
return CompletableFuture.completedFuture(Collections.emptyList());
}
return Arrays.stream(files)
.map(this::findExpansionInFile) .map(this::findExpansionInFile)
.collect(Futures.collector()); .collect(Futures.collector());
} }