-
Notifications
You must be signed in to change notification settings - Fork 114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Not able to register event handlers in onClose
, unless I scheduleSyncDelayedTask
#348
Comments
Not necessarily a bad thing, in fact it's often better that way. Not that it matters that much, but yeah you'll want to avoid having 100s of listeners.
This sounds counterproductive. Not that I've looked at your code in detail, but in general there's very little reason to unregister listeners especially if you intend to re-register them again and so on. Registering or unregistering listeners is bad for performance because the HandlerList needs to be rebaked each time. At least, as far as I've understood it. You can read more about it or ask in the SpigotMC or PaperMC Discord servers, for example, here is an old answer in the SpigotMC Discord. As for this issue you're reporting, I don't know exactly what's causing it, but if you want to keep debugging it I would suggest setting some breakpoints to verify what happens when you try to register the event handler. It's not clear to me whether you've verified that the event listener doesn't get registered at all or whether one (or more) events didn't fire, but maybe the listener is in fact still registered. Either way here are a few possible causes that I would also investigate:
Of course, if there's a problem in AnvilGUI, then we should fix it. So please do investigate this and report your findings. 🙂 |
My understanding was that this was only really a problem if you were unregistering from all different event handlers, but I'm only unregistering from InventoryClickEvent and InventoryOpenEvent. However, the helpers in the SpigotMC Discord certainly seem very against it, and most of the responses I've seen are for GUIs. So, I might stop doing this, but it's worth noting that I think AnvilGUI is doing the same thing.
I haven't directly checked if the event listener has been registered, but, if I close the search GUI while nobody else is viewing a GUI, neither InventoryCloseEvent nor InventoryClickEvent are fired. But then, if someone else opens a GUI while I'm still looking at mine, they start being fired again, which I can only assume means the event listener wasn't registered the first time. I'll double-check, though!
I'm on the latest version
This is not actually something I knew and I'm pretty sure I'm currently doing what is being advised against here😅I imagine it would be documented if this also applied to InventoryCloseEvent, though. |
Double-checked now by doing this System.out.println(Arrays.toString(InventoryCloseEvent.getHandlerList().getRegisteredListeners())); And you're right, it is being registered
but for some reason the events aren't being fired🤨But then, if I re-register it, the output of the above code doesn't change, but they start being fired. |
Regarding the warning about not opening inventories from |
I could be wrong, but I think the rebaking has to happen whenever any listener is registered or unregistered. It could be that the server waits until the end of the tick or something to do it (so that multiple registrations are batched together), but either way I think it's "best practice" to register listeners once, when your plugin starts. Of course, there are some exceptions, like if the user changes the config and a listener is no longer needed at all (in which case, unregistering can make sense). Now, in the end, the performance impact of (un)registering listeners all the time might not be that noticeable if your server doesn't have many plugins installed (i.e. there are not that many listeners to rebake), so again, it's a best practice, but probably not the end of the world if you don't follow it. And you're right, AnvilGUI is also not following best practice here, in fact AnvilGUI is registering and unregistering a listener each time the anvil is opened, for each player. To be honest I was not aware of this issue, I was not involved in the initial development of AnvilGUI. Fixing this now would require a bit of refactoring, which is extra tricky in AnvilGUI since this is a library that many people depend on, and ideally we want to avoid accidentally breaking existing functionality in the plugins which use AnvilGUI. If someone has evidence that the performance impact for AnvilGUI is large, then it might be a good idea to investigate such a refactor, but otherwise, I think it's pretty low priority.
Yeah one would hope so, but you never know with the Bukkit documentation. If it's a real close event triggered by the player pressing the escape key or something, I think it's safe to do most inventory-related things in the close event handler, but I could be wrong. The Bukkit Javadocs I linked does warn that it's "not an exhaustive list".
I'm pretty sure Builder.open just directly opens the inventory, which may also involve closing any previously opened inventory. If you want to do this from a click event, I would probably wrap it in a task. |
I get that it would need to rebake, but I thought each event had a distinct handler list meaning the scope of the rebaking would be limited? I honestly have no idea though lol
I thought that was just referring to the list of methods not to use in InventoryClickEvent? |
Yeah that's a good point, I think you're right about that. But inventory listeners are pretty common among plugins, so I still think the rebaking argument can be valid. Especially if other plugins register multiple inventory listeners.
Probably yes, but it's also an indication that some things are undocumented and that inventories are quite finicky in general. |
@hopperelec I just had a look at the Spigot source code and can confirm that it looks like my theory is correct, strange and undefined behavior will happen if you open an inventory from a close event (AnvilGUI's I would argue that regardless, this is a documentation issue on Spigot's side, because even though I'll keep this issue open for the time being because I think AnvilGUI should also warn about this or maybe even schedule the click/close handlers as tasks (though it should probably still be optional). |
This is a bit of a strange issue and is likely to be more of a Bukkit-related issue so I'm not expecting a "fix" to be made in AnvilGUI, but I imagine the issue is being caused by something AnvilGUI is doing and I don't know what that could be so I wouldn't really know what to ask in any Bukkit-related forums so hopefully it's ok to ask about it here.
Basically, my plugin uses a custom GUI system and I insist on only using one listener (GUILIstener) for handling inventory-related events for all these GUIs. I also insist on this listener only being registered when one of my plugin's GUIs is actually open. So, whenever one of my plugin's GUIs is opened, I register the listener, and then I unregister the listener once the inventory is closed.
I am using AnvilGUI to allow players to search through my plugin's paginated GUIs. So, when the AnvilGUI is closed, I re-open the paginated GUI. As a result, my plugin tries to re-register the GUIListener. However, for some reason it doesn't actually start listening, but it does if I re-open the inventory from outside of
onClose
or within ascheduleSyncDelayedTask
.My first guess was that this was because
onClose
was being executed outside of the main thread but, looking at AnvilGUI's source, it seems that it just stems fromonInventoryClose
(which callscloseInventory(false)
) which, as a Bukkit event, should be executed on the main thread.Of course, there's not really any problems with me just using
scheduleSyncDelayedTask
to get around this, but I'm very curious what could be causing this and I'm also worried that it could cause further issues down the line. Any ideas?The text was updated successfully, but these errors were encountered: