diff --git a/command-basics.md b/command-basics.md new file mode 100644 index 00000000000..f91a7a876d5 --- /dev/null +++ b/command-basics.md @@ -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 + +``` +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 + +``` + +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 : + 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 : + 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 : + 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 : + 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 : + 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 : + 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 : + 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 : + 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 : + cooldown: 5 minutes + cooldown message: You must wait %remaining time% before broadcasting again! + trigger: + broadcast arg 1 +``` + + + diff --git a/commands.md b/commands.md new file mode 100644 index 00000000000..0354b6c15b2 --- /dev/null +++ b/commands.md @@ -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 : + 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 / : + 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 `. Type arguments must be surrounded by angle brackets `<>` and can also be made optional by surrounding them with square brackets: `[]`. + +\ +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: ``, which can then be referenced as a local variable: `{_name}`. Here's the full pattern for arguments: + +``` + +``` + +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] : + 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 []: + 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 [in [the] radius ]: + 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 []: + 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 [with name ] [[and] with lore ]: + 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 : + 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 : + 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 []: + description: Set, delete or teleport to your home. + usage: /home set/remove , /home + 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 %arg-2% to %location of player%" 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 %arg-2%" 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 " 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 %arg-1%." to player +``` + +Written by Sovde, parts used with permission from [blueyescat's tutorial](https://skripthub.net/tutorials/10) on [SkriptHub](https://skripthub.net/). \ No newline at end of file