Conversation
RobertWesner
left a comment
There was a problem hiding this comment.
Works, but the code has some minor edges that we might want to change.
| } catch (UnknownDependencyException ex) { | ||
| server.getLogger().log(Level.SEVERE, "Could not load '" + plannedPlugin.file.getPath() + "' in folder '" + directory.getPath() + "': " + ex.getMessage(), ex); | ||
| } catch (InvalidPluginException ex) { | ||
| server.getLogger().log(Level.SEVERE, "Could not load '" + plannedPlugin.file.getPath() + "' in folder '" + directory.getPath() + "': ", ex.getCause()); | ||
| } catch (InvalidDescriptionException ex) { | ||
| server.getLogger().log(Level.SEVERE, "Could not load '" + plannedPlugin.file.getPath() + "' in folder '" + directory.getPath() + "': " + ex.getMessage(), ex); |
There was a problem hiding this comment.
- multi-catch would be beneficial here, as all catches are (almost¹) exactly the same
- ¹ InvalidDescriptionException is missing the message but has the colon and using
ex.getCause()instead ofex - in my opinion you don't need to attach the previous exception message, the cause exists for that purpose, the information is practically included twice.
| } catch (UnknownDependencyException ex) { | |
| server.getLogger().log(Level.SEVERE, "Could not load '" + plannedPlugin.file.getPath() + "' in folder '" + directory.getPath() + "': " + ex.getMessage(), ex); | |
| } catch (InvalidPluginException ex) { | |
| server.getLogger().log(Level.SEVERE, "Could not load '" + plannedPlugin.file.getPath() + "' in folder '" + directory.getPath() + "': ", ex.getCause()); | |
| } catch (InvalidDescriptionException ex) { | |
| server.getLogger().log(Level.SEVERE, "Could not load '" + plannedPlugin.file.getPath() + "' in folder '" + directory.getPath() + "': " + ex.getMessage(), ex); | |
| } catch (UnknownDependencyException | InvalidPluginException | InvalidDescriptionException ex) { | |
| server.getLogger().log(Level.SEVERE, "Could not load '" + plannedPlugin.file.getPath() + "' in folder '" + directory.getPath() + "'.", ex); |
| try { | ||
| plugin.getPluginLoader().enablePlugin(plugin); | ||
| // Record successful enables so shutdown can run in strict reverse dependency order. | ||
| if (plugin.isEnabled() && !enableOrder.contains(plugin)) { |
There was a problem hiding this comment.
In what scenario could the second condition !enableOrder.contains(plugin) be relevant?
It could only ever reach here when its not already enabled.
Sounds like its a defensive check that will never actually happen ^^
| return plugin.getDescription().getLoad().ordinal() <= type.ordinal(); | ||
| } | ||
|
|
||
| private boolean enablePlugin(Plugin plugin, PluginLoadOrder type, Set<String> enabling) { |
There was a problem hiding this comment.
I don't fully understand why this complexity is needed.
Is it just to ensure startup plugins get loaded first and remaining plugins get loaded afterwards?
Why not just .filter() the plugin load order beforehand into those that run on startup and those who run post world load?
How is a a startup plugin depending on postworld handled?
| } catch (YAMLException ex) { | ||
| throw new InvalidPluginException(ex); | ||
| } finally { | ||
| if (stream != null) { |
There was a problem hiding this comment.
you could use try-with-resources since java7 on both stream and jar, which in my opinion is much cleaner than checking for being null in finally
|
|
||
| try { | ||
| description = getPluginDescription(file); | ||
| } catch (InvalidPluginException ex) { |
There was a problem hiding this comment.
this also could be a multi catch, and InvalidPluginException is missing the message (which imo can be omitted from both) and is using ex.getCause instead of ex
| import java.util.regex.Matcher; | ||
| import java.util.regex.Pattern; | ||
|
|
||
| public final class PluginLoadPlanner { |
| private final Map<Boolean, Set<Permission>> defaultPerms = new LinkedHashMap<Boolean, Set<Permission>>(); | ||
| private final Map<String, Map<Permissible, Boolean>> permSubs = new HashMap<String, Map<Permissible, Boolean>>(); | ||
| private final Map<Boolean, Map<Permissible, Boolean>> defSubs = new HashMap<Boolean, Map<Permissible, Boolean>>(); | ||
| private final List<Plugin> enableOrder = new ArrayList<Plugin>(); |
There was a problem hiding this comment.
Why do we have the generic types on all new? It can be inferred by compiler (and IDE). Just stylistic choice?
| if ((!plugin.isEnabled()) && (plugin.getDescription().getLoad() == type)) { | ||
| loadPlugin(plugin); | ||
| // Re-evaluate every disabled plugin on each phase so deferred dependencies can come alive later. | ||
| if ((!plugin.isEnabled()) && shouldAttemptEnable(plugin, type)) { |
There was a problem hiding this comment.
| if ((!plugin.isEnabled()) && shouldAttemptEnable(plugin, type)) { | |
| if (!plugin.isEnabled() && shouldAttemptEnable(plugin, type)) { |

📌 Pull Request
Description
Improve plugin load, enable, and disable ordering by introducing a plugin load order planner.
Behaviour:
Related Issues / Discussions
Fixes issues discussed in the RetroMC Discord with Zavdav and RobertWesner
Motivation & Context
Fixes several bugs regarding plugin loading, enabling, and disabling.
Type of Change
Please tick all that apply:
Testing Performed
mvn clean packageTest details:
Compatibility Considerations
Compatibility Notes
This PR shouldn't break compatibility of plugins with correct plugin.yml files.
Checklist
Please confirm the following: