package carpet.script; import carpet.CarpetServer; import carpet.fakes.MinecraftServerInterface; import carpet.fakes.BiomeArrayInterface; import carpet.fakes.StatTypeInterface; import carpet.helpers.FeatureGenerator; import carpet.mixins.ChunkTicketManager_scarpetMixin; import carpet.mixins.ServerChunkManager_scarpetMixin; import carpet.script.Fluff.TriFunction; import carpet.script.bundled.Module; import carpet.script.exception.CarpetExpressionException; import carpet.script.exception.ExitStatement; import carpet.script.exception.ExpressionException; import carpet.script.exception.InternalExpressionException; import carpet.CarpetSettings; import carpet.script.value.BlockValue; import carpet.script.value.EntityValue; import carpet.script.value.FunctionValue; import carpet.script.value.LazyListValue; import carpet.script.value.ListValue; import carpet.script.value.NBTSerializableValue; import carpet.script.value.NullValue; import carpet.script.value.NumericValue; import carpet.script.value.StringValue; import carpet.script.value.ThreadValue; import carpet.script.value.Value; import carpet.utils.BlockInfo; import carpet.utils.Messenger; import com.google.common.collect.Sets; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.minecraft.block.BarrierBlock; import net.minecraft.block.BedrockBlock; import net.minecraft.block.Block; import net.minecraft.block.BlockPlacementEnvironment; import net.minecraft.block.BlockState; import net.minecraft.block.CommandBlock; import net.minecraft.block.JigsawBlock; import net.minecraft.block.StructureBlock; import net.minecraft.block.entity.BlockEntity; import net.minecraft.client.network.packet.GuiSlotUpdateS2CPacket; import net.minecraft.client.network.packet.PlaySoundIdS2CPacket; import net.minecraft.command.arguments.ItemStackArgument; import net.minecraft.command.arguments.ParticleArgumentType; import net.minecraft.enchantment.Enchantments; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LightningEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.SpawnType; import net.minecraft.entity.decoration.ArmorStandEntity; import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; import net.minecraft.particle.ParticleEffect; import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ChunkTicket; import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.BlockSoundGroup; import net.minecraft.sound.SoundCategory; import net.minecraft.stat.Stat; import net.minecraft.stat.StatType; import net.minecraft.state.StateManager; import net.minecraft.state.property.Property; import net.minecraft.text.LiteralText; import net.minecraft.util.Clearable; import net.minecraft.util.Identifier; import net.minecraft.util.InvalidIdentifierException; import net.minecraft.util.SortedArraySet; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.EulerAngle; import net.minecraft.util.math.Vec3d; import net.minecraft.util.registry.Registry; import net.minecraft.world.Heightmap; import net.minecraft.world.LightType; import net.minecraft.world.World; import net.minecraft.world.biome.Biome; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkStatus; import net.minecraft.world.chunk.WorldChunk; import net.minecraft.world.dimension.DimensionType; import net.minecraft.loot.context.LootContext; import net.minecraft.loot.context.LootContextParameters; import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.function.BiFunction; import java.util.function.Predicate; import java.util.stream.Collectors; import static java.lang.Math.abs; import static java.lang.Math.max; import static java.lang.Math.min; import static java.lang.Math.sqrt; /** *
scarpet language add-ons and commandsHere is the gist of the Minecraft related functions. Otherwise the CarpetScript could live without Minecraft.
*One note, which is important is that most of the calls for entities and blocks
* would refer to the current dimension of the caller, meaning, that if we for example
* list all the players using player('all') function, if a player is in the
* other dimension, calls to entities and blocks around that player would point incorrectly.
* Moreover, running commandblocks in the spawn chunks would mean that commands will always
* refer to the overworld blocks and entities.
* In case you would want to run commands across all dimensions, just run three of them, using
* /execute in overworld/the_nether/the_end run script run ... and query
* players using player('*'), which only returns players in current dimension, or use
* in_dimension(expr) function.
script stop/script resume command
* /script stop allows to stop execution of any script currently running that calls the
* game_tick() function which
* allows the game loop to regain control of the game and process other commands. This will also make sure
* that all current and future programs will stop their execution. Execution of all programs will be
* prevented until /script resume command is called.
*
Lets look at the following example. This is a program computes Fibonacci number in a recursive manner:
*
* fib(n) -> if(n<3, 1, fib(n-1)+fib(n-2) ); fib(8)
*
* That's really bad way of doing it, because the higher number we need to compute the compute requirements will rise
* exponentially with n. It takes a little over 50 milliseconds to do fib(24), so above one tick,
* but about a minute to do fib(40). Calling fib(40) will not only freeze the game, but also you woudn't be able to interrupt
* its execution. We can modify the script as follows
fib(n) -> ( game_tick(50); if(n<3, 1, fib(n-1)+fib(n-2) ) ); fib(40)*
But this would never finish as such call would finish after ~ 2^40 ticks. To make our computations
* responsive, yet able to respond to user interactions, other commands, as well as interrupt execution,
* we could do the following:
fib(n) -> ( if(n==23, game_tick(50) ); if(n<3, 1, fib(n-1)+fib(n-2) ) ); fib(40)*
This would slow down the computation of fib(40) from a minute to two, but allows the game to keep continue running
* and be responsive to commands, using about half of each tick to advance the computation.
* Obviously depending on the problem, and available hardware, certain things can take
* more or less time to execute, so portioning of work with calling gametick should be balanced in each
* case separately
block(x, y, z), block(l(x,y,z)), block(state)Returns either a block from specified location, or block with a specific state
* (as used by /setblock command), so allowing for block properties, block entity data etc.
* Blocks otherwise can be referenced everywhere by its simple string name, but its only used in its default state
* block('air') => air
* block('iron_trapdoor[half=top]') => iron_trapdoor
* block(0,0,0) == block('bedrock') => 1
* block('hopper[facing=north]{Items:[{Slot:1b,id:"minecraft:slime_ball",Count:16b}]}') => hopper
*
* Retrieving a block with block function has also a side-effect of evaluating its current state and data.
* so if you use it later it will reflect block state and data of the block that was when block was called, rather than
* when it was used. Block values passed in various places like scan functions, etc, are not fully evaluated
* unless its properties are needed. This means that if the block at the location changes before its queried in the program
* this might result in getting the later state, which might not be desired. Consider the following example:
* set(10,10,10,'stone');
* scan(10,10,10,0,0,0, b = _);
* set(10,10,10,'air');
* print(b); // 'air', block was remembered 'lazily', and evaluated by `print`, when it was already set to air
*
* set(10,10,10,'stone');
* scan(10,10,10,0,0,0, b = block(_));
* set(10,10,10,'air');
* print(b); // 'stone', block was evaluated 'eagerly' but call to `block`
*
*
* All the functions below can be used with block value, queried with coord triple, or 3-long list.
* All pos in the functions referenced below refer to either method of passing block position
set(pos, block, property?, value?, ...)First part of the set function is either a coord triple, list of three numbers, or other block
* with coordinates. Second part, block is either block value as a result of block() function
* string value indicating the block name, and optional property - value pairs for extra block properties.
* If block is specified only by name, then if a destination block is the same the set operation
* is skipped, otherwise is executed, for other potential extra properties
The returned value is either the block state that has been set, or false if block setting was skipped
* set(0,5,0,'bedrock') => bedrock
* set(l(0,5,0), 'bedrock') => bedrock
* set(block(0,5,0), 'bedrock') => bedrock
* scan(0,5,0,0,0,0,set(_,'bedrock')) => 1
* set(pos(players()), 'bedrock') => bedrock
* set(0,0,0,'bedrock') => 0 // or 1 in overworlds generated in 1.8 and before
* scan(0,100,0,20,20,20,set(_,'glass'))
* // filling the area with glass
* scan(0,100,0,20,20,20,set(_,block('glass')))
* // little bit faster due to internal caching of block state selectors
* b = block('glass'); scan(0,100,0,20,20,20,set(_,b))
* // yet another option, skips all parsing
* set(x,y,z,'iron_trapdoor') // sets bottom iron trapdoor
* set(x,y,z,'iron_trapdoor[half=top]') // Incorrect. sets bottom iron trapdoor - no parsing of properties
* set(x,y,z,'iron_trapdoor','half','top') // correct - top trapdoor
* set(x,y,z,block('iron_trapdoor[half=top]')) // also correct, block() provides extra parsing
* set(x,y,z,'hopper[facing=north]{Items:[{Slot:1b,id:"minecraft:slime_ball",Count:16b}]}') // extra block data
*
* place_item(item, pos, facing?, sneak?)Places a given item in the world like it was placed by a player. Item names are default minecraft item name, * less the minecraft prefix. Default facing is 'up', but there are other options: 'down', 'north', 'east', * 'south', 'west', but also there are other secondary directions important for placement of blocks like stairs, doors, etc. * Try experiment with options like 'north-up' which is placed facing north with cursor pointing to the upper part of the block, * or 'up-north', which means a block placed facing up (player looking down) and placed smidge away of the block center * towards north. Optional sneak is a boolean indicating if a player would be sneaking while placing the block - * this option only affects placement of chests and scaffolding at the moment. * Returns true if placement was successful, false otherwise.
*
* place_item('stone',x,y,z) // places a stone block on x,y,z block
* place_item('piston,x,y,z,'down') // places a piston facing down
* place_item('carrot',x,y,z) // attempts to plant a carrot plant. Returns true if could place carrots at that position.
*
* biome(pos)returns biome at that block position.
*set_biome(pos, biome_name)changes biome at that block position.
*update(pos)Causes a block update at position.
*block_tick(pos)Causes a block to tick at position.
*random_tick(pos)Causes a random tick at position.
*destroy(pos), destroy(pos, -1), destroy(pos, <N>)Destroys the block like it was mined by a player. Add -1 for silk touch, and positive number for fortune level. * This function, unlike harvest, will affect all kinds of blocks
*harvest(player, pos)Causes a block to be harvested by a specified player entity. Honors player item enchantments, as well as damages the * tool if applicable. If the entity is not a valid player, no block gets destroyed. If a player is not allowed to * break that block, a block doesn't get destroyed either.
* *pos(block), pos(entity)Returns a triple of coordinates of a specified block or entity. Technically entities are queried with
* query function and the same can be achieved with query(entity,'pos'), but for simplicity
* pos allows to pass all positional objects.
* pos(block(0,5,0)) => l(0,5,0)
* pos(players()) => l(12.3, 45.6, 32.05)
* pos(block('stone')) => Error: Cannot fetch position of an unrealized block
*
* pos_offset(pos, direction, amount?)Returns a coords triple that is offset in a specified direction by amount of blocks.
* The default offset amount is 1 block. To offset into opposite facing, use negative numbers for the amount.
*
* pos_offset(block(0,5,0), 'up', 2) => l(0,7,0)
* pos_offset(l(0,5,0), 'up', -2 ) => l(0,3,0)
*
* block_properties(pos)Returns a list of available block properties for a particular block. If a block has no properties, returns an empty list.
*property(pos, name)Returns property of block at pos, or specified by block argument. If a block doesn't
* have that property, null value is returned. Returned values are always strings. It is expected from
* the user to know what to expect and convert values to numbers using number() function or booleans
* using bool() function.
* set(x,y,z,'iron_trapdoor','half','top'); property(x,y,z,'half') => top
* set(x,y,z,'air'); property(x,y,z,'half') => null
* property(block('iron_trapdoor[half=top]'),'half') => top
* property(block('iron_trapdoor[half=top]'),'powered') => false
* bool(property(block('iron_trapdoor[half=top]'),'powered')) => 0
*
* block_data(pos)Return NBT string associated with specific location, or null if the block does not carry block data. * Can be currently used to match specific information from it, or use it to copy to another block
*
* block_data(x,y,z) => '{TransferCooldown:0,x:450,y:68, ... }'
*
* solid(pos)Boolean function, true if the block is solid
*air(pos)Boolean function, true if a block is air.... or cave air... * or void air.... or any other air they come up with.
*liquid(pos)Boolean function, true if the block is liquid, or liquidlogged
*flammable(pos)Boolean function, true if the block is flammable
*transparent(pos)Boolean function, true if the block is transparent
*opacity(pos)Numeric, returning opacity level of a block
*blocks_daylight(pos)Boolean function, true if the block blocks daylight
*emitted_light(pos)Numeric, returning light level emitted from block
*light(pos)Integer function, returning total light level at position
*block_light(pos)Integer function, returning block light at position. From torches and other light sources.
*sky_light(pos)Numeric function, returning sky light at position. From the sky access.
*see_sky(pos)Boolean function, returning true if the block can see sky.
*hardness(pos)Numeric function, indicating hardness of a block.
*blast_resistance(pos)Numeric function, indicating blast_resistance of a block.
*top(type, pos)Returns the Y value of the topmost block at given x, z coords (y value of a block is not important), according to the
* heightmap specified by type. Valid options are:
light: topmost light blocking block (1.13 only)motion: topmost motion blocking blockterrain: topmost motion blocking block except leavesocean_floor: topmost non-water blocksurface: topmost surface block
* top('motion', x, y, z) => 63
* top('ocean_floor', x, y, z) => 41
*
* loaded(pos)Boolean function, true if the block is accessible forthe game mechanics.
* Normally scarpet doesn't check if operates on
* loaded area - the game will automatically load missing blocks. We see this as advantage.
* Vanilla fill/clone commands only check the specified corners for loadness.
To check if block is truly loaded, I mean in memory, use generation_status(x) != null, as
* chunks can still be loaded outside of the playable area, just are not used any of the game mechanics processes.
* loaded(pos(players())) => 1
* loaded(100000,100,1000000) => 0
*
* (Deprecated) loaded_ep(pos)Boolean function, true if the block is loaded and entity processing, as per 1.13.2
*Deprecated as of scarpet 1.6, use loaded_status(x) > 0, or
* just loaded(x) with the same effect
loaded_status(pos)Returns loaded status as per new 1.14 chunk ticket system, 0 for inaccessible, 1 for border chunk, * 2 for ticking, 3 for entity ticking
*generation_status(pos), generation_status(pos, true)Returns generation status as per new 1.14 chunk ticket system. Can return any value from several available
* but chunks can only be valid in a few states: full, features, liquid_carvers,
* and structure_starts. Returns null if the chunk is not in memory unless called with optional
* true.
suffocates(pos)Boolean function, true if the block causes suffocation.
*power(pos)Numeric function, returning redstone power level at position.
*ticks_randomly(pos)Boolean function, true if the block ticks randomly.
*blocks_movement(pos)Boolean function, true if block at position blocks movement.
*block_sound(pos)Returns the name of sound type made by the block at position. One of:
*wood gravel grass stone metal glass wool sand snow ladder anvil slime sea_grass coral material(pos)Returns the name of material of the block at position. very useful to target a group of blocks. One of:
* air void portal carpet plant water_plant vine sea_grass water bubble_column lava snow_layer fire redstone_bits cobweb redstone_lamp clay dirt grass packed_ice sand sponge wood wool tnt leaves glass ice cactus stone iron snow anvil barrier piston coral gourd dragon_egg cake map_colour(pos)Returns the map colour of a block at position. One of:
* air grass sand wool tnt ice iron foliage snow clay dirt stone water wood quartz adobe magenta light_blue yellow lime pink gray light_gray cyan purple blue brown green red black gold diamond lapis emerald obsidian netherrack white_terracotta orange_terracotta magenta_terracotta light_blue_terracotta yellow_terracotta lime_terracotta pink_terracotta gray_terracotta light_gray_terracotta cyan_terracotta purple_terracotta blue_terracotta brown_terracotta green_terracotta red_terracotta black_terracotta Most functions in this category require inventory as the first argument. Inventory could be specified by
* an entity, or a block, or position (three coordinates) of a potential block with inventory. Player enderchest inventory
* require two arguments, keyword 'enderchest', followed by the player entity argument.
* If the entity or a block doesn't
* have an inventory, they typically do nothing and return null.
Most items returned are in the form of * a triple of item name, count, and nbt or the extra data associated with an item. * Manipulating of the nbt data can be costly, but retrieving them from the tuple to match other aspects is cheap
*stack_limit(item)Returns number indicating what is the stack limit for the item. Its typically 1 (non-stackable), * 16 (like buckets), or 64 - rest. It is recommended to consult this, as other inventory API functions * ignore normal stack limits, and it is up to the programmer to keep it at bay. As of 1.13, game checks for negative * numbers and setting an item to negative is the same as empty.
*
* stack_limit('wooden_axe') => 1
* stack_limit('ender_pearl') => 16
* stack_limit('stone') => 64
*
* item_category(item)Returns the string representing the category of a given item, like `building_blocks`, `combat`, or `tools`.
*
* item_category('wooden_axe') => tools
* item_category('ender_pearl') => misc
* item_category('stone') => building_blocks
*
* inventory_size(inventory)Returns the size of the inventory for the entity or block in question. Returns null if the block or entity * don't have an inventory
*
* inventory_size(player()) => 41
* inventory_size('enderchest', player()) => 27 // enderchest
* inventory_size(x,y,z) => 27 // chest
* inventory_size(block(pos)) => 5 // hopper
*
* inventory_has_items(inventory)Returns true, if the inventory is not empty, false if it is empty, and null, if its not an inventory.
*
* inventory_has_items(player()) => true
* inventory_has_items(x,y,z) => false // empty chest
* inventory_has_items(block(pos)) => null // stone
*
* inventory_get(inventory, slot)Returns the item in the corresponding inventory slot, or null if slot empty or inventory is invalid. * You can use negative numbers to indicate slots counted from 'the back'.
*
* inventory_get(player(), 0) => null // nothing in first hotbar slot
* inventory_get(x,y,z, 5) => ['stone', 1, {}]
* inventory_get(player(), -1) => ['diamond_pickaxe', 1, {Damage:4}] // slightly damaged diamond pick in the offhand
*
*
* inventory_set(inventory, slot, count, item?, nbt?) Modifies or sets a stack in inventory. specify count 0 to empty the slot. * If item is not specified, keeps existing item, just modifies the count. If item is provided - replaces current item. * If nbt is provided - adds a tag to the stack at slot. Returns previous stack in that slot.
*
* inventory_set(player(), 0, 0) => ['stone', 64, {}] // player had a stack of stone in first hotbar slot
* inventory_set(player(), 0, 6) => ['diamond', 64, {}] // changed stack of diamonds in player slot to 6
* inventory_set(player(), 0, 1, 'diamond_axe','{Damage:5}') => null //added slightly damaged pick to first player slot
*
*
* inventory_find(inventory, item, start_slot?, ), inventory_find(inventory, null, start_slot?) Finds the first slot with a corresponding item in the inventory, or if queried with null: the first empty slot. * Returns slot number if found, or null otherwise. Optional start_slot argument allows to skip all preceeding slots * allowing for efficient (so not slot-by-slot) inventory search for items.
*
* inventory_find(player(), 'stone') => 0 // player has stone in first hotbar slot
* inventory_find(player(), null) => null // player's inventory has no empty spot
* while( (slot = inventory_find(p, 'diamond', slot)) != null, 41, drop_item(p, slot) )
* // spits all diamonds from player inventory wherever they are
* inventory_drop(x,y,z, 0) => 64 // removed and spawned in the world a full stack of items
*
*
* inventory_remove(inventory, item, amount?) Removes amount (defaults to 1) of item from inventory. If the inventory doesn't have the defined amount, nothing * happens, otherwise the given amount of items is removed wherever they are in the inventory. Returns boolean whether * the removal operation was successful. Easiest way to remove a specific item from player inventory without specifying * the slot.
*
* inventory_remove(player(), 'diamond') => 1 // removed diamond from player inventory
* inventory_remove(player(), 'diamond', 100) => 0 // player doesn't have 100 diamonds, nothing happened
*
*
* drop_item(inventory, slot, amount?, )Drops the items from indicated inventory slot, like player that Q's an item or villager, that exchanges food. * You can Q items from block inventories as well. default amount is 0 - which is all from the slot. NOTE: hoppers are quick * enough to pick all the queued items from their inventory anyways. * Returns size of the actual dropped items.
*
* inventory_drop(player(), 0, 1) => 1 // Q's one item on the ground
* inventory_drop(x,y,z, 0) => 64 // removed and spawned in the world a full stack of items
*
* Entities have to be fetched before using them. Entities can also change their state between calls to the script
* if game happens either in between separate calls to the programs, or if the program calls game_tick
* on its own. In this case - entities would need to be re-fetched, or the code should account for entities getting dead
player(), player(type), player(name)
* With no arguments, it returns the calling player or the player closest to the caller. Note that the main context
* will receive p variable pointing to this player. With type or name specified
* it will try first to match a type, returning a list of players matching a type, and if this fails, will assume its
* player name query retuning player with that name, or null if no player was found.
* With 'all', list of all players in the game, in all dimensions, so end user needs to be cautious, that
* you might be referring to wrong blocks and entities around the player in question.
* WIth type = '*' it returns all players in caller dimension, 'survival' returns all survival
* and adventure players, 'creative' returns all creative players, 'spectating' returns all spectating
* players, and '!spectating', all not-spectating players. If all fails,
* with name, the player in question, if is logged in.
entity_id(uuid), entity_id(id)Fetching entities wither by their ID obtained via entity ~ 'id', which is unique
* for a dimension and current world run, or by UUID, obtained via entity ~ 'uuid'.
* It returns null if no such entity
* is found. Safer way to 'store' entities between calls, as missing entities will be returning null.
* Both calls using UUID or numerical ID are O(1), but obviously using UUIDs takes more memory and compute.
entity_list(type)Returns global lists of entities in the current dimension of a specified type. Currently the following selectors are available:
**: alllivingitemsplayers!playersentity_area(type, cx, cy, cz, dx, dy, dz)Returns entities of a specified type in an area centered on cx, cy, cz and
* at most dx, dy, dz blocks away from the center point. Uses same selectors as entities_list
entity_selector(selector)Returns entities satisfying given vanilla entity selector. Most complex among all the methods of selecting * entities, but the most capable. Selectors are cached so should be as fast as other methods of selecting entities.
* *spawn(name, pos, nbt?)Spawns and places an entity in world, like /summon vanilla command.
* Requires a position to spawn, and optional extra nbt data to merge with the entity. What makes it different from calling
* run('summon ...'), is the fact that you get the entity back as a return value, which is swell.
Unlike with blocks, that use plethora of vastly different querying functions, entities are queried with
* query function and altered via modify function. Type of information needed or
* values to be modified are different for each call
Using ~ (in) operator is an alias for query. Especially useful if a statement has
* no arguments, which in this case can be radically simplified
* query(p, 'name') <=> p ~ 'name' // much shorter and cleaner
* query(p, 'holds', 'offhand') <=> p ~ l('holds', 'offhand') // not really but can be done
*
* query(e,'removed')Boolean. True if the entity is removed
*query(e,'id')Returns numerical id of the entity. Most efficient way to keep track of entites in a script. Ids are only unique * within current game session (ids are not preserved between restarts), and dimension (each dimension has its own ids * which can overlap.
*query(e,'uuid')Returns UUID (unique id) of the entity. Can be used to access entities with the other vanilla commands and remains unique * regardless of the dimension, and is preserved between game restarts. * Apparently players cannot be accessed via UUID, but name instead.
*
* map(entities_area('*',x,y,z,30,30,30),run('kill '+query(_,'id'))) // doesn't kill the player
*
* query(e,'pos')Triple of entity position
*query(e,'location')Quin-tuple of entity position (x, y, and z coords), and rotation (yaw, pitch)
*query(e,'x'), query(e,'y'), query(e,'z')Respective entity coordinate
*query(e,'pitch'), query(e,'yaw')Pitch and Yaw or where entity is looking.
*query(e,'look')Returns a 3d vector where the entity is looking.
*query(e,'motion')Triple of entity motion vector, l(motion_x, motion_y, motion_z)
query(e,'motion_x'), query(e,'motion_y'), query(e,'motion_z')Respective component of the motion vector
*query(e,'name'), query(e,'custom_name'), query(e,'type')String of entity name
*
* query(e,'name') => Leatherworker
* query(e,'custom_name') => null
* query(e,'type') => villager
*
* query(e,'is_riding')Boolean. True if riding another entity.
*query(e,'is_ridden')Boolean. True if another entity is riding it.
*query(e,'passengers')List of entities riding the entity.
*query(e,'mount')Entity that e rides.
query(e,'tags')List of entity tags.
*query(e,'has_tags',tag)Boolean, True if the entity is marked with tag.
query(e,'is_burning')Boolean, True if the entity is burning.
*query(e,'fire')Number of remaining ticks of being on fire.
*query(e,'silent')Boolean, True if the entity is silent.
*query(e,'gravity')Boolean, True if the entity is affected by gravity, like most entities do.
*query(e,'immune_to_fire')Boolean, True if the entity is immune to fire.
*query(e,'dimension')Name of the dimension entity is in.
*query(e,'height')Height of the entity.
*query(e,'width')Width of the entity.
*query(e,'eye_height')Eye height of the entity.
*query(e,'age')Age, in ticks, of the entity, i.e. how long it existed.
*query(e,'despawn_timer')For living entities - the number of ticks they fall outside of immediate player presence.
*query(e,'item')The item triple (name, count, nbt) if its an item entity, null otherwise
query(e,'count')Number of items in a stack from item entity, null otherwise
query(e,'pickup_delay')Retrieves pickup delay timeout for an item entity, null otherwise
query(e,'is_baby')Boolean, true if its a baby.
*query(e,'target')Returns mob's attack target or null if none or not applicable.
*query(e,'home')Returns creature's home position or null if none or not applicable.
*query(e,'sneaking')Boolean, true if entity is sneaking.
*query(e,'sprinting')Boolean, true if entity is sprinting.
*query(e,'swimming')Boolean, true if entity is swimming.
*query(e,'jumping')Boolean, true if entity is jumping.
*query(e,'gamemode')String with gamemode, or null if not a player.
query(e,'gamemode_id')Good'ol gamemode id, or null if not a player.
*query(e,'permission_level')Player's permission level, or null if not applicable for this entity.
query(e,'effect',name?)Without extra arguments, it returns list of effect active on a living entity.
* Each entry is a triple of short effect name, amplifier, and remaining duration.
* With an argument, if the living entity has not that potion active, returns null, otherwise
* return a tuple of amplifier and remaining duration
* query(p,'effect') => [[haste, 0, 177], [speed, 0, 177]]
* query(p,'effect','haste') => [0, 177]
* query(p,'effect','resistance') => null
*
* query(e,'health')Number indicating remaining entity health, or null if not applicable.
query(e,'holds',slot?)Returns triple of short name, stack count, and NBT of item held in slot.
* Available options for slot are:
mainhandoffhandheadchestlegsfeetIf slot is not specified, it defaults to the main hand.
query(e,'selected_slot')Number indicating the selected slot of entity inventory. Currently only applicable to players.
*query(e,'facing', order?)Returns where the entity is facing. optional order (number from 0 to 5, and negative), indicating * primary directions where entity is looking at. From most prominent (order 0) to opposite (order 5, or -1)
*query(e,'trace', reach?, options?...)Returns the result of ray tracing from entity perspective, indicating what it is looking at. Default reach is 4.5
* blocks (5 for creative players), and by default it traces for blocks and entities, identical to player attack tracing action.
* This can be customized with options, use 'blocks' to trace for blocks only, 'liquids' to include liquid blocks
* as possible results, and 'entities' to trace entities as well.
Regardless of the options selected, the result could be null if nothing is in reach, entity, if look
* targets an antity, and block value if block is in reach. Tracing always hits blocks. Even if an entity tracing is requested
* and there is a block in the way - the block will be returned.
query(e,'nbt',path?)Returns full NBT of the entity. If path is specified, it fetches only that portion of the NBT,
* that corresponds to the path. For specification of path attribute, consult
* vanilla /data get entity command.
Note that calls to nbt are considerably more expensive comparing to other
* calls in Minecraft API, and should only be used when there is no other option. Returned value is of type nbt,
* which can be further manipulated with nbt type objects via get, put, has, delete, so try to use API calls
* first for that.
Like with entity querying, entity modifications happen through one function. Most position and movements * modifications don't work currently on players as their position is controlled by clients.
*Currently there is no ability to modify NBT directly, but you could always use run('data modify entity
modify(e,'remove')Removes (not kills) entity from the game.
*modify(e,'kill')Kills the entity.
*modify(e, 'pos', x, y, z), modify(e, 'pos', l(x,y,z) )Moves the entity to a specified coords.
*modify(e, 'location', x, y, z, yaw, pitch), modify(e, 'location', l(x, y, z, yaw, pitch) )Changes full location vector all at once.
*modify(e, 'x', x), modify(e, 'y', y), modify(e, 'z', z)Moves the entity in.... one direction.
*modify(e, 'pitch', pitch), modify(e, 'yaw', yaw)Changes entity's pitch or yaw.
*modify(e, 'move', x, y, z), modify(e, 'move', l(x,y,z) )Moves the entity by a vector from its current location.
*modify(e, 'motion', x, y, z), modify(e, 'motion', l(x,y,z) )Sets the motion vector (where and how much entity is moving).
*modify(e, 'motion_z', x), modify(e, 'motion_y', y), modify(e, 'motion_z', z)Sets the corresponding component of the motion vector.
*modify(e, 'accelerate', x, y, z), modify(e, 'accelerate', l(x, y, z) )Adds a vector to the motion vector. Most realistic way to apply a force to an entity.
*modify(e, 'custom_name'), modify(e, 'custom_name', name )modify(e, 'pickup_delay')Sets a custom pickup delay if the entity argument is an item entity
*modify(e, 'despawn_timer')Sets a custom despawn timer value.
*modify(e, 'dismount')Dismounts riding entity.
*modify(e, 'mount', other)Mounts the entity to the other.
modify(e, 'drop_passengers')Shakes off all passengers.
*modify(e, 'mount_passengers', passenger, ? ...), modify(e, 'mount_passengers', l(passengers) )Mounts on all listed entities on e.
modify(e, 'tag', tag, ? ...), modify(e, 'tag', l(tags) )Adds tag / tags to the entity.
*modify(e, 'clear_tag', tag, ? ...), modify(e, 'clear_tag', l(tags) )Removes tag from entity.
*modify(e, 'talk')Make noises.
*modify(e, 'ai', boolean)If called with false value, it will disable AI in the mob. true will enable it again.
modify(e, 'no_clip', boolean)Sets if the entity obeys any collisions, including collisions with the terrain and basic physics. * Not affecting players, since they are controlled client side
*modify(e, 'effect', name, duration, amplifier?, show_particles?, show_icon?)Applies status effect to the living entity. Takes several optional parameters, which default to 0,
* true and true.
modify(e, 'home', null), modify(e, 'home', block, distance?), modify(e, 'home', x, y, z, distance?)Sets AI to stay around the home position, within distance blocks from it. distance
* defaults to 16 blocks. null removes it. May not work fully with mobs that have this AI built in, like
* Villagers.
There is a number of events that happen to entities that you can attach your own code to in the form of event
* handlers. The event handler is any function that runs in your package that accepts certain expected parameters, which
* you can expand with your own arguments. When it comes to the moment when the given command needs to be executed, it
* does so providing that number of arguments it accepts is equal number of event arguments, and extra arguments passed when
* defining the callback with entity_event
The following events can be handled by entities.
*'on_tick': executes every tick right before entity is ticked in the game. Required arguments: entity'on_death': executes once when a living entity dies. Required arguments: entity, reason'on_removed': execute once when an entity is removed. Required arguments: entity'on_damaged': executed every time a living entity is about to receive damage. Required arguments: entity, amount, source, attacking_entityIt doesn't mean that all entity types will have a chance to * execute a given event, but entities will not error when you will attach inapplicable event to it.
*entity_event(e, event, call_name, args...)Attaches specific function from the current package to be called upon the event, with extra args
* curried to the original required arguments for the event handler
* protect_villager(entity, amount, source, source_entity, healing_player) ->
* (
* if(source_entity && source_entity~'type' != 'player',
* modify(entity, 'health', amount + entity~'health' );
* particle('end_rod', pos(entity)+l(0,3,0));
* print(str('%s healed thanks to %s', entity, healing_player))
* )
* );
*
* __on_player_interacts_with_entity(player, entity, hand) ->
* (
* if (entity~'type' == 'villager',
* entity_event(entity, 'on_damage', 'protect_villager', player~'name')
* )
* )
*
* In this case this will protect a villager from entity damage (zombies, etc.) except players by granting all the health * back to the villager after being harmed.
*These functions help scan larger areas of blocks without using generic loop functions,
* like nested loop.
scan(cx, cy, cz, dx, dy, dz, px?, py?, pz?, expr)Evaluates expression over area of blocks defined by its center (cx, cy, cz),
* expanded in all directions by dx, dy, dz blocks, or optionally in negative with d coords,
* and p coords in positive values. expr receives _x, _y, _z
* as coords of current analyzed block and _ which represents the block itself.
volume(x1, y1, z1, x2, y2, z2, expr)Evaluates expression for each block in the area, the same as the scanfunction, but using two opposite
* corners of the rectangular cuboid. Any corners can be specified, its like you would do with /fill command
neighbours(x, y, z), neighbours(block), neighbours(l(x,y,z))Returns the list of 6 neighbouring blocks to the argument. Commonly used with other loop functions like for
* for(neighbours(x,y,z),air(_)) => 4 // number of air blocks around a block
*
* rect(cx, cy, cz, dx?, dy?, dz?, px?, py?, pz?)returns an iterator, just like range function that iterates over rectangular cubarea of blocks. If
* only center point is specified, it iterates over 27 blocks. If d arguments are specified, expands selection
* of respective number of blocks in each direction. If p arguments are specified, it uses d for
* negative offset, and p for positive.
diamond(cx, cy, cz, radius?, height?)Iterates over a diamond like area of blocks. With no radius and height, its 7 blocks centered around the middle * (block + neighbours). With a radius specified, it expands shape on x and z coords, and with a custom height, on y. Any of these can be * zero as well. radius of 0 makes a stick, height of 0 makes a diamond shape pad.
*Collection of other methods that control smaller, yet still important aspects of the game
*sound(name, pos, volume?, pitch?)Plays a specific sound name, at block or position pos, with optional
* volume and modified pitch. pos can be either a block, triple of coords,
* or a list of thee numbers. Uses the same options as a corresponding playsound command.
particle(name, pos, count?. spread?, speed?, playername?)Renders a cloud of particles name centered around pos position, by default
* count 10 of them, default speed of 0, and to all players nearby, but these
* options can be changed via optional arguments. Follow vanilla /particle command on details on those
* options. Valid particle names are for example
* 'angry_villager', 'item diamond', 'block stone', 'dust 0.8 0.1 0.1 4'
particle_line(name, pos, pos2, density?)Renders a line of particles from point pos to pos2 with supplied density (defaults 1),
* which indicates how far part you would want particles to appear, so 0.1 means one every 10cm.
particle_rect(name, pos, pos2, density?)Renders a cuboid of particles between point pos to pos2 with supplied density.
create_marker(text, pos, rotation?, block?)Spawns a (permanent) marker entity with text or block at position. Returns that entity for further manipulations. * Unloading the app that spawned them will cause all the markers from the loaded portion of the world to be removed. * Also - if the game loads that marker in the future and the app is not loaded, it will be removed as well.
*remove_all_markers()Removes all scarpet markers from the loaded portion of the world created by this app, in case you didn't want * to do the proper cleanup
*nbt(expr)Treats the argument as a nbt serializable string and returns its nbt value.
* In case nbt is not in a correct nbt compound tag format, it will return null value.
Consult section about container operations in Expression to learn about possible operations on nbt values.
escape_nbt(expr)Excapes all the special characters in the string or nbt tag and returns a string that can be stored in nbt directly as * a string value.
*print(expr)Displays the result of the expression to the chat. Overrides default scarpet behaviour of
* sending everyting to stderr.
logger(expr)Prints the message to system logs, and not to chat.
*run(expr)Runs a vanilla command from the string result of the expr and returns its success count
* run('fill 1 1 1 10 10 10 air') -> 123 // 123 block were filled, this operation was successful 123 times out of a possible 1000 blocks volume
* run('give @s stone 4') -> 1 // this operation was successful once
*
* save()Performs autosave, saves all chunks, player data, etc. Useful for programs where autosave is disabled * due to performance reasons and saves the world only on demand.
*load_app_data(), load_app_data(file)Loads the app data associated with the app from the world /scripts folder. Without argument returns the memory * managed and buffered / throttled NBT tag. With a file name - reads explicitly a file with that name from the scripts * folder.
*You can use app data to save non-vanilla information separately from the world and other scripts.
*store_app_data(tag), store_app_data(tag, file)Stores the app data associated with the app from the world /scripts folder. With the file parameter
* saves immediately and with every call, without file parameter, it may take up to 10 seconds for the output
* file to sync preventing flickering in case this tag changes frequently. It will be synced when server closes.
tick_time()Returns game tick counter. Can be used to run certain operations every n-th ticks, or to count in-game time
*game_tick(mstime?)Causes game to run for one tick. By default runs it and returns control to the program, but can optionally
* accept expected tick length, in milliseconds. You can't use it to permanently change the game speed, but
* setting longer commands with custom tick speeds can be interrupted via /script stop command
* loop(1000,game_tick()) // runs the game as fast as it can for 1000 ticks
* loop(1000,game_tick(100)) // runs the game twice as slow for 1000 ticks
*
* current_dimension()Returns current dimension that the script runs in.
*in_dimension(smth, expr)Evaluates the expression expr with different dimension execution context. smth can
* be an entity, world-localized block, so not block('stone'), or a string representing a dimension like:
* 'nether', 'the_nether', 'end' or 'overworld', etc.
schedule(delay, function, args...)Schedules a user defined function to run with a specified delay ticks of delay.
* Scheduled functions run at the end of the tick, and they will run in order they were scheduled.
statistic(player, category, entry)Queries in-game statistics for certain values. Categories include:
*mined: blocks minedcrafted: items craftedused: items usedbroken: items brokenpicked_up: items picked updropped: items droppedkilled: mobs killedkilled_by: blocks minedcustom: various random statsFor the options of entry, consult your statistics page, or give it a guess.
The call will return null if the statistics options are incorrect, or player didn't get these
* in their history. If the player encountered the statisitic, or game created for him empty one, it will
* return a number. Scarpet will not affect the entries of the statistics, even if it is just creating empty ones.
* With null response it could either mean your input is wrone, or statistic has effectively
* a value of 0.
plop(pos, what)Plops a structure or a feature at a given pos, so block, triple position coordinates
* or a list of coordinates. To what gets plopped and exactly where it often depends on the
* feature or structure itself. For example, all structures are chunk aligned, and often span multiple chunks.
* Repeated calls to plop a structure in the same chunk would result either in the same strucuture generated on
* top of each other, or with different state, but same position. Most
* structures generate at specific altitudes, which are hardcoded, or with certain blocks around them. API will cancel
* all extra position / biome / random requirements for structure / feature placement, but some hardcoded limitations
* may still cause some of strucutures/features not to place. Some features require special blocks to be present, like
* coral -> water or ice spikes -> snow block, and for some features, like fossils, placement is all sorts of
* messed up.
* All generated structures will retain their properties, like mob spawning, however in many cases the world / dimension * itself has certain rules to spawn mobs, like plopping a nether fortress in the overworld will not spawn nether mobs * because nether mobs can spawn only in the nether, but plopped in the nether - will behave like a valid nether * fortress.
*plop will not use world random number generator to generate structures and features, but its own.
* This has a benefit that they will generate properly randomly, not the same time every time
Structure list:
*monument: Ocean Monument. Generates at fixed Y coordinate, surrounds itself with water.fortress: Nether Fortress. Altitude varies, but its bounded by the code.mansion: Woodland Mansionjungle_temple: Jungle Templedesert_temple: Desert Temple. Generates at fixed Y altitude.end_city: End City with Shulkersigloo: Iglooshipwreck: Shipwreck, version1?shipwreck2: Shipwreck, version2?witchhutoceanruin, oceanruin_small, oceanruin_tall: Stone variants of ocean ruins.oceanruin_warm, oceanruin_warm_small, oceanruin_warm_tall: Sandstone variants of ocean ruins.treasure: A treasure chest. Yes, its a whole structure.pillager_outpost: A pillager outpost.mineshaft: A mineshaft.mineshaft_mesa: A Mesa (Badlands) version of a mineshaft.village: Plains, oak village.village_desert: Desert, sandstone village.village_savanna: Savanna, acacia village.village_taiga: Taiga, spruce village.village_snowy: Resolute, Canada.Feature list:
*oakoak_beehive: oak with a hive (1.15+).oak_large: oak with branches.oak_large_beehive: oak with branches and a beehive (1.15+).birchbirch_large: tall variant of birch tree.shrub: low bushes that grow in jungles.shrub_acacia: low bush but configured with acacia (1.14 only)shrub_snowy: low bush with white blocks (1.14 only)jungle: a treejungle_large: 2x2 jungle treesprucespruce_large: 2x2 spruce treepine: spruce with minimal leafage (1.15+)pine_large: 2x2 spruce with minimal leafage (1.15+)spruce_matchstick: see 1.15 pine (1.14 only).spruce_matchstick_large: see 1.15 pine_large (1.14 only).dark_oakacaciaoak_swamp: oak with more leaves and vines.well: desert wellgrass: a few spots of tall grassgrass_jungle: little bushier grass feature (1.14 only)lush_grass: grass with patchy ferns (1.15+)tall_grass: 2-high grass patch (1.15+)fern: a few random 2-high fernscactus: random cactidead_bush: a few random dead bushifossils: underground fossils, placement little wonkymushroom_brown: large brown mushroom.mushroom_red: large red mushroom.ice_spike: ice spike. Require snow block below to place.glowstone: glowstone cluster. Required netherrack above it.melon: a patch of melonsmelon_pile: a pile of melons (1.15+)pumpkin: a patch of pumpkinspumpkin_pile: a pile of pumpkins (1.15+)sugarcanelilypaddungeon: Dungeon. These are hard to place, and fail often.iceberg: Iceberg. Generate at sea level.iceberg_blue: Blue ice iceberg.lakelava_lakeend_islandchorus: Chorus plant. Require endstone to place.sea_grass: a patch of sea grass. Require water.sea_grass_river: a variant.kelpcoral_tree, coral_mushroom, coral_claw: various coral types, random color.coral: random coral structure. Require water to spawn.sea_pickleboulder: A rocky, mossy formation from a giant taiga biome. Doesn't update client properly,
* needs relogging./script scan, /script fill and /script outline commandsThese commands can be used to evaluate an expression over an area of blocks. They all need to have specified
* the origin of the analyzed area (which is used as referenced (0,0,0), and two corners of an area to analyzed. If
* you would want that the script block coordinates refer to the actual world coordinates, use origin of 0 0 0,
* or if it doesn't matter, duplicating coordinates of one of the corners is the easiest way.
These commands, unlike raw /script run are limited by vanilla fill / clone command
* limit of 32k blocks, which can be altered with carpet mod's own /carpet fillLimit command.
/script scan origin<x y z> corner<x y z> corner<x y z> exprEvaluates expression for each point in the area and returns number of successes (result was positive). Since * the command by itself doesn't affect the area, the effects would be in side effects.
*/script fill origin<x y z> corner<x y z> corner<x y z> "expr" <block> (? replace <replacement>) Think of it as a regular fill command, that sets blocks based on whether a result of the command was successful.
* Note that the expression is in quotes. Thankfully string constants in scarpet use single quotes. Can be used
* to fill complex geometric shapes.
/script outline origin<x y z> corner<x y z> corner<x y z> "expr" <block> (? replace <replacement>) Similar to fill command it evaluates an expression for each block in the area, but in this case setting blocks
* where condition was true and any of the neighbouring blocks were evaluated negatively. This allows to create surface areas,
* like sphere for example, without resorting to various rounding modes and tricks.
Here is an example of seven ways to draw a sphere of radius of 32 blocks around 0 100 0:
*
* /script outline 0 100 0 -40 60 -40 40 140 40 "x*x+y*y+z*z < 32*32" white_stained_glass replace air
* /script outline 0 100 0 -40 60 -40 40 140 40 "x*x+y*y+z*z <= 32*32" white_stained_glass replace air
* /script outline 0 100 0 -40 60 -40 40 140 40 "x*x+y*y+z*z < 32.5*32.5" white_stained_glass replace air
* /script fill 0 100 0 -40 60 -40 40 140 40 "floor(sqrt(x*x+y*y+z*z)) == 32" white_stained_glass replace air
* /script fill 0 100 0 -40 60 -40 40 140 40 "round(sqrt(x*x+y*y+z*z)) == 32" white_stained_glass replace air
* /script fill 0 100 0 -40 60 -40 40 140 40 "ceil(sqrt(x*x+y*y+z*z)) == 32" white_stained_glass replace air
* /draw sphere 0 100 0 32 white_stained_glass replace air
*
* fluffy ball round(sqrt(x*x+y*y+z*z)-rand(abs(y)))==32
*
*
* The last method is the one that world edit is using (part of carpet mod). It turns out that the outline method with 32.5 radius,
* fill method with round function and draw command are equivalent
/script run commandPrimary way to input commands. The command executes in the context, position, and dimension of the executing
* player, commandblock, etc... The command receives 4 variables, x, y, z
* and p indicating position and the executing entity of the command.
* You will receive tab completion suggestions as you type your code suggesting functions and global variables.
* It is advisable to use /execute in ... at ... as ... run script run ... or similar, to simulate running
* commands in a different scope
/script invoke / invokepoint / invokearea, /script globals commandsinvoke family of commands provide convenient way to invoke stored procedures (i.e. functions
* that has been defined previously by any running script. To view current stored procedure set,
* run /script globals(or /script globals all to display all functions even hidden ones),
* to define a new stored procedure, just run a /script run function(a,b) -> ( ... )
* command with your procedure once, and to forget a procedure, use undef function:
* /script run undef('function')
/script invoke <fun> <args?> ... Equivalent of running /script run fun(args, ...), but you get the benefit of getting the tab completion of the
* command name, and lower permission level required to run these (since player is not capable of running any custom code
* in this case, only this that has been executed before by an operator). Arguments will be checked for validity, and
* you can only pass simple values as arguments (strings, numbers, or null value). Use quotes to include
* whitespaces in argument strings.
Command will check provided arguments with required arguments (count) and fail if not enough or too much arguments * are provided. Operators defining functions are advised to use descriptive arguments names, as these will be visible * for invokers and form the base of understanding what each argument does.
*invoke family of commands will tab complete any stored function that does not start with '_',
* it will still allow to run procedures starting with '_' but not suggest them, and ban execution of any
* hidden stored procedures, so ones that start with '__'. In case operator needs to use subroutines
* for convenience and don't want to expose them to the invoke callers, they can use this mechanic.
* /script run example_function(const, phrase, price) -> print(const+' '+phrase+' '+price)
* /script invoke example_function pi costs 5
*
* /script invokepoint <fun> <coords x y z> <args?> ... It is equivalent to invoke except it assumes that the first three arguments are coordinates, and provides
* coordinates tab completion, with looking at... mechanics for convenience. All other arguments are expected
* at the end
/script invokearea <fun> <coords x y z> <coords x y z> <args?> ... It is equivalent to invoke except it assumes that the first three arguments are one set of ccordinates,
* followed by the second set of coordinates, providing tab completion, with looking at... mechanics for convenience,
* followed by any other required arguments
/script load / unload <app> (global?), /script in <app> commandsload / 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, 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:
*
* foo = 1;
* //This is a comment
* bar = 2;
* // This never worked, so I commented it out
* // baz = foo()
*
*
* /script load/unload <app> (?global) Loading operation will load that script code from disk and execute it right away. You would probably use it to
* load some stored procedures to be used for later. To reload the module, just type /script load again.
* Reloading removes all the current global state (globals and functions) that were added later by the module.
Loading a module, if it contains a __command() method, will attempt to registed a command with that
* app name, and register all public (no underscore) functions available in the module as subcommands. It will also
* bind specific events to the event system (check Events section for details).
Loaded apps have the ability to store and load external files, especially their persistent tag state.
* For that check load_app_data and store_app_data functions.
If an app defines __config method, and that method returns a map, it will be used to apply custom
* settings for this app. Currently the following options are supported:
scope: default scope for global variables for the app, Default is 'player' which means
* that globals and defined functions will be unique for each player so that apps for each player will run in
* isolation. This is useful in tool-like applications. Another option is 'global' which shares global state for all
* runs on the server - applicable to 'block' like solutions, where custom behaviours are applied to blocks.stay_loaded: defaults to false. If true, and /carpet scriptsAutoload is turned on,
* the following apps will stay loaded after startup. Otherwise, after reading a code, 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.Unloading an app removes all of its state from the game, disables commands, and removes bounded events,
* and saves its global state. If more
* cleanup is needed, one can define an __on_close() function which will be executed when the module is unloaded,
* or server is closing, or crashing. However, there is no need to do that explicitly for the things mentioned
* in the previous statement.
Scripts can be loaded in shared(global) and player mode. Default is player, so all globals and stored functions are
* individual for each player, meaning scripts don't need to worry about making sure they store some intermittent data
* for each player independently. In global mode - all global values and stored functions are shared among all players.
* To access specific player data with commandblocks, use /execute as (player) run script in (app) run ...
* To access global/server state, you need to disown the command from any player, so use a commandblock, or any arbitrary
* entity: /execute as @e[type=bat,limit=1] run script in (module) globals for instance.
*
/script in <app> ... Allows to run normal /script commands in a specific app, like run, invoke,..., globals etc...
Provides the ability to execute specific function whenever an event occurs. The functions to be registered
* need to conform with the arguments to the event specification. When loading module functions, each function that
* starts with __on_... and has the required arguments, will be bound automatically.
* In case of player specific modules, all player action events will be directed to the appropriate player space, and
* all tick events will be executed in the global context, so its not a good idea to mix these two, so use either of these,
* or use commands to call tick events directly, or handle player specific data inside a module.
Here is a list of events that can be handled by scarpet. This list includes prefixes required by modules to * autoload them, but you can add any function to any event if it accepts required number of parameters:
*
* __on_tick() // can access blocks and entities in the overworld
* __on_tick_nether() // can access blocks and entities in the nether
* __on_tick_ender() // can access blocks and entities in the end
*
* // player specific callbacks
* __on_player_uses_item(player, item_tuple, hand) // right click action
* __on_player_releases_item(player, item_tuple, hand) // client action (e.g. bow)
* __on_player_finishes_using_item(player, item_tuple, hand)) // server action (e.g. food), called item is from before it is used.
* __on_player_clicks_block(player, block, face) // left click attack on a block
* __on_player_breaks_block(player, block) // called after block is broken (the caller receives previous blockstate)
* __on_player_right_clicks_block(player, item_tuple, hand, block, face, hitvec) // player right clicks block with anything
* __on_player_interacts_with_block(player, hand, block, face, hitvec) //right click on a block resulted in activation of said block
* __on_player_places_block(player, item_tuple, hand, block) // player have just placed the block.
* __on_player_interacts_with_entity(player, entity, hand)
* __on_player_attacks_entity(player, entity)
* __on_player_rides(player, forward, strafe, jumping, sneaking)
* __on_player_jumps(player)
* __on_player_deploys_elytra(player)
* __on_player_wakes_up(player)
* __on_player_starts_sneaking(player)
* __on_player_stops_sneaking(player)
* __on_player_starts_sprinting(player)
* __on_player_stops_sprinting(player)
* __on_player_drops_item(player)
* __on_player_drops_stack(player)
*
* __on_statistic(player, category, event, value) // player statistic changes
*
* /script event commandused to display current events and bounded functions. use add_to ro register new event, or remove_from
* to unbind a specific function from an event. Function to be bounded to an event needs to have the same
* number of parameters as the action is attempting to bind to (see list above). All calls in modules
* loaded via /script load that have functions listed above will be automatically bounded and unbounded when
* script is unloaded.