Variables
Containers to hold, manipulate and store data in a program.
Variables are named containers for storing objects in code. They typically function as expressions, and use the simple set/get/delete behaviour.
Variables can be recognised by the {...} curly brackets around their name. Special types of variable are recognisable by a non-alphanumeric character @$#!? at the start of their name.
Some types of variable have special behaviour in certain situations, detailed below.

Value Variables

Most variables are value variables: these store a raw value. Value variables have the standard {variable} name pattern.
Normal (value) variables are local to the current trigger section.
Variables can be set and retrieved like a normal expression.
1
set {var} to 100
2
set {var} to {var} - 1
3
print {var}
4
if {var} is 6:
5
set {var} to 20
Copied!
Variables can be set to each other.
1
set {var} to 100
2
set {blob} to {var}
3
assert {blob} is {var}
Copied!
Setting one will not affect the other - these are different containers for the same object.
1
set {var} to 100
2
set {blob} to {var}
3
assert {blob} is {var}
4
set {var} to 50
5
assert {blob} is not {var}
6
// blob = 100, var = 50
Copied!
Using a variable as a return or an argument will pass its value.
The function that uses it will not change the original variable.
1
function first:
2
trigger:
3
set {var} to 5
4
run second({var}) // var isn't changed
5
assert {var} is 5
6
​
7
function second (number):
8
trigger:
9
set {number} to {number} + 1
10
assert {number} is 6
Copied!
The same is true for lambdas, which will also freeze the variable value.
1
set {var} to 5
2
run a new runnable:
3
set {var} to 3 // {var} here is local to this lambda
4
assert {var} is 5
Copied!

Atomic Variables

Atomic variables use the {@variable} name pattern. They are reference variables, and store a reference to the object rather than the object's value itself.
In normal code, atomic variables function exactly the same as regular value variables.
1
set {@var} to 100
2
set {@var} to {@var} - 1
3
print {@var}
4
if {@var} is 6:
5
set {@var} to 20
Copied!
Remember: a variable named {@var} is different from a variable named {var}.
1
set {@var} to 1 // atomic
2
set {var} to 2 // normal
3
assert {var} is not {@var}
Copied!
Atomics are designed for being passed to lambdas or background functions. When passed as an argument to something, the passed argument is linked to the original.
Changing the passed copy will change the original.
1
set {@var} to 5
2
run a new runnable:
3
set {@var} to 3 // changes the original copy
4
assert {@var} is 3
Copied!
This also works in function arguments, if and only if the function uses a special atomic parameter.
1
function first:
2
trigger:
3
set {@var} to 5
4
run second({@var}) // var is changed
5
assert {@var} is 6
6
​
7
function second (@number): // @name = atomic parameter
8
trigger:
9
set {@number} to {@number} + 1 // changes original copy
10
assert {@number} is 6
Copied!
If a function does not take an atomic parameter, the value will be extracted. This means that the original copy will not be changed.
1
function first:
2
trigger:
3
set {@var} to 5
4
run second({@var}) // var is not changed
5
assert {@var} is 4
6
​
7
function second (number): // non-atomic parameter,
8
trigger:
9
set {number} to {number} + 1 // not linked to original copy
10
assert {number} is 6
Copied!
The reverse is also true: passing a non-atomic argument to an atomic parameter will wrap the argument as an atomic inside that function, but will not alter the original copy.
1
function first:
2
trigger:
3
set {var} to 5 // not atomic
4
run second({var}) // var is not changed
5
assert {var} is 4
6
​
7
function second (@number): // @name = atomic parameter
8
trigger:
9
set {@number} to {@number} + 1 // not linked to original copy
10
assert {@number} is 6
Copied!
Atomics cannot be passed as return values: their value will always be extracted.
1
function first:
2
trigger:
3
set {var} to second(1) // return is not atomic
4
set {@var} to second(1)
5
​
6
function second (@number): // @name = atomic parameter
7
trigger:
8
return {@number} // value is extracted, NOT atomic
Copied!
For advanced users, the raw atomic handle can be extracted using the get_atomic_literal(object) function from the skript namespace.
This would allow an atomic variable to be returned from a function secretly, but re-wrapping it for use would be complex.
This will be an AtomicVariable object and may be difficult to manipulate.

Thread-Local Variables

