Skip to content

Command Tutorials #45

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: tutorials
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 176 additions & 0 deletions command-basics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# The Basics of Custom Commands
Custom commands are one of the most essential and core parts of writing scripts, which is why it's invaluable to have a good grasp on how to make them. This page will go over the basics of writing a command. The other command tutorial, [this page](commands.html), will have less explanation but will cover more complex bits and pieces, including things this tutorial may skip over or leave out for brevity.

## The Bare Bones

A command is made up of, at minimum, two things. A **command name**, the thing you type to execute the command, and a **trigger**, the code that runs when the command is executed. Skript organizes these two as follows:

```applescript
command /your-command-name:
trigger:
# your code here!
```
*secret tip: the / is actually optional!*

We tell Skript that we're making a command by writing `command`, then follow it up with the name of the command. After that, we move to the next line, indent because we're inside the command now, and use `trigger:` to tell Skript we want to write some code next.

This may be surprising, because events don't use `trigger:`, nor do functions. The reason is due to the other fields a command can have, like aliases, cooldowns, permissions, and other stuff we'll get to shortly.

Once we're inside the `trigger` section (with a new line and another indentation), we can start writing code like normal. Let's make this command do something, like broadcast text!

```applescript
command /broadcast:
trigger:
broadcast "Hello world!"
```

This is now a completely valid command you can run in your own server. It's basically the simplest viable command possible. Let's see about adding some complexity.

## Arguments

Our command can send text, but it can only send one thing. It'd be very useful if we can give our command some information and it'd respond to that. Say, for example, like telling it what to broadcast.

This is where **arguments** come in. I'm sure you've used Minecraft commands before, but just as a refresher, these are bits of information you can give the command so it can do more stuff. Like teleport you to a set of coords, or a specific player.

In Skript, they look like this:

```applescript
<name:type = default value>
```
Now that's a lot to take in, so let's simplify it for now. If you want to know more about the other bits, check out the [command reference page](commands.mdurl).

```applescript
<type>
```

We just need to tell Skript what `type` we want our argument to be. There's a whole list of `type`s on the [Types page](types.htmlorwhatever), but be aware that only some work in commands. This is because the type has to be able to be parsed from a string. Don't worry if you don't know what this means, it's only partially relevant.

The main point here is that we need to tell Skript what we're looking for. We want a broadcast command, so we're interested in text, or strings:

```applescript
command /broadcast <text>:
trigger:
broadcast "Hello world!"
```

See how the arguments go right after the command name? It's like how you would write it if you were actually running the command!

But we're not doing anything with this new bit of input yet. No matter what we type when running the command, it still broadcasts `"Hello world!"`. This is where the [argument expression](argumentexpressionurlhere) comes in:

```
[the] last arg[ument]
[the] arg[ument](-| )<(\d+)>
[the] <(\d*1)st|(\d*2)nd|(\d*3)rd|(\d*[4-90])th> arg[ument][s]
[(all [[of] the]|the)] arg[ument][s]
[the] %*type%( |-)arg[ument][( |-)<\d+>]
[the] arg[ument]( |-)%*type%[( |-)<\d+>]
```

This jumble of syntax is the many ways to reference an argument inside a command. Here's a few examples:

```applescript
the 1st argument
arg-1
arg 1
arg-text
text argument 1
last arg
```

So let's use one of these. I'm going to use `arg 1` as it's pretty easy to write, it's clear, and it can't be confused with subtraction like `arg-1` can.

```applescript
command /broadcast <text>:
trigger:
broadcast arg 1
```

Now our command broadcasts whatever we want! However, anyone can use this command, and we don't want our users broadcasting whatever they want. Let's add some restrictions.

## Permissions and Executable By

Commands are a lot more than just names, arguments, and triggers. They have a whole host of other fields you can use to add more features and functionality. We'll start with the two that determine who can run the command and who can't.

Firstly, permissions. This is a very simple field that is just a permission the player needs to run the command.

```applescript
command /broadcast <text>:
permission: server.broadcast
trigger:
broadcast arg 1
```

