From 927f23c4b01e29f56bf558f5988981a7839e8372 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Mon, 9 Feb 2026 12:42:59 -0800 Subject: [PATCH 1/7] JsonDocPrinter - print warning when missing "since" tag --- .../skriptdev/skript/api/skript/docs/JsonDocPrinter.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/github/skriptdev/skript/api/skript/docs/JsonDocPrinter.java b/src/main/java/com/github/skriptdev/skript/api/skript/docs/JsonDocPrinter.java index a5096e3..554f516 100644 --- a/src/main/java/com/github/skriptdev/skript/api/skript/docs/JsonDocPrinter.java +++ b/src/main/java/com/github/skriptdev/skript/api/skript/docs/JsonDocPrinter.java @@ -298,6 +298,8 @@ private void printFunctions(BsonDocument mainDocs, SkriptRegistration registrati String since = documentation.getSince(); if (since != null) { functionDoc.put("since", new BsonArray(List.of(new BsonString(since)))); + } else { + Utils.warn(this.sender, "Function '%s' has no since tag!", name); } // RETURN TYPE @@ -384,6 +386,8 @@ private void printTypes(BsonDocument mainDocs, SkriptRegistration registration) String since = documentation.getSince(); if (since != null) { syntaxDoc.put("since", new BsonArray(List.of(new BsonString(since)))); + } else { + Utils.warn(this.sender, "Type '%s' has no since tag!", baseName); } @@ -459,6 +463,8 @@ private void printDocumentation(String type, BsonDocument syntaxDoc, SyntaxInfo< String since = documentation.getSince(); if (since != null) { syntaxDoc.put("since", new BsonArray(List.of(new BsonString(since)))); + } else { + Utils.warn(this.sender, "Syntax '%s' has no since tag!", syntaxInfo.getSyntaxClass().getSimpleName()); } } From eace4784abb0384cbb6234e2830a863d2ef9a53a Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Mon, 9 Feb 2026 14:01:18 -0800 Subject: [PATCH 2/7] config.sk - reformat config --- src/main/resources/config.sk | 68 ++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/main/resources/config.sk b/src/main/resources/config.sk index 6b00151..9c803be 100644 --- a/src/main/resources/config.sk +++ b/src/main/resources/config.sk @@ -1,64 +1,64 @@ # HySkript Config -hyskript-version: $pluginVersion # Do not change this value manually. # This is automatically updated when you update HySkript. # This is used to update the config if it's outdated. +hyskript-version: $pluginVersion -debug: false # Whether or not to enable debug mode (maybe print more verbose logs to console). +debug: false -max-target-block-distance: 160 # The maximum distance from a Player to a block to be considered a target block. # Default 160 = 5 chunks -# Increasing this amount could cause performance issues, so test carefully. +# Increasing this amount could cause performance issues, so test thoroughly. +max-target-block-distance: 160 -commands-generate-permissions: true # Hytale by default generates permissions for all commands. # If you want to disable this, set this to false. # You can also disable it per command in the command entries. +commands-generate-permissions: true # Effect commands allow you to execute effects in chat. effect-commands: - enabled: true - # Whether or not effect commands are enabled. + # Whether or not effect commands are enabled. + enabled: true - allow-ops: false - # Whether or not ops can use effect commands. - # If false, they will require the permission specified below in 'required-permission'. + # Whether or not ops can use effect commands. + # If false, they will require the permission specified below in 'required-permission'. + allow-ops: false - required-permission: skript.hyskript.effect-commands - # The permission required to use effect commands (if allow-ops is false). + # The permission required to use effect commands (if allow-ops is false). + required-permission: skript.hyskript.effect-commands - token: ! - # The token used to execute effects in chat. + # The token used to execute effects in chat. + token: ! # Represents the database[s] used by HySkript to save variables to. # You can add as many databases as you want. databases: # dummy: (This is the name of your database) -# type: json-database -# This is the type of database, currently only 'json-database' is supported +# type: json-database +# This is the type of database, currently only 'json-database' is supported # -# enabled: true -# Whether or not the database is enabled +# enabled: true +# Whether or not the database is enabled # -# file-type: json -# The file type of the database, currently only 'json' and 'bson' are supported -# 'json' = Will save as a JSON file in text format (Easy to read/change if you need to). -# 'bson' = Will save as a BSON file in binary format (This is what Hytale uses, much smaller file). +# file-type: json +# The file type of the database, currently only 'json' and 'bson' are supported +# 'json' = Will save as a JSON file in text format (Easy to read/change if you need to). +# 'bson' = Will save as a BSON file in binary format (This is what Hytale uses, much smaller file). # -# file: variables.json -# The file to save variables to. +# file: variables.json +# The file to save variables to. # -# pattern: .* -# The regex pattern to match variables to. -# '.*' = Will save all variables. -# '(?!-).*' = Will only save variables that don't start with '-' (ex: '{-some_var}' will not be saved). +# pattern: .* +# The regex pattern to match variables to. +# '.*' = Will save all variables. +# '(?!-).*' = Will only save variables that don't start with '-' (ex: '{-some_var}' will not be saved). - default: - type: json-database - enabled: true - file-type: json - file: variables.json - pattern: (?!-).* + default: + type: json-database + enabled: true + file-type: json + file: variables.json + pattern: (?!-).* From f83dce4c832da6f93edecbd965da38b9228b9e0a Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Mon, 9 Feb 2026 14:03:02 -0800 Subject: [PATCH 3/7] SkriptConfig - add updater --- .../api/skript/config/SkriptConfig.java | 98 ++++++++++++++++--- 1 file changed, 87 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/github/skriptdev/skript/api/skript/config/SkriptConfig.java b/src/main/java/com/github/skriptdev/skript/api/skript/config/SkriptConfig.java index 60c5115..5c32136 100644 --- a/src/main/java/com/github/skriptdev/skript/api/skript/config/SkriptConfig.java +++ b/src/main/java/com/github/skriptdev/skript/api/skript/config/SkriptConfig.java @@ -10,14 +10,25 @@ import io.github.syst3ms.skriptparser.log.SkriptLogger; import org.jetbrains.annotations.Nullable; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; /** * Config for Skript */ public class SkriptConfig { - private final Config config; + private Config config; private final boolean debug; private final int maxTargetBlockDistance; private final ConfigSection effectCommands; @@ -40,8 +51,15 @@ public SkriptConfig(Skript skript) { logger.debug("Checking for update from: " + configVersion); Semver hySkriptVersion = skript.getPlugin().getManifest().getVersion(); if (configVersion.compareTo(hySkriptVersion) < 0) { - logger.debug("Updating config to version: " + hySkriptVersion); - updateConfig(); + logger.info("Updating config to version: " + hySkriptVersion); + try { + // Update the config from the default config + updateConfig(skriptConfigPath, hySkriptVersion.toString()); + // Reload the config so we have updated values + this.config = new Config(skriptConfigPath, "/config.sk", logger); + } catch (IOException e) { + throw new RuntimeException(e); + } } else { logger.debug("Config is up to date"); } @@ -51,10 +69,7 @@ public SkriptConfig(Skript skript) { // Set up max-target-block-distance this.maxTargetBlockDistance = this.config.getInt("max-target-block-distance"); - if (this.maxTargetBlockDistance == -1) { - // This would happen if the config is missing this value - // TODO update config - } else if (this.maxTargetBlockDistance < 0) { + if (this.maxTargetBlockDistance < 0) { logger.error("max-target-block-distance must be greater than or equal to 0", ErrorType.STRUCTURE_ERROR); } @@ -62,14 +77,12 @@ public SkriptConfig(Skript skript) { this.effectCommands = this.config.getConfigSection("effect-commands"); if (this.effectCommands == null) { logger.error("Effect commands section not found in config.sk", ErrorType.STRUCTURE_ERROR); - // TODO update config } // Set up databases this.databases = this.config.getConfigSection("databases"); if (this.databases == null) { logger.error("Databases section not found in config.sk", ErrorType.STRUCTURE_ERROR); - // TODO update config } // Set up commands generate permissions @@ -131,8 +144,71 @@ public boolean getCommandsGeneratePermissions() { return this.commandsGeneratePermissions; } - private void updateConfig() { - // TODO update config + @SuppressWarnings("resource") + private void updateConfig(Path userPath, String version) throws IOException { + Set userKeys = Files.lines(userPath) + .map(String::trim) + .filter(l -> !l.startsWith("#") && l.contains(":")) + .map(l -> l.split(":")[0].trim()) + .collect(Collectors.toSet()); + + InputStream stream = SkriptConfig.class.getResourceAsStream("/config.sk"); + assert stream != null; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); + BufferedWriter writer = Files.newBufferedWriter(userPath, StandardOpenOption.APPEND)) { + + List commentBuffer = new ArrayList<>(); + String line; + + while ((line = reader.readLine()) != null) { + String trimmed = line.trim(); + + if (trimmed.startsWith("#")) { + // It's a comment, save it for the next key we find + commentBuffer.add(line); + } else if (trimmed.contains(":")) { + String key = trimmed.split(":")[0].trim(); + + if (!userKeys.contains(key)) { + // User is missing this key! + writer.newLine(); // Add spacing for readability + + // Write the buffered comments first + for (String comment : commentBuffer) { + writer.write(comment); + writer.newLine(); + } + // Write the actual key-value pair + writer.write(line); + writer.newLine(); + } + // Clear buffer regardless of whether we wrote it or not + commentBuffer.clear(); + } else if (trimmed.isEmpty()) { + commentBuffer.clear(); + } + } + } + + updateConfigVersion(userPath, version); + } + + private void updateConfigVersion(Path userPath, String newVersion) throws IOException { + List lines = Files.readAllLines(userPath); + boolean updated = false; + + for (int i = 0; i < lines.size(); i++) { + String line = lines.get(i).trim(); + if (line.startsWith("hyskript-version:")) { + lines.set(i, "hyskript-version: " + newVersion); + updated = true; + break; + } + } + + if (updated) { + Files.write(userPath, lines); + } } } From efc7433ef85dd6c29886c4e2a11546f6d0f78e2a Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Mon, 9 Feb 2026 22:13:33 -0800 Subject: [PATCH 4/7] EffBreakBlock - add missing name --- .../skript/plugin/elements/effects/block/EffBreakBlock.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/effects/block/EffBreakBlock.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/effects/block/EffBreakBlock.java index 17351bb..9734546 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/effects/block/EffBreakBlock.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/effects/block/EffBreakBlock.java @@ -12,6 +12,7 @@ public class EffBreakBlock extends Effect { public static void register(SkriptRegistration reg) { reg.newEffect(EffBreakBlock.class, "break %blocks% [with settings %number%]") + .name("Break Block") .description("Breaks the specified blocks.", "**Settings**:", "I don't really know what this does yet, but from testing:", From f7ba4ee96c026c3fd5f1e1bf700dea42a6e243cd Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Mon, 9 Feb 2026 22:20:52 -0800 Subject: [PATCH 5/7] EffTeleport - fix example --- .../skript/plugin/elements/effects/entity/EffTeleport.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/effects/entity/EffTeleport.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/effects/entity/EffTeleport.java index 52d74e8..c566099 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/effects/entity/EffTeleport.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/effects/entity/EffTeleport.java @@ -23,7 +23,7 @@ public static void register(SkriptRegistration registration) { .name("Teleport") .description("Teleport entities to a location.") .examples("teleport all players to {_location}", - "teleport player to bed location of player") + "teleport player to first element of (respawn locations of player)") .since("1.0.0") .register(); } From e677ea552578b7d7501efa5bb8cdcb103688b3ba Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Mon, 9 Feb 2026 22:22:43 -0800 Subject: [PATCH 6/7] ExprPlayerRespawnLocations - rename to match --- .../elements/expressions/ExpressionHandler.java | 4 ++-- ...yerSpawns.java => ExprPlayerRespawnLocations.java} | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) rename src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/player/{ExprPlayerSpawns.java => ExprPlayerRespawnLocations.java} (92%) diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/ExpressionHandler.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/ExpressionHandler.java index 0bc119c..953c272 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/ExpressionHandler.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/ExpressionHandler.java @@ -49,7 +49,7 @@ import com.github.skriptdev.skript.plugin.elements.expressions.player.ExprGameMode; import com.github.skriptdev.skript.plugin.elements.expressions.player.ExprPlayerPermissionGroup; import com.github.skriptdev.skript.plugin.elements.expressions.player.ExprPlayerPermissions; -import com.github.skriptdev.skript.plugin.elements.expressions.player.ExprPlayerSpawns; +import com.github.skriptdev.skript.plugin.elements.expressions.player.ExprPlayerRespawnLocations; import com.github.skriptdev.skript.plugin.elements.expressions.server.ExprConsole; import com.github.skriptdev.skript.plugin.elements.expressions.world.ExprChunkAtLocation; import com.github.skriptdev.skript.plugin.elements.expressions.world.ExprRelativePositionResolve; @@ -118,7 +118,7 @@ public static void register(SkriptRegistration registration) { ExprGameMode.register(registration); ExprPlayerPermissionGroup.register(registration); ExprPlayerPermissions.register(registration); - ExprPlayerSpawns.register(registration); + ExprPlayerRespawnLocations.register(registration); // SERVER ExprConsole.register(registration); diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/player/ExprPlayerSpawns.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/player/ExprPlayerRespawnLocations.java similarity index 92% rename from src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/player/ExprPlayerSpawns.java rename to src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/player/ExprPlayerRespawnLocations.java index 683776e..dfd81ef 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/player/ExprPlayerSpawns.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/expressions/player/ExprPlayerRespawnLocations.java @@ -15,14 +15,15 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; -public class ExprPlayerSpawns implements Expression { +public class ExprPlayerRespawnLocations implements Expression { public static void register(SkriptRegistration reg) { - reg.newExpression(ExprPlayerSpawns.class, Location.class, false, + reg.newExpression(ExprPlayerRespawnLocations.class, Location.class, false, "[player] respawn locations of %player%", "[player] respawn locations of %player% in %worlds%") .name("Player Respawn Locations") @@ -57,11 +58,9 @@ public Location[] getValues(@NotNull TriggerContext ctx) { List worlds = new ArrayList<>(); if (this.worlds != null) { - for (World world : this.worlds.getArray(ctx)) { - worlds.add(world); - } + Collections.addAll(worlds, this.worlds.getArray(ctx)); } else { - Universe.get().getWorlds().forEach((s, world) -> worlds.add(world)); + Universe.get().getWorlds().forEach((_, world) -> worlds.add(world)); } List spawns = new ArrayList<>(); From 481286b1f1f3e46e5ca918b5a9d9b7514cdd5287 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Mon, 9 Feb 2026 22:40:39 -0800 Subject: [PATCH 7/7] ScriptCommandBuilder - modify normal commands to run in a world if executed by player --- .../skript/command/ScriptCommandBuilder.java | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/github/skriptdev/skript/api/skript/command/ScriptCommandBuilder.java b/src/main/java/com/github/skriptdev/skript/api/skript/command/ScriptCommandBuilder.java index 2da6793..a060201 100644 --- a/src/main/java/com/github/skriptdev/skript/api/skript/command/ScriptCommandBuilder.java +++ b/src/main/java/com/github/skriptdev/skript/api/skript/command/ScriptCommandBuilder.java @@ -39,6 +39,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; /** * Builder for Script Commands. @@ -171,14 +172,29 @@ protected boolean canGeneratePermission() { protected @Nullable CompletableFuture execute(@NotNull CommandContext commandContext) { CompletableFuture.runAsync(() -> { CommandSender sender = commandContext.sender(); - Player player = null; - if (sender instanceof Player p) player = p; - ScriptCommandContext context = new ScriptCommandContext(ScriptCommandBuilder.this.commandName, - sender); - - createLocalVariables(commandContext, context); - Statement.runAll(trigger, context); - Variables.clearLocalVariables(context); + + AtomicReference context = new AtomicReference<>(); + + Runnable code = () -> { + createLocalVariables(commandContext, context.get()); + Statement.runAll(trigger, context.get()); + Variables.clearLocalVariables(context.get()); + }; + + if (sender instanceof Player player && player.getWorld() != null) { + // If a player runs the command, run it in their world + context.set(new PlayerScriptCommandContext(commandName, player)); + World world = player.getWorld(); + if (world.isInThread()) { + code.run(); + } else { + world.execute(code); + } + } else { + // Otherwise run as normal + context.set(new ScriptCommandContext(commandName, sender)); + code.run(); + } }); return null; }