From b228a92887ce461557235f9f88cc771717e65b15 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Tue, 27 Jan 2026 13:00:13 -0800 Subject: [PATCH 1/7] Variables - initial work on variables (in progress) --- .../skript/variables/JsonVariableStorage.java | 135 ++++++++++++++++++ .../skriptdev/skript/plugin/Skript.java | 52 ++++++- .../skript/plugin/elements/types/Types.java | 25 ++-- src/main/resources/config.sk | 7 + 4 files changed, 210 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java create mode 100644 src/main/resources/config.sk diff --git a/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java b/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java new file mode 100644 index 00000000..8bc9d509 --- /dev/null +++ b/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java @@ -0,0 +1,135 @@ +package com.github.skriptdev.skript.api.skript.variables; + +import com.github.skriptdev.skript.api.utils.Utils; +import com.github.skriptdev.skript.plugin.HySk; +import com.google.gson.JsonElement; +import com.hypixel.hytale.server.core.util.BsonUtil; +import io.github.syst3ms.skriptparser.file.FileSection; +import io.github.syst3ms.skriptparser.log.SkriptLogger; +import io.github.syst3ms.skriptparser.variables.VariableStorage; +import org.bson.BsonDocument; +import org.bson.BsonString; +import org.bson.BsonValue; +import org.bson.json.JsonWriterSettings; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Locale; + +public class JsonVariableStorage extends VariableStorage { + + public enum Type { + JSON, + BSON; + } + + private File file; + private Type type = null; + private final BsonDocument bsonFile = new BsonDocument(); + + public JsonVariableStorage(SkriptLogger logger, String name) { + super(logger, name); + } + + @Override + protected boolean load(@NotNull FileSection section) { + String fileType = getConfigurationValue(section, "file-type"); + if (fileType == null) { + Utils.error("No 'file-type' specified for database '%s'!", this.name); + return false; + } + this.type = switch (fileType.toLowerCase(Locale.ROOT)) { + case "json" -> Type.JSON; + case "bson" -> Type.BSON; + default -> { + Utils.error("Unknown file-type '%s' in database '%s'", fileType, this.name); + yield null; + } + }; + Utils.log("Database '%s' loaded with filetype '%s'", this.name, this.type); + return this.type != null; + } + + @Override + protected void allLoaded() { + // Load variables here?!?! + } + + @Override + protected boolean requiresFile() { + return true; + } + + @Override + protected @Nullable File getFile(@NotNull String fileName) { + Path resolve = HySk.getInstance().getDataDirectory().resolve(fileName); + File varFile = resolve.toFile(); + if (!varFile.exists()) { + try { + if (varFile.createNewFile()) { + Utils.log("Created " + fileName + " file!"); + } else { + Utils.error("Failed to create " + fileName + " file!"); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + this.file = varFile; + return varFile; + } + + @Override + protected boolean save(@NotNull String name, @Nullable String type, @Nullable JsonElement value) { + BsonDocument myDocument = BsonDocument.parse("{}"); + + + if (type != null && value != null) { + try { + BsonValue bsonValue = BsonUtil.translateJsonToBson(value); + myDocument.put("type", new BsonString(type)); + + if (bsonValue instanceof BsonDocument doc) { + myDocument.put("value", doc); + } else { + myDocument.put("value", bsonValue); + } + } catch (Exception e) { + Utils.error("Failed to parse value: " + value); + } + } else { + this.bsonFile.remove(name); + } + + this.bsonFile.put(name, myDocument); + try { + writeBsonDocumentToFile(this.type, this.bsonFile, this.file); + } catch (IOException e) { + Utils.error("Failed to save variable file"); + throw new RuntimeException(e); + } + return true; + } + + @Override + public void close() throws IOException { + this.closed = true; + } + + @SuppressWarnings("StatementWithEmptyBody") + public static void writeBsonDocumentToFile(Type type, BsonDocument document, File file) throws IOException { + if (type == Type.JSON) { + FileWriter fileWriter = new FileWriter(file); + JsonWriterSettings.Builder indent = JsonWriterSettings.builder().indent(true); + fileWriter.write(document.toJson(indent.build())); + fileWriter.close(); + } else { + } + } + +} diff --git a/src/main/java/com/github/skriptdev/skript/plugin/Skript.java b/src/main/java/com/github/skriptdev/skript/plugin/Skript.java index 36d000dd..3fafdb6a 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/Skript.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/Skript.java @@ -3,15 +3,28 @@ import com.github.skriptdev.skript.api.skript.ScriptsLoader; import com.github.skriptdev.skript.api.skript.command.ArgUtils; import com.github.skriptdev.skript.api.skript.registration.SkriptRegistration; +import com.github.skriptdev.skript.api.skript.variables.JsonVariableStorage; import com.github.skriptdev.skript.api.utils.ReflectionUtils; import com.github.skriptdev.skript.api.utils.Utils; import com.github.skriptdev.skript.plugin.elements.ElementRegistration; +import com.google.errorprone.annotations.Var; import com.hypixel.hytale.server.core.console.ConsoleSender; import io.github.syst3ms.skriptparser.Parser; +import io.github.syst3ms.skriptparser.file.FileElement; +import io.github.syst3ms.skriptparser.file.FileParser; +import io.github.syst3ms.skriptparser.file.FileSection; +import io.github.syst3ms.skriptparser.log.LogEntry; import io.github.syst3ms.skriptparser.log.SkriptLogger; import io.github.syst3ms.skriptparser.registration.SkriptAddon; +import io.github.syst3ms.skriptparser.util.FileUtils; +import io.github.syst3ms.skriptparser.variables.VariableStorage; +import io.github.syst3ms.skriptparser.variables.Variables; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; public class Skript extends SkriptAddon { @@ -46,9 +59,12 @@ private void setup() { printSyntaxCount(); Utils.log("HySkript setup complete!"); + // LOAD VARIABLES + loadVariables(); + // LOAD SCRIPTS this.scriptsLoader = new ScriptsLoader(this); - this.scriptsLoader.loadScripts(ConsoleSender.INSTANCE, this.scriptsPath, false); + this.scriptsLoader.loadScripts(null, this.scriptsPath, false); // FINALIZE SCRIPT LOADING Parser.getMainRegistration().getRegisterer().finishedLoading(); @@ -97,4 +113,38 @@ public ScriptsLoader getScriptsLoader() { return this.scriptsLoader; } + public void loadVariables() { + Utils.log("Loading variables..."); + Variables.registerStorage(JsonVariableStorage.class, "json-database"); + Path configPath = this.hySk.getDataDirectory().resolve("config.sk"); + if (!configPath.toFile().exists()) { + InputStream resourceAsStream = this.getClass().getResourceAsStream("/config.sk"); + try { + Files.copy(resourceAsStream, configPath); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + SkriptLogger logger = new SkriptLogger(true); + List strings; + try { + strings = FileUtils.readAllLines(configPath); + } catch (IOException e) { + throw new RuntimeException(e); + } + List fileElements = FileParser.parseFileLines("config.sk", strings, 0, 1, logger); + for (FileElement fileElement : fileElements) { + if (fileElement instanceof FileSection sec && fileElement.getLineContent().equals("databases")) { + Variables.load(logger, sec); + logger.finalizeLogs(); + for (LogEntry logEntry : logger.close()) { + Utils.log(logEntry.getMessage()); + } + } + } + Utils.log("Finished loading variables!"); + + } + } diff --git a/src/main/java/com/github/skriptdev/skript/plugin/elements/types/Types.java b/src/main/java/com/github/skriptdev/skript/plugin/elements/types/Types.java index a69d8708..c6ad7ceb 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/elements/types/Types.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/elements/types/Types.java @@ -52,6 +52,7 @@ import java.util.UUID; +@SuppressWarnings("deprecation") public class Types { public static void register(SkriptRegistration registration) { @@ -73,18 +74,16 @@ private static void registerJavaTypes(SkriptRegistration registration) { .description("Represents a UUID.") .examples("set {_uuid} to uuid of {_player}") .since("INSERT VERSION") + .toStringFunction(UUID::toString) .serializer(new TypeSerializer<>() { - // TODO no clue if this actually works, will need to test @Override - public JsonElement serialize(@NotNull Gson gson, @NotNull UUID uuid) { - String json = gson.toJson(uuid, UUID.class); - return gson.fromJson(json, JsonElement.class); + public JsonElement serialize(@NotNull Gson gson, @NotNull UUID value) { + return gson.toJsonTree(value.toString()); } @Override public UUID deserialize(@NotNull Gson gson, @NotNull JsonElement element) { - UUID uuid = gson.fromJson(element.toString(), UUID.class); - return uuid == null ? UUID.fromString(element.getAsString()) : uuid; + return UUID.fromString(element.getAsString()); } }) .register(); @@ -113,7 +112,6 @@ private static void registerServerTypes(SkriptRegistration registration) { .description("Represents a stylized message sent to a message receiver.") .since("INSERT VERSION") .serializer(new TypeSerializer<>() { - @Override public JsonElement serialize(@NotNull Gson gson, @NotNull Message value) { BsonValue encode = Message.CODEC.encode(value, new ExtraInfo()); @@ -138,7 +136,6 @@ public Message deserialize(@NotNull Gson gson, @NotNull JsonElement element) { "Often used for the rotation of entities in a world.") .since("INSERT VERSION") .serializer(new TypeSerializer<>() { - @Override public JsonElement serialize(@NotNull Gson gson, @NotNull Vector3f value) { BsonDocument encode = Vector3f.CODEC.encode(value, new ExtraInfo()); @@ -269,6 +266,18 @@ public ItemStack deserialize(@NotNull Gson gson, @NotNull JsonElement element) { .description("Represents an inventory of an entity or block.") .since("INSERT VERSION") .toStringFunction(Inventory::toString) + .serializer(new TypeSerializer<>() { + @Override + public JsonElement serialize(@NotNull Gson gson, @NotNull Inventory value) { + BsonDocument encode = Inventory.CODEC.encode(value, new ExtraInfo()); + return gson.fromJson(encode.toJson(), JsonElement.class); + } + + @Override + public Inventory deserialize(@NotNull Gson gson, @NotNull JsonElement element) { + return Inventory.CODEC.decode(BsonDocument.parse(element.toString()), new ExtraInfo()); + } + }) .register(); EnumRegistry.register(registration, InventoryActionType.class, "inventoryactiontype", "inventoryActionType@s") .name("Inventory Action Type") diff --git a/src/main/resources/config.sk b/src/main/resources/config.sk new file mode 100644 index 00000000..e72d2e78 --- /dev/null +++ b/src/main/resources/config.sk @@ -0,0 +1,7 @@ +databases: + default: + type: json-database + file-type: json + file: variables.json + pattern: .* + From 7c51e7a1aa0acc155899fc2b2a5e94f83b349643 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 28 Jan 2026 11:48:48 -0800 Subject: [PATCH 2/7] Utils - change debug color --- .../java/com/github/skriptdev/skript/api/utils/Utils.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/github/skriptdev/skript/api/utils/Utils.java b/src/main/java/com/github/skriptdev/skript/api/utils/Utils.java index 8ba28e88..cee1b64f 100644 --- a/src/main/java/com/github/skriptdev/skript/api/utils/Utils.java +++ b/src/main/java/com/github/skriptdev/skript/api/utils/Utils.java @@ -38,7 +38,7 @@ public static void log(IMessageReceiver receiver, Level level, String message, O if (receiver == null) { HySk.getInstance().getLogger().at(level).log(message); } else { - Color color = level == Level.SEVERE ? Color.RED : level == Level.WARNING ? Color.YELLOW : Color.WHITE; + Color color = level == Level.SEVERE ? Color.RED : level == Level.WARNING ? Color.YELLOW : level == Level.FINE ? Color.PINK : Color.WHITE; Message coloredMessage = Message.raw(message).color(color); Message m = Message.empty().insert(CORE_PREFIX).insert(coloredMessage); @@ -58,9 +58,9 @@ public static void log(IMessageReceiver receiver, LogEntry logEntry) { String message = logEntry.getMessage(); switch (logEntry.getType()) { case DEBUG -> log(receiver, Level.FINE, message); - case INFO -> log(receiver, message); - case ERROR -> error(receiver, message); - case WARNING -> warn(receiver, message); + case INFO -> log(receiver, Level.INFO, message); + case ERROR -> log(receiver, Level.SEVERE, message); + case WARNING -> log(receiver, Level.WARNING, message); } } From 4442ffb66be273d7e9fc469fe4cb6126b745b20c Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 28 Jan 2026 11:56:09 -0800 Subject: [PATCH 3/7] Variables - got saving/loading working --- .../skript/variables/JsonVariableStorage.java | 181 +++++++++++++++--- .../github/skriptdev/skript/plugin/HySk.java | 9 + .../skriptdev/skript/plugin/Skript.java | 11 +- 3 files changed, 169 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java b/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java index 8bc9d509..6df3b6f2 100644 --- a/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java +++ b/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java @@ -3,60 +3,166 @@ import com.github.skriptdev.skript.api.utils.Utils; import com.github.skriptdev.skript.plugin.HySk; import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.hypixel.hytale.server.core.HytaleServer; import com.hypixel.hytale.server.core.util.BsonUtil; import io.github.syst3ms.skriptparser.file.FileSection; +import io.github.syst3ms.skriptparser.log.ErrorType; import io.github.syst3ms.skriptparser.log.SkriptLogger; import io.github.syst3ms.skriptparser.variables.VariableStorage; +import io.github.syst3ms.skriptparser.variables.Variables; +import org.bson.BsonBinaryReader; +import org.bson.BsonBinaryWriter; import org.bson.BsonDocument; +import org.bson.BsonReader; import org.bson.BsonString; import org.bson.BsonValue; +import org.bson.ByteBufNIO; +import org.bson.codecs.BsonDocumentCodec; +import org.bson.codecs.DecoderContext; +import org.bson.codecs.EncoderContext; +import org.bson.io.BasicOutputBuffer; +import org.bson.io.ByteBufferBsonInput; import org.bson.json.JsonWriterSettings; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Files; import java.nio.file.Path; import java.util.Locale; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; public class JsonVariableStorage extends VariableStorage { public enum Type { - JSON, - BSON; + JSON, BSON; } private File file; private Type type = null; - private final BsonDocument bsonFile = new BsonDocument(); + private BsonDocument bsonDocument; + private final AtomicInteger changes = new AtomicInteger(0); + private final int changesToSave = 500; + ScheduledFuture schedule; + private final SkriptLogger logger; public JsonVariableStorage(SkriptLogger logger, String name) { super(logger, name); + this.logger = logger; } @Override protected boolean load(@NotNull FileSection section) { String fileType = getConfigurationValue(section, "file-type"); if (fileType == null) { - Utils.error("No 'file-type' specified for database '%s'!", this.name); + this.logger.error("No 'file-type' specified for database '" + this.name + "'!", ErrorType.EXCEPTION); return false; } this.type = switch (fileType.toLowerCase(Locale.ROOT)) { case "json" -> Type.JSON; case "bson" -> Type.BSON; default -> { - Utils.error("Unknown file-type '%s' in database '%s'", fileType, this.name); + this.logger.error("Unknown file-type '" + fileType + "' in database '" + this.name + "'", ErrorType.EXCEPTION); yield null; } }; - Utils.log("Database '%s' loaded with filetype '%s'", this.name, this.type); + this.logger.error("Database '" + this.name + "' loaded with filetype '" + this.type + "'", ErrorType.EXCEPTION); return this.type != null; } @Override protected void allLoaded() { - // Load variables here?!?! + loadVariablesFromFile(); + startFileWatcher(); + } + + private void startFileWatcher() { + this.schedule = HytaleServer.SCHEDULED_EXECUTOR.scheduleAtFixedRate(() -> { + if (this.changes.get() >= this.changesToSave) { + try { + saveVariables(false); + this.logger.info("Saved " + this.changes.get() + " changes to '" + this.file.getName() + "'"); // TODO REMOVE (debug) + this.changes.set(0); + } catch (IOException e) { + this.logger.error("Failed to save variable file", ErrorType.EXCEPTION); + throw new RuntimeException(e); + } + } + }, 5, 5, TimeUnit.MINUTES); + } + + private void loadVariablesFromFile() { + this.logger.info("Loading variables from file..."); + + try { + if (this.type == Type.JSON) { + readJsonFile(); + } else if (this.type == Type.BSON) { + readBsonFile(); + } + if (this.bsonDocument == null) { + this.bsonDocument = new BsonDocument(); + } + JsonElement jsonElement = BsonUtil.translateBsonToJson(this.bsonDocument); + if (jsonElement instanceof JsonObject jsonObject) { + jsonObject.entrySet().forEach(entry -> { + String name = entry.getKey(); + JsonObject value = entry.getValue().getAsJsonObject(); + String type = value.get("type").getAsString(); + JsonElement jsonValue = value.get("value"); + + this.logger.debug("Loading variable '" + name + "' of type '" + type + "' from file. With data '" + jsonValue.toString() + "'"); + loadVariable(name, type, jsonValue); + }); + } + + } catch (IOException e) { + this.logger.error("Failed to load variables from file", ErrorType.EXCEPTION); + throw new RuntimeException(e); + } + } + + private void readJsonFile() throws IOException { + String jsonContent = Files.readString(this.file.toPath()); + if (jsonContent.isBlank()) { + this.bsonDocument = new BsonDocument(); + } else { + this.bsonDocument = BsonDocument.parse(jsonContent); + } + } + + private void readBsonFile() throws IOException { + if (!this.file.exists()) { + throw new FileNotFoundException("File not found: " + this.file.getAbsolutePath()); + } + + try (FileInputStream fis = new FileInputStream(file); FileChannel fc = fis.getChannel()) { + // Read the entire file into a ByteBuffer + ByteBuffer buffer = ByteBuffer.allocate((int) fc.size()); + fc.read(buffer); + buffer.flip(); + + try (ByteBufferBsonInput bib = new ByteBufferBsonInput(new ByteBufNIO(buffer))) { + // Use BsonBinaryReader to read the BSON data + BsonReader reader = new BsonBinaryReader(bib); + + // Use a BsonDocumentCodec to decode the BSON into a BsonDocument object + BsonDocumentCodec codec = new BsonDocumentCodec(); + DecoderContext decoderContext = DecoderContext.builder().build(); + + this.bsonDocument = codec.decode(reader, decoderContext); + } + } } @Override @@ -71,9 +177,9 @@ protected boolean requiresFile() { if (!varFile.exists()) { try { if (varFile.createNewFile()) { - Utils.log("Created " + fileName + " file!"); + this.logger.info("Created " + fileName + " file!"); } else { - Utils.error("Failed to create " + fileName + " file!"); + this.logger.error("Failed to create " + fileName + " file!", ErrorType.EXCEPTION); } } catch (IOException e) { throw new RuntimeException(e); @@ -88,47 +194,66 @@ protected boolean requiresFile() { protected boolean save(@NotNull String name, @Nullable String type, @Nullable JsonElement value) { BsonDocument myDocument = BsonDocument.parse("{}"); - if (type != null && value != null) { try { BsonValue bsonValue = BsonUtil.translateJsonToBson(value); myDocument.put("type", new BsonString(type)); - if (bsonValue instanceof BsonDocument doc) { - myDocument.put("value", doc); - } else { - myDocument.put("value", bsonValue); - } + if (bsonValue instanceof BsonDocument doc) { + myDocument.put("value", doc); + } else { + myDocument.put("value", bsonValue); + } } catch (Exception e) { Utils.error("Failed to parse value: " + value); } } else { - this.bsonFile.remove(name); + this.bsonDocument.remove(name); } - this.bsonFile.put(name, myDocument); - try { - writeBsonDocumentToFile(this.type, this.bsonFile, this.file); - } catch (IOException e) { - Utils.error("Failed to save variable file"); - throw new RuntimeException(e); - } + this.bsonDocument.put(name, myDocument); + this.changes.incrementAndGet(); return true; } @Override public void close() throws IOException { + Utils.log("Closing database '" + this.name + "'"); + saveVariables(true); this.closed = true; } - @SuppressWarnings("StatementWithEmptyBody") - public static void writeBsonDocumentToFile(Type type, BsonDocument document, File file) throws IOException { - if (type == Type.JSON) { + private void saveVariables(boolean finalSave) throws IOException { + if (finalSave) { + this.schedule.cancel(true); + } + try { + Variables.getLock().lock(); + writeBsonDocumentToFile(); + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + Variables.getLock().unlock(); + } + } + + public void writeBsonDocumentToFile() throws IOException { + if (this.type == Type.JSON) { FileWriter fileWriter = new FileWriter(file); JsonWriterSettings.Builder indent = JsonWriterSettings.builder().indent(true); - fileWriter.write(document.toJson(indent.build())); + fileWriter.write(this.bsonDocument.toJson(indent.build())); fileWriter.close(); - } else { + } else if (this.type == Type.BSON) { + try (BasicOutputBuffer outputBuffer = new BasicOutputBuffer(); FileOutputStream fos = new FileOutputStream(this.file)) { + + BsonBinaryWriter writer = new BsonBinaryWriter(outputBuffer); + // Use BsonDocumentCodec to encode the BsonDocument to the writer + new BsonDocumentCodec().encode(writer, this.bsonDocument, EncoderContext.builder().isEncodingCollectibleDocument(true).build()); + writer.close(); + + // Write the byte array to the file + fos.write(outputBuffer.toByteArray()); + } } } diff --git a/src/main/java/com/github/skriptdev/skript/plugin/HySk.java b/src/main/java/com/github/skriptdev/skript/plugin/HySk.java index c27e0694..b26fd0ea 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/HySk.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/HySk.java @@ -1,8 +1,10 @@ package com.github.skriptdev.skript.plugin; +import com.github.skriptdev.skript.api.utils.Utils; import com.hypixel.hytale.server.core.plugin.JavaPlugin; import com.hypixel.hytale.server.core.plugin.JavaPluginInit; import com.github.skriptdev.skript.plugin.command.SkriptCommand; +import io.github.syst3ms.skriptparser.variables.Variables; import org.jetbrains.annotations.NotNull; public class HySk extends JavaPlugin { @@ -25,6 +27,13 @@ protected void start() { new SkriptCommand(getCommandRegistry()); } + @Override + protected void shutdown() { + Utils.log("Shutting down HySkript..."); + this.skript.shutdown(); + Utils.log("HySkript shutdown complete!"); + } + public Skript getSkript() { return this.skript; } diff --git a/src/main/java/com/github/skriptdev/skript/plugin/Skript.java b/src/main/java/com/github/skriptdev/skript/plugin/Skript.java index 3fafdb6a..6a40da7f 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/Skript.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/Skript.java @@ -7,8 +7,6 @@ import com.github.skriptdev.skript.api.utils.ReflectionUtils; import com.github.skriptdev.skript.api.utils.Utils; import com.github.skriptdev.skript.plugin.elements.ElementRegistration; -import com.google.errorprone.annotations.Var; -import com.hypixel.hytale.server.core.console.ConsoleSender; import io.github.syst3ms.skriptparser.Parser; import io.github.syst3ms.skriptparser.file.FileElement; import io.github.syst3ms.skriptparser.file.FileParser; @@ -17,7 +15,6 @@ import io.github.syst3ms.skriptparser.log.SkriptLogger; import io.github.syst3ms.skriptparser.registration.SkriptAddon; import io.github.syst3ms.skriptparser.util.FileUtils; -import io.github.syst3ms.skriptparser.variables.VariableStorage; import io.github.syst3ms.skriptparser.variables.Variables; import java.io.IOException; @@ -70,6 +67,12 @@ private void setup() { Parser.getMainRegistration().getRegisterer().finishedLoading(); } + public void shutdown() { + Utils.log("Saving variables..."); + Variables.shutdown(); + Utils.log("Variable saving complete!"); + } + private void printSyntaxCount() { io.github.syst3ms.skriptparser.registration.SkriptRegistration mainRegistration = Parser.getMainRegistration(); @@ -126,7 +129,7 @@ public void loadVariables() { } } - SkriptLogger logger = new SkriptLogger(true); + SkriptLogger logger = new SkriptLogger(false); List strings; try { strings = FileUtils.readAllLines(configPath); From ec9f3bae7679050e6a4a5ff56098b8304d93a8fd Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 28 Jan 2026 12:05:06 -0800 Subject: [PATCH 4/7] JsonVariableStorage - fix reading empty bin doc --- .../skript/api/skript/variables/JsonVariableStorage.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java b/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java index 6df3b6f2..bd89227e 100644 --- a/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java +++ b/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java @@ -16,6 +16,7 @@ import org.bson.BsonDocument; import org.bson.BsonReader; import org.bson.BsonString; +import org.bson.BsonType; import org.bson.BsonValue; import org.bson.ByteBufNIO; import org.bson.codecs.BsonDocumentCodec; @@ -159,8 +160,12 @@ private void readBsonFile() throws IOException { // Use a BsonDocumentCodec to decode the BSON into a BsonDocument object BsonDocumentCodec codec = new BsonDocumentCodec(); DecoderContext decoderContext = DecoderContext.builder().build(); - - this.bsonDocument = codec.decode(reader, decoderContext); + BsonType type = reader.getCurrentBsonType(); + if (type == null || type == BsonType.NULL || type == BsonType.END_OF_DOCUMENT) { + this.bsonDocument = new BsonDocument(); + } else { + this.bsonDocument = codec.decode(reader, decoderContext); + } } } } From 3435f671f2d09a445dea06ff2071320a891e0f4e Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 28 Jan 2026 13:04:31 -0800 Subject: [PATCH 5/7] JsonVariableStorage - fix reading/writing bin doc --- .../skript/variables/JsonVariableStorage.java | 90 ++++++++----------- 1 file changed, 36 insertions(+), 54 deletions(-) diff --git a/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java b/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java index bd89227e..c36cb119 100644 --- a/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java +++ b/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java @@ -14,28 +14,22 @@ import org.bson.BsonBinaryReader; import org.bson.BsonBinaryWriter; import org.bson.BsonDocument; -import org.bson.BsonReader; import org.bson.BsonString; -import org.bson.BsonType; import org.bson.BsonValue; -import org.bson.ByteBufNIO; import org.bson.codecs.BsonDocumentCodec; import org.bson.codecs.DecoderContext; import org.bson.codecs.EncoderContext; import org.bson.io.BasicOutputBuffer; -import org.bson.io.ByteBufferBsonInput; import org.bson.json.JsonWriterSettings; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; import java.util.Locale; @@ -133,43 +127,6 @@ private void loadVariablesFromFile() { } } - private void readJsonFile() throws IOException { - String jsonContent = Files.readString(this.file.toPath()); - if (jsonContent.isBlank()) { - this.bsonDocument = new BsonDocument(); - } else { - this.bsonDocument = BsonDocument.parse(jsonContent); - } - } - - private void readBsonFile() throws IOException { - if (!this.file.exists()) { - throw new FileNotFoundException("File not found: " + this.file.getAbsolutePath()); - } - - try (FileInputStream fis = new FileInputStream(file); FileChannel fc = fis.getChannel()) { - // Read the entire file into a ByteBuffer - ByteBuffer buffer = ByteBuffer.allocate((int) fc.size()); - fc.read(buffer); - buffer.flip(); - - try (ByteBufferBsonInput bib = new ByteBufferBsonInput(new ByteBufNIO(buffer))) { - // Use BsonBinaryReader to read the BSON data - BsonReader reader = new BsonBinaryReader(bib); - - // Use a BsonDocumentCodec to decode the BSON into a BsonDocument object - BsonDocumentCodec codec = new BsonDocumentCodec(); - DecoderContext decoderContext = DecoderContext.builder().build(); - BsonType type = reader.getCurrentBsonType(); - if (type == null || type == BsonType.NULL || type == BsonType.END_OF_DOCUMENT) { - this.bsonDocument = new BsonDocument(); - } else { - this.bsonDocument = codec.decode(reader, decoderContext); - } - } - } - } - @Override protected boolean requiresFile() { return true; @@ -234,7 +191,7 @@ private void saveVariables(boolean finalSave) throws IOException { } try { Variables.getLock().lock(); - writeBsonDocumentToFile(); + writeBsonFile(); } catch (IOException e) { throw new RuntimeException(e); } finally { @@ -242,22 +199,47 @@ private void saveVariables(boolean finalSave) throws IOException { } } - public void writeBsonDocumentToFile() throws IOException { + private void readJsonFile() throws IOException { + String jsonContent = Files.readString(this.file.toPath()); + if (jsonContent.isBlank()) { + this.bsonDocument = new BsonDocument(); + } else { + this.bsonDocument = BsonDocument.parse(jsonContent); + } + } + + private void readBsonFile() throws IOException { + if (!this.file.exists()) { + throw new FileNotFoundException("File not found: " + this.file.getAbsolutePath()); + } + + byte[] bsonBytes = Files.readAllBytes(this.file.toPath()); + if (bsonBytes.length > 0) { + try (BsonBinaryReader reader = new BsonBinaryReader(ByteBuffer.wrap(bsonBytes))) { + BsonDocument doc = new BsonDocumentCodec().decode(reader, DecoderContext.builder().build()); + this.bsonDocument = doc == null ? new BsonDocument() : doc; + } + } else { + this.bsonDocument = new BsonDocument(); + } + + } + + public void writeBsonFile() throws IOException { if (this.type == Type.JSON) { - FileWriter fileWriter = new FileWriter(file); + FileWriter fileWriter = new FileWriter(this.file); JsonWriterSettings.Builder indent = JsonWriterSettings.builder().indent(true); fileWriter.write(this.bsonDocument.toJson(indent.build())); fileWriter.close(); } else if (this.type == Type.BSON) { - try (BasicOutputBuffer outputBuffer = new BasicOutputBuffer(); FileOutputStream fos = new FileOutputStream(this.file)) { - - BsonBinaryWriter writer = new BsonBinaryWriter(outputBuffer); - // Use BsonDocumentCodec to encode the BsonDocument to the writer - new BsonDocumentCodec().encode(writer, this.bsonDocument, EncoderContext.builder().isEncodingCollectibleDocument(true).build()); - writer.close(); + BasicOutputBuffer outputBuffer = new BasicOutputBuffer(); + try (BsonBinaryWriter writer = new BsonBinaryWriter(outputBuffer)) { + new BsonDocumentCodec().encode(writer, this.bsonDocument, EncoderContext.builder().build()); + } - // Write the byte array to the file - fos.write(outputBuffer.toByteArray()); + byte[] bsonBytes = outputBuffer.toByteArray(); + try (FileOutputStream fos = new FileOutputStream(this.file)) { + fos.write(bsonBytes); } } } From 10f103719e457170351ecb98ec2367f70b489fec Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 28 Jan 2026 14:52:45 -0800 Subject: [PATCH 6/7] Variables - more updates --- .../skript/variables/JsonVariableStorage.java | 8 +-- .../skriptdev/skript/plugin/Skript.java | 54 +++++++------------ 2 files changed, 22 insertions(+), 40 deletions(-) diff --git a/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java b/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java index c36cb119..ff4d835e 100644 --- a/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java +++ b/src/main/java/com/github/skriptdev/skript/api/skript/variables/JsonVariableStorage.java @@ -6,7 +6,7 @@ import com.google.gson.JsonObject; import com.hypixel.hytale.server.core.HytaleServer; import com.hypixel.hytale.server.core.util.BsonUtil; -import io.github.syst3ms.skriptparser.file.FileSection; +import io.github.syst3ms.skriptparser.config.Config.ConfigSection; import io.github.syst3ms.skriptparser.log.ErrorType; import io.github.syst3ms.skriptparser.log.SkriptLogger; import io.github.syst3ms.skriptparser.variables.VariableStorage; @@ -57,8 +57,8 @@ public JsonVariableStorage(SkriptLogger logger, String name) { } @Override - protected boolean load(@NotNull FileSection section) { - String fileType = getConfigurationValue(section, "file-type"); + protected boolean load(@NotNull ConfigSection section) { + String fileType = section.getString("file-type"); if (fileType == null) { this.logger.error("No 'file-type' specified for database '" + this.name + "'!", ErrorType.EXCEPTION); return false; @@ -71,7 +71,7 @@ protected boolean load(@NotNull FileSection section) { yield null; } }; - this.logger.error("Database '" + this.name + "' loaded with filetype '" + this.type + "'", ErrorType.EXCEPTION); + this.logger.info("Database '" + this.name + "' loaded with filetype '" + this.type + "'"); return this.type != null; } diff --git a/src/main/java/com/github/skriptdev/skript/plugin/Skript.java b/src/main/java/com/github/skriptdev/skript/plugin/Skript.java index 6a40da7f..3c82d49c 100644 --- a/src/main/java/com/github/skriptdev/skript/plugin/Skript.java +++ b/src/main/java/com/github/skriptdev/skript/plugin/Skript.java @@ -8,25 +8,21 @@ import com.github.skriptdev.skript.api.utils.Utils; import com.github.skriptdev.skript.plugin.elements.ElementRegistration; import io.github.syst3ms.skriptparser.Parser; -import io.github.syst3ms.skriptparser.file.FileElement; -import io.github.syst3ms.skriptparser.file.FileParser; -import io.github.syst3ms.skriptparser.file.FileSection; +import io.github.syst3ms.skriptparser.config.Config; +import io.github.syst3ms.skriptparser.config.Config.ConfigSection; +import io.github.syst3ms.skriptparser.log.ErrorType; import io.github.syst3ms.skriptparser.log.LogEntry; import io.github.syst3ms.skriptparser.log.SkriptLogger; import io.github.syst3ms.skriptparser.registration.SkriptAddon; -import io.github.syst3ms.skriptparser.util.FileUtils; import io.github.syst3ms.skriptparser.variables.Variables; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; import java.nio.file.Path; -import java.util.List; public class Skript extends SkriptAddon { public static Skript INSTANCE; private final HySk hySk; + private final Config skriptConfig; private final Path scriptsPath; private final SkriptLogger logger; private SkriptRegistration registration; @@ -37,10 +33,18 @@ public Skript(HySk hySk) { INSTANCE = this; this.hySk = hySk; this.scriptsPath = hySk.getDataDirectory().resolve("scripts"); - this.logger = new SkriptLogger(true); + this.logger = new SkriptLogger(); + + Path skriptConfigPath = hySk.getDataDirectory().resolve("config.sk"); + this.skriptConfig = new Config(skriptConfigPath, "/config.sk", this.logger); + this.logger.setDebug(this.skriptConfig.getBoolean("debug")); Utils.log("Setting up HySkript!"); setup(); + this.logger.finalizeLogs(); + for (LogEntry logEntry : this.logger.close()) { + Utils.log(null, logEntry); + } } private void setup() { @@ -119,35 +123,13 @@ public ScriptsLoader getScriptsLoader() { public void loadVariables() { Utils.log("Loading variables..."); Variables.registerStorage(JsonVariableStorage.class, "json-database"); - Path configPath = this.hySk.getDataDirectory().resolve("config.sk"); - if (!configPath.toFile().exists()) { - InputStream resourceAsStream = this.getClass().getResourceAsStream("/config.sk"); - try { - Files.copy(resourceAsStream, configPath); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - SkriptLogger logger = new SkriptLogger(false); - List strings; - try { - strings = FileUtils.readAllLines(configPath); - } catch (IOException e) { - throw new RuntimeException(e); - } - List fileElements = FileParser.parseFileLines("config.sk", strings, 0, 1, logger); - for (FileElement fileElement : fileElements) { - if (fileElement instanceof FileSection sec && fileElement.getLineContent().equals("databases")) { - Variables.load(logger, sec); - logger.finalizeLogs(); - for (LogEntry logEntry : logger.close()) { - Utils.log(logEntry.getMessage()); - } - } + ConfigSection databases = this.skriptConfig.getConfigSection("databases"); + if (databases == null) { + this.logger.error("Databases section not found in config.sk", ErrorType.STRUCTURE_ERROR); + return; } + Variables.load(this.logger, databases); Utils.log("Finished loading variables!"); - } } From 47af3c2c793736b7b28bc91bd6a127cbe014a492 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 28 Jan 2026 15:01:20 -0800 Subject: [PATCH 7/7] config.sk - forgot to push --- src/main/resources/config.sk | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/main/resources/config.sk b/src/main/resources/config.sk index e72d2e78..4d281a25 100644 --- a/src/main/resources/config.sk +++ b/src/main/resources/config.sk @@ -1,7 +1,34 @@ +# HySkript Config + +debug: false +# Whether or not to enable debug mode (maybe print more verbose logs to console). + +# 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 +# +# 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: 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). + default: type: json-database + enabled: true file-type: json file: variables.json pattern: .* -