package carpet.script; import carpet.CarpetServer; import carpet.fakes.MinecraftServerInterface; import carpet.helpers.FeatureGenerator; import carpet.helpers.Tracer; import carpet.script.Fluff.TriFunction; import carpet.script.exception.CarpetExpressionException; import carpet.script.exception.ExpressionException; import carpet.script.exception.InternalExpressionException; import carpet.script.value.BlockValue; import carpet.script.value.EntityValue; 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 net.minecraft.block.Block; import net.minecraft.block.BlockPlacementEnvironment; import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; 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.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.ServerWorld; import net.minecraft.sound.BlockSoundGroup; import net.minecraft.sound.SoundCategory; import net.minecraft.state.StateFactory; import net.minecraft.state.property.Property; import net.minecraft.text.LiteralText; import net.minecraft.text.TranslatableText; import net.minecraft.util.Clearable; import net.minecraft.util.Identifier; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.hit.HitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; 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.loot.context.LootContext; import net.minecraft.world.loot.context.LootContextParameters; import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; 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.
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(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
*
* 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.
*
* 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 harvest by a player. Add -1 for silk touch, and positive number for fortune level.
*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.
* * *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
*
* 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, x, z)Returns the Y value of the topmost block at given x, z coords, according to the
* heightmap specified by type. Valid options are:
light: topmost light blocking blockmotion: topmost motion blocking blockterrain: topmost motion blocking block except leavesocean_floor: topmost non-water blocksurface: topmost surface block
* top('motion', x, z) => 63
* top('ocean_floor', x, z) => 41
*
* loaded(pos)Boolean function, true if the block is loaded. 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.
* loaded(pos(players())) => 1
* loaded(100000,100,1000000) => 0
*
* loaded_ep(pos)Boolean function, true if the block is loaded and entity processing, as per 1.13.2
*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
*
* 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_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.
* *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,'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,'item')Name of the item if its an item entity, null otherwise
query(e,'count')Number of items in a stack from 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,'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. Also returned
* NBT is just a string to any retrieval of information post can currently only be done with matching
* operator ~. With time we are hoping not to support the 'nbt' call better,
* but rather to fill the API, so that 'nbt' calls are not needed
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 )Sets a custom name for an entity. No argument sets it empty, not removes it. Vanilla doesn't allow removing * of attributes.
*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, '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.
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.
print(expr)Displays the result of the expression to the chat. Overrides default scarpet behaviour of
* sending everyting to stderr.
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.
*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 scripts run in.
*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, 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