diff --git a/docs/scarpet/Documentation.md b/docs/scarpet/Documentation.md index 4e5305a4..fcc8dc42 100644 --- a/docs/scarpet/Documentation.md +++ b/docs/scarpet/Documentation.md @@ -1,4 +1,4 @@ -#API Reference +# API Reference ## Language Specification @@ -36,4 +36,5 @@ [`/script` Command](/docs/scarpet/api/ScriptCommand.md) +## [One Page](/docs/scarpet/Full.md) diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md new file mode 100644 index 00000000..478888a7 --- /dev/null +++ b/docs/scarpet/Full.md @@ -0,0 +1,3150 @@ +# Fundamental components of `scarpet` programming language (towards version 1.7). + +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 interact with the world. + +The project was initially built based on the EvalEx project, however it now diverged +so far away from the original implementation, it would be hard to tell it without +this mention. EvalEx is a handy expression evaluator for Java, that allows to evaluate +simple mathematical and boolean expressions. For more information, +see: [EvalEx GitHub repository](https://github.com/uklimaschewski/EvalEx) + +This specification is divided into two sections: this one is agnostic to any +Minecraft related features and could function on its own, and CarpetExpression +for Minecraft specific routines and world manipulation functions. + +# Synopsis + +
+script run print('Hello World!')
+
+
+or an OVERLY complex example:
+
+
+/script run
+ block_check(x1, y1, z1, x2, y2, z2, block_to_check) ->
+ (
+ l(minx, maxx) = sort(l(x1, x2));
+ 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 in the command mode';
+ xsize = maxx - minx + 1;
+ ysize = maxy - miny + 1;
+ zsize = maxz - minz + 1;
+ total_count = 0;
+ loop(xsize,
+ xx = minx + _ ;
+ loop(ysize,
+ yy = miny + _ ;
+ loop(zsize,
+ zz = minz + _ ;
+ if ( block(xx,yy,zz) == block_to_check,
+ total_count += ceil(rand(1))
+ )
+ )
+ )
+ );
+ total_count
+ );
+ check_area_around_closest_player_for_block(block_to_check) ->
+ (
+ closest_player = player();
+ l(posx, posy, posz) = query(closest_player, 'pos');
+ total_count = block_check( posx-8,1,posz-8, posx+8,17,posz+8, block_to_check);
+ print('There is '+total_count+' of '+block_to_check+' around you')
+ )
+/script invoke check_area_around_closest_player_for_block 'diamond_ore'
+
+
+or simply
+
+
+/script run print('There is'+for(rect(x,9,z,8,8,8), _ == 'diamond_ore')+' diamond ore around you')
+
+
+It definitely pays to check what higher level `scarpet` functions have to offer.
+
+# Programs
+
+You can think of an program like a mathematical expression, like `"2.4*sin(45)/(2-4)"` or `"sin(y)>0 & max(z, 3)>3"`.
+Writing a program, is like writing a `2+3`, just a bit longer.
+
+## Basic language components
+
+Programs consist of constants, like `2`, `3.14`, `pi`, or `'foo'`, operators like `+`, `/`, `->`, variables which you
+can define, like `foo` or special ones that will be defined for you, like `_x`, or `_` , which I specific to a each
+built in function, and functions with name, and arguments in the form of `f(a,b,c)`, where `f` is the function name,
+and `a, b, c` are the arguments which can be any other expression. And that's all the parts of the language, so all
+in all - sounds quite simple.
+
+## Code flow
+
+Like any other proper programming language, `scarpet` needs brackets, basically to identify where stuff begins and
+where it ends. In the languages that uses much more complicated constructs, like Java, they tend to use all sort of
+them, round ones to indicate function calls, curly to indicate section of code, square to access lists, pointy for
+generic types etc... I mean - there is no etc, cause they have exhausted all the bracket options...
+
+`Scarpet` is different, since it runs everything based on functions (although its not per se a functional
+language like lisp) only needs the round brackets for everything, and it is up to the programmer to organize
+its code so its readable, as adding more brackets does not have any effect on the performance of the programs
+as they are compiled before they are executed. Look at the following example usage of `if()` function:
+
+
+if(x<y+6,set(x,8+y,z,'air');plop(x,top('surface',x,z),z,'birch'),sin(query(player(),'yaw'))>0.5,plop(0,0,0,'boulder'),particle('fire',x,y,z))
+
+
+Would you prefer to read
+
+
+if( x<y+6,
+ set(x,8+y,z,'air');
+ plop(x,top('surface',x,z),z,'birch'),
+ sin(query(player(),'yaw'))>0.5,
+ plop(0,0,0,'boulder'),
+ particle('fire',x,y,z)
+)
+
+
+Or rather:
+
+
+if
+(
+ x<y+6,
+ (
+ set(x,8+y,z,'air');
+ plop(x,top('surface',x,z),z,'birch')
+ ),
+ sin(query(player(),'yaw'))>0.5,
+ (
+ plop(0,0,0,'boulder')
+ ),
+ particle('fire',x,y,z)
+)
+
+
+Whichever style you prefer it doesn't matter. It typically depends on the situation and the complexity of the
+subcomponents. No matter how many whitespaces and extra brackets you add - the code will evaluate to exactly the
+same expression, and will run exactly the same, so make sure your programs are nice and clean so others don't
+have problems with them
+
+## Functions and scoping
+
+Users can define functions in the form `fun(args....) -> expression` and they are compiled and saved for further
+execution in this but also subsequent calls of /script command. Functions can also be assigned to variables,
+passed as arguments, called with `call` function, but in most cases you would want to call them directly by
+name, in the form of `fun(args...)`. This means that once defined functions are saved with the world for
+further use. For variables, there are two types of them, global - which are shared anywhere in the code,
+and those are all which name starts with 'global_', and local variables which is everything else and those
+are only visible inside each function. This also means that all the parameters in functions are
+passed 'by value', not 'by reference'.
+
+## Outer variables
+
+Functions can still 'borrow' variables from the outer scope, by adding them to the function signature wrapped
+around built-in function `outer`. It adds the specified value to the function call stack so they behave exactly
+like capturing lambdas in Java, but unlike java captured variables don't need to be final. Scarpet will just
+attach their new values at the time of the function definition, even if they change later. Most value will be
+copied, but mutable values, like maps or lists, allow to keep the 'state' with the function, allowing them to
+have memory and act like objects so to speak. . Check `outer(var)` for details.
+
+## Code delivery, line indicators
+
+Note that this should only apply to pasting your code to execute with commandblock. Scarpet recommends placing
+your code in apps (files with `.sc` extension that can be placed inside "/scripts" folder in the world files and
+loaded as a scarpet app with command `/script load [app_name]`. Scarpet apps loaded from disk should only
+contain code, no need to start with "/script run" prefix
+
+The following is the code that could be provided in a `foo.sc` app file located in world `/scripts` folder
+
+
+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, I salute you, but for the most part it is quite likely that your program +might break, either at compile time, when its initially analyzed, or at execute time, when you suddenly attempt to +divide something by zero. In these cases you would want to get a meaningful error message, but for that you would +need to indicate for the compiler where did you put these new lines, since command block would squish them. For that, +place at the beginning of the line to let the compiler know where are you. This makes so that `$` is the only +character that is illegal in programs, since it will be replaced with new lines. As far as I know, `$` is not +used anywhere inside Minecraft identifiers, so this shouldn't hinder the abilities of your programs. + +Consider the following program executed as command block command: + +
+/script run
+run_program() -> (
+ loop( 10,
+ foo = floor(rand(_));
+ check_not_zero(foo);
+ print(_+' - foo: '+foo);
+ print(' reciprocal: '+ _/foo )
+ )
+);
+check_not_zero(foo) -> (
+ if (foo==0, foo = 1)
+)
+
+
+Lets say that the intention was to check if the bar is zero and prevent division by zero in print, but because
+the `foo` is passed as a variable, it never changes the original foo value. Because of the inevitable division
+by zero, we get the following message:
+
+
+Your math is wrong, Incorrect number format for NaN at pos 98
+run_program() -> ( loop( 10, foo = floor(rand(_)); check_not_zero(foo); print(_+' - foo: '+foo);
+HERE>> print(' reciprocal: '+ _/foo ) ));check_not_zero(foo) -> ( if (foo==0, foo = 1))
+
+
+As we can see, we got our problem where the result of the mathematical operation was not a number
+(infinity, so not a number), however by pasting our program into the command made it squish the newlines so
+while it is clear where the error happened and we still can track the error down, the position of the error (98)
+is not very helpful and wouldn't be useful if the program gets significantly longer. To combat this issue we can
+precede every line of the script with dollar signs `$`:
+
+
+/script run
+$run_program() -> (
+$ loop( 10,
+$ foo = floor(rand(_));
+$ check_not_zero(foo);
+$ print(_+' - foo: '+foo);
+$ print(' reciprocal: '+ _/foo )
+$ )
+$);
+$check_not_zero(foo) -> (
+$ if (foo==0, foo = 1)
+$)
+
+
+Then we get the following error message
+
+
+Your math is wrong, Incorrect number format for NaN at line 7, pos 2
+ print(_+' - foo: '+foo);
+ HERE>> print(' reciprocal: '+ _/foo )
+ )
+
+
+As we can note not only we get much more concise snippet, but also information about the line number and position,
+so means its way easier to locate the potential problems problem
+
+Obviously that's not the way we intended this program to work. To get it `foo` modified via a function call,
+we would either return it as a result and assign it to the new variable:
+
++foo = check_not_zero(foo); +... +check_not_zero(foo) -> if(foo == 0, 1, foo) ++ +.. or convert it to a global variable, which in this case passing as an argument is not required + +
+global_foo = floor(rand(10)); +check_foo_not_zero(); +... +check_foo_not_zero() -> if(global_foo == 0, global_foo = 1) +# Variables and Constants + +`scarpet` provides a number of constants that can be used literally in scripts + +* `null`: nothing, zilch, not even false +* `true`: pure true, or just 1 (one) +* `false`: false truth, or true falsth, 0 (zero) actually +* `pi`: for the fans of perimeters, its a perimeter of an apple pi of diameter 1\. About 3.14 +* `euler`: clever guy. Derivative of its exponent is goto 1\. About 2.72 + +Apart from that, there is a bunch of system variables, that start with `_` that are set by `scarpet` built-ins, +like `_`, typically each consecutive value in loops, `_i` indicating iteration, or `_a` like an accumulator +for `reduce` function. Certain calls to Minecraft specific calls would also set `_x`, `_y`, `_z`, indicating +block positions. All variables starting with `_` are read-only, and cannot be declared and modified in client code. + +## Literals + +`scarpet` accepts numeric and string liters constants. Numbers look like `1, 2.5, -3e-7, 0xff,` and are internally +represented as Java's `double` but `scarpet` will try to trim trailing zeros as much as possible so if you need to +use them as intergers, you can. Strings using single quoting, for multiple reasons, but primarily to allow for +easier use of strings inside doubly quoted command arguments (when passing a script as a parameter of `/script fill` +for example, or when typing in jsons inside scarpet to feed back into a `/data merge` command for example. +Strings also use backslashes `\` for quoting special characters, in both plain strings and regular expressions + +
+'foo'
+print('This doesn\'t work')
+nbt ~ '\\.foo' // matching '.' as a '.', not 'any character match'
+
+# Operators
+
+There is a number of operators you can use inside the expressions. Those could be considered generic type operators
+that apply to most data types. They also follow standard operator precedence, i.e. `2+2*2` is understood
+as `2+(2*2)`, not `(2+2)*2`, otherwise they are applied from left to right, i.e. `2+4-3` is interpreted
+as `(2+4)-3`, which in case of numbers doesn't matter, but since `scarpet` allows for mixing all value types
+the associativity would matter, and may lead to unintended effects:
+
+Important operator is function definition `->` operator. It will be covered
+in [User Defined Functions and Program Control Flow](docs/scarpet/language/FunctionsAndControlFlow.md)
+
+
+'123'+4-2 => ('123'+4)-2 => '1234'-2 => '134'
+'123'+(4-2) => '123'+2 => '1232'
+3*'foo' => 'foofoofoo'
+1357-5 => 1352
+1357-'5' => 137
+3*'foo'-'o' => 'fff'
+l(1,3,5)+7 => l(8,10,12)
+
+
+As you can see, values can behave differently when mixed with other types in the same expression.
+In case values are of the same types, the result tends to be obvious, but `Scarpet` tries to make sense of whatever
+it has to deal with
+
+## Operator Precedence
+
+Here is the complete list of operators in `scarpet` including control flow operators. Note, that commas and brackets
+are not technically operators, but part of the language, even if they look like them:
+
+* Match, Get `~ :`
+* Unary `+ - !`
+* Exponent `^`
+* Multiplication `* / %`
+* Addition `+ -`
+* Comparison `== != > >= <= <`
+* Logical And`&&`
+* Logical Or `||`
+* Assignment `= += <>`
+* Definition `->`
+* Next statement`;`
+* Comma `,`
+* Bracket `( )`
+
+### `Get, Accessor Operator :`
+
+Operator version of the `get(...)` function to access elements of lists, maps, and potentially other containers
+(i.e. NBTs). It is important to distinguish from `~` operator, which is a matching operator, which is expected to
+perform some extra computations to retrieve the result, while `:` should be straightforward and immediate, and
+the source object should behave like a container and support full container API,
+meaning `get(...)`, `put(...)`, `delete(...)`, and `has(...)` functions
+
+For certain operators and functions (get, put, delete, has, =, +=) objects can use `:` annotated fields as l-values,
+meaning construct like `foo:0 = 5`, would act like `put(foo, 0, 5)`, rather than `get(foo, 0) = 5`,
+which would result in an error.
+
+TODO: add more information about l-value behaviour.
+
+### `Matching Operator ~`
+
+This operator should be understood as 'matches', 'contains', 'is_in', or 'find me some stuff about something else.
+For strings it matches the right operand as a regular expression to the left, returning the first match.
+This can be used to extract information from unparsed nbt's in a more convoluted way (use `get(...)` for
+more appropriate way of doing it). For lists it checks if an element is in the list, and returns the
+index of that element, or `null` if no such element was found, especially that the use of `first(...)`
+function will not return the index. Currently it doesn't have any special behaviour for numbers - it checks for
+existence of characters in string representation of the left operand with respect of the regular expression on
+the right hand side.
+
+In Minecraft API portion `entity ~ feature` is a shortcode for `query(entity,feature)` for queries that do not take
+any extra arguments.
+
+
+l(1,2,3) ~ 2 => 1
+l(1,2,3) ~ 4 => null
+'foobar' ~ '.b' => 'ob'
+player('*') ~ 'gnembon' // null unless player gnembon is logged in (better to use player('gnembon') instead
+p ~ 'sneaking' // if p is an entity returns whether p is sneaking
+
+
+Or a longer example of an ineffective way to searching for a squid
+
+
+entities = entities_area('all',x,y,z,100,10,100);
+sid = entities ~ 'Squid';
+if(sid != null, run('execute as '+query(get(entities,sid),'id')+' run say I am here '+query(get(entities,sid),'pos') ) )
+
+
+Or an example to find if a player has specific enchantment on a held axe (either hand) and get its level
+(not using proper NBTs query support via `get(...)`):
+
+
+global_get_enchantment(p, ench) -> (
+$ for(l('main','offhand'),
+$ holds = query(p, 'holds', _);
+$ if( holds,
+$ l(what, count, nbt) = holds;
+$ if( what ~ '_axe' && nbt ~ ench,
+$ lvl = max(lvl, number(nbt ~ '(?<=lvl:)\\d') )
+$ )
+$ )
+$ );
+$ lvl
+$);
+/script run global_get_enchantment(players(), 'sharpness')
+
+
+### `Basic Arithmetic Operators + - * /`
+
+Allows to add the results of two expressions. If the operands resolve to numbers, the result is arithmetic operation.
+In case of strings, adding or subtracting from a string results in string concatenation and removal of substrings
+from that string. Multiplication of strings and numbers results in repeating the string N times and division results
+in taking the first k'th part of the string, so that `str*n/n ~ str` In case first operand is a list, either it
+results in a new list with all elements modified one by one with the other operand, or if the operand is a list
+with the same number of items - element-wise addition/subtraction
+
+Examples:
+
++2+3 => 5 +'foo'+3+2 => 'foo32' +'foo'+(3+2) => 'foo5' +3+2+'bar' => '5bar' +'foo'*3 => 'foofoofoo' +'foofoofoo' / 3 => 'foo' +'foofoofoo'-'o' => 'fff' +l(1,2,3)+1 => l(2,3,4) +b = l(100,63,100); b+l(10,0,10) => l(110,63,110) ++ +### `Just Operators % ^` + +The modulo and exponent (power) operators work only if both operands are numbers + +
pi^pi%euler => 1.124.... +-9 % 4 => -1 +9 % -4 => 0 ¯\_(ツ)_/¯ Java +-3 ^ 2 => 9 +-3 ^ pi => // Error ++ +### `Comparison Operators == != < > <= >=` + +Allows to compare the results of two expressions. For numbers it is considers arithmetic order of numbers, for +strings - lexicographical, nulls are always 'less' than everything else, and lists check their elements - +if the sizes are different, the size matters, otherwise, pairwise comparisons for each elements are performed. +The same order rules than with all these operators are used with the default sortographical order as used by `sort` +function. All of these are true: + +
+null == null +null != false +0 == false +1 == true +null < 0 +null < -1000 +1000 < 'a' +'bar' < 'foo' +3 == 3.0 ++ +### `Logical Operators && ||` + +These operator compute respective boolean operation on the operands. What it important is that if calculating of the +second operand is not necessary, it won't be evaluated, which means one can use them as conditional statements. In +case of success returns first positive operand (`||`) or last one (`&&`). + +
+true || false => 1
+null || false => 0
+null != false || run('kill gnembon') => 1 // gnembon survives
+null != false && run('kill gnembon') => 0 // when cheats not allowed
+null != false && run('kill gnembon') => 1 // gnembon dies, cheats allowed
+
+
+### `Assignment Operators = <> +=`
+
+A set of assignment operators. All require bounded variable on the LHS, `<>` requires bounded arguments on the
+right hand side as well (bounded, meaning being variables). Additionally they can also handle list constructors
+with all bounded variables, and work then as list assignment operators. When `+=` is used on a list, it extends
+that list of that element, and returns the list (old == new). `scarpet` doesn't support currently removal of items.
+Removal of items can be obtaine via `filter` command, and reassigning it fo the same variable. Both operations would
+require rewriting of the array anyways.
+
++a = 5 => a == 5 +l(a,b,c) = l(3,4,5) => a==3, b==4, c==5 +l(minx,maxx) = sort(xi,xj); // minx assumes min(xi, xj) and maxx, max(xi, xj) +l(a,b,c,d,e,f) = l(range(6)); l(a,b,c) <> l(d,e,f); l(a,b,c,d,e,f) => [3,4,5,0,1,2] +a = l(1,2,3); a += 4 => [1,2,3,4] +a = l(1,2,3,4); a = filter(a,_!=2) => [1,3,4] ++ +### `Unary Operators - +` + +Require a number, flips the sign. One way to assert it's a number is by crashing the script. gg. + +
+-4 => -4 ++4 => 4 ++'4' // Error message ++ +### `Negation Operator !` + +flips boolean condition of the expression. Equivalent of `bool(expr)==false` + +
+!true => 0 +!false => 1 +!null => 1 +!5 => 0 +!l() => 1 +!l(null) => 0 ++# Arithmetic operations + +## Basic Arithmetic Functions + +There is bunch of them - they require a number and spit out a number, doing what you would expect them to do. + +### `fact(n)` + +Factorial of a number, a.k.a `n!`, just not in `scarpet`. Gets big... quick... + +### `sqrt(n)` + +Square root. For other fancy roots, use `^`, math and yo noggin. Imagine square roots on a tree... + +### `abs(n)` + +Absolut value. + +### `round(n)` + +Closest integer value. Did you know the earth is also round? + +### `floor(n)` + +Highest integer that is still no larger then `n`. Insert a floor pun here. + +### `ceil(n)` + +First lucky integer that is not smalller than `n`. As you would expect, ceiling is typically right above the floor. + +### `ln(n)` + +Natural logarithm of `n`. Naturally. + +### `ln1p(n)` + +Natural logarithm of `n+1`. Very optimistic. + +### `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 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 sorthoraphical order. +In case you are missing `argmax`, just use `a ~ max(a)`, little less efficient, but still fun. + +Interesting bit - `min` and `max` don't remove variable associations from arguments, which means can be used as +LHS of assignments (obvious case), or argument spec in function definitions (far less obvious). + +
+a = 1; b = 2; min(a,b) = 3; l(a,b) => [3, 2] +a = 1; b = 2; fun(x, min(a,b)) -> l(a,b); fun(3,5) => [5, 0] ++ +Absolutely no idea, how the latter might be useful in practice. But since it compiles, can ship it. + +### `relu(n)` + +Linear rectifier of `n`. 0 below 0, n above. Why not. `max(0,n)` with less moral repercussions. + +## Trigonometric / Geometric Functions + +### `sin(x)` + +### `cos(x)` + +### `tan(x)` + +### `asin(x)` + +### `acos(x)` + +### `atan(x)` + +### `atan2(x,y)` + +### `sinh(x)` + +### `cosh(x)` + +### `tanh(x)` + +### `sec(x)` + +### `csc(x)` + +### `sech(x)` + +### `csch(x)` + +### `cot(x)` + +### `acot(x)` + +### `coth(x)` + +### `asinh(x)` + +### `acosh(x)` + +### `atanh(x)` + +### `rad(deg)` + +### `deg(rad)` + +Use as you wish +# System functions + +## Type conversion functions + +### `copy(expr)` + +Returns the deep copy of the expression. Can be used to copy mutable objects, like maps and lists + +### `type(expr)` + +Returns the string value indicating type of the expression. Possible outcomes +are `null, number, string, list, iterator`, as well as minecraft related concepts like `block, entity, nbt` + +### `bool(expr)` + +Returns a boolean context of the expression. Note that there are no true/false values in scarpet. `true` is +alias of 1, and `false` is 0\. Bool is also interpreting string values as boolean, which is different from other +places where boolean context can be used. This can be used in places where API functions return string values to +represent binary values + +
+bool(pi) => 1
+bool(false) => 0
+bool('') => 0
+bool(l()) => 0
+bool(l('')) => 1
+bool('foo') => 1
+bool('false') => 0
+bool('nulL') => 0
+if('false',1,0) => 1
+
+
+### `number(expr)`
+
+Returns a numeric context of the expression. Can be used to read numbers from strings
+
+
+number(null) => null
+number(false) => 0
+number('') => null
+number('3.14') => 3.14
+number(l()) => 0
+number(l('')) => 1
+number('foo') => null
+number('3bar') => null
+number('2')+number('2') => 4
+
+
+### `str(expr, params? ... ), str(expr, param_list)`
+
+Returns a formatted string representing expression. Accepts formatting style accepted by `String.format`.
+Supported types (with `"%?"` syntax):
+
+* d, o, x: integers
+* a, e, f, g: floats
+* b: booleans
+* s: strings
+
+
+str(null) => null
+str(false) => 0
+str('') => null
+str('3.14') => 3.14
+str(l()) => 0
+str(l('')) => 1
+str('foo') => null
+str('3bar') => null
+str(2)+str(2) => 22
+str('pi: %.2f',pi) => 'pi: 3.14'
+str('player at: %d %d %d',pos(player())) => 'player at: 567, -2423, 124'
+
+
+* * *
+## Threading and Parallel Execution
+
+Scarpet allows to run threads of execution in parallel to the main script execution thread. In Minecraft, the main
+thread scripts are executed on the main server thread. Since Minecraft is inherently NOT thread safe, it is not that
+beneficial to parallel execution in order to access world resources faster. Both `GetBlockState` and `setBlockState`
+are not thread safe and require the execution to park on the server thread, where these requests can be executed in
+the off-tick time in between ticks that didn't take 50ms. There are however benefits of running things in parallel,
+like fine time control not relying on the tick clock, or running things independent on each other. You can still run
+your actions on tick-by-tick basis, either taking control of the execution using `game_tick()` API function
+(nasty solution), or scheduling tick using `schedule()` function (much nicer solution), but threading often gives
+the neatest solution to solve problems in parallel (see scarpet camera).
+
+Due to limitations with the game, there are some limits to the threading as well. You cannot for
+instance `join_task()` at all from the main script and server thread, because any use of Minecraft specific
+function that require any world access, will require to park and join on the main thread to get world access,
+meaning that calling join on that task would inevitably lead to a typical deadlock. You can still join tasks
+from other threads, just because the only possibility of a deadlock in this case would come explicitly from your
+bad code, not the internal world access behaviour. Some things tough like player or entity manipulation, can be
+effectively parallelized.
+
+### `task(function, ?args...., ?executor)`
+
+Creates and runs a parallel task, returning the handle to the task object. Task will return the return value of the
+function when its completed, or will return `null` immediately if task is still in progress, so grabbing a value of
+a task object is non-blocking. Function can be either function value, or function lambda, or a name of an existing
+defined function. In case function needs arguments to be called with, they should be supplied after the function
+name, or value. Optional `executor` identifier is to place the task in a specific queue identified by this value.
+The default thread value is the `null` thread. There is no limits on number of parallel tasks for any executor,
+so using different queues is solely for synchronization purposes. Also, since `task` function knows how many extra
+arguments it requires, the use of tailing optional parameter for the custom executor thread pool is not ambiguous.
+
+
+task( _() -> print('Hello Other World') ) => Runs print command on a separate thread
+foo(a, b) -> print(a+b); task('foo',2,2) => Uses existing function definition to start a task
+task('foo',3,5,'temp'); => runs function foo with a different thread executor, identified as 'temp'
+a = 3; task( _(outer(a), b) -> foo(a,b), 5, 'temp')
+ => Another example of running the same thing passing arguments using closure over anonymous function as well as passing a parameter.
+
+
+### `task_count(executor?)`
+
+If no argument provided, returns total number of tasks being executed in parallel at this moment using scarpet
+threading system. If the executor is provided, returns number of active tasks for that provider. Use `task_count(null)`
+to get the task count of the default executor only.
+
+### `task_value(task)`
+
+Returns the task return value, or `null` if task hasn't finished yet. Its a non-blocking operation. Unlike `join_task`,
+can be called on any task at any point
+
+### `task_join(task)`
+
+Waits for the task completion and returns its computed value. If the task has already finished returns it immediately.
+Unless taking the task value directly, i.e. via `task_value`, this operation is blocking. Since Minecraft has a
+limitation that all world access operations have to be performed on the main game thread in the off-tick time,
+joining any tasks that use Minecraft API from the main thread would mean automatic lock, so joining from the main
+thread is not allowed. Join tasks from other threads, if you really need to, or communicate asynchronously with
+the task via globals or function data / arguments to monitor its progress, communicate, get partial results,
+or signal termination.
+
+### `task_completed(task)`
+
+Returns true if task has completed, or false otherwise.
+
+### `synchronize(lock, expression)`
+
+Evaluates `expression` synchronized with respect to the lock `lock`. Returns the value of the expression.
+
+* * *
+
+## Auxiliary functions
+
+### `lower(expr), upper(expr), title(expr)`
+
+Returns lowercase, uppercase or titlecase representation of a string representation of the passed expression
+
+
+lower('aBc') => 'abc'
+upper('aBc') => 'ABC'
+title('aBc') => 'Abc'
+
+
+### `replace(string, regex, repl?); replace_first(string, regex, repl?)`
+
+Replaces all, or first occurence of a regular expression in the string with `repl` expression,
+or nothing, if not specified
+
+
+replace('abbccddebfg','b+','z') // => azccddezfg
+replace_first('abbccddebfg','b+','z') // => azccddebfg
+
+
+### `length(expr)`
+
+Returns length of the expression, the length of the string, the length of the integer part of the number,
+or length of the list
+
+
+length(pi) => 1
+length(pi*pi) => 1
+length(pi^pi) => 2
+length(l()) => 0
+length(l(1,2,3)) => 3
+length('') => 0
+length('foo') => 3
+
+
+### `rand(expr), rand(expr, seed)`
+
+returns a random number from `0.0` (inclusive) to `expr` (exclusive). In boolean context (in conditions,
+boolean functions, or `bool`), returns false if the randomly selected value is less than 1\. This means
+that `rand(2)` returns true half of the time and `rand(5)` returns true for 80% (4/5) of the time. If seed is not
+provided, uses a random seed. If seed is provided, each consecutive call to rand() will act like 'next' call to the
+same random object. Scarpet keeps track of up to 1024 custom random number generators, so if you exceed this number
+(per app), then your random sequence will revert to the beginning.
+
+
+map(range(10), floor(rand(10))) => [5, 8, 0, 6, 9, 3, 9, 9, 1, 8]
+map(range(10), bool(rand(2))) => [1, 1, 1, 0, 0, 1, 1, 0, 0, 0]
+map(range(10), str('%.1f',rand(_))) => [0.0, 0.4, 0.6, 1.9, 2.8, 3.8, 5.3, 2.2, 1.6, 5.6]
+
+
+### `perlin(x), perlin(x, y), perlin(x, y, z), perlin(x, y, z, seed)`
+
+returns a noise value from `0.0` to `1.0` (roughly) for 1, 2 or 3 dimensional coordinate. The default seed it samples
+from is `0`, but seed can be specified as a 4th argument as well. In case you need 1D or 2D noise values with custom
+seed, use `null` for `z`, or `y` and `z` arguments respectively.
+
+Perlin noise is based on a square grid and generates rougher maps comparing to Simplex, which is creamier.
+Querying for lower-dimensional result, rather than affixing unused dimensions to constants has a speed benefit,
+
+Thou shall not sample from noise changing seed frequently. Scarpet will keep track of the last 256 perlin seeds
+used for sampling providing similar speed comparing to the default seed of `0`. In case the app engine uses more
+than 256 seeds at the same time, switching between them can get much more expensive.
+
+### `simplex(x, y), simplex(x, y, z), simplex(x, y, z, seed)`
+
+returns a noise value from `0.0` to `1.0` (roughly) for 2 or 3 dimensional coordinate. The default seed it samples
+from is `0`, but seed can be specified as a 4th argument as well. In case you need 2D noise values with custom seed,
+use `null` for `z` argument.
+
+Simplex noise is based on a triangular grid and generates smoother maps comparing to Perlin. To sample 1D simplex
+noise, affix other coordinate to a constant.
+
+Thou shall not sample from noise changing seed frequently. Scarpet will keep track of the last 256 simplex seeds
+used for sampling providing similar speed comparing to the default seed of `0`. In case the app engine uses more
+than 256 seeds at the same time, switching between them can get much more expensive.
+
+### `print(expr)`
+
+prints the value of the expression to chat. Passes the result of the argument to the output unchanged,
+so `print`-statements can be weaved in code to debug programming issues
+
+
+print('foo') => results in foo, prints: foo
+a = 1; print(a = 5) => results in 5, prints: 5
+a = 1; print(a) = 5 => results in 5, prints: 1
+print('pi = '+pi) => prints: pi = 3.141592653589793
+print(str('pi = %.2f',pi)) => prints: pi = 3.14
+
+
+### `sleep(expr)`
+
+Halts the execution of the program (and the game itself) for `expr` milliseconds. All in all, its better to
+use `game_tick(expr)` to let the game do its job while the program waits
+
++sleep(50) ++ +### `time()` + +Returns the number of milliseconds since 'some point', like Java's `System.nanoTime()`. +It returns a float, which has 1 microsecond precision (0.001 ms) + +
+start_time = time();
+flip_my_world_upside_down();
+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.
+
+* * *
+
+## Access to variables and stored functions (use with caution)
+
+### `var(expr)`
+
+Returns the variable under the name of the string value of the expression. Allows to manipulate variables in more
+programmatic manner, which allows to use local variable set with a hash map type key-value access,
+can also be used with global variables
+
+
+a = 1; var('a') = 'foo'; a => a == 'foo'
+
+
+### `undef(expr)`
+
+Removes all bindings of a variable with a name of `expr`. Removes also all function definitions with that name.
+It can affect global variable pool, and local variable set for a particular function.
+
+
+inc(i) -> i+1; foo = 5; inc(foo) => 6
+inc(i) -> i+1; foo = 5; undef('foo'); inc(foo) => 1
+inc(i) -> i+1; foo = 5; undef('inc'); undef('foo'); inc(foo) => Error: Function inc is not defined yet at pos 53
+undef('pi') => bad idea - removes hidden variable holding the pi value
+undef('true') => even worse idea, unbinds global true value, all references to true would now refer to the default 0
+
+
+### `vars(prefix)`
+
+It returns all names of variables from local scope (if prefix does not start with 'global') or global variables
+(otherwise). Here is a larger example that uses combination of `vars` and `var` functions to be
+used for object counting
+
+
+/script run
+$ count_blocks(ent) -> (
+$ l(cx, cy, cz) = query(ent, 'pos');
+$ scan(cx, cy, cz, 16, 16, 16, var('count_'+_) += 1);
+$ for ( sort_key( vars('count_'), -var(_)),
+$ print(str( '%s: %d', slice(_,6), var(_) ))
+$ )
+$ )
+/script run count_blocks(player())
+
+
+* * *
+
+## System key-value storage
+
+Scarpet runs apps in isolation. The can share code via use of shared libraries, but each library that is imported to
+each app is specific to that app. Apps can store and fetch state from disk, but its restricted to specific locations
+meaning apps cannot interact via disk either. To facilitate communication for interappperability, scarpet hosts its
+own key-value storage that is shared between all apps currently running on the host, providing methods for getting an
+associated value with optional setting it if not present, and an operation of modifying a content of a system
+global value.
+
+### `system_variable_get(key, default_value ?)`
+
+Returns the variable from the system shared key-value storage keyed with a `key` value, optionally if value is
+not present, and default expression is provided, sets a new value to be associated with that key
+
+### `system_variable_set(key, new_value)`
+
+Returns the variable from the system shared key-value storage keyed with a `key` value, and sets a new
+mapping for the key# Loops, and higher order functions
+
+Efficient use of these functions can greatly simplify your programs and speed them up, as these functions will
+internalize most of the operations that need to be applied on multiple values at the same time. Most of them take
+a `list` argument which can be any iterable structure in scarpet, including generators, like `rect`, or `range`,
+and maps, where the iterator returns all the map keys
+
+## Loops
+
+### `break(), break(expr), continue(), continue(expr)`
+
+These allow to control execution of a loop either skipping current iteration code, using `continue`, or finishing the
+current loop, using `break`. `break` and `continue` can only be used inside `for, while, loop, map, filter and reduce`
+functions, while `break` can be used in `first` as well. Outside of the internal expressions of these functions,
+calling `break` or `continue` will cause an error. In case of the nexted loops, and more complex setups, use
+custom `try` and `throw` setup.
+
+Please check corresponding loop function description what `continue` and `break` do in their contexts, but in
+general case, passed values to `break` and `continue` will be used in place of the return value of the internal
+iteration expression.
+
+### `for(list,expr(_,_i))`
+
+Evaluates expression over list of items from the `list`. Supplies `_`(value) and `_i`(iteration number) to the `expr`.
+
+Returns the number of times `expr` was successful. Uses `continue` and `break` argument in place of the returned
+value from the `expr`(if supplied), to determine if the iteration was successful.
+
++check_prime(n) -> !first( range(2, sqrt(n)+1), !(n % _) ); +for(range(1000000,1100000),check_prime(_)) => 7216 ++ +From which we can learn that there is 7216 primes between 1M and 1.1M + +### `while(cond, limit)` + +Evaluates expression `expr` repeatedly until condition `cond` becomes false, but not more than `limit` times. +Returns the result of the last `expr` evaluation, or `null` if nothing was successful. Both `expr` and `cond` will +recveived a bound variable `_` indicating current iteration, so its a number. + +
+while(a<100,10,a=_*_) => 81 // loop exhausted via limit +while(a<100,20,a=_*_) => 100 // loop stopped at condition, but a has already been assigned +while(_*_<100,20,a=_*_) => 81 // loop stopped at condition, before a was assigned a value ++ +### `loop(num,expr(_),exit(_)?)` + +Evaluates expression `expr`, `num` number of times. code>expr receives `_` system variable indicating the iteration. + +
+loop(5, game_tick()) => repeat tick 5 times +list = l(); loop(5, x = _; loop(5, list += l(x, _) ) ); list + // double loop, produces: [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [1, 0], [1, 1], ... , [4, 2], [4, 3], [4, 4]] ++ +In this small example we will search for first 10 primes, apparently including 0: + +
+check_prime(n) -> !first( range(2, sqrt(n)+1), !(n % _) ); +primes = l(); +loop(10000, if(check_prime(_), primes += _ ; if (length(primes) >= 10, break()))); +primes +// outputs: [0, 1, 2, 3, 5, 7, 11, 13, 17, 19] ++ +## Higher Order Functions + +### `map(list,expr(_,_i))` + +Converts a `list` of values, to another list where each value is result of an expression `v = expr(_, _i)` +where `_` is passed as each element of the list, and `_i` is the index of such element. If `break` is called the +map returns whatever collected thus far. If `continue` and `break` are used with supplied argument, it is used in +place of the resulting map element, otherwise current element is skipped. + +
+map(range(10), _*_) => [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
+map(players('*'), _+' is stoopid') [gnembon is stoopid, herobrine is stoopid]
+
+
+### `filter(list,expr(_,_i))`
+
+filters `list` elements returning only these that return positive result of the `expr`. With `break` and `continue`
+statements, the supplied value can be used as a boolean check instead.
+
+
+filter(range(100), !(_%5), _*_>1000) => [0, 5, 10, 15, 20, 25, 30]
+map(filter(entity_list('*'),_=='Witch'), query(_,'pos') ) => [[1082.5, 57, 1243.5]]
+
+
+### `first(list,expr(_,_i))`
+
+Finds and returns the first item in the list that satisfies `expr`. It sets `_` for current element value,
+and `_i` for index of that element. `break` can be called inside the iteration code, using its argument value
+instead of the current item. `continue` has no sense and cannot be called inside `first` call.
+
++first(range(1000,10000), n=_; !first( range(2, sqrt(n)+1), !(n % _) ) ) => 1009 // first prime after 1000 ++ +Notice in the example above, that we needed to rename the outer `_` to be albe to use in in the inner `first` call + +### `all(list,expr(_,_i))` + +Returns `true` if all elements on the list satisfy the condition. Its roughly equivalent +to `all(list,expr) <=> for(list,expr)==length(list)`. `expr` also receives bound `_` and `_i` variables. `break` +and `continue` have no sense and cannot be used inside of `expr` body. + +
+all([1,2,3], check_prime(_)) => 1 +all(neighbours(x,y,z), _=='stone') => 1 // if all neighbours of [x, y, z] are stone +map(filter(rect(0,4,0,1000,0,1000), l(x,y,z)=pos(_); all(rect(x,y,z,1,0,1),_=='bedrock') ), pos(_) ) + => [[-298, 4, -703], [-287, 4, -156], [-269, 4, 104], [242, 4, 250], [-159, 4, 335], [-208, 4, 416], [-510, 4, 546], [376, 4, 806]] + // find all 3x3 bedrock structures in the top bedrock layer +map( filter( rect(0,4,0,1000,1,1000,1000,0,1000), l(x,y,z)=pos(_); + all(rect(x,y,z,1,0,1),_=='bedrock') && for(rect(x,y-1,z,1,1,1,1,0,1),_=='bedrock')<8), + pos(_) ) => [[343, 3, -642], [153, 3, -285], [674, 3, 167], [-710, 3, 398]] + // ditto, but requiring at most 7 bedrock block in the 18 blocks below them ++ +### `reduce(list,expr(_a,_,_i), initial)` + +Applies `expr` for each element of the list and saves the result in `_a` accumulator. Consecutive calls to `expr` +can access that value to apply more values. You also need to specify the initial value to apply for the +accumulator. `break` can be used to terminate reduction prematurely. If a value is provided to `break` or `continue`, +it will be used from now on as a new value for the accumulator. + +
+reduce([1,2,3,4],_a+_,0) => 10 +reduce([1,2,3,4],_a*_,1) => 24 +# User-defined functions and program control flow + +## Writing programs with more than 1 line + +### `Operator ;` + +To effectively write programs that have more than one line, a programmer needs way to specify a sequence of commands +that execute one after another. In `scarpet` this can be achieved with `;`. Its an operator, and by separating +statements with semicolons. And since whitespaces and +`$` (commandline visible newline separator) +sign are all treats as whitespaces, how you layout your code doesn't matter, as long as it is readable to everyone involved. + +
+expr; +expr; +expr; +expr ++ +Notice that the last expression is not followed by a semicolon. Since instruction separation is functional +in `scarpet`, and not barely an instruction delimiter, terminating the code with a dangling operator wouldn't +be valid. Having said that, since many programming languages don't care about the number of op terminators +programmers use, carpet preprocessor will remove all unnecessary semicolons from scripts when compiled. + +In general `expr; expr; expr; expr` is equivalent to `(((expr ; expr) ; expr) ; expr)`. + +Result of the evaluated expression is the same as the result of the second expression, but first expression +is also evaluated for side-effects + +
+expr1 ; expr2 => expr2 // with expr1 as a side-effect ++ +## Global variables + +All defined functions are compiled, stored persistently, and available globally - accessible to all other scripts. +Functions can only be undefined via call to `undef('fun')`, which would erase global entry for function `fun`. +Since all variables have local scope inside each function, one way to share large objects is via global variables + +Any variable that is used with a name that starts with `'global_'` will be stored and accessible globally, not, +inside current scope. It will also persist across scripts, so if a procedure needs to use its own construct, it +needs to define it, or initialize it explicitly, or undefine it via `undef` + +
+a() -> global_list+=1; global_list = l(1,2,3); a(); a(); global_list // => [1,2,3,1,1] ++ +### `Operator ->` + +To organize code better than a flat sequence of operations, one can define functions. Definition is correct +if has the following form + +
+fun(args, ...) -> expr ++ +Where `fun(args, ...)` is a function signature indicating function name, number of arguments, and their names, +and expr is an expression (can be complex) that is evaluated when `fun` is called. 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 `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 and other containers, however their +copy will be shallow. + +The function returns its name as a string, which means it can be used to call it later with the `call` function + +Using `_` as the function name creates anonymous function, so each time `_` function is defined, it will be given +a unique name, which you can pass somewhere else to get this function `call`ed. + +
+a(lst) -> lst+=1; list = l(1,2,3); a(list); a(list); list // => [1,2,3] ++ +In case the inner function wants to operate and modify larger objects, lists from the outer scope, but not global, +it needs to use `outer` function in function signature + +### `outer(arg)` + +`outer` function can only be used in the function signature, and it will cause an error everywhere else. It +saves the value of that variable from the outer scope and allows its use in the inner scope. This is a similar +behaviour to using outer variables in lambda function definitions from Java, except here you have to specify +which variables you want to use, and borrow + +This mechanism can be used to use static mutable objects without the need of using `global_...` variables + +
+list = l(1,2,3); a(outer(list)) -> list+=1; a(); a(); list // => [1,2,3,1,1] ++ +The return value of a function is the value of the last expression. This as the same effect as using outer or +global lists, but is more expensive + +
+a(lst) -> lst+=1; list = l(1,2,3); list=a(list); list=a(list); list // => [1,2,3,1,1] ++ +Ability to combine more statements into one expression, with functions, passing parameters, and global and outer +scoping allow to organize even larger scripts + +### `import(module_name, symbols ...)` + +Imports symbols from other apps and libraries into the current one: global variables or functions, allowing to use +them in the current app. This include other symbols imported by these modules. Scarpet supports cicular dependencies, +but if symbols are used directly in the module body rather than functions, it may not be able to retrieve them. +Returns full list of available symbols that could be imported from this module, which can be used to debug import +issues, and list contents of libraries. + +### `call(function, args.....)` + +calls a user defined function with specified arguments. It is equivalent to calling `function(args...)` directly +except you can use it with function value, or name instead. This means you can pass functions to other user defined +functions as arguments and call them with `call` internally. And since function definitions return the defined +function, they can be defined in place as anonymous functions. + +Little technical note: the use of `_` in expression passed to built in functions is much more efficient due to not +creating new call stacks for each invoked function, but anonymous functions is the only mechanism available for +programmers with their own lambda arguments + +
+my_map(list, function) -> map(list, call(function, _)); +my_map(l(1,2,3), _(x) -> x*x); // => [1,4,9] +profile_expr(my_map(l(1,2,3), _(x) -> x*x)); // => ~32000 +sq(x) -> x*x; profile_expr(my_map(l(1,2,3), 'sq')); // => ~36000 +sq = (_(x) -> x*x); profile_expr(my_map(l(1,2,3), sq)); // => ~36000 +profile_expr(map(l(1,2,3), _*_)); // => ~80000 ++ +## Control flow + +### `return(expr?)` + +Sometimes its convenient to break the organized control flow, or it is not practical to pass the final result value of +a function to the last statement, in this case a return statement can be used + +If no argument is provided - returns null value. + +
+def() -> ( + expr1; + expr2; + return(expr3); // function terminates returning expr3 + expr4; // skipped + expr5 // skipped +) ++ +In general its cheaper to leave the last expression as a return value, rather than calling +returns everywhere, but it would often lead to a messy code. + +### `exit(expr?)` + +It terminates entire program passing `expr` as the result of the program execution, or null if omitted. + +### `try(expr, catch_expr(_)?) ... throw(value?)` + +`try` function evaluates expression, and continues further unless `throw` function is called anywhere +inside `expr`. In that case the `catch_expr` is evaluates with `_` set to the argument `throw` was called with. +This mechanic accepts skipping thrown value - it throws null instead, and catch expression - then try returns +null as well This mechanism allows to terminate large portion of a convoluted call stack and continue program +execution. There is only one level of exceptions currently in carpet, so if the inner function also defines +the `try` catchment area, it will received the exception first, but it can technically rethrow the value its +getting for the outer scope. Unhandled throw acts like an exit statement. + +### `if(cond, expr, cond?, expr?, ..., default?)` + +If statement is a function that takes a number of conditions that are evaluated one after another and if any of +them turns out true, its `expr` gets returned, otherwise, if all conditions fail, the return value is `default` +expression, or `null` if default is skipped + +`if` function is equivalent to `if (cond) expr; else if (cond) expr; else default;` from Java, +just in a functional form +# Lists, Maps and API support for Containers + +Scarpet supports basic container types: lists and maps (aka hashmaps, dicts etc..) + +## Container manipulation + +Here is a list of operations that work on all types of containers: lists, maps, as well as other Minecraft specific +modifyable containers, like NBTs + +### `get(container, address, ...), get(lvalue), ':' operator` + +Returns the value at `address` element from the `value`. For lists it indicates an index, use negative numbers to +reach elements from the end of the list. `get` call will always be able to find the index. In case there is few +items, it will loop over + +for maps, retrieves the value under the key specified in the `address` or null otherwise + +[Minecraft specific usecase]: In case `value` is of `nbt` type, uses address as the nbt path to query, returning null, +if path is not found, one value if there was one match, or list of values if result is a list. Returned elements can +be of numerical type, string texts, or another compound nbt tags + +In case to simplify the access with nested objects, you can add chain of addresses to the arguments of `get` rather +than calling it multiple times. `get(get(foo,a),b)` is equivalent to `get(foo, a, b)`, or `foo:a:b`. + +
+get(l(range(10)), 5) => 5
+get(l(range(10)), -1) => 9
+get(l(range(10)), 10) => 0
+l(range(10)):93 => 3
+get(player() ~ 'nbt', 'Health') => 20 // inefficient way to get player health, use player() ~ 'health' instead
+get(m( l('foo',2), l('bar',3), l('baz',4) ), 'bar') => 3
+
+
+### `has(container, address, ...), has(lvalue)`
+
+Similar to `get`, but returns boolean value indicating if the given index / key / path is in the container.
+Can be used to determine if `get(...)==null` means the element doesn't exist, or the stored value for this
+address is `null`, and is cheaper to run than `get`.
+
+Like get, it can accept multiple addresses for chains in nested containers. In this case `has(foo:a:b)` is
+equivalent to `has(get(foo,a), b)` or `has(foo, a, b)`
+
+### `delete(container, address, ...), delete(lvalue)`
+
+Removes specific entry from the container. For the lists - removes the element and shrinks it. For maps, it
+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.
+
+Like with the `get` and `has`, `delete` can accept chained addresses, as well as l-value container access, removing
+the value from the leaf of the path provided, so `delete(foo, a, b)` is the
+same as `delete(get(foo,a),b)` or `delete(foo:a:b)`
+
+Returns true, if container was changed, false, if it was left unchanged, and null if operation was invalid.
+
+### `put(container, address, value), put(container, address, value, mode), put(lvalue, value)`
+
+**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 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 end
+* `insert`: 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 put
+* `extend`: 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 list
+
+Due to the extra mode parameter, there is no chaining for `put`, but you can still use l-value container access to
+indicate container and address, so `put(foo, key, value)` is the same as `put(foo:key, value)` or `foo:key=value`
+
+Returns true, if container got modified, false otherwise, and null if operation was invalid.
+
+**Maps**
+
+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.
+* `
+a = l(1, 2, 3); put(a, 1, 4); a => [1, 4, 3]
+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]}]}
+
+
+## List operations
+
+### `l(values ...), l(iterator)`
+
+Creates a list of values of the expressions passed as parameters. It can be used as an L-value and if all
+elements are variables, you coujld use it to return multiple results from one function call, if that
+function returns a list of results with the same size as the `l` call uses. In case there is only one
+argument and it is an iterator (vanilla expression specification has `range`, but Minecraft API implements
+a bunch of them, like `diamond`), it will convert it to a proper list. Iterators can only be used in high order
+functions, and are treated as empty lists, unless unrolled with `l`
+
++l(1,2,'foo') => [1, 2, foo] +l() => [] (empty list) +l(range(10)) => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +l(1, 2) = l(3, 4) => Error: l is not a variable +l(foo, bar) = l(3,4); foo==3 && bar==4 => 1 +l(foo, bar, baz) = l(2, 4, 6); l(min(foo, bar), baz) = l(3, 5); l(foo, bar, baz) => [3, 4, 5] ++ +In the last example `l(min(foo, bar), baz)` creates a valid L-value, as min(foo, bar) finds the lower of the +variables (in this case `foo`) creating a valid assignable L-list of [foo, baz], and these values +will be assigned new values + +### `join(delim, list), join(delim, values ...)` + +Returns a string that contains joined elements of the list, iterator, or all values, +concatenated with `delim` delimiter + +
+join('-',range(10)) => 0-1-2-3-4-5-6-7-8-9
+join('-','foo') => foo
+join('-', 'foo', 'bar') => foo-bar
+
+
+### `split(delim, expr)`
+
+Splits a string undr `expr` by `delim` which can be a regular expression
+
+
+split('',foo) => [f, o, o]
+split('.','foo.bar') => []
+split('\\.','foo.bar') => [foo, bar]
+
+
+### `slice(expr, from, to?)`
+
+extracts a substring, or sublist (based on the type of the result of the expression under expr with
+starting index of `from`, and ending at `to` if provided, or the end, if omitted
+
+
+slice(l(0,1,2,3,4,5), 1, 3) => [1, 2, 3]
+slice('foobar', 0, 1) => 'f'
+slice('foobar', 3) => 'bar'
+slice(range(10), 3, 5) => [3, 4, 5]
+slice(range(10), 5) => [5, 6, 7, 8, 9]
+
+
+### `sort(list), sort(values ...)`
+
+Sorts in the default sortographical order either all arguments, or a list if its the only argument.
+It returns a new sorted list, not affecting the list passed to the argument
+
+sort(3,2,1) => [1, 2, 3]
+sort('a',3,11,1) => [1, 3, 11, 'a']
+list = l(4,3,2,1); sort(list) => [1, 2, 3, 4]
+
+
+### `sort_key(list, key_expr)`
+
+Sorts a copy of the list in the order or keys as defined by the `key_expr` for each element
+
++sort_key([1,3,2],_) => [1, 2, 3] +sort_key([1,3,2],-_) => [3, 2, 1] +sort_key(l(range(10)),rand(1)) => [1, 0, 9, 6, 8, 2, 4, 5, 7, 3] +sort_key(l(range(20)),str(_)) => [0, 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 3, 4, 5, 6, 7, 8, 9] ++ +### `range(to), range(from, to), range(from, to, step)` + +Creates a range of numbers from `from`, no greater/larger than `to`. The `step` parameter dictates not only the +increment size, but also direction (can be negative). The returned value is not a proper list, just the iterator +but if for whatever reason you need a proper list with all items evaluated, use `l(range(to))`. +Primarily to be used in higher order functions + +
+range(10) => [...] +l(range(10)) => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +map(range(10),_*_) => [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] +reduce(range(10),_a+_, 0) => 45 +range(5,10) => [5, 6, 7, 8, 9] +range(20, 10, -2) => [20, 18, 16, 14, 12] ++ +### `element(list, index)(deprecated)` + +Legacy support for older method that worked only on lists. Please use `get(...)` for equivalent support, or `.` +operator. Also previous unique behaviours with `put` on lists has been removed to support all type of +container types. + +## Map operations + +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
+# Minecraft specific API and `scarpet` language add-ons and commands
+
+Here is the gist of the Minecraft related functions. Otherwise the CarpetScript could live without Minecraft.
+
+## Dimension warning
+
+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 `player('all')` function,
+if a player is in the other dimension, calls to entities and blocks around that player would point incorrectly.
+Moreover, running commandblocks in the spawn chunks would mean that commands will always 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, or use `in_dimension(expr)` function.# Blocks / World API
+
+## Specifying blocks
+
+### `block(x, y, z)`, `block(l(x,y,z))`, `block(state)`
+
+Returns either a block from specified location, or block with a specific state (as used by `/setblock` command),
+so allowing for block properties, block entity data etc. Blocks otherwise can be referenced everywhere by its simple
+string name, but its only used in its default state.
+
+
+block('air') => air
+block('iron_trapdoor[half=top]') => iron_trapdoor
+block(0,0,0) == block('bedrock') => 1
+block('hopper[facing=north]{Items:[{Slot:1b,id:"minecraft:slime_ball",Count:16b}]}') => hopper
+
+
+Retrieving a block with `block` function has also a side-effect of evaluating its current state and data.
+So if you use it later it will reflect block state and data of the block that was when block was called, rather than
+when it was used. Block values passed in various places like `scan` functions, etc, are not fully evaluated unless
+its properties are needed. This means that if the block at the location changes before its queried in the program this
+might result in getting the later state, which might not be desired. Consider the following example:
+
+set(10,10,10,'stone'); +scan(10,10,10,0,0,0, b = _); +set(10,10,10,'air'); +print(b); // 'air', block was remembered 'lazily', and evaluated by `print`, when it was already set to air +set(10,10,10,'stone'); +scan(10,10,10,0,0,0, b = block(_)); +set(10,10,10,'air'); +print(b); // 'stone', block was evaluated 'eagerly' but call to `block` ++ +## World Manipulation + +All the functions below can be used with block value, queried with coord triple, or 3-long list. All `pos` in the +functions referenced below refer to either method of passing block position. + +### `set(pos, block, property?, value?, ...)` + +First part of the `set` function is either a coord triple, list of three numbers, or other block with coordinates. +Second part, `block` is either block value as a result of `block()` function string value indicating the block name, +and optional `property - value` pairs for extra block properties. If `block` is specified only by name, then if a +destination block is the same the `set` operation is skipped, otherwise is executed, for other potential extra +properties. + +The returned value is either the block state that has been set, or `false` if block setting was skipped + +
+set(0,5,0,'bedrock') => bedrock
+set(l(0,5,0), 'bedrock') => bedrock
+set(block(0,5,0), 'bedrock') => bedrock
+scan(0,5,0,0,0,0,set(_,'bedrock')) => 1
+set(pos(players()), 'bedrock') => bedrock
+set(0,0,0,'bedrock') => 0 // or 1 in overworlds generated in 1.8 and before
+scan(0,100,0,20,20,20,set(_,'glass'))
+ // filling the area with glass
+scan(0,100,0,20,20,20,set(_,block('glass')))
+ // little bit faster due to internal caching of block state selectors
+b = block('glass'); scan(0,100,0,20,20,20,set(_,b))
+ // yet another option, skips all parsing
+set(x,y,z,'iron_trapdoor') // sets bottom iron trapdoor
+set(x,y,z,'iron_trapdoor[half=top]') // Incorrect. sets bottom iron trapdoor - no parsing of properties
+set(x,y,z,'iron_trapdoor','half','top') // correct - top trapdoor
+set(x,y,z, block('iron_trapdoor[half=top]')) // also correct, block() provides extra parsing
+set(x,y,z,'hopper[facing=north]{Items:[{Slot:1b,id:"minecraft:slime_ball",Count:16b}]}') // extra block data
+
+
+### `without_updates(expr)`
+
+Evaluates subexpression without causing updates when blocks change in the world
+
+Consider following scenario: We would like to generate a bunch of terrain in a flat world following a perling noise
+generator. The following code causes cascading effect as blocks placed on chunk borders will cause other chunks to get
+loaded to full, thus generated:
+
+
+__config() -> m(l('scope', 'global'));
+__on_chunk_generated(x, z) -> (
+ scan(x,0,z,0,0,0,15,15,15,
+ if (perlin(_x/16, _y/8, _z/16) > _y/16,
+ set(_, 'black_stained_glass');
+ )
+ )
+)
+
+
+The following addition resolves this issue, by not allowing block updates pass chunk borders:
+
+
+__config() -> m(l('scope', 'global'));
+__on_chunk_generated(x, z) -> (
+ without_updates(
+ scan(x,0,z,0,0,0,15,15,15,
+ if (perlin(_x/16, _y/8, _z/16) > _y/16,
+ set(_, 'black_stained_glass');
+ )
+ )
+ )
+)
+
+
+### `place_item(item, pos, facing?, sneak?)`
+
+Places a given item in the world like it was placed by a player. Item names are default minecraft item name,
+less the minecraft prefix. Default facing is 'up', but there are other options: 'down', 'north', 'east', 'south',
+'west', but also there are other secondary directions important for placement of blocks like stairs, doors, etc.
+Try experiment with options like 'north-up' which is placed facing north with cursor pointing to the upper part of the
+block, or 'up-north', which means a block placed facing up (player looking down) and placed smidge away of the block
+center towards north. Optional sneak is a boolean indicating if a player would be sneaking while placing the
+block - this option only affects placement of chests and scaffolding at the moment. Returns true if placement was
+successful, false otherwise.
+
+
+place_item('stone',x,y,z) // places a stone block on x,y,z block
+place_item('piston,x,y,z,'down') // places a piston facing down
+place_item('carrot',x,y,z) // attempts to plant a carrot plant. Returns true if could place carrots at that position.
+
+
+### `set_poi(pos, type, occupancy?)`
+
+Sets a Point of Interest (POI) of a specified type with optional custom occupancy. By default new POIs are not occupied.
+If type is `null`, POI at position is removed. In any case, previous POI is also removed. Available POI types are:
+
+* `'unemployed', 'armorer', 'butcher', 'cartographer', 'cleric', 'farmer', 'fisherman', 'fletcher', 'leatherworker', 'librarian', 'mason', 'nitwit', 'shepherd', 'toolsmith', 'weaponsmith', 'home', 'meeting', 'beehive', 'bee_nest', 'nether_portal'`
+
+Interestingly, `unemployed`, and `nitwit` are not used in the game, meaning, they could be used as permanent spatial
+markers for scarpet apps. `meeting` is the only one with increased max occupancy of 32.
+
+### `set_biome(pos, biome_name)`
+
+changes biome at that block position.
+
+### `update(pos)`
+
+Causes a block update at position.
+
+### `block_tick(pos)`
+
+Causes a block to tick at position.
+
+### `random_tick(pos)`
+
+Causes a random tick at position.
+
+### `destroy(pos), destroy(pos, -1), destroy(pos,
+mine(x,y,z) ->
+(
+ p = player();
+ slot = p~'selected_slot';
+ item_tuple = inventory_get(p, slot);
+ if (!item_tuple, destroy(x,y,z,'air'); return()); // empty hand, just break with 'air'
+ l(item, count, tag) = item_tuple;
+ tag_back = destroy(x,y,z, item, tag);
+ if (tag_back == false, // failed to break the item
+ return(tag_back)
+ );
+ if (tag_back == true, // block broke, tool has no tag
+ return(tag_back)
+ );
+ if (tag_back == null, //item broke
+ delete(tag:'Damage');
+ inventory_set(p, slot, count-1, item, tag);
+ return(tag_back)
+ );
+ if (type(tag_back) == 'nbt', // item didn't break, here is the effective nbt
+ inventory_set(p, slot, count, item, tag_back);
+ return(tag_back)
+ );
+ print('How did we get here?');
+)
+
+
+### `harvest(player, pos)`
+
+Causes a block to be harvested by a specified player entity. Honors player item enchantments, as well as damages the
+tool if applicable. If the entity is not a valid player, no block gets destroyed. If a player is not allowed to break
+that block, a block doesn't get destroyed either.
+
+## Block and World querying
+
+### `pos(block), pos(entity)`
+
+Returns a triple of coordinates of a specified block or entity. Technically entities are queried with `query` function
+and the same can be achieved with `query(entity,'pos')`, but for simplicity `pos` allows to pass all positional objects.
+
+
+pos(block(0,5,0)) => l(0,5,0)
+pos(players()) => l(12.3, 45.6, 32.05)
+pos(block('stone')) => Error: Cannot fetch position of an unrealized block
+
+
+### `pos_offset(pos, direction, amount?)`
+
+Returns a coords triple that is offset in a specified `direction` by `amount` of blocks. The default offset amount is
+1 block. To offset into opposite facing, use negative numbers for the `amount`.
+
++pos_offset(block(0,5,0), 'up', 2) => l(0,7,0) +pos_offset(l(0,5,0), 'up', -2 ) => l(0,3,0) ++ +### `block_properties(pos)` + +Returns a list of available block properties for a particular block. If a block has no properties, returns an empty list. + +### `property(pos, name)` + +Returns property of block at `pos`, or specified by `block` argument. If a block doesn't have that property, `null` +value is returned. Returned values are always strings. It is expected from the user to know what to expect and convert +values to numbers using `number()` function or booleans using `bool()` function. + +
+set(x,y,z,'iron_trapdoor','half','top'); property(x,y,z,'half') => top
+set(x,y,z,'air'); property(x,y,z,'half') => null
+property(block('iron_trapdoor[half=top]'),'half') => top
+property(block('iron_trapdoor[half=top]'),'powered') => false
+bool(property(block('iron_trapdoor[half=top]'),'powered')) => 0
+
+
+### `block_data(pos)`
+
+Return NBT string associated with specific location, or null if the block does not carry block data. Can be currently
+used to match specific information from it, or use it to copy to another block
+
+ block_data(x,y,z) => '{TransferCooldown:0,x:450,y:68, ... }'
+
+
+### `poi(pos), poi(pos, radius), poi(pos, radius, status)`
+
+Queries a POI (Point of Interest) at a given position, returning `null` if none is found, or tuple of poi type and its
+occupancy load. With optional `radius` and `status`, returns a list of POIs around `pos` within a given `radius`.
+If `status` is specified (either 'available', or 'occupied') returns only POIs with that status. The return format is
+again, poi type, occupancy load, and extra tripple of coordinates.
+
+Querying for POIs using the radius is intended use of POI mechanics and ability of accessing individual POIs
+via `poi(pos)` in only provided for completness.
+
++poi(x,y,z) => null // nothing set at position +poi(x,y,z) => ['meeting',3] // its a bell-type meeting point occupied by 3 villagers +poi(x,y,z,5) => [] // nothing around +poi(x,y,z,5) => [['nether_portal',0,[7,8,9]],['nether_portal',0,[7,9,9]]] // two portal blocks in the range ++ +### `biome(pos)` + +returns biome at that block position. + +### `solid(pos)` + +Boolean function, true if the block is solid + +### `air(pos)` + +Boolean function, true if a block is air.... or cave air... or void air.... or any other air they come up with. + +### `liquid(pos)` + +Boolean function, true if the block is liquid, or liquidlogged + +### `flammable(pos)` + +Boolean function, true if the block is flammable + +### `transparent(pos)` + +Boolean function, true if the block is transparent + +### `opacity(pos)` + +Numeric, returning opacity level of a block + +### `blocks_daylight(pos)` + +Boolean function, true if the block blocks daylight + +### `emitted_light(pos)` + +Numeric, returning light level emitted from block + +### `light(pos)` + +Integer function, returning total light level at position + +### `block_light(pos)` + +Integer function, returning block light at position. From torches and other light sources. + +### `sky_light(pos)` + +Numeric function, returning sky light at position. From the sky access. + +### `see_sky(pos)` + +Boolean function, returning true if the block can see sky. + +### `hardness(pos)` + +Numeric function, indicating hardness of a block. + +### `blast_resistance(pos)` + +Numeric function, indicating blast_resistance of a block. + +### `in_slime_chunk(pos)` + +Boolean indicating if the given block position is in a slime chunk. + +### `top(type, pos)` + +Returns the Y value of the topmost block at given x, z coords (y value of a block is not important), according to the +heightmap specified by `type`. Valid options are: + +* `light`: topmost light blocking block (1.13 only) +* `motion`: topmost motion blocking block +* `terrain`: topmost motion blocking block except leaves +* `ocean_floor`: topmost non-water block +* `surface`: topmost surface block + +
+top('motion', x, y, z) => 63
+top('ocean_floor', x, y, z) => 41
+
+
+### `loaded(pos)`
+
+Boolean function, true if the block is accessible for the game mechanics. Normally `scarpet` doesn't check if operates
+on loaded area - the game will automatically load missing blocks. We see this as advantage. Vanilla `fill/clone`
+commands only check the specified corners for loadness.
+
+To check if block is truly loaded, I mean in memory, use `generation_status(x) != null`, as chunks can still be loaded
+outside of the playable area, just are not used any of the game mechanics processes.
+
++loaded(pos(players())) => 1 +loaded(100000,100,1000000) => 0 ++ +### `(Deprecated) loaded_ep(pos)` + +Boolean function, true if the block is loaded and entity processing, as per 1.13.2 + +Deprecated as of scarpet 1.6, use `loaded_status(x) > 0`, or just `loaded(x)` with the same effect + +### `loaded_status(pos)` + +Returns loaded status as per new 1.14 chunk ticket system, 0 for inaccessible, 1 for border chunk, 2 for ticking, +3 for entity ticking + +### `generation_status(pos), generation_status(pos, true)` + +Returns generation status as per new 1.14 chunk ticket system. Can return any value from several available but chunks +can only be valid in a few states: `full`, `features`, `liquid_carvers`, and `structure_starts`. Returns `null` +if the chunk is not in memory unless called with optional `true`. + +### `structures(pos), structures(pos, structure_name)` + +Returns structure information for a given block position. Note that structure information is the same for all the +blocks from the same chunk. `structures` function can be called with a block, or a block and a structure name. In +the first case it returns a map of structures at a given position, keyed by structure name, with values indicating +the bounding box of the structure - a pair of two 3-value coords (see examples). When called with an extra structure +name, returns list of components for that structure, with their name, direction and two sets of coordinates +indicating the bounding box of the structure piece. + +### `structure_references(pos), structure_references(pos, structure_name)` + +Returns structure information that a chunk with a given block position is part of. `structure_references` function +can be called with a block, or a block and a structure name. In the first case it returns a list of structure names +that give chunk belongs to. When called with an extra structure name, returns list of positions pointing to the +lowest block position in chunks that hold structure starts for these structures. You can query that chunk structures +then to get its bounding boxes. + +### `set_structure(pos, structure_name), set_structure(pos, structure_name, null)` + +Creates or removes structure information of a structure associated with a chunk of `pos`. Unlike `plop`, blocks are +not placed in the world, only structure information is set. For the game this is a fully functional structure even +if blocks are not set. To remove structure a given point is in, use `structure_references` to find where current +structure starts. + +### `suffocates(pos)` + +Boolean function, true if the block causes suffocation. + +### `power(pos)` + +Numeric function, returning redstone power level at position. + +### `ticks_randomly(pos)` + +Boolean function, true if the block ticks randomly. + +### `blocks_movement(pos)` + +Boolean function, true if block at position blocks movement. + +### `block_sound(pos)` + +Returns the name of sound type made by the block at position. One of: + +* `wood` +* `gravel` +* `grass` +* `stone` +* `metal` +* `glass` +* `wool` +* `sand` +* `snow` +* `ladder` +* `anvil` +* `slime` +* `sea_grass` +* `coral` + +### `material(pos)` + +Returns the name of material of the block at position. very useful to target a group of blocks. One of: + +* `air` +* `void` +* `portal` +* `carpet` +* `plant` +* `water_plant` +* `vine` +* `sea_grass` +* `water` +* `bubble_column` +* `lava` +* `snow_layer` +* `fire` +* `redstone_bits` +* `cobweb` +* `redstone_lamp` +* `clay` +* `dirt` +* `grass` +* `packed_ice` +* `sand` +* `sponge` +* `wood` +* `wool` +* `tnt` +* `leaves` +* `glass` +* `ice` +* `cactus` +* `stone` +* `iron` +* `snow` +* `anvil` +* `barrier` +* `piston` +* `coral` +* `gourd` +* `dragon_egg` +* `cake` + +### `map_colour(pos)` + +Returns the map colour of a block at position. One of: + +* `air` +* `grass` +* `sand` +* `wool` +* `tnt` +* `ice` +* `iron` +* `foliage` +* `snow` +* `clay` +* `dirt` +* `stone` +* `water` +* `wood` +* `quartz` +* `adobe` +* `magenta` +* `light_blue` +* `yellow` +* `lime` +* `pink` +* `gray` +* `light_gray` +* `cyan` +* `purple` +* `blue` +* `brown` +* `green` +* `red` +* `black` +* `gold` +* `diamond` +* `lapis` +* `emerald` +* `obsidian` +* `netherrack` +* `white_terracotta` +* `orange_terracotta` +* `magenta_terracotta` +* `light_blue_terracotta` +* `yellow_terracotta` +* `lime_terracotta` +* `pink_terracotta` +* `gray_terracotta` +* `light_gray_terracotta` +* `cyan_terracotta` +* `purple_terracotta` +* `blue_terracotta` +* `brown_terracotta` +* `green_terracotta` +* `red_terracotta` +* `black_terracotta` +# Iterating over larger areas of blocks + +These functions help scan larger areas of blocks without using generic loop functions, like nested `loop`. + +### `scan(cx, cy, cz, dx, dy, dz, px?, py?, pz?, expr)` + +Evaluates expression over area of blocks defined by its center (`cx, cy, cz`), expanded in all directions +by `dx, dy, dz` blocks, or optionally in negative with `d` coords, and `p` coords in positive values. `expr` +receives `_x, _y, _z` as coords of current analyzed block and `_`, which represents the block itself. + +### `volume(x1, y1, z1, x2, y2, z2, expr)` + +Evaluates expression for each block in the area, the same as the `scan`function, but using two opposite corners of +the rectangular cuboid. Any corners can be specified, its like you would do with `/fill` command. + +### `neighbours(x, y, z), neighbours(block), neighbours(l(x,y,z))` + +Returns the list of 6 neighbouring blocks to the argument. Commonly used with other loop functions like `for`. + +
+for(neighbours(x,y,z),air(_)) => 4 // number of air blocks around a block ++ +### `rect(cx, cy, cz, dx?, dy?, dz?, px?, py?, pz?)` + +returns an iterator, just like `range` function that iterates over rectangular cubarea of blocks. If only center +point is specified, it iterates over 27 blocks. If `d` arguments are specified, expands selection of respective +number of blocks in each direction. If `p` arguments are specified, it uses `d` for negative offset, and `p` for positive. + +### `diamond(cx, cy, cz, radius?, height?)` + +Iterates over a diamond like area of blocks. With no radius and height, its 7 blocks centered around the middle +(block + neighbours). With a radius specified, it expands shape on x and z coords, and with a custom height, on y. +Any of these can be zero as well. radius of 0 makes a stick, height of 0 makes a diamond shape pad. +# Entity API + +## Entity Selection + +Entities have to be fetched before using them. Entities can also change their state between calls to the script if +game happens either in between separate calls to the programs, or if the program calls `game_tick` on its own. +In this case - entities would need to be re-fetched, or the code should account for entities getting dead. + +### `player(), player(type), player(name)` + +With no arguments, it returns the calling player or the player closest to the caller. Note that the main context +will receive `p` variable pointing to this player. With `type` or `name` specified it will try first to match a type, +returning a list of players matching a type, and if this fails, will assume its player name query retuning player with +that name, or `null` if no player was found. With `'all'`, list of all players in the game, in all dimensions, so end +user needs to be cautious, that you might be referring to wrong blocks and entities around the player in question. +With `type = '*'` it returns all players in caller dimension, `'survival'` returns all survival and adventure players, +`'creative'` returns all creative players, `'spectating'` returns all spectating players, and `'!spectating'`, +all not-spectating players. If all fails, with `name`, the player in question, if is logged in. + +### `entity_id(uuid), entity_id(id)` + +Fetching entities wither by their ID obtained via `entity ~ 'id'`, which is unique for a dimension and current world +run, or by UUID, obtained via `entity ~ 'uuid'`. It returns null if no such entity is found. Safer way to 'store' +entities between calls, as missing entities will be returning `null`. Both calls using UUID or numerical ID are `O(1)`, +but obviously using UUIDs takes more memory and compute. + +### `entity_list(type)` + +Returns global lists of entities in the current dimension of a specified type. Currently the following +selectors are available: + +* `*`: all entites +* `living` +* `items` +* `players` +* `!players` + +### `entity_area(type, cx, cy, cz, dx, dy, dz)` + +Returns entities of a specified type in an area centered on `cx, cy, cz` and at most `dx, dy, dz` blocks away from +the center point. Uses same selectors as `entities_list` + +### `entity_selector(selector)` + +Returns entities satisfying given vanilla entity selector. Most complex among all the methods of selecting entities, +but the most capable. Selectors are cached so should be as fast as other methods of selecting entities. + +### `spawn(name, pos, nbt?)` + +Spawns and places an entity in world, like `/summon` vanilla command. Requires a position to spawn, and optional +extra nbt data to merge with the entity. What makes it different from calling `run('summon ...')`, is the fact that +you get the entity back as a return value, which is swell. + +## Entity Manipulation + +Unlike with blocks, that use plethora of vastly different querying functions, entities are queried with `query` +function and altered via `modify` function. Type of information needed or values to be modified are different for +each call. + +Using `~` (in) operator is an alias for `query`. Especially useful if a statement has no arguments, +which in this case can be radically simplified + +
+query(p, 'name') <=> p ~ 'name' // much shorter and cleaner
+query(p, 'holds', 'offhand') <=> p ~ l('holds', 'offhand') // not really but can be done
+
+
+### `query(e,'removed')`
+
+Boolean. True if the entity is removed
+
+### `query(e,'id')`
+
+Returns numerical id of the entity. Most efficient way to keep track of entites in a script.
+Ids are only unique within current game session (ids are not preserved between restarts),
+and dimension (each dimension has its own ids which can overlap.
+
+### `query(e,'uuid')`
+
+Returns UUID (unique id) of the entity. Can be used to access entities with the other vanilla commands and
+remains unique regardless of the dimension, and is preserved between game restarts. Apparently players cannot be
+accessed via UUID, but name instead.
+
+
+map(entities_area('*',x,y,z,30,30,30),run('kill '+query(_,'id'))) // doesn't kill the player
+
+
+### `query(e,'pos')`
+
+Triple of entity position
+
+### `query(e,'location')`
+
+Quin-tuple of entity position (x, y, and z coords), and rotation (yaw, pitch)
+
+### `query(e,'x'), query(e,'y'), query(e,'z')`
+
+Respective entity coordinate
+
+### `query(e,'pitch'), query(e,'yaw')`
+
+Pitch and Yaw or where entity is looking.
+
+### `query(e,'look')`
+
+Returns a 3d vector where the entity is looking.
+
+### `query(e,'motion')`
+
+Triple of entity motion vector, `l(motion_x, motion_y, motion_z)`
+
+### `query(e,'motion_x'), query(e,'motion_y'), query(e,'motion_z')`
+
+Respective component of the motion vector
+
+### `query(e,'name'), query(e,'custom_name'), query(e,'type')`
+
+String of entity name
+
+query(e,'name') => Leatherworker +query(e,'custom_name') => null +query(e,'type') => villager ++ +### `query(e,'is_riding')` + +Boolean. True if riding another entity. + +### `query(e,'is_ridden')` + +Boolean. True if another entity is riding it. + +### `query(e,'passengers')` + +List of entities riding the entity. + +### `query(e,'mount')` + +Entity that `e` rides. + +### `query(e,'tags')` + +List of entity tags. + +### `query(e,'has_tags',tag)` + +Boolean, True if the entity is marked with `tag`. + +### `query(e,'is_burning')` + +Boolean, True if the entity is burning. + +### `query(e,'fire')` + +Number of remaining ticks of being on fire. + +### `query(e,'silent')` + +Boolean, True if the entity is silent. + +### `query(e,'gravity')` + +Boolean, True if the entity is affected by gravity, like most entities do. + +### `query(e,'immune_to_fire')` + +Boolean, True if the entity is immune to fire. + +### `query(e,'dimension')` + +Name of the dimension entity is in. + +### `query(e,'height')` + +Height of the entity. + +### `query(e,'width')` + +Width of the entity. + +### `query(e,'eye_height')` + +Eye height of the entity. + +### `query(e,'age')` + +Age, in ticks, of the entity, i.e. how long it existed. + +### `query(e,'breeding_age')` + +Breeding age of passive entity, in ticks. If negative it it time to adulthood, if positive, breeding cooldown + +### `query(e,'despawn_timer')` + +For living entities - the number of ticks they fall outside of immediate player presence. + +### `query(e,'item')` + +The item triple (name, count, nbt) if its an item entity, `null` otherwise + +### `query(e,'count')` + +Number of items in a stack from item entity, `null` otherwise + +### `query(e,'pickup_delay')` + +Retrieves pickup delay timeout for an item entity, `null` otherwise + +### `query(e,'is_baby')` + +Boolean, true if its a baby. + +### `query(e,'target')` + +Returns mob's attack target or null if none or not applicable. + +### `query(e,'home')` + +Returns creature's home position or null if none or not applicable. + +### `query(e,'sneaking')` + +Boolean, true if entity is sneaking. + +### `query(e,'sprinting')` + +Boolean, true if entity is sprinting. + +### `query(e,'swimming')` + +Boolean, true if entity is swimming. + +### `query(e,'jumping')` + +Boolean, true if entity is jumping. + +### `query(e,'gamemode')` + +String with gamemode, or `null` if not a player. + +### `query(e,'gamemode_id')` + +Good'ol gamemode id, or null if not a player. + +### `query(e,'player_type')` + +Returns `null` if the argument is not a player, otherwise: + +* `singleplayer`: for singleplayer game +* `multiplayer`: for players on a dedicated server +* `lan_host`: for singleplayer owner that opened the game to LAN +* `lan_player`: for all other players that connected to a LAN host +* `fake`: any carpet-spanwed fake player +* `shadow`: any carpet-shadowed real player +* `realms`: ? + +### `query(e,'permission_level')` + +Player's permission level, or `null` if not applicable for this entity. + +### `query(e,'effect',name?)` + +Without extra arguments, it returns list of effect active on a living entity. Each entry is a triple of short +effect name, amplifier, and remaining duration. With an argument, if the living entity has not that potion active, +returns `null`, otherwise return a tuple of amplifier and remaining duration. + +
+query(p,'effect') => [[haste, 0, 177], [speed, 0, 177]] +query(p,'effect','haste') => [0, 177] +query(p,'effect','resistance') => null ++ +### `query(e,'health')` + +Number indicating remaining entity health, or `null` if not applicable. + +### `query(e,'holds',slot?)` + +Returns triple of short name, stack count, and NBT of item held in `slot`. Available options for `slot` are: + +* `mainhand` +* `offhand` +* `head` +* `chest` +* `legs` +* `feet` + +If `slot` is not specified, it defaults to the main hand. + +### `query(e,'selected_slot')` + +Number indicating the selected slot of entity inventory. Currently only applicable to players. + +### `query(e,'facing', order?)` + +Returns where the entity is facing. optional order (number from 0 to 5, and negative), indicating primary directions +where entity is looking at. From most prominent (order 0) to opposite (order 5, or -1) + +### `query(e,'trace', reach?, options?...)` + +Returns the result of ray tracing from entity perspective, indicating what it is looking at. Default reach is 4.5 +blocks (5 for creative players), and by default it traces for blocks and entities, identical to player attack tracing +action. This can be customized with `options`, use 'blocks' to trace for blocks, 'liquids' to include liquid blocks +as possible results, and 'entities' to trace entities. Any combination of the above is possible. When tracing +entities and blocks, blocks will take over the priority even if transparent or non-colliding +(aka fighting chickens in tall grass). + +Regardless of the options selected, the result could be `null` if nothing is in reach, entity, if look targets an +entity, and block value if block is in reach. + +### `query(e,'nbt',path?)` + +Returns full NBT of the entity. If path is specified, it fetches only that portion of the NBT, that corresponds to the +path. For specification of `path` attribute, consult vanilla `/data get entity` command. + +Note that calls to `nbt` are considerably more expensive comparing to other calls in Minecraft API, and should only +be used when there is no other option. Returned value is of type `nbt`, which can be further manipulated with nbt +type objects via `get, put, has, delete`, so try to use API calls first for that. + +## Entity Modification + +Like with entity querying, entity modifications happen through one function. Most position and movements modifications +don't work currently on players as their position is controlled by clients. + +Currently there is no ability to modify NBT directly, but you could always use `run('data modify entity` + +### `modify(e,'remove')` + +Removes (not kills) entity from the game. + +### `modify(e,'kill')` + +Kills the entity. + +### `modify(e, 'pos', x, y, z), modify(e, 'pos', l(x,y,z) )` + +Moves the entity to a specified coords. + +### `modify(e, 'location', x, y, z, yaw, pitch), modify(e, 'location', l(x, y, z, yaw, pitch) )` + +Changes full location vector all at once. + +### `modify(e, 'x', x), modify(e, 'y', y), modify(e, 'z', z)` + +Moves the entity in.... one direction. + +### `modify(e, 'pitch', pitch), modify(e, 'yaw', yaw)` + +Changes entity's pitch or yaw. + +### `modify(e, 'move', x, y, z), modify(e, 'move', l(x,y,z) )` + +Moves the entity by a vector from its current location. + +### `modify(e, 'motion', x, y, z), modify(e, 'motion', l(x,y,z) )` + +Sets the motion vector (where and how much entity is moving). + +### `modify(e, 'motion_z', x), modify(e, 'motion_y', y), modify(e, 'motion_z', z)` + +Sets the corresponding component of the motion vector. + +### `modify(e, 'accelerate', x, y, z), modify(e, 'accelerate', l(x, y, z) )` + +Adds a vector to the motion vector. Most realistic way to apply a force to an entity. + +### `modify(e, 'custom_name'), modify(e, 'custom_name', name )` + +### `modify(e, 'age', number)` + +Modifies entity's internal age counter. Fiddling with this will affect directly behaviours of complex +entities, so use it with caution. + +### `modify(e, 'pickup_delay', number)` + +### `modify(e, 'breeding_age', number)` + +### `modify(e, 'despawn_timer', number)` + +Sets a custom despawn timer value. + +### `modify(e, 'dismount')` + +Dismounts riding entity. + +### `modify(e, 'mount', other)` + +Mounts the entity to the `other`. + +### `modify(e, 'drop_passengers')` + +Shakes off all passengers. + +### `modify(e, 'mount_passengers', passenger, ? ...), modify(e, 'mount_passengers', l(passengers) )` + +Mounts on all listed entities on `e`. + +### `modify(e, 'tag', tag, ? ...), modify(e, 'tag', l(tags) )` + +Adds tag / tags to the entity. + +### `modify(e, 'clear_tag', tag, ? ...), modify(e, 'clear_tag', l(tags) )` + +Removes tag from entity. + +### `modify(e, 'talk')` + +Make noises. + +### `modify(e, 'ai', boolean)` + +If called with `false` value, it will disable AI in the mob. `true` will enable it again. + +### `modify(e, 'no_clip', boolean)` + +Sets if the entity obeys any collisions, including collisions with the terrain and basic physics. Not affecting +players, since they are controlled client side + +### `modify(e, 'effect', name, duration?, amplifier?, show_particles?, show_icon?)` + +Applies status effect to the living entity. Takes several optional parameters, which default to `0`, `true` +and `true`. If no duration is specified, or it is null or 0, the effect is removed. + +### `modify(e, 'home', null), modify(e, 'home', block, distance?), modify(e, 'home', x, y, z, distance?)` + +Sets AI to stay around the home position, within `distance` blocks from it. `distance` defaults to 16 blocks. +`null` removes it. _May_ not work fully with mobs that have this AI built in, like Villagers. + +## Entity Events + +There is a number of events that happen to entities that you can attach your own code to in the form of event handlers. +The event handler is any function that runs in your package that accepts certain expected parameters, which you can +expand with your own arguments. When it comes to the moment when the given command needs to be executed, it does so +providing that number of arguments it accepts is equal number of event arguments, and extra arguments passed when +defining the callback with `entity_event` + +The following events can be handled by entities. + +* `'on_tick'`: executes every tick right before entity is ticked in the game. Required arguments: `entity` +* `'on_death'`: executes once when a living entity dies. Required arguments: `entity, reason` +* `'on_removed'`: execute once when an entity is removed. Required arguments: `entity` +* `'on_damaged'`: executed every time a living entity is about to receive damage. +Required arguments: `entity, amount, source, attacking_entity` + +It doesn't mean that all entity types will have a chance to execute a given event, but entities will not error +when you will attach inapplicable event to it. + +### `entity_event(e, event, call_name, args...)` + +Attaches specific function from the current package to be called upon the `event`, with extra `args` curried to the +original required arguments for the event handler + +
+protect_villager(entity, amount, source, source_entity, healing_player) ->
+(
+ if(source_entity && source_entity~'type' != 'player',
+ modify(entity, 'health', amount + entity~'health' );
+ particle('end_rod', pos(entity)+l(0,3,0));
+ print(str('%s healed thanks to %s', entity, healing_player))
+ )
+);
+__on_player_interacts_with_entity(player, entity, hand) ->
+(
+ if (entity~'type' == 'villager',
+ entity_event(entity, 'on_damage', 'protect_villager', player~'name')
+ )
+)
+
+
+In this case this will protect a villager from entity damage (zombies, etc.) except players by granting all the
+health back to the villager after being harmed.
+# Inventory and Items API
+
+## Manipulating inventories of blocks and entities
+
+Most functions in this category require inventory as the first argument. Inventory could be specified by an entity,
+or a block, or position (three coordinates) of a potential block with inventory. Player enderchest inventory require
+two arguments, keyword `'enderchest'`, followed by the player entity argument. If the entity or a block doesn't have
+an inventory, they typically do nothing and return null.
+
+Most items returned are in the form of a triple of item name, count, and nbt or the extra data associated with an item.
+Manipulating of the nbt data can be costly, but retrieving them from the tuple to match other aspects is cheap
+
+### `stack_limit(item)`
+
+Returns number indicating what is the stack limit for the item. Its typically 1 (non-stackable), 16 (like buckets),
+or 64 - rest. It is recommended to consult this, as other inventory API functions ignore normal stack limits, and
+it is up to the programmer to keep it at bay. As of 1.13, game checks for negative numbers and setting an item to
+negative is the same as empty.
+
+
+stack_limit('wooden_axe') => 1
+stack_limit('ender_pearl') => 16
+stack_limit('stone') => 64
+
+
+### `item_category(item)`
+
+Returns the string representing the category of a given item, like `building_blocks`, `combat`, or `tools`.
+
+
+item_category('wooden_axe') => tools
+item_category('ender_pearl') => misc
+item_category('stone') => building_blocks
+
+
+### `inventory_size(inventory)`
+
+Returns the size of the inventory for the entity or block in question. Returns null if the block or entity don't
+have an inventory
+
+
+inventory_size(player()) => 41
+inventory_size('enderchest', player()) => 27 // enderchest
+inventory_size(x,y,z) => 27 // chest
+inventory_size(block(pos)) => 5 // hopper
+
+
+### `inventory_has_items(inventory)`
+
+Returns true, if the inventory is not empty, false if it is empty, and null, if its not an inventory.
+
+inventory_has_items(player()) => true + inventory_has_items(x,y,z) => false // empty chest + inventory_has_items(block(pos)) => null // stone ++ +### `inventory_get(inventory, slot)` + +Returns the item in the corresponding inventory slot, or null if slot empty or inventory is invalid. You can use +negative numbers to indicate slots counted from 'the back'. + +
+inventory_get(player(), 0) => null // nothing in first hotbar slot
+inventory_get(x,y,z, 5) => ['stone', 1, {}]
+inventory_get(player(), -1) => ['diamond_pickaxe', 1, {Damage:4}] // slightly damaged diamond pick in the offhand
+
+
+### `inventory_set(inventory, slot, count, item?, nbt?)`
+
+Modifies or sets a stack in inventory. specify count 0 to empty the slot. If item is not specified, keeps existing
+item, just modifies the count. If item is provided - replaces current item. If nbt is provided - adds a tag to the
+stack at slot. Returns previous stack in that slot.
+
+
+inventory_set(player(), 0, 0) => ['stone', 64, {}] // player had a stack of stone in first hotbar slot
+inventory_set(player(), 0, 6) => ['diamond', 64, {}] // changed stack of diamonds in player slot to 6
+inventory_set(player(), 0, 1, 'diamond_axe','{Damage:5}') => null //added slightly damaged pick to first player slot
+
+
+### `inventory_find(inventory, item, start_slot?, ), inventory_find(inventory, null, start_slot?)`
+
+Finds the first slot with a corresponding item in the inventory, or if queried with null: the first empty slot.
+Returns slot number if found, or null otherwise. Optional start_slot argument allows to skip all preceeding slots
+allowing for efficient (so not slot-by-slot) inventory search for items.
+
++inventory_find(player(), 'stone') => 0 // player has stone in first hotbar slot +inventory_find(player(), null) => null // player's inventory has no empty spot +while( (slot = inventory_find(p, 'diamond', slot)) != null, 41, drop_item(p, slot) ) + // spits all diamonds from player inventory wherever they are +inventory_drop(x,y,z, 0) => 64 // removed and spawned in the world a full stack of items ++ +### `inventory_remove(inventory, item, amount?)` + +Removes amount (defaults to 1) of item from inventory. If the inventory doesn't have the defined amount, nothing +happens, otherwise the given amount of items is removed wherever they are in the inventory. Returns boolean +whether the removal operation was successful. Easiest way to remove a specific item from player inventory +without specifying the slot. + +
+inventory_remove(player(), 'diamond') => 1 // removed diamond from player inventory +inventory_remove(player(), 'diamond', 100) => 0 // player doesn't have 100 diamonds, nothing happened ++ +### `drop_item(inventory, slot, amount?, )` + +Drops the items from indicated inventory slot, like player that Q's an item or villager, that exchanges food. +You can Q items from block inventories as well. default amount is 0 - which is all from the slot. +NOTE: hoppers are quick enough to pick all the queued items from their inventory anyways. +Returns size of the actual dropped items. + +
+inventory_drop(player(), 0, 1) => 1 // Q's one item on the ground +inventory_drop(x,y,z, 0) => 64 // removed and spawned in the world a full stack of items ++# Scarpet events system + +Provides the ability to execute specific function whenever an event occurs. The functions to be registered need to +conform with the arguments to the event specification. When loading module functions, each function that starts +with `__on_...` and has the required arguments, will be bound automatically. In case of player specific modules, +all player action events will be directed to the appropriate player space, and all tick events will be executed in +the global context, so its not a good idea to mix these two, so use either of these, or use commands to call tick +events directly, or handle player specific data inside a module. In near future using global events +(on_tick, on_chunk_generated) will be not allowed in player scoped apps. + +### Event list + +Here is a list of events that can be handled by scarpet. This list includes prefixes required by modules to autoload +them, but you can add any function to any event if it accepts required number of parameters: + +
+__on_tick() // can access blocks and entities in the overworld +__on_tick_nether() // can access blocks and entities in the nether +__on_tick_ender() // can access blocks and entities in the end +__on_chunk_generated(x,z) // called after a chunk is promoted to the full chunk, + // prodiving lowest x and z coords in the chunk + // event will not work with optifine installed in the game +// player specific callbacks +__on_player_uses_item(player, item_tuple, hand) // right click action +__on_player_releases_item(player, item_tuple, hand) // client action (e.g. bow) +__on_player_finishes_using_item(player, item_tuple, hand)) // server action (e.g. food), called item is from before it is used. +__on_player_clicks_block(player, block, face) // left click attack on a block +__on_player_breaks_block(player, block) // called after block is broken (the caller receives previous blockstate) +__on_player_right_clicks_block(player, item_tuple, hand, block, face, hitvec) // player right clicks block with anything +__on_player_interacts_with_block(player, hand, block, face, hitvec) //right click on a block resulted in activation of said block +__on_player_places_block(player, item_tuple, hand, block) // player have just placed the block. +__on_player_interacts_with_entity(player, entity, hand) +__on_player_attacks_entity(player, entity) +__on_player_rides(player, forward, strafe, jumping, sneaking) +__on_player_jumps(player) +__on_player_deploys_elytra(player) +__on_player_wakes_up(player) +__on_player_starts_sneaking(player) +__on_player_stops_sneaking(player) +__on_player_starts_sprinting(player) +__on_player_stops_sprinting(player) +__on_player_drops_item(player) +__on_player_drops_stack(player) +__on_statistic(player, category, event, value) // player statistic changes ++ +### `/script event` command + +used to display current events and bounded functions. use `add_to` ro register new event, or `remove_from` to +unbind a specific function from an event. Function to be bounded to an event needs to have the same number of +parameters as the action is attempting to bind to (see list above). All calls in modules loaded via `/script load` +that have functions listed above will be automatically bounded and unbounded when script is unloaded. +# Auxiliary aspects + +Collection of other methods that control smaller, yet still important aspects of the game + +## Sounds + +### `sound(name, pos, volume?, pitch?)` + +Plays a specific sound `name`, at block or position `pos`, with optional `volume` and modified `pitch`. `pos` can be +either a block, triple of coords, or a list of thee numbers. Uses the same options as a corresponding `playsound` command. + +## Particles + +### `particle(name, pos, count?. spread?, speed?, playername?)` + +Renders a cloud of particles `name` centered around `pos` position, by default `count` 10 of them, default `speed` +of 0, and to all players nearby, but these options can be changed via optional arguments. Follow vanilla `/particle` +command on details on those options. Valid particle names are +for example `'angry_villager', 'item diamond', 'block stone', 'dust 0.8 0.1 0.1 4'`. + +### `particle_line(name, pos, pos2, density?)` + +Renders a line of particles from point `pos` to `pos2` with supplied density (defaults to 1), which indicates how far +apart you would want particles to appear, so `0.1` means one every 10cm. + +### `particle_rect(name, pos, pos2, density?)` + +Renders a cuboid of particles between point `pos` to `pos2` with supplied density. + +## Markers + +### `create_marker(text, pos, rotation?, block?)` + +Spawns a (permanent) marker entity with text or block at position. Returns that entity for further manipulations. +Unloading the app that spawned them will cause all the markers from the loaded portion of the world to be removed. +Also - if the game loads that marker in the future and the app is not loaded, it will be removed as well. + +### `remove_all_markers()` + +Removes all scarpet markers from the loaded portion of the world created by this app, in case you didn't want to do + the proper cleanup. + +## System 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. + +### `escape_nbt(expr)` + +Excapes all the special characters in the string or nbt tag and returns a string that can be stored in nbt directly +as a string value. + +### `print(expr)` + +Displays the result of the expression to the chat. Overrides default `scarpet` behaviour of sending everyting to stderr. + +### `logger(expr)` + +Prints the message to system logs, and not to chat. + +### `run(expr)` + +Runs a vanilla command from the string result of the `expr` and returns its success count + +
+run('fill 1 1 1 10 10 10 air') -> 123 // 123 block were filled, this operation was successful 123 times out of a possible 1000 blocks volume
+run('give @s stone 4') -> 1 // this operation was successful once
+
+
+### `save()`
+
+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.
+
+### `load_app_data(), load_app_data(file)`
+
+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
+scripts folder.
+
+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)`
+
+Stores the app data associated with the app from the world /scripts folder. With the `file` parameter saves
+immediately and with every call, without `file` parameter, it may take up to 10 seconds for the output file
+to sync preventing flickering in case this tag changes frequently. It will be synced when server closes.
+
+### `tick_time()`
+
+Returns game tick counter. Can be used to run certain operations every n-th ticks, or to count in-game time
+
+### `game_tick(mstime?)`
+
+Causes game to run for one tick. By default runs it and returns control to the program, but can optionally
+accept expected tick length, in milliseconds. You can't use it to permanently change the game speed, but setting
+longer commands with custom tick speeds can be interrupted via `/script stop` command
+
++loop(1000,game_tick()) // runs the game as fast as it can for 1000 ticks +loop(1000,game_tick(100)) // runs the game twice as slow for 1000 ticks ++ +### `seed()` + +Returns current world seed. + +### `current_dimension()` + +Returns current dimension that the script runs in. + +### `in_dimension(smth, expr)` + +Evaluates the expression `expr` with different dimension execution context. `smth` can be an entity, +world-localized block, so not `block('stone')`, or a string representing a dimension like: + `'nether'`, `'the_nether'`, `'end'` or `'overworld'`, etc. + +### `schedule(delay, function, args...)` + +Schedules a user defined function to run with a specified `delay` ticks of delay. Scheduled functions run at the end +of the tick, and they will run in order they were scheduled. + +### `statistic(player, category, entry)` + +Queries in-game statistics for certain values. Categories include: + +* `mined`: blocks mined +* `crafted`: items crafted +* `used`: items used +* `broken`: items broken +* `picked_up`: items picked up +* `dropped`: items dropped +* `killed`: mobs killed +* `killed_by`: blocks mined +* `custom`: various random stats + +For the options of `entry`, consult your statistics page, or give it a guess. + +The call will return `null` if the statistics options are incorrect, or player didn't get these in their history. +If the player encountered the statistic, or game created for him empty one, it will return a number. +Scarpet will not affect the entries of the statistics, even if it is just creating empty ones. With `null` response +it could either mean your input is wrong, or statistic has effectively a value of `0`. + +### `plop(pos, what)` + +Plops a structure or a feature at a given `pos`, so block, triple position coordinates or a list of coordinates. +To `what` gets plopped and exactly where it often depends on the feature or structure itself. For example, all +structures are chunk aligned, and often span multiple chunks. Repeated calls to plop a structure in the same chunk +would result either in the same structure generated on top of each other, or with different state, but same position. +Most structures generate at specific altitudes, which are hardcoded, or with certain blocks around them. API will +cancel all extra position / biome / random requirements for structure / feature placement, but some hardcoded +limitations may still cause some of structures/features not to place. Some features require special blocks to be +present, like coral -> water or ice spikes -> snow block, and for some features, like fossils, placement is all sorts +of messed up. This can be partially avoided for structures by setting their structure information via `set_structure`, +which sets it without looking into world blocks, and then use `plop` to fill it with blocks. This may, or may not work. + +All generated structures will retain their properties, like mob spawning, however in many cases the world / dimension +itself has certain rules to spawn mobs, like plopping a nether fortress in the overworld will not spawn nether mobs, +because nether mobs can spawn only in the nether, but plopped in the nether - will behave like a valid nether fortress. + +`plop` will not use world random number generator to generate structures and features, but its own. This has a benefit +that they will generate properly randomly, not the same time every time. + +Structure list: + +* `monument`: Ocean Monument. Generates at fixed Y coordinate, surrounds itself with water. +* `fortress`: Nether Fortress. Altitude varies, but its bounded by the code. +* `mansion`: Woodland Mansion +* `jungle_temple`: Jungle Temple +* `desert_temple`: Desert Temple. Generates at fixed Y altitude. +* `end_city`: End City with Shulkers +* `igloo`: Igloo +* `shipwreck`: Shipwreck, version1? +* `shipwreck2`: Shipwreck, version2? +* `witch_hut` +* `ocean_ruin`, `ocean_ruin_small`, `ocean_ruin_tall`: Stone variants of ocean ruins. +* `ocean_ruin_warm`, `ocean_ruin_warm_small`, `ocean_ruin_warm_tall`: Sandstone variants of ocean ruins. +* `treasure`: A treasure chest. Yes, its a whole structure. +* `pillager_outpost`: A pillager outpost. +* `mineshaft`: A mineshaft. +* `mineshaft_mesa`: A Mesa (Badlands) version of a mineshaft. +* `village`: Plains, oak village. +* `village_desert`: Desert, sandstone village. +* `village_savanna`: Savanna, acacia village. +* `village_taiga`: Taiga, spruce village. +* `village_snowy`: Resolute, Canada. + +Feature list: + +* `oak` +* `oak_beehive`: oak with a hive (1.15+). +* `oak_large`: oak with branches. +* `oak_large_beehive`: oak with branches and a beehive (1.15+). +* `birch` +* `birch_large`: tall variant of birch tree. +* `shrub`: low bushes that grow in jungles. +* `shrub_acacia`: low bush but configured with acacia (1.14 only) +* `shrub_snowy`: low bush with white blocks (1.14 only) +* `jungle`: a tree +* `jungle_large`: 2x2 jungle tree +* `spruce` +* `spruce_large`: 2x2 spruce tree +* `pine`: spruce with minimal leafage (1.15+) +* `pine_large`: 2x2 spruce with minimal leafage (1.15+) +* `spruce_matchstick`: see 1.15 pine (1.14 only). +* `spruce_matchstick_large`: see 1.15 pine_large (1.14 only). +* `dark_oak` +* `acacia` +* `oak_swamp`: oak with more leaves and vines. +* `well`: desert well +* `grass`: a few spots of tall grass +* `grass_jungle`: little bushier grass feature (1.14 only) +* `lush_grass`: grass with patchy ferns (1.15+) +* `tall_grass`: 2-high grass patch (1.15+) +* `fern`: a few random 2-high ferns +* `cactus`: random cacti +* `dead_bush`: a few random dead bushi +* `fossils`: underground fossils, placement little wonky +* `mushroom_brown`: large brown mushroom. +* `mushroom_red`: large red mushroom. +* `ice_spike`: ice spike. Require snow block below to place. +* `glowstone`: glowstone cluster. Required netherrack above it. +* `melon`: a patch of melons +* `melon_pile`: a pile of melons (1.15+) +* `pumpkin`: a patch of pumpkins +* `pumpkin_pile`: a pile of pumpkins (1.15+) +* `sugarcane` +* `lilypad` +* `dungeon`: Dungeon. These are hard to place, and fail often. +* `iceberg`: Iceberg. Generate at sea level. +* `iceberg_blue`: Blue ice iceberg. +* `lake` +* `lava_lake` +* `end_island` +* `chorus`: Chorus plant. Require endstone to place. +* `sea_grass`: a patch of sea grass. Require water. +* `sea_grass_river`: a variant. +* `kelp` +* `coral_tree, coral_mushroom, coral_claw`: various coral types, random color. +* `coral`: random coral structure. Require water to spawn. +* `sea_pickle` +* `boulder`: A rocky, mossy formation from a giant taiga biome. Doesn't update client properly, needs relogging. +# `/script run` command + +Primary way to input commands. The command executes in the context, position, and dimension of the executing player, +commandblock, etc... The command receives 4 variables, `x`, `y`, `z` and `p` indicating position and +the executing entity of the command. You will receive tab completion suggestions as you type your code suggesting +functions and global variables. It is advisable to use `/execute in ... at ... as ... run script run ...` or similar, +to simulate running commands in a different scope. + +# `/script load / unload
+foo = 1; +//This is a comment +bar = 2; +// This never worked, so I commented it out +// baz = foo() ++ +### `/script load/unload
+/script run example_function(const, phrase, price) -> print(const+' '+phrase+' '+price) +/script invoke example_function pi costs 5 ++ +### `/script invokepoint
+/script outline 0 100 0 -40 60 -40 40 140 40 "x*x+y*y+z*z < 32*32" white_stained_glass replace air +/script outline 0 100 0 -40 60 -40 40 140 40 "x*x+y*y+z*z <= 32*32" white_stained_glass replace air +/script outline 0 100 0 -40 60 -40 40 140 40 "x*x+y*y+z*z < 32.5*32.5" white_stained_glass replace air +/script fill 0 100 0 -40 60 -40 40 140 40 "floor(sqrt(x*x+y*y+z*z)) == 32" white_stained_glass replace air +/script fill 0 100 0 -40 60 -40 40 140 40 "round(sqrt(x*x+y*y+z*z)) == 32" white_stained_glass replace air +/script fill 0 100 0 -40 60 -40 40 140 40 "ceil(sqrt(x*x+y*y+z*z)) == 32" white_stained_glass replace air +/draw sphere 0 100 0 32 white_stained_glass replace air // fluffy ball round(sqrt(x*x+y*y+z*z)-rand(abs(y)))==32 ++ +The last method is the one that world edit is using (part of carpet mod). It turns out that the outline method +with `32.5` radius, fill method with `round` function and draw command are equivalent + +# `script stop/script resume` command + +`/script stop` allows to stop execution of any script currently running that calls the `game_tick()` function which +allows the game loop to regain control of the game and process other commands. This will also make sure that all +current and future programs will stop their execution. Execution of all programs will be prevented +until `/script resume` command is called. + +Lets look at the following example. This is a program computes Fibonacci number in a recursive manner: + +
+fib(n) -> if(n<3, 1, fib(n-1)+fib(n-2) ); fib(8) ++ +That's really bad way of doing it, because the higher number we need to compute the compute requirements will +rise exponentially with `n`. It takes a little over 50 milliseconds to do fib(24), so above one tick, but about +a minute to do fib(40). Calling fib(40) will not only freeze the game, but also you woudn't be able to interrupt +its execution. We can modify the script as follows + +
+fib(n) -> ( game_tick(50); if(n<3, 1, fib(n-1)+fib(n-2) ) ); fib(40) ++ +But this would never finish as such call would finish after `~ 2^40` ticks. To make our computations responsive, +yet able to respond to user interactions, other commands, as well as interrupt execution, we could do the following: + +
+fib(n) -> ( if(n==23, game_tick(50) ); if(n<3, 1, fib(n-1)+fib(n-2) ) ); fib(40) ++ +This would slow down the computation of fib(40) from a minute to two, but allows the game to keep continue running +and be responsive to commands, using about half of each tick to advance the computation. Obviously depending on the +problem, and available hardware, certain things can take more or less time to execute, so portioning of work with +calling `gametick` should be balanced in each case separately diff --git a/mergedoc.bat b/mergedoc.bat new file mode 100644 index 00000000..ad269be7 --- /dev/null +++ b/mergedoc.bat @@ -0,0 +1,2 @@ +cat docs/scarpet/language/Overview.md docs/scarpet/language/VariablesAndConstants.md docs/scarpet/language/Operators.md docs/scarpet/language/Math.md docs/scarpet/language/SystemFunctions.md docs/scarpet/language/LoopsAndHigherOrderFunctions.md docs/scarpet/language/FunctionsAndControlFlow.md docs/scarpet/language/Containers.md docs/scarpet/api/Overview.md docs/scarpet/api/BlocksAndWorldAccess.md docs/scarpet/api/BlockIterations.md docs/scarpet/api/Entities.md docs/scarpet/api/Inventories.md docs/scarpet/api/Events.md docs/scarpet/api/Auxiliary.md docs/scarpet/api/ScriptCommand.md > docs/scarpet/Full.md +