Search code examples
javaminecraftbukkit

Bukkit; How to trigger multiple ClickEvent RUN_COMMAND actions with a single click on a single chat message


I've written a rather simple method for my paper/spigot Minecraft server plugin that detects potential lag machines under construction.

The issue I have is that I want to send a single chat message that, when clicked once, will first run a /vanish command on behalf of the clicker.

Then if (and only if) the vanish was successful, I want to run a teleport command to a location included along with the specific instance of the ClickEvent.

Both of those commands need to be completed from the single user click event.

For reference here is the method that calls notifyOps() and includes the TextComponent in question, msg

        if (LagMats.contains(blockType) || mat.contains("MINECART") || mat.contains("DOOR")) {
            int counter = 0;

            for (Material thisMat: LagMats) {
                if (thisMat != Material.GRAVEL) {
                    counter += Utilities.blockCounter(block.getChunk(), thisMat);
                }
            }

            TextComponent warn = new TextComponent("WARN "); warn.setBold(true);
            warn.setColor(ChatColor.RED);

            TextComponent msg = new TextComponent("Potential lag-machine at " +
                    block.getX() + ", " + block.getY() + ", " + block.getZ() + " in " + dimension +
                    " by " + placer_name + " with UUID: " + placer.getUniqueId());

            String cmd = "/execute in " + env + " run tp @s " +
                    block.getX() + " " + block.getY() + " " + block.getZ();

            msg.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, cmd));

            if (counter > 256) {
                Utilities.notifyOps(new TextComponent(warn, msg));
            }
        }

Oh and the actual little code of notifyOps where the TextComponent is used in a message:

    // send a message to all online ops and console
    public static boolean notifyOps(TextComponent msg) {
        if (msg == null) return false;

        for (Player thisPlayer: Bukkit.getOnlinePlayers()) {
            try {
                if (thisPlayer.isOp()) thisPlayer.spigot().sendMessage(msg);
            } catch (Exception e) {return false;}
        }
        System.out.println(msg.getText());
        return true;
    }

So I want to have the user click just once, run two commands, the second only if the first succeeds, and would be best if it could be done within the try block the message is sent from.

I could write a custom command for this purpose, and then just run that command, but I rather avoid adding classes for such a small addition if it's actually possible and I just have no idea.

Thanks for any advice or help!


Solution

  • There is no way of doing that without writing a custom command...

    This is impossible because the ClickEvent and HoverEvent are entirely client-side. That means that there are no packets sent from the Player to the server. Therefore, it is impossible to callback the click of the Player and call a method to perform what you are trying to do.

    You may notice that all the ClickEvent.Actions do not affect the server. OPEN_URL, OPEN_FILE, RUN_COMMAND, SUGGEST_COMMAND, CHANGE_PAGE and COPY_TO_CLIPBOARD are all actions taken on the client-side.

    The only way here is to make the client send a command to the server which will trigger a method.