Skip to content
Open
Show file tree
Hide file tree
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
4 changes: 3 additions & 1 deletion src/main/java/ch/njol/skript/Skript.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@
import org.skriptlang.skript.bukkit.registration.BukkitSyntaxInfos;
import org.skriptlang.skript.bukkit.text.TextComponentParser;
import org.skriptlang.skript.common.CommonModule;
import org.skriptlang.skript.common.elements.functions.MathFunctions;
import org.skriptlang.skript.common.elements.functions.StringFunctions;
import org.skriptlang.skript.common.elements.functions.TimeFunctions;
import org.skriptlang.skript.docs.Origin;
import org.skriptlang.skript.lang.comparator.Comparator;
import org.skriptlang.skript.lang.comparator.Comparators;
Expand Down Expand Up @@ -554,7 +557,6 @@ public void load(org.skriptlang.skript.addon.SkriptAddon addon) {
throw new RuntimeException(e);
}
BukkitEventValues.register(eventValueRegistry);
new DefaultFunctions();
new DefaultOperations();
}

Expand Down
1,084 changes: 0 additions & 1,084 deletions src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public ExprFunctionCall(FunctionReference<?> reference, Class<? extends T>[] exp
Class<?> returnType = Utils.getComponentType(functionReturnType);
if (CollectionUtils.containsSuperclass(expectedReturnTypes, returnType)) {
// Function returns expected type already
this.returnTypes = new Class[] {returnType};
this.returnTypes = new Class[]{returnType};
this.returnType = (Class<T>) returnType;
} else {
// Return value needs to be converted
Expand All @@ -55,12 +55,12 @@ public ExprFunctionCall(FunctionReference<?> reference, Class<? extends T>[] exp
if (execute == null) {
values = null;
} else if (!execute.getClass().isArray()) {
values = new Object[] {execute};
values = new Object[]{execute};
} else {
values = (Object[]) execute;
}

String[] keys = reference.function().returnedKeys();
String[] keys = reference.function().getReturnedKeys().toArray(new String[0]);
reference.function().resetReturnValue();

//noinspection unchecked
Expand All @@ -71,7 +71,7 @@ public ExprFunctionCall(FunctionReference<?> reference, Class<? extends T>[] exp
}

Converters.convert(values, convertedValues, returnTypes);
if (keys != null) {
if (keys.length > 0) {
for (int i = 0; i < convertedValues.length; i++) {
if (convertedValues[i] == null)
keys[i] = null;
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/ch/njol/skript/lang/function/Function.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import ch.njol.skript.SkriptConfig;
import ch.njol.skript.classes.ClassInfo;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.KeyProviderExpression;
import ch.njol.skript.lang.KeyedValue;
import ch.njol.util.coll.CollectionUtils;
import org.bukkit.Bukkit;
Expand All @@ -16,6 +15,8 @@
import org.skriptlang.skript.common.function.ScriptParameter;

import java.util.Arrays;
import java.util.Collections;
import java.util.SequencedCollection;

/**
* Functions can be called using arguments.
Expand Down Expand Up @@ -188,6 +189,15 @@ public Class<T> type() {
return null;
}

@Override
public final @NotNull SequencedCollection<String> getReturnedKeys() {
String[] returnedKeys = returnedKeys();
if (returnedKeys == null || returnedKeys.length == 0) {
return Collections.emptyList();
}
return Arrays.asList(returnedKeys);
}

/**
* Resets the return value of the {@code Function}.
* Should be called right after execution.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.skriptlang.skript.common.function.Parameters;

import java.util.Arrays;
import java.util.SequencedCollection;

public class ScriptFunction<T> extends Function<T> implements ReturnHandler<T> {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import org.skriptlang.skript.bukkit.enchantments.EnchantmentModule;
import org.skriptlang.skript.bukkit.entity.EntityModule;
import org.skriptlang.skript.bukkit.fishing.FishingModule;
import org.skriptlang.skript.bukkit.functions.BukkitFunctions;
import org.skriptlang.skript.bukkit.functions.VectorFunctions;
import org.skriptlang.skript.bukkit.input.InputModule;
import org.skriptlang.skript.bukkit.item.ItemModule;
import org.skriptlang.skript.bukkit.itemcomponents.ItemComponentModule;
Expand Down Expand Up @@ -73,6 +75,9 @@ protected void initSelf(SkriptAddon addon) {
Classes.registerClass(new PlayerClassInfo());
Classes.registerClass(new SlotClassInfo());
Classes.registerClass(new VectorClassInfo());

new BukkitFunctions(this, addon);
new VectorFunctions(this, addon);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
package org.skriptlang.skript.bukkit.functions;

import ch.njol.skript.lang.function.Functions;
import ch.njol.skript.util.Color;
import ch.njol.skript.util.ColorRGB;
import ch.njol.skript.util.Utils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.skriptlang.skript.addon.SkriptAddon;
import org.skriptlang.skript.bukkit.BukkitModule;
import org.skriptlang.skript.common.function.DefaultFunction;
import org.skriptlang.skript.common.function.Parameter.Modifier;

import java.util.UUID;

/**
* Contains all functions using Bukkit classes which cannot easily be grouped.
*/
public class BukkitFunctions {

public BukkitFunctions(BukkitModule module, SkriptAddon addon) {
SkriptAddon skript = module.origin(addon).addon();

Functions.register(DefaultFunction.builder(skript, "world", World.class)
.description("Gets a world from its name.")
.examples("set {_nether} to world(\"%{_world}%_nether\")")
.since("2.2")
.parameter("name", String.class)
.build(args -> Bukkit.getWorld(args.<String>get("name"))));

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")
teleport player to location(1,1,1, world "world", 100, 0)
teleport player to location(1,1,1, world "world", yaw of player, pitch of player)
teleport player to location(1,1,1, world of player)
teleport player to location(1,1,1, world("world"))
teleport player to location({_x}, {_y}, {_z}, {_w}, {_yaw}, {_pitch})

# SETTING BLOCKS
set block at location(1,1,1, world "world") to stone
set block at location(1,1,1, world "world", 100, 0) to stone
set block at location(1,1,1, world of player) to stone
set block at location(1,1,1, world("world")) to stone
set block at location({_x}, {_y}, {_z}, {_w}) to stone

# USING VARIABLES
set {_l1} to location(1,1,1)
set {_l2} to location(10,10,10)
set blocks within {_l1} and {_l2} to stone
if player is within {_l1} and {_l2}:

# OTHER
kill all entities in radius 50 around location(1,65,1, world "world")
delete all entities in radius 25 around location(50,50,50, world "world_nether")
ignite all entities in radius 25 around location(1,1,1, world of player)
"""
)
.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().getFirst());

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));
}));

Functions.register(DefaultFunction.builder(skript, "calcExperience", Long.class)
.description("Calculates the total amount of experience needed to achieve given level from scratch in Minecraft.")
.since("2.2-dev32")
.parameter("level", Long.class, Modifier.ranged(0L, Long.MAX_VALUE))
.build(args -> {
long level = args.get("level");
long exp;
if (level <= 0) {
exp = 0;
} else if (level <= 15) {
exp = level * level + 6 * level;
} else if (level <= 30) { // Truncating decimal parts probably works
exp = (int) (2.5 * level * level - 40.5 * level + 360);
} else { // Half experience points do not exist, anyway
exp = (int) (4.5 * level * level - 162.5 * level + 2220);
}

return exp;
}));

Functions.register(DefaultFunction.builder(skript, "rgb", Color.class)
.description("""
Returns a RGB color from the given red, green and blue parameters.
Alpha values can be added optionally but these only take affect in certain situations, like text display backgrounds.""")
.examples(
"dye player's leggings rgb(120, 30, 45)",
"set the colour of a text display to rgb(10, 50, 100, 50)"
)
.since("2.5, 2.10 (alpha)")
.parameter("red", Long.class, Modifier.ranged(0, 255))
.parameter("green", Long.class, Modifier.ranged(0, 255))
.parameter("blue", Long.class, Modifier.ranged(0, 255))
.parameter("alpha", Long.class, Modifier.ranged(0, 255), Modifier.OPTIONAL)
.build(args -> ColorRGB.fromRGBA(
args.<Long>get("red").intValue(),
args.<Long>get("green").intValue(),
args.<Long>get("blue").intValue(),
args.getOrDefault("alpha", 255L).intValue()
)));

Functions.register(DefaultFunction.builder(skript, "player", Player.class)
.description(
"Returns an online player from their name or UUID, if player is offline function will return nothing.",
"Setting 'getExactPlayer' parameter to true will return the player whose name is exactly equal to the provided name instead of returning a player that their name starts with the provided name."
)
.examples(
"set {_p} to player(\"Notch\") # will return an online player whose name is or starts with 'Notch'",
"set {_p} to player(\"Notch\", true) # will return the only online player whose name is 'Notch'",
"set {_p} to player(\"069a79f4-44e9-4726-a5be-fca90e38aaf5\") # <none> if player is offline"
)
.since("2.8.0")
.parameter("nameOrUUID", String.class)
.parameter("getExactPlayer", Boolean.class, Modifier.OPTIONAL)
.build(args -> {
String name = args.get("nameOrUUID");
boolean isExact = args.getOrDefault("getExactPlayer", false);

UUID uuid = null;
if (name.length() > 16 || name.contains("-")) {
if (Utils.isValidUUID(name))
uuid = UUID.fromString(name);
}

if (uuid != null)
return Bukkit.getPlayer(uuid);
if (isExact)
return Bukkit.getPlayerExact(name);
return Bukkit.getPlayer(name);
}));

Functions.register(DefaultFunction.builder(skript, "offlineplayer", OfflinePlayer.class)
.description(
"Returns a offline player from their name or UUID. This function will still return the player if they're online. " +
"If Paper 1.16.5+ is used, the 'allowLookup' parameter can be set to false to prevent this function from doing a " +
"web lookup for players who have not joined before. Lookups can cause lag spikes of up to multiple seconds, so " +
"use offline players with caution."
)
.examples(
"set {_p} to offlineplayer(\"Notch\")",
"set {_p} to offlineplayer(\"069a79f4-44e9-4726-a5be-fca90e38aaf5\")",
"set {_p} to offlineplayer(\"Notch\", false)"
)
.since("2.8.0, 2.9.0 (prevent lookups)")
.parameter("nameOrUUID", String.class)
.parameter("allowLookups", Boolean.class, Modifier.OPTIONAL)
.build(args -> {
String name = args.get("nameOrUUID");
UUID uuid = null;
if (name.length() > 16 || name.contains("-")) { // shortcut
if (Utils.isValidUUID(name))
uuid = UUID.fromString(name);
}
OfflinePlayer result;

if (uuid != null) {
result = Bukkit.getOfflinePlayer(uuid); // doesn't do lookups
} else if (!args.getOrDefault("allowLookups", true)) {
result = Bukkit.getOfflinePlayerIfCached(name);
} else {
result = Bukkit.getOfflinePlayer(name);
}

return result;
}));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package org.skriptlang.skript.bukkit.functions;

import ch.njol.skript.Skript;
import ch.njol.skript.lang.function.Functions;
import org.bukkit.util.Vector;
import org.joml.AxisAngle4f;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.skriptlang.skript.addon.SkriptAddon;
import org.skriptlang.skript.bukkit.BukkitModule;
import org.skriptlang.skript.common.function.DefaultFunction;

/**
* Contains all functions using Bukkit vectors.
*/
public class VectorFunctions {

public VectorFunctions(BukkitModule module, SkriptAddon addon) {
SkriptAddon skript = module.origin(addon).addon();

Functions.register(DefaultFunction.builder(skript, "vector", Vector.class)
.description("Creates a vector from a single argument. Equivalent to vector(n, n, n).")
.examples("vector(1) # = vector(1, 1, 1)")
.since("2.15")
.parameter("n", Number.class)
.build(args -> {
double value = args.<Number>get("n").doubleValue();
return new Vector(value, value, value);
}));

Functions.register(DefaultFunction.builder(skript, "vector", Vector.class)
.description("Creates a new vector, which can be used with various expressions, effects and functions.")
.examples("vector(0, 0, 0)")
.since("2.2-dev23")
.parameter("x", Number.class)
.parameter("y", Number.class)
.parameter("z", Number.class)
.build(args -> new Vector(
args.<Number>get("x").doubleValue(),
args.<Number>get("y").doubleValue(),
args.<Number>get("z").doubleValue()
)));

if (Skript.classExists("org.joml.Quaternionf")) {
Functions.register(DefaultFunction.builder(skript, "quaternion", Quaternionf.class)
.description("Returns a quaternion from the given W, X, Y and Z parameters. ")
.examples("quaternion(1, 5.6, 45.21, 10)")
.since("2.10")
.parameter("w", Number.class)
.parameter("x", Number.class)
.parameter("y", Number.class)
.parameter("z", Number.class)
.build(args -> {
double w = args.<Number>get("w").doubleValue();
double x = args.<Number>get("x").doubleValue();
double y = args.<Number>get("y").doubleValue();
double z = args.<Number>get("z").doubleValue();
return new Quaternionf(x, y, z, w);
}));
}

if (Skript.classExists("org.joml.AxisAngle4f")) {
Functions.register(DefaultFunction.builder(skript, "axisAngle", Quaternionf.class)
.description("Returns a quaternion from the given angle (in degrees) and axis (as a vector). This represents a rotation around the given axis by the given angle.")
.examples("axisAngle(90, (vector from player's facing))")
.since("2.10")
.parameter("angle", Number.class)
.parameter("axis", Vector.class)
.build(args -> {
float angle = (float) (args.<Number>get("angle").floatValue() / 180 * Math.PI);
Vector v = args.get("axis");
if (v.isZero() || !Double.isFinite(v.getX()) || !Double.isFinite(v.getY()) || !Double.isFinite(v.getZ()))
return null;
Vector3f axis = v.toVector3f();
return new Quaternionf(new AxisAngle4f(angle, axis));
}));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import org.skriptlang.skript.addon.HierarchicalAddonModule;
import org.skriptlang.skript.addon.SkriptAddon;
import org.skriptlang.skript.common.elements.expressions.*;
import org.skriptlang.skript.common.elements.functions.MathFunctions;
import org.skriptlang.skript.common.elements.functions.StringFunctions;
import org.skriptlang.skript.common.elements.functions.TimeFunctions;
import org.skriptlang.skript.common.properties.PropertiesModule;
import org.skriptlang.skript.common.types.*;

Expand Down Expand Up @@ -35,6 +38,10 @@ protected void loadSelf(SkriptAddon addon) {
ExprRecursiveSize::register,
ExprReplace::register
);

new MathFunctions();
new StringFunctions();
new TimeFunctions();
}

@Override
Expand Down
Loading
Loading