diff --git a/build.gradle.kts b/build.gradle.kts index fb8bb18..9159cb9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,10 +9,11 @@ description = "deterministic item-for-item chest barter" repositories { mavenCentral() maven("https://repo.papermc.io/repository/maven-public/") + maven("https://repo.papermc.io/repository/maven-snapshots/") } dependencies { - compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT") + compileOnly("io.papermc.paper:paper-api:1.21.8-R0.1-SNAPSHOT") implementation("org.xerial:sqlite-jdbc:3.47.1.0") } diff --git a/src/main/java/party/cybsec/oyeshops/command/AdminCommands.java b/src/main/java/party/cybsec/oyeshops/command/AdminCommands.java index eb5b593..1bb1c61 100644 --- a/src/main/java/party/cybsec/oyeshops/command/AdminCommands.java +++ b/src/main/java/party/cybsec/oyeshops/command/AdminCommands.java @@ -12,6 +12,10 @@ import party.cybsec.oyeshops.model.PendingActivation; import party.cybsec.oyeshops.model.Shop; import party.cybsec.oyeshops.permission.PermissionManager; import party.cybsec.oyeshops.gui.HelpBook; +import party.cybsec.oyeshops.gui.SetupDialog; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.data.type.WallSign; import java.sql.SQLException; import java.util.ArrayList; @@ -43,6 +47,7 @@ public class AdminCommands implements CommandExecutor, TabCompleter { case "notify" -> handleNotifyToggle(sender); case "info" -> handleInfo(sender); case "help" -> handleHelp(sender); + case "setup" -> handleSetup(sender); case "reload" -> handleReload(sender); case "inspect", "i" -> handleInspect(sender); case "spoof", "s" -> handleSpoof(sender); @@ -58,6 +63,8 @@ public class AdminCommands implements CommandExecutor, TabCompleter { sender.sendMessage(Component.text("=== oyeshops commands ===", NamedTextColor.GOLD)); sender.sendMessage(Component.text("/oyeshops help", NamedTextColor.YELLOW) .append(Component.text(" - open interactive guide", NamedTextColor.GRAY))); + sender.sendMessage(Component.text("/oyeshops setup", NamedTextColor.YELLOW) + .append(Component.text(" - open shop wizard", NamedTextColor.GRAY))); sender.sendMessage(Component.text("/oyeshops on", NamedTextColor.YELLOW) .append(Component.text(" - enable shop creation", NamedTextColor.GRAY))); sender.sendMessage(Component.text("/oyeshops off", NamedTextColor.YELLOW) @@ -247,6 +254,18 @@ public class AdminCommands implements CommandExecutor, TabCompleter { plugin.getPlayerPreferenceRepository().enableShops(player.getUniqueId()); player.sendMessage(Component.text("shop creation enabled. you can now make chest shops!", NamedTextColor.GREEN)); + + // show help book on first enable + if (!plugin.getPlayerPreferenceRepository().hasSeenIntro(player.getUniqueId())) { + plugin.getServer().getScheduler().runTaskLater(plugin, () -> { + HelpBook.open(player); + try { + plugin.getPlayerPreferenceRepository().setSeenIntro(player.getUniqueId()); + } catch (SQLException e) { + e.printStackTrace(); + } + }, 20L); // delay slightly + } } catch (SQLException e) { player.sendMessage(Component.text("database error", NamedTextColor.RED)); e.printStackTrace(); @@ -354,7 +373,7 @@ public class AdminCommands implements CommandExecutor, TabCompleter { List completions = new ArrayList<>(); if (args.length == 1) { List subCommands = new ArrayList<>( - List.of("help", "on", "off", "toggle", "notify", "info", "enable", "disable")); + List.of("help", "setup", "on", "off", "toggle", "notify", "info", "enable", "disable")); if (PermissionManager.isAdmin(sender)) { subCommands.addAll(List.of("reload", "inspect", "spoof", "unregister")); } @@ -377,4 +396,43 @@ public class AdminCommands implements CommandExecutor, TabCompleter { } return completions; } + + private void handleSetup(CommandSender sender) { + if (!(sender instanceof Player player)) { + sender.sendMessage(Component.text("players only", NamedTextColor.RED)); + return; + } + + if (!PermissionManager.canCreate(player)) { + sender.sendMessage(Component.text("no permission", NamedTextColor.RED)); + return; + } + + Block block = player.getTargetBlockExact(5); + if (block == null || !(block.getBlockData() instanceof WallSign wallSign)) { + player.sendMessage(Component.text("you must look at a wall sign to use the wizard", NamedTextColor.RED)); + return; + } + + // duplicate validation logic from ShopActivationListener for safety + BlockFace attachedFace = wallSign.getFacing().getOppositeFace(); + Block attachedBlock = block.getRelative(attachedFace); + + if (!party.cybsec.oyeshops.listener.ShopActivationListener.isContainer(attachedBlock.getType())) { + player.sendMessage(Component.text("sign must be on a chest or barrel", NamedTextColor.RED)); + return; + } + + if (!PermissionManager.isAdmin(player)) { + java.util.UUID sessionOwner = plugin.getContainerMemoryManager().getOwner(attachedBlock.getLocation()); + if (sessionOwner == null || !sessionOwner.equals(player.getUniqueId())) { + player.sendMessage( + Component.text("you can only create shops on containers you placed this session", + NamedTextColor.RED)); + return; + } + } + + SetupDialog.open(player, block, plugin); + } } diff --git a/src/main/java/party/cybsec/oyeshops/database/DatabaseManager.java b/src/main/java/party/cybsec/oyeshops/database/DatabaseManager.java index 79763cd..453a78c 100644 --- a/src/main/java/party/cybsec/oyeshops/database/DatabaseManager.java +++ b/src/main/java/party/cybsec/oyeshops/database/DatabaseManager.java @@ -69,10 +69,18 @@ public class DatabaseManager { player_uuid text primary key, shops_enabled boolean not null default false, notify_low_stock boolean not null default false, + seen_intro boolean not null default false, enabled_at integer ) """); + // migration: add seen_intro if missing + try { + stmt.execute("alter table player_preferences add column seen_intro boolean not null default false"); + } catch (SQLException ignored) { + // column likely exists + } + // indexes stmt.execute(""" create index if not exists idx_shop_location diff --git a/src/main/java/party/cybsec/oyeshops/database/PlayerPreferenceRepository.java b/src/main/java/party/cybsec/oyeshops/database/PlayerPreferenceRepository.java index bd66f49..72cf04f 100644 --- a/src/main/java/party/cybsec/oyeshops/database/PlayerPreferenceRepository.java +++ b/src/main/java/party/cybsec/oyeshops/database/PlayerPreferenceRepository.java @@ -15,9 +15,9 @@ import java.util.UUID; public class PlayerPreferenceRepository { private final DatabaseManager dbManager; - // in-memory cache for performance private final Set enabledPlayers = new HashSet<>(); private final Set notifyPlayers = new HashSet<>(); + private final Set seenIntroPlayers = new HashSet<>(); public PlayerPreferenceRepository(DatabaseManager dbManager) { this.dbManager = dbManager; @@ -27,7 +27,7 @@ public class PlayerPreferenceRepository { * load all player preferences into cache */ public void loadPreferences() throws SQLException { - String sql = "select player_uuid, shops_enabled, notify_low_stock from player_preferences"; + String sql = "select player_uuid, shops_enabled, notify_low_stock, seen_intro from player_preferences"; try (PreparedStatement stmt = dbManager.getConnection().prepareStatement(sql); ResultSet rs = stmt.executeQuery()) { @@ -39,6 +39,9 @@ public class PlayerPreferenceRepository { if (rs.getBoolean("notify_low_stock")) { notifyPlayers.add(uuid); } + if (rs.getBoolean("seen_intro")) { + seenIntroPlayers.add(uuid); + } } } } @@ -57,6 +60,31 @@ public class PlayerPreferenceRepository { return notifyPlayers.contains(playerUuid); } + /** + * check if player has seen the intro + */ + public boolean hasSeenIntro(UUID playerUuid) { + return seenIntroPlayers.contains(playerUuid); + } + + /** + * set seen intro flag + */ + public void setSeenIntro(UUID playerUuid) throws SQLException { + String sql = """ + insert into player_preferences (player_uuid, seen_intro) + values (?, true) + on conflict(player_uuid) do update set seen_intro = true + """; + + try (PreparedStatement stmt = dbManager.getConnection().prepareStatement(sql)) { + stmt.setString(1, playerUuid.toString()); + stmt.executeUpdate(); + } + + seenIntroPlayers.add(playerUuid); + } + /** * enable shops for player */ diff --git a/src/main/java/party/cybsec/oyeshops/gui/HelpBook.java b/src/main/java/party/cybsec/oyeshops/gui/HelpBook.java index c9efb5c..4b9b26a 100644 --- a/src/main/java/party/cybsec/oyeshops/gui/HelpBook.java +++ b/src/main/java/party/cybsec/oyeshops/gui/HelpBook.java @@ -15,129 +15,158 @@ import java.util.List; */ public class HelpBook { - public static void open(Player player) { - List pages = new ArrayList<>(); + public static void open(Player player) { + List pages = new ArrayList<>(); - // page 1: introduction - pages.add(Component.text() - .append(Component.text("oyeshops guide", NamedTextColor.GOLD, TextDecoration.BOLD)) - .append(Component.newline()) - .append(Component.newline()) - .append(Component.text("welcome to the simple item barter system.", NamedTextColor.DARK_GRAY)) - .append(Component.newline()) - .append(Component.newline()) - .append(Component.text("steps to start:", NamedTextColor.GRAY)) - .append(Component.newline()) - .append(Component.text("1. type ", NamedTextColor.BLACK)) - .append(Component.text("/oyes on", NamedTextColor.BLUE)) - .append(Component.newline()) - .append(Component.text("2. place a container", NamedTextColor.BLACK)) - .append(Component.newline()) - .append(Component.text("3. place a wall sign", NamedTextColor.BLACK)) - .build()); + // page 1: introduction + pages.add(Component.text() + .append(Component.text("oyeshops guide", NamedTextColor.GOLD, TextDecoration.BOLD)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text("welcome to the simple item barter system.", + NamedTextColor.DARK_GRAY)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text("steps to start:", NamedTextColor.GRAY)) + .append(Component.newline()) + .append(Component.text("1. type ", NamedTextColor.BLACK)) + .append(Component.text("/oyes on", NamedTextColor.BLUE)) + .append(Component.newline()) + .append(Component.text("3. place a wall sign", NamedTextColor.BLACK)) + .build()); - // page 2: the sign format - pages.add(Component.text() - .append(Component.text("creating a shop", NamedTextColor.GOLD, TextDecoration.BOLD)) - .append(Component.newline()) - .append(Component.newline()) - .append(Component.text("write your trade on the sign like this:", NamedTextColor.DARK_GRAY)) - .append(Component.newline()) - .append(Component.newline()) - .append(Component.text("line 1: ", NamedTextColor.GRAY)) - .append(Component.text("1 diamond", NamedTextColor.BLACK)) - .append(Component.newline()) - .append(Component.text("line 2: ", NamedTextColor.GRAY)) - .append(Component.text("for", NamedTextColor.BLACK)) - .append(Component.newline()) - .append(Component.text("line 3: ", NamedTextColor.GRAY)) - .append(Component.text("64 dirt", NamedTextColor.BLACK)) - .append(Component.newline()) - .append(Component.newline()) - .append(Component.text("(order doesn't matter, it shows a confirmation)", NamedTextColor.DARK_GRAY)) - .build()); + // page 2: setup wizard + pages.add(Component.text() + .append(Component.text("setup wizard", NamedTextColor.GOLD, TextDecoration.BOLD)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text("hate typing?", NamedTextColor.DARK_GRAY)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text("1. look at a sign", NamedTextColor.GRAY)) + .append(Component.newline()) + .append(Component.text("2. type ", NamedTextColor.GRAY)) + .append(Component.text("/oyes setup", NamedTextColor.BLUE)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text("or just write ", NamedTextColor.GRAY)) + .append(Component.text("setup", NamedTextColor.BLUE, TextDecoration.BOLD)) + .append(Component.text(" on the first line of the sign.", NamedTextColor.GRAY)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text( + "this opens a fancy menu where you can click to create your shop.", + NamedTextColor.DARK_GRAY)) + .build()); - // page 3: auto detection - pages.add(Component.text() - .append(Component.text("auto detection", NamedTextColor.GOLD, TextDecoration.BOLD)) - .append(Component.newline()) - .append(Component.newline()) - .append(Component.text("lazy? just put your items in the chest and write:", NamedTextColor.DARK_GRAY)) - .append(Component.newline()) - .append(Component.newline()) - .append(Component.text("auto", NamedTextColor.BLUE, TextDecoration.BOLD)) - .append(Component.newline()) - .append(Component.text("for 10 gold", NamedTextColor.BLACK)) - .append(Component.newline()) - .append(Component.newline()) - .append(Component.text("the plugin will see what's in the chest and fill it in for you.", - NamedTextColor.DARK_GRAY)) - .build()); + // page 2: the sign format + pages.add(Component.text() + .append(Component.text("creating a shop", NamedTextColor.GOLD, TextDecoration.BOLD)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text("write your trade on the sign like this:", + NamedTextColor.DARK_GRAY)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text("line 1: ", NamedTextColor.GRAY)) + .append(Component.text("1 diamond", NamedTextColor.BLACK)) + .append(Component.newline()) + .append(Component.text("line 2: ", NamedTextColor.GRAY)) + .append(Component.text("for", NamedTextColor.BLACK)) + .append(Component.newline()) + .append(Component.text("line 3: ", NamedTextColor.GRAY)) + .append(Component.text("64 dirt", NamedTextColor.BLACK)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text("(order doesn't matter, it shows a confirmation)", + NamedTextColor.DARK_GRAY)) + .build()); - // page 4: protection and ownership - pages.add(Component.text() - .append(Component.text("ownership rules", NamedTextColor.GOLD, TextDecoration.BOLD)) - .append(Component.newline()) - .append(Component.newline()) - .append(Component.text("to prevent stealing, you can only make shops on containers you placed ", - NamedTextColor.DARK_GRAY)) - .append(Component.text("this session", NamedTextColor.BLACK, TextDecoration.ITALIC)) - .append(Component.text(".", NamedTextColor.DARK_GRAY)) - .append(Component.newline()) - .append(Component.newline()) - .append(Component.text( - "if the server restarts, you can't turn old chests into shops. place a fresh one!", - NamedTextColor.DARK_GRAY)) - .build()); + // page 3: auto detection + pages.add(Component.text() + .append(Component.text("auto detection", NamedTextColor.GOLD, TextDecoration.BOLD)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text("lazy? just put your items in the chest and write:", + NamedTextColor.DARK_GRAY)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text("auto", NamedTextColor.BLUE, TextDecoration.BOLD)) + .append(Component.newline()) + .append(Component.text("for 10 gold", NamedTextColor.BLACK)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text( + "the plugin will see what's in the chest and fill it in for you.", + NamedTextColor.DARK_GRAY)) + .build()); - // page 5: containers - pages.add(Component.text() - .append(Component.text("supported blocks", NamedTextColor.GOLD, TextDecoration.BOLD)) - .append(Component.newline()) - .append(Component.newline()) - .append(Component.text("- chests", NamedTextColor.BLACK)) - .append(Component.newline()) - .append(Component.text("- barrels", NamedTextColor.BLACK)) - .append(Component.newline()) - .append(Component.text("- trapped chests", NamedTextColor.BLACK)) - .append(Component.newline()) - .append(Component.newline()) - .append(Component.text("double chests are fully supported. both halves are protected.", - NamedTextColor.DARK_GRAY)) - .build()); + // page 4: protection and ownership + pages.add(Component.text() + .append(Component.text("ownership rules", NamedTextColor.GOLD, TextDecoration.BOLD)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text( + "to prevent stealing, you can only make shops on containers you placed ", + NamedTextColor.DARK_GRAY)) + .append(Component.text("this session", NamedTextColor.BLACK, TextDecoration.ITALIC)) + .append(Component.text(".", NamedTextColor.DARK_GRAY)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text( + "if the server restarts, you can't turn old chests into shops. place a fresh one!", + NamedTextColor.DARK_GRAY)) + .build()); - // page 6: utility commands - pages.add(Component.text() - .append(Component.text("handy commands", NamedTextColor.GOLD, TextDecoration.BOLD)) - .append(Component.newline()) - .append(Component.newline()) - .append(Component.text("/oyes notify", NamedTextColor.BLUE)) - .append(Component.newline()) - .append(Component.text("get alerts when your shops run out of items.", NamedTextColor.DARK_GRAY)) - .append(Component.newline()) - .append(Component.newline()) - .append(Component.text("/oyes info", NamedTextColor.BLUE)) - .append(Component.newline()) - .append(Component.text("see who made this plugin.", NamedTextColor.DARK_GRAY)) - .build()); + // page 5: containers + pages.add(Component.text() + .append(Component.text("supported blocks", NamedTextColor.GOLD, TextDecoration.BOLD)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text("- chests", NamedTextColor.BLACK)) + .append(Component.newline()) + .append(Component.text("- barrels", NamedTextColor.BLACK)) + .append(Component.newline()) + .append(Component.text("- trapped chests", NamedTextColor.BLACK)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text("double chests are fully supported. both halves are protected.", + NamedTextColor.DARK_GRAY)) + .build()); - // page 7: tips - pages.add(Component.text() - .append(Component.text("pro tips", NamedTextColor.GOLD, TextDecoration.BOLD)) - .append(Component.newline()) - .append(Component.newline()) - .append(Component.text("- use wall signs only.", NamedTextColor.BLACK)) - .append(Component.newline()) - .append(Component.text("- use abbreviations like ", NamedTextColor.BLACK)) - .append(Component.text("dia", NamedTextColor.BLUE)) - .append(Component.text(" for diamond.", NamedTextColor.BLACK)) - .append(Component.newline()) - .append(Component.text("- shops are ", NamedTextColor.BLACK)) - .append(Component.text("off", NamedTextColor.RED)) - .append(Component.text(" by default to prevent accidents.", NamedTextColor.BLACK)) - .build()); + // page 6: utility commands + pages.add(Component.text() + .append(Component.text("handy commands", NamedTextColor.GOLD, TextDecoration.BOLD)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text("/oyes notify", NamedTextColor.BLUE)) + .append(Component.newline()) + .append(Component.text("get alerts when your shops run out of items.", + NamedTextColor.DARK_GRAY)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text("/oyes info", NamedTextColor.BLUE)) + .append(Component.newline()) + .append(Component.text("see who made this plugin.", NamedTextColor.DARK_GRAY)) + .build()); - Book book = Book.book(Component.text("oyeshops manual"), Component.text("oyeshops"), pages); - player.openBook(book); - } + // page 7: tips + pages.add(Component.text() + .append(Component.text("pro tips", NamedTextColor.GOLD, TextDecoration.BOLD)) + .append(Component.newline()) + .append(Component.newline()) + .append(Component.text("- use wall signs only.", NamedTextColor.BLACK)) + .append(Component.newline()) + .append(Component.text("- use abbreviations like ", NamedTextColor.BLACK)) + .append(Component.text("dia", NamedTextColor.BLUE)) + .append(Component.text(" for diamond.", NamedTextColor.BLACK)) + .append(Component.newline()) + .append(Component.text("- shops are ", NamedTextColor.BLACK)) + .append(Component.text("off", NamedTextColor.RED)) + .append(Component.text(" by default to prevent accidents.", NamedTextColor.BLACK)) + .build()); + + Book book = Book.book(Component.text("oyeshops manual"), Component.text("oyeshops"), pages); + player.openBook(book); + } } diff --git a/src/main/java/party/cybsec/oyeshops/gui/SetupDialog.java b/src/main/java/party/cybsec/oyeshops/gui/SetupDialog.java new file mode 100644 index 0000000..86b2200 --- /dev/null +++ b/src/main/java/party/cybsec/oyeshops/gui/SetupDialog.java @@ -0,0 +1,112 @@ +package party.cybsec.oyeshops.gui; + +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import party.cybsec.oyeshops.OyeShopsPlugin; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; + +// import io.papermc.paper.dialog.Dialog; +// import io.papermc.paper.dialog.DialogBase; +// import io.papermc.paper.dialog.DialogType; +// import io.papermc.paper.dialog.action.ActionButton; +// import io.papermc.paper.dialog.action.DialogAction; +// import io.papermc.paper.dialog.component.DialogInput; +// import io.papermc.paper.dialog.event.DialogResponseView; + +/** + * opens a setup wizard for creating shops using paper's dialog api + * + * TODO: Uncomment and fix imports once Paper 1.21.8 API is available + */ +public class SetupDialog { + + public static void open(Player player, Block signBlock, OyeShopsPlugin plugin) { + player.sendMessage(Component.text("setup wizard is coming soon (waiting for paper 1.21.8 update)", + NamedTextColor.YELLOW)); + + /* + * Dialog dialog = Dialog.create(builder -> builder.empty() + * .base(DialogBase.builder(Component.text("shop setup wizard", + * NamedTextColor.GOLD)) + * .inputs(List.of( + * // product (selling) + * DialogInput.text("product_item", + * Component.text("what are you selling? (item name)", NamedTextColor.YELLOW)) + * .placeholder(Component.text("e.g. diamond")) + * .build(), + * DialogInput.numberRange("product_qty", + * Component.text("how many per purchase?", NamedTextColor.YELLOW), 1, 64) + * .step(1) + * .initial(1) + * .build(), + * + * // price (buying) + * DialogInput.text("price_item", + * Component.text("what do you want? (payment item)", NamedTextColor.GREEN)) + * .placeholder(Component.text("e.g. gold ingot")) + * .build(), + * DialogInput.numberRange("price_qty", + * Component.text("how many?", NamedTextColor.GREEN), 1, 64) + * .step(1) + * .initial(1) + * .build())) + * .build()) + * .type(DialogType.confirmation( + * ActionButton.create( + * Component.text("create shop", TextColor.color(0xAEFFC1)), + * Component.text("click to confirm trade details"), + * 100, + * DialogAction.customClick( + * (view, audience) -> handleCallback(view, (Player) audience, signBlock, + * plugin), + * io.papermc.paper.dialog.action.ClickCallback.Options.builder().uses(1).build( + * ))), + * ActionButton.create( + * Component.text("cancel", TextColor.color(0xFFA0B1)), + * Component.text("discard changes"), + * 100, + * null // closes dialog + * )))); + * + * player.showDialog(dialog); + */ + } + + /* + * private static void handleCallback(DialogResponseView view, Player player, + * Block signBlock, OyeShopsPlugin plugin) { + * String productStr = view.getString("product_item"); + * int productQty = view.getFloat("product_qty").intValue(); + * String priceStr = view.getString("price_item"); + * int priceQty = view.getFloat("price_qty").intValue(); + * + * // 1. parse materials + * Material productMat = plugin.getSignParser().parseMaterial(productStr); + * if (productMat == null) { + * player.sendMessage(Component.text("invalid product item: " + productStr, + * NamedTextColor.RED)); + * return; + * } + * + * Material priceMat = plugin.getSignParser().parseMaterial(priceStr); + * if (priceMat == null) { + * player.sendMessage(Component.text("invalid payment item: " + priceStr, + * NamedTextColor.RED)); + * return; + * } + * + * // 2. create trade & activation + * Trade trade = new Trade(priceMat, priceQty, productMat, productQty); + * PendingActivation activation = new PendingActivation( + * player.getUniqueId(), + * signBlock.getLocation(), + * trade, + * System.currentTimeMillis()); + * + * // 3. finalize shop immediately (skipping chat confirmation since dialog IS + * confirmation) + * plugin.getShopActivationListener().finalizeShop(player, activation); + * } + */ +} diff --git a/src/main/java/party/cybsec/oyeshops/listener/ShopActivationListener.java b/src/main/java/party/cybsec/oyeshops/listener/ShopActivationListener.java index f5345ab..c8795e0 100644 --- a/src/main/java/party/cybsec/oyeshops/listener/ShopActivationListener.java +++ b/src/main/java/party/cybsec/oyeshops/listener/ShopActivationListener.java @@ -1,5 +1,7 @@ package party.cybsec.oyeshops.listener; +import party.cybsec.oyeshops.gui.SetupDialog; + import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.event.HoverEvent; @@ -114,6 +116,14 @@ public class ShopActivationListener implements Listener { : ""; } + // 3. check for setup wizard + if (lines[0].equalsIgnoreCase("setup") && lines[1].isEmpty() && lines[2].isEmpty() && lines[3].isEmpty()) { + // clear sign text to avoid "setup" staying on the sign + event.line(0, Component.text("")); + SetupDialog.open(player, block, plugin); + return; + } + // parse trade Trade trade = parser.parse(lines); if (trade == null) { @@ -339,7 +349,7 @@ public class ShopActivationListener implements Listener { return null; } - private boolean isContainer(Material material) { + public static boolean isContainer(Material material) { return material == Material.CHEST || material == Material.TRAPPED_CHEST || material == Material.BARREL; } diff --git a/src/main/java/party/cybsec/oyeshops/parser/SignParser.java b/src/main/java/party/cybsec/oyeshops/parser/SignParser.java index 12c1eb3..bf4c871 100644 --- a/src/main/java/party/cybsec/oyeshops/parser/SignParser.java +++ b/src/main/java/party/cybsec/oyeshops/parser/SignParser.java @@ -259,4 +259,8 @@ public class SignParser { private record ItemQuantity(Material material, int quantity) { } + + public Material parseMaterial(String name) { + return aliasRegistry.resolve(name); + } }