fix(settings): use Purpur dialog API
This commit is contained in:
@@ -17,7 +17,7 @@ jobs:
|
|||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: temurin
|
||||||
java-version: 17
|
java-version: 25
|
||||||
cache: gradle
|
cache: gradle
|
||||||
|
|
||||||
- name: Validate conventional commits
|
- name: Validate conventional commits
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ jobs:
|
|||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: temurin
|
||||||
java-version: 17
|
java-version: 25
|
||||||
cache: gradle
|
cache: gradle
|
||||||
|
|
||||||
- name: Set up Node.js
|
- name: Set up Node.js
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Spigot Base
|
# Spigot Base
|
||||||
|
|
||||||
A Spigot 26.2 plugin providing progression-gated player bases and quality-of-life unlocks.
|
A Purpur 26.2 plugin providing progression-gated player bases and quality-of-life unlocks.
|
||||||
|
|
||||||
Players begin by breaking Survival-mode grass blocks or dirt. The progression paths provide a persistent base, navigation particles, expanding base bounds, controlled flight, personal teleportation, and visitor teleportation.
|
Players begin by breaking Survival-mode grass blocks or dirt. The progression paths provide a persistent base, navigation particles, expanding base bounds, controlled flight, personal teleportation, and visitor teleportation.
|
||||||
|
|
||||||
@@ -8,8 +8,8 @@ The approved behavior is specified in the [OKF design bundle](design/index.md).
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Spigot 26.2
|
- Purpur 26.2 build 2618
|
||||||
- Java 17 or newer
|
- Java 25 or newer
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -9,23 +9,23 @@ version = providers.gradleProperty("releaseVersion")
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
|
maven("https://repo.purpurmc.org/snapshots/")
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
toolchain {
|
toolchain {
|
||||||
languageVersion = JavaLanguageVersion.of(17)
|
languageVersion = JavaLanguageVersion.of(25)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<JavaCompile>().configureEach {
|
tasks.withType<JavaCompile>().configureEach {
|
||||||
options.compilerArgs.addAll(listOf("-Xlint:all", "-Werror"))
|
options.compilerArgs.addAll(listOf("-Xlint:all,-deprecation,-removal", "-Werror"))
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly("org.spigotmc:spigot-api:26.2-R0.1-SNAPSHOT")
|
compileOnly("org.purpurmc.purpur:purpur-api:26.2.build.2618-stable")
|
||||||
|
|
||||||
testImplementation("org.spigotmc:spigot-api:26.2-R0.1-SNAPSHOT")
|
testImplementation("org.purpurmc.purpur:purpur-api:26.2.build.2618-stable")
|
||||||
testImplementation(platform("org.junit:junit-bom:5.13.4"))
|
testImplementation(platform("org.junit:junit-bom:5.13.4"))
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||||
testImplementation("org.mockito:mockito-core:5.18.0")
|
testImplementation("org.mockito:mockito-core:5.18.0")
|
||||||
|
|||||||
@@ -122,3 +122,10 @@ description: Chronological record of material decisions affecting the Spigot Bas
|
|||||||
- Retained the detailed chat report under `/basesettings status` and kept dialog actions routed through the existing validated command behavior.
|
- Retained the detailed chat report under `/basesettings status` and kept dialog actions routed through the existing validated command behavior.
|
||||||
- Added dialog routing, autocomplete, alias, non-player, generated-control, locked-state, and purchase-confirmation coverage.
|
- Added dialog routing, autocomplete, alias, non-player, generated-control, locked-state, and purchase-confirmation coverage.
|
||||||
- Verified the feature with `./gradlew clean check jar`.
|
- Verified the feature with `./gradlew clean check jar`.
|
||||||
|
|
||||||
|
## 2026-08-24 — Purpur dialog runtime compatibility
|
||||||
|
|
||||||
|
- Replaced the Spigot-only Bungee dialog types that were absent from production with Purpur's supported Paper dialog API.
|
||||||
|
- Compiled and tested against the exact Purpur 26.2 build 2618 API with Java 25, and updated both CI workflows to use Java 25.
|
||||||
|
- 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`.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
type: User Story
|
type: User Story
|
||||||
title: "US-012: Build and release the plugin"
|
title: "US-012: Build and release the plugin"
|
||||||
description: Give maintainers repeatable Spigot builds, automated verification, and versioned Gitea releases.
|
description: Give maintainers repeatable Purpur builds, automated verification, and versioned Gitea releases.
|
||||||
status: done
|
status: done
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ As a **plugin maintainer**, I want automated builds and releases modeled on Trig
|
|||||||
|
|
||||||
## Acceptance criteria
|
## Acceptance criteria
|
||||||
|
|
||||||
- [x] The Gradle project compiles against Spigot API `26.2-R0.1-SNAPSHOT` using a Java 17 toolchain.
|
- [x] The Gradle project compiles against Purpur API `26.2.build.2618-stable` using a Java 25 toolchain.
|
||||||
- [x] Compiler lint warnings fail the build.
|
- [x] Compiler lint warnings fail the build.
|
||||||
- [x] Automated JUnit 5 tests run as part of the Gradle check lifecycle.
|
- [x] Automated JUnit 5 tests run as part of the Gradle check lifecycle.
|
||||||
- [x] Pushes and pull requests build and test the plugin in Gitea Actions.
|
- [x] Pushes and pull requests build and test the plugin in Gitea Actions.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
type: User Story
|
type: User Story
|
||||||
title: "US-020: Control a base through a dialog UI"
|
title: "US-020: Control a base through a dialog UI"
|
||||||
description: Let players inspect and control their base through Minecraft's native dialog interface.
|
description: Let players inspect and control their base through Minecraft's native dialog interface.
|
||||||
status: done
|
status: in-progress
|
||||||
---
|
---
|
||||||
|
|
||||||
# US-020: Control a base through a dialog UI
|
# US-020: Control a base through a dialog UI
|
||||||
@@ -21,6 +21,7 @@ As a **player**, I want a dialog-based base dashboard so that I can inspect prog
|
|||||||
- [x] `ui` is offered through command autocomplete.
|
- [x] `ui` is offered through command autocomplete.
|
||||||
- [x] Non-player execution remains safely rejected.
|
- [x] Non-player execution remains safely rejected.
|
||||||
- [x] Automated tests verify dialog routing and generated controls.
|
- [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.
|
||||||
|
|
||||||
## Related
|
## Related
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1,5 @@
|
|||||||
|
plugins {
|
||||||
|
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
|
||||||
|
}
|
||||||
|
|
||||||
rootProject.name = "spigot-base"
|
rootProject.name = "spigot-base"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package games.dmg.spigotbase;
|
package games.dmg.spigotbase;
|
||||||
|
|
||||||
|
import io.papermc.paper.dialog.Dialog;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -28,6 +29,7 @@ final class BaseSettingsCommand implements CommandExecutor, TabCompleter {
|
|||||||
private final TeleportPolicy teleportPolicy;
|
private final TeleportPolicy teleportPolicy;
|
||||||
private final BaseFlightController flightController;
|
private final BaseFlightController flightController;
|
||||||
private final PocketBaseManager pocketBases;
|
private final PocketBaseManager pocketBases;
|
||||||
|
private final DialogProvider dialogProvider;
|
||||||
|
|
||||||
BaseSettingsCommand(
|
BaseSettingsCommand(
|
||||||
BaseStateManager stateManager,
|
BaseStateManager stateManager,
|
||||||
@@ -42,12 +44,30 @@ final class BaseSettingsCommand implements CommandExecutor, TabCompleter {
|
|||||||
PluginSettingsProvider settings,
|
PluginSettingsProvider settings,
|
||||||
BaseFlightController flightController,
|
BaseFlightController flightController,
|
||||||
PocketBaseManager pocketBases
|
PocketBaseManager pocketBases
|
||||||
|
) {
|
||||||
|
this(
|
||||||
|
stateManager,
|
||||||
|
settings,
|
||||||
|
flightController,
|
||||||
|
pocketBases,
|
||||||
|
(owner, pocket) -> new BaseSettingsDialogFactory(settings.current())
|
||||||
|
.create(owner, pocket)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseSettingsCommand(
|
||||||
|
BaseStateManager stateManager,
|
||||||
|
PluginSettingsProvider settings,
|
||||||
|
BaseFlightController flightController,
|
||||||
|
PocketBaseManager pocketBases,
|
||||||
|
DialogProvider dialogProvider
|
||||||
) {
|
) {
|
||||||
this.stateManager = stateManager;
|
this.stateManager = stateManager;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.teleportPolicy = new TeleportPolicy(settings);
|
this.teleportPolicy = new TeleportPolicy(settings);
|
||||||
this.flightController = flightController;
|
this.flightController = flightController;
|
||||||
this.pocketBases = pocketBases;
|
this.pocketBases = pocketBases;
|
||||||
|
this.dialogProvider = dialogProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -449,7 +469,7 @@ final class BaseSettingsCommand implements CommandExecutor, TabCompleter {
|
|||||||
PocketBaseState pocket = pocketBases == null
|
PocketBaseState pocket = pocketBases == null
|
||||||
? PocketBaseState.locked(state.playerId())
|
? PocketBaseState.locked(state.playerId())
|
||||||
: pocketBases.state(state.playerId());
|
: pocketBases.state(state.playerId());
|
||||||
player.showDialog(new BaseSettingsDialogFactory(settings.current()).create(state, pocket));
|
player.showDialog(dialogProvider.create(state, pocket));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showStatus(Player player, PlayerState state) {
|
private void showStatus(Player player, PlayerState state) {
|
||||||
@@ -672,6 +692,11 @@ final class BaseSettingsCommand implements CommandExecutor, TabCompleter {
|
|||||||
return met ? ChatColor.YELLOW : ChatColor.RED;
|
return met ? ChatColor.YELLOW : ChatColor.RED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
interface DialogProvider {
|
||||||
|
Dialog create(PlayerState owner, PocketBaseState pocket);
|
||||||
|
}
|
||||||
|
|
||||||
private static void sendUsage(Player player) {
|
private static void sendUsage(Player player) {
|
||||||
player.sendMessage(ChatColor.RED + "Usage: /basesettings "
|
player.sendMessage(ChatColor.RED + "Usage: /basesettings "
|
||||||
+ "[ui|status|upgrade|pocket upgrade|pocket mobs "
|
+ "[ui|status|upgrade|pocket upgrade|pocket mobs "
|
||||||
|
|||||||
@@ -1,19 +1,17 @@
|
|||||||
package games.dmg.spigotbase;
|
package games.dmg.spigotbase;
|
||||||
|
|
||||||
|
import io.papermc.paper.dialog.Dialog;
|
||||||
|
import io.papermc.paper.registry.RegistryKey;
|
||||||
|
import io.papermc.paper.registry.data.dialog.ActionButton;
|
||||||
|
import io.papermc.paper.registry.data.dialog.DialogBase;
|
||||||
|
import io.papermc.paper.registry.data.dialog.action.DialogAction;
|
||||||
|
import io.papermc.paper.registry.data.dialog.body.DialogBody;
|
||||||
|
import io.papermc.paper.registry.data.dialog.type.DialogType;
|
||||||
|
import io.papermc.paper.registry.set.RegistrySet;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
|
||||||
import net.md_5.bungee.api.dialog.ConfirmationDialog;
|
|
||||||
import net.md_5.bungee.api.dialog.Dialog;
|
|
||||||
import net.md_5.bungee.api.dialog.DialogBase;
|
|
||||||
import net.md_5.bungee.api.dialog.DialogListDialog;
|
|
||||||
import net.md_5.bungee.api.dialog.MultiActionDialog;
|
|
||||||
import net.md_5.bungee.api.dialog.NoticeDialog;
|
|
||||||
import net.md_5.bungee.api.dialog.action.ActionButton;
|
|
||||||
import net.md_5.bungee.api.dialog.action.RunCommandAction;
|
|
||||||
import net.md_5.bungee.api.dialog.body.PlainMessageBody;
|
|
||||||
|
|
||||||
final class BaseSettingsDialogFactory {
|
final class BaseSettingsDialogFactory {
|
||||||
private static final int DIALOG_WIDTH = 420;
|
private static final int DIALOG_WIDTH = 420;
|
||||||
@@ -24,8 +22,18 @@ final class BaseSettingsDialogFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Dialog create(PlayerState owner, PocketBaseState pocket) {
|
Dialog create(PlayerState owner, PocketBaseState pocket) {
|
||||||
return new DialogListDialog(
|
return render(specification(owner, pocket));
|
||||||
base(
|
}
|
||||||
|
|
||||||
|
DialogSpec specification(PlayerState owner, PocketBaseState pocket) {
|
||||||
|
List<DialogSpec> dialogs = List.of(
|
||||||
|
generalSettings(owner),
|
||||||
|
progressReport(),
|
||||||
|
baseUpgrade(owner),
|
||||||
|
pocketSettings(owner, pocket)
|
||||||
|
);
|
||||||
|
return new ListSpec(
|
||||||
|
content(
|
||||||
"Base Settings",
|
"Base Settings",
|
||||||
"Base Settings",
|
"Base Settings",
|
||||||
"Base " + owner.baseLevel() + "/4 • Size " + owner.sizeLevel() + "/3"
|
"Base " + owner.baseLevel() + "/4 • Size " + owner.sizeLevel() + "/3"
|
||||||
@@ -33,27 +41,14 @@ final class BaseSettingsDialogFactory {
|
|||||||
+ "Pocket Base " + pocket.level() + " • "
|
+ "Pocket Base " + pocket.level() + " • "
|
||||||
+ humanize(pocket.biome().commandName())
|
+ humanize(pocket.biome().commandName())
|
||||||
),
|
),
|
||||||
List.of(
|
dialogs,
|
||||||
generalSettings(owner),
|
|
||||||
progressReport(),
|
|
||||||
baseUpgrade(owner),
|
|
||||||
pocketSettings(owner, pocket)
|
|
||||||
),
|
|
||||||
null,
|
|
||||||
2,
|
2,
|
||||||
190
|
190
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dialog generalSettings(PlayerState owner) {
|
private DialogSpec generalSettings(PlayerState owner) {
|
||||||
return new MultiActionDialog(
|
List<ButtonSpec> actions = List.of(
|
||||||
base(
|
|
||||||
"Base Controls",
|
|
||||||
"Base Controls",
|
|
||||||
"Select a setting to change it. Locked controls remain visible and explain "
|
|
||||||
+ "their requirement in chat when selected."
|
|
||||||
),
|
|
||||||
List.of(
|
|
||||||
toggle(
|
toggle(
|
||||||
"Visitors",
|
"Visitors",
|
||||||
owner.baseLevel() >= 4,
|
owner.baseLevel() >= 4,
|
||||||
@@ -69,8 +64,7 @@ final class BaseSettingsDialogFactory {
|
|||||||
owner.navigationEnabled(),
|
owner.navigationEnabled(),
|
||||||
"Enabled",
|
"Enabled",
|
||||||
"Disabled",
|
"Disabled",
|
||||||
"basesettings navigation "
|
"basesettings navigation " + mode(!owner.navigationEnabled())
|
||||||
+ mode(!owner.navigationEnabled())
|
|
||||||
),
|
),
|
||||||
toggle(
|
toggle(
|
||||||
"Flight",
|
"Flight",
|
||||||
@@ -107,21 +101,31 @@ final class BaseSettingsDialogFactory {
|
|||||||
"Disabled",
|
"Disabled",
|
||||||
"basesettings bossbar " + mode(!owner.bossBarEnabled())
|
"basesettings bossbar " + mode(!owner.bossBarEnabled())
|
||||||
)
|
)
|
||||||
|
);
|
||||||
|
return new MultiSpec(
|
||||||
|
content(
|
||||||
|
"Base Controls",
|
||||||
|
"Base Controls",
|
||||||
|
"Select a setting to change it. Locked controls remain visible and explain "
|
||||||
|
+ "their requirement in chat when selected."
|
||||||
),
|
),
|
||||||
2,
|
actions,
|
||||||
null
|
2
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dialog progressReport() {
|
private DialogSpec progressReport() {
|
||||||
return new NoticeDialog(base(
|
return new NoticeSpec(
|
||||||
|
content(
|
||||||
"Progress Report",
|
"Progress Report",
|
||||||
"Progress Report",
|
"Progress Report",
|
||||||
"Display the detailed progression report in chat."
|
"Display the detailed progression report in chat."
|
||||||
)).action(commandButton("Show in Chat", "basesettings status"));
|
),
|
||||||
|
commandButton("Show in Chat", "basesettings status")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dialog baseUpgrade(PlayerState owner) {
|
private DialogSpec baseUpgrade(PlayerState owner) {
|
||||||
if (owner.baseLevel() >= 4) {
|
if (owner.baseLevel() >= 4) {
|
||||||
return notice("Base IV", "Base IV and visitor access are already unlocked.");
|
return notice("Base IV", "Base IV and visitor access are already unlocked.");
|
||||||
}
|
}
|
||||||
@@ -131,17 +135,22 @@ final class BaseSettingsDialogFactory {
|
|||||||
"Unlock and establish Base III before purchasing Base IV visitor access."
|
"Unlock and establish Base III before purchasing Base IV visitor access."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
int price = settings.visitorUnlockDiamondCost();
|
|
||||||
return confirmation(
|
return confirmation(
|
||||||
"Unlock Base IV",
|
"Unlock Base IV",
|
||||||
"Purchase visitor access for " + price + " diamonds?",
|
"Purchase visitor access for " + settings.visitorUnlockDiamondCost()
|
||||||
|
+ " diamonds?",
|
||||||
"basesettings upgrade"
|
"basesettings upgrade"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dialog pocketSettings(PlayerState owner, PocketBaseState pocket) {
|
private DialogSpec pocketSettings(PlayerState owner, PocketBaseState pocket) {
|
||||||
return new DialogListDialog(
|
List<DialogSpec> dialogs = List.of(
|
||||||
base(
|
pocketUpgrade(owner, pocket),
|
||||||
|
pocketMobSettings(pocket),
|
||||||
|
pocketBiomeSettings(pocket)
|
||||||
|
);
|
||||||
|
return new ListSpec(
|
||||||
|
content(
|
||||||
"Pocket Base",
|
"Pocket Base",
|
||||||
"Pocket Base " + pocket.level(),
|
"Pocket Base " + pocket.level(),
|
||||||
pocket.level() == 0
|
pocket.level() == 0
|
||||||
@@ -151,18 +160,13 @@ final class BaseSettingsDialogFactory {
|
|||||||
+ enabled(pocket.hostileMobSpawningEnabled()) + " • Passive mobs: "
|
+ enabled(pocket.hostileMobSpawningEnabled()) + " • Passive mobs: "
|
||||||
+ enabled(pocket.passiveMobSpawningEnabled())
|
+ enabled(pocket.passiveMobSpawningEnabled())
|
||||||
),
|
),
|
||||||
List.of(
|
dialogs,
|
||||||
pocketUpgrade(owner, pocket),
|
|
||||||
pocketMobSettings(pocket),
|
|
||||||
pocketBiomeSettings(pocket)
|
|
||||||
),
|
|
||||||
null,
|
|
||||||
1,
|
1,
|
||||||
260
|
260
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dialog pocketUpgrade(PlayerState owner, PocketBaseState pocket) {
|
private DialogSpec pocketUpgrade(PlayerState owner, PocketBaseState pocket) {
|
||||||
if (owner.baseLevel() < 4 || owner.base().isEmpty()) {
|
if (owner.baseLevel() < 4 || owner.base().isEmpty()) {
|
||||||
return notice(
|
return notice(
|
||||||
"Pocket Upgrade — Locked",
|
"Pocket Upgrade — Locked",
|
||||||
@@ -183,20 +187,14 @@ final class BaseSettingsDialogFactory {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dialog pocketMobSettings(PocketBaseState pocket) {
|
private DialogSpec pocketMobSettings(PocketBaseState pocket) {
|
||||||
if (pocket.level() < 1) {
|
if (pocket.level() < 1) {
|
||||||
return notice(
|
return notice(
|
||||||
"Mob Spawning — Locked",
|
"Mob Spawning — Locked",
|
||||||
"Unlock Pocket Base I to control natural mob spawning."
|
"Unlock Pocket Base I to control natural mob spawning."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return new MultiActionDialog(
|
List<ButtonSpec> actions = List.of(
|
||||||
base(
|
|
||||||
"Mob Spawning",
|
|
||||||
"Mob Spawning",
|
|
||||||
"Control natural spawning independently for each mob category."
|
|
||||||
),
|
|
||||||
List.of(
|
|
||||||
toggle(
|
toggle(
|
||||||
"Hostile Mobs",
|
"Hostile Mobs",
|
||||||
true,
|
true,
|
||||||
@@ -215,25 +213,30 @@ final class BaseSettingsDialogFactory {
|
|||||||
"basesettings pocket mobs passive "
|
"basesettings pocket mobs passive "
|
||||||
+ mode(!pocket.passiveMobSpawningEnabled())
|
+ mode(!pocket.passiveMobSpawningEnabled())
|
||||||
)
|
)
|
||||||
|
);
|
||||||
|
return new MultiSpec(
|
||||||
|
content(
|
||||||
|
"Mob Spawning",
|
||||||
|
"Mob Spawning",
|
||||||
|
"Control natural spawning independently for each mob category."
|
||||||
),
|
),
|
||||||
1,
|
actions,
|
||||||
null
|
1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dialog pocketBiomeSettings(PocketBaseState pocket) {
|
private DialogSpec pocketBiomeSettings(PocketBaseState pocket) {
|
||||||
if (pocket.level() < 1) {
|
if (pocket.level() < 1) {
|
||||||
return notice(
|
return notice(
|
||||||
"Change Biome — Locked",
|
"Change Biome — Locked",
|
||||||
"Unlock Pocket Base I to purchase biome changes."
|
"Unlock Pocket Base I to purchase biome changes."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
List<Dialog> worldTypes = Arrays.stream(PocketBaseWorldType.values())
|
List<DialogSpec> worldTypes = Arrays.stream(PocketBaseWorldType.values())
|
||||||
.map(type -> pocketBiomeType(pocket, type))
|
.map(type -> pocketBiomeType(pocket, type))
|
||||||
.map(Dialog.class::cast)
|
|
||||||
.toList();
|
.toList();
|
||||||
return new DialogListDialog(
|
return new ListSpec(
|
||||||
base(
|
content(
|
||||||
"Change Biome",
|
"Change Biome",
|
||||||
"Change Biome",
|
"Change Biome",
|
||||||
"Current biome: " + pocket.biome().worldType().commandName() + "/"
|
"Current biome: " + pocket.biome().worldType().commandName() + "/"
|
||||||
@@ -242,35 +245,32 @@ final class BaseSettingsDialogFactory {
|
|||||||
+ humanize(settings.pocketBaseBiomeCurrencyMaterial()) + "."
|
+ humanize(settings.pocketBaseBiomeCurrencyMaterial()) + "."
|
||||||
),
|
),
|
||||||
worldTypes,
|
worldTypes,
|
||||||
null,
|
|
||||||
1,
|
1,
|
||||||
220
|
220
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DialogListDialog pocketBiomeType(
|
private DialogSpec pocketBiomeType(
|
||||||
PocketBaseState pocket,
|
PocketBaseState pocket,
|
||||||
PocketBaseWorldType worldType
|
PocketBaseWorldType worldType
|
||||||
) {
|
) {
|
||||||
List<Dialog> biomes = Arrays.stream(PocketBaseBiome.values())
|
List<DialogSpec> biomes = Arrays.stream(PocketBaseBiome.values())
|
||||||
.filter(biome -> biome.worldType() == worldType)
|
.filter(biome -> biome.worldType() == worldType)
|
||||||
.map(biome -> biomeConfirmation(pocket, biome))
|
.map(biome -> biomeConfirmation(pocket, biome))
|
||||||
.map(Dialog.class::cast)
|
|
||||||
.toList();
|
.toList();
|
||||||
return new DialogListDialog(
|
return new ListSpec(
|
||||||
base(
|
content(
|
||||||
humanize(worldType.commandName()),
|
humanize(worldType.commandName()),
|
||||||
humanize(worldType.commandName()) + " Biomes",
|
humanize(worldType.commandName()) + " Biomes",
|
||||||
"Choose a biome subtype. The active biome is marked as selected."
|
"Choose a biome subtype. The active biome is marked as selected."
|
||||||
),
|
),
|
||||||
biomes,
|
biomes,
|
||||||
null,
|
|
||||||
2,
|
2,
|
||||||
190
|
190
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dialog biomeConfirmation(PocketBaseState pocket, PocketBaseBiome biome) {
|
private DialogSpec biomeConfirmation(PocketBaseState pocket, PocketBaseBiome biome) {
|
||||||
String title = humanize(biome.commandName())
|
String title = humanize(biome.commandName())
|
||||||
+ (pocket.biome() == biome ? " — Selected" : "");
|
+ (pocket.biome() == biome ? " — Selected" : "");
|
||||||
if (pocket.biome() == biome) {
|
if (pocket.biome() == biome) {
|
||||||
@@ -285,16 +285,18 @@ final class BaseSettingsDialogFactory {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dialog confirmation(String title, String message, String command) {
|
private static DialogSpec confirmation(String title, String message, String command) {
|
||||||
return new ConfirmationDialog(base(title, title, message))
|
return new ConfirmationSpec(
|
||||||
.yes(commandButton("Confirm", command));
|
content(title, title, message),
|
||||||
|
commandButton("Confirm", command)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dialog notice(String title, String message) {
|
private static DialogSpec notice(String title, String message) {
|
||||||
return new NoticeDialog(base(title, title, message));
|
return new NoticeSpec(content(title, title, message), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActionButton toggle(
|
private static ButtonSpec toggle(
|
||||||
String name,
|
String name,
|
||||||
boolean unlocked,
|
boolean unlocked,
|
||||||
boolean active,
|
boolean active,
|
||||||
@@ -306,29 +308,106 @@ final class BaseSettingsDialogFactory {
|
|||||||
String tooltip = unlocked
|
String tooltip = unlocked
|
||||||
? "Click to change this setting."
|
? "Click to change this setting."
|
||||||
: "This setting has not been unlocked yet.";
|
: "This setting has not been unlocked yet.";
|
||||||
return new ActionButton(
|
return new ButtonSpec(name + ": " + state, tooltip, 190, "/" + command);
|
||||||
text(name + ": " + state),
|
}
|
||||||
text(tooltip),
|
|
||||||
190,
|
private static ButtonSpec commandButton(String label, String command) {
|
||||||
new RunCommandAction("/" + command)
|
return new ButtonSpec(label, "", 150, "/" + command);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DialogContent content(
|
||||||
|
String title,
|
||||||
|
String externalTitle,
|
||||||
|
String message
|
||||||
|
) {
|
||||||
|
return new DialogContent(title, externalTitle, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dialog render(DialogSpec specification) {
|
||||||
|
DialogType type;
|
||||||
|
if (specification instanceof ListSpec list) {
|
||||||
|
List<Dialog> dialogs = list.dialogs().stream()
|
||||||
|
.map(BaseSettingsDialogFactory::render)
|
||||||
|
.toList();
|
||||||
|
type = DialogType.dialogList(
|
||||||
|
RegistrySet.valueSet(RegistryKey.DIALOG, dialogs),
|
||||||
|
null,
|
||||||
|
list.columns(),
|
||||||
|
list.buttonWidth()
|
||||||
);
|
);
|
||||||
|
} else if (specification instanceof MultiSpec multi) {
|
||||||
|
List<ActionButton> actions = multi.actions().stream()
|
||||||
|
.map(BaseSettingsDialogFactory::render)
|
||||||
|
.toList();
|
||||||
|
type = DialogType.multiAction(actions, null, multi.columns());
|
||||||
|
} else if (specification instanceof ConfirmationSpec confirmation) {
|
||||||
|
ActionButton cancel = ActionButton.builder(Component.text("Cancel")).build();
|
||||||
|
type = DialogType.confirmation(render(confirmation.confirm()), cancel);
|
||||||
|
} else if (specification instanceof NoticeSpec notice) {
|
||||||
|
type = notice.action() == null
|
||||||
|
? DialogType.notice()
|
||||||
|
: DialogType.notice(render(notice.action()));
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unsupported dialog specification");
|
||||||
}
|
}
|
||||||
|
DialogContent content = specification.content();
|
||||||
private static ActionButton commandButton(String label, String command) {
|
DialogBase base = DialogBase.builder(Component.text(content.title()))
|
||||||
return new ActionButton(text(label), new RunCommandAction("/" + command));
|
.externalTitle(Component.text(content.externalTitle()))
|
||||||
}
|
.body(List.of(DialogBody.plainMessage(
|
||||||
|
Component.text(content.message()), DIALOG_WIDTH
|
||||||
private static DialogBase base(String title, String externalTitle, String message) {
|
)))
|
||||||
return new DialogBase(text(title))
|
|
||||||
.externalTitle(text(externalTitle))
|
|
||||||
.body(List.of(new PlainMessageBody(text(message), DIALOG_WIDTH)))
|
|
||||||
.canCloseWithEscape(true)
|
.canCloseWithEscape(true)
|
||||||
.pause(false)
|
.pause(false)
|
||||||
.afterAction(DialogBase.AfterAction.CLOSE);
|
.afterAction(DialogBase.DialogAfterAction.CLOSE)
|
||||||
|
.build();
|
||||||
|
return Dialog.create(factory -> factory.empty().base(base).type(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BaseComponent text(String value) {
|
private static ActionButton render(ButtonSpec button) {
|
||||||
return new TextComponent(value);
|
ActionButton.Builder builder = ActionButton.builder(Component.text(button.label()))
|
||||||
|
.width(button.width())
|
||||||
|
.action(DialogAction.commandTemplate(button.command()));
|
||||||
|
if (!button.tooltip().isEmpty()) {
|
||||||
|
builder.tooltip(Component.text(button.tooltip()));
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed interface DialogSpec permits ListSpec, MultiSpec, ConfirmationSpec, NoticeSpec {
|
||||||
|
DialogContent content();
|
||||||
|
}
|
||||||
|
|
||||||
|
record DialogContent(String title, String externalTitle, String message) {
|
||||||
|
}
|
||||||
|
|
||||||
|
record ListSpec(
|
||||||
|
DialogContent content,
|
||||||
|
List<DialogSpec> dialogs,
|
||||||
|
int columns,
|
||||||
|
int buttonWidth
|
||||||
|
) implements DialogSpec {
|
||||||
|
}
|
||||||
|
|
||||||
|
record MultiSpec(
|
||||||
|
DialogContent content,
|
||||||
|
List<ButtonSpec> actions,
|
||||||
|
int columns
|
||||||
|
) implements DialogSpec {
|
||||||
|
}
|
||||||
|
|
||||||
|
record ConfirmationSpec(
|
||||||
|
DialogContent content,
|
||||||
|
ButtonSpec confirm
|
||||||
|
) implements DialogSpec {
|
||||||
|
}
|
||||||
|
|
||||||
|
record NoticeSpec(
|
||||||
|
DialogContent content,
|
||||||
|
ButtonSpec action
|
||||||
|
) implements DialogSpec {
|
||||||
|
}
|
||||||
|
|
||||||
|
record ButtonSpec(String label, String tooltip, int width, String command) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String mode(boolean active) {
|
private static String mode(boolean active) {
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ final class PocketBaseWorldService {
|
|||||||
World world = server.getWorld(name);
|
World world = server.getWorld(name);
|
||||||
boolean created = world == null;
|
boolean created = world == null;
|
||||||
if (created) {
|
if (created) {
|
||||||
WorldCreator creator = new WorldCreator(name)
|
WorldCreator creator = new WorldCreator(NamespacedKey.minecraft(name))
|
||||||
.environment(World.Environment.NORMAL)
|
.environment(World.Environment.NORMAL)
|
||||||
.generator(new VoidPocketChunkGenerator())
|
.generator(new VoidPocketChunkGenerator())
|
||||||
.generateStructures(false);
|
.generateStructures(false);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import org.bukkit.command.CommandSender;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.PlayerInventory;
|
import org.bukkit.inventory.PlayerInventory;
|
||||||
import net.md_5.bungee.api.dialog.Dialog;
|
import net.kyori.adventure.dialog.DialogLike;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
|
||||||
@@ -186,10 +186,12 @@ final class BaseSettingsCommandTest {
|
|||||||
when(player.getUniqueId()).thenReturn(playerId);
|
when(player.getUniqueId()).thenReturn(playerId);
|
||||||
when(player.getName()).thenReturn("Host");
|
when(player.getName()).thenReturn("Host");
|
||||||
PlayerInventory inventory = mock(PlayerInventory.class);
|
PlayerInventory inventory = mock(PlayerInventory.class);
|
||||||
|
ItemStack firstStack = item(Material.DIAMOND, 64);
|
||||||
|
ItemStack secondStack = item(Material.DIAMOND, 64);
|
||||||
when(player.getInventory()).thenReturn(inventory);
|
when(player.getInventory()).thenReturn(inventory);
|
||||||
when(inventory.getStorageContents()).thenReturn(new ItemStack[] {
|
when(inventory.getStorageContents()).thenReturn(new ItemStack[] {
|
||||||
new ItemStack(Material.DIAMOND, 64),
|
firstStack,
|
||||||
new ItemStack(Material.DIAMOND, 64)
|
secondStack
|
||||||
});
|
});
|
||||||
|
|
||||||
PlayerState current = PlayerState.newPlayer(playerId, "Host")
|
PlayerState current = PlayerState.newPlayer(playerId, "Host")
|
||||||
@@ -227,10 +229,9 @@ final class BaseSettingsCommandTest {
|
|||||||
when(player.getUniqueId()).thenReturn(playerId);
|
when(player.getUniqueId()).thenReturn(playerId);
|
||||||
when(player.getName()).thenReturn("Builder");
|
when(player.getName()).thenReturn("Builder");
|
||||||
PlayerInventory inventory = mock(PlayerInventory.class);
|
PlayerInventory inventory = mock(PlayerInventory.class);
|
||||||
|
ItemStack currency = item(Material.DIAMOND_BLOCK, 64);
|
||||||
when(player.getInventory()).thenReturn(inventory);
|
when(player.getInventory()).thenReturn(inventory);
|
||||||
when(inventory.getStorageContents()).thenReturn(new ItemStack[] {
|
when(inventory.getStorageContents()).thenReturn(new ItemStack[] {currency});
|
||||||
new ItemStack(Material.DIAMOND_BLOCK, 64)
|
|
||||||
});
|
|
||||||
PlayerState owner = PlayerState.newPlayer(playerId, "Builder")
|
PlayerState owner = PlayerState.newPlayer(playerId, "Builder")
|
||||||
.withAdministrativeLevels(4, 0, 0, 0, 0, false, false, true)
|
.withAdministrativeLevels(4, 0, 0, 0, 0, false, false, true)
|
||||||
.withBase(
|
.withBase(
|
||||||
@@ -264,10 +265,9 @@ final class BaseSettingsCommandTest {
|
|||||||
when(player.getUniqueId()).thenReturn(playerId);
|
when(player.getUniqueId()).thenReturn(playerId);
|
||||||
when(player.getName()).thenReturn("Builder");
|
when(player.getName()).thenReturn("Builder");
|
||||||
PlayerInventory inventory = mock(PlayerInventory.class);
|
PlayerInventory inventory = mock(PlayerInventory.class);
|
||||||
|
ItemStack currency = item(Material.NETHERITE_BLOCK, 16);
|
||||||
when(player.getInventory()).thenReturn(inventory);
|
when(player.getInventory()).thenReturn(inventory);
|
||||||
when(inventory.getStorageContents()).thenReturn(new ItemStack[] {
|
when(inventory.getStorageContents()).thenReturn(new ItemStack[] {currency});
|
||||||
new ItemStack(Material.NETHERITE_BLOCK, 16)
|
|
||||||
});
|
|
||||||
BaseStateManager stateManager = mock(BaseStateManager.class);
|
BaseStateManager stateManager = mock(BaseStateManager.class);
|
||||||
when(stateManager.player(playerId, "Builder"))
|
when(stateManager.player(playerId, "Builder"))
|
||||||
.thenReturn(PlayerState.newPlayer(playerId, "Builder"));
|
.thenReturn(PlayerState.newPlayer(playerId, "Builder"));
|
||||||
@@ -429,10 +429,9 @@ final class BaseSettingsCommandTest {
|
|||||||
when(player.getUniqueId()).thenReturn(playerId);
|
when(player.getUniqueId()).thenReturn(playerId);
|
||||||
when(player.getName()).thenReturn("Builder");
|
when(player.getName()).thenReturn("Builder");
|
||||||
PlayerInventory inventory = mock(PlayerInventory.class);
|
PlayerInventory inventory = mock(PlayerInventory.class);
|
||||||
|
ItemStack currency = item(Material.DIAMOND_BLOCK, 64);
|
||||||
when(player.getInventory()).thenReturn(inventory);
|
when(player.getInventory()).thenReturn(inventory);
|
||||||
when(inventory.getStorageContents()).thenReturn(new ItemStack[] {
|
when(inventory.getStorageContents()).thenReturn(new ItemStack[] {currency});
|
||||||
new ItemStack(Material.DIAMOND_BLOCK, 64)
|
|
||||||
});
|
|
||||||
PlayerState owner = PlayerState.newPlayer(playerId, "Builder")
|
PlayerState owner = PlayerState.newPlayer(playerId, "Builder")
|
||||||
.withAdministrativeLevels(4, 0, 0, 0, 0, false, false, true)
|
.withAdministrativeLevels(4, 0, 0, 0, 0, false, false, true)
|
||||||
.withBase(
|
.withBase(
|
||||||
@@ -554,14 +553,16 @@ final class BaseSettingsCommandTest {
|
|||||||
BaseSettingsCommand command = new BaseSettingsCommand(
|
BaseSettingsCommand command = new BaseSettingsCommand(
|
||||||
stateManager,
|
stateManager,
|
||||||
new PluginSettingsProvider(PluginSettings.from(Map.of())),
|
new PluginSettingsProvider(PluginSettings.from(Map.of())),
|
||||||
mock(BaseFlightController.class)
|
mock(BaseFlightController.class),
|
||||||
|
null,
|
||||||
|
(owner, pocket) -> null
|
||||||
);
|
);
|
||||||
|
|
||||||
command.onCommand(player, null, "basesettings", new String[0]);
|
command.onCommand(player, null, "basesettings", new String[0]);
|
||||||
command.onCommand(player, null, "homesettings", new String[] {"ui"});
|
command.onCommand(player, null, "homesettings", new String[] {"ui"});
|
||||||
command.onCommand(player, null, "basesettings", new String[] {"status"});
|
command.onCommand(player, null, "basesettings", new String[] {"status"});
|
||||||
|
|
||||||
verify(player, times(2)).showDialog(any(Dialog.class));
|
verify(player, times(2)).showDialog((DialogLike) null);
|
||||||
verify(player).sendMessage(ChatColor.GOLD + "=== Base Progress ===");
|
verify(player).sendMessage(ChatColor.GOLD + "=== Base Progress ===");
|
||||||
verify(player).sendMessage(
|
verify(player).sendMessage(
|
||||||
org.mockito.ArgumentMatchers.<String>argThat(message ->
|
org.mockito.ArgumentMatchers.<String>argThat(message ->
|
||||||
@@ -582,6 +583,18 @@ final class BaseSettingsCommandTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ItemStack item(Material material, int amount) {
|
||||||
|
ItemStack item = mock(ItemStack.class);
|
||||||
|
ItemStack copy = mock(ItemStack.class);
|
||||||
|
when(item.getType()).thenReturn(material);
|
||||||
|
when(item.getAmount()).thenReturn(amount);
|
||||||
|
when(item.clone()).thenReturn(copy);
|
||||||
|
when(copy.getType()).thenReturn(material);
|
||||||
|
when(copy.getAmount()).thenReturn(amount);
|
||||||
|
when(copy.clone()).thenReturn(copy);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
private static CommandResult execute(PlayerState current, String... arguments) {
|
private static CommandResult execute(PlayerState current, String... arguments) {
|
||||||
Player player = mock(Player.class);
|
Player player = mock(Player.class);
|
||||||
when(player.getUniqueId()).thenReturn(current.playerId());
|
when(player.getUniqueId()).thenReturn(current.playerId());
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package games.dmg.spigotbase;
|
package games.dmg.spigotbase;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
@@ -9,14 +10,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import net.md_5.bungee.api.dialog.ConfirmationDialog;
|
|
||||||
import net.md_5.bungee.api.dialog.Dialog;
|
|
||||||
import net.md_5.bungee.api.dialog.DialogListDialog;
|
|
||||||
import net.md_5.bungee.api.dialog.MultiActionDialog;
|
|
||||||
import net.md_5.bungee.api.dialog.NoticeDialog;
|
|
||||||
import net.md_5.bungee.api.dialog.action.Action;
|
|
||||||
import net.md_5.bungee.api.dialog.action.ActionButton;
|
|
||||||
import net.md_5.bungee.api.dialog.action.RunCommandAction;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
final class BaseSettingsDialogFactoryTest {
|
final class BaseSettingsDialogFactoryTest {
|
||||||
@@ -42,12 +35,15 @@ final class BaseSettingsDialogFactoryTest {
|
|||||||
PocketBaseBiome.PLAINS
|
PocketBaseBiome.PLAINS
|
||||||
);
|
);
|
||||||
|
|
||||||
Dialog dialog = new BaseSettingsDialogFactory(
|
BaseSettingsDialogFactory.DialogSpec specification =
|
||||||
PluginSettings.from(Map.of())
|
new BaseSettingsDialogFactory(PluginSettings.from(Map.of()))
|
||||||
).create(owner, pocket);
|
.specification(owner, pocket);
|
||||||
|
|
||||||
DialogListDialog root = assertInstanceOf(DialogListDialog.class, dialog);
|
BaseSettingsDialogFactory.ListSpec root = assertInstanceOf(
|
||||||
assertTrue(root.getBase().body().get(0).toString().contains("Base 4/4"));
|
BaseSettingsDialogFactory.ListSpec.class,
|
||||||
|
specification
|
||||||
|
);
|
||||||
|
assertTrue(root.content().message().contains("Base 4/4"));
|
||||||
List<String> commands = commands(root);
|
List<String> commands = commands(root);
|
||||||
assertTrue(commands.contains("/basesettings status"));
|
assertTrue(commands.contains("/basesettings status"));
|
||||||
assertTrue(commands.contains("/basesettings visitors blocked"));
|
assertTrue(commands.contains("/basesettings visitors blocked"));
|
||||||
@@ -72,23 +68,19 @@ final class BaseSettingsDialogFactoryTest {
|
|||||||
Instant.EPOCH
|
Instant.EPOCH
|
||||||
);
|
);
|
||||||
|
|
||||||
DialogListDialog root = assertInstanceOf(
|
BaseSettingsDialogFactory.ListSpec root = assertInstanceOf(
|
||||||
DialogListDialog.class,
|
BaseSettingsDialogFactory.ListSpec.class,
|
||||||
new BaseSettingsDialogFactory(PluginSettings.from(Map.of())).create(
|
new BaseSettingsDialogFactory(PluginSettings.from(Map.of())).specification(
|
||||||
owner,
|
owner,
|
||||||
PocketBaseState.locked(playerId)
|
PocketBaseState.locked(playerId)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
ConfirmationDialog upgrade = assertInstanceOf(
|
BaseSettingsDialogFactory.ConfirmationSpec upgrade = assertInstanceOf(
|
||||||
ConfirmationDialog.class,
|
BaseSettingsDialogFactory.ConfirmationSpec.class,
|
||||||
root.dialogs().get(2)
|
root.dialogs().get(2)
|
||||||
);
|
);
|
||||||
|
|
||||||
RunCommandAction action = assertInstanceOf(
|
assertEquals("/basesettings upgrade", upgrade.confirm().command());
|
||||||
RunCommandAction.class,
|
|
||||||
upgrade.yes().action()
|
|
||||||
);
|
|
||||||
assertTrue(action.template().equals("/basesettings upgrade"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -96,20 +88,19 @@ final class BaseSettingsDialogFactoryTest {
|
|||||||
UUID playerId = UUID.randomUUID();
|
UUID playerId = UUID.randomUUID();
|
||||||
PlayerState owner = PlayerState.newPlayer(playerId, "Newcomer");
|
PlayerState owner = PlayerState.newPlayer(playerId, "Newcomer");
|
||||||
|
|
||||||
DialogListDialog root = assertInstanceOf(
|
BaseSettingsDialogFactory.ListSpec root = assertInstanceOf(
|
||||||
DialogListDialog.class,
|
BaseSettingsDialogFactory.ListSpec.class,
|
||||||
new BaseSettingsDialogFactory(PluginSettings.from(Map.of())).create(
|
new BaseSettingsDialogFactory(PluginSettings.from(Map.of())).specification(
|
||||||
owner,
|
owner,
|
||||||
PocketBaseState.locked(playerId)
|
PocketBaseState.locked(playerId)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
MultiActionDialog controls = assertInstanceOf(
|
BaseSettingsDialogFactory.MultiSpec controls = assertInstanceOf(
|
||||||
MultiActionDialog.class,
|
BaseSettingsDialogFactory.MultiSpec.class,
|
||||||
root.dialogs().get(0)
|
root.dialogs().get(0)
|
||||||
);
|
);
|
||||||
List<String> labels = controls.actions().stream()
|
List<String> labels = controls.actions().stream()
|
||||||
.map(ActionButton::label)
|
.map(BaseSettingsDialogFactory.ButtonSpec::label)
|
||||||
.map(Object::toString)
|
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
assertTrue(labels.stream().anyMatch(label -> label.contains("Visitors: Locked")));
|
assertTrue(labels.stream().anyMatch(label -> label.contains("Visitors: Locked")));
|
||||||
@@ -119,34 +110,28 @@ final class BaseSettingsDialogFactoryTest {
|
|||||||
assertTrue(labels.stream().anyMatch(label -> label.contains("Spawnable Overlay: Locked")));
|
assertTrue(labels.stream().anyMatch(label -> label.contains("Spawnable Overlay: Locked")));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<String> commands(Dialog dialog) {
|
private static List<String> commands(
|
||||||
|
BaseSettingsDialogFactory.DialogSpec specification
|
||||||
|
) {
|
||||||
List<String> commands = new ArrayList<>();
|
List<String> commands = new ArrayList<>();
|
||||||
collect(dialog, commands);
|
collect(specification, commands);
|
||||||
return commands;
|
return commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void collect(Dialog dialog, List<String> commands) {
|
private static void collect(
|
||||||
if (dialog instanceof DialogListDialog list) {
|
BaseSettingsDialogFactory.DialogSpec specification,
|
||||||
|
List<String> commands
|
||||||
|
) {
|
||||||
|
if (specification instanceof BaseSettingsDialogFactory.ListSpec list) {
|
||||||
list.dialogs().forEach(child -> collect(child, commands));
|
list.dialogs().forEach(child -> collect(child, commands));
|
||||||
collect(list.exitAction(), commands);
|
} else if (specification instanceof BaseSettingsDialogFactory.MultiSpec multi) {
|
||||||
} else if (dialog instanceof MultiActionDialog actions) {
|
multi.actions().forEach(button -> commands.add(button.command()));
|
||||||
actions.actions().forEach(button -> collect(button, commands));
|
} else if (specification
|
||||||
collect(actions.exitAction(), commands);
|
instanceof BaseSettingsDialogFactory.ConfirmationSpec confirmation) {
|
||||||
} else if (dialog instanceof ConfirmationDialog confirmation) {
|
commands.add(confirmation.confirm().command());
|
||||||
collect(confirmation.yes(), commands);
|
} else if (specification instanceof BaseSettingsDialogFactory.NoticeSpec notice
|
||||||
collect(confirmation.no(), commands);
|
&& notice.action() != null) {
|
||||||
} else if (dialog instanceof NoticeDialog notice) {
|
commands.add(notice.action().command());
|
||||||
collect(notice.action(), commands);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void collect(ActionButton button, List<String> commands) {
|
|
||||||
if (button == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Action action = button.action();
|
|
||||||
if (action instanceof RunCommandAction command) {
|
|
||||||
commands.add(command.template());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ final class PocketBaseControllerTest {
|
|||||||
World world = mock(World.class);
|
World world = mock(World.class);
|
||||||
Block clicked = block(world, -2, 66, 0, Material.DIAMOND_BLOCK);
|
Block clicked = block(world, -2, 66, 0, Material.DIAMOND_BLOCK);
|
||||||
PlayerInteractEvent event = mock(PlayerInteractEvent.class);
|
PlayerInteractEvent event = mock(PlayerInteractEvent.class);
|
||||||
|
ItemStack activator = item(Material.FLINT_AND_STEEL);
|
||||||
BaseStateManager baseStates = mock(BaseStateManager.class);
|
BaseStateManager baseStates = mock(BaseStateManager.class);
|
||||||
PocketBaseManager pocketBases = mock(PocketBaseManager.class);
|
PocketBaseManager pocketBases = mock(PocketBaseManager.class);
|
||||||
PluginSettings settings = PluginSettings.from(Map.of());
|
PluginSettings settings = PluginSettings.from(Map.of());
|
||||||
@@ -49,7 +50,7 @@ final class PocketBaseControllerTest {
|
|||||||
when(event.getPlayer()).thenReturn(owner);
|
when(event.getPlayer()).thenReturn(owner);
|
||||||
when(event.getAction()).thenReturn(Action.RIGHT_CLICK_BLOCK);
|
when(event.getAction()).thenReturn(Action.RIGHT_CLICK_BLOCK);
|
||||||
when(event.getClickedBlock()).thenReturn(clicked);
|
when(event.getClickedBlock()).thenReturn(clicked);
|
||||||
when(event.getItem()).thenReturn(new ItemStack(Material.FLINT_AND_STEEL));
|
when(event.getItem()).thenReturn(activator);
|
||||||
when(world.getUID()).thenReturn(worldId);
|
when(world.getUID()).thenReturn(worldId);
|
||||||
when(world.getName()).thenReturn("world");
|
when(world.getName()).thenReturn("world");
|
||||||
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenAnswer(invocation -> {
|
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenAnswer(invocation -> {
|
||||||
@@ -98,6 +99,7 @@ final class PocketBaseControllerTest {
|
|||||||
World world = mock(World.class);
|
World world = mock(World.class);
|
||||||
Block clicked = block(world, 8, 67, 8, Material.DIAMOND_BLOCK);
|
Block clicked = block(world, 8, 67, 8, Material.DIAMOND_BLOCK);
|
||||||
PlayerInteractEvent event = mock(PlayerInteractEvent.class);
|
PlayerInteractEvent event = mock(PlayerInteractEvent.class);
|
||||||
|
ItemStack activator = item(Material.FLINT_AND_STEEL);
|
||||||
PocketBaseManager pocketBases = mock(PocketBaseManager.class);
|
PocketBaseManager pocketBases = mock(PocketBaseManager.class);
|
||||||
PluginSettings settings = PluginSettings.from(Map.of());
|
PluginSettings settings = PluginSettings.from(Map.of());
|
||||||
|
|
||||||
@@ -105,7 +107,7 @@ final class PocketBaseControllerTest {
|
|||||||
when(event.getPlayer()).thenReturn(owner);
|
when(event.getPlayer()).thenReturn(owner);
|
||||||
when(event.getAction()).thenReturn(Action.RIGHT_CLICK_BLOCK);
|
when(event.getAction()).thenReturn(Action.RIGHT_CLICK_BLOCK);
|
||||||
when(event.getClickedBlock()).thenReturn(clicked);
|
when(event.getClickedBlock()).thenReturn(clicked);
|
||||||
when(event.getItem()).thenReturn(new ItemStack(Material.FLINT_AND_STEEL));
|
when(event.getItem()).thenReturn(activator);
|
||||||
when(world.getUID()).thenReturn(worldId);
|
when(world.getUID()).thenReturn(worldId);
|
||||||
when(world.getName()).thenReturn("pocket");
|
when(world.getName()).thenReturn("pocket");
|
||||||
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenAnswer(invocation -> {
|
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenAnswer(invocation -> {
|
||||||
@@ -152,6 +154,7 @@ final class PocketBaseControllerTest {
|
|||||||
World world = mock(World.class);
|
World world = mock(World.class);
|
||||||
Block clicked = block(world, 30, 67, 8, Material.DIAMOND_BLOCK);
|
Block clicked = block(world, 30, 67, 8, Material.DIAMOND_BLOCK);
|
||||||
PlayerInteractEvent event = mock(PlayerInteractEvent.class);
|
PlayerInteractEvent event = mock(PlayerInteractEvent.class);
|
||||||
|
ItemStack activator = item(Material.FLINT_AND_STEEL);
|
||||||
PocketBaseManager pocketBases = mock(PocketBaseManager.class);
|
PocketBaseManager pocketBases = mock(PocketBaseManager.class);
|
||||||
PluginSettings settings = PluginSettings.from(Map.of());
|
PluginSettings settings = PluginSettings.from(Map.of());
|
||||||
|
|
||||||
@@ -159,7 +162,7 @@ final class PocketBaseControllerTest {
|
|||||||
when(event.getPlayer()).thenReturn(owner);
|
when(event.getPlayer()).thenReturn(owner);
|
||||||
when(event.getAction()).thenReturn(Action.RIGHT_CLICK_BLOCK);
|
when(event.getAction()).thenReturn(Action.RIGHT_CLICK_BLOCK);
|
||||||
when(event.getClickedBlock()).thenReturn(clicked);
|
when(event.getClickedBlock()).thenReturn(clicked);
|
||||||
when(event.getItem()).thenReturn(new ItemStack(Material.FLINT_AND_STEEL));
|
when(event.getItem()).thenReturn(activator);
|
||||||
when(world.getUID()).thenReturn(worldId);
|
when(world.getUID()).thenReturn(worldId);
|
||||||
when(world.getName()).thenReturn("pocket");
|
when(world.getName()).thenReturn("pocket");
|
||||||
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenAnswer(invocation -> {
|
when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenAnswer(invocation -> {
|
||||||
@@ -227,6 +230,12 @@ final class PocketBaseControllerTest {
|
|||||||
verify(event).setCancelled(true);
|
verify(event).setCancelled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ItemStack item(Material material) {
|
||||||
|
ItemStack item = mock(ItemStack.class);
|
||||||
|
when(item.getType()).thenReturn(material);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
private static Block block(
|
private static Block block(
|
||||||
World world,
|
World world,
|
||||||
int x,
|
int x,
|
||||||
|
|||||||
Reference in New Issue
Block a user