read_file, delete_file, and write_file
Deprecated some uses of load_app_data and store_app_data
This commit is contained in:
1 parent
b3484fd012
commit
fb3a5cfa64
7 files changed
+351
-55
No files matched your search
+71
-12
@@ -3154,25 +3154,23 @@ Optional shared shape attributes:
|
|||||||
in the form of `0xRRGGBBAA`, with the default of `-1`, so white opaque, or `0xFFFFFFFF`.
|
in the form of `0xRRGGBBAA`, with the default of `-1`, so white opaque, or `0xFFFFFFFF`.
|
||||||
* `player` - name or player entity to send the shape to. If specified, the shapes will appear only for the specified
|
* `player` - name or player entity to send the shape to. If specified, the shapes will appear only for the specified
|
||||||
player, otherwise it will be send to all players in the dimension.
|
player, otherwise it will be send to all players in the dimension.
|
||||||
|
* `width` - line thickness, defaults to 2.0pt
|
||||||
|
* `fill` - color for the faces, defaults to no fill. Use `color` attribute format
|
||||||
|
* `follow` - entity, or player name. Shape will follow an entity instead of being static.
|
||||||
|
Follow attribute requires all positional arguments to be relative to the entity and disallow
|
||||||
|
of using entity or block as position markers. You must specify positions as a triple.
|
||||||
|
|
||||||
Available shapes:
|
Available shapes:
|
||||||
* `'line'` - draws a straight line between two points
|
* `'line'` - draws a straight line between two points
|
||||||
* Required attributes:
|
* Required attributes:
|
||||||
* `from` - triple coordinates, entity, or block value indicating one end of the line
|
* `from` - triple coordinates, entity, or block value indicating one end of the line
|
||||||
* `to` - other end of the line, same format as `from`
|
* `to` - other end of the line, same format as `from`
|
||||||
* Optional attributes:
|
|
||||||
* `width` - line thickness, defaults to 2.0pt
|
|
||||||
* `follow` - entity, or player name. Shape will follow an entity instead of being static.
|
|
||||||
Follow attribute requires all positional arguments to be relative to the entity and disallow
|
|
||||||
of using entity or block as position markers. You must specify positions as a triple.
|
|
||||||
|
|
||||||
* `'box'` - draws a box with corners in specified points
|
* `'box'` - draws a box with corners in specified points
|
||||||
* Required attributes:
|
* Required attributes:
|
||||||
* `from` - triple coordinates, entity, or block value indicating one corner of the box
|
* `from` - triple coordinates, entity, or block value indicating one corner of the box
|
||||||
* `to` - other corner, same format as `from`
|
* `to` - other corner, same format as `from`
|
||||||
* Optional attributes:
|
|
||||||
* `width` - mesh line thickness, defaults to 2.0pt
|
|
||||||
* `fill` - color for the box faces, defaults to no fill, use shared color attribute format
|
|
||||||
* `'sphere'` - draws a sphere
|
* `'sphere'` - draws a sphere
|
||||||
* Required attributes:
|
* Required attributes:
|
||||||
* `center` - center of the sphere
|
* `center` - center of the sphere
|
||||||
@@ -3180,7 +3178,6 @@ Available shapes:
|
|||||||
* Optional attributes:
|
* Optional attributes:
|
||||||
* `level` - level of details, or grid size. The more the denser your sphere. Default level of 0, means that the
|
* `level` - level of details, or grid size. The more the denser your sphere. Default level of 0, means that the
|
||||||
level of detail will be selected automatically based on radius.
|
level of detail will be selected automatically based on radius.
|
||||||
* `width` - line thickness
|
|
||||||
|
|
||||||
### `create_marker(text, pos, rotation?, block?)`
|
### `create_marker(text, pos, rotation?, block?)`
|
||||||
|
|
||||||
@@ -3269,6 +3266,63 @@ Example usages:
|
|||||||
|
|
||||||
Prints the message to system logs, and not to chat.
|
Prints the message to system logs, and not to chat.
|
||||||
|
|
||||||
|
### read_file(resource, type)
|
||||||
|
### delete_file(resource, type)
|
||||||
|
### write_file(resource, type, data, ...)
|
||||||
|
|
||||||
|
With the specified `resource` in the scripts folder, of a specific `type`, writes/appends `data` to it, reads its
|
||||||
|
content, or deletes the resource.
|
||||||
|
|
||||||
|
Resource is identified by a path to the file.
|
||||||
|
A path can contain letters, numbers and folder separator: `'/'`. Any other characters are stripped
|
||||||
|
from the name. Empty descriptors are invalid. Do not add file extensions to the descriptor - extensions are inferred
|
||||||
|
based on the `type` of the file.
|
||||||
|
|
||||||
|
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
|
||||||
|
they can eat of each others file, however all access to files is synchronized, and files are never left open, so
|
||||||
|
this should not lead to any access problems.
|
||||||
|
|
||||||
|
If the app's name is `'foo'`, the script location would
|
||||||
|
be `world/scripts/foo.sc`, app
|
||||||
|
specific data directory is under `world/scripts/foo.data/...`, and shared data space is under
|
||||||
|
`world/scripts/shared/...`.
|
||||||
|
|
||||||
|
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 and delete operations). Returns `true`
|
||||||
|
for success writes and deletes, and requested data, based on the file type, for read operations.
|
||||||
|
|
||||||
|
NBT files can be written once as they an store one tag at a time. Consecutive writes will overwrite previous data.
|
||||||
|
|
||||||
|
Write operations to text files always result in appending to the existing file, so consecutive writes will increase
|
||||||
|
the size of the file and add data to it. Since files are closed after each write, sending multiple lines of data to
|
||||||
|
write is beneficial for writing speed. To send multiple packs of data, either provide them flat or as a list in the
|
||||||
|
third argument.
|
||||||
|
* `write_file('temp', 'text', 'foo', 'bar', 'baz')` or
|
||||||
|
* write_file('temp', 'text', l('foo', 'bar', 'baz'))
|
||||||
|
|
||||||
|
To log a single line of string
|
||||||
|
|
||||||
|
Supported values for resource `type` is:
|
||||||
|
* `nbt` - NBT tag
|
||||||
|
* `text` - text resource with automatic newlines added
|
||||||
|
* `raw` - text resource without implied newlines
|
||||||
|
* `shared_nbt`, `shared_text`, `shared_raw` - shared versions of the above
|
||||||
|
|
||||||
|
NBT files have extension `.nbt`, store one NBT tag, and return a NBT type value. Text files have `.txt` extension,
|
||||||
|
stores multiple lines of text and returns lists of all lines from the file. With `write_file`, multiple lines can be
|
||||||
|
sent to the file at once. The only difference between `raw` and `text` types are automatic newlines added after each
|
||||||
|
record to the file.
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
write_file('foo', 'shared_text, l('one', 'two'));
|
||||||
|
write_file('foo', 'shared_text', 'three\n', 'four\n');
|
||||||
|
write_file('foo', 'shared_raw', 'five\n', 'six\n');
|
||||||
|
|
||||||
|
read_file('foo', 'shared_text') => ['one', 'two', 'three', '', 'four', '', 'five', 'six']
|
||||||
|
</pre>
|
||||||
|
|
||||||
### `run(expr)`
|
### `run(expr)`
|
||||||
|
|
||||||
Runs a vanilla command from the string result of the `expr` and returns its success count
|
Runs a vanilla command from the string result of the `expr` and returns its success count
|
||||||
@@ -3283,7 +3337,10 @@ run('give @s stone 4') -> 1 // this operation was successful once
|
|||||||
Performs autosave, saves all chunks, player data, etc. Useful for programs where autosave is disabled due to
|
Performs autosave, saves all chunks, player data, etc. Useful for programs where autosave is disabled due to
|
||||||
performance reasons and saves the world only on demand.
|
performance reasons and saves the world only on demand.
|
||||||
|
|
||||||
### `load_app_data(), load_app_data(file), load_app_data(file, shared?)`
|
### `load_app_data()`
|
||||||
|
|
||||||
|
NOTE: usages with arguments, so `load_app_data(file)` and `load_app_data(file, shared?)` are deprecated.
|
||||||
|
Use `read_file` instead.
|
||||||
|
|
||||||
Loads the app data associated with the app from the world /scripts folder. Without argument returns the memory
|
Loads the app data associated with the app from the world /scripts folder. Without argument returns the memory
|
||||||
managed and buffered / throttled NBT tag. With a file name, reads explicitly a file with that name from the
|
managed and buffered / throttled NBT tag. With a file name, reads explicitly a file with that name from the
|
||||||
@@ -3291,7 +3348,7 @@ scripts folder that belongs exclusively to the app. if `shared` is true, the fil
|
|||||||
to the app anymore, but located in a shared app space.
|
to the app anymore, but located in a shared app space.
|
||||||
|
|
||||||
File descriptor can contain letters, numbers and folder separator: `'/'`. Any other characters are stripped
|
File descriptor can contain letters, numbers and folder separator: `'/'`. Any other characters are stripped
|
||||||
from the name before saving/loading. Empty descriptors are invalid.
|
from the name before saving/loading. Empty descriptors are invalid. Do not add file extensions to the descriptor
|
||||||
|
|
||||||
Function returns nbt value with the file content, or `null` if the file is missing or there were problems
|
Function returns nbt value with the file content, or `null` if the file is missing or there were problems
|
||||||
with retrieving the data.
|
with retrieving the data.
|
||||||
@@ -3305,7 +3362,9 @@ specific data directory is under `world/scripts/foo.data/bar/../baz.nbt`, and sh
|
|||||||
|
|
||||||
You can use app data to save non-vanilla information separately from the world and other scripts.
|
You can use app data to save non-vanilla information separately from the world and other scripts.
|
||||||
|
|
||||||
### `store_app_data(tag), store_app_data(tag, file), store_app_data(tag, file, shared?)`
|
### `store_app_data(tag)`
|
||||||
|
|
||||||
|
Note: `store_app_data(tag, file)` and `store_app_data(tag, file, shared?)` usages deprecated. Use `write_file` instead.
|
||||||
|
|
||||||
Stores the app data associated with the app from the world `/scripts` folder. With the `file` parameter saves
|
Stores the app data associated with the app from the world `/scripts` folder. With the `file` parameter saves
|
||||||
immediately and with every call to a specific file defined by the `file`, either in app space, or in the scripts
|
immediately and with every call to a specific file defined by the `file`, either in app space, or in the scripts
|
||||||
|
|||||||
@@ -172,6 +172,63 @@ Example usages:
|
|||||||
|
|
||||||
Prints the message to system logs, and not to chat.
|
Prints the message to system logs, and not to chat.
|
||||||
|
|
||||||
|
### read_file(resource, type)
|
||||||
|
### delete_file(resource, type)
|
||||||
|
### write_file(resource, type, data, ...)
|
||||||
|
|
||||||
|
With the specified `resource` in the scripts folder, of a specific `type`, writes/appends `data` to it, reads its
|
||||||
|
content, or deletes the resource.
|
||||||
|
|
||||||
|
Resource is identified by a path to the file.
|
||||||
|
A path can contain letters, numbers and folder separator: `'/'`. Any other characters are stripped
|
||||||
|
from the name. Empty descriptors are invalid. Do not add file extensions to the descriptor - extensions are inferred
|
||||||
|
based on the `type` of the file.
|
||||||
|
|
||||||
|
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
|
||||||
|
they can eat of each others file, however all access to files is synchronized, and files are never left open, so
|
||||||
|
this should not lead to any access problems.
|
||||||
|
|
||||||
|
If the app's name is `'foo'`, the script location would
|
||||||
|
be `world/scripts/foo.sc`, app
|
||||||
|
specific data directory is under `world/scripts/foo.data/...`, and shared data space is under
|
||||||
|
`world/scripts/shared/...`.
|
||||||
|
|
||||||
|
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 and delete operations). Returns `true`
|
||||||
|
for success writes and deletes, and requested data, based on the file type, for read operations.
|
||||||
|
|
||||||
|
NBT files can be written once as they an store one tag at a time. Consecutive writes will overwrite previous data.
|
||||||
|
|
||||||
|
Write operations to text files always result in appending to the existing file, so consecutive writes will increase
|
||||||
|
the size of the file and add data to it. Since files are closed after each write, sending multiple lines of data to
|
||||||
|
write is beneficial for writing speed. To send multiple packs of data, either provide them flat or as a list in the
|
||||||
|
third argument.
|
||||||
|
* `write_file('temp', 'text', 'foo', 'bar', 'baz')` or
|
||||||
|
* write_file('temp', 'text', l('foo', 'bar', 'baz'))
|
||||||
|
|
||||||
|
To log a single line of string
|
||||||
|
|
||||||
|
Supported values for resource `type` is:
|
||||||
|
* `nbt` - NBT tag
|
||||||
|
* `text` - text resource with automatic newlines added
|
||||||
|
* `raw` - text resource without implied newlines
|
||||||
|
* `shared_nbt`, `shared_text`, `shared_raw` - shared versions of the above
|
||||||
|
|
||||||
|
NBT files have extension `.nbt`, store one NBT tag, and return a NBT type value. Text files have `.txt` extension,
|
||||||
|
stores multiple lines of text and returns lists of all lines from the file. With `write_file`, multiple lines can be
|
||||||
|
sent to the file at once. The only difference between `raw` and `text` types are automatic newlines added after each
|
||||||
|
record to the file.
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
write_file('foo', 'shared_text, l('one', 'two'));
|
||||||
|
write_file('foo', 'shared_text', 'three\n', 'four\n');
|
||||||
|
write_file('foo', 'shared_raw', 'five\n', 'six\n');
|
||||||
|
|
||||||
|
read_file('foo', 'shared_text') => ['one', 'two', 'three', '', 'four', '', 'five', 'six']
|
||||||
|
</pre>
|
||||||
|
|
||||||
### `run(expr)`
|
### `run(expr)`
|
||||||
|
|
||||||
Runs a vanilla command from the string result of the `expr` and returns its success count
|
Runs a vanilla command from the string result of the `expr` and returns its success count
|
||||||
@@ -186,7 +243,10 @@ run('give @s stone 4') -> 1 // this operation was successful once
|
|||||||
Performs autosave, saves all chunks, player data, etc. Useful for programs where autosave is disabled due to
|
Performs autosave, saves all chunks, player data, etc. Useful for programs where autosave is disabled due to
|
||||||
performance reasons and saves the world only on demand.
|
performance reasons and saves the world only on demand.
|
||||||
|
|
||||||
### `load_app_data(), load_app_data(file), load_app_data(file, shared?)`
|
### `load_app_data()`
|
||||||
|
|
||||||
|
NOTE: usages with arguments, so `load_app_data(file)` and `load_app_data(file, shared?)` are deprecated.
|
||||||
|
Use `read_file` instead.
|
||||||
|
|
||||||
Loads the app data associated with the app from the world /scripts folder. Without argument returns the memory
|
Loads the app data associated with the app from the world /scripts folder. Without argument returns the memory
|
||||||
managed and buffered / throttled NBT tag. With a file name, reads explicitly a file with that name from the
|
managed and buffered / throttled NBT tag. With a file name, reads explicitly a file with that name from the
|
||||||
@@ -194,7 +254,7 @@ scripts folder that belongs exclusively to the app. if `shared` is true, the fil
|
|||||||
to the app anymore, but located in a shared app space.
|
to the app anymore, but located in a shared app space.
|
||||||
|
|
||||||
File descriptor can contain letters, numbers and folder separator: `'/'`. Any other characters are stripped
|
File descriptor can contain letters, numbers and folder separator: `'/'`. Any other characters are stripped
|
||||||
from the name before saving/loading. Empty descriptors are invalid.
|
from the name before saving/loading. Empty descriptors are invalid. Do not add file extensions to the descriptor
|
||||||
|
|
||||||
Function returns nbt value with the file content, or `null` if the file is missing or there were problems
|
Function returns nbt value with the file content, or `null` if the file is missing or there were problems
|
||||||
with retrieving the data.
|
with retrieving the data.
|
||||||
@@ -208,7 +268,9 @@ specific data directory is under `world/scripts/foo.data/bar/../baz.nbt`, and sh
|
|||||||
|
|
||||||
You can use app data to save non-vanilla information separately from the world and other scripts.
|
You can use app data to save non-vanilla information separately from the world and other scripts.
|
||||||
|
|
||||||
### `store_app_data(tag), store_app_data(tag, file), store_app_data(tag, file, shared?)`
|
### `store_app_data(tag)`
|
||||||
|
|
||||||
|
Note: `store_app_data(tag, file)` and `store_app_data(tag, file, shared?)` usages deprecated. Use `write_file` instead.
|
||||||
|
|
||||||
Stores the app data associated with the app from the world `/scripts` folder. With the `file` parameter saves
|
Stores the app data associated with the app from the world `/scripts` folder. With the `file` parameter saves
|
||||||
immediately and with every call to a specific file defined by the `file`, either in app space, or in the scripts
|
immediately and with every call to a specific file defined by the `file`, either in app space, or in the scripts
|
||||||
|
|||||||
@@ -2476,6 +2476,18 @@ public class CarpetExpression
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String recognizeResource(Value value)
|
||||||
|
{
|
||||||
|
String origfile = value.getString();
|
||||||
|
String file = origfile.toLowerCase(Locale.ROOT).replaceAll("[^A-Za-z0-9/]", "");
|
||||||
|
file = Arrays.stream(file.split("/+")).filter(s -> !s.isEmpty()).collect(Collectors.joining("/"));
|
||||||
|
if (file.isEmpty())
|
||||||
|
{
|
||||||
|
throw new InternalExpressionException("Cannot use "+origfile+" as resource name - must have some letters and numbers");
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
private void API_AuxiliaryAspects()
|
private void API_AuxiliaryAspects()
|
||||||
{
|
{
|
||||||
this.expr.addLazyFunction("sound", -1, (c, t, lv) -> {
|
this.expr.addLazyFunction("sound", -1, (c, t, lv) -> {
|
||||||
@@ -2864,13 +2876,6 @@ public class CarpetExpression
|
|||||||
// implmenetation should dock the task on the main thread.
|
// implmenetation should dock the task on the main thread.
|
||||||
});
|
});
|
||||||
|
|
||||||
this.expr.addLazyFunction("logger", 1, (c, t, lv) ->
|
|
||||||
{
|
|
||||||
Value res = lv.get(0).evalValue(c);
|
|
||||||
CarpetSettings.LOG.error(res.getString());
|
|
||||||
return (_c, _t) -> res; // pass through for variables
|
|
||||||
});
|
|
||||||
|
|
||||||
this.expr.addLazyFunction("run", 1, (c, t, lv) -> {
|
this.expr.addLazyFunction("run", 1, (c, t, lv) -> {
|
||||||
BlockPos target = ((CarpetContext)c).origin;
|
BlockPos target = ((CarpetContext)c).origin;
|
||||||
Vec3d posf = new Vec3d((double)target.getX()+0.5D,(double)target.getY(),(double)target.getZ()+0.5D);
|
Vec3d posf = new Vec3d((double)target.getX()+0.5D,(double)target.getY(),(double)target.getZ()+0.5D);
|
||||||
@@ -3057,25 +3062,108 @@ public class CarpetExpression
|
|||||||
return (c_, t_) -> Value.TRUE;
|
return (c_, t_) -> Value.TRUE;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.expr.addLazyFunction("logger", 1, (c, t, lv) ->
|
||||||
|
{
|
||||||
|
Value res = lv.get(0).evalValue(c);
|
||||||
|
CarpetSettings.LOG.error(res.getString());
|
||||||
|
return (_c, _t) -> res; // pass through for variables
|
||||||
|
});
|
||||||
|
|
||||||
|
this.expr.addLazyFunction("read_file", 2, (c, t, lv) -> {
|
||||||
|
String resource = recognizeResource(lv.get(0).evalValue(c));
|
||||||
|
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 (!type.equals("raw") && !type.equals("text") && !type.equals("nbt"))
|
||||||
|
throw new InternalExpressionException("Unsupported file type: "+origtype);
|
||||||
|
Value retVal;
|
||||||
|
if (type.equals("nbt"))
|
||||||
|
{
|
||||||
|
Tag state = ((CarpetScriptHost)((CarpetContext)c).host).readFileTag(resource, shared);
|
||||||
|
if (state == null) return LazyValue.NULL;
|
||||||
|
retVal = new NBTSerializableValue(state);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<String> content = ((CarpetScriptHost) ((CarpetContext) c).host).readTextResource(resource, shared);
|
||||||
|
if (content == null) return LazyValue.NULL;
|
||||||
|
retVal = ListValue.wrap(content.stream().map(StringValue::new).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
return (cc, tt) -> retVal;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.expr.addLazyFunction("delete_file", 2, (c, t, lv) -> {
|
||||||
|
String resource = recognizeResource(lv.get(0).evalValue(c));
|
||||||
|
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 (!type.equals("raw") && !type.equals("text") && !type.equals("nbt"))
|
||||||
|
throw new InternalExpressionException("Unsupported file type: "+origtype);
|
||||||
|
boolean success = ((CarpetScriptHost)((CarpetContext)c).host).removeResourceFile(resource, shared, type);
|
||||||
|
return success?LazyValue.TRUE:LazyValue.FALSE;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.expr.addLazyFunction("write_file", -1, (c, t, lv) -> {
|
||||||
|
if (lv.size() < 3) throw new InternalExpressionException("'write_file' requires three or more arguments");
|
||||||
|
String resource = recognizeResource(lv.get(0).evalValue(c));
|
||||||
|
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 (!type.equals("raw") && !type.equals("text") && !type.equals("nbt"))
|
||||||
|
throw new InternalExpressionException("Unsupported file type: "+origtype);
|
||||||
|
boolean success;
|
||||||
|
if (type.equals("nbt"))
|
||||||
|
{
|
||||||
|
Value val = lv.get(2).evalValue(c);
|
||||||
|
NBTSerializableValue tagValue = (val instanceof NBTSerializableValue)
|
||||||
|
? (NBTSerializableValue) val
|
||||||
|
: new NBTSerializableValue(val.getString());
|
||||||
|
Tag tag = tagValue.getTag();
|
||||||
|
success = ((CarpetScriptHost)((CarpetContext)c).host).writeTagFile(tag, resource, shared);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<String> data = new ArrayList<>();
|
||||||
|
if (lv.size()==3)
|
||||||
|
{
|
||||||
|
Value val = lv.get(2).evalValue(c);
|
||||||
|
if (val instanceof ListValue)
|
||||||
|
{
|
||||||
|
List<Value> lval = ((ListValue) val).getItems();
|
||||||
|
lval.forEach(v -> data.add(v.getString()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.add(val.getString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(int i = 2; i < lv.size(); i++)
|
||||||
|
{
|
||||||
|
data.add(lv.get(i).evalValue(c).getString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
success = ((CarpetScriptHost) ((CarpetContext) c).host).appendLogFile(resource, shared, type, data);
|
||||||
|
}
|
||||||
|
return success?LazyValue.TRUE:LazyValue.FALSE;
|
||||||
|
});
|
||||||
|
|
||||||
|
//write_file
|
||||||
|
|
||||||
this.expr.addLazyFunction("load_app_data", -1, (c, t, lv) ->
|
this.expr.addLazyFunction("load_app_data", -1, (c, t, lv) ->
|
||||||
{
|
{
|
||||||
String file = null;
|
String file = null;
|
||||||
boolean shared = false;
|
boolean shared = false;
|
||||||
if (lv.size()>0)
|
if (lv.size()>0)
|
||||||
{
|
{
|
||||||
String origfile = lv.get(0).evalValue(c).getString();
|
file = recognizeResource(lv.get(0).evalValue(c));
|
||||||
file = origfile.toLowerCase(Locale.ROOT).replaceAll("[^A-Za-z0-9/]", "");
|
|
||||||
file = Arrays.stream(file.split("/+")).filter(s -> !s.isEmpty()).collect(Collectors.joining("/"));
|
|
||||||
if (file.isEmpty())
|
|
||||||
{
|
|
||||||
throw new InternalExpressionException("Cannot use "+origfile+" as resource name - must have at least some letters and numbers");
|
|
||||||
}
|
|
||||||
if (lv.size() > 1)
|
if (lv.size() > 1)
|
||||||
{
|
{
|
||||||
shared = lv.get(1).evalValue(c).getBoolean();
|
shared = lv.get(1).evalValue(c).getBoolean();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Tag state = ((CarpetScriptHost)((CarpetContext)c).host).getGlobalState(file, shared);
|
Tag state = ((CarpetScriptHost)((CarpetContext)c).host).readFileTag(file, shared);
|
||||||
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);
|
||||||
@@ -3091,13 +3179,7 @@ public class CarpetExpression
|
|||||||
boolean shared = false;
|
boolean shared = false;
|
||||||
if (lv.size()>1)
|
if (lv.size()>1)
|
||||||
{
|
{
|
||||||
String origfile = lv.get(1).evalValue(c).getString();
|
file = recognizeResource(lv.get(1).evalValue(c));
|
||||||
file = origfile.toLowerCase(Locale.ROOT).replaceAll("[^A-Za-z0-9/]", "");
|
|
||||||
file = Arrays.stream(file.split("/+")).filter(s -> !s.isEmpty()).collect(Collectors.joining("/"));
|
|
||||||
if (file.isEmpty())
|
|
||||||
{
|
|
||||||
throw new InternalExpressionException("Cannot use "+origfile+" as resource name - must have some letters and numbers");
|
|
||||||
}
|
|
||||||
if (lv.size() > 2)
|
if (lv.size() > 2)
|
||||||
{
|
{
|
||||||
shared = lv.get(2).evalValue(c).getBoolean();
|
shared = lv.get(2).evalValue(c).getBoolean();
|
||||||
@@ -3107,7 +3189,7 @@ public class CarpetExpression
|
|||||||
? (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).setGlobalState(tag, file, shared);
|
boolean success = ((CarpetScriptHost)((CarpetContext)c).host).writeTagFile(tag, file, shared);
|
||||||
return success?LazyValue.TRUE:LazyValue.FALSE;
|
return success?LazyValue.TRUE:LazyValue.FALSE;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -369,7 +369,7 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
return Module.getData(main, null, false);
|
return Module.getData(main, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tag getGlobalState(String file, boolean isShared)
|
public Tag readFileTag(String file, boolean isShared)
|
||||||
{
|
{
|
||||||
if (getName() == null && !isShared) return null;
|
if (getName() == null && !isShared) return null;
|
||||||
if (file != null)
|
if (file != null)
|
||||||
@@ -379,7 +379,7 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
return ((CarpetScriptHost)parent).globalState;
|
return ((CarpetScriptHost)parent).globalState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setGlobalState(Tag tag, String file, boolean isShared)
|
public boolean writeTagFile(Tag tag, String file, boolean isShared)
|
||||||
{
|
{
|
||||||
if (getName() == null && !isShared) return false; // if belongs to an app, cannot be default host.
|
if (getName() == null && !isShared) return false; // if belongs to an app, cannot be default host.
|
||||||
|
|
||||||
@@ -398,6 +398,25 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean appendLogFile(String resource, boolean isShared, String type, List<String> data)
|
||||||
|
{
|
||||||
|
if (getName() == null && !isShared) return false; // if belongs to an app, cannot be default host.
|
||||||
|
return Module.appendToTextFile(main, resource, type, isShared, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> readTextResource(String resource, boolean isShared)
|
||||||
|
{
|
||||||
|
if (getName() == null && !isShared) return null; //
|
||||||
|
return Module.listFile(main, resource, "txt", isShared);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void tick()
|
public void tick()
|
||||||
{
|
{
|
||||||
if (this.saveTimeout > 0)
|
if (this.saveTimeout > 0)
|
||||||
|
|||||||
@@ -173,9 +173,9 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
|
|||||||
}
|
}
|
||||||
else if (nextChar == 't')
|
else if (nextChar == 't')
|
||||||
{
|
{
|
||||||
throw new ExpressionException(context, this.expression, token,
|
//throw new ExpressionException(context, this.expression, token,
|
||||||
"Tab character is not supported");
|
// "Tab character is not supported");
|
||||||
//token.append('\t');
|
token.append('\t');
|
||||||
}
|
}
|
||||||
else if (nextChar == 'r')
|
else if (nextChar == 'r')
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,17 +1,24 @@
|
|||||||
package carpet.script.bundled;
|
package carpet.script.bundled;
|
||||||
|
|
||||||
import carpet.CarpetServer;
|
|
||||||
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 java.io.BufferedReader;
|
||||||
|
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.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
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.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class FileModule extends Module
|
public class FileModule extends Module
|
||||||
@@ -96,4 +103,44 @@ public class FileModule extends Module
|
|||||||
if (!file.exists()) file_2.renameTo(file);
|
if (!file.exists()) file_2.renameTo(file);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean appendText(File filePath, boolean addNewLines, List<String> data)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OutputStream out = Files.newOutputStream(filePath.toPath(), 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static List<String> listFileContent(File filePath)
|
||||||
|
{
|
||||||
|
try (BufferedReader reader = Files.newBufferedReader(filePath.toPath(), 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -5,15 +5,14 @@ import net.minecraft.nbt.Tag;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.util.List;
|
||||||
import static carpet.script.bundled.FileModule.read;
|
|
||||||
import static carpet.script.bundled.FileModule.write;
|
|
||||||
|
|
||||||
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();
|
||||||
|
public final static Object writeIOSync = new Object();
|
||||||
|
|
||||||
private static String getDescriptor(Module module, String file, boolean isShared)
|
private static String getDescriptor(Module module, String file, boolean isShared)
|
||||||
{
|
{
|
||||||
@@ -33,20 +32,48 @@ public abstract class Module
|
|||||||
|
|
||||||
public static Tag getData(Module module, String file, boolean isShared)
|
public static Tag getData(Module module, String file, boolean isShared)
|
||||||
{
|
{
|
||||||
if (!isShared && (module == null || module.getName() == null)) return null;
|
File dataFile = resolveResource(module, file, "nbt", isShared);
|
||||||
File dataFile = CarpetServer.minecraft_server.getLevelStorage().resolveFile(
|
if (dataFile == null) return null;
|
||||||
CarpetServer.minecraft_server.getLevelName(), "scripts/"+getDescriptor(module, file, isShared)+".nbt");
|
|
||||||
if (!Files.exists(dataFile.toPath()) || !(dataFile.isFile())) return null;
|
if (!Files.exists(dataFile.toPath()) || !(dataFile.isFile())) return null;
|
||||||
return read(dataFile);
|
synchronized (writeIOSync) { return FileModule.read(dataFile); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean saveData(Module module, String file, Tag globalState, boolean isShared)
|
public static boolean saveData(Module module, String file, Tag globalState, boolean isShared)
|
||||||
{
|
{
|
||||||
if (!isShared && (module == null || module.getName() == null)) return false;
|
File dataFile = resolveResource(module, file, "nbt", isShared);
|
||||||
File dataFile =CarpetServer.minecraft_server.getLevelStorage().resolveFile(
|
if (dataFile == null) return false;
|
||||||
CarpetServer.minecraft_server.getLevelName(), "scripts/"+getDescriptor(module, file, isShared)+".nbt");
|
|
||||||
if (!Files.exists(dataFile.toPath().getParent()) && !dataFile.getParentFile().mkdirs()) return false;
|
if (!Files.exists(dataFile.toPath().getParent()) && !dataFile.getParentFile().mkdirs()) return false;
|
||||||
return write(globalState, dataFile);
|
synchronized (writeIOSync) { return FileModule.write(globalState, dataFile); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean appendToTextFile(Module module, String resourceName, String type, boolean isShared, List<String> message)
|
||||||
|
{
|
||||||
|
File dataFile = resolveResource(module, resourceName, "txt", isShared);
|
||||||
|
if (dataFile == null) return false;
|
||||||
|
if (!Files.exists(dataFile.toPath().getParent()) && !dataFile.getParentFile().mkdirs()) return false;
|
||||||
|
synchronized (writeIOSync) { return FileModule.appendText(dataFile, type.equals("text"), message); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean dropExistingFile(Module module, String resourceName, String ext, boolean isShared)
|
||||||
|
{
|
||||||
|
File dataFile = resolveResource(module, resourceName, ext, isShared);
|
||||||
|
if (dataFile == null) return false;
|
||||||
|
synchronized (writeIOSync) { return dataFile.delete(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> listFile(Module module, String resourceName, String ext, boolean isShared)
|
||||||
|
{
|
||||||
|
File dataFile = resolveResource(module, resourceName, ext, isShared);
|
||||||
|
if (dataFile == null) return null;
|
||||||
|
if (!dataFile.exists()) return null;
|
||||||
|
synchronized (writeIOSync) { return FileModule.listFileContent(dataFile); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File resolveResource(Module module, String resourceName, String ext, boolean isShared)
|
||||||
|
{
|
||||||
|
if (!isShared && (module == null || module.getName() == null)) return null;
|
||||||
|
return CarpetServer.minecraft_server.getLevelStorage().resolveFile(
|
||||||
|
CarpetServer.minecraft_server.getLevelName(), "scripts/"+getDescriptor(module, resourceName, isShared)+"."+ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in new issue
Block a user