Thread-local variables use the {_variable} name pattern. They are reference variables.
Thread-local variables are accessible anywhere on the current process (thread). This includes other functions and lambdas. Thread-local variables are not accessible from other threads.
A thread/process is like a queue of instructions, executed in order. Using the wait or sleepeffect will pause the thread.
The run ... in the background effect can be used to create a different, branching process that will run at the same time as the current one.
In normal code, thread-local variables function exactly the same as regular value variables.
1
set {_var} to 100
2
set {_var} to {_var} - 1
3
print {_var}
4
if {_var} is 6:
5
set {_var} to 20
Copied!
Remember: a variable named {_var} is different from a variable named {var}.
1
set {_var} to 1 // thread-local
2
set {var} to 2 // normal
3
assert {var} is not {_var}
Copied!
Thread-local variables make it easy to pass data between triggers that are guaranteed to be executed in the same process.
1
function first:
2
trigger:
3
set {_var} to 10 // thread-local
4
set {var} to 5 // normal (local to this trigger)
5
run second()
6
​
7
function second:
8
trigger:
9
assert {var} is null
10
assert {_var} is 10 // value is kept from before call
Copied!
Thread-local variables are atomic, and any use alters the same copy of the variable.
1
function first:
2
trigger:
3
set {_var} to 10 // thread-local
4
assert {_var} is 10
5
run second() // value is changed in this function
6
assert {_var} is 5
7
​
8
function second:
9
trigger:
10
assert {_var} is 10
11
set {_var} to 5
12
assert {_var} is 5
Copied!
Thread-local variables can be accessed and changed from lambdas, unlike regular variables.
1
function my_function:
2
trigger:
3
set {_var} to 10 // thread-local
4
set {thing} to a new runnable:
5
assert {_var} is 10
6
set {_var} to 5
7
assert {_var} is 5
8
assert {_var} is 10
9
run {thing} // value is changed by the runnable
10
assert {_var} is 5
Copied!
However, lambdas or functions run in the background will not be able to access the value.
This is because background processes are run on a different thread, so their thread-local {_variables} are different.
1
function my_function:
2
trigger:
3
set {_var} to 10 // thread-local
4
set {thing} to a new runnable:
5
assert {_var} is null
6
set {_var} to 5 // does NOT update the other _var
7
assert {_var} is 5
8
assert {_var} is 10
9
run {thing} in the background // run on a DIFFERENT thread
10
wait 10 milliseconds // wait for other thread to finish
11
assert {_var} is 10 // _var is unchanged
Copied!
Events and other entry-points are triggered on a new thread, so there is no cross-contamination between processes.
1
on load:
2
trigger:
3
assert {_var} is null // not set yet
4
set {_var} to 10 // thread-local
5
assert {_var} is 10
6
​
7
on load: // different event trigger, so run on different thread
8
trigger:
9
assert {_var} is null // not set on THIS thread
10
set {_var} to 10 // thread-local
11
assert {_var} is 10
Copied!
The skript namespace has a special function to transfer thread-local variables to a different thread.
Transferring these will copy the variables, so the original copy will not be updated by changes.
1
function my_function:
2
trigger:
3
set {thread} to the current process
4
set {_var} to 10 // thread-local
5
set {thing} to a new runnable:
6
run copy_threadlocals_from({thread})
7
assert {_var} is 10 // copied from other _var
8
set {_var} to 5 // does NOT update the other _var
9
assert {_var} is 5
10
assert {_var} is 10
11
run {thing} in the background // run on a DIFFERENT thread
12
assert {_var} is 10 // _var is unchanged, the COPY was changed
Copied!

Global Variables

Global variables use the {!variable} name pattern. They are reference variables. These are most similar to the normal variables from original Skript.
Any copy of a global {!variable} anywhere on any process will access the same value.
Unlike in original Skript, global variables are not persistent across restarts (by default.)
In normal code, globals variables function exactly the same as regular value variables.
1
set {!var} to 100
2
set {!var} to {!var} - 1
3
print {!var}
4
if {!var} is 6:
5
set {!var} to 20
Copied!
Remember: a variable named {!var} is different from a variable named {var}.
1
set {!var} to 1 // global
2
set {var} to 2 // normal
3
assert {var} is not {!var}
Copied!
Global variables make it easy to pass data between triggers and entire scripts.
1
function first:
2
trigger:
3
set {!var} to 10 // thread-local
4
set {var} to 5 // normal (local to this trigger)
5
run second()
6
​
7
function second:
8
trigger:
9
assert {var} is null
10
assert {!var} is 10 // value is kept from before call
Copied!
Global variables are atomic and can be accessed and changed from other triggers, lambdas and different threads, unlike regular variables.
1
function my_function:
2
trigger:
3
set {!var} to 10 // thread-local
4
set {thing} to a new runnable:
5
assert {!var} is 10
6
set {!var} to 5
7
assert {!var} is 5
8
assert {!var} is 10
9
run {thing} in the background // value is changed by the runnable
10
wait 10 milliseconds // wait for other thread to finish
11
assert {!var} is 5
Copied!
Global variables are accessible from any process.
1
on load:
2
trigger:
3
assert {!var} is null // not set yet
4
set {!var} to 10 // global
5
assert {!var} is 10
6
​
7
on load: // different event trigger, so run on different thread
8
trigger:
9
wait 10 milliseconds // wait for previous trigger to finish
10
assert {!var} is 10 // set everywhere
11
set {!var} to 5 al
12
assert {!var} is 5
Copied!