package com.w67clement.mineapi.utils; import com.w67clement.mineapi.api.ReflectionAPI; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.net.URLClassLoader; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.stream.Collectors; import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.PluginIdentifiableCommand; import org.bukkit.command.SimpleCommandMap; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.InvalidDescriptionException; import org.bukkit.plugin.InvalidPluginException; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.UnknownDependencyException; import org.bukkit.plugin.java.JavaPlugin; /** * An plugin manager utils class * * @author w67clement */ public class PluginManagerUtils { /** * Gets the jar file of an plugin. * * @param plugin Plugin * * @return The plugin's JarFile. */ public static File getPluginFile(Plugin plugin) { File file; file = (File) ReflectionAPI.getValue(plugin, ReflectionAPI.getField(JavaPlugin.class, "file", true)); return file; } public static File findPluginFile(String pluginName) { File file = null; Plugin plugin = Bukkit.getPluginManager().getPlugin(pluginName); if (getPluginFile(plugin) == null) { // Plugins folder File pluginsFolder = new File("plugins/"); // Verify all files for (File pluginFile : pluginsFolder.listFiles()) { if (pluginFile.isFile()) { if (pluginFile.getName().endsWith(".jar")) { // Verify plugin.yml try { FileConfiguration config = getPluginDescription(pluginFile); assert config != null; if (config.getString("name").equals(pluginName)) { file = pluginFile; } } catch (InvalidPluginException e) { e.printStackTrace(); } } } } } else { file = getPluginFile(plugin); } return file; } public static FileConfiguration getPluginDescription(File file) throws InvalidPluginException { if (file.exists()) { JarFile jarFile; InputStream stream; try { jarFile = new JarFile(file); JarEntry entry = jarFile.getJarEntry("plugin.yml"); if (entry == null) { throw new InvalidPluginException(); } stream = jarFile.getInputStream(entry); return YamlConfiguration.loadConfiguration(stream); } catch (IOException e) { e.printStackTrace(); } } return null; } @SuppressWarnings({"rawtypes", "unchecked"}) public static boolean unloadPlugin(Plugin plugin) { PluginManager pm = Bukkit.getPluginManager(); if (pm == null) return false; // Plugin name String name = plugin.getName(); List<Plugin> plugins; Map<String, Plugin> lookupNames; SimpleCommandMap commandMap; Map<String, Command> knownCommands; Field commandMapField; // Gets fields. try { Field pluginsField = Bukkit.getPluginManager().getClass().getDeclaredField("plugins"); pluginsField.setAccessible(true); plugins = (List) pluginsField.get(pm); Field lookupNamesField = Bukkit.getPluginManager().getClass().getDeclaredField("lookupNames"); lookupNamesField.setAccessible(true); lookupNames = (Map) lookupNamesField.get(pm); commandMapField = Bukkit.getPluginManager().getClass().getDeclaredField("commandMap"); commandMapField.setAccessible(true); commandMap = (SimpleCommandMap) commandMapField.get(pm); Field knownCommandsField = SimpleCommandMap.class.getDeclaredField("knownCommands"); knownCommandsField.setAccessible(true); knownCommands = (Map) knownCommandsField.get(commandMap); } catch (Exception e) { e.printStackTrace(); return false; } // Disable plugin. if (plugin.isEnabled()) pm.disablePlugin(plugin); // Starting unloading.. if ((plugins != null) && (plugins.contains(plugin))) plugins.remove(plugin); if ((lookupNames != null) && (lookupNames.containsKey(name))) lookupNames.remove(name); if (commandMap != null) { HashSet<String> a = knownCommands.entrySet().stream().filter(b -> (b.getValue() instanceof PluginIdentifiableCommand) && (((PluginIdentifiableCommand) b.getValue()).getPlugin() == plugin)).map(b -> b.getKey()).collect(Collectors.toCollection(HashSet::new)); for (String c : a) { Command cmd = knownCommands.remove(c); if ((cmd != null) && (cmd instanceof PluginIdentifiableCommand) && (((PluginIdentifiableCommand) cmd).getPlugin() == plugin)) { cmd.unregister(commandMap); } else if (cmd != null) { knownCommands.put(c, cmd); } } } ClassLoader pluginClassLoader = plugin.getClass().getClassLoader(); if (pluginClassLoader instanceof URLClassLoader) { try { ((URLClassLoader) pluginClassLoader).close(); } catch (IOException e) { e.printStackTrace(); return false; } } System.gc(); return true; } public static boolean reloadPlugin(Plugin plugin) { boolean reloadSuccess; PluginManager pm = Bukkit.getPluginManager(); // Disable plugin pm.disablePlugin(plugin); String pluginName = plugin.getName(); // Unload plugin reloadSuccess = unloadPlugin(plugin); // Find the file of the plugin. File pluginFile = findPluginFile(pluginName); Plugin newPlugin = null; if (reloadSuccess) try { // Load plugin newPlugin = pm.loadPlugin(pluginFile); } catch (UnknownDependencyException e) { System.out.println("[MineAPI] Error on the loading of the plugin: '" + plugin.getName() + "', Reason: " + e.getMessage()); } catch (InvalidPluginException | InvalidDescriptionException e) { e.printStackTrace(); } if (newPlugin != null) { // Enable plugin. pm.enablePlugin(newPlugin); reloadSuccess = true; } return reloadSuccess; } public static boolean uninstallPlugin(Plugin plugin) { boolean uninstall; File pluginFile = getPluginFile(plugin); uninstall = unloadPlugin(plugin); if (uninstall) uninstall = pluginFile.delete(); return uninstall; } }