Skript’s functions allow users to perform specific actions at multiple points in a code base. To allow addons to easily add their own functions, Skript 2.13 introduced a new API for registering functions, which uses the DefaultFunction class. Compared to the previous way of dealing with functions, this new API is a drastic improvement in several key ways.
As an example, let’s register a function that removes a specific character from some strings, which defaults to removing all spaces.
# Intended result
set {_x::*} to remove(" hello ") # "hello"
set {_y::*} to remove(" hello ", " hey ") # "hello", "hey"
set {_z::*} to remove((" hello ", " hey "), "h") # " ello ", " ey "
First, create a new DefaultFunction.Builder. This builder takes the SkriptAddon
instance of your addon, the name of the function, and the return type of the function. Since our
function always returns an array of strings, we can specify the return type as String[].class.
If our function only returned a single string value, the return type would be String.class.
SkriptAddon addon = SkriptAddon.of(YourMainClass.class);
DefaultFunction.builder(addon, "remove", String[].class)
The documentation should be specified next. This allows documentation sites to view more information about the function.
DefaultFunction.builder(addon, "remove", String[].class)
.description("Removes a specific character from the strings.",
"Removes spaces if no character is specified.")
.examples("""
set {_x::*} to remove(" hello ") # "hello"
set {_y::*} to remove(" hello ", " hey ") # "hello", "hey"
set {_z::*} to remove((" hello ", " hey "), "h") # " ello ", " ey "
""")
.since("3.0")
.keywords("format", "strings")
Next, we should specify what arguments our function with the parameter function.
This specifies the parameter name and the type it accepts. Like the return type,
using an array indicates that multiple values can be passed to the argument.
Note that the char parameter contains a modifier which indicates that no value is required to be passed to the argument.
DefaultFunction.builder(addon, "remove", String[].class)
.description("Removes a specific character from the strings.",
"Removes spaces if no character is specified.")
.examples("""
set {_x::*} to remove(" hello ") # "hello"
set {_y::*} to remove(" hello ", " hey ") # "hello", "hey"
set {_z::*} to remove((" hello ", " hey "), "h") # " ello ", " ey "
""")
.since("3.0")
.keywords("format", "strings")
.parameter("strings", String[].class)
.parameter("char", String.class, Modifier.OPTIONAL)
To complete our function, we add the actual implementation code.
The build method provides you with a FunctionArguments instance, called args in our example. This contains
all the values for the parameters that are passed when a function is called. These values are associated by the name
of the parameter.
DefaultFunction.builder(addon, "remove", String[].class)
.description("Removes a specific character from the strings.",
"Removes spaces if no character is specified.")
.examples("""
set {_x::*} to remove(" hello ") # "hello"
set {_y::*} to remove(" hello ", " hey ") # "hello", "hey"
set {_z::*} to remove((" hello ", " hey "), "h") # " ello ", " ey "
""")
.since("3.0")
.keywords("format", "strings")
.parameter("strings", String[].class)
.parameter("char", String.class, Modifier.OPTIONAL)
.build(args -> {
// what the user entered for strings
String[] strings = args.get("strings");
// what the user entered, or, if the user passed nothing, returns " "
// this is only necessary because char has Modifier.OPTIONAL
String chr = args.getOrDefault("char", " ");
// actually replace all the characters
for (int i = 0; i < strings.length; i++) {
strings[i] = strings[i].replaceAll(chr, "");
}
// return the value
return strings;
});
Now that we have our function, we should register it. To do this, use Functions#register.
DefaultFunction<String[]> remove = DefaultFunction.builder(addon, "remove", String[].class)
.description("Removes a specific character from the strings.",
"Removes spaces if no character is specified.")
.examples("""
set {_x::*} to remove(" hello ") # "hello"
set {_y::*} to remove(" hello ", " hey ") # "hello", "hey"
set {_z::*} to remove((" hello ", " hey "), "h") # " ello ", " ey "
""")
.since("3.0")
.keywords("format", "strings")
.parameter("strings", String[].class)
.parameter("char", String.class, Modifier.OPTIONAL)
.build(args -> {
// what the user entered for strings
String[] strings = args.get("strings");
// what the user entered, or, if the user passed nothing, returns " "
// this is only necessary because char has Modifier.OPTIONAL
String chr = args.getOrDefault("char", " ");
// actually replace all the characters
for (int i = 0; i < strings.length; i++) {
strings[i] = strings[i].replaceAll(chr, "");
}
// return the value
return strings;
});
Functions.register(remove);
These are some other implementations that are currently being used by Skript.
DefaultFunction.builder(skript, "concat", String.class)
.description("Joins the provided texts (and other things) into a single text.")
.examples(
"concat(\"hello \", \"there\") # hello there",
"concat(\"foo \", 100, \" bar\") # foo 100 bar"
)
.since("2.9.0")
.parameter("texts", Object[].class)
.build(args -> {
StringBuilder builder = new StringBuilder();
Object[] objects = args.get("texts");
for (Object object : objects) {
builder.append(Classes.toString(object));
}
return builder.toString();
});
Functions.register(DefaultFunction.builder(skript, "location", Location.class)
.description(
"Creates a location from a world and 3 coordinates, with an optional yaw and pitch.",
"If for whatever reason the world is not found, it will fallback to the server's main world."
)
.examples("""
# TELEPORTING
teleport player to location(1,1,1, world "world")"""
)
.since("2.2")
.parameter("x", Number.class)
.parameter("y", Number.class)
.parameter("z", Number.class)
.parameter("world", World.class, Modifier.OPTIONAL)
.parameter("yaw", Float.class, Modifier.OPTIONAL)
.parameter("pitch", Float.class, Modifier.OPTIONAL)
.build(args -> {
World world = args.getOrDefault("world", Bukkit.getWorlds().get(0));
return new Location(world,
args.<Number>get("x").doubleValue(), args.<Number>get("y").doubleValue(), args.<Number>get("z").doubleValue(),
args.getOrDefault("yaw", 0f), args.getOrDefault("pitch", 0f));
}));