Merge branch 'master' into scoreboard-criterion-mod

This commit is contained in:
replaceitem authored and GitHub committed 2020-12-16 20:40:29 +01:00
commit 6bb7eb2ae2
63 files changed
+2386 -797

No files matched your search

+347 -165
View File
@@ -151,9 +151,10 @@ 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
your code in apps (files with `.sc` extension that can be placed inside `/scripts` folder in the world files
or as a globally available app in singleplayer in the `.minecraft/config/carpet/scripts` folder and loaded
as a Scarpet app with the 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
@@ -803,6 +804,9 @@ a = 3; task_thread('temp', _(outer(a), b) -> foo(a,b), 5)
=> Another example of running the same thing passing arguments using closure over anonymous function as well as passing a parameter.
</pre>
In case you want to create a task based on a function that is not defined in your module, please read the tips on
"Passing function references to other modules of your application" section in the `call(...)` section.
### `sleep()` `sleep(timeout)`, `sleep(timeout, close_expr)`
@@ -1372,7 +1376,7 @@ foo(... x) -> ... # all arguments for foo are included in the list
### `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,
them in the current app. This includes other symbols imported by these modules. Scarpet supports circular 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.
@@ -1381,9 +1385,57 @@ issues, and list contents of libraries.
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
functions as arguments and call them with `call` internally. Since function definitions return the defined
function, they can be defined in place as anonymous functions.
#### Passing function references to other modules of your application
In case a function is defined by its name, Scarpet will attempt to resolve its definition in the given module and its imports,
meaning if the call is in a imported library, and not in the main module of your app, and that function is not visible from the
library perspective, but in the app, it won't be call-able. In case you pass a function name to a separate module in your app,
it should import back that method from the main module for visibility.
Check an example of a problematic code of a library that expects a function value as a passed argument and how it is called in
the parent app:
```
//app.sc
import('lib', 'callme');
foo(x) -> x*x;
test() -> callme('foo' , 5);
```
```
//lib.scl
callme(fun, arg) -> call(fun, arg);
```
In this case `'foo'` will fail to dereference in `lib` as it is not visible by name. In tightly coupled modules, where `lib` is just
a component of your `app` you can use circular import to acknowledge the symbol from the other module (pretty much like
imports in Java classes), and that solves the issue but makes the library dependent on the main app:
```
//lib.scl
import('app','foo');
callme(fun, arg) -> call(fun, arg);
```
You can circumvent that issue by explicitly dereferencing the local function where it is used as a lambda argument created
in the module in which the requested function is visible:
```
//app.sc
import('lib', 'callme');
foo(x) -> x*x;
test() -> callme(_(x) -> foo(x), 5);
```
```
//lib.scl
callme(fun, arg) -> call(fun, arg);
```
Or by passing an explicit reference to the function, instead of calling it by name:
```
//app.sc
import('lib', 'callme');
global_foohandler = (foo(x) -> x*x);
test() -> callme(global_foohandler, 5);
```
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
@@ -1658,6 +1710,8 @@ 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]
range(-0.3, 0.3, 0.1) => [-0.3, -0.2, -0.1, 0, 0.1, 0.2]
range(0.3, -0.3, -0.1) => [0.3, 0.2, 0.1, -0, -0.1, -0.2]
</pre>
## Map operations
@@ -1705,7 +1759,9 @@ Here is the gist of the Minecraft related functions. Otherwise the CarpetScript
## App structure
The main delivery method for scarpet programs into the game is in the form of apps in `*.sc` files located in the world `scripts`
folder. When loaded (via `/script load` command, etc.), the game will run the content of the app once, regardless of its scope
folder, flat. In singleplayer, you can also save apps in `.minecraft/config/carpet/scripts` for them to be available in any world,
and here you can actually organize them in folders.
When loaded (via `/script load` command, etc.), the game will run the content of the app once, regardless of its scope
(more about the app scopes below), without executing of any functions, unless called directly, and with the exception of the
`__config()` function, if present, which will be executed once. Loading the app will also bind specific
events to the event system (check Events section for details).
@@ -1731,15 +1787,14 @@ the app state and all players interactions run in the same context, sharing defi
explicitly keyed with players, player names, uuids, etc.
Even for `'player'` scoped apps, you can access specific player app with with commandblocks using
`/execute as <player> run script in <app> run ...`.
To access global/server state for a player app, you need to disown the command from any player,
To access global/server state for a player app, which you shouldn't do, you need to disown the command from any player,
so either use a command block, or any
arbitrary entity: `/execute as @e[type=bat,limit=1] run script in <app> globals` for instance, however
running anything in the global scope for a `'player'` scoped app is not recommended.
* `'stay_loaded'`: defaults to `false`. If true, and `/carpet scriptsAutoload` is turned on, the following apps will
running anything in the global scope for a `'player'` scoped app is not intended.
* `'stay_loaded'`: defaults to `true`. If true, and `/carpet scriptsAutoload` is turned on, the following apps will
stay loaded after startup. Otherwise, after reading the app the first time, and fetching the config, server will drop them down.
This is to allow to store multiple apps on the server/world and selectively decide which one should be running at
startup. WARNING: all apps will run once at startup anyways, so be aware that their actions that are called
statically, will be performed once anyways.
WARNING: all apps will run once at startup anyways, so be aware that their actions that are called
statically, will be performed once anyways. Only apps present in the world's `scripts` folder will be autoloaded.
* `'legacy_command_type_support'` - if `true`, and the app defines the legacy command system via `__command()` function,
all parameters of command functions will be interpreted and used using brigadier / vanilla style argument parser and their type
will be inferred from their names, otherwise
@@ -1749,9 +1804,20 @@ conflicts and ambiguities between different paths of execution. While ambiguous
and they tend to execute correctly, the suggestion support works really poorly in these situations and scarpet
will warn and prevent such apps from loading with an error message. If `allow_command_conflicts` is specified and
`true`, then scarpet will load all provided commands regardless.
* `'command_permission'` - indicates a custom permission to run the command. It can either be a number indicating
permission level (from 1 to 4) or a string value, one of: `'all'` (default), `'ops'` (default opped player with permission level of 2),
`'server'` - command accessible only through the server console and commandblocks, but not in chat, `'players'` - opposite
of the former, allowing only use in player chat. It can also be a function (lambda function or function value, not function name)
that takes 1 parameter, which represents the calling player, or `'null'` if the command represents a server call.
The function will prevent the command from running if it evaluates to `false`.
Please note, that Minecraft evaluates eligible commands for players when they join, or on reload/restart, so if you use a
predicate that is volatile and might change, the command might falsely do or do not indicate that it is available to the player,
however player will always be able to type it in and either succeed, or fail, based on their current permissions.
Custom permission applies to legacy commands with `'legacy_command_type_support'` as well
as for the custom commands defined with `'commands'`, see below.
* `'arguments'` - defines custom argument types for legacy commands with `'legacy_command_type_support'` as well
as for the custom commands defined with `'commands'`, see below
* `'commands'` - defines custom commands for the app to be executed with `/<app>` command, see below
as for the custom commands defined with `'commands'`, see below.
* `'commands'` - defines custom commands for the app to be executed with `/<app>` command, see below.
## Custom app commands
@@ -1904,6 +1970,20 @@ Here is a list of built-in types, with their return value formats, as well as a
* `'pos'`: block position as a triple of coordinates. Customized with `'loaded'`, if true requiring the position
to be loaded.
* `'block'`: a valid block state wrapped in a block value (including block properties and data)
* `'blockpredicate`': returns a 4-tuple indicating conditions of a block to match: block name, block tag,
map of required state properties, and tag to match. Either block name or block tag are `null` but not both.
Property map is always specified, but its empty for no conditions, and matching nbt tag can be `null` indicating
no requirements. Technically the 'all-matching' predicate would be `[null, null, {}, null]`, but
block name or block tag is always specified. One can use the following routine to match a block agains this predicate:
```
block_to_match = block(x,y,z);
[block_name, block_tag, properties, nbt_tag] = block_predicate;
(block_name == null || block_name == block_to_match) &&
(block_tag == null || block_tags(block_to_match, block_tag)) &&
all(properties, block_state(block_to_match, _) == properties:_) &&
(!tag || tag_matches(block_data(block_to_match), tag))
```
* `'teamcolor'`: name of a team, and an integer color value of one of 16 valid team colors.
* `'columnpos'`: a pair of x and z coordinates.
* `'dimension'`: string representing a valid dimension in the world.
@@ -1992,18 +2072,19 @@ print(b); // 'stone', block was evaluated 'eagerly' but call to `block`
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?, ..., block_data?)`, `set(pos, block, l(property?, value?, ...), block_data?)`
### `set(pos, block, property?, value?, ..., block_data?)`, `set(pos, block, [property?, value?, ...], block_data?)`, `set(pos, block, {property? -> value?, ...}, block_data?)`
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. Optional `block_data` include the block data to
First argument for the `set` function is either a coord triple, list of three numbers, or a world localized block value.
Second argument, `block`, is either an existing block value, a result of `block()` function, or a string value indicating the block name
with optional state and block data. It is then followed by an optional
`property - value` pairs for extra block state (which can also be provided in a list or a map). Optional `block_data` include the block data to
be set for the target block.
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.
properties that the original source block may have contained.
The returned value is either the block state that has been set, or `false` if block setting was skipped
The returned value is either the block state that has been set, or `false` if block setting was skipped, or failed
<pre>
set(0,5,0,'bedrock') => bedrock
@@ -2019,11 +2100,15 @@ scan(0,100,0,20,20,20,set(_,block('glass')))
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,'iron_trapdoor[half=top]') // sets the top trapdoor
set(x,y,z,'iron_trapdoor','half','top') // also correct - top trapdoor
set(x,y,z,'iron_trapdoor', ['half','top']) // same
set(x,y,z,'iron_trapdoor', {'half' -> 'top'}) // same
set(x,y,z, block('iron_trapdoor[half=top]')) // also correct, block() provides extra parsing of block state
set(x,y,z,'hopper[facing=north]{Items:[{Slot:1b,id:"minecraft:slime_ball",Count:16b}]}') // extra block data
set(x,y,z,'hopper', l('facing', 'north'), nbt('{Items:[{Slot:1b,id:"minecraft:slime_ball",Count:16b}]}') ) // same
set(x,y,z,'hopper', {'facing' -> 'north'}, nbt('{Items:[{Slot:1b,id:"minecraft:slime_ball",Count:16b}]}') ) // same
</pre>
### `without_updates(expr)`
@@ -2168,6 +2253,16 @@ Causes a block to be harvested by a specified player entity. Honors player item
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.
### `weather()`,`weather(type)`,`weather(type, ticks)`
If called with no args, returns `'clear'`, `'rain` or `'thunder'` based on the current weather. If thundering, will
always return `'thunder'`, if not will return `'rain'` or `'clear'` based on the current weather.
With one arg, (either `'clear'`, `'rain` or `'thunder'`), returns the number of remaining ticks for that weather type.
NB: It can thunder without there being a thunderstorm, there has to be both rain and thunder to form a storm.
With two args, sets the weather to `type` for `ticks` ticks.
## Block and World querying
### `pos(block), pos(entity)`
@@ -2738,14 +2833,16 @@ the future.
These functions help scan larger areas of blocks without using generic loop functions, like nested `loop`.
### `scan(center, range, lower_range?, expr)`
### `scan(center, range, upper_range?, expr)`
Evaluates expression over area of blocks defined by its center `center = (cx, cy, cz)`, expanded in all directions
by `range = (dx, dy, dz)` blocks, or optionally in negative with `range` coords, and `upper_range` coords in
positive values.
`center` can be defined either as three coordinates, a list of three coords, or a block value.
`range` and `lower_range` can have the same representations, just if its a block, it computes the distance to the center
positive values, so you can use that if you know the lower coord, and dimension by calling `'scan(center, 0, 0, 0, w, h, d, ...)`.
`center` can be defined either as three coordinates, a single tuple of three coords, or a block value.
`range` and `upper_range` can have the same representations, just if they are block values, it computes the distance to the center
as range instead of taking the values as is.
`expr` receives `_x, _y, _z` as coords of current analyzed block and `_`, which represents the block itself.
Returns number of successful evaluations of `expr` (with `true` boolean result) unless called in void context,
@@ -2770,7 +2867,7 @@ Returns the list of 6 neighbouring blocks to the argument. Commonly used with ot
for(neighbours(x,y,z),air(_)) => 4 // number of air blocks around a block
</pre>
### `rect(centre, range?, positive_range?)`
### `rect(centre, range?, upper_range?)`
Returns an iterator, just like `range` function that iterates over a rectangular area of blocks. If only center
point is specified, it iterates over 27 blocks. If `range` arguments are specified, expands selection by the respective
@@ -2778,7 +2875,7 @@ number of blocks in each direction. If `positive_range` arguments are specified,
it uses `range` for negative offset, and `positive_range` for positive.
`centre` can be defined either as three coordinates, a list of three coords, or a block value.
`range` and `positive_range` can have the same representations, just if its a block, it computes the distance to the center
`range` and `positive_range` can have the same representations, just if they are block values, it computes the distance to the center
as range instead of taking the values as is.`
### `diamond(centre_pos, radius?, height?)`
@@ -2840,7 +2937,9 @@ to the `regular` group.
* `monster`, `creature`, `ambient`, `water_creature`, `water_ambient`, `misc` - another categorization of
living entities based on their spawn group. Negative descriptor resolves to all living types that don't belong to that
category.
* Any of the following standard entity types (equivalent to selection from `/summon` vanilla command:
* All entity tags including those provided with datapacks. Built-in entity tags include: `skeletons`, `raiders`,
`beehive_inhabitors` (bee, duh), `arrows` and `impact_projectiles`.
* Any of the following standard entity types (equivalent to selection from `/summon` vanilla command:
`area_effect_cloud`, `armor_stand`, `arrow`, `bat`, `bee`, `blaze`, `boat`, `cat`, `cave_spider`, `chest_minecart`,
`chicken`, `cod`, `command_block_minecart`, `cow`, `creeper`, `dolphin`, `donkey`, `dragon_fireball`, `drowned`,
`egg`, `elder_guardian`, `end_crystal`, `ender_dragon`, `ender_pearl`, `enderman`, `endermite`, `evoker`,
@@ -2862,10 +2961,13 @@ belonging to that group.
Returns entities of a specified type in an area centered on `center` and at most `distance` blocks away from
the center point. Uses the same `type` selectors as `entities_list`.
the center point/area. Uses the same `type` selectors as `entities_list`.
`center` and `distance` can either be a triple of coordinates or three consecutive arguments for `entity_area`. `center` can
also be represented as a block, in this case the search box will be centered on the middle of the block.
also be represented as a block, in this case the search box will be centered on the middle of the block, or an entity - in this case
entire bounding box of the entity serves as a 'center' of search which is then expanded in all directions with the `'distance'` vector.
In any case - returns all entities which bounding box collides with the bounding box defined by `'center'` and `'disteance'`.
entity_area is simpler than `entity_selector` and runs about 20% faster, but is limited to predefined selectors and
cuboid search area.
@@ -2994,13 +3096,21 @@ List of entities riding the entity.
Entity that `e` rides.
### `query(e, 'tags')`
### `query(e, 'scoreboard_tags')`, `query(e, 'tags')`(deprecated)
List of entity's tags.
List of entity's scoreboard tags.
### `query(e, 'has_tag',tag)`
### `query(e, 'has_scoreboard_tag',tag)`, `query(e, 'has_tag',tag)`(deprecated)
Boolean, true if the entity is marked with `tag`.
Boolean, true if the entity is marked with a `tag` scoreboad tag.
### `query(e, 'entity_tags')`
List of entity tags assigned to the type this entity represents.
### `query(e, 'has_entity_tag', tag)`
Returns `true` if the entity matches that entity tag, `false` if it doesn't, and `null` if the tag is not valid.
### `query(e, 'is_burning')`
@@ -3154,6 +3264,11 @@ Player's ping in milliseconds, or `null` if its not a player.
Player's permission level, or `null` if not applicable for this entity.
### `query(e, 'client_brand')`
Returns recognized type of client of the client connected. Possible results include `'vanilla'`, or `'carpet <version>'` where
version indicates the version of the connected carpet client.
### `query(e, 'effect', name?)`
Without extra arguments, it returns list of effect active on a living entity. Each entry is a triple of short
@@ -3176,6 +3291,18 @@ Number indicating remaining entity health, or `null` if not applicable.
Retrieves player hunger related information. For non-players, returns `null`.
### `query(e, 'absorption')`
Gets the absorption of the player (yellow hearts, e.g when having a golden apple.)
### `query(e,'xp')`
### `query(e,'xp_level')`
### `query(e,'xp_progress')`
### `query(e,'score')`
Numbers related to player's xp. `xp` is the overall xp player has, `xp_level` is the levels seen in the hotbar,
`xp_progress` is a float between 0 and 1 indicating the percentage of the xp bar filled, and `score` is the number displayed upon death
### `query(e, 'air')`
Number indicating remaining entity health, or `null` if not applicable.
@@ -3486,6 +3613,20 @@ Will set entity on fire for `ticks` ticks. Set to 0 to extinguish.
Modifies directly player raw hunger components. Has no effect on non-players
### `modify(e, 'absorption', value)`
Sets the absorption value for the player. Each point is half a yellow heart.
### `modify(e, 'add_xp', value)`
### `modify(e, 'xp_level', value)`
### `modify(e, 'xp_progress', value)`
### `modify(e, 'xp_score', value)`
Manipulates player xp values - `'add_xp'` the method you probably want to use
to manipulate how much 'xp' an action should give. `'xp_score'` only affects the number you see when you die, and
`'xp_progress'` controls the xp progressbar above the hotbar, should take values from 0 to 1, but you can set it to any value,
maybe you will get a double, who knows.
### `modify(e, 'air', ticks)`
Modifies entity air
@@ -3529,6 +3670,10 @@ 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 attach an inapplicable event to it.
In case you want to pass an event handler that is not defined in your module, please read the tips on
"Passing function references to other modules of your application" section in the `call(...)` section.
### `entity_load_handler(descriptor / descriptors, function)`, `entity_load_handler(descriptor / descriptors, call_name, ... args?)`
Attaches a callback to when any entity matching the following type / types is loaded in the game, allowing to grab a handle
@@ -3627,6 +3772,14 @@ an inventory, all API functions 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.
### item_list(tag?)
With no arguments, returns a list of all items in the game. With an item tag provided, list items matching the tag, or `null` if tag is not valid.
### item_tags(item, tag?)
Returns list of tags the item belongs to, or, if tag is provided, `true` if an item maches the tag, `false` if it doesn't and `null` if that's not a valid tag
### `stack_limit(item)`
Returns number indicating what is the stack limit for the item. Its typically 1 (non-stackable), 16 (like buckets),
@@ -3800,10 +3953,8 @@ with `__on_<event>` and has the required arguments, will be bound automatically
of such function would result in unbinding the app from this event.
In case of `player` scoped apps,
all player action events will be directed to the appropriate player hosts. Global events, like `'tick'`, cannot be handled
in `'player'` scoped app.
`'global'` scoped apps will receive both global and player built-in events.
all player action events will be directed to the appropriate player hosts. Global events, like `'tick'`, that don't have a specific
player target will be executed multiple times, once for each player, and once in `'global'` scoped apps.
Most built-in events strive to report right before they take an effect in the game. The purpose of that is that this give a choice
for the programmer to handle them right away (as it happens, potentially affect the course of action by changing the
@@ -3822,8 +3973,15 @@ if it accepts required number of parameters.
## Built-in global events
Handling global events is only allowed in apps with `'global'` scope. With the default scope (`'player'`) you
simply wouldn't know which player to hook up this event to.
Global events will be handled once per app that is with `'global'` scope. With `player` scoped apps, each player instance
is responsible independently from handling their events, so a global event may be executed multiple times for each player.
### `__on_server_starts()`
Event triggers after world is loaded and after all startup apps have started. It won't be triggered with `/reload`.
### `__on_server_shuts_down()`
Event triggers when the server started the shutdown process, before `__on_close()` is executed. Unlike `__on_close()`, it doesn't
trigger with `/reload`.
### `__on_tick()`
Event triggers at the beginning of each tick, located in the overworld. You can use `in_dimension()`
@@ -3900,7 +4058,12 @@ adjusted.
### `__on_player_interacts_with_entity(player, entity, hand)`
Triggered when player right clicks (interacts) with an entity, even if the entity has no vanilla interaction with the player or
the item they are holding. The event is invoked after receiving a packet from the client, before anything happens server side
with that interaction
with that interaction.
### `__on_player_trades(player, entity, buy_left, buy_right, sell)`
Triggered when player trades with a merchant. The event is invoked after the server allow the trade, but before the inventory
changes and merchant updates its trade-uses counter.
The parameter `entity` can be `null` if the merchant is not an entity.
### `__on_player_collides_with_entity(player, entity)`
Triggered every time a player - entity collisions are calculated, before effects of collisions are applied in the game.
@@ -3996,8 +4159,11 @@ is handled before scoreboard values for these statistics are changed.
App programmers can define and trigger their own custom events. Unlike built-in events, all custom events pass a single value
as an argument, but this doesn't mean that they cannot pass a complex list, map, or nbt tag as a message. Each event signal is
either targetting all global context apps, if no target player has been identified, or only player scoped apps, if the target player
is specified.
either targetting all apps instances for all players, including global apps, if no target player has been identified,
or only player scoped apps, if the target player
is specified, running once for that player app. You cannot target global apps with player-targeted signals. Built-in events
do target global apps, since their first argument is clearly defined and passed. That may change in the future in case there is
a compelling argument to be able to target global apps with player scopes.
Programmers can also handle built-in events the same way as custom events, as well as triggering built-in events, which I have
have no idea why you would need that. The following snippets have the same effect:
@@ -4021,11 +4187,11 @@ handle_event('player_breaks_block', null);
And `signal_event` can be used as a trigger, called twice for player based built-in events
```
signal_event('player_breaks_block', player, player, block); // to target all player scoped apps
signal_event('player_breaks_block', null , player, block); // to target all global scoped apps
signal_event('player_breaks_block', null , player, block); // to target all global scoped apps and all player instances
```
or (for global only events)
or (for global events)
```
signal_event('tick') // trigger only global scoped apps with no extra arguments
signal_event('tick') // trigger all apps with a tick event
```
### `handle_event(event, callback ...)`
@@ -4039,6 +4205,8 @@ If extra arguments are provided, they will be appended to the argument list of t
Returns `true` if subscription to the event was successful, or `false` if it failed (for instance wrong scope for built-in event,
or incorect number of parameters for the event).
If a callback is specified as `null`, the given app (or player app instance )stops handling that event.
<pre>
foo(a) -> print(a);
handle_event('boohoo', 'foo');
@@ -4051,116 +4219,64 @@ handle_event('tick', _() -> foo('tick happened')); // built-in event
handle_event('tick', null) // nah, ima good, kthxbai
</pre>
In case you want to pass an event handler that is not defined in your module, please read the tips on
"Passing function references to other modules of your application" section in the `call(...)` section.
### `signal_event(event, target_player?, ... args?)`
Fires a specific event. If the event does not exist (only `handle_event` creates missing mising new events), or provided argument list
Fires a specific event. If the event does not exist (only `handle_event` creates missing new events), or provided argument list
was not matching the callee expected arguments, returns `null`,
otherwise returns number of apps notified. If `target_player` is specified and not `null` triggers a player specific event, targetting
only `player` scoped apps for that player. Apps with globals scope will not be notified even if they handle this event.
If the `target_player` is omitted or `null`, it will instead only target `global` scoped apps and skip `player` scoped.
Therefore each custom event trigger can trigger each app once, but calls to '`signal_event`' can be repeated to cover
all app scopes. Note that all built-in player events have a player as a first argument, so to trigger these events, you need to
If the `target_player` is omitted or `null`, it will target `global` scoped apps and all instances of `player` scoped apps.
Note that all built-in player events have a player as a first argument, so to trigger these events, you need to
provide them twice - once to specify the target player scope and second - to provide as an argument to the handler function.
<pre>
signal_event('player_breaks_block', player, player, block); // to target all player scoped apps
signal_event('player_breaks_block', null , player, block); // to target all global scoped apps
signal_event('tick') // triggering tick event in all loaded apps
signal_event('player_breaks_block', null , player, block); // to target all global scoped apps and all player instances
signal_event('tick') // trigger all apps with a tick event
</pre>
## Custom events example
The following example contains 4 apps, 2 of them defining a new event, `"player_farts"` triggered after 40 ticks of continuous
squatting. Note that this could call the recipient event handlers twice, since `signal_event` will be called twice, but
in this case the event is once called as a global event, and once as a player event, targeting each app once. Custom events is
a good idea to share common event detection code with one app, and using the outcome of these events in multiple places.
Obviously you would define each event handler once not twice in your app system.
In this
case here we have two ways of detecting all players squatting for more than 40 ticks - one of those apps will produce cloud particles
in an apprpriate location, and the other will produce a sound when it happens, and they both will proceed to signal the same event,
thankfully for different scopes, otherwise other apps would trigger twice.
The following example shows how you can communicate between different instances of the same player scoped app. It important to note
that signals can trigger other apps as well, assuming the name of the event matches. In this case the request name is called
`tp_request` and is triggered with a command.
```
// detector1.sc
// detecting event in a tick loop
__config() -> {'scope' -> 'global'};
global_sneaks = {};
__on_tick() -> for(player('all'),
if (_~'sneaking',
sneak_time = if (has(global_sneaks:_), tick_time()-global_sneaks:_ , global_sneaks:_=tick_time(); 0);
if (sneak_time > 20 && sneak_time < 40,
particle('cloud', pos(_) + [0, _~'height'/2, 0] - _~'look', 1, 0.1)
);
if (sneak_time == 40,
signal_event('player_farts', _, _) // triggering all player scoped apps from a global app
// tpa.sc
global_requester = null;
__config() -> {
'commands' -> {
'<player>' -> _(to) -> signal_event('tp_request', to, player()),
'accept' -> _() -> if(global_requester,
run('tp '+global_requester~'command_name');
global_requester = null
)
, // else
delete(global_sneaks:_)
)
)
},
'arguments' -> {
'player' -> {'type' -> 'players', 'single' -> true}
}
};
handle_event('tp_request', _(req) -> (
global_requester = req;
print(player(), format(
'w '+req+' requested to teleport to you. Click ',
'yb here', '^yb here', '!/tpa accept',
'w to accept it.'
));
));
```
```
// detector2.sc
// detecting events in a more appropriate way - player based and event based app
__on_player_starts_sneaking(p) ->
(
global_sneaking = tick_time();
schedule(40, 'check', p);
);
check(p) ->
if( global_sneaking && tick_time() - global_sneaking == 40,
sound('entity.shulker.shoot', pos(p), 1, 0.6, 'player');
signal_event('player_farts', null, p) // trigerring all global apps from a player scoped app
);
__on_player_stops_sneaking(p) -> (global_sneaking = false);
```
And then two other apps that meant to do something with this event. One mimics an explosion, and the other - grows crops around
the player.
```
client1.sc
__config() -> {'scope' -> 'global'};
on_fart(p, msg) ->
(
print(p+msg);
particle('explosion', pos(p));
sound('entity.generic.explode', pos(p), 1, 0.5);
);
handle_event('player_farts', 'on_fart', ' goes kaboom');
```
```
client2.sc
longsneak(p) ->
(
ppos = pos(p);
loop ( 500,
target = ppos+[rand(12),rand(8),rand(12)]-[rand(12),rand(8),rand(12)];
if (material(target) == 'plant' && ticks_randomly(target),
particle('happy_villager', target, 2, 0.4)
);
random_tick(target)
)
);
handle_event('player_farts', 'longsneak');
```
## `/script event` command
used to display current events and bounded functions. use `add_to` ro register new event, or `remove_from` to
used to display current events and bounded functions. use `add_to` to register a 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.
that handle specific built-in events will be automatically bounded, and unbounded when script is unloaded.
# Scoreboard
### `scoreboard()`, `scoreboard(objective)`, `scoreboard(objective, key)`, `scoreboard(objective, key, value)`
@@ -4267,6 +4383,65 @@ team_property('admin','seeFriendlyInvisibles',true) Make all players in 'a
team_property('admin','deathMessageVisibility','hideForOtherTeams') Make all players in 'admin' see other admins even when invisible
```
## `bossbar()`, `bossbar(id)`, `bossbar(id,property,value?)`
Manage bossbars just like with the `/bossbar` command.
Without any arguments, returns a list of all bossbars.
When an id is specified, creates a bossbar with that `id` and returns the id of the created bossbar.
Bossbar ids need a namespace and a name. If no namespace is specified, it will automatically use `minecraft:`.
In that case you should keep track of the bossbar with the id that `bossbar(id)` returns, because a namespace may be added automatically.
If the id was invalid (for example by having more than one colon), returns `null`.
If the bossbar already exists, returns `false`.
`bossbar('timer') => 'minecraft:timer'` (Adds the namespace `minecraft:` because none is specified)
`bossbar('scarpet:test') => 'scarpet:test'` In this case there is already a namespace specified
`bossbar('foo:bar:baz') => null` Invalid identifier
`bossbar(id,property)` is used to query the `property` of a bossbar.
`bossbar(id,property,value)` can modify the `property` of the bossbar to a specified `value`.
Available properties are:
* color: can be `'pink'`, `'blue'`, `'red'`, `'green'`, `'yellow'`, `'purple'` or `'white'`
* style: can be `'progress'`, `'notched_6'`, `'notched_10'`, `'notched_12'` or `'notched_20'`
* value: value of the bossbar progress
* max: maximum value of the bossbar progress, by default 100
* name: Text to display above the bossbar, supports formatted text
* visible: whether the bossbar is visible or not
* players: List of players that can see the bossbar
* add_player: add a player to the players that can see this bossbar, this can only be used for modifying (`value` must be present)
* remove: remove this bossbar, no `value` required
```
bossbar('script:test','style','notched_12')
bossbar('script:test','value',74)
bossbar('script:test','name',format('rb Test')) -> Change text
bossbar('script:test','visible',false) -> removes visibility, but keeps players
bossbar('script:test','players',player('all')) -> Visible for all players
bossbar('script:test','players',player('Steve')) -> Visible for Steve only
bossbar('script:test','players',null) -> Invalid player, removing all players
bossbar('script:test','add_player',player('Alex')) -> Add Alex to the list of players that can see the bossbar
bossbar('script:test','remove') -> remove bossbar 'script:test'
for(bossbar(),bossbar(_,'remove')) -> remove all bossbars
```
# Auxiliary aspects
Collection of other methods that control smaller, yet still important aspects of the game
@@ -4462,9 +4637,10 @@ Other value types will only be converted to tags (including NBT tags) if `force`
extra treatment when loading them back from NBT, but using `force` true will always produce output / never
produce an exception.
### `print(expr)`
### `print(expr)`, `print(player/player_list, expr)`
Displays the result of the expression to the chat. Overrides default `scarpet` behaviour of sending everyting to stderr.
Can optionally define player or list of players to send the message to.
### `format(components, ...)`, `format(l(components, ...))`
@@ -4544,13 +4720,15 @@ Available output types:
### `read_file(resource, type)`
### `delete_file(resource, type)`
### `write_file(resource, type, data, ...)`
### `list_files(resource, type)`
With the specified `resource` in the scripts folder, of a specific `type`, writes/appends `data` to it, reads its
content, or deletes the resource.
content, deletes the resource, or lists other files under this resource.
Resource is identified by a path to the file.
A path can contain letters, numbers, characters `-`, `+`, or `_`, and a folder separator: `'/'`. Any other characters are stripped
from the name. Empty descriptors are invalid. Do not add file extensions to the descriptor - extensions are inferred
from the name. Empty descriptors are invalid, except for `list_files` where it means the root folder.
Do not add file extensions to the descriptor - extensions are inferred
based on the `type` of the file.
Resources can be located in the app specific space, or a shared space for all the apps. Accessing of app-specific
@@ -4565,33 +4743,26 @@ specific data directory is under `world/scripts/foo.data/...`, and shared data s
The default no-name app, via `/script run` command can only save/load/read files from the shared space.
Functions return `null` if an error is encounter or no file is present (for read and delete operations). Returns `true`
for success writes and deletes, and requested data, based on the file type, for read operations.
NBT files can be written once as they an store one tag at a time. Consecutive writes will overwrite previous data.
Write operations to text files always result in appending to the existing file, so consecutive writes will increase
the size of the file and add data to it. Since files are closed after each write, sending multiple lines of data to
write is beneficial for writing speed. To send multiple packs of data, either provide them flat or as a list in the
third argument.
* `write_file('temp', 'text', 'foo', 'bar', 'baz')` or
* write_file('temp', 'text', l('foo', 'bar', 'baz'))
Functions return `null` if an error is encounter or no file is present (for read, list and delete operations). Returns `true`
for success writes and deletes, and requested data, based on the file type, for read operations. It returns list of files
for folder listing.
To log a single line of string
Supported values for resource `type` is:
Supported values for resource `type` are:
* `nbt` - NBT tag
* `text` - text resource with automatic newlines added
* `raw` - text resource without implied newlines
* `shared_nbt`, `shared_text`, `shared_raw` - shared versions of the above
* `folder` - for `list_files` only - indicting folder listing instead of files
* `shared_nbt`, `shared_text`, `shared_raw`, `shared_folder` - shared versions of the above
NBT files have extension `.nbt`, store one NBT tag, and return a NBT type value. Text files have `.txt` extension,
stores multiple lines of text and returns lists of all lines from the file. With `write_file`, multiple lines can be
sent to the file at once. The only difference between `raw` and `text` types are automatic newlines added after each
record to the file.
record to the file. Since files are closed after each write, sending multiple lines of data to
write is beneficial for writing speed. To send multiple packs of data, either provide them flat or as a list in the
third argument.
<pre>
write_file('foo', 'shared_text, l('one', 'two'));
write_file('foo', 'shared_text, ['one', 'two']);
write_file('foo', 'shared_text', 'three\n', 'four\n');
write_file('foo', 'shared_raw', 'five\n', 'six\n');
@@ -4718,6 +4889,9 @@ algorithm has taken in to account last time mobs spawned.
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.
In case you want to schedule a function that is not defined in your module, please read the tips on
"Passing function references to other modules of your application" section in the `call(...)` section.
### `statistic(player, category, entry)`
Queries in-game statistics for certain values. Categories include:
@@ -4757,7 +4931,9 @@ Available options in the scarpet app space:
* `world_path` - full path to the world saves folder
* `world_folder` - name of the direct folder in the saves that holds world files
* `world_carpet_rules` - returns all Carpet rules in a map form (`rule`->`value`). Note that the values are always returned as strings, so you can't do boolean comparisons directly. Includes rules from extensions with their namespace (`namespace:rule`->`value`). You can later listen to rule changes with the `on_carpet_rule_changes(rule, newValue)` event.
* `world_gamerules` - returns all gamerules in a map form (`rule`->`value`). Like carpet rules, values are returned as strings, so you can use appropriate value conversions using `bool()` or `number()` to convert them to other values. Gamerules are read-only to discourage app programmers to mess up with the settings intentionally applied by server admins. Isn't that just super annoying when a datapack messes up with your gamerule settings? It is still possible to change them though using `run('gamerule ...`.
Relevant gameplay related properties
* `game_difficulty` - current difficulty of the game: `'peacefu'`, `'easy'`, `'normal'`, or `'hard'`
* `game_hardcore` - boolean whether the game is in hardcore mode
@@ -4769,13 +4945,13 @@ Available options in the scarpet app space:
* `game_version` - base version of the game
Server related properties
* `server_motd` - the motd of the server visible when joining
* `server_ip` - IP adress of the game hosted
* `server_whitelisted` - boolean indicating whether the access to the server is only for whitelisted players
* `server_whitelist` - list of players allowed to log in
* `server_banned_players` - list of banned player names
* `server_banned_ips` - list of banned IP addresses
* `server_dev_environment` - boolean indicating whether this server is in a development environment.
System related properties
* `java_max_memory` - maximum allowed memory accessible by JVM
@@ -4785,7 +4961,11 @@ Available options in the scarpet app space:
* `java_version` - version of Java
* `java_bits` - number indicating how many bits the Java has, 32 or 64
* `java_system_cpu_load` - current percentage of CPU used by the system
* `java_process_cpu_load` - current percentage of CPU used by JVM# `/script run` command
* `java_process_cpu_load` - current percentage of CPU used by JVM
Scarpet related properties
* `scarpet_version` - returns the version of the carpet your scarpet comes with.
# `/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
@@ -4795,13 +4975,15 @@ to simulate running commands in a different scope.
# `/script load / unload <app> (global?)`, `/script in <app>` commands
`load / unload` commands allow for very conventient way of writing your code, providing it to the game and
distribute with your worlds without the need of use of commandblocks. Just place your scarpet code in the
/scripts folder of your world files and make sure it ends with `.sc` extension. The good thing about editing that
code is that you can no only use normal editing without the need of marking of newlines,
`load / unload` commands allow for very convenient way of writing your code, providing it to the game and
distribute with your worlds without the need of use of commandblocks. Just place your Scarpet code in the
`/scripts` folder of your world files and make sure it ends with `.sc` extension. In singleplayer, you can
also save your scripts in `.minecraft/config/carpet/scripts` to make them available in any world.
The good thing about editing that code is that you can not only use normal editing without the need of marking of newlines,
but you can also use comments in your code.
a comment is anything that starts with a double slash, and continues to the end of the line:
A comment is anything that starts with a double slash, and continues to the end of the line:
<pre>
foo = 1;
+27 -23
View File
@@ -193,9 +193,10 @@ Other value types will only be converted to tags (including NBT tags) if `force`
extra treatment when loading them back from NBT, but using `force` true will always produce output / never
produce an exception.
### `print(expr)`
### `print(expr)`, `print(player/player_list, expr)`
Displays the result of the expression to the chat. Overrides default `scarpet` behaviour of sending everyting to stderr.
Can optionally define player or list of players to send the message to.
### `format(components, ...)`, `format(l(components, ...))`
@@ -275,13 +276,15 @@ Available output types:
### `read_file(resource, type)`
### `delete_file(resource, type)`
### `write_file(resource, type, data, ...)`
### `list_files(resource, type)`
With the specified `resource` in the scripts folder, of a specific `type`, writes/appends `data` to it, reads its
content, or deletes the resource.
content, deletes the resource, or lists other files under this resource.
Resource is identified by a path to the file.
A path can contain letters, numbers, characters `-`, `+`, or `_`, and a folder separator: `'/'`. Any other characters are stripped
from the name. Empty descriptors are invalid. Do not add file extensions to the descriptor - extensions are inferred
from the name. Empty descriptors are invalid, except for `list_files` where it means the root folder.
Do not add file extensions to the descriptor - extensions are inferred
based on the `type` of the file.
Resources can be located in the app specific space, or a shared space for all the apps. Accessing of app-specific
@@ -296,33 +299,26 @@ specific data directory is under `world/scripts/foo.data/...`, and shared data s
The default no-name app, via `/script run` command can only save/load/read files from the shared space.
Functions return `null` if an error is encounter or no file is present (for read and delete operations). Returns `true`
for success writes and deletes, and requested data, based on the file type, for read operations.
NBT files can be written once as they an store one tag at a time. Consecutive writes will overwrite previous data.
Write operations to text files always result in appending to the existing file, so consecutive writes will increase
the size of the file and add data to it. Since files are closed after each write, sending multiple lines of data to
write is beneficial for writing speed. To send multiple packs of data, either provide them flat or as a list in the
third argument.
* `write_file('temp', 'text', 'foo', 'bar', 'baz')` or
* write_file('temp', 'text', l('foo', 'bar', 'baz'))
Functions return `null` if an error is encounter or no file is present (for read, list and delete operations). Returns `true`
for success writes and deletes, and requested data, based on the file type, for read operations. It returns list of files
for folder listing.
To log a single line of string
Supported values for resource `type` is:
Supported values for resource `type` are:
* `nbt` - NBT tag
* `text` - text resource with automatic newlines added
* `raw` - text resource without implied newlines
* `shared_nbt`, `shared_text`, `shared_raw` - shared versions of the above
* `folder` - for `list_files` only - indicting folder listing instead of files
* `shared_nbt`, `shared_text`, `shared_raw`, `shared_folder` - shared versions of the above
NBT files have extension `.nbt`, store one NBT tag, and return a NBT type value. Text files have `.txt` extension,
stores multiple lines of text and returns lists of all lines from the file. With `write_file`, multiple lines can be
sent to the file at once. The only difference between `raw` and `text` types are automatic newlines added after each
record to the file.
record to the file. Since files are closed after each write, sending multiple lines of data to
write is beneficial for writing speed. To send multiple packs of data, either provide them flat or as a list in the
third argument.
<pre>
write_file('foo', 'shared_text, l('one', 'two'));
write_file('foo', 'shared_text, ['one', 'two']);
write_file('foo', 'shared_text', 'three\n', 'four\n');
write_file('foo', 'shared_raw', 'five\n', 'six\n');
@@ -449,6 +445,9 @@ algorithm has taken in to account last time mobs spawned.
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.
In case you want to schedule a function that is not defined in your module, please read the tips on
"Passing function references to other modules of your application" section in the `call(...)` section.
### `statistic(player, category, entry)`
Queries in-game statistics for certain values. Categories include:
@@ -488,7 +487,9 @@ Available options in the scarpet app space:
* `world_path` - full path to the world saves folder
* `world_folder` - name of the direct folder in the saves that holds world files
* `world_carpet_rules` - returns all Carpet rules in a map form (`rule`->`value`). Note that the values are always returned as strings, so you can't do boolean comparisons directly. Includes rules from extensions with their namespace (`namespace:rule`->`value`). You can later listen to rule changes with the `on_carpet_rule_changes(rule, newValue)` event.
* `world_gamerules` - returns all gamerules in a map form (`rule`->`value`). Like carpet rules, values are returned as strings, so you can use appropriate value conversions using `bool()` or `number()` to convert them to other values. Gamerules are read-only to discourage app programmers to mess up with the settings intentionally applied by server admins. Isn't that just super annoying when a datapack messes up with your gamerule settings? It is still possible to change them though using `run('gamerule ...`.
Relevant gameplay related properties
* `game_difficulty` - current difficulty of the game: `'peacefu'`, `'easy'`, `'normal'`, or `'hard'`
* `game_hardcore` - boolean whether the game is in hardcore mode
@@ -500,13 +501,13 @@ Available options in the scarpet app space:
* `game_version` - base version of the game
Server related properties
* `server_motd` - the motd of the server visible when joining
* `server_ip` - IP adress of the game hosted
* `server_whitelisted` - boolean indicating whether the access to the server is only for whitelisted players
* `server_whitelist` - list of players allowed to log in
* `server_banned_players` - list of banned player names
* `server_banned_ips` - list of banned IP addresses
* `server_dev_environment` - boolean indicating whether this server is in a development environment.
System related properties
* `java_max_memory` - maximum allowed memory accessible by JVM
@@ -516,4 +517,7 @@ Available options in the scarpet app space:
* `java_version` - version of Java
* `java_bits` - number indicating how many bits the Java has, 32 or 64
* `java_system_cpu_load` - current percentage of CPU used by the system
* `java_process_cpu_load` - current percentage of CPU used by JVM
* `java_process_cpu_load` - current percentage of CPU used by JVM
Scarpet related properties
* `scarpet_version` - returns the version of the carpet your scarpet comes with.
+8 -6
View File
@@ -2,14 +2,16 @@
These functions help scan larger areas of blocks without using generic loop functions, like nested `loop`.
### `scan(center, range, lower_range?, expr)`
### `scan(center, range, upper_range?, expr)`
Evaluates expression over area of blocks defined by its center `center = (cx, cy, cz)`, expanded in all directions
by `range = (dx, dy, dz)` blocks, or optionally in negative with `range` coords, and `upper_range` coords in
positive values.
`center` can be defined either as three coordinates, a list of three coords, or a block value.
`range` and `lower_range` can have the same representations, just if its a block, it computes the distance to the center
positive values, so you can use that if you know the lower coord, and dimension by calling `'scan(center, 0, 0, 0, w, h, d, ...)`.
`center` can be defined either as three coordinates, a single tuple of three coords, or a block value.
`range` and `upper_range` can have the same representations, just if they are block values, it computes the distance to the center
as range instead of taking the values as is.
`expr` receives `_x, _y, _z` as coords of current analyzed block and `_`, which represents the block itself.
Returns number of successful evaluations of `expr` (with `true` boolean result) unless called in void context,
@@ -34,7 +36,7 @@ Returns the list of 6 neighbouring blocks to the argument. Commonly used with ot
for(neighbours(x,y,z),air(_)) => 4 // number of air blocks around a block
</pre>
### `rect(centre, range?, positive_range?)`
### `rect(centre, range?, upper_range?)`
Returns an iterator, just like `range` function that iterates over a rectangular area of blocks. If only center
point is specified, it iterates over 27 blocks. If `range` arguments are specified, expands selection by the respective
@@ -42,7 +44,7 @@ number of blocks in each direction. If `positive_range` arguments are specified,
it uses `range` for negative offset, and `positive_range` for positive.
`centre` can be defined either as three coordinates, a list of three coords, or a block value.
`range` and `positive_range` can have the same representations, just if its a block, it computes the distance to the center
`range` and `positive_range` can have the same representations, just if they are block values, it computes the distance to the center
as range instead of taking the values as is.`
### `diamond(centre_pos, radius?, height?)`
+25 -10
View File
@@ -36,18 +36,19 @@ print(b); // 'stone', block was evaluated 'eagerly' but call to `block`
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?, ..., block_data?)`, `set(pos, block, l(property?, value?, ...), block_data?)`
### `set(pos, block, property?, value?, ..., block_data?)`, `set(pos, block, [property?, value?, ...], block_data?)`, `set(pos, block, {property? -> value?, ...}, block_data?)`
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. Optional `block_data` include the block data to
First argument for the `set` function is either a coord triple, list of three numbers, or a world localized block value.
Second argument, `block`, is either an existing block value, a result of `block()` function, or a string value indicating the block name
with optional state and block data. It is then followed by an optional
`property - value` pairs for extra block state (which can also be provided in a list or a map). Optional `block_data` include the block data to
be set for the target block.
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.
properties that the original source block may have contained.
The returned value is either the block state that has been set, or `false` if block setting was skipped
The returned value is either the block state that has been set, or `false` if block setting was skipped, or failed
<pre>
set(0,5,0,'bedrock') => bedrock
@@ -63,11 +64,15 @@ scan(0,100,0,20,20,20,set(_,block('glass')))
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,'iron_trapdoor[half=top]') // sets the top trapdoor
set(x,y,z,'iron_trapdoor','half','top') // also correct - top trapdoor
set(x,y,z,'iron_trapdoor', ['half','top']) // same
set(x,y,z,'iron_trapdoor', {'half' -> 'top'}) // same
set(x,y,z, block('iron_trapdoor[half=top]')) // also correct, block() provides extra parsing of block state
set(x,y,z,'hopper[facing=north]{Items:[{Slot:1b,id:"minecraft:slime_ball",Count:16b}]}') // extra block data
set(x,y,z,'hopper', l('facing', 'north'), nbt('{Items:[{Slot:1b,id:"minecraft:slime_ball",Count:16b}]}') ) // same
set(x,y,z,'hopper', {'facing' -> 'north'}, nbt('{Items:[{Slot:1b,id:"minecraft:slime_ball",Count:16b}]}') ) // same
</pre>
### `without_updates(expr)`
@@ -212,6 +217,16 @@ Causes a block to be harvested by a specified player entity. Honors player item
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.
### `weather()`,`weather(type)`,`weather(type, ticks)`
If called with no args, returns `'clear'`, `'rain` or `'thunder'` based on the current weather. If thundering, will
always return `'thunder'`, if not will return `'rain'` or `'clear'` based on the current weather.
With one arg, (either `'clear'`, `'rain` or `'thunder'`), returns the number of remaining ticks for that weather type.
NB: It can thunder without there being a thunderstorm, there has to be both rain and thunder to form a storm.
With two args, sets the weather to `type` for `ticks` ticks.
## Block and World querying
### `pos(block), pos(entity)`
+55 -7
View File
@@ -52,7 +52,9 @@ to the `regular` group.
* `monster`, `creature`, `ambient`, `water_creature`, `water_ambient`, `misc` - another categorization of
living entities based on their spawn group. Negative descriptor resolves to all living types that don't belong to that
category.
* Any of the following standard entity types (equivalent to selection from `/summon` vanilla command:
* All entity tags including those provided with datapacks. Built-in entity tags include: `skeletons`, `raiders`,
`beehive_inhabitors` (bee, duh), `arrows` and `impact_projectiles`.
* Any of the following standard entity types (equivalent to selection from `/summon` vanilla command:
`area_effect_cloud`, `armor_stand`, `arrow`, `bat`, `bee`, `blaze`, `boat`, `cat`, `cave_spider`, `chest_minecart`,
`chicken`, `cod`, `command_block_minecart`, `cow`, `creeper`, `dolphin`, `donkey`, `dragon_fireball`, `drowned`,
`egg`, `elder_guardian`, `end_crystal`, `ender_dragon`, `ender_pearl`, `enderman`, `endermite`, `evoker`,
@@ -74,10 +76,13 @@ belonging to that group.
Returns entities of a specified type in an area centered on `center` and at most `distance` blocks away from
the center point. Uses the same `type` selectors as `entities_list`.
the center point/area. Uses the same `type` selectors as `entities_list`.
`center` and `distance` can either be a triple of coordinates or three consecutive arguments for `entity_area`. `center` can
also be represented as a block, in this case the search box will be centered on the middle of the block.
also be represented as a block, in this case the search box will be centered on the middle of the block, or an entity - in this case
entire bounding box of the entity serves as a 'center' of search which is then expanded in all directions with the `'distance'` vector.
In any case - returns all entities which bounding box collides with the bounding box defined by `'center'` and `'disteance'`.
entity_area is simpler than `entity_selector` and runs about 20% faster, but is limited to predefined selectors and
cuboid search area.
@@ -206,13 +211,21 @@ List of entities riding the entity.
Entity that `e` rides.
### `query(e, 'tags')`
### `query(e, 'scoreboard_tags')`, `query(e, 'tags')`(deprecated)
List of entity's tags.
List of entity's scoreboard tags.
### `query(e, 'has_tag',tag)`
### `query(e, 'has_scoreboard_tag',tag)`, `query(e, 'has_tag',tag)`(deprecated)
Boolean, true if the entity is marked with `tag`.
Boolean, true if the entity is marked with a `tag` scoreboad tag.
### `query(e, 'entity_tags')`
List of entity tags assigned to the type this entity represents.
### `query(e, 'has_entity_tag', tag)`
Returns `true` if the entity matches that entity tag, `false` if it doesn't, and `null` if the tag is not valid.
### `query(e, 'is_burning')`
@@ -366,6 +379,11 @@ Player's ping in milliseconds, or `null` if its not a player.
Player's permission level, or `null` if not applicable for this entity.
### `query(e, 'client_brand')`
Returns recognized type of client of the client connected. Possible results include `'vanilla'`, or `'carpet <version>'` where
version indicates the version of the connected carpet client.
### `query(e, 'effect', name?)`
Without extra arguments, it returns list of effect active on a living entity. Each entry is a triple of short
@@ -388,6 +406,18 @@ Number indicating remaining entity health, or `null` if not applicable.
Retrieves player hunger related information. For non-players, returns `null`.
### `query(e, 'absorption')`
Gets the absorption of the player (yellow hearts, e.g when having a golden apple.)
### `query(e,'xp')`
### `query(e,'xp_level')`
### `query(e,'xp_progress')`
### `query(e,'score')`
Numbers related to player's xp. `xp` is the overall xp player has, `xp_level` is the levels seen in the hotbar,
`xp_progress` is a float between 0 and 1 indicating the percentage of the xp bar filled, and `score` is the number displayed upon death
### `query(e, 'air')`
Number indicating remaining entity health, or `null` if not applicable.
@@ -698,6 +728,20 @@ Will set entity on fire for `ticks` ticks. Set to 0 to extinguish.
Modifies directly player raw hunger components. Has no effect on non-players
### `modify(e, 'absorption', value)`
Sets the absorption value for the player. Each point is half a yellow heart.
### `modify(e, 'add_xp', value)`
### `modify(e, 'xp_level', value)`
### `modify(e, 'xp_progress', value)`
### `modify(e, 'xp_score', value)`
Manipulates player xp values - `'add_xp'` the method you probably want to use
to manipulate how much 'xp' an action should give. `'xp_score'` only affects the number you see when you die, and
`'xp_progress'` controls the xp progressbar above the hotbar, should take values from 0 to 1, but you can set it to any value,
maybe you will get a double, who knows.
### `modify(e, 'air', ticks)`
Modifies entity air
@@ -741,6 +785,10 @@ 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 attach an inapplicable event to it.
In case you want to pass an event handler that is not defined in your module, please read the tips on
"Passing function references to other modules of your application" section in the `call(...)` section.
### `entity_load_handler(descriptor / descriptors, function)`, `entity_load_handler(descriptor / descriptors, call_name, ... args?)`
Attaches a callback to when any entity matching the following type / types is loaded in the game, allowing to grab a handle
+63 -100
View File
@@ -9,10 +9,8 @@ with `__on_<event>` and has the required arguments, will be bound automatically
of such function would result in unbinding the app from this event.
In case of `player` scoped apps,
all player action events will be directed to the appropriate player hosts. Global events, like `'tick'`, cannot be handled
in `'player'` scoped app.
`'global'` scoped apps will receive both global and player built-in events.
all player action events will be directed to the appropriate player hosts. Global events, like `'tick'`, that don't have a specific
player target will be executed multiple times, once for each player, and once in `'global'` scoped apps.
Most built-in events strive to report right before they take an effect in the game. The purpose of that is that this give a choice
for the programmer to handle them right away (as it happens, potentially affect the course of action by changing the
@@ -31,8 +29,15 @@ if it accepts required number of parameters.
## Built-in global events
Handling global events is only allowed in apps with `'global'` scope. With the default scope (`'player'`) you
simply wouldn't know which player to hook up this event to.
Global events will be handled once per app that is with `'global'` scope. With `player` scoped apps, each player instance
is responsible independently from handling their events, so a global event may be executed multiple times for each player.
### `__on_server_starts()`
Event triggers after world is loaded and after all startup apps have started. It won't be triggered with `/reload`.
### `__on_server_shuts_down()`
Event triggers when the server started the shutdown process, before `__on_close()` is executed. Unlike `__on_close()`, it doesn't
trigger with `/reload`.
### `__on_tick()`
Event triggers at the beginning of each tick, located in the overworld. You can use `in_dimension()`
@@ -109,7 +114,12 @@ adjusted.
### `__on_player_interacts_with_entity(player, entity, hand)`
Triggered when player right clicks (interacts) with an entity, even if the entity has no vanilla interaction with the player or
the item they are holding. The event is invoked after receiving a packet from the client, before anything happens server side
with that interaction
with that interaction.
### `__on_player_trades(player, entity, buy_left, buy_right, sell)`
Triggered when player trades with a merchant. The event is invoked after the server allow the trade, but before the inventory
changes and merchant updates its trade-uses counter.
The parameter `entity` can be `null` if the merchant is not an entity.
### `__on_player_collides_with_entity(player, entity)`
Triggered every time a player - entity collisions are calculated, before effects of collisions are applied in the game.
@@ -205,8 +215,11 @@ is handled before scoreboard values for these statistics are changed.
App programmers can define and trigger their own custom events. Unlike built-in events, all custom events pass a single value
as an argument, but this doesn't mean that they cannot pass a complex list, map, or nbt tag as a message. Each event signal is
either targetting all global context apps, if no target player has been identified, or only player scoped apps, if the target player
is specified.
either targetting all apps instances for all players, including global apps, if no target player has been identified,
or only player scoped apps, if the target player
is specified, running once for that player app. You cannot target global apps with player-targeted signals. Built-in events
do target global apps, since their first argument is clearly defined and passed. That may change in the future in case there is
a compelling argument to be able to target global apps with player scopes.
Programmers can also handle built-in events the same way as custom events, as well as triggering built-in events, which I have
have no idea why you would need that. The following snippets have the same effect:
@@ -230,11 +243,11 @@ handle_event('player_breaks_block', null);
And `signal_event` can be used as a trigger, called twice for player based built-in events
```
signal_event('player_breaks_block', player, player, block); // to target all player scoped apps
signal_event('player_breaks_block', null , player, block); // to target all global scoped apps
signal_event('player_breaks_block', null , player, block); // to target all global scoped apps and all player instances
```
or (for global only events)
or (for global events)
```
signal_event('tick') // trigger only global scoped apps with no extra arguments
signal_event('tick') // trigger all apps with a tick event
```
### `handle_event(event, callback ...)`
@@ -248,6 +261,8 @@ If extra arguments are provided, they will be appended to the argument list of t
Returns `true` if subscription to the event was successful, or `false` if it failed (for instance wrong scope for built-in event,
or incorect number of parameters for the event).
If a callback is specified as `null`, the given app (or player app instance )stops handling that event.
<pre>
foo(a) -> print(a);
handle_event('boohoo', 'foo');
@@ -260,113 +275,61 @@ handle_event('tick', _() -> foo('tick happened')); // built-in event
handle_event('tick', null) // nah, ima good, kthxbai
</pre>
In case you want to pass an event handler that is not defined in your module, please read the tips on
"Passing function references to other modules of your application" section in the `call(...)` section.
### `signal_event(event, target_player?, ... args?)`
Fires a specific event. If the event does not exist (only `handle_event` creates missing mising new events), or provided argument list
Fires a specific event. If the event does not exist (only `handle_event` creates missing new events), or provided argument list
was not matching the callee expected arguments, returns `null`,
otherwise returns number of apps notified. If `target_player` is specified and not `null` triggers a player specific event, targetting
only `player` scoped apps for that player. Apps with globals scope will not be notified even if they handle this event.
If the `target_player` is omitted or `null`, it will instead only target `global` scoped apps and skip `player` scoped.
Therefore each custom event trigger can trigger each app once, but calls to '`signal_event`' can be repeated to cover
all app scopes. Note that all built-in player events have a player as a first argument, so to trigger these events, you need to
If the `target_player` is omitted or `null`, it will target `global` scoped apps and all instances of `player` scoped apps.
Note that all built-in player events have a player as a first argument, so to trigger these events, you need to
provide them twice - once to specify the target player scope and second - to provide as an argument to the handler function.
<pre>
signal_event('player_breaks_block', player, player, block); // to target all player scoped apps
signal_event('player_breaks_block', null , player, block); // to target all global scoped apps
signal_event('tick') // triggering tick event in all loaded apps
signal_event('player_breaks_block', null , player, block); // to target all global scoped apps and all player instances
signal_event('tick') // trigger all apps with a tick event
</pre>
## Custom events example
The following example contains 4 apps, 2 of them defining a new event, `"player_farts"` triggered after 40 ticks of continuous
squatting. Note that this could call the recipient event handlers twice, since `signal_event` will be called twice, but
in this case the event is once called as a global event, and once as a player event, targeting each app once. Custom events is
a good idea to share common event detection code with one app, and using the outcome of these events in multiple places.
Obviously you would define each event handler once not twice in your app system.
In this
case here we have two ways of detecting all players squatting for more than 40 ticks - one of those apps will produce cloud particles
in an apprpriate location, and the other will produce a sound when it happens, and they both will proceed to signal the same event,
thankfully for different scopes, otherwise other apps would trigger twice.
The following example shows how you can communicate between different instances of the same player scoped app. It important to note
that signals can trigger other apps as well, assuming the name of the event matches. In this case the request name is called
`tp_request` and is triggered with a command.
```
// detector1.sc
// detecting event in a tick loop
__config() -> {'scope' -> 'global'};
global_sneaks = {};
__on_tick() -> for(player('all'),
if (_~'sneaking',
sneak_time = if (has(global_sneaks:_), tick_time()-global_sneaks:_ , global_sneaks:_=tick_time(); 0);
if (sneak_time > 20 && sneak_time < 40,
particle('cloud', pos(_) + [0, _~'height'/2, 0] - _~'look', 1, 0.1)
);
if (sneak_time == 40,
signal_event('player_farts', _, _) // triggering all player scoped apps from a global app
// tpa.sc
global_requester = null;
__config() -> {
'commands' -> {
'<player>' -> _(to) -> signal_event('tp_request', to, player()),
'accept' -> _() -> if(global_requester,
run('tp '+global_requester~'command_name');
global_requester = null
)
, // else
delete(global_sneaks:_)
)
)
},
'arguments' -> {
'player' -> {'type' -> 'players', 'single' -> true}
}
};
handle_event('tp_request', _(req) -> (
global_requester = req;
print(player(), format(
'w '+req+' requested to teleport to you. Click ',
'yb here', '^yb here', '!/tpa accept',
'w to accept it.'
));
));
```
```
// detector2.sc
// detecting events in a more appropriate way - player based and event based app
__on_player_starts_sneaking(p) ->
(
global_sneaking = tick_time();
schedule(40, 'check', p);
);
check(p) ->
if( global_sneaking && tick_time() - global_sneaking == 40,
sound('entity.shulker.shoot', pos(p), 1, 0.6, 'player');
signal_event('player_farts', null, p) // trigerring all global apps from a player scoped app
);
__on_player_stops_sneaking(p) -> (global_sneaking = false);
```
And then two other apps that meant to do something with this event. One mimics an explosion, and the other - grows crops around
the player.
```
client1.sc
__config() -> {'scope' -> 'global'};
on_fart(p, msg) ->
(
print(p+msg);
particle('explosion', pos(p));
sound('entity.generic.explode', pos(p), 1, 0.5);
);
handle_event('player_farts', 'on_fart', ' goes kaboom');
```
```
client2.sc
longsneak(p) ->
(
ppos = pos(p);
loop ( 500,
target = ppos+[rand(12),rand(8),rand(12)]-[rand(12),rand(8),rand(12)];
if (material(target) == 'plant' && ticks_randomly(target),
particle('happy_villager', target, 2, 0.4)
);
random_tick(target)
)
);
handle_event('player_farts', 'longsneak');
```
## `/script event` command
used to display current events and bounded functions. use `add_to` ro register new event, or `remove_from` to
used to display current events and bounded functions. use `add_to` to register a 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.
that handle specific built-in events will be automatically bounded, and unbounded when script is unloaded.
+8
View File
@@ -28,6 +28,14 @@ an inventory, all API functions 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.
### item_list(tag?)
With no arguments, returns a list of all items in the game. With an item tag provided, list items matching the tag, or `null` if tag is not valid.
### item_tags(item, tag?)
Returns list of tags the item belongs to, or, if tag is provided, `true` if an item maches the tag, `false` if it doesn't and `null` if that's not a valid tag
### `stack_limit(item)`
Returns number indicating what is the stack limit for the item. Its typically 1 (non-stackable), 16 (like buckets),
+35 -9
View File
@@ -6,7 +6,9 @@ Here is the gist of the Minecraft related functions. Otherwise the CarpetScript
## App structure
The main delivery method for scarpet programs into the game is in the form of apps in `*.sc` files located in the world `scripts`
folder. When loaded (via `/script load` command, etc.), the game will run the content of the app once, regardless of its scope
folder, flat. In singleplayer, you can also save apps in `.minecraft/config/carpet/scripts` for them to be available in any world,
and here you can actually organize them in folders.
When loaded (via `/script load` command, etc.), the game will run the content of the app once, regardless of its scope
(more about the app scopes below), without executing of any functions, unless called directly, and with the exception of the
`__config()` function, if present, which will be executed once. Loading the app will also bind specific
events to the event system (check Events section for details).
@@ -32,15 +34,14 @@ the app state and all players interactions run in the same context, sharing defi
explicitly keyed with players, player names, uuids, etc.
Even for `'player'` scoped apps, you can access specific player app with with commandblocks using
`/execute as <player> run script in <app> run ...`.
To access global/server state for a player app, you need to disown the command from any player,
To access global/server state for a player app, which you shouldn't do, you need to disown the command from any player,
so either use a command block, or any
arbitrary entity: `/execute as @e[type=bat,limit=1] run script in <app> globals` for instance, however
running anything in the global scope for a `'player'` scoped app is not recommended.
* `'stay_loaded'`: defaults to `false`. If true, and `/carpet scriptsAutoload` is turned on, the following apps will
running anything in the global scope for a `'player'` scoped app is not intended.
* `'stay_loaded'`: defaults to `true`. If true, and `/carpet scriptsAutoload` is turned on, the following apps will
stay loaded after startup. Otherwise, after reading the app the first time, and fetching the config, server will drop them down.
This is to allow to store multiple apps on the server/world and selectively decide which one should be running at
startup. WARNING: all apps will run once at startup anyways, so be aware that their actions that are called
statically, will be performed once anyways.
WARNING: all apps will run once at startup anyways, so be aware that their actions that are called
statically, will be performed once anyways. Only apps present in the world's `scripts` folder will be autoloaded.
* `'legacy_command_type_support'` - if `true`, and the app defines the legacy command system via `__command()` function,
all parameters of command functions will be interpreted and used using brigadier / vanilla style argument parser and their type
will be inferred from their names, otherwise
@@ -50,9 +51,20 @@ conflicts and ambiguities between different paths of execution. While ambiguous
and they tend to execute correctly, the suggestion support works really poorly in these situations and scarpet
will warn and prevent such apps from loading with an error message. If `allow_command_conflicts` is specified and
`true`, then scarpet will load all provided commands regardless.
* `'command_permission'` - indicates a custom permission to run the command. It can either be a number indicating
permission level (from 1 to 4) or a string value, one of: `'all'` (default), `'ops'` (default opped player with permission level of 2),
`'server'` - command accessible only through the server console and commandblocks, but not in chat, `'players'` - opposite
of the former, allowing only use in player chat. It can also be a function (lambda function or function value, not function name)
that takes 1 parameter, which represents the calling player, or `'null'` if the command represents a server call.
The function will prevent the command from running if it evaluates to `false`.
Please note, that Minecraft evaluates eligible commands for players when they join, or on reload/restart, so if you use a
predicate that is volatile and might change, the command might falsely do or do not indicate that it is available to the player,
however player will always be able to type it in and either succeed, or fail, based on their current permissions.
Custom permission applies to legacy commands with `'legacy_command_type_support'` as well
as for the custom commands defined with `'commands'`, see below.
* `'arguments'` - defines custom argument types for legacy commands with `'legacy_command_type_support'` as well
as for the custom commands defined with `'commands'`, see below
* `'commands'` - defines custom commands for the app to be executed with `/<app>` command, see below
as for the custom commands defined with `'commands'`, see below.
* `'commands'` - defines custom commands for the app to be executed with `/<app>` command, see below.
## Custom app commands
@@ -205,6 +217,20 @@ Here is a list of built-in types, with their return value formats, as well as a
* `'pos'`: block position as a triple of coordinates. Customized with `'loaded'`, if true requiring the position
to be loaded.
* `'block'`: a valid block state wrapped in a block value (including block properties and data)
* `'blockpredicate`': returns a 4-tuple indicating conditions of a block to match: block name, block tag,
map of required state properties, and tag to match. Either block name or block tag are `null` but not both.
Property map is always specified, but its empty for no conditions, and matching nbt tag can be `null` indicating
no requirements. Technically the 'all-matching' predicate would be `[null, null, {}, null]`, but
block name or block tag is always specified. One can use the following routine to match a block agains this predicate:
```
block_to_match = block(x,y,z);
[block_name, block_tag, properties, nbt_tag] = block_predicate;
(block_name == null || block_name == block_to_match) &&
(block_tag == null || block_tags(block_to_match, block_tag)) &&
all(properties, block_state(block_to_match, _) == properties:_) &&
(!tag || tag_matches(block_data(block_to_match), tag))
```
* `'teamcolor'`: name of a team, and an integer color value of one of 16 valid team colors.
* `'columnpos'`: a pair of x and z coordinates.
* `'dimension'`: string representing a valid dimension in the world.
+59
View File
@@ -105,3 +105,62 @@ team_property('admin','seeFriendlyInvisibles',true) Make all players in 'a
team_property('admin','deathMessageVisibility','hideForOtherTeams') Make all players in 'admin' see other admins even when invisible
```
## `bossbar()`, `bossbar(id)`, `bossbar(id,property,value?)`
Manage bossbars just like with the `/bossbar` command.
Without any arguments, returns a list of all bossbars.
When an id is specified, creates a bossbar with that `id` and returns the id of the created bossbar.
Bossbar ids need a namespace and a name. If no namespace is specified, it will automatically use `minecraft:`.
In that case you should keep track of the bossbar with the id that `bossbar(id)` returns, because a namespace may be added automatically.
If the id was invalid (for example by having more than one colon), returns `null`.
If the bossbar already exists, returns `false`.
`bossbar('timer') => 'minecraft:timer'` (Adds the namespace `minecraft:` because none is specified)
`bossbar('scarpet:test') => 'scarpet:test'` In this case there is already a namespace specified
`bossbar('foo:bar:baz') => null` Invalid identifier
`bossbar(id,property)` is used to query the `property` of a bossbar.
`bossbar(id,property,value)` can modify the `property` of the bossbar to a specified `value`.
Available properties are:
* color: can be `'pink'`, `'blue'`, `'red'`, `'green'`, `'yellow'`, `'purple'` or `'white'`
* style: can be `'progress'`, `'notched_6'`, `'notched_10'`, `'notched_12'` or `'notched_20'`
* value: value of the bossbar progress
* max: maximum value of the bossbar progress, by default 100
* name: Text to display above the bossbar, supports formatted text
* visible: whether the bossbar is visible or not
* players: List of players that can see the bossbar
* add_player: add a player to the players that can see this bossbar, this can only be used for modifying (`value` must be present)
* remove: remove this bossbar, no `value` required
```
bossbar('script:test','style','notched_12')
bossbar('script:test','value',74)
bossbar('script:test','name',format('rb Test')) -> Change text
bossbar('script:test','visible',false) -> removes visibility, but keeps players
bossbar('script:test','players',player('all')) -> Visible for all players
bossbar('script:test','players',player('Steve')) -> Visible for Steve only
bossbar('script:test','players',null) -> Invalid player, removing all players
bossbar('script:test','add_player',player('Alex')) -> Add Alex to the list of players that can see the bossbar
bossbar('script:test','remove') -> remove bossbar 'script:test'
for(bossbar(),bossbar(_,'remove')) -> remove all bossbars
```
+7 -5
View File
@@ -8,13 +8,15 @@ to simulate running commands in a different scope.
# `/script load / unload <app> (global?)`, `/script in <app>` commands
`load / unload` commands allow for very conventient way of writing your code, providing it to the game and
distribute with your worlds without the need of use of commandblocks. Just place your scarpet code in the
/scripts folder of your world files and make sure it ends with `.sc` extension. The good thing about editing that
code is that you can no only use normal editing without the need of marking of newlines,
`load / unload` commands allow for very convenient way of writing your code, providing it to the game and
distribute with your worlds without the need of use of commandblocks. Just place your Scarpet code in the
`/scripts` folder of your world files and make sure it ends with `.sc` extension. In singleplayer, you can
also save your scripts in `.minecraft/config/carpet/scripts` to make them available in any world.
The good thing about editing that code is that you can not only use normal editing without the need of marking of newlines,
but you can also use comments in your code.
a comment is anything that starts with a double slash, and continues to the end of the line:
A comment is anything that starts with a double slash, and continues to the end of the line:
<pre>
foo = 1;
+2
View File
@@ -215,6 +215,8 @@ 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]
range(-0.3, 0.3, 0.1) => [-0.3, -0.2, -0.1, 0, 0.1, 0.2]
range(0.3, -0.3, -0.1) => [0.3, 0.2, 0.1, -0, -0.1, -0.2]
</pre>
## Map operations
@@ -135,7 +135,7 @@ foo(... x) -> ... # all arguments for foo are included in the list
### `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,
them in the current app. This includes other symbols imported by these modules. Scarpet supports circular 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.
@@ -144,9 +144,57 @@ issues, and list contents of libraries.
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
functions as arguments and call them with `call` internally. Since function definitions return the defined
function, they can be defined in place as anonymous functions.
#### Passing function references to other modules of your application
In case a function is defined by its name, Scarpet will attempt to resolve its definition in the given module and its imports,
meaning if the call is in a imported library, and not in the main module of your app, and that function is not visible from the
library perspective, but in the app, it won't be call-able. In case you pass a function name to a separate module in your app,
it should import back that method from the main module for visibility.
Check an example of a problematic code of a library that expects a function value as a passed argument and how it is called in
the parent app:
```
//app.sc
import('lib', 'callme');
foo(x) -> x*x;
test() -> callme('foo' , 5);
```
```
//lib.scl
callme(fun, arg) -> call(fun, arg);
```
In this case `'foo'` will fail to dereference in `lib` as it is not visible by name. In tightly coupled modules, where `lib` is just
a component of your `app` you can use circular import to acknowledge the symbol from the other module (pretty much like
imports in Java classes), and that solves the issue but makes the library dependent on the main app:
```
//lib.scl
import('app','foo');
callme(fun, arg) -> call(fun, arg);
```
You can circumvent that issue by explicitly dereferencing the local function where it is used as a lambda argument created
in the module in which the requested function is visible:
```
//app.sc
import('lib', 'callme');
foo(x) -> x*x;
test() -> callme(_(x) -> foo(x), 5);
```
```
//lib.scl
callme(fun, arg) -> call(fun, arg);
```
Or by passing an explicit reference to the function, instead of calling it by name:
```
//app.sc
import('lib', 'callme');
global_foohandler = (foo(x) -> x*x);
test() -> callme(global_foohandler, 5);
```
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
+4 -3
View File
@@ -151,9 +151,10 @@ 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
your code in apps (files with `.sc` extension that can be placed inside `/scripts` folder in the world files
or as a globally available app in singleplayer in the `.minecraft/config/carpet/scripts` folder and loaded
as a Scarpet app with the 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
+3
View File
@@ -122,6 +122,9 @@ a = 3; task_thread('temp', _(outer(a), b) -> foo(a,b), 5)
=> Another example of running the same thing passing arguments using closure over anonymous function as well as passing a parameter.
</pre>
In case you want to create a task based on a function that is not defined in your module, please read the tips on
"Passing function references to other modules of your application" section in the `call(...)` section.
### `sleep()` `sleep(timeout)`, `sleep(timeout, close_expr)`
+9 -3
View File
@@ -12,8 +12,10 @@ block_tick
block_tags
blocks_daylight
blocks_movement
bossbar
brightness
chunk_tickets
convert_date
crafting_remaining_item
create_marker
current_dimension
@@ -51,9 +53,12 @@ inventory_remove
inventory_set
inventory_size
item_category
item_list
item_tags
last_tick_times
light
liquid
list_files
load_app_data
loaded
loaded_status
@@ -92,10 +97,10 @@ scoreboard_remove
scoreboard_display
tag_matches
team_add
team_list
team_remove
team_leave
team_list
team_property
team_remove
read_file
see_sky
set
@@ -121,8 +126,9 @@ ticks_randomly
top
transparent
update
unix_time
view_distance
volume
without_updates
world_time
write_file
write_file
@@ -58,15 +58,19 @@
structure_eligibility structures structure_references set_structure reset_chunk reload_chunk custom_dimension
add_chunk_ticket
convert_date unix_time
display_title
scoreboard scoreboard_add scoreboard_remove scoreboard_display
team_add team_list team_remove team_leave team_property
bossbar
player spawn entity_id entity_list entity_area entity_selector query modify entity_event entity_load_handler entity_types
stack_limit item_category recipe_data crafting_remaining_item
item_list item_tags stack_limit item_category recipe_data crafting_remaining_item
inventory_size inventory_has_items inventory_get inventory_set inventory_find inventory_remove drop_item
@@ -80,7 +84,7 @@
plop harvest destroy schedule nbt draw_shape create_marker remove_all_markers
load_app_data store_app_data read_file write_file delete_file
load_app_data store_app_data read_file write_file delete_file list_files
escape_nbt parse_nbt encode_nbt tag_matches statistic
</Keywords>
<Keywords name="Keywords3">euler pi null true false</Keywords>