diff --git a/prompt-ui-26.1/src/main/java/dev/cyr1en/promptui/v26_1/FrameworkAnvilScreen.java b/prompt-ui-26.1/src/main/java/dev/cyr1en/promptui/v26_1/FrameworkAnvilScreen.java index 28f08bb..f2458e3 100644 --- a/prompt-ui-26.1/src/main/java/dev/cyr1en/promptui/v26_1/FrameworkAnvilScreen.java +++ b/prompt-ui-26.1/src/main/java/dev/cyr1en/promptui/v26_1/FrameworkAnvilScreen.java @@ -124,7 +124,8 @@ private void openOnPlayerThread() { plugin .getSLF4JLogger() .debug("FrameworkAnvilScreen result: player={}", player.getName()); - complete(ScreenResult.answer(answer), true); + event.setCancelled(true); + completeAfterClick(ScreenResult.answer(answer)); }); anvilGui.createInventory(); @@ -241,7 +242,8 @@ private void setupItems() { plugin .getSLF4JLogger() .debug("FrameworkAnvilScreen cancel: player={}", player.getName()); - complete(ScreenResult.manualCancel(), true); + event.setCancelled(true); + completeAfterClick(ScreenResult.manualCancel()); }); anvilGui.getSecondItemComponent().addItem(cancelGuiItem, 0, 0); } @@ -295,6 +297,24 @@ public void close() { scheduleCleanup(gui, impl, true); } + /** + * Finishes a click-triggered result on the next tick. Closing the anvil inside the click event + * left the client holding its predicted cursor item (a copy of the input), which creative-mode + * players could then keep. Waiting one tick lets the server resync the cancelled click first. + */ + private void completeAfterClick(ScreenResult result) { + try { + ScheduledTask task = + player.getScheduler().run(plugin, ignored -> complete(result, true), null); + if (task != null) { + return; + } + } catch (Throwable ignored) { + // Fall through and finish now. + } + complete(result, true); + } + private void complete(ScreenResult result, boolean closePlayer) { AnvilGui gui; AnvilInventoryImpl impl; diff --git a/prompt-ui-26.2/src/main/java/dev/cyr1en/promptui/v26_2/FrameworkAnvilScreen.java b/prompt-ui-26.2/src/main/java/dev/cyr1en/promptui/v26_2/FrameworkAnvilScreen.java index 8628a30..7446a9c 100644 --- a/prompt-ui-26.2/src/main/java/dev/cyr1en/promptui/v26_2/FrameworkAnvilScreen.java +++ b/prompt-ui-26.2/src/main/java/dev/cyr1en/promptui/v26_2/FrameworkAnvilScreen.java @@ -119,7 +119,8 @@ private void openOnPlayerThread() { plugin .getSLF4JLogger() .debug("FrameworkAnvilScreen result: player={}", player.getName()); - complete(ScreenResult.answer(answer), true); + event.setCancelled(true); + completeAfterClick(ScreenResult.answer(answer)); }); anvilGui.createInventory(); @@ -238,7 +239,8 @@ private void setupItems() { plugin .getSLF4JLogger() .debug("FrameworkAnvilScreen cancel: player={}", player.getName()); - complete(ScreenResult.manualCancel(), true); + event.setCancelled(true); + completeAfterClick(ScreenResult.manualCancel()); }); anvilGui.getSecondItemComponent().addItem(cancelGuiItem, 0, 0); } @@ -292,6 +294,24 @@ public void close() { scheduleCleanup(gui, impl, true); } + /** + * Finishes a click-triggered result on the next tick. Closing the anvil inside the click event + * left the client holding its predicted cursor item (a copy of the input), which creative-mode + * players could then keep. Waiting one tick lets the server resync the cancelled click first. + */ + private void completeAfterClick(ScreenResult result) { + try { + ScheduledTask task = + player.getScheduler().run(plugin, ignored -> complete(result, true), null); + if (task != null) { + return; + } + } catch (Throwable ignored) { + // Fall through and finish now. + } + complete(result, true); + } + private void complete(ScreenResult result, boolean closePlayer) { AnvilGui gui; AnvilInventoryImpl impl; diff --git a/prompt-ui-26.3/src/main/java/dev/cyr1en/promptui/v26_3/FrameworkAnvilScreen.java b/prompt-ui-26.3/src/main/java/dev/cyr1en/promptui/v26_3/FrameworkAnvilScreen.java index 72b7dcd..5a627da 100644 --- a/prompt-ui-26.3/src/main/java/dev/cyr1en/promptui/v26_3/FrameworkAnvilScreen.java +++ b/prompt-ui-26.3/src/main/java/dev/cyr1en/promptui/v26_3/FrameworkAnvilScreen.java @@ -119,7 +119,8 @@ private void openOnPlayerThread() { plugin .getSLF4JLogger() .debug("FrameworkAnvilScreen result: player={}", player.getName()); - complete(ScreenResult.answer(answer), true); + event.setCancelled(true); + completeAfterClick(ScreenResult.answer(answer)); }); anvilGui.createInventory(); @@ -238,7 +239,8 @@ private void setupItems() { plugin .getSLF4JLogger() .debug("FrameworkAnvilScreen cancel: player={}", player.getName()); - complete(ScreenResult.manualCancel(), true); + event.setCancelled(true); + completeAfterClick(ScreenResult.manualCancel()); }); anvilGui.getSecondItemComponent().addItem(cancelGuiItem, 0, 0); } @@ -292,6 +294,24 @@ public void close() { scheduleCleanup(gui, impl, true); } + /** + * Finishes a click-triggered result on the next tick. Closing the anvil inside the click event + * left the client holding its predicted cursor item (a copy of the input), which creative-mode + * players could then keep. Waiting one tick lets the server resync the cancelled click first. + */ + private void completeAfterClick(ScreenResult result) { + try { + ScheduledTask task = + player.getScheduler().run(plugin, ignored -> complete(result, true), null); + if (task != null) { + return; + } + } catch (Throwable ignored) { + // Fall through and finish now. + } + complete(result, true); + } + private void complete(ScreenResult result, boolean closePlayer) { AnvilGui gui; AnvilInventoryImpl impl;