[Java] [Java] Spigot Plugin Development-Registering commands as vanilla commands

2 minute read

Overview

  • Register the command that is normally registered in plugin.yml as a vanilla command.

Target audience

・Plug-in development environment is in place.

environment

・Windows 10-1909 ・Eclipse IDE Version: 2020-06 (4.16.0) ・Minecraft 1.16.1 ・Spigot 1.16.1

Note

We use the command engine brigadier added from Minecraft 1.13, so it may not be possible with versions below 1.13.

Command to create

・This time, we will safely create a command to make the player fly. Command syntax /fly <player> allow

Source code and description

・First, let’s create a class.

FlyCommand.java


package com.hamusuke.qiita.command;

import java.util.Collection;

import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;

import net.minecraft.server.v1_16_R1.ArgumentEntity;
import net.minecraft.server.v1_16_R1.ChatMessage;
import net.minecraft.server.v1_16_R1.CommandListenerWrapper;
import net.minecraft.server.v1_16_R1.EntityPlayer;

public class FlyCommand {
public static void register(CommandDispatcher<CommandListenerWrapper> dispatcher) {
LiteralArgumentBuilder<CommandListenerWrapper> literalArgumentBuilder = net.minecraft.server.v1_16_R1.CommandDispatcher.a("fly").requires((permission) -> {
return permission.hasPermission(2);
}).then(net.minecraft.server.v1_16_R1.CommandDispatcher.a("target", ArgumentEntity.d()).then(net.minecraft.server.v1_16_R1.CommandDispatcher.a("allow").executes(( commandcontext) -> (
return execute(commandcontext.getSource(), ArgumentEntity.f(commandcontext, "target"));
})));

dispatcher.register(literalArgumentBuilder);
}

private static int execute(CommandListenerWrapper commandListenerWrapper, Collection<EntityPlayer> players) (
for(EntityPlayer entityPlayer :players) {
entityPlayer.abilities.canFly = true;
entityPlayer.updateAbilities();
}

if(players.size() == 1) {
commandListenerWrapper.sendMessage(new ChatMessage("Make %s flyable", new Object[] {players.iterator().next().getScoreboardDisplayName()}), true);
}else {
commandListenerWrapper.sendMessage(new ChatMessage("Allowed %s players to fly", new Object[] {players.size()}), true);
}

return players.size();
}
}

public static void register(CommandDispatcher<CommandListenerWrapper> dispatcher) {

・Create a method for command registration. ・CommandDispatcher is the com.mojang.brigadier.CommandDispatcher

LiteralArgumentBuilder<CommandListenerWrapper> literalArgumentBuilder = net.minecraft.server.v1_16_R1.CommandDispatcher.a("fly").requires((permission) -> {
return permission.hasPermission(2);
}).then(net.minecraft.server.v1_16_R1.CommandDispatcher.a("target", ArgumentEntity.d()).then(net.minecraft.server.v1_16_R1.CommandDispatcher.a("allow").executes(( commandcontext) -> (
return execute(commandcontext.getSource(), ArgumentEntity.f(commandcontext, "target"));
})));

Net.minecraft.server.v1_16_R1.CommandDispatcher.a("fly") This is the /fly part.

requires((permission) -> { return permission.hasPermission(2); }); Specifies the privilege level at which the command can be executed. If you specify 2, only players with administrator privileges can execute it.

  • then(net.minecraft.server.v1_16_R1.CommandDispatcher.a("target", ArgumentEntity.d()).then(net.minecraft.server.v1_16_R1.CommandDispatcher.a("allow")) is the syntax after /fly ArgumentEntity.d() is used when you want to specify only the player. If you specify an entity such as @e, you will get an error like this. Untitled.jpg
executes((commandcontext) -> {
    return execute(commandcontext.getSource(), ArgumentEntity.f(commandcontext, "target"));
})
  • /Fly Describe the process when allow is executed.
  • You can get CommandListenerWrapper with getSource().
  • You can get Collection<EntityPlayer> with ArgumentEntity.f(commandcontext, "target").
dispatcher.register(literalArgumentBuilder);
  • The command syntax is registered.
for(EntityPlayer entityPlayer :players) {
    entityPlayer.abilities.canFly = true;
    entityPlayer.updateAbilities();
}
  • You can enable flight with entityPlayer.abilities.canFly = true.
  • entityPlayer.updateAbilities() notifies the server that the player’s ability (entityPlayer.abilities) has changed. Be sure to write this when you change it.
if(players.size() == 1) {
    commandListenerWrapper.sendMessage(new ChatMessage("Make %s flyable", new Object[] {players.iterator().next().getScoreboardDisplayName()}), true);
}else {
    commandListenerWrapper.sendMessage(new ChatMessage("Allowed %s players to fly", new Object[] {players.size()}), true);
}
  • commandListenerWrapper.sendMessage() sends a message to the command sender.
  • If you use getScoreboardDisplayName(), information will be displayed when the cursor is placed like this. Untitled 1.jpg
  • If you specify true, it will also be sent to other players and server logs.
  • If you specify false, only the command sender will be sent.

Main.java


package com.hamusuke.qiita;

import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_16_R1.CraftServer;
import org.bukkit.plugin.java.JavaPlugin;

import com.hamusuke.qiita.command.FlyCommand;
import com.mojang.brigadier.CommandDispatcher;

import net.minecraft.server.v1_16_R1.CommandListenerWrapper;
import net.minecraft.server.v1_16_R1.DedicatedServer;

public class Main extends JavaPlugin {
@Overridepublic void onEnable() {
DedicatedServer dedicatedServer = ((CraftServer)Bukkit.getServer()).getServer();
CommandDispatcher<CommandListenerWrapper> dispatcher = dedicatedServer.vanillaCommandDispatcher.a();
It's a sequel.
  FlyCommand.register(dispatcher);
  getLogger().info("registered fly command");
}
}
  • OnEnable() will be called when the plugin is loaded, so register the command here.

Put it in the server

Untitled 3.jpg I have successfully registered. Untitled 2.jpg You can fly.

Since it is registered as a vanilla command, it will be /minecraft:fly. (minecraft: can be omitted)

Good point

  • It works the same as the vanilla command.
  • It is not necessary to describe in plugin.yml.
  • You don’t have to create a class for tab completion.

    bad place

    ・The code tends to be long. (Hard to see)

    At the end

    Thank you for looking at the article. This is the first time I’ve written an article, so it may have been difficult to understand.