Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
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.google.gson.JsonObject;
import com.hypixel.hytale.server.core.HytaleServer;
import com.hypixel.hytale.server.core.util.BsonUtil;
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;
import io.github.syst3ms.skriptparser.variables.Variables;
import org.bson.BsonBinaryReader;
import org.bson.BsonBinaryWriter;
import org.bson.BsonDocument;
import org.bson.BsonString;
import org.bson.BsonValue;
import org.bson.codecs.BsonDocumentCodec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
import org.bson.io.BasicOutputBuffer;
import org.bson.json.JsonWriterSettings;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.ByteBuffer;
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;
}

private File file;
private Type type = null;
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 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;
}
this.type = switch (fileType.toLowerCase(Locale.ROOT)) {
case "json" -> Type.JSON;
case "bson" -> Type.BSON;
default -> {
this.logger.error("Unknown file-type '" + fileType + "' in database '" + this.name + "'", ErrorType.EXCEPTION);
yield null;
}
};
this.logger.info("Database '" + this.name + "' loaded with filetype '" + this.type + "'");
return this.type != null;
}

@Override
protected void allLoaded() {
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);
}
}

@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()) {
this.logger.info("Created " + fileName + " file!");
} else {
this.logger.error("Failed to create " + fileName + " file!", ErrorType.EXCEPTION);
}
} 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.bsonDocument.remove(name);
}

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

private void saveVariables(boolean finalSave) throws IOException {
if (finalSave) {
this.schedule.cancel(true);
}
try {
Variables.getLock().lock();
writeBsonFile();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
Variables.getLock().unlock();
}
}

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(this.file);
JsonWriterSettings.Builder indent = JsonWriterSettings.builder().indent(true);
fileWriter.write(this.bsonDocument.toJson(indent.build()));
fileWriter.close();
} else if (this.type == Type.BSON) {
BasicOutputBuffer outputBuffer = new BasicOutputBuffer();
try (BsonBinaryWriter writer = new BsonBinaryWriter(outputBuffer)) {
new BsonDocumentCodec().encode(writer, this.bsonDocument, EncoderContext.builder().build());
}

byte[] bsonBytes = outputBuffer.toByteArray();
try (FileOutputStream fos = new FileOutputStream(this.file)) {
fos.write(bsonBytes);
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/main/java/com/github/skriptdev/skript/plugin/HySk.java
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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;
}
Expand Down
41 changes: 38 additions & 3 deletions src/main/java/com/github/skriptdev/skript/plugin/Skript.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,26 @@
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.hypixel.hytale.server.core.console.ConsoleSender;
import io.github.syst3ms.skriptparser.Parser;
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.variables.Variables;

import java.nio.file.Path;

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;
Expand All @@ -27,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() {
Expand All @@ -46,14 +60,23 @@ 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();
}

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

Expand Down Expand Up @@ -97,4 +120,16 @@ public ScriptsLoader getScriptsLoader() {
return this.scriptsLoader;
}

public void loadVariables() {
Utils.log("Loading variables...");
Variables.registerStorage(JsonVariableStorage.class, "json-database");
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!");
}

}
Loading
Loading