Now any player with the permission can run the command and any player without it can not. But let's be even more secure. Let's say we only want the console to be able to run this command. This is what the `executable by` field is for. It can be set to `players`, `console`, or `players and console`. If you leave it out, both players and console can run it.

```applescript
command /broadcast <text>:
permission: server.broadcast
executable by: console
trigger:
broadcast arg 1
```

Most of the time, executable by isn't very necessary, but it's good practice to exclude the console if you're ever doing something that involves the `player` instead of just the `sender`. Speaking of the sender, let's talk about the command sender!

## Command Sender

There's a bit of information that every command gets for free, even without arguments. This is the `command sender`, which can either be a `player` or `console`. You can reference it with `command sender` or `sender`:

```applescript
command /broadcast <text>:
trigger:
broadcast "%sender% says %arg 1%"
if player is set:
broadcast "sender is %player%, a player!"
else:
broadcast "sender must be %console%!"
```

If you know it's a player, you can use `player` or `event-player`, and if you know it's console, well, you can just use `console`. If it was executed by console, `player` will not be set, which is why using `executable by` is good practice!

## Aliases

I don't have a good transition for this section.

Aliases are alternate names for your command. Think `/tp` and `/teleport`. Skript gives you a field to tell it what aliases you want for your command:

```applescript
command /broadcast <text>:
permission: server.broadcast
aliases: /announce, yell
trigger:
broadcast arg 1
```

However, Skript does not actually register commands under these names, so they won't show up in tab complete, and if another plugin already has that command name, your command won't overwrite the existing one! If you run into these issues, consider writing a small dummy command that just redirects to your main one:

```applescript
command /yell <text>:
permission: server.broadcast
trigger:
make sender execute command "/broadcast %arg 1%"
```

## Cooldowns

One of the *coolest* things about Skript commands is their built-in cooldowns. I'll only give a very basic example here, but you can see the [main command tutorial](commands.md) for all the options. Let's say we only want players to broadcast things every five minutes. We can simply use the `cooldown` field:

```applescript
command /broadcast <text>:
cooldown: 5 minutes
trigger:
broadcast arg 1
```

Perfect! That's all we need to do! However, the message is simply "You are using this command too often." Let's tell our players how much longer they have to wait. We can do this with the `cooldown message` field and the `remaining time` expression:

```applescript
command /broadcast <text>:
cooldown: 5 minutes
cooldown message: You must wait %remaining time% before broadcasting again!
trigger:
broadcast arg 1
```



284 changes: 284 additions & 0 deletions commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
# Custom Commands

Skript allows you to easily create custom commands in your scripts, like the following:

```applescript
# A simple "broadcast" command for broadcasting the text argument.
# This is accessible only to users with the "skript.example.broadcast" permission.
command /broadcast <text>:
permission: skript.example.broadcast
description: Broadcasts a message to everyone including console.
trigger:
broadcast arg-text
```

That's a simple example, but you can do much more complex things with custom commands! That "/broadcast" command only shows a few of the options you have available when creating a custom command.

This will be a overview page with limited explanation. If you want an in-depth tutorial on creating your first command, please visit [this page]("command-basics.html??") instead


### Command Pattern

Here's the full list of features that you can use in your commands. They're all optional, except for the trigger section. We'll explain each one individually below.

```applescript
command /<command name> <arguments>:
aliases: # alternate command names
prefix: # command prefix, defaults to "skript"
executable by: # players or console
usage: # the message that explains how to use the command
description: # the command's description
permission: # the permission needed to use the command
permission message: # the message sent to users without the correct permissions
cooldown: # a timespan, during which the command can't be used again
cooldown message: # the message sent when the command is used again too fast
cooldown bypass: # the permission necessary to bypass the cooldown
cooldown storage: # what variable to store the cooldown in
trigger:
# The code to run goes here.
```

### Command Name

The command name is what comes immediately after `command`. It can consist of any characters you want, except for space. Additionally, the / in front of the command is optional. This means `command /broadcast` and `command broadcast` are the same. Here are a few examples:

