From ef757aec1d9c752420602793b919996d4442a5e2 Mon Sep 17 00:00:00 2001
From: gnembon Here is the gist of the Minecraft related functions. Otherwise the CarpetScript could live without Minecraft. One note, which is important is that most of the calls for entities and blocks
* would refer to the current dimension of the caller, meaning, that if we for example
* list all the players using Minecraft specific API and
* scarpet language add-ons and commandsDimension issues
+ * Dimension warning
* player('all') function, if a player is in the
@@ -108,7 +108,8 @@ import static java.lang.Math.sqrt;
* refer to the overworld blocks and entities.
* In case you would want to run commands across all dimensions, just run three of them, using
* /execute in overworld/the_nether/the_end run script run ... and query
- * players using player('*'), which only returns players in current dimension.player('*'), which only returns players in current dimension, or use
+ * in_dimension(expr) function.
nbt(expr)Treats the argument as a nbt serializable string and returns its nbt value.
* In case nbt is not in a correct nbt compound tag format, it will return null value.
Consult section about container operations in Expression to learn about possible operations on nbt values.
print(expr)Displays the result of the expression to the chat. Overrides default scarpet behaviour of
* sending everyting to stderr.
scarpet programming language.scarpet programming language (towards upcoming version 1.5).Scarpet (a.k.a. Carpet Script, or Script for Carpet) is a programming language designed to provide * the ability to write custom programs to run within Minecraft and @@ -74,7 +74,7 @@ import static java.lang.Math.min; *
* script run print('Hello World!')
*
- * or an overly complex example:
+ *or an OVERLY complex example:
** /script run * block_check(x1, y1, z1, x2, y2, z2, block_to_check) -> @@ -83,7 +83,7 @@ import static java.lang.Math.min; * l(miny, maxy) = sort(l(y1, y2)); * l(minz, maxz) = sort(l(z1, z2)); * 'Need to compute the size of the area of course'; - * 'Cause this language doesn\'t support comments'; + * 'Cause this language doesn\'t support comments in the command mode'; * xsize = maxx - minx + 1; * ysize = maxy - miny + 1; * zsize = maxz - minz + 1; @@ -202,11 +202,36 @@ import static java.lang.Math.min; * Variables from outer scopes have a similar behaviour to, for example,nonlocalvariables from python. * * - *Line indicators
+ *Code delivery, line indicators
*Note that this should only apply to pasting your code to execute with commandblock. Scarpet recommends placing your * code in packages (files with
+ *.scextension that can be placed inside "/scripts" folder in the world files * and loaded as a module with command/script load [package_name]. Scarpet modules loaded from disk should only * contain code, no need to start with "/script run" prefixThe following is the code that could be provided in a
+ * + *foo.scfile located in world/scriptsfolder+ * run_program() -> ( + * loop( 10, + * // looping 10 times + * // comments are allowed in scripts located in world files + * // since we can tell where that line ends + * foo = floor(rand(10)); + * check_not_zero(foo); + * print(_+' - foo: '+foo); + * print(' reciprocal: '+ _/foo ) + * ) + * ); + * check_not_zero(foo) -> ( + * if (foo==0, foo = 1) + * ) + *+ *Which we then call in-game with:
+ *+ * /script load foo + * /script in foo invoke run_program + *+ *However the following code can also be input as a command, or in a command block.
+ * *Since the maximum command that can be input to the chat is limited in length, you will be probably inserting your * programs by pasting them to command blocks or reading from world files, however pasting to command blocks will remove some whitespaces and squish * your newlines making the code not readable. If you are pasting a program that is perfect and will never cause an error, @@ -833,7 +858,8 @@ public class Expression implements Cloneable * Names in the signature don't need to be used anywhere else, other occurrences of these names * will be masked in this function scope. * Function call creates new scope for variables inside
+ * visible from the caller scope. All parameters are passed by value to the new scope, including lists and other + * containers, however their copy will be shallow. *expr, so all non-global variables are not - * visible from the caller scope. All parameters are passed by value to the new scope, including lists* a(lst) -> lst+=1; list = l(1,2,3); a(list); a(list); list // => [1,2,3] *@@ -1045,7 +1071,7 @@ public class Expression implements Cloneable * even if they look like them: * *
~ .~ .+ - !^* / %get(...), put(...), delete(...),
* and has(...) functions
+ * WARNING: Unlike for some languages, where item access operator can be an L-value, to assign new values to
+ * container elements, use put function instead, i.e. a.1='foo' won't work.
Matching Operator ~This operator should be understood as 'matches', 'contains', 'is_in', @@ -1400,14 +1428,14 @@ public class Expression implements Cloneable *
log10(n)Decimal logarithm of n. Its ceiling is the length of its floor.
log(n)Binary logarithm of n. Finally, a proper one, not like the other 100.
Binary logarithm of n. Finally, a proper one, not like the previous 11.
log1p(n)Binary logarithm of n+1. Also always positive.
mandelbrot(a, b, limit)Computes the value of the mandelbrot set, for set a and b spot.
* Spot the beetle. Why not.
min(arg, ...), min(list), max(arg, ...), max(list)Compute minimum or maximum of supplied arguments assuming default sortraphical order. In case you are + *
Compute minimum or maximum of supplied arguments assuming default sorthoraphical order. In case you are
* missing argmax, just use a ~ max(a), little less efficient, but still fun.
*
@@ -2011,18 +2039,61 @@ public class Expression implements Cloneable * removes the key from the map, and for nbt - removes content from a given path. For lists and maps returns previous * entry at the address, for nbt's - number of removed objects, with 0 indicating that the original value was unaffected.
* - *put(container, address, value), put(container, address, value, condition)put(container, address, value), put(container, address, value, mode)Lists
*Modifies the container by replacing the value under the address with the supplied value.
- * For lists, a valid index is required, but can be negative as well. If null is supplied as the address, it
- * appends that value to the end of the table.
+ * For lists, a valid index is required, but can be negative as well to indicate positions from the end of the list.
+ * If null is supplied as the address, it always means - add to the end of the list.
There are three modes that lists can have items added to them: + *
replace(default): Replaces item under given index(address). Doesn't change the size of the array
+ * unless null address is used, which is an exception and then it appends to the endinsert: Inserts given element at a specified index, shifting the rest of the array to make space
+ * for the item. Note that index of -1 points to the last element of the list, thus inserting at that position and
+ * moving the previous last element to the new last element position. To insert at the end, use +=
+ * operator, or null address in putextend: treats the supplied value as an iterable set of values to insert at a given index,
+ * extending the list by this amount of items. Again use null address/index to point to the end of
+ * the listMaps
+ *For maps there are no modes available (yet, seems there is no reason to). It replaces the value under the supplied + * key (address), or sets it if not currently present.
+ *NBT Tags
+ *
+ * The address for nbt values is a valid nbt path that you would use with /data command, and tag is any
+ * tag that would be applicable for a given insert operation. Note that to distinguish between proper types (like integer
+ * types, you need to use command notation, i.e. regular ints is 123, while byte size int would be 123b
+ * and an explicit string would be "5", so it helps that scarpet uses single quotes in his strings. Unlike
+ * for lists and maps, it returns the number of affected nodes, or 0 if none were affected.
+ *
There are three modes that NBT tags can have items added to them: + *
replace(default): Replaces item under given path(address). Removes them first if possible, and then
+ * adds given element to the supplied position. The target path can indicate compound tag keys, lists, or individual
+ * elements of the lists.<N>: Index for list insertions. Inserts given element at a specified index, inside a list
+ * specified with the path address. Fails if list is not specified. It behaves like insert mode for lists,
+ * i.e. it is not removing any of the existing elements. Use replace to remove and replace existing element.
+ * merge: assumes that both path and replacement target are of compound type (dictionaries, maps,
+ * {} types), and merges keys from value with the compound tag under the path
* a = l(1, 2, 3); put(a, 1, 4); a => [1, 4, 3]
- * a = l(1, 2, 3); put(a, null, 4, 5, 6); a => [1, 2, 3, 4, 5, 6]
- * a = l(l(0,0,0),l(0,0,0),l(0,0,0)); put(element(a, 1), 1, 1); a => [[0, 0, 0], [0, 1, 0], [0, 0, 0]]
+ * a = l(1, 2, 3); put(a, null, 4); a => [1, 2, 3, 4]
+ * a = l(1, 2, 3); put(a, 1, 4, 'insert'); a => [1, 4, 2, 3]
+ * a = l(1, 2, 3); put(a, null, l(4, 5, 6), 'extend'); a => [1, 2, 3, 4, 5, 6]
+ * a = l(1, 2, 3); put(a, 1, l(4, 5, 6), 'extend'); a => [1, 4, 5, 6, 2, 3]
+ * a = l(l(0,0,0),l(0,0,0),l(0,0,0)); put(a.1, 1, 1); a => [[0, 0, 0], [0, 1, 0], [0, 0, 0]]
+ * a = m(1,2,3,4); put(a, 5, null); a => {1: null, 2: null, 3: null, 4: null, 5: null}
+ * tag = nbt('{}'); put(tag, 'BlockData.Properties', '[1,2,3,4]'); tag => {BlockData:{Properties:[1,2,3,4]}}
+ * tag = nbt('{a:[{lvl:3},{lvl:5},{lvl:2}]}'); put(tag, 'a[].lvl', 1); tag => {a:[{lvl:1},{lvl:1},{lvl:1}]}
+ * tag = nbt('{a:[{lvl:[1,2,3]},{lvl:[3,2,1]},{lvl:[4,5,6]}]}'); put(tag, 'a[].lvl', 1, 2); tag
+ * => {a:[{lvl:[1,2,1,3]},{lvl:[3,2,1,1]},{lvl:[4,5,1,6]}]}
+ * tag = nbt('{a:[{lvl:[1,2,3]},{lvl:[3,2,1]},{lvl:[4,5,6]}]}'); put(tag, 'a[].lvl[1]', 1); tag
+ * => {a:[{lvl:[1,1,3]},{lvl:[3,1,1]},{lvl:[4,1,6]}]}
*
*
* Scarpet supports map structures, aka hashmaps, dicts etc. Map structure can also be used, with null
* values as sets. Apart from container access functions, (. , get, put, has, delete),
* the following functions:
m(values ...), m(iterator), m(key_value_pairs) creates and initializes a map with supplied keys, and values. If the arguments contains a flat list, + * these are all treated as keys with no value, same goes with the iterator - creates a map that behaves like a set. + * If the arguments is a list of lists, they have to have two elements each, and then first is a key, and second, + * a value
+ *
+ * m(1,2,'foo') => {1: null, 2: null, foo: null}
+ * m() => {} (empty map)
+ * m(range(10)) => {0: null, 1: null, 2: null, 3: null, 4: null, 5: null, 6: null, 7: null, 8: null, 9: null}
+ * m(l(1, 2), l(3, 4)) => {1: 2, 3: 4}
+ * reduce(range(10), put(_a, _, _*_); _a, m())
+ * => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
+ *
+ * keys(map), values(map), pairs(map) Returns full lists of keys, values and key-value pairs (2-element lists) for all the entries in the map
+ * * */ - void BasicDataStructures() + public void BasicDataStructures() { addFunction("l", lv -> { @@ -2380,7 +2467,7 @@ public class Expression implements Cloneable *lower(expr), uppper(expr), title(expr)lower(expr), upper(expr), title(expr)Returns lowercase, uppercase or titlecase representation of a string representation of the passed expression
*
* lower('aBc') => 'abc'
@@ -2439,8 +2526,13 @@ public class Expression implements Cloneable
* print(str('this took %d milliseconds',time()-start_time))
*
*
+ * profile_expr(expression)Returns number of times given expression can be run in 50ms time. Useful to profile and optimize your + * code. Note that, even if its only a number, it WILL run these commands, so if they are destructive, + * you need to be careful.
+ * *var(expr)Returns the variable under the name of the string value of the expression. Allows to diff --git a/src/main/java/carpet/script/value/MapValue.java b/src/main/java/carpet/script/value/MapValue.java index a6137e21..bf217311 100644 --- a/src/main/java/carpet/script/value/MapValue.java +++ b/src/main/java/carpet/script/value/MapValue.java @@ -179,13 +179,19 @@ public class MapValue extends AbstractListValue implements ContainerValueInterfa @Override public Value delete(Value where) { - return map.remove(where); + Value ret = map.remove(where); + if (ret == null) + return Value.NULL; + return ret; } @Override public Value put(Value key, Value value) { - return map.put(key, value); + Value ret = map.put(key, value); + if (ret == null) + return Value.NULL; + return ret; } @Override diff --git a/src/main/java/carpet/script/value/NBTSerializableValue.java b/src/main/java/carpet/script/value/NBTSerializableValue.java index f326be97..ebfee982 100644 --- a/src/main/java/carpet/script/value/NBTSerializableValue.java +++ b/src/main/java/carpet/script/value/NBTSerializableValue.java @@ -73,6 +73,10 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa return value; } + public Value clone() + { + return new NBTSerializableValue(getTag().copy()); + } public NBTSerializableValue(Tag tag) { nbtTag = tag; diff --git a/src/main/resources/carpet.mixins.json b/src/main/resources/carpet.mixins.json index 2781ed19..afc47410 100644 --- a/src/main/resources/carpet.mixins.json +++ b/src/main/resources/carpet.mixins.json @@ -1,5 +1,6 @@ { "required": true, + "refmap": "carpet-refmap.json", "package": "carpet.mixins", "compatibilityLevel": "JAVA_8", "mixins": [