You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

1.8版本Spigot/Bukkit插件开发:点击GUI物品弹出链接确认菜单能否用数据包实现?

实现1.8 Spigot/Bukkit GUI点击后的链接确认菜单

Hey there! I totally get what you're trying to build—1.8 is a bit limited compared to newer Minecraft versions, but we can absolutely pull off this confirmation menu with a mix of chat components (via packets) or a tiny custom GUI. Let's break down the options:

Core Context First

  • 1.8 doesn't have a built-in "pop-up confirmation" API, and there's no way to directly trigger clipboard copy from the server (that feature didn't arrive until 1.15 with the COPY_TO_CLIPBOARD click event). So we'll work around that with a clear manual copy prompt.
  • We can use either chat messages (lightweight, no extra GUI) or a small confirmation GUI (more visual, feels like a proper pop-up) to get the job done.

This approach uses interactive JSON chat messages (sent via Spigot's built-in spigot().sendMessage() method) to create clickable options right in the player's chat window. No messy NMS required!

Step 1: Listen for GUI Item Clicks

import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemStack;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;

public class WebsiteGUIListener implements Listener {

    private static final String TARGET_WEBSITE = "https://your-site-here.com";

    @EventHandler
    public void onGUIClick(InventoryClickEvent e) {
        Player player = (Player) e.getWhoClicked();
        ItemStack clickedItem = e.getCurrentItem();

        // Check if this is the item we care about (adjust the display name to match your GUI item)
        if (clickedItem == null || !clickedItem.hasItemMeta() || !clickedItem.getItemMeta().getDisplayName().equals("§b打开网站")) {
            return;
        }

        e.setCancelled(true);
        player.closeInventory(); // Close the original GUI

        // Build the interactive confirmation message
        TextComponent mainPrompt = new TextComponent("§6您确定要打开以下网站吗?\n");
        
        // Add the clickable website link
        TextComponent link = new TextComponent("§b" + TARGET_WEBSITE);
        link.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, TARGET_WEBSITE));
        mainPrompt.addExtra(link);
        mainPrompt.addExtra("\n");

        // "是"选项(点击打开链接)
        TextComponent yesOption = new TextComponent("§a[是]");
        yesOption.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, TARGET_WEBSITE));
        yesOption.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent("§f点击打开网站")));
        mainPrompt.addExtra(yesOption);
        mainPrompt.addExtra(" §7| ");

        // "复制到剪贴板"选项(1.8无法自动复制,提示手动操作)
        TextComponent copyOption = new TextComponent("§e[复制到剪贴板]");
        copyOption.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent("§f选中上方链接并按Ctrl+C复制")));
        mainPrompt.addExtra(copyOption);
        mainPrompt.addExtra(" §7| ");

        // "否"选项(取消操作)
        TextComponent noOption = new TextComponent("§c[否]");
        noOption.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/cancel-website"));
        noOption.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent("§f取消操作")));
        mainPrompt.addExtra(noOption);

        // Send the interactive message to the player
        player.spigot().sendMessage(mainPrompt);
    }
}

Step 2: Handle the "Cancel" Command

Register a simple command to process the "否" option:

import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;

public class CancelWebsiteCommand implements CommandExecutor {

    @Override
    public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
        if (!(sender instanceof Player)) return false;
        Player player = (Player) sender;
        
        player.sendMessage("§7操作已取消。");
        // 可选:在这里重新打开你的主GUI
        // openYourMainGUI(player);
        return true;
    }
}

Don't forget to register the listener and command in your plugin's main class!


Option 2: Custom Confirmation GUI (More Visual)

If you want something that feels like a proper pop-up menu, create a small 9-slot GUI with three dedicated buttons:

import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.TextComponent;

import java.util.Arrays;

public class ConfirmationGUI implements Listener {

    private static final String TARGET_WEBSITE = "https://your-site-here.com";

    // 打开确认菜单
    public void openConfirmMenu(Player player) {
        Inventory confirmMenu = Bukkit.createInventory(null, 9, "§6确认打开网站");

        // 是按钮(绿色玻璃块)
        ItemStack yesBtn = new ItemStack(Material.STAINED_GLASS_PANE, 1, (short) 5);
        ItemMeta yesMeta = yesBtn.getItemMeta();
        yesMeta.setDisplayName("§a是");
        yesMeta.setLore(Arrays.asList("§f打开网站"));
        yesBtn.setItemMeta(yesMeta);
        confirmMenu.setItem(2, yesBtn);

        // 复制按钮(黄色玻璃块)
        ItemStack copyBtn = new ItemStack(Material.STAINED_GLASS_PANE, 1, (short) 4);
        ItemMeta copyMeta = copyBtn.getItemMeta();
        copyMeta.setDisplayName("§e复制链接");
        copyMeta.setLore(Arrays.asList("§f链接: " + TARGET_WEBSITE, "§f选中链接并按Ctrl+C复制"));
        copyBtn.setItemMeta(copyMeta);
        confirmMenu.setItem(4, copyBtn);

        // 否按钮(红色玻璃块)
        ItemStack noBtn = new ItemStack(Material.STAINED_GLASS_PANE, 1, (short) 14);
        ItemMeta noMeta = noBtn.getItemMeta();
        noMeta.setDisplayName("§c否");
        noMeta.setLore(Arrays.asList("§f取消操作"));
        noBtn.setItemMeta(noMeta);
        confirmMenu.setItem(6, noBtn);

        player.openInventory(confirmMenu);
    }

    // 处理主GUI和确认菜单的点击事件
    @EventHandler
    public void onInventoryClick(InventoryClickEvent e) {
        Player player = (Player) e.getWhoClicked();
        ItemStack clickedItem = e.getCurrentItem();

        // 处理主GUI点击,打开确认菜单
        if (e.getView().getTitle().equals("§b你的主GUI标题")) { // 替换为你的主GUI标题
            if (clickedItem != null && clickedItem.hasItemMeta() && clickedItem.getItemMeta().getDisplayName().equals("§b打开网站")) {
                e.setCancelled(true);
                player.closeInventory();
                openConfirmMenu(player);
            }
            return;
        }

        // 处理确认菜单点击
        if (e.getView().getTitle().equals("§6确认打开网站")) {
            e.setCancelled(true);
            if (clickedItem == null || !clickedItem.hasItemMeta()) return;

            String btnName = clickedItem.getItemMeta().getDisplayName();
            switch (btnName) {
                case "§a是":
                    // 发送可点击的链接消息
                    TextComponent linkMsg = new TextComponent("§b正在打开网站...");
                    linkMsg.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, TARGET_WEBSITE));
                    player.spigot().sendMessage(linkMsg);
                    player.closeInventory();
                    break;
                case "§e复制链接":
                    player.sendMessage("§e链接: §b" + TARGET_WEBSITE);
                    player.sendMessage("§7请选中链接并按Ctrl+C复制!");
                    player.closeInventory();
                    break;
                case "§c否":
                    player.closeInventory();
                    // 可选:重新打开主GUI
                    // openYourMainGUI(player);
                    break;
            }
        }
    }
}

Key Notes for 1.8

  1. Clipboard Limitation: As mentioned, 1.8 doesn't support server-triggered clipboard copies. The best we can do is display the link clearly and prompt the player to copy it manually.
  2. Cancel Click Events: Always call e.setCancelled(true) in InventoryClickEvent to prevent players from moving items in your GUI.
  3. Version Compatibility: Using Spigot's built-in chat component methods avoids messy NMS code, making your plugin more stable across 1.8 builds.

内容的提问来源于stack exchange,提问作者Dan

火山引擎 最新活动