```applescript
command /test-command:
trigger:
broadcast "Command: /test-command"
command nickname:
trigger:
broadcast "Command: /nickname"
command //set!:
trigger:
broadcast "Command: //set!"
```

### Arguments

[Arguments](https://docs.skriptlang.org/expressions.html#ExprArgument) follow the command name, and are separated by spaces.\
You can make arguments optional by surrounding them with square brackets `[]`, like this: `command /kill [all entities]`.

\
However, the real power in arguments comes from type arguments. These allow a command to take in a [type](https://docs.skriptlang.org/classes.html), like `command /kill <player>`. Type arguments must be surrounded by angle brackets `<>` and can also be made optional by surrounding them with square brackets: `[<player>]`.

\
The argument can then be referenced in the trigger section by `arg-1` or `argument 1` or a [number of other ways](https://docs.skriptlang.org/expressions.html#ExprArgument). You can also name type variables like so: `<name:type>`, which can then be referenced as a local variable: `{_name}`. Here's the full pattern for arguments:

```
<name:type=%default value%>
```

Arguments can be used in a lot of different ways, so I'll provide some examples ranging from the simplest possible to more complex uses.

```applescript
# this command can be run by "/test" or by "/test command".
command /test [command]:
trigger:
broadcast "Command: /test or /test command"
# sends the name of the given player. "of" is optional.
command /name [of] <player>:
trigger:
# here 'to player' refers to the player executing the command
send "Player's name: %arg-1%, %argument 1%, or %player-argument%" to player
# heals the player in the argument. If no player is given, it will heal the sender.
command /heal [<player=%player%>]:
trigger:
heal argument 1
# this can be used like /kill zombies, /kill creepers and animals in radius 100,
# or /kill monsters in the radius 6.
# the radius will default to 20 if isn't entered.
command /kill <entity types> [in [the] radius <number = 20>]:
executable by: players # this will be explained later on
trigger:
loop entities in radius arg-2 of player:
if loop-entity is arg-1:
kill loop-entity
# broadcasts the text given in the command. If no text is given,
# it will broadcast the default value of "default text".
# note that the text is referenced as {_text input}, rather than arg-1 or similar.
command /broadcast [<text input:text="default text">]:
trigger:
broadcast {_text input}
# Using optional commands for flags
# eg:
# /give-item stone sword with name Sword in the Stone and with lore Haha, get it?
# or
# /give-item heart of the sea with lore &bA murky blue orb.
command /give-item <item> [with name <text>] [[and] with lore <text>]:
trigger:
set {_item} to arg-1
# set name
if arg-2 is set:
set name of {_item} to formatted arg-2
# set lore
if arg-3 is set:
set lore of {_item} to formatted arg-3
# give item
give player {_item}
```

### Executable by

Who can execute this command. The options are `players`, `console`, or `players and console`.

```applescript
command /shutdown:
executable by: console
trigger:
shutdown the server
```

### Aliases

Aliases are alternate names for your command. For example, the command `/teleport` could have an alias `/tp`. Like in the command name, the forward slash (`/`) is optional.

```applescript
# this command can be run by "/teleport" or by "/tp".
command /teleport <number> <number> <number>:
executable by: players
aliases: tp
trigger:
teleport player to location(arg-1, arg-2, arg-3)
```

Aliases **will not** overwrite commands registered by other plugins. Say another plugin registers `/spawn`, and you have the following command:

```applescript
command /tp-to-spawn:
aliases: spawn, sp
trigger:
teleport player to spawn of world
```

If you run `/spawn`, that other plugin's command will run. You'll need to register a new command with that name and have it run your first command.

### Prefix

The prefix is an optional prefix before a command that users can choose to add. This helps when differentiating commands of the same name from multiple plugins or datapacks. For example, all minecraft commands can be prefixed with `minecraft` like so: `/minecraft:tp @a @s`. By default, this is `skript`, so your commands will be runnable via `/skript:your-command`.

If two custom Skript commands have the same name but different prefixes, only one will be registered.

```applescript
# This command can be run by "/test" or "/testing_prefix:test"
command /test:
prefix: testing_prefix
trigger:
broadcast "test"
# This command can be run by "/test2" or "/skript:test2"
command /test2:
trigger:
broadcast "test2"
```

### Description

The description of the command. Other plugins can get/show this with `/help`, like `/help teleport`.

### Permission

The permission required to execute this command. The message sent to players without the proper permission can be customized with the `permission message:` field.

```applescript
command /shutdown:
permission: server.admin
permission message: Only admins can shut down the server!
trigger:
shutdown the server
```

### Cooldowns

This field takes a timespan that the player must wait out before executing the command again. The cooldown can be canceled with `cancel the cooldown` ([documentation here](https://docs.skriptlang.org/effects.html#EffCancelCooldown)). Like with the permissions, you can change the default cooldown message with the `cooldown message:` field. The remaining time of the cooldown can be displayed with `%remaining time%` Additionally, you can store the cooldown in a variable with `cooldown storage:`, in order to store the cooldown even when the server restarts.

```applescript
command /vote:
executable by: players
cooldown: 1 day
cooldown message: You can only vote once a day!
cooldown storage: {vote::cooldown::%uuid of player%}
trigger:
add 1 to {vote::players::%uuid of player%}
```

There are also a number of expressions you can use to interact with the cooldowns of commands. You can get the remaining time with `remaining time`, the elapsed time with `elapsed time`, and the total time with `cooldown time`. You can also get the bypass permission with `bypass permission`.

If you've enabled `keep command last usage dates` in your `config.sk` file, you can get the last time the player used the command with `last usage date`.

You can see the full syntax for these expressions [here](https://docs.skriptlang.org/expressions.html#ExprCmdCooldownInfo).

```applescript
# The same vote command but with an improved cooldown message.
# Sorry about the really long line, can't do much about how it's displayed.
command /vote:
executable by: players
cooldown: 1 day
cooldown message: You can only vote once a day! You last voted at %last usage%, and it's only been %elapsed time%. Please wait another %remaining time%.
cooldown storage: {vote::cooldown::%uuid of player%}
cooldown bypass: vote.cooldown.bypass
trigger:
add 1 to {vote::players::%uuid of player%}
```

### The Trigger Section

This section is where all the code the command should run is located. I'm sure you're familiar with how it works from the previous examples, but in case you're still unsure, some more examples of commands will be displayed here. You can see these example commands and more in the `/plugins/Skript/scripts/-examples/commands.sk` file in your server.

```applescript
command /item <items>:
description: Give yourself some items.
usage: /item
aliases: /i
executable by: players # test
permission: skript.example.item
cooldown: 30 seconds
cooldown message: You need to wait %remaining time% to use this command again.
cooldown bypass: skript.example.cooldown.bypass
trigger:
if player has permission "skript.example.item.all":
give arguments to player
else:
loop arguments:
if (TNT, bedrock, obsidian, mob spawner, lava, lava bucket) does not contain loop-item:
give loop-item to player
else:
send "%loop-item% is blacklisted and cannot be spawned." to player
```

```applescript
command /home <text> [<text>]:
description: Set, delete or teleport to your home.
usage: /home set/remove <name>, /home <name>
permission: skript.example.home
executable by: players
trigger:
if arg-1 is "set":
if arg-2 is set:
set {homes::%uuid of player%::%arg-2%} to player's location
send "Set your home <green>%arg-2%<reset> to <grey>%location of player%<reset>" to player
else:
send "You must specify a name for this home." to player
else if arg-1 is "remove":
if arg-2 is set:
delete {homes::%uuid of player%::%arg-2%}
send "Deleted your home <green>%arg-2%<reset>" to player
else:
send "You must specify the name of this home." to player
else if arg-2 is set:
send "Correct usage: /home set/remove <name>" to player
else if {homes::%uuid of player%::%arg-1%} is set:
teleport player to {homes::%uuid of player%::%arg-1%}
else:
send "You have no home named <green>%arg-1%<reset>." to player
```

Written by Sovde, parts used with permission from [blueyescat's tutorial](https://skripthub.net/tutorials/10) on [SkriptHub](https://skripthub.net/).