diff --git a/design/log.md b/design/log.md index c53e1ec..21253ba 100644 --- a/design/log.md +++ b/design/log.md @@ -130,6 +130,13 @@ description: Chronological record of material decisions affecting the Spigot Bas - Preserved unit-test coverage through server-independent dialog specifications and adapted Bukkit test fixtures to Purpur's registry-aware API behavior. - Verified 128 tests and the Java 25 plugin artifact with `./gradlew clean check jar`. +## 2026-08-25 — Static dialog command actions + +- Replaced macro command templates with static run-command actions for fixed dialog buttons. +- Added regression coverage for the generated run-command action and its unchanged command payload. +- Verified `/basesettings` opens without command exceptions on a local Purpur 26.2 build 2618 server. +- Verified the plugin artifact with `./gradlew clean check jar`. + ## 2026-08-24 — Pocket Base mob portal travel - Added five-tick collision scanning that transports non-player living mobs through active Pocket Base entrance and return portals. diff --git a/design/user-stories/us-020-control-base-through-dialog-ui.md b/design/user-stories/us-020-control-base-through-dialog-ui.md index 56260c7..e11d372 100644 --- a/design/user-stories/us-020-control-base-through-dialog-ui.md +++ b/design/user-stories/us-020-control-base-through-dialog-ui.md @@ -2,7 +2,7 @@ type: User Story title: "US-020: Control a base through a dialog UI" description: Let players inspect and control their base through Minecraft's native dialog interface. -status: in-progress +status: done --- # US-020: Control a base through a dialog UI @@ -21,7 +21,9 @@ As a **player**, I want a dialog-based base dashboard so that I can inspect prog - [x] `ui` is offered through command autocomplete. - [x] Non-player execution remains safely rejected. - [x] Automated tests verify dialog routing and generated controls. -- [ ] The dialog uses Purpur's supported Paper dialog API and opens on the production Purpur 26.2 runtime without missing-class or command exceptions. +- [x] Fixed dialog commands use Purpur static run-command actions rather than macro templates. +- [x] A rendering regression test verifies fixed command buttons do not throw `No variables in macro`. +- [x] The dialog uses Purpur's supported Paper dialog API and opens on the production Purpur 26.2 runtime without missing-class or command exceptions. ## Related diff --git a/src/main/java/games/dmg/spigotbase/BaseSettingsDialogFactory.java b/src/main/java/games/dmg/spigotbase/BaseSettingsDialogFactory.java index 2c68998..4bd3adb 100644 --- a/src/main/java/games/dmg/spigotbase/BaseSettingsDialogFactory.java +++ b/src/main/java/games/dmg/spigotbase/BaseSettingsDialogFactory.java @@ -12,6 +12,7 @@ import java.util.Arrays; import java.util.List; import java.util.Locale; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; final class BaseSettingsDialogFactory { private static final int DIALOG_WIDTH = 420; @@ -366,13 +367,17 @@ final class BaseSettingsDialogFactory { private static ActionButton render(ButtonSpec button) { ActionButton.Builder builder = ActionButton.builder(Component.text(button.label())) .width(button.width()) - .action(DialogAction.commandTemplate(button.command())); + .action(DialogAction.staticAction(commandClick(button.command()))); if (!button.tooltip().isEmpty()) { builder.tooltip(Component.text(button.tooltip())); } return builder.build(); } + static ClickEvent commandClick(String command) { + return ClickEvent.runCommand(command); + } + sealed interface DialogSpec permits ListSpec, MultiSpec, ConfirmationSpec, NoticeSpec { DialogContent content(); } diff --git a/src/test/java/games/dmg/spigotbase/BaseSettingsDialogFactoryTest.java b/src/test/java/games/dmg/spigotbase/BaseSettingsDialogFactoryTest.java index d49b1c6..58d9a26 100644 --- a/src/test/java/games/dmg/spigotbase/BaseSettingsDialogFactoryTest.java +++ b/src/test/java/games/dmg/spigotbase/BaseSettingsDialogFactoryTest.java @@ -10,9 +10,24 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; +import net.kyori.adventure.text.event.ClickEvent; import org.junit.jupiter.api.Test; final class BaseSettingsDialogFactoryTest { + @Test + void createsStaticRunCommandActionWithoutMacroVariables() { + ClickEvent action = BaseSettingsDialogFactory.commandClick( + "/basesettings status" + ); + + assertEquals(ClickEvent.Action.RUN_COMMAND, action.action()); + ClickEvent.Payload.Text payload = assertInstanceOf( + ClickEvent.Payload.Text.class, + action.payload() + ); + assertEquals("/basesettings status", payload.value()); + } + @Test void createsControlsForEveryBaseSettingAndConfirmedPurchase() { UUID playerId = UUID.randomUUID();