mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2025-01-07 17:07:36 +01:00
Enable plugins to register Addons (#1768)
* Enable plugins to register Addons * Pladdon approach. Loads addons as plugins. * Added auto-move for pladdons.
This commit is contained in:
parent
9fc22aa8e7
commit
6e9513f2ea
@ -33,14 +33,14 @@ public class AddonClassLoader extends URLClassLoader {
|
||||
private Addon addon;
|
||||
private AddonsManager loader;
|
||||
|
||||
public AddonClassLoader(AddonsManager addonsManager, YamlConfiguration data, File path, ClassLoader parent)
|
||||
public AddonClassLoader(AddonsManager addonsManager, YamlConfiguration data, File jarFile, ClassLoader parent)
|
||||
throws InvalidAddonInheritException,
|
||||
MalformedURLException,
|
||||
InvalidDescriptionException,
|
||||
InvalidAddonDescriptionException,
|
||||
InstantiationException,
|
||||
IllegalAccessException, InvocationTargetException, NoSuchMethodException {
|
||||
super(new URL[]{path.toURI().toURL()}, parent);
|
||||
super(new URL[]{jarFile.toURI().toURL()}, parent);
|
||||
|
||||
loader = addonsManager;
|
||||
|
||||
@ -55,7 +55,7 @@ public class AddonClassLoader extends URLClassLoader {
|
||||
throw new InvalidAddonFormatException("Package declaration cannot start with 'world.bentobox.bentobox'");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new InvalidDescriptionException("Could not load '" + path.getName() + "' in folder '" + path.getParent() + "' - " + e.getMessage());
|
||||
throw new InvalidDescriptionException("Could not load '" + jarFile.getName() + "' in folder '" + jarFile.getParent() + "' - " + e.getMessage());
|
||||
}
|
||||
|
||||
Class<? extends Addon> addonClass;
|
||||
@ -78,7 +78,7 @@ public class AddonClassLoader extends URLClassLoader {
|
||||
* @throws InvalidAddonDescriptionException - if there's a bug in the addon.yml
|
||||
*/
|
||||
@NonNull
|
||||
private AddonDescription asDescription(YamlConfiguration data) throws InvalidAddonDescriptionException {
|
||||
public static AddonDescription asDescription(YamlConfiguration data) throws InvalidAddonDescriptionException {
|
||||
AddonDescription.Builder builder = new AddonDescription.Builder(data.getString("main"), data.getString("name"), data.getString("version"))
|
||||
.authors(data.getString("authors"))
|
||||
.metrics(data.getBoolean("metrics", true))
|
||||
|
@ -0,0 +1,51 @@
|
||||
package world.bentobox.bentobox.api.addons;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
public abstract class Pladdon extends JavaPlugin {
|
||||
|
||||
private static final String ADDONS_FOLDER = "BentoBox/addons";
|
||||
|
||||
public abstract Addon getAddon();
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
String parentFolder = getFile().getParent();
|
||||
if (parentFolder == null || !parentFolder.endsWith(ADDONS_FOLDER)) {
|
||||
// Jar is in the wrong place. Let's move it
|
||||
moveJar();
|
||||
}
|
||||
}
|
||||
|
||||
public void moveJar() {
|
||||
getLogger().severe(getFile().getName() + " must be in the BentoBox/addons folder! Trying to move it there...");
|
||||
File addons = new File(getFile().getParent(), ADDONS_FOLDER);
|
||||
if (addons.exists() || addons.mkdirs()) {
|
||||
File to = new File(addons, getFile().getName());
|
||||
if (!to.exists()) {
|
||||
try {
|
||||
Files.move(getFile(), to);
|
||||
getLogger().severe(getFile().getName() + " moved successfully.");
|
||||
|
||||
} catch (IOException ex) {
|
||||
getLogger().severe("Failed to move it. " + ex.getMessage());
|
||||
getLogger().severe("Move " + getFile().getName() + " manually into the BentoBox/addons folder. Then restart server.");
|
||||
}
|
||||
} else {
|
||||
getLogger().warning(getFile().getName() + " already is in the addons folder. Delete the one in the plugins folder.");
|
||||
}
|
||||
} else {
|
||||
getLogger().severe("BentoBox addons folder could not be made! " + addons.getAbsolutePath());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -4,6 +4,8 @@ import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@ -29,6 +31,9 @@ import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginLoader;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.util.permissions.DefaultPermissions;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
@ -38,6 +43,7 @@ import world.bentobox.bentobox.api.addons.Addon;
|
||||
import world.bentobox.bentobox.api.addons.Addon.State;
|
||||
import world.bentobox.bentobox.api.addons.AddonClassLoader;
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.addons.Pladdon;
|
||||
import world.bentobox.bentobox.api.addons.exceptions.InvalidAddonDescriptionException;
|
||||
import world.bentobox.bentobox.api.addons.exceptions.InvalidAddonFormatException;
|
||||
import world.bentobox.bentobox.api.configuration.ConfigObject;
|
||||
@ -65,6 +71,8 @@ public class AddonsManager {
|
||||
private @NonNull Map<@NonNull String, @Nullable GameModeAddon> worldNames;
|
||||
private @NonNull Map<@NonNull Addon, @NonNull List<Listener>> listeners;
|
||||
|
||||
private final PluginLoader pluginLoader;
|
||||
|
||||
public AddonsManager(@NonNull BentoBox plugin) {
|
||||
this.plugin = plugin;
|
||||
addons = new ArrayList<>();
|
||||
@ -72,6 +80,42 @@ public class AddonsManager {
|
||||
classes = new HashMap<>();
|
||||
listeners = new HashMap<>();
|
||||
worldNames = new HashMap<>();
|
||||
pluginLoader = plugin.getPluginLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a plugin as an addon
|
||||
* @param parent - parent plugin
|
||||
* @param addon - addon class
|
||||
*/
|
||||
public void registerAddon(Plugin parent, Addon addon) {
|
||||
plugin.log("Registering " + parent.getDescription().getName());
|
||||
|
||||
// Get description in the addon.yml file
|
||||
// Open a reader to the jar
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(parent.getResource("addon.yml")))) {
|
||||
setAddonFile(parent, addon);
|
||||
// Grab the description in the addon.yml file
|
||||
YamlConfiguration data = new YamlConfiguration();
|
||||
data.load(reader);
|
||||
// Description
|
||||
addon.setDescription(AddonClassLoader.asDescription(data));
|
||||
// Set various files
|
||||
addon.setDataFolder(parent.getDataFolder());
|
||||
// Initialize
|
||||
initializeAddon(addon);
|
||||
sortAddons();
|
||||
|
||||
} catch (Exception e) {
|
||||
plugin.logError("Failed to register addon: " + e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void setAddonFile(Plugin parent, Addon addon) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
|
||||
Method getFileMethod = JavaPlugin.class.getDeclaredMethod("getFile");
|
||||
getFileMethod.setAccessible(true);
|
||||
addon.setFile((File) getFileMethod.invoke(parent));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,10 +153,24 @@ public class AddonsManager {
|
||||
return;
|
||||
}
|
||||
// Load the addon
|
||||
addonClassLoader = new AddonClassLoader(this, data, f, this.getClass().getClassLoader());
|
||||
try {
|
||||
|
||||
// Get the addon itself
|
||||
addon = addonClassLoader.getAddon();
|
||||
Plugin pladdon = pluginLoader.loadPlugin(f);
|
||||
if (pladdon instanceof Pladdon) {
|
||||
addon = ((Pladdon) pladdon).getAddon();
|
||||
addon.setDescription(AddonClassLoader.asDescription(data));
|
||||
} else {
|
||||
plugin.logError("Could not load pladdon!");
|
||||
return;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// Addon not pladdon
|
||||
addonClassLoader = new AddonClassLoader(this, data, f, this.getClass().getClassLoader());
|
||||
// Get the addon itself
|
||||
addon = addonClassLoader.getAddon();
|
||||
// Add to the list of loaders
|
||||
loaders.put(addon, addonClassLoader);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// We couldn't load the addon, aborting.
|
||||
plugin.logError("Could not load addon! " + e.getMessage());
|
||||
@ -123,7 +181,12 @@ public class AddonsManager {
|
||||
// Initialize some settings
|
||||
addon.setDataFolder(new File(f.getParent(), addon.getDescription().getName()));
|
||||
addon.setFile(f);
|
||||
// Initialize addon
|
||||
initializeAddon(addon);
|
||||
|
||||
}
|
||||
|
||||
private void initializeAddon(Addon addon) {
|
||||
// Locales
|
||||
plugin.getLocalesManager().copyLocalesFromAddonJar(addon);
|
||||
plugin.getLocalesManager().loadLocalesFromFile(addon.getDescription().getName());
|
||||
@ -134,10 +197,6 @@ public class AddonsManager {
|
||||
// Add it to the list of addons
|
||||
addons.remove(addon);
|
||||
addons.add(addon);
|
||||
|
||||
// Add to the list of loaders
|
||||
loaders.put(addon, addonClassLoader);
|
||||
|
||||
// Checks if this addon is compatible with the current BentoBox version.
|
||||
if (!isAddonCompatibleWithBentoBox(addon)) {
|
||||
// It is not, abort.
|
||||
@ -165,6 +224,7 @@ public class AddonsManager {
|
||||
// Unhandled exception. We'll give a bit of debug here.
|
||||
handleAddonError(addon, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -383,6 +443,7 @@ public class AddonsManager {
|
||||
// Grab the description in the addon.yml file
|
||||
YamlConfiguration data = new YamlConfiguration();
|
||||
data.load(reader);
|
||||
reader.close();
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -12,11 +12,22 @@ load: STARTUP
|
||||
|
||||
loadbefore: [Multiverse-Core, Residence]
|
||||
|
||||
softdepend: [Vault, PlaceholderAPI, dynmap, WorldEdit, WorldBorderAPI, BsbMongo, WorldGeneratorApi, AdvancedChests, LangUtils, WildStacker, LuckPerms]
|
||||
softdepend:
|
||||
- Vault
|
||||
- PlaceholderAPI
|
||||
- dynmap
|
||||
- WorldEdit
|
||||
- WorldBorderAPI
|
||||
- BsbMongo
|
||||
- WorldGeneratorApi
|
||||
- AdvancedChests
|
||||
- LangUtils
|
||||
- WildStacker
|
||||
- LuckPerms
|
||||
|
||||
permissions:
|
||||
bentobox.admin:
|
||||
description: Allows most of bentobox commands usage
|
||||
description: Allows admin command usage
|
||||
default: op
|
||||
children:
|
||||
bentobox.admin.catalog:
|
||||
|
Loading…
Reference in New Issue
Block a user