Variables

Variables

Skript's events, commands, and effects are rather useful on their own, but you need variables to really get the most out of Skript. They allow you to store data, move data around, make code readable, and much more.

At their core, variables are a label for information. You can think of them as a little labelled box that you can put things into and then look in later to see what's inside. To be succinct, variables are representations, or stand-ins, of unknown or changing data.

Using Variables in Skript

In Skript, variables are represented by a variable name contained within two curly braces, like so:

set {variable} to 1
set {_variable} to 2
set {hey, what's going on} to "not much, what about you?"

Variables can be have nearly any name you'd like. They have have spaces, dashes, symbols, whatever. The only exception is the asterisk, *, which is used as the list wildcard and will be explained later. There are also different types of variables which depend on how you write the variable's name, but that will be explained in a moment as well.

First, an example. Here's a quick and dirty /home script, with a major flaw. See if you can spot it.

command /sethome:
    trigger:
        set {home} to player's location

command /home:
    trigger:
        teleport player to {home}

Before we get into the flaw, notice the usefulness of the variable. We can communicate information from one command to another, and it doesn't matter how long of an interval is between to the two commands. The data is stored in the variable and all we need to do to use it is look inside.

Now, the flaw. What happens if a player uses the /sethome command, but then a second player uses the /home command? The second player will be teleported to the first player's home. This is because the variable isn't unique. This means that the variable is always the same box, no matter who runs the command. We only have one box named "home", with only one spot for a location. In order to save different homes for different players, we need a box for each of them. Here's a simple solution: using the player's uuid in the label.

command /sethome:
    trigger:
        set {home::%player's uuid%} to player's location

command /home:
    trigger:
        teleport player to {home::%player's uuid%}

Now, each player has their own box, and the data is stored in the box that corresponds to them. However, this is just scratching the surface of what we can do with variables.

Variable Types

There are two main types of variables in Skript: global vars and local vars. The main differences between the two can be summarized in the following table, but a more detailed explanation will follow.

Global Variables Local Variables
Scope Can be accessed from any trigger, in any script, at any time. Can only be accessed from the trigger it was created in, and only for that instance of the trigger.
Persistence Data is saved permanently, including through server restarts. Data is saved temporarily, disappearing when the trigger is finished.
Uniqueness Since the variable can be accessed anywhere, it must be given a unique name manually to avoid collisions. Each variable is tied to its own trigger, and will not conflict with any other variables of the same name.
Main Use Storing data that needs to be accessed from multiple triggers, or for storing data that needs to persist over time. For example: warps, player statistics. Storing data that is only needed temporarily and only in one location. For example: creating an item to give a player, keeping track of a loop's iterations.

Global Variables

Global variables are variables that can be used anywhere in any of your scripts. If you put 1 in the box, it'll be 1 the next time you open the box it, no matter who's doing the looking. This makes them ideal for storing long-term data, like player stats, or for communicating between different parts of your scripts.

command /stop-loop:
    trigger:
        set {stop-loop} to true

# running the /stop-loop command can stop this loop, despite being a different trigger.
on load:
    while {stop-loop} is not set:
        broadcast "ping"
        wait 1 second

See how the variable is used in two different triggers? That's the power of global variables. Global vars are also stored to your server's hard drive, so they'll stick around if you restart. You can find them in variables.csv, but it's recommended to not mess with that file in case things get messed up.

However, as powerful as global variables are, they have a big shortcoming. Back when we introduced that /home script, we mentioned that just using {home} wasn't unique to each player, it was just one home that anyone could set and anyone could teleport to. To fix this, we made the variable specific to the player by including the player's uuid in the name:

command /sethome:
    trigger:
        set {home::%uuid of player%} to player's location

command /home:
    trigger:
        teleport player to {home::%uuid of player%}

Now, each player has their own home and they can't teleport to anyone else's. This is an important thing to remember about global variables. No two boxes can have the same label, and if you try to do that, you'll just end up trying to stuff two things into one box.

We're using :: as a separator to make it a list, which will be explained later. Suffice to say, it gives us a little more control over the variable in the future. You should, in general, use :: over other separators like ..

Local Variables

Local variables are variables that can only be accessed from the trigger they were created in. They're not stored to the hard drive like global vars are, so they'll disappear when the trigger is finished. This makes them ideal for storing temporary data. For example, let's look at this particle command:

command /particles:
    trigger:
        set {location} to player's location
        loop 20 times:
            show lava at {location}
            wait 5 ticks

This command is supposed to show some lava particles at the place the command was executed. However, if the command is executed again while the loop is still running, all the particles will move to the new location. It's the same problem as with the /home command, but now we can't really use player uuids to make the names unique. Furthermore, we don't even want to save this info! It's not useful once the command is finished.

To fix this, we can use a local variable. Local variables are created by putting a _ character at the start of a variable's name. These have slightly different properties. They only stick around in the same trigger that they were created in. It's like putting a small box on the table you're working on. If you move to another table, you can't reach the box anymore. Also, when you're done using that table you'll clean everything up, including the box. If you make one in /sethome, it won't be accessible in /home. However, since they won't ever collide with any other variable of the same name, they're great for information that doesn't need to leave the trigger.

command /particles:
    trigger:
        set {_location} to player's location
        loop 20 times:
            show lava at {_location}
            wait 5 ticks

Now, we can execute /particles as many times as we want and each location will be separate from the last. Each instance of running the command creates a new version of our location variable, which doesn't conflict with any of the others. Think of it like each time we run the command, Skript sets up a new worktable with new boxes, so nothing conflicts with anything else.

Lists

Lists are a feature of variables that allow them to store multiple values. It's like having a whole room of boxes, with a label on the door, as well as on each box. We can ask for all the boxes in the room, or a specific box from a specific room. They're created by using :: as a separator. For example, we can create a list of all the players on the server with:

set {players::*} to all players

This will create a list of all the players on the server. We can then access the list all at once with {players::*}, or individually, like getting the first player in the list: {players::1}.

List variables can be added to, removed from, or deleted all at once. Most expressions and effects support lists as well, so you can kill a whole list of entities all at once, with a single line.

set {list::*} to 1, 2, 3, 4, and 5
add 6 to {list::*}
remove 2 from {list::*}
broadcast {list::*} # broadcasts "1, 3, 4, 5, and 6"
delete {list::*}

When you put something into a list by using add, or setting the whole list at once, it's put under a number like {players::1}, where 1 means the first element. This is called the index, while the thing itself is called the value.

set {variable name::index} to "value"

As you can see above, you can set specific indices to specific values. This is actually something we already saw with the /home command! There, we created a list called home and used the player's uuid as the index. We stored the location as the value.

This means we can use all the abilities that lists provide on the list of homes! We could loop all the homes, we could delete them all at once, we could broadcast them all, whatever we want!

command /home-list:
    trigger:
        loop {home::*}:
            broadcast "%loop-index parsed as offlineplayer%'s home is at %loop-value%"

This command will broadcast the location of every home on the server. You can see how we get the player from their uuid by using loop-index, and the location by using loop-value.

Options and the Variables Section

Options

Options are a special tool. They're literally replaced before the script gets parsed, so unlike variables it's like literally typing out whatever the option is. This makes them very useful for things like little configs, or some bit of code you have to type out a ton. They follow the following pattern:

options:
    option name: value
    example: 6 + 7 / 2

on load:
    broadcast "{@option name}" # broadcasts "value"
    broadcast "{@example}" # broadcasts "6 + 7 / 2"
    broadcast {@example} # broadcasts "9.5"

As you can see, options can be very powerful since they can represent any amount of code. However, over-using options is a great way to cause hard-to-find bugs and severely impact your parsing times. Remeber, even if it looks shorter to you, it's the same length when Skript goes to parse it.

Options are best used as a small config file to make key values easier to change. If you're using it to reduce the amount of code you need to write, consider instead a global variable set in an on load event, or even a function.

The Variables Section

The variables section is a special section that allows you to give variables default values. There are two main things it can do. One, set a variable if it isn't already set when the script is loaded. This works the same as setting a variable in an on load event, but it will only set it when the variable isn't already set.

variables:
    {variable name} = "value"

The other main thing is it can give a variable a default value. This can be extremely useful for things like lists, but be careful, it can be finicky.

variables:
    {variable name::%player%} = "value"

Now, whenever you ask for {variable name::%some player%}, no matter what player, it'll give you "value". Again, it won't override any values that are already set, so don't try to change existing lists using this feature, it's for, as the name suggests, default values.

Guide written by sovde.