Merge branch 'master' into scoreboard-criterion-mod
This commit is contained in:
63 files changed
+2386
-797
No files matched your search
@@ -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.
|
||||
@@ -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?)`
|
||||
|
||||
@@ -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)`
|
||||
|
||||
@@ -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
@@ -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.
|
||||
@@ -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),
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user