From aabff1623b58c01f08962475b04872a5b114850e Mon Sep 17 00:00:00 2001 From: altrisi Date: Sun, 27 Dec 2020 02:04:19 +0100 Subject: [PATCH] Reading/Writing JSON, first working version --- .../java/carpet/script/CarpetScriptHost.java | 18 +++-- .../java/carpet/script/api/Auxiliary.java | 35 ++++++--- .../carpet/script/bundled/FileModule.java | 22 +++++- .../java/carpet/script/bundled/Module.java | 41 +++++++--- .../script/utils/ScarpetJsonDeserializer.java | 78 +++++++++++++++++++ .../script/value/AbstractListValue.java | 2 +- 6 files changed, 163 insertions(+), 33 deletions(-) create mode 100644 src/main/java/carpet/script/utils/ScarpetJsonDeserializer.java diff --git a/src/main/java/carpet/script/CarpetScriptHost.java b/src/main/java/carpet/script/CarpetScriptHost.java index 09e08153..3bed089d 100644 --- a/src/main/java/carpet/script/CarpetScriptHost.java +++ b/src/main/java/carpet/script/CarpetScriptHost.java @@ -705,7 +705,7 @@ public class CarpetScriptHost extends ScriptHost public boolean removeResourceFile(String resource, boolean isShared, String type) { if (getName() == null && !isShared) return false; // - return Module.dropExistingFile(main, resource, type.equals("nbt")?"nbt":"txt", isShared); + return Module.dropExistingFile(main, resource, type, isShared); } public boolean appendLogFile(String resource, boolean isShared, String type, List data) @@ -714,16 +714,22 @@ public class CarpetScriptHost extends ScriptHost return Module.appendToTextFile(main, resource, type, isShared, data); } - public List readTextResource(String resource, boolean isShared) + public List readTextResource(String resource, String type, boolean isShared) { - if (getName() == null && !isShared) return null; // - return Module.listFile(main, resource, "txt", isShared); + if (getName() == null && !isShared) return null; + return Module.listFile(main, resource, type, isShared); + } + + public Value readJsonFile(String resource, String type, boolean isShared) + { + if (getName() == null && !isShared) return null; + return Module.readJsonFile(main, resource, type, isShared); } - public Stream listFolder(String resource, String ext, boolean isShared) + public Stream listFolder(String resource, String type, boolean isShared) { if (getName() == null && !isShared) return null; // - return Module.listFolder(main, resource, ext, isShared); + return Module.listFolder(main, resource, type, isShared); } diff --git a/src/main/java/carpet/script/api/Auxiliary.java b/src/main/java/carpet/script/api/Auxiliary.java index cb8dbee4..0949b6bd 100644 --- a/src/main/java/carpet/script/api/Auxiliary.java +++ b/src/main/java/carpet/script/api/Auxiliary.java @@ -6,6 +6,7 @@ import carpet.fakes.MinecraftServerInterface; import carpet.fakes.StatTypeInterface; import carpet.fakes.ThreadedAnvilChunkStorageInterface; import carpet.helpers.FeatureGenerator; +import carpet.script.bundled.Module; import carpet.script.CarpetContext; import carpet.script.CarpetEventServer; import carpet.script.CarpetScriptHost; @@ -19,6 +20,7 @@ import carpet.script.argument.Vector3Argument; import carpet.script.exception.ExitStatement; import carpet.script.exception.InternalExpressionException; import carpet.script.utils.FixedCommandSource; +import carpet.script.utils.ScarpetJsonDeserializer; import carpet.script.utils.ShapeDispatcher; import carpet.script.utils.WorldTools; import carpet.script.value.EntityValue; @@ -33,7 +35,9 @@ import carpet.script.value.StringValue; import carpet.script.value.Value; import carpet.script.value.ValueConversions; import carpet.utils.Messenger; -import com.google.common.collect.ImmutableMap; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; @@ -86,12 +90,7 @@ import static java.lang.Math.min; public class Auxiliary { public static final String MARKER_STRING = "__scarpet_marker"; private static final Map mixerMap = Arrays.stream(SoundCategory.values()).collect(Collectors.toMap(SoundCategory::getName, k -> k)); - private static final Map supportedTypes = ImmutableMap.of( - "raw", ".txt", - "text", ".txt", - "nbt", ".nbt", - "folder", "folder" - ); + public static final Gson gson = new GsonBuilder().setPrettyPrinting().registerTypeAdapter(Value.class, new ScarpetJsonDeserializer()).create(); public static String recognizeResource(Value value, boolean isFloder) { @@ -112,7 +111,7 @@ public class Auxiliary { String origtype = lv.get(1).evalValue(c).getString().toLowerCase(Locale.ROOT); boolean shared = origtype.startsWith("shared_"); String type = shared ? origtype.substring(7) : origtype; //len(shared_) - if (!supportedTypes.containsKey(type)) + if (!Module.supportedTypes.containsKey(type)) throw new InternalExpressionException("Unsupported file type: "+origtype); if (type.equals("folder") && !isFloder) throw new InternalExpressionException("Folder types are no supported for this IO function"); @@ -526,7 +525,7 @@ public class Auxiliary { Text title = null; if (lv.size() > 2) { - pVal = lv.get(2).evalValue(c); + pVal = lv.get(2).evalValue(c); if (pVal instanceof FormattedTextValue) title = ((FormattedTextValue) pVal).getText(); else @@ -803,7 +802,7 @@ public class Auxiliary { expression.addLazyFunction("list_files", 2, (c, t, lv) -> { Triple fdesc = getFileDescriptor(lv, c, true); - Stream files = ((CarpetScriptHost) c.host).listFolder(fdesc.getLeft(), supportedTypes.get(fdesc.getMiddle()), fdesc.getRight()); + Stream files = ((CarpetScriptHost) c.host).listFolder(fdesc.getLeft(), fdesc.getMiddle(), fdesc.getRight()); if (files == null) return LazyValue.NULL; Value ret = ListValue.wrap(files.map(StringValue::of).collect(Collectors.toList())); return (cc, tt) -> ret; @@ -820,9 +819,17 @@ public class Auxiliary { if (state == null) return LazyValue.NULL; retVal = new NBTSerializableValue(state); } + else if (fdesc.getMiddle().equals("json")) + { + Value parsedJson = ((CarpetScriptHost) c.host).readJsonFile(fdesc.getLeft(), fdesc.getMiddle(), fdesc.getRight()); + if (parsedJson == null) + retVal = Value.NULL; + else + retVal = parsedJson; + } else { - List content = ((CarpetScriptHost) c.host).readTextResource(fdesc.getLeft(), fdesc.getRight()); + List content = ((CarpetScriptHost) c.host).readTextResource(fdesc.getLeft(), fdesc.getMiddle(), fdesc.getRight()); if (content == null) return LazyValue.NULL; retVal = ListValue.wrap(content.stream().map(StringValue::new).collect(Collectors.toList())); } @@ -851,6 +858,12 @@ public class Auxiliary { Tag tag = tagValue.getTag(); success = ((CarpetScriptHost) c.host).writeTagFile(tag, fdesc.getLeft(), fdesc.getRight()); } + else if (fdesc.getMiddle().equals("json")) + { + List data = Collections.singletonList(gson.toJson(lv.get(2).evalValue(c).toJson())); + ((CarpetScriptHost) c.host).removeResourceFile(fdesc.getLeft(), fdesc.getRight(), fdesc.getMiddle()); + success = ((CarpetScriptHost) c.host).appendLogFile(fdesc.getLeft(), fdesc.getRight(), fdesc.getMiddle(), data); + } else { List data = new ArrayList<>(); diff --git a/src/main/java/carpet/script/bundled/FileModule.java b/src/main/java/carpet/script/bundled/FileModule.java index b710b376..ad798e27 100644 --- a/src/main/java/carpet/script/bundled/FileModule.java +++ b/src/main/java/carpet/script/bundled/FileModule.java @@ -25,6 +25,9 @@ import java.util.List; import java.util.Locale; import java.util.stream.Stream; +import carpet.script.api.Auxiliary; +import carpet.script.value.Value; + public class FileModule extends Module { private String name; @@ -137,11 +140,11 @@ public class FileModule extends Module return true; } - public static boolean appendText(File filePath, boolean addNewLines, List data) + public static boolean appendText(Path filePath, boolean addNewLines, List data) { try { - OutputStream out = Files.newOutputStream(filePath.toPath(), StandardOpenOption.APPEND, StandardOpenOption.CREATE); + OutputStream out = Files.newOutputStream(filePath, StandardOpenOption.APPEND, StandardOpenOption.CREATE); try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8))) { for (String line: data) @@ -159,9 +162,9 @@ public class FileModule extends Module } - public static List listFileContent(File filePath) + public static List listFileContent(Path filePath) { - try (BufferedReader reader = Files.newBufferedReader(filePath.toPath(), StandardCharsets.UTF_8)) { + try (BufferedReader reader = Files.newBufferedReader(filePath, StandardCharsets.UTF_8)) { List result = new ArrayList<>(); for (;;) { String line = reader.readLine(); @@ -176,6 +179,17 @@ public class FileModule extends Module return null; } } + + public static Value readJsonContent(Path filePath) + { + try (BufferedReader reader = Files.newBufferedReader(filePath, StandardCharsets.UTF_8)) { + return Auxiliary.gson.fromJson(reader, Value.class); + } + catch (IOException e) + { + return null; + } + } public static Stream listFiles(Path dir, String ext) { diff --git a/src/main/java/carpet/script/bundled/Module.java b/src/main/java/carpet/script/bundled/Module.java index 3bf5f8ce..510aa6e0 100644 --- a/src/main/java/carpet/script/bundled/Module.java +++ b/src/main/java/carpet/script/bundled/Module.java @@ -1,13 +1,17 @@ package carpet.script.bundled; import carpet.CarpetServer; +import carpet.script.value.Value; import net.minecraft.nbt.Tag; import net.minecraft.util.WorldSavePath; import org.apache.commons.io.FilenameUtils; +import com.google.common.collect.ImmutableMap; + import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.Map; import java.util.stream.Stream; public abstract class Module @@ -16,6 +20,13 @@ public abstract class Module public abstract String getCode(); public abstract boolean isLibrary(); public final static Object writeIOSync = new Object(); + public final static Map supportedTypes = ImmutableMap.of( + "raw", ".txt", + "text", ".txt", + "nbt", ".nbt", + "json", ".json", + "folder", "folder" + ); private static String getDescriptor(Module module, String file, boolean isShared) { @@ -32,7 +43,7 @@ public abstract class Module public static Tag getData(Module module, String file, boolean isShared) { - Path dataFile = resolveResource(module, file, "nbt", isShared); + Path dataFile = resolveResource(module, file, ".nbt", isShared); if (dataFile == null) return null; if (!Files.exists(dataFile) || !(dataFile.toFile().isFile())) return null; synchronized (writeIOSync) { return FileModule.read(dataFile.toFile()); } @@ -40,7 +51,7 @@ public abstract class Module public static boolean saveData(Module module, String file, Tag globalState, boolean isShared) { - Path dataFile = resolveResource(module, file, "nbt", isShared); + Path dataFile = resolveResource(module, file, ".nbt", isShared); if (dataFile == null) return false; if (!Files.exists(dataFile.getParent()) && !dataFile.toFile().getParentFile().mkdirs()) return false; synchronized (writeIOSync) { return FileModule.write(globalState, dataFile.toFile()); } @@ -48,30 +59,38 @@ public abstract class Module public static boolean appendToTextFile(Module module, String resourceName, String type, boolean isShared, List message) { - Path dataFile = resolveResource(module, resourceName, "txt", isShared); + Path dataFile = resolveResource(module, resourceName, supportedTypes.get(type), isShared); if (dataFile == null) return false; if (!Files.exists(dataFile.getParent()) && !dataFile.toFile().getParentFile().mkdirs()) return false; - synchronized (writeIOSync) { return FileModule.appendText(dataFile.toFile(), type.equals("text"), message); } + synchronized (writeIOSync) { return FileModule.appendText(dataFile, type.equals("text"), message); } } - public static boolean dropExistingFile(Module module, String resourceName, String ext, boolean isShared) + public static boolean dropExistingFile(Module module, String resourceName, String type, boolean isShared) { - Path dataFile = resolveResource(module, resourceName, ext, isShared); + Path dataFile = resolveResource(module, resourceName, supportedTypes.get(type), isShared); if (dataFile == null) return false; synchronized (writeIOSync) { return dataFile.toFile().delete(); } } - public static List listFile(Module module, String resourceName, String ext, boolean isShared) + public static List listFile(Module module, String resourceName, String type, boolean isShared) { - Path dataFile = resolveResource(module, resourceName, ext, isShared); + Path dataFile = resolveResource(module, resourceName, supportedTypes.get(type), isShared); if (dataFile == null) return null; if (!dataFile.toFile().exists()) return null; - synchronized (writeIOSync) { return FileModule.listFileContent(dataFile.toFile()); } + synchronized (writeIOSync) { return FileModule.listFileContent(dataFile); } + } + + public static Value readJsonFile(Module module, String resourceName, String type, boolean isShared) { + Path dataFile = resolveResource(module, resourceName, supportedTypes.get(type), isShared); + if (dataFile == null) return null; + if (!dataFile.toFile().exists()) return null; + synchronized (writeIOSync) { return FileModule.readJsonContent(dataFile); } } - public static Stream listFolder(Module module, String resourceName, String ext, boolean isShared) + public static Stream listFolder(Module module, String resourceName, String type, boolean isShared) { Path dir = resolveResource(module, resourceName, null, isShared); + String ext = supportedTypes.get(type); if (dir == null) return null; if (!Files.exists(dir)) return null; Stream result; @@ -87,7 +106,7 @@ public abstract class Module private static Path resolveResource(Module module, String resourceName, String ext, boolean isShared) { if (!isShared && (module == null || module.getName() == null)) return null; - return CarpetServer.minecraft_server.getSavePath(WorldSavePath.ROOT).resolve("scripts/"+getDescriptor(module, resourceName, isShared)+(ext==null?"":"."+ext)); + return CarpetServer.minecraft_server.getSavePath(WorldSavePath.ROOT).resolve("scripts/"+getDescriptor(module, resourceName, isShared)+(ext==null?"":ext)); } @Override diff --git a/src/main/java/carpet/script/utils/ScarpetJsonDeserializer.java b/src/main/java/carpet/script/utils/ScarpetJsonDeserializer.java new file mode 100644 index 00000000..759e0dd5 --- /dev/null +++ b/src/main/java/carpet/script/utils/ScarpetJsonDeserializer.java @@ -0,0 +1,78 @@ +package carpet.script.utils; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; + +import carpet.script.value.ListValue; +import carpet.script.value.MapValue; +import carpet.script.value.NumericValue; +import carpet.script.value.StringValue; +import carpet.script.value.Value; + +public class ScarpetJsonDeserializer implements JsonDeserializer{ + + @Override + public Value deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + return parseElement(json); + } + + private Value parseElement(JsonElement element) throws JsonParseException { + if (element.isJsonObject()) + { + return parseMap(element.getAsJsonObject()); + } + else if (element.isJsonArray()) + { + return parseList(element.getAsJsonArray()); + } + else if (element.isJsonPrimitive()) + { + return parsePrimitive(element.getAsJsonPrimitive()); + } + return Value.NULL; + } + + private Value parseMap(JsonObject jsonMap) throws JsonParseException { + Map map = new HashMap(); + jsonMap.entrySet().forEach(entry -> { + map.put(new StringValue(entry.getKey()), parseElement(entry.getValue())); + }); + return MapValue.wrap(map); + } + + private Value parseList(JsonArray jsonList) throws JsonParseException { + List list = new ArrayList(); + jsonList.forEach(elem -> { + list.add(parseElement(elem)); + }); + return new ListValue(list); + } + + private Value parsePrimitive(JsonPrimitive primitive) throws JsonParseException { + if (primitive.isString()) + { + return new StringValue(primitive.getAsString()); + } + else if (primitive.isBoolean()) + { + return primitive.getAsBoolean() ? Value.TRUE : Value.FALSE; + } + else if (primitive.isNumber()) + { + return NumericValue.of(primitive.getAsNumber()); + } + return Value.NULL; + } +} diff --git a/src/main/java/carpet/script/value/AbstractListValue.java b/src/main/java/carpet/script/value/AbstractListValue.java index cba8a000..fcb1f237 100644 --- a/src/main/java/carpet/script/value/AbstractListValue.java +++ b/src/main/java/carpet/script/value/AbstractListValue.java @@ -4,7 +4,7 @@ import carpet.script.exception.InternalExpressionException; import java.util.Iterator; -public abstract class AbstractListValue extends Value +public abstract class AbstractListValue extends Value implements Iterable { public abstract Iterator iterator(); public void fatality() { }