Skip to content

Latest commit

 

History

History
228 lines (169 loc) · 6.87 KB

creating-variants-of-teleport.md

File metadata and controls

228 lines (169 loc) · 6.87 KB
icon description
transporter-1
This page will explain how we can use Lamp to create multiple variants of the /teleport command

Creating variants of /teleport

The /greet command we built in the last section was relatively simple, and enough to showcase basic command creation in Lamp.

In this section, however, we will build more complicated commands that simulate real-life cases. Tons of fun awaits us!

Creating variants of /teleport

The /teleport command in Minecraft is a good example of a multi-functional command. In these examples, we will build the following:

  • /teleport <x> <y> <z>
  • /teleport <target> <x> <y> <z>
  • /teleport <target> here
  • /teleport <to target>

We will also define them with the /tp as a shorter form.

We will start with implementing the core functionality. To keep things simple for now, we will not add fancy features like ~ and ^ (relative coordinates and angles). We will introduce them in later sections, however.

Let's start by creating a separate class for containing these commands:

{% tabs %} {% tab title="Java" %}

public class TeleportCommands {

}

{% endtab %}

{% tab title="Kotlin" %}

class TeleportCommands {

}

{% endtab %} {% endtabs %}

And register it to our Lamp instance:

{% tabs %} {% tab title="Java" %}

public final class TestPlugin extends JavaPlugin {

    @Override public void onEnable() {
        var lamp = BukkitLamp.builder(this).build();
        lamp.register(new TeleportCommands());
    }
}

{% endtab %}

{% tab title="Kotlin" %}

class TestPlugin : JavaPlugin() {

    override fun onEnable() {
        val lamp = BukkitLamp.builder(this).build()
        lamp.register(TeleportCommands())
    }
}

{% endtab %} {% endtabs %}

/teleport <x> <y> <z>

This command should be easy to create. Let's define our function:

{% tabs %} {% tab title="Java" %}

public class TeleportCommands {

    @Command({"teleport", "tp"})
    public void teleport(Player sender, double x, double y, double z) {
        Location location = new Location(sender.getWorld(), x, y, z);
        sender.teleport(location);
    }
}

{% endtab %}

{% tab title="Kotlin" %}

class TeleportCommands {
    
    @Command("teleport", "tp")
    fun teleport(sender: Player, x: Double, y: Double, z: Double) {
        val location = Location(sender.world, x, y, z)
        sender.teleport(location)
    }
}

{% endtab %} {% endtabs %}

Let's break this down:

  • @Command({"teleport", "tp"}): This command defines our command as /teleport and /tp.
    • Any aliases defined
  • Player sender: This is the argument that represents the player executing the command.
    • Because this is the first parameter in the method, Lamp will implicitly infer it as the command sender
    • Because it is a Player, any non-player entity attempting to execute this command will receive a You must be a player to use this command!-like error. This makes it easy to restrict certain commands to player senders only.
  • double x, double y, double z: These are the arguments that our command will receive. Lamp will automatically parse the user input and parse it into doubles, or emit errors if the user inputs an invalid value.

Let's try our command:

Executing /teleport

That's one variant down. Let's create another.

/teleport <target> <x> <y> <z>

{% tabs %} {% tab title="Java" %}

@Command({"teleport", "tp"})
public void teleport(Player sender, EntitySelector<LivingEntity> target, double x, double y, double z) {
    Location location = new Location(sender.getWorld(), x, y, z);
    for (LivingEntity entity : target)
        entity.teleport(location);
}

{% endtab %}

{% tab title="Kotlin" %}

@Command("teleport", "tp")
fun teleport(sender: Player, target: EntitySelector<LivingEntity>, x: Double, y: Double, z: Double) {
    val location = Location(sender.world, x, y, z)
    for (entity in target) 
        entity.teleport(location)
}

{% endtab %} {% endtabs %}

Note that our commands with similar signatures can co-exist peacefully with no problems.

We can have as many variants of /teleport as we want, as long as Lamp can actually differentiate between them.

When there are multiple candidates for commands, Lamp will try to find the best one. This method is not foolproof and may go wrong in rare cases of real confusion.

At the end of the page, we will go through the criteria Lamp uses to decide the best execution candidate.

/teleport <target> here

Now, we will implement /teleport <target> here. This command is slightly different from the ones above as it involves an argument in the middle of the command.

We noticed that, in previous commands, arguments would always come at the end of the command, in the same order they are defined. However, we can declare the order in the command annotations as needed. And, as expected, if a parameter is not defined in the command path, it will be put at the end of the command.

💡 To define an argument in the middle of the command, simply declare it in the command annotation, enclosed with <>. For example

{% tabs %} {% tab title="Java" %}

@Command("teleport <target> here")
public void teleportHere(Player sender, EntitySelector<LivingEntity> target) {
    for (LivingEntity entity : target)
        entity.teleport(sender);
}

{% endtab %}

{% tab title="Kotlin" %}

@Command("teleport <target> here")
fun teleportHere(sender: Player, target: EntitySelector<LivingEntity>) {
    for (entity in target)
        entity.teleport(sender)
}

{% endtab %} {% endtabs %}

When Lamp encounters a name enclosed by <>, it will automatically infer it as a parameter name and look for a parameter with that name.

⚠️ Important note: You need to enable parameter names for this, or define an @Named annotation on the method's parameters. Lamp will throw an exception if it cannot find the parameter.

Using /teleport <target> here command

Let's create the simple /teleport <to>

/teleport <to>

This one is relatively simple too:

{% tabs %} {% tab title="Java" %}

@Command({"teleport", "tp"})
public void teleport(Player sender, Entity target) {
    sender.teleport(target);
}

{% endtab %}

{% tab title="Kotlin" %}

@Command("teleport", "tp")
fun teleport(sender: Player, target: Entity) {
    sender.teleport(target)
}

{% endtab %} {% endtabs %}

That's it! We can see how Lamp can work with a single command that has multiple variants, and how we can define arguments that come in different places of the command.

In the next