package carpet.script; import carpet.CarpetServer; import carpet.fakes.MinecraftServerInterface; import carpet.fakes.BiomeArrayInterface; import carpet.helpers.FeatureGenerator; import carpet.mixins.ChunkTicketManager_scarpetMixin; import carpet.mixins.ServerChunkManager_scarpetMixin; import carpet.script.Fluff.TriFunction; import carpet.script.exception.CarpetExpressionException; import carpet.script.exception.ExitStatement; import carpet.script.exception.ExpressionException; import carpet.script.exception.InternalExpressionException; 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.Value; import carpet.settings.CarpetSettings; 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.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.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.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 carpet.script.value.NBTSerializableValue.nameFromRegistryId; 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
* gametick() 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) -> ( gametick(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, gametick(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. * 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(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,'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, '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 command from the string result of the expr expression, and returns its success count
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 * floder.
*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,tick()) // runs the game as fast as it can for 1000 ticks
* loop(1000,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.
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.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.Feature list:
*oakoak_large: oak with branches.birchbirch_large: tall variant of birch tree.shrub: low bushes that grow in jungles.shrub_acacia: low bush but configured with acaciashrub_snowy: low bush with white blocksjungle: a treespruce_matchstick: tall spruce with minimal leafage.dark_oakacaciaspruceoak_swamp: oak with more leaves and vines.jungle_large: 2x2 jungle treespruce_matchstick_large: 2x2 spruce tree with minimal leafagespruce_large: 2x2 spruce treewell: desert wellgrass: a few spots of tall grassgrass_jungle: little bushier grass featurefern: a few random 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 melonspumpkin: a patch of pumpkinssugarcanelilypaddungeon: 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
*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_right_clicks_block(player, item_tuple, hand, block, face, hitvec)
* __on_player_breaks_block(player, block) // called after block is broken (the caller receives previous blockstate)
* __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)
*
* /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.