Bukkit has long had its problems with plugin life-cycles. Plugins have had no explicit control over whether they are safe to be reloaded or not, if they're shutting down or reloading during JavaPlugin#onDisable (up until #3129), and how many plugin cycles a plugin has gone through. Combine those core problems with upstream's desire to not expose plugin life-cycles through API (because think about all those non-ticking, Bukkit-implementing server softwares that never shutdown!~!!1!11!) and no wonder reloading plugins is such a nightmare.
This is where this issue comes into play. I will be writing and PRing a new plugin life-cycle API to Paper within in the next couple of days/weeks (depends on how busy I am with work). Below are my current plans for the new API which should help solve some of the problems listed below.
The reason I am opening this as an issue for discussion is so that project members, contributors, or plugin developers can give their two-cents on the current API plans and/or suggest even more plugin life-cycle API that would help them write their plugins to respect (or avoid) plugin life-cycles better.
reload Property in plugin.ymlThis property would have 3 different configuration options: always meaning the plugin is safe to be reloaded and properly handles its own life-cycle; never meaning the plugin in not safe to reload and that the reload command should skip over this plugin; same-hash (please suggest a better name) meaning that the plugin is safe to be reloaded as long as the plugin's hash (probably md5 hash due to its speed and since this isn't a security feature) hasn't been changed since the server start.
Something I'd like input on here is the default value for this property. I'm leaning towards same-hash to ensure existing compatibility while adding some safety but it could also be set to false or true idk.
getPluginReloadCount()I & getGlobalReloadCount()IThe motivation behind this API is to get the number of times the plugin/server has been run through a life-cycle (reloaded). The number of plugin cycles would be incremented each time a plugin is reloaded (forcibly or not). The number of global cycles would be incremented each time the /reload command is used.
The destination of these methods are TBD as I'm writing this before looking too deeply into implementation.
Bukkit#isStarting & Server#isStartingThis API would allow for plugins to understand what part of the plugin life-cycle they are in during JavaPlugin#onEnable
/reloadThe /reload command will have a new argument added to it, force, which will forcibly reload plugins and ignore their reload property. (Personally, I'm on the side of not documenting this in the confirmation message as I think that would train users to always use it.) Also, the /reload command will now display what plugins are reloaded and what plugins aren't.
/versionThe /version command will now display the number of global cycles or will display the number of plugin cycles if a plugin is specified.
So those are my changes that I plan on making! I'd love feedback from project members, contributors, or plugin developers on improvements or additions I could make!
I'm fully in support of the new APIs, behaviour, and especially the property in plugin.yml.
Could we also have some API to know when the server is starting and/or the plugin is loaded for the first time (e.g. in the case of PlugMan where a plugin may be loaded well into the server lifetime)?
One thing I am somewhat scared of however is when #getPluginCycles would be incremented. Would plugins like PlugMan automatically respect this (disclaimer: I do not entirely know how PlugMan works)? If so, is it only on reload, or also on unload & load?
Could we also have some API to know when the server is starting and/or the plugin is loaded for the first time (e.g. in the case of PlugMan where a plugin may be loaded well into the server lifetime)?
Yeah sure, I could add Bukkit#isStarting to compliment that Bukkit#isStopping I added in #3129
One thing I am somewhat scared of however is when #getPluginCycles would be incremented. Would plugins like PlugMan automatically respect this (disclaimer: I do not entirely know how PlugMan works)? If so, is it only on reload, or also on unload & load?
I can try my best to force plugins like PlugMan to respect the changes in this document, the cycle count shouldn't be a problem to enforce but the question is if I should break PlugMan until it specifically accounts for these new changes from Paper.
but the question is if I should break PlugMan until it specifically accounts for these new changes from Paper.
Noo, never, do not break shit; if a plugin makes others misbehave, we don't really have reason to give a shit. PlugMan should add support once the API lands, and its users should update the plugin that already causes many, many headaches.
cycles feels like a weird word to use instead of just getReloadCount lol.
and commands dont use - syntax so it should be /reload force
and prob would need like /reload safe to exhibit NEW behavior
ultimately the issue with reloading partial boils down to dependency order. loadafter is fine, but if a reloadable plugin has a loadbefore and that loadbefore plugin is not reloadable, then you have order issues.
But i think the idea is valid just going to be iffy to achieve strong enforcement of behavior.
ideally would need to bring this up w/ spigot to try to get more adoption.
Most helpful comment
Noo, never, do not break shit; if a plugin makes others misbehave, we don't really have reason to give a shit. PlugMan should add support once the API lands, and its users should update the plugin that already causes many, many headaches.