diff --git a/paper-api/src/main/java/org/bukkit/command/defaults/PluginsCommand.java b/paper-api/src/main/java/org/bukkit/command/defaults/PluginsCommand.java index 11fbd0e0c..bcb576a42 100644 --- a/paper-api/src/main/java/org/bukkit/command/defaults/PluginsCommand.java +++ b/paper-api/src/main/java/org/bukkit/command/defaults/PluginsCommand.java @@ -45,6 +45,10 @@ public class PluginsCommand extends BukkitCommand { pluginList.append(plugin.isEnabled() ? ChatColor.GREEN : ChatColor.RED); pluginList.append(plugin.getDescription().getName()); + + if (plugin.getDescription().getProvides().size() > 0) { + pluginList.append(" (").append(String.join(", ", plugin.getDescription().getProvides())).append(")"); + } } return "(" + plugins.length + "): " + pluginList.toString(); diff --git a/paper-api/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java b/paper-api/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java index cb31a6d5a..70d508190 100644 --- a/paper-api/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java +++ b/paper-api/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java @@ -64,6 +64,10 @@ import org.yaml.snakeyaml.nodes.Tag; *
providesversion* A plugin.yml example:
*name: Inferno
+ *provides: [Hell]
*version: 1.4.1
*description: This plugin is so 31337. You can set yourself on fire.
*# We could place every author in the authors list, but chose not to for illustrative purposes
@@ -218,6 +223,7 @@ public final class PluginDescriptionFile {
};
String rawName = null;
private String name = null;
+ private List provides = ImmutableList.of();
private String main = null;
private String classLoaderOf = null;
private List depend = ImmutableList.of();
@@ -299,6 +305,37 @@ public final class PluginDescriptionFile {
return name;
}
+ /**
+ * Gives the list of other plugin APIs which this plugin provides.
+ * These are usable for other plugins to depend on.
+ *
+ * - Must consist of all alphanumeric characters, underscores, hyphon,
+ * and period (a-z,A-Z,0-9, _.-). Any other character will cause the
+ * plugin.yml to fail loading.
+ *
- A different plugin providing the same one or using it as their name
+ * will not result in the plugin to fail loading.
+ *
- Case sensitive.
+ *
- An entry of this list can be referenced in {@link #getDepend()},
+ * {@link #getSoftDepend()}, and {@link #getLoadBefore()}.
+ *
provides must be in YAML list
+ * format.
+ *
+ *
+ * In the plugin.yml, this entry is named provides.
+ *
+ * Example:
+ *
provides:
+ *- OtherPluginName
+ *- OldPluginName
+ *
+ * @return immutable list of the plugin APIs which this plugin provides
+ */
+ @NotNull
+ public List getProvides() {
+ return provides;
+ }
+
/**
* Gives the version of the plugin.
*
@@ -459,7 +496,7 @@ public final class PluginDescriptionFile {
* plugin in the network,
* all plugins in that network will fail.
- * depend must be in must be in depend must be in YAML list
* format.
*
@@ -923,6 +960,8 @@ public final class PluginDescriptionFile {
throw new InvalidDescriptionException(ex, "name is of wrong type");
}
+ provides = makePluginNameList(map, "provides");
+
try {
version = map.get("version").toString();
} catch (NullPointerException ex) {
@@ -1080,6 +1119,9 @@ public final class PluginDescriptionFile {
Map map = new HashMap();
map.put("name", name);
+ if (provides != null) {
+ map.put("provides", provides);
+ }
map.put("main", main);
map.put("version", version);
map.put("order", order.toString());
diff --git a/paper-api/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/paper-api/src/main/java/org/bukkit/plugin/SimplePluginManager.java
index 844adf514..d92a24acf 100644
--- a/paper-api/src/main/java/org/bukkit/plugin/SimplePluginManager.java
+++ b/paper-api/src/main/java/org/bukkit/plugin/SimplePluginManager.java
@@ -123,6 +123,7 @@ public final class SimplePluginManager implements PluginManager {
Map plugins = new HashMap();
Set loadedPlugins = new HashSet();
+ Map pluginsProvided = new HashMap<>();
Map> dependencies = new HashMap>();
Map> softDependencies = new HashMap>();
@@ -165,6 +166,38 @@ public final class SimplePluginManager implements PluginManager {
));
}
+ String removedProvided = pluginsProvided.remove(description.getName());
+ if (removedProvided != null) {
+ server.getLogger().warning(String.format(
+ "Ambiguous plugin name `%s'. It is also provided by `%s'",
+ description.getName(),
+ removedProvided
+ ));
+ }
+
+ for (String provided : description.getProvides()) {
+ File pluginFile = plugins.get(provided);
+ if (pluginFile != null) {
+ server.getLogger().warning(String.format(
+ "`%s provides `%s' while this is also the name of `%s' in `%s'",
+ file.getPath(),
+ provided,
+ pluginFile.getPath(),
+ directory.getPath()
+ ));
+ } else {
+ String replacedPlugin = pluginsProvided.put(provided, description.getName());
+ if (replacedPlugin != null) {
+ server.getLogger().warning(String.format(
+ "`%s' is provided by both `%s' and `%s'",
+ provided,
+ description.getName(),
+ replacedPlugin
+ ));
+ }
+ }
+ }
+
Collection softDependencySet = description.getSoftDepend();
if (softDependencySet != null && !softDependencySet.isEmpty()) {
if (softDependencies.containsKey(description.getName())) {
@@ -224,7 +257,7 @@ public final class SimplePluginManager implements PluginManager {
dependencyIterator.remove();
// We have a dependency not found
- } else if (!plugins.containsKey(dependency)) {
+ } else if (!plugins.containsKey(dependency) && !pluginsProvided.containsKey(dependency)) {
missingDependency = false;
pluginIterator.remove();
softDependencies.remove(plugin);
@@ -249,7 +282,7 @@ public final class SimplePluginManager implements PluginManager {
String softDependency = softDependencyIterator.next();
// Soft depend is no longer around
- if (!plugins.containsKey(softDependency)) {
+ if (!plugins.containsKey(softDependency) && !pluginsProvided.containsKey(softDependency)) {
softDependencyIterator.remove();
}
}
@@ -265,8 +298,14 @@ public final class SimplePluginManager implements PluginManager {
missingDependency = false;
try {
- result.add(loadPlugin(file));
- loadedPlugins.add(plugin);
+ Plugin loadedPlugin = loadPlugin(file);
+ if (loadedPlugin != null) {
+ result.add(loadedPlugin);
+ loadedPlugins.add(loadedPlugin.getName());
+ loadedPlugins.addAll(loadedPlugin.getDescription().getProvides());
+ } else {
+ server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'");
+ }
continue;
} catch (InvalidPluginException ex) {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'", ex);
@@ -290,8 +329,14 @@ public final class SimplePluginManager implements PluginManager {
pluginIterator.remove();
try {
- result.add(loadPlugin(file));
- loadedPlugins.add(plugin);
+ Plugin loadedPlugin = loadPlugin(file);
+ if (loadedPlugin != null) {
+ result.add(loadedPlugin);
+ loadedPlugins.add(loadedPlugin.getName());
+ loadedPlugins.addAll(loadedPlugin.getDescription().getProvides());
+ } else {
+ server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'");
+ }
break;
} catch (InvalidPluginException ex) {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "'", ex);
@@ -352,6 +397,9 @@ public final class SimplePluginManager implements PluginManager {
if (result != null) {
plugins.add(result);
lookupNames.put(result.getDescription().getName(), result);
+ for (String provided : result.getDescription().getProvides()) {
+ lookupNames.putIfAbsent(provided, result);
+ }
}
return result;
@@ -796,7 +844,17 @@ public final class SimplePluginManager implements PluginManager {
Preconditions.checkArgument(plugin != null, "plugin");
Preconditions.checkArgument(depend != null, "depend");
- return dependencyGraph.nodes().contains(plugin.getName()) && Graphs.reachableNodes(dependencyGraph, plugin.getName()).contains(depend.getName());
+ if (dependencyGraph.nodes().contains(plugin.getName())) {
+ if (Graphs.reachableNodes(dependencyGraph, plugin.getName()).contains(depend.getName())) {
+ return true;
+ }
+ for (String provided : depend.getProvides()) {
+ if (Graphs.reachableNodes(dependencyGraph, plugin.getName()).contains(provided)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
@Override