Stop skills from retaining every event they handle - #152
Conversation
Each skill kept a HashSet of every event passed to handle(), so that an event registered under more than one trigger was only acted on once. The set was never cleared, so every handled event -- and the block, player and entities it references -- stayed reachable for the lifetime of the server. The duplicate delivery is now prevented at its source: a skill registers a listener only for the event classes its trigger methods accept, and each listener forwards only events of the exact class it was registered for, since Bukkit delivers an event to registrations made for any class sharing its handler list. handle() already dispatches on the event's exact class, so nothing else changes about which trigger runs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Self-review rubric (scored against the diff and command output, not judgement):
Judgement call left for a reviewer rather than fixed unilaterally: narrowing Two observations fall outside the diff and have been filed rather than folded in:
This review was performed and posted during a Gardener session (https://github.com/Stephenson-Software/gardener). drafted by Claude on behalf of Daniel Stephenson |
Every skill kept a
HashSetof every event it had ever handled, and nothing ever removed an entry, so each handled event — and the block, player and entities it references — stayed reachable for as long as the server ran.The set existed only to stop a skill acting twice on one event. That duplicate is now prevented where it originated, so the memo is no longer needed and has been removed.
What changed
register()previously registered a listener for all twelve values ofTriggersfor every skill, even thoughhandle(Event)discards an event no trigger method accepts. Registration is now driven by the trigger methods found on the class, which for the skills in this repository is between one and three listeners each instead of twelve.handle(Event)was already on the event's exact class, so the filter changes nothing about which trigger method runs.calledEventsset is gone, along with the retention it caused.getPluginManager()seam was added, becauseBukkit.getPluginManager()reads static server state that a unit test has no server to provide.The event classes named by the skills' constructors are exactly the twelve values of
Triggers, so no skill loses a listener it was relying on.Test plan
mvn test— 36 tests, all passing (33 before, 3 added)Field 'calledEvents' retains the handled event, plus the two registration assertions), and pass once the change is restoredhandle_doesNotRetainTheEventItHandled, which asserts that no field of the skill holds the event after it has been handledregister_registersOnlyTheEventsTheSkillHasATriggerMethodForandregister_deliversAnEventToItsTriggerMethodOnlyOnce.testcontainerSpigot harness is not run in CI and was not run here. A smoke test on a real server is worth doing before this reaches users.Documentation
No command, permission node or configuration key changes, so
HelpCommand.java,COMMANDS.md,USER_GUIDE.mdandCONFIG.mdare unaffected. AFixedentry has been added toCHANGELOG.mdunder[Unreleased].Issues deferred this cycle
The remaining open issues were left untouched: #87, #109, #97, #127 and #88 are feature or persistence work larger than one polish-sized change; #128, #129, #124, #112, #119 and #140 already have a draft pull request open against them (#131, #130, #132, #118, #120, #141); #116 changes
pom.xml, which is on this loop's do-not-auto-merge list and is better handled where a human can approve the dependency bump; #77, #86, #89 and #90 are feature requests.Closes #149
This PR description was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).
drafted by Claude on behalf of Daniel Stephenson