Repository navigation
Conversation
There was a problem hiding this comment.
🔵 Needs a closer look
Threading changes routing simulateItemUse to the main thread require live Paper/Folia verification and per-block sync cost assessment that cannot be performed here, warranting deferral to quorum.
No open issues 🎉
What changed in this PR
This PR fixes issue #3613, where item brushes (e.g. //brush apply sphere item red_wool) threw IllegalStateException: BlockCanBuildEvent may only be triggered synchronously. FAWE edits run on async worker threads, but simulateItemUse ultimately fires Bukkit events (via the NMS BlockItem.canPlace/BlockCanBuildEvent path) that require the main thread. The delegate adapter now wraps the parent call in TaskManager.taskManager().sync(...), hopping to the main thread (and running inline when already on it) before performing the simulated item use.
Changes:
- Wrap
getParent().simulateItemUse(...)inTaskManager.taskManager().sync(...)so the simulated item use (and its synchronous events) runs on the main thread. - Add the
TaskManagerimport.
| File | Description |
|---|---|
worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IDelegateBukkitImplAdapter.java |
Routes simulateItemUse through TaskManager.sync to execute on the main thread, and imports TaskManager. |
Assessment: The change is minimal, correct, and idiomatic. TaskManager.taskManager().sync(...) is the established FAWE pattern for Bukkit API calls that must be synchronous when invoked from async edit threads (used across ~52 files, e.g. IBukkitAdapter.java:391, BukkitWorld.java:152, WorldWrapper.java:272). The delegate adapter is confirmed to be in the call path (matching the issue's stack trace), and the parent PaperweightAdapter.simulateItemUse performs the event-firing placement directly, so the delegate is the appropriate place for this fix. sync returns directly when already on the main thread (no self-deadlock), and the boxed Boolean result is never null, so auto-unboxing is safe. I found no objective defects to comment on.
Review effort: Balanced
|
Tested this on a live Paper server, comparing the CI build of this PR against the CI build of its base commit. Setup: Paper
Steps:
The exact repro from #3613 ( Per-block sync cost: I timed the radius-12 stroke by polling the red wool count over RCON every ~60 ms. From the first block to the last took 1.43 s for 3,189 blocks (≈2,200 blocks/s, ≈110 per tick). During the strokes:
The main thread works through the queued item uses inside the normal Stack trace on the base commitStroke timer output (after)Not tested: Folia. This was also a single machine and a single plugin, so it isn't a full benchmark. |
|
@MattBDev look over this whenever you're able to. |


Fixes #3613
Item brushes no longer throw when placing blocks.