refactored file IO and zupport for sips

This commit is contained in:
gnembon committed 2021-03-20 06:22:23 -03:00
1 parent f8208c8334
commit 1a47f4333f
10 files changed
+335 -482

No files matched your search

+7 -2
View File
@@ -298,7 +298,8 @@ Resource is identified by a path to the file.
A path can contain letters, numbers, characters `-`, `+`, or `_`, and a folder separator: `'/'`. Any other characters are stripped A path can contain letters, numbers, characters `-`, `+`, or `_`, and a folder separator: `'/'`. Any other characters are stripped
from the name. Empty descriptors are invalid, except for `list_files` where it means the root folder. from the name. Empty descriptors are invalid, except for `list_files` where it means the root folder.
Do not add file extensions to the descriptor - extensions are inferred Do not add file extensions to the descriptor - extensions are inferred
based on the `type` of the file. based on the `type` of the file. A path can have one `'.zip'` component indicating a zip folder allowing to read / write to and from
zip files, although you cannot nest zip files in other zip files.
Resources can be located in the app specific space, or a shared space for all the apps. Accessing of app-specific Resources can be located in the app specific space, or a shared space for all the apps. Accessing of app-specific
resources is guaranteed to be isolated from other apps. Shared resources are... well, shared across all apes, meaning resources is guaranteed to be isolated from other apps. Shared resources are... well, shared across all apes, meaning
@@ -312,7 +313,7 @@ specific data directory is under `world/scripts/foo.data/...`, and shared data s
The default no-name app, via `/script run` command can only save/load/read files from the shared space. The default no-name app, via `/script run` command can only save/load/read files from the shared space.
Functions return `null` if an error is encounter or no file is present (for read, list and delete operations). Returns `true` Functions return `null` if no file is present (for read, list and delete operations). Returns `true`
for success writes and deletes, and requested data, based on the file type, for read operations. It returns list of files for success writes and deletes, and requested data, based on the file type, for read operations. It returns list of files
for folder listing. for folder listing.
@@ -336,6 +337,10 @@ third argument.
Throws: Throws:
- `nbt_read_error`: When failed to read NBT file. - `nbt_read_error`: When failed to read NBT file.
- `json_read_error`: When failed to read JSON file. The exception data will contain details about the problem. - `json_read_error`: When failed to read JSON file. The exception data will contain details about the problem.
- `io_exception`: For all other errors when handling data on disk not related to encoding issues
All other errors resulting of improper use of input arguments should result in `null` returned from the function, rather than exception
thrown.
<pre> <pre>
write_file('foo', 'shared_text, ['one', 'two']); write_file('foo', 'shared_text, ['one', 'two']);
@@ -265,8 +265,8 @@ but like everywhere else, doing that sounds like a bad idea.
`unknown_poi_type`, `unknown_dimension`, `unknown_structure`, `unknown_criterion`: Specific `unknown_poi_type`, `unknown_dimension`, `unknown_structure`, `unknown_criterion`: Specific
errors thrown when a specified internal name does not exist or is invalid. errors thrown when a specified internal name does not exist or is invalid.
- `io_exception`: This is the parent for any exception that occurs due to an error handling external data. - `io_exception`: This is the parent for any exception that occurs due to an error handling external data.
- `nbt_read_error`: Incorrect input NBT file. - `nbt_error`: Incorrect input/output NBT file.
- `json_read_error`: Incorrect input JSON data. - `json_error`: Incorrect input/output JSON data.
- `user_exception`: Exception thrown by default with `throw` function. - `user_exception`: Exception thrown by default with `throw` function.
Synopsis: Synopsis:
@@ -3,6 +3,7 @@ package carpet.script;
import carpet.CarpetServer; import carpet.CarpetServer;
import carpet.CarpetSettings; import carpet.CarpetSettings;
import carpet.script.api.Auxiliary; import carpet.script.api.Auxiliary;
import carpet.script.argument.FileArgument;
import carpet.script.argument.FunctionArgument; import carpet.script.argument.FunctionArgument;
import carpet.script.bundled.Module; import carpet.script.bundled.Module;
import carpet.script.command.CommandArgument; import carpet.script.command.CommandArgument;
@@ -347,7 +348,7 @@ public class CarpetScriptHost extends ScriptHost
if (main == null) return false; if (main == null) return false;
if (getFunction("__command") == null) return false; if (getFunction("__command") == null) return false;
if (scriptServer.isValidCommandRoot(getName())) if (scriptServer.isInvalidCommandRoot(getName()))
{ {
notifier.accept(Messenger.c("gi Tried to mask vanilla command.")); notifier.accept(Messenger.c("gi Tried to mask vanilla command."));
return null; return null;
@@ -785,31 +786,31 @@ public class CarpetScriptHost extends ScriptHost
private void dumpState() private void dumpState()
{ {
Module.saveData(main, null, globalState, false); Module.saveData(main, globalState);
} }
private Tag loadState() private Tag loadState()
{ {
return Module.getData(main, null, false); return Module.getData(main);
} }
public Tag readFileTag(String file, boolean isShared) public Tag readFileTag(FileArgument fdesc)
{ {
if (getName() == null && !isShared) return null; if (getName() == null && !fdesc.isShared) return null;
if (file != null) if (fdesc.resource != null)
return Module.getData(main, file, isShared); return fdesc.getNbtData(main);
if (parent == null) if (parent == null)
return globalState; return globalState;
return ((CarpetScriptHost)parent).globalState; return ((CarpetScriptHost)parent).globalState;
} }
public boolean writeTagFile(Tag tag, String file, boolean isShared) public boolean writeTagFile(Tag tag, FileArgument fdesc)
{ {
if (getName() == null && !isShared) return false; // if belongs to an app, cannot be default host. if (getName() == null && !fdesc.isShared) return false; // if belongs to an app, cannot be default host.
if (file!= null) if (fdesc.resource != null)
{ {
return Module.saveData(main, file, tag, isShared); return fdesc.saveNbtData(main, tag);
} }
CarpetScriptHost responsibleHost = (parent != null)?(CarpetScriptHost) parent:this; CarpetScriptHost responsibleHost = (parent != null)?(CarpetScriptHost) parent:this;
@@ -822,34 +823,34 @@ public class CarpetScriptHost extends ScriptHost
return true; return true;
} }
public boolean removeResourceFile(String resource, boolean isShared, String type) public boolean removeResourceFile(FileArgument fdesc)
{ {
if (getName() == null && !isShared) return false; // if (getName() == null && !fdesc.isShared) return false; //
return Module.dropExistingFile(main, resource, type, isShared); return fdesc.dropExistingFile(main);
} }
public boolean appendLogFile(String resource, boolean isShared, String type, List<String> data) public boolean appendLogFile(FileArgument fdesc, List<String> data)
{ {
if (getName() == null && !isShared) return false; // if belongs to an app, cannot be default host. if (getName() == null && !fdesc.isShared) return false; // if belongs to an app, cannot be default host.
return Module.appendToTextFile(main, resource, type, isShared, data); return fdesc.appendToTextFile(main, data);
} }
public List<String> readTextResource(String resource, String type, boolean isShared) public List<String> readTextResource(FileArgument fdesc)
{ {
if (getName() == null && !isShared) return null; if (getName() == null && !fdesc.isShared) return null;
return Module.listFile(main, resource, type, isShared); return fdesc.listFile(main);
} }
public JsonElement readJsonFile(String resource, String type, boolean isShared) public JsonElement readJsonFile(FileArgument fdesc)
{ {
if (getName() == null && !isShared) return null; if (getName() == null && !fdesc.isShared) return null;
return Module.readJsonFile(main, resource, type, isShared); return fdesc.readJsonFile(main);
} }
public Stream<String> listFolder(String resource, String type, boolean isShared) public Stream<String> listFolder(FileArgument fdesc)
{ {
if (getName() == null && !isShared) return null; // if (getName() == null && !fdesc.isShared) return null; //
return Module.listFolder(main, resource, type, isShared); return fdesc.listFolder(main);
} }
@@ -305,9 +305,9 @@ public class CarpetScriptServer
return true; return true;
} }
public boolean isValidCommandRoot(String appName) public boolean isInvalidCommandRoot(String appName)
{ {
return !holyMoly.contains(appName); return holyMoly.contains(appName);
} }
+29 -83
View File
@@ -7,7 +7,7 @@ import carpet.fakes.ServerWorldInterface;
import carpet.fakes.StatTypeInterface; import carpet.fakes.StatTypeInterface;
import carpet.fakes.ThreadedAnvilChunkStorageInterface; import carpet.fakes.ThreadedAnvilChunkStorageInterface;
import carpet.helpers.FeatureGenerator; import carpet.helpers.FeatureGenerator;
import carpet.script.bundled.Module; import carpet.script.argument.FileArgument;
import carpet.script.CarpetContext; import carpet.script.CarpetContext;
import carpet.script.CarpetEventServer; import carpet.script.CarpetEventServer;
import carpet.script.CarpetScriptHost; import carpet.script.CarpetScriptHost;
@@ -99,7 +99,6 @@ import net.minecraft.world.level.UnmodifiableLevelProperties;
import net.minecraft.world.level.storage.LevelStorage; import net.minecraft.world.level.storage.LevelStorage;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
@@ -133,6 +132,7 @@ public class Auxiliary {
private static final Map<String, SoundCategory> mixerMap = Arrays.stream(SoundCategory.values()).collect(Collectors.toMap(SoundCategory::getName, k -> k)); private static final Map<String, SoundCategory> mixerMap = Arrays.stream(SoundCategory.values()).collect(Collectors.toMap(SoundCategory::getName, k -> k));
public static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().registerTypeAdapter(Value.class, new ScarpetJsonDeserializer()).create(); public static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().registerTypeAdapter(Value.class, new ScarpetJsonDeserializer()).create();
@Deprecated
public static String recognizeResource(Value value, boolean isFloder) public static String recognizeResource(Value value, boolean isFloder)
{ {
String origfile = value.getString(); String origfile = value.getString();
@@ -145,20 +145,6 @@ public class Auxiliary {
return file; return file;
} }
public static Triple<String, String, Boolean> getFileDescriptor(List<LazyValue> lv, Context c, boolean isFloder)
{
if (lv.size() < 2) throw new InternalExpressionException("File functions require path and type as first two arguments");
String resource = recognizeResource(lv.get(0).evalValue(c), isFloder);
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 (!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");
return Triple.of(resource, type, shared);
}
public static void apply(Expression expression) public static void apply(Expression expression)
{ {
expression.addLazyFunction("sound", -1, (c, t, lv) -> { expression.addLazyFunction("sound", -1, (c, t, lv) -> {
@@ -854,49 +840,27 @@ public class Auxiliary {
expression.addLazyFunction("list_files", 2, (c, t, lv) -> expression.addLazyFunction("list_files", 2, (c, t, lv) ->
{ {
Triple<String, String, Boolean> fdesc = getFileDescriptor(lv, c, true); FileArgument fdesc = FileArgument.from(lv, c, true, FileArgument.Reason.READ);
Stream<String> files = ((CarpetScriptHost) c.host).listFolder(fdesc.getLeft(), fdesc.getMiddle(), fdesc.getRight()); Stream<String> files = ((CarpetScriptHost) c.host).listFolder(fdesc);
if (files == null) return LazyValue.NULL; if (files == null) return LazyValue.NULL;
Value ret = ListValue.wrap(files.map(StringValue::of).collect(Collectors.toList())); Value ret = ListValue.wrap(files.map(StringValue::of).collect(Collectors.toList()));
return (cc, tt) -> ret; return (cc, tt) -> ret;
}); });
expression.addLazyFunction("read_file", 2, (c, t, lv) -> expression.addLazyFunction("read_file", 2, (c, t, lv) ->
{ {
Triple<String, String, Boolean> fdesc = getFileDescriptor(lv, c, false); FileArgument fdesc = FileArgument.from(lv, c, false, FileArgument.Reason.READ);
Value retVal; Value retVal;
if (fdesc.getMiddle().equals("nbt")) if (fdesc.type == FileArgument.Type.NBT)
{ {
Tag state; Tag state = ((CarpetScriptHost) c.host).readFileTag(fdesc);
try
{
state = ((CarpetScriptHost) c.host).readFileTag(fdesc.getLeft(), fdesc.getRight());
} catch (CrashException e)
{
throw new ThrowStatement((fdesc.getRight()?"shared/":"")+ fdesc.getLeft(), Throwables.NBT_READ);
}
if (state == null) return LazyValue.NULL; if (state == null) return LazyValue.NULL;
retVal = new NBTSerializableValue(state); retVal = new NBTSerializableValue(state);
} }
else if (fdesc.getMiddle().equals("json")) else if (fdesc.type == FileArgument.Type.JSON)
{ {
JsonElement json; JsonElement json;
try json = ((CarpetScriptHost) c.host).readJsonFile(fdesc);
{
json = ((CarpetScriptHost) c.host).readJsonFile(fdesc.getLeft(), fdesc.getMiddle(), fdesc.getRight());
}
catch (JsonParseException e)
{
Throwable exc = e;
if(e.getCause() != null)
exc = e.getCause();
throw new ThrowStatement(MapValue.wrap(ImmutableMap.of(
StringValue.of("error"), StringValue.of(exc.getMessage()),
StringValue.of("path"), StringValue.of((fdesc.getRight()?"shared/":"")+ fdesc.getLeft())
)), Throwables.JSON_READ);
}
Value parsedJson = GSON.fromJson(json, Value.class); Value parsedJson = GSON.fromJson(json, Value.class);
if (parsedJson == null) if (parsedJson == null)
retVal = Value.NULL; retVal = Value.NULL;
@@ -905,7 +869,7 @@ public class Auxiliary {
} }
else else
{ {
List<String> content = ((CarpetScriptHost) c.host).readTextResource(fdesc.getLeft(), fdesc.getMiddle(), fdesc.getRight()); List<String> content = ((CarpetScriptHost) c.host).readTextResource(fdesc);
if (content == null) return LazyValue.NULL; if (content == null) return LazyValue.NULL;
retVal = ListValue.wrap(content.stream().map(StringValue::new).collect(Collectors.toList())); retVal = ListValue.wrap(content.stream().map(StringValue::new).collect(Collectors.toList()));
} }
@@ -913,32 +877,29 @@ public class Auxiliary {
}); });
expression.addLazyFunction("delete_file", 2, (c, t, lv) -> { expression.addLazyFunction("delete_file", 2, (c, t, lv) -> {
Triple<String, String, Boolean> fdesc = getFileDescriptor(lv, c, false); FileArgument fdesc = FileArgument.from(lv, c, false, FileArgument.Reason.DELETE);
return ((CarpetScriptHost) c.host).removeResourceFile(fdesc.getLeft(), fdesc.getRight(), fdesc.getMiddle()) return ((CarpetScriptHost) c.host).removeResourceFile(fdesc) ? LazyValue.TRUE : LazyValue.FALSE;
? LazyValue.TRUE
: LazyValue.FALSE;
}); });
expression.addLazyFunction("write_file", -1, (c, t, lv) -> { expression.addLazyFunction("write_file", -1, (c, t, lv) -> {
if (lv.size() < 3) throw new InternalExpressionException("'write_file' requires three or more arguments"); if (lv.size() < 3) throw new InternalExpressionException("'write_file' requires three or more arguments");
Triple<String, String, Boolean> fdesc = getFileDescriptor(lv, c, false); FileArgument fdesc = FileArgument.from(lv, c, false, FileArgument.Reason.CREATE);
boolean success; boolean success;
if (fdesc.getMiddle().equals("nbt")) if (fdesc.type == FileArgument.Type.NBT)
{ {
Value val = lv.get(2).evalValue(c); Value val = lv.get(2).evalValue(c);
NBTSerializableValue tagValue = (val instanceof NBTSerializableValue) NBTSerializableValue tagValue = (val instanceof NBTSerializableValue)
? (NBTSerializableValue) val ? (NBTSerializableValue) val
: new NBTSerializableValue(val.getString()); : new NBTSerializableValue(val.getString());
Tag tag = tagValue.getTag(); Tag tag = tagValue.getTag();
success = ((CarpetScriptHost) c.host).writeTagFile(tag, fdesc.getLeft(), fdesc.getRight()); success = ((CarpetScriptHost) c.host).writeTagFile(tag, fdesc);
} }
else if (fdesc.getMiddle().equals("json")) else if (fdesc.type == FileArgument.Type.JSON)
{ {
List<String> data = Collections.singletonList(GSON.toJson(lv.get(2).evalValue(c).toJson())); List<String> data = Collections.singletonList(GSON.toJson(lv.get(2).evalValue(c).toJson()));
((CarpetScriptHost) c.host).removeResourceFile(fdesc.getLeft(), fdesc.getRight(), fdesc.getMiddle()); ((CarpetScriptHost) c.host).removeResourceFile(fdesc);
success = ((CarpetScriptHost) c.host).appendLogFile(fdesc.getLeft(), fdesc.getRight(), fdesc.getMiddle(), data); success = ((CarpetScriptHost) c.host).appendLogFile(fdesc, data);
} }
else else
{ {
@@ -963,34 +924,22 @@ public class Auxiliary {
data.add(lv.get(i).evalValue(c).getString()); data.add(lv.get(i).evalValue(c).getString());
} }
} }
success = ((CarpetScriptHost) c.host).appendLogFile(fdesc.getLeft(), fdesc.getRight(), fdesc.getMiddle(), data); success = ((CarpetScriptHost) c.host).appendLogFile(fdesc, data);
} }
return success?LazyValue.TRUE:LazyValue.FALSE; return success?LazyValue.TRUE:LazyValue.FALSE;
}); });
//write_file
expression.addLazyFunction("load_app_data", -1, (c, t, lv) -> expression.addLazyFunction("load_app_data", -1, (c, t, lv) ->
{ {
String file = null; FileArgument fdesc = new FileArgument(null, FileArgument.Type.NBT, null, false, false, FileArgument.Reason.READ);
boolean shared = false;
if (lv.size()>0) if (lv.size()>0)
{ {
c.host.issueDeprecation("load_app_data(...) with arguments"); c.host.issueDeprecation("load_app_data(...) with arguments");
file = recognizeResource(lv.get(0).evalValue(c), false); String resource = recognizeResource(lv.get(0).evalValue(c), false);
if (lv.size() > 1) boolean shared = lv.size() > 1 && lv.get(1).evalValue(c).getBoolean();
{ fdesc = new FileArgument(resource, FileArgument.Type.NBT, null, false, shared, FileArgument.Reason.READ);
shared = lv.get(1).evalValue(c).getBoolean();
}
}
Tag state;
try
{
state = ((CarpetScriptHost)((CarpetContext)c).host).readFileTag(file, shared);
} catch (CrashException e)
{
throw new ThrowStatement("app data", Throwables.NBT_READ);
} }
Tag state = ((CarpetScriptHost) c.host).readFileTag(fdesc);
if (state == null) if (state == null)
return (cc, tt) -> Value.NULL; return (cc, tt) -> Value.NULL;
Value retVal = new NBTSerializableValue(state); Value retVal = new NBTSerializableValue(state);
@@ -1002,22 +951,19 @@ public class Auxiliary {
if (lv.size() == 0) if (lv.size() == 0)
throw new InternalExpressionException("'store_app_data' needs NBT tag and an optional file"); throw new InternalExpressionException("'store_app_data' needs NBT tag and an optional file");
Value val = lv.get(0).evalValue(c); Value val = lv.get(0).evalValue(c);
String file = null; FileArgument fdesc = new FileArgument(null, FileArgument.Type.NBT, null, false, false, FileArgument.Reason.CREATE);
boolean shared = false;
if (lv.size()>1) if (lv.size()>1)
{ {
c.host.issueDeprecation("store_app_data(...) with more than one argument"); c.host.issueDeprecation("store_app_data(...) with more than one argument");
file = recognizeResource(lv.get(1).evalValue(c), false); String resource = recognizeResource(lv.get(1).evalValue(c), false);
if (lv.size() > 2) boolean shared = lv.size() > 2 && lv.get(2).evalValue(c).getBoolean();
{ fdesc = new FileArgument(resource, FileArgument.Type.NBT, null, false, shared, FileArgument.Reason.CREATE);
shared = lv.get(2).evalValue(c).getBoolean();
}
} }
NBTSerializableValue tagValue = (val instanceof NBTSerializableValue) NBTSerializableValue tagValue = (val instanceof NBTSerializableValue)
? (NBTSerializableValue) val ? (NBTSerializableValue) val
: new NBTSerializableValue(val.getString()); : new NBTSerializableValue(val.getString());
Tag tag = tagValue.getTag(); Tag tag = tagValue.getTag();
boolean success = ((CarpetScriptHost)((CarpetContext)c).host).writeTagFile(tag, file, shared); boolean success = ((CarpetScriptHost) c.host).writeTagFile(tag, fdesc);
return success?LazyValue.TRUE:LazyValue.FALSE; return success?LazyValue.TRUE:LazyValue.FALSE;
}); });
@@ -5,34 +5,47 @@ import carpet.script.Context;
import carpet.script.LazyValue; import carpet.script.LazyValue;
import carpet.script.bundled.Module; import carpet.script.bundled.Module;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ThrowStatement;
import carpet.script.exception.Throwables;
import carpet.script.value.MapValue;
import carpet.script.value.StringValue;
import carpet.script.value.Value; import carpet.script.value.Value;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.sun.nio.zipfs.ZipPath;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtIo; import net.minecraft.nbt.NbtIo;
import net.minecraft.nbt.PositionTracker; import net.minecraft.nbt.PositionTracker;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.nbt.TagReaders; import net.minecraft.nbt.TagReaders;
import net.minecraft.util.WorldSavePath; import net.minecraft.util.WorldSavePath;
import net.minecraft.util.crash.CrashException;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.tuple.Pair;
import java.io.BufferedInputStream;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.net.URI;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.FileSystems;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@@ -47,9 +60,22 @@ public class FileArgument
public boolean isFolder; public boolean isFolder;
public boolean isShared; public boolean isShared;
public Reason reason; public Reason reason;
private FileSystem zfs;
private Path zipPath;
public final static Object writeIOSync = new Object(); public final static Object writeIOSync = new Object();
public void close() {
if (zfs != null && zfs.isOpen()) {
try {
zfs.close();
} catch (IOException e) {
throw new InternalExpressionException("Unable to close zip container: "+zipContainer);
}
zfs = null;
}
}
public enum Type public enum Type
{ {
RAW("raw", ".txt"), RAW("raw", ".txt"),
@@ -75,7 +101,7 @@ public class FileArgument
READ, CREATE, DELETE READ, CREATE, DELETE
} }
private FileArgument(String resource, Type type, String zipContainer, boolean isFolder, boolean isShared, Reason reason) public FileArgument(String resource, Type type, String zipContainer, boolean isFolder, boolean isShared, Reason reason)
{ {
this.resource = resource; this.resource = resource;
this.type = type; this.type = type;
@@ -83,47 +109,103 @@ public class FileArgument
this.isFolder = isFolder; this.isFolder = isFolder;
this.isShared = isShared; this.isShared = isShared;
this.reason = reason; this.reason = reason;
this.zfs = null;
this.zipPath = null;
}
@Override
public String toString() {
return "path: "+resource+" zip: "+zipContainer+" type: "+type.id+" folder: "+isFolder+" shared: "+isShared+" reason: "+reason.toString();
} }
public static FileArgument from(List<LazyValue> lv, Context c, boolean isFolder, Reason reason) public static FileArgument from(List<LazyValue> lv, Context c, boolean isFolder, Reason reason)
{ {
if (lv.size() < 2) throw new InternalExpressionException("File functions require path and type as first two arguments"); if (lv.size() < 2) throw new InternalExpressionException("File functions require path and type as first two arguments");
String resource = recognizeResource(lv.get(0).evalValue(c), isFolder); Pair<String, String> resource = recognizeResource(lv.get(0).evalValue(c), isFolder);
String origtype = lv.get(1).evalValue(c).getString().toLowerCase(Locale.ROOT); String origtype = lv.get(1).evalValue(c).getString().toLowerCase(Locale.ROOT);
boolean shared = origtype.startsWith("shared_"); boolean shared = origtype.startsWith("shared_");
String typeString = shared ? origtype.substring(7) : origtype; //len(shared_) String typeString = shared ? origtype.substring(7) : origtype; //len(shared_)
Type type = Type.of.get(typeString); Type type = Type.of.get(typeString);
if (!Type.of.containsKey(typeString)) if (type==null)
throw new InternalExpressionException("Unsupported file type: "+origtype); throw new InternalExpressionException("Unsupported file type: "+origtype);
if (type==Type.FOLDER && !isFolder) if (type==Type.FOLDER && !isFolder)
throw new InternalExpressionException("Folder types are no supported for this IO function"); throw new InternalExpressionException("Folder types are no supported for this IO function");
return new FileArgument(resource, type,null, isFolder, shared, reason); return new FileArgument(resource.getLeft(), type,resource.getRight(), isFolder, shared, reason);
} }
public static String recognizeResource(Value value, boolean isFolder) public static Pair<String,String> recognizeResource(Value value, boolean isFolder)
{ {
String origfile = value.getString(); String origfile = value.getString();
String file = origfile.toLowerCase(Locale.ROOT).replaceAll("[^A-Za-z0-9\\-+_/]", ""); String[] pathElements = origfile.toLowerCase(Locale.ROOT).split("[/\\\\]+");
file = Arrays.stream(file.split("/+")).filter(s -> !s.isEmpty()).collect(Collectors.joining("/")); List<String> path = new ArrayList<>();
if (file.isEmpty() && !isFolder) String zipPath = null;
for (String token : pathElements)
{ {
throw new InternalExpressionException("Cannot use "+origfile+" as resource name - must have some letters and numbers"); boolean isZip = token.endsWith(".zip");
if (zipPath != null && isZip) throw new InternalExpressionException(token+" indicates zip access in an already zipped location "+zipPath);
if (isZip) token = token.substring(0, token.length()-4);
token = token.replaceAll("[^A-Za-z0-9\\-+_]", "");
if (token.isEmpty()) continue;
if (isZip) token = token + ".zip";
path.add(token);
if (isZip)
{
zipPath = String.join("/", path);
path.clear();
}
} }
return file; if (path.isEmpty() && !isFolder)
throw new InternalExpressionException(
"Cannot use "+origfile+" as resource name: indicated path is empty"+((zipPath==null)?"":" in zip container "+zipPath)
);
return Pair.of(String.join("/", path), zipPath);
}
private Path resolve(String suffix)
{
if (CarpetServer.minecraft_server == null)
throw new InternalExpressionException("Accessing world files without server running");
return CarpetServer.minecraft_server.getSavePath(WorldSavePath.ROOT).resolve("scripts/"+suffix);
} }
private Path toPath(Module module) private Path toPath(Module module)
{ {
if (!isShared && (module == null || module.getName() == null)) return null; if (!isShared && (module == null || module.getName() == null)) return null;
return CarpetServer.minecraft_server.getSavePath(WorldSavePath.ROOT).resolve("scripts/"+getDescriptor(module, resource)+type.extension); if (zipContainer == null)
return resolve(getDescriptor(module, resource)+(isFolder?"":type.extension));
else
{
if (zfs == null)
{
Map<String, String> env = new HashMap<>();
if (reason == Reason.CREATE) env.put("create", "true");
zipPath = resolve(getDescriptor(module, zipContainer));
try {
zfs = FileSystems.newFileSystem(URI.create("jar:"+ zipPath.toUri().toString()), env);
}
catch (FileSystemNotFoundException fsnfe)
{
return null;
}
catch (IOException e)
{
throw new ThrowStatement("Unable to open zip file: "+zipContainer, Throwables.IO_EXCEPTION);
}
}
return zfs.getPath(resource+(isFolder?"/":type.extension));
}
} }
private Path moduleRootPath(Module module) private Path moduleRootPath(Module module)
{ {
if (!isShared && (module == null || module.getName() == null)) return null; if (!isShared && (module == null || module.getName() == null)) return null;
return CarpetServer.minecraft_server.getSavePath(WorldSavePath.ROOT).resolve("scripts/"+getDescriptor(module, "")); return resolve(isShared?"shared":module.getName()+".data");
}
public String getDisplayPath()
{
return (isShared?"shared/":"")+(zipContainer!=null?zipContainer+"/":"")+resource+type.extension;
} }
private String getDescriptor(Module module, String res) private String getDescriptor(Module module, String res)
@@ -136,7 +218,7 @@ public class FileArgument
{ {
return module.getName()+".data"+(res==null || res.isEmpty()?"":"/"+res); return module.getName()+".data"+(res==null || res.isEmpty()?"":"/"+res);
} }
throw new RuntimeException("Invalid file descriptor: "+res); throw new InternalExpressionException("Invalid file descriptor: "+res);
} }
public Stream<Path> listFiles(Module module) public Stream<Path> listFiles(Module module)
@@ -146,8 +228,7 @@ public class FileArgument
String ext = type.extension; String ext = type.extension;
try try
{ {
return Files.list(dir). return Files.list(dir).filter(path -> (type==Type.FOLDER)?path.toString().endsWith("/"):path.toString().endsWith(ext));
filter(path -> isFolder?Files.isDirectory(path):path.toString().endsWith(ext));
} }
catch (IOException ignored) catch (IOException ignored)
{ {
@@ -157,73 +238,106 @@ public class FileArgument
public Stream<String> listFolder(Module module) public Stream<String> listFolder(Module module)
{ {
Stream<Path> result; Stream<String> strings;
synchronized (writeIOSync) { result = listFiles(module); } try { synchronized (writeIOSync)
if (result == null) return null; {
Path rootPath = moduleRootPath(module); Stream<Path> result;
Stream<String> strings = result.map(p -> rootPath.relativize(p).toString().replaceAll("[\\\\/]","/")); result = listFiles(module);
if (type != Type.FOLDER) if (result == null) return null;
return strings.map(FilenameUtils::removeExtension); Path rootPath = moduleRootPath(module);
return strings; if (rootPath == null) return null;
String zipComponent = (zipContainer != null) ? rootPath.relativize(zipPath).toString() : null;
strings = result.map(p -> {
if (zipContainer == null)
return rootPath.relativize(p).toString().replaceAll("[\\\\/]+", "/");
return (zipComponent + p.toString()).replaceAll("[\\\\/]+", "/");
});
} }
finally
{
close();
}
if (type == Type.FOLDER)
return strings.map(s -> s.endsWith("/")?s.substring(0, s.length()-2):s);
return strings.map(FilenameUtils::removeExtension);
}
private void createPaths(Path file)
{
try {
if ((zipContainer == null || file.getParent() != null) &&
!Files.exists(file.getParent()) &&
Files.createDirectories(file.getParent()) == null
) throw new IOException();
} catch (IOException e) {
throw new ThrowStatement("Unable to create paths for "+file.toString(), Throwables.IO_EXCEPTION);
}
} }
public boolean appendToTextFile(Module module, List<String> message) public boolean appendToTextFile(Module module, List<String> message)
{ {
Path dataFile = toPath(module);//, resourceName, supportedTypes.get(type), isShared); try { synchronized (writeIOSync)
if (dataFile == null) return false;
if (!Files.exists(dataFile.getParent()) && !dataFile.toFile().getParentFile().mkdirs()) return false;
synchronized (writeIOSync)
{ {
try Path dataFile = toPath(module);//, resourceName, supportedTypes.get(type), isShared);
if (dataFile == null) return false;
createPaths(dataFile);
OutputStream out = Files.newOutputStream(dataFile, StandardOpenOption.APPEND, StandardOpenOption.CREATE);
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8)))
{ {
OutputStream out = Files.newOutputStream(dataFile, StandardOpenOption.APPEND, StandardOpenOption.CREATE); for (String line: message)
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8)))
{ {
for (String line: message) writer.append(line);
{ if (type == Type.TEXT) writer.newLine();
writer.append(line);
if (type == Type.TEXT) writer.newLine();
}
} }
} }
catch (IOException e) } }
{ catch (IOException e)
return false; {
} throw new ThrowStatement("Error when writing to the file: "+e, Throwables.IO_EXCEPTION);
return true;
} }
finally
{
close();
}
return true;
} }
public Tag getNbtData(Module module) // aka getData public Tag getNbtData(Module module) // aka getData
{ {
Path dataFile = toPath(module); try { synchronized (writeIOSync) {
if (dataFile == null) return null; Path dataFile = toPath(module);
if (!Files.exists(dataFile) || !(dataFile.toFile().isFile())) return null; if (dataFile == null || !Files.exists(dataFile)) return null;
synchronized (writeIOSync) { return readTag(dataFile.toFile()); } return readTag(dataFile);
} }
finally {
close();
}
} }
//copied private method from net.minecraft.nbt.NbtIo.read() //copied private method from net.minecraft.nbt.NbtIo.read()
// to read non-compound tags - these won't be compressed // to read non-compound tags - these won't be compressed
public static Tag readTag(File file) public static Tag readTag(Path path)
{ {
try try
{ {
return NbtIo.readCompressed(file); return NbtIo.readCompressed(Files.newInputStream(path));
} }
catch (IOException e) catch (IOException e)
{ {
// Copy of NbtIo.read(File) because that's now client-side only // Copy of NbtIo.read(File) because that's now client-side only
if (!file.exists()) if (!Files.exists(path))
{ {
return null; return null;
} }
try (DataInputStream in = new DataInputStream(new FileInputStream(file))) try (DataInputStream in = new DataInputStream(new BufferedInputStream(Files.newInputStream(path))))
{ {
return NbtIo.read(in); return NbtIo.read(in);
} }
catch (IOException ioException) catch (IOException ioException)
{ {
try (DataInputStream dataInput_1 = new DataInputStream(new FileInputStream(file))) // not compressed compound tag neither uncompressed compound tag - trying any type of a tag
try (DataInputStream dataInput_1 = new DataInputStream(new BufferedInputStream(Files.newInputStream(path))))
{ {
byte byte_1 = dataInput_1.readByte(); byte byte_1 = dataInput_1.readByte();
if (byte_1 == 0) if (byte_1 == 0)
@@ -238,71 +352,102 @@ public class FileArgument
} }
catch (IOException ignored) catch (IOException ignored)
{ {
throw new ThrowStatement("Not a valid NBT tag in "+path.toString(), Throwables.NBT_ERROR);
} }
return null;
} }
} }
catch (CrashException e)
{
throw new ThrowStatement("Error when reading NBT file "+path.toString(), Throwables.NBT_ERROR);
}
} }
public boolean saveNbtData(Module module, Tag tag) // aka saveData public boolean saveNbtData(Module module, Tag tag) // aka saveData
{ {
Path dataFile = toPath(module); try { synchronized (writeIOSync) {
if (dataFile == null) return false; Path dataFile = toPath(module);
if (!Files.exists(dataFile.getParent()) && !dataFile.toFile().getParentFile().mkdirs()) return false; if (dataFile == null) return false;
synchronized (writeIOSync) { return writeTag(tag, dataFile.toFile()); } createPaths(dataFile);
return writeTagDisk(tag, dataFile);
} }
finally
{
close();
}
} }
//copied private method from net.minecraft.nbt.NbtIo.write() and client method safe_write //copied private method from net.minecraft.nbt.NbtIo.write() and client method safe_write
public static boolean writeTag(Tag tag_1, File file) public static boolean writeTagDisk(Tag tag_1, Path path)
{ {
File file_2 = new File(file.getAbsolutePath() + "_tmp"); Path original = path;
if (file_2.exists()) file_2.delete(); try
{
boolean zipped = path instanceof ZipPath;
if (!zipped)
{
path = new File(path.toFile().getAbsolutePath() + "_tmp").toPath();
Files.deleteIfExists(path);
}
if (tag_1 instanceof CompoundTag) if (tag_1 instanceof CompoundTag)
{
try
{ {
NbtIo.writeCompressed((CompoundTag) tag_1, file_2); NbtIo.writeCompressed((CompoundTag) tag_1, Files.newOutputStream(path));
} }
catch (IOException e) else
{ {
return false; try (DataOutputStream dataOutputStream_1 = new DataOutputStream(Files.newOutputStream(path)))
}
}
else
{
try (DataOutputStream dataOutputStream_1 = new DataOutputStream(new FileOutputStream(file_2)))
{
dataOutputStream_1.writeByte(tag_1.getType());
if (tag_1.getType() != 0)
{ {
dataOutputStream_1.writeUTF(""); dataOutputStream_1.writeByte(tag_1.getType());
tag_1.write(dataOutputStream_1); if (tag_1.getType() != 0)
{
dataOutputStream_1.writeUTF("");
tag_1.write(dataOutputStream_1);
}
} }
} }
catch (IOException e) if (!zipped)
{ {
return false; Files.deleteIfExists(original);
Files.move(path, original);
} }
return true;
}
catch (IOException e)
{
throw new ThrowStatement("Unable to write tag to "+original.toString(), Throwables.IO_EXCEPTION);
} }
if (file.exists()) file.delete();
if (!file.exists()) file_2.renameTo(file);
return true;
} }
public boolean dropExistingFile(Module module) public boolean dropExistingFile(Module module)
{ {
Path dataFile = toPath(module);
if (dataFile == null) return false; try { synchronized (writeIOSync)
synchronized (writeIOSync) { return dataFile.toFile().delete(); } {
Path dataFile = toPath(module);
if (dataFile == null) return false;
return Files.deleteIfExists(dataFile);
} }
catch (IOException e)
{
throw new ThrowStatement("Error while removing file: "+getDisplayPath(), Throwables.IO_EXCEPTION);
}
finally
{
close();
}
} }
public List<String> listFile(Module module) public List<String> listFile(Module module)
{ {
Path dataFile = toPath(module); try { synchronized (writeIOSync) {
if (dataFile == null) return null; Path dataFile = toPath(module);
if (!dataFile.toFile().exists()) return null; if (dataFile == null) return null;
synchronized (writeIOSync) { return listFileContent(dataFile); } if (!Files.exists(dataFile)) return null;
return listFileContent(dataFile);
} }
finally {
close();
}
} }
public static List<String> listFileContent(Path filePath) public static List<String> listFileContent(Path filePath)
@@ -319,15 +464,19 @@ public class FileArgument
} }
catch (IOException e) catch (IOException e)
{ {
return null; throw new ThrowStatement("Failed to read text file "+filePath.toString(), Throwables.IO_EXCEPTION);
} }
} }
public JsonElement readJsonFile(Module module) { public JsonElement readJsonFile(Module module) {
Path dataFile = toPath(module); try { synchronized (writeIOSync) {
if (dataFile == null) return null; Path dataFile = toPath(module);
if (!dataFile.toFile().exists()) return null; if (dataFile == null || !Files.exists(dataFile)) return null;
synchronized (writeIOSync) { return readJsonContent(dataFile); } return readJsonContent(dataFile);
} }
finally {
close();
}
} }
public static JsonElement readJsonContent(Path filePath) public static JsonElement readJsonContent(Path filePath)
@@ -336,9 +485,19 @@ public class FileArgument
{ {
return new JsonParser().parse(new JsonReader(reader)); return new JsonParser().parse(new JsonReader(reader));
} }
catch (JsonParseException e)
{
Throwable exc = e;
if(e.getCause() != null)
exc = e.getCause();
throw new ThrowStatement(MapValue.wrap(ImmutableMap.of(
StringValue.of("error"), StringValue.of(exc.getMessage()),
StringValue.of("path"), StringValue.of(filePath.toString())
)), Throwables.JSON_ERROR);
}
catch (IOException e) catch (IOException e)
{ {
return null; throw new ThrowStatement("Failed to read json file content "+filePath.toString(), Throwables.IO_EXCEPTION);
} }
} }
@@ -1,33 +1,10 @@
package carpet.script.bundled; package carpet.script.bundled;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtIo;
import net.minecraft.nbt.PositionTracker;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.TagReaders;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.stream.Stream;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.stream.JsonReader;
public class FileModule extends Module public class FileModule extends Module
{ {
@@ -66,155 +43,4 @@ public class FileModule extends Module
return library; return library;
} }
//copied private method from net.minecraft.nbt.NbtIo.read()
// to read non-compound tags - these won't be compressed
@Deprecated
public static Tag read(File file)
{
try
{
return NbtIo.readCompressed(file);
}
catch (IOException e)
{
// Copy of NbtIo.read(File) because that's now client-side only
if (!file.exists())
{
return null;
}
try (DataInputStream in = new DataInputStream(new FileInputStream(file)))
{
return NbtIo.read(in);
}
catch (IOException ioException)
{
try (DataInputStream dataInput_1 = new DataInputStream(new FileInputStream(file)))
{
byte byte_1 = dataInput_1.readByte();
if (byte_1 == 0)
{
return null;
}
else
{
dataInput_1.readUTF();
return TagReaders.of(byte_1).read(dataInput_1, 0, PositionTracker.DEFAULT);
}
}
catch (IOException ignored)
{
}
return null;
}
}
}
//copied private method from net.minecraft.nbt.NbtIo.write() and client method safe_write
@Deprecated
public static boolean write(Tag tag_1, File file)
{
File file_2 = new File(file.getAbsolutePath() + "_tmp");
if (file_2.exists()) file_2.delete();
if (tag_1 instanceof CompoundTag)
{
try
{
NbtIo.writeCompressed((CompoundTag) tag_1, file_2);
}
catch (IOException e)
{
return false;
}
}
else
{
try (DataOutputStream dataOutputStream_1 = new DataOutputStream(new FileOutputStream(file_2)))
{
dataOutputStream_1.writeByte(tag_1.getType());
if (tag_1.getType() != 0)
{
dataOutputStream_1.writeUTF("");
tag_1.write(dataOutputStream_1);
}
}
catch (IOException e)
{
return false;
}
}
if (file.exists()) file.delete();
if (!file.exists()) file_2.renameTo(file);
return true;
}
@Deprecated
public static boolean appendText(Path filePath, boolean addNewLines, List<String> data)
{
try
{
OutputStream out = Files.newOutputStream(filePath, StandardOpenOption.APPEND, StandardOpenOption.CREATE);
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8)))
{
for (String line: data)
{
writer.append(line);
if (addNewLines) writer.newLine();
}
}
}
catch (IOException e)
{
return false;
}
return true;
}
@Deprecated
public static List<String> listFileContent(Path filePath)
{
try (BufferedReader reader = Files.newBufferedReader(filePath, StandardCharsets.UTF_8)) {
List<String> result = new ArrayList<>();
for (;;) {
String line = reader.readLine();
if (line == null)
break;
result.add(line.replaceAll("[\n\r]+",""));
}
return result;
}
catch (IOException e)
{
return null;
}
}
@Deprecated
public static JsonElement readJsonContent(Path filePath)
{
try (BufferedReader reader = Files.newBufferedReader(filePath, StandardCharsets.UTF_8))
{
return new JsonParser().parse(new JsonReader(reader));
}
catch (IOException e)
{
return null;
}
}
@Deprecated
public static Stream<Path> listFiles(Path dir, String ext)
{
boolean folderListing = ext.equals("folder");
try
{
return Files.list(dir).
filter(path -> folderListing?Files.isDirectory(path):path.toString().endsWith(ext));
}
catch (IOException ignored)
{
return null;
}
}
} }
+12 -96
View File
@@ -1,123 +1,39 @@
package carpet.script.bundled; package carpet.script.bundled;
import carpet.CarpetServer; import carpet.CarpetServer;
import carpet.script.argument.FileArgument;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.util.WorldSavePath; import net.minecraft.util.WorldSavePath;
import org.apache.commons.io.FilenameUtils;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonElement;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
public abstract class Module public abstract class Module
{ {
public abstract String getName(); public abstract String getName();
public abstract String getCode(); public abstract String getCode();
public abstract boolean isLibrary(); public abstract boolean isLibrary();
@Deprecated
public final static Object writeIOSync = new Object();
@Deprecated
public final static Map<String, String> supportedTypes = ImmutableMap.of(
"raw", ".txt",
"text", ".txt",
"nbt", ".nbt",
"json", ".json",
"folder", "folder"
);
@Deprecated public static Tag getData(Module module)
private static String getDescriptor(Module module, String file, boolean isShared)
{ {
if (isShared) Path dataFile = resolveResource(module);
{
return file.isEmpty()?"shared":"shared/"+file;
}
if (module != null && module.getName() != null) // appdata
{
return module.getName()+".data"+(file==null || file.isEmpty()?"":"/"+file);
}
throw new RuntimeException("Invalid file descriptor: "+file);
}
@Deprecated
public static Tag getData(Module module, String file, boolean isShared)
{
Path dataFile = resolveResource(module, file, ".nbt", isShared);
if (dataFile == null) return null; if (dataFile == null) return null;
if (!Files.exists(dataFile) || !(dataFile.toFile().isFile())) return null; if (!Files.exists(dataFile) || !(dataFile.toFile().isFile())) return null;
synchronized (writeIOSync) { return FileModule.read(dataFile.toFile()); } synchronized (FileArgument.writeIOSync) { return FileArgument.readTag(dataFile); }
} }
@Deprecated public static void saveData(Module module, Tag globalState)
public static boolean saveData(Module module, String file, Tag globalState, boolean isShared)
{ {
Path dataFile = resolveResource(module, file, ".nbt", isShared); Path dataFile = resolveResource(module);
if (dataFile == null) return false; if (dataFile == null) return;
if (!Files.exists(dataFile.getParent()) && !dataFile.toFile().getParentFile().mkdirs()) return false; if (!Files.exists(dataFile.getParent()) && !dataFile.toFile().getParentFile().mkdirs()) return;
synchronized (writeIOSync) { return FileModule.write(globalState, dataFile.toFile()); } synchronized (FileArgument.writeIOSync) { FileArgument.writeTagDisk(globalState, dataFile); }
} }
@Deprecated private static Path resolveResource(Module module)
public static boolean appendToTextFile(Module module, String resourceName, String type, boolean isShared, List<String> message)
{ {
Path dataFile = resolveResource(module, resourceName, supportedTypes.get(type), isShared); if (module == null || module.getName() == null) return null; // commandline app
if (dataFile == null) return false; return CarpetServer.minecraft_server.getSavePath(WorldSavePath.ROOT).resolve("scripts/"+module.getName()+".data.nbt");
if (!Files.exists(dataFile.getParent()) && !dataFile.toFile().getParentFile().mkdirs()) return false;
synchronized (writeIOSync) { return FileModule.appendText(dataFile, type.equals("text"), message); }
}
@Deprecated
public static boolean dropExistingFile(Module module, String resourceName, String type, boolean isShared)
{
Path dataFile = resolveResource(module, resourceName, supportedTypes.get(type), isShared);
if (dataFile == null) return false;
synchronized (writeIOSync) { return dataFile.toFile().delete(); }
}
@Deprecated
public static List<String> listFile(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.listFileContent(dataFile); }
}
@Deprecated
public static JsonElement 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); }
}
@Deprecated
public static Stream<String> 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<Path> result;
synchronized (writeIOSync) { result = FileModule.listFiles(dir, ext); }
if (result == null) return null;
Path rootPath = resolveResource(module, "", null, isShared);
Stream<String> strings = result.map(p -> rootPath.relativize(p).toString().replaceAll("[\\\\/]","/"));
if (!ext.equals("folder"))
return strings.map(FilenameUtils::removeExtension);
return strings;
}
@Deprecated
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));
} }
@Override @Override
@@ -25,8 +25,8 @@ public class Throwables {
public static final Throwables UNKNOWN_STRUCTURE = register("unknown_structure", VALUE_EXCEPTION); public static final Throwables UNKNOWN_STRUCTURE = register("unknown_structure", VALUE_EXCEPTION);
public static final Throwables UNKNOWN_CRITERION = register("unknown_criterion", VALUE_EXCEPTION); public static final Throwables UNKNOWN_CRITERION = register("unknown_criterion", VALUE_EXCEPTION);
public static final Throwables IO_EXCEPTION = register("io_exception", THROWN_EXCEPTION_TYPE); public static final Throwables IO_EXCEPTION = register("io_exception", THROWN_EXCEPTION_TYPE);
public static final Throwables NBT_READ = register("nbt_read_error", IO_EXCEPTION); public static final Throwables NBT_ERROR = register("nbt_error", IO_EXCEPTION);
public static final Throwables JSON_READ = register("json_read_error", IO_EXCEPTION); public static final Throwables JSON_ERROR = register("json_error", IO_EXCEPTION);
public static final Throwables USER_DEFINED = register("user_exception", THROWN_EXCEPTION_TYPE); public static final Throwables USER_DEFINED = register("user_exception", THROWN_EXCEPTION_TYPE);
/** /**
@@ -119,7 +119,7 @@ public class Loops {
c.setVariable("_i", (cc, tt) -> new NumericValue(doYouReally).bindTo("_i")); c.setVariable("_i", (cc, tt) -> new NumericValue(doYouReally).bindTo("_i"));
try try
{ {
result.add(expr.evalValue(c)); result.add(expr.evalValue(c, t));
} }
catch (BreakStatement | ContinueStatement stmt) catch (BreakStatement | ContinueStatement stmt)
{ {