wiki:Scripting/API

Scripting API

The way the script will interact with WorldPainter is through a context object named wp which exports a number of operations in the form of functions or methods (depending on your scripting language). The operations follow the "builder pattern" or "method chaining", meaning that you chain one or more method invocations to set the parameters and then invoke "go()" to actually perform the operation, which may or may not return a value. For example, in JavaScript:

var world = wp.getWorld()
    .fromFile('path/to/world/worldname.world')
    .go();

This single statement loads a WorldPainter world from the specified file and stores it in a variable named "world", which you can then use in further operations to refer to the loaded world.

Don't Forget The Go!

Once again: every operation ends with a call to .go(), which will actually perform the operation and return the result, if any. Don't forget it, or nothing will happen!

Commandline Arguments

The script will have access to any commandline arguments specified by the user when invoking the script via the arguments or argv array (both are available; the first command line argument is in arguments[0] or argv[1]; argv[0] contains the name of the script; in the arguments array that is not available).

Variables Available Inside WorldPainter

When a script is executed inside WorldPainter (Tools -> Run script...) it has the same arguments and argv arrays available as when run on the command line, in which the arguments entered by the user on the Run Script screen will be available.

In addition it will have two global variables available: world and dimension, which point to the currently loaded world and the currently selected dimension respectively, and through which the script can modify the currently loaded world.

Loading a World

Loading a WorldPainter world from disk:

var world = wp.getWorld()
    .fromFile('path/to/world/myworld.world') // The filename of the world to load; may be absolute or relative to the current directory
    .go();

Saving a World

Saving a WorldPainter world to disk:

wp.saveWorld(world) // The world to save. See "Loading a World"
    .toFile('path/to/world/myworld.world') // The filename under which to save the world. If it already exists a backup will automatically be made using the backup settings stored in the !WorldPainter configuration of the user running the script
    .go();

Exporting a World

Exporting a WorldPainter world as a Minecraft map:

wp.exportWorld(world) // The world to export. See "Loading a World"
    .toDirectory('path/to/saves') // The directory in which to export the world. Should NOT include the world name; a directory with the name of the world will automatically be created inside the specified directory. If a directory with that name already exists it will automatically be backed up
    .go();

Loading a Layer

Getting a standard WorldPainter layer:

var layer = wp.getLayer()
    .withName('Frost') // The name of the standard layer
    .go();

Getting a layer from a WorldPainter world:

var layer = wp.getLayer()
    .fromWorld(world) // See "Loading a World"
    .withName('My Layer') // The name of layer in the world
    .go();

Loading a layer from a .layer file exported from WorldPainter:

var layer = wp.getLayer()
    .fromFile('path/to/layer/mylayer.layer') // The filename of the layer to load
    .go();

Loading a Custom Terrain

Loading a Custom Terrain from a .terrain file exported from WorldPainter:

var terrain = wp.getTerrain()
    .fromFile('path/to/terrain/myterrain.terrain') // The filename of the terrain to load
    .go();

Note that to actually use a Custom Terrain you must first install it on the world! See below for the "Installing a Custom Terrain" operation.

Installing a Custom Terrain

Before you can actually use a Custom Terrain you must first install it on the world using the following operation:

var customTerrainIndex = wp.installCustomTerrain(terrain) // The Custom Terrain to install on the world. See "Loading a Custom Terrain"
    .toWorld(world) // The world on which to install the Custom Terrain. See "Loading a World"
    .inSlot(1) // Optional. The Custom Terrain slot from 1 to 96 (inclusive) on which to install the terrain. When not specified the first free slot will be used. If there are no free slots an exception will be thrown
    .go(); // Returns the terrain index to use for actually placing this Custom Terrain using other operations

Loading a Height Map

There are several operations which take a height map as input. Here is how to load one:

var heightMap = wp.getHeightMap()
    .fromFile('path/to/heightmap/myheightmap.png') // The filename of the height map to load. Supported formats are dependent on the Java platform, but usually include at least PNG and TIFF
    .selectRedChannel() // Optional. If the image is not a grayscale image you may invoke ONE OF selectRedChannel(), selectGreenChannel() or selectBlueChannel() to indicate which channel should be used to read values from. This is the default for colour images
    .selectGreenChannel() // Optional. If the image is not a grayscale image you may invoke ONE OF selectRedChannel(), selectGreenChannel() or selectBlueChannel() to indicate which channel should be used to read values from. The default is to use the red channel for colour images.
    .selectBlueChannel() // Optional. If the image is not a grayscale image you may invoke ONE OF selectRedChannel(), selectGreenChannel() or selectBlueChannel() to indicate which channel should be used to read values from. The default is to use the red channel for colour images.
    .go(); // Returns the loaded height map for use in other operations

Loading a Map Format

To be able to specify the map format of a newly created world you need to obtain a reference to the map format like so:

var mapFormat = wp.getMapFormat()
    .withId('id') // Mutually exclusive with withName(). The ID of the map format to obtain
    .withName('name') // Mutually exclusive with withId(). The name of the map format to obtain
    .go(); // Returns the map format with the specified ID or name

Note that it is recommended to use the ID, as that is guaranteed to be stable, while the names might change from release to release. Here are the IDs of the currently supported map formats of WorldPainter:

org.pepsoft.mcregion Minecraft 1.1 (MCRegion)
org.pepsoft.anvil Minecraft 1.2 - 1.12
org.pepsoft.anvil.1.13 Minecraft 1.15 - 1.16
org.pepsoft.anvil.1.17 Minecraft 1.17
org.pepsoft.anvil.1.18 Minecraft 1.18
org.pepsoft.anvil.1.19 Minecraft 1.19 or later

Creating a World from a Height Map

Creating a new world from a height map:

var world = wp.createWorld()
    .fromHeightMap(heightMap) // See "Loading a Height Map"
    .scale(100) // Optional. The % at which to scale the height map. Default value: 100%
    .shift(0, 0) // Optional. The number of blocks the height map should be shifted east and south respectively (negative numbers shift west and north). Default value: 0, 0
    .fromLevels(0, 255).toLevels(0, 255) // Optional. Specifies how image values should be mapped to surface heights. The first two values are the lower and upper bounds of the range of image values; the second pair of values if the corresponding range of surface heights those image values should be mapped to. The default is to map the values one on one
    .withWaterLevel(62) // Optional. The default water level to set the new world to. Default value: 62
    .withMapFormat(mapFormat) // Optional. The map format to set the new world to. See above for obtaining the reference to the map format. Defaults to the default map format configured in the WorldPainter Preferences
    .withLowerBuildLimit(-64) // Optional. The lower build limit to set the new world to. This value is inclusive. Defaults to the default lower build limit of the map format
    .withUpperBuildLimit(320) // Optional. The upper build limit to set the new world to. This valus is exclusive. Defaults to the default upper build limit of the map format
    .go(); // Returns the created world for exporting, saving or using in other operations

Note that WorldPainter supports 16-bit height maps! You can import them to create worlds with high resolution height information, which will make smooth snow look better and editing work more smoothly. You'll need to tell WorldPainter to map the full range of the height map (or any other desired range) to the full range of the world height though, by setting fromLevels() and toLevels() like this:

    .fromLevels(0, 65535).toLevels(0, 255)

Applying a Height Map as a Layer

To apply a height map to a world as a layer:

wp.applyHeightMap(heightMap) // See "Loading a Height Map"
    .toWorld(world) // See "Loading a World" or "Creating a World from a Height Map"
    .withFilter(filter) // Optional. Specifies conditions for where the layer will be applied. See below for details about creating a filter
    .applyToSurface() // Optional. Mutually exclusive with applyToNether() and applyToEnd(). Indicates that the layer should be applied to the Surface dimension. This is the default
    .applyToNether() // Optional. Mutually exclusive with applyToSurface() and applyToEnd(). Indicates that the layer should be applied to the Nether dimension
    .applyToEnd() // Optional. Mutually exclusive with applyToSurface() and applyToNether(). Indicates that the layer should be applied to the End dimension
    .scale(100) // Optional. The % at which to scale the height map. Default value: 100%
    .shift(0, 0) // Optional. The number of blocks the height map should be shifted east and south respectively (negative numbers shift west and north). Default value: 0, 0
    .applyToLayer(layer) // See "Loading a Layer"
    .fromLevel(0).toLevel(0) // Optional. Repeatable. Specifies that a single value from the image must be mapped to a single layer intensity (see below)
    .fromLevels(0, 255).toLevel(0) // Optional. Repeatable. Specifies that a range of values from the image must be mapped to a single layer intensity (see below)
    .fromLevels(0, 255).toLevels(0, 255) // Optional. Repeatable. Specifies that a range of values from the image must be mapped to a range of layer intensities (see below)
    .fromColour(0, 0, 0).toLevel(0) // Optional. Repeatable. Specificies that a single colour, in the form of red, green and blue components from 0 to 255 (inclusive), from the image must be mapped to a single layer intensity (see below). The alpha value is assumed to be 255 (fully opaque)
    .fromColour(0, 0, 0, 0).toLevel(0) // Optional. Repeatable. Specificies that a single colour, in the form of alpha, red, green and blue components from 0 to 255 (inclusive), from the image must be mapped to a single layer intensity (see below)
    .setAlways() // Optional. Mutually exclusive with setWhenLower() and setWhenHigher(). Indicates that the layer intensity must always be overridden, no matter what it was before. This is the default
    .setWhenLower() // Optional. Mutually exclusive with setAlways() and setWhenHigher(). Indicates that the layer intensity must only be overridden if the value from the image is lower than what was already there in the world
    .setWhenHigher() // Optional. Mutually exclusive with setAlways() and setWhenLower(). Indicates that the layer intensity must only be overridden if the value from the image is higher than what was already there in the world
    .go();

About the mapping:

You may map EITHER grey scale values (using fromLevel() and fromLevels()) OR colour values (using fromColour()), but you may not mix both. Mapping colour values obviously is only useful if the height map was derived from a colour image. Note that the colours are only matched exactly as specified. Slightly different colours don't match. Therefore you must make sure that your input image contains only solid areas of discrete colours and has no anti-aliasing, smoothing, mixing of colours, gradients, etc.

You must specify a mapping by using the fromLevel(s)/fromColour(s)/toLevel(s) setters at least once. The value mapping specifies which layer intensities should be set for which input values. Any input values not mapped will be ignored, i.e. the existing layer intensity, if any, will remain unaltered in those locations. To correctly set the mapping you must know which target values to use for the type of layer you are mapping to. As of now there are three layer types:

On/Off Layers

So-called on/off or true/false or 1-bit layers don't have an intensity. Instead they are either on or off for each coordinate. Examples of this type of layer are: the Frost layer, the Void layer, Custom Ground Cover layers and Custom Cave/Tunnel layers.

For these layers a target value of zero means "off" and any other value means "on". In other words, if you use the default mapping, any areas where the height map is not completely black will result in the layer being applied.

Continuous Layers

So-called continuous or 4-bit layers have an intensity. In the GUI the intensity is displayed as a percentage between 0% and 100%, but technically these layers only have 16 discrete intensities, from 0 to 15. Zero means the layer is absent; 1 corresponds to 1%, 8 to 50% and 15 to 100%. Examples of this type of layer are: the Caverns and Chasms layers, the standard tree layers, the Resources layer, Custom Object layers, Custom Underground Pockets layers and Combined layers.

For these layers the target value must therefore lie between 0 and 15 (inclusive). If you use the default mapping, any areas where the height map is completely black will not have the layer set; where the height map value is between 1 and 14 (inclusive) will have the layer set to a percentage from 1% to 93% and where the value is 15 (which is still very dark) or higher the layer will be set to 100%.

Direct Mapping Layers

These are layers which don't have an intensity, but where the layer values correspond directly to arbitrary concepts such as colours or biomes. Examples of this type of layer are the Biomes layer and the Annotations layer.

It depends on the type of height map what kind of mapping makes sense for these layers. If it is a genuine height map (i.e. it corresponds to surface heights) then you can use it to map different height ranges to different biomes, for instance, and it makes sense to use the ranged setters (fromLevels().toLevel() and fromLevels().toLevels()) to set up the mapping.

If instead the "height map" is a value map or mask which directly indicates which biomes, for instance, must be used then using the ranged setters does not make sense and it would be better to use the one on one setter (fromLevel().toLevel()) repeatedly to set up each mapping of a "height map" value to a biome, or a colour.

For the Biomes layer, the target values are the Minecraft biome IDs which you can find on the Minecraft wiki. To reset the biome to "automatic", set the layer value to 255.

For the Annotations layer, the target values must be between 0 and 15. 0 indicates that the layer should not be present; the other values indicate individual colours. See this page for an overview of the colour mapping.

Applying a Height Map to the Terrain Type

To apply a height map to a world as the terrain type:

wp.applyHeightMap(heightMap) // See "Loading a Height Map"
    .toWorld(world) // See "Loading a World" or "Creating a World from a Height Map"
    .withFilter(filter) // Optional. Specifies conditions for where the terrain will be applied. See below for details about creating a filter
    .applyToSurface() // Optional. Mutually exclusive with applyToNether() and applyToEnd(). Indicates that the terrain should be changed of the Surface dimension. This is the default
    .applyToNether() // Optional. Mutually exclusive with applyToSurface() and applyToEnd(). Indicates that the terrain should be changed of the Nether dimension
    .applyToEnd() // Optional. Mutually exclusive with applyToSurface() and applyToNether(). Indicates that the terrain should be changed of the End dimension
    .scale(100) // Optional. The % at which to scale the height map. Default value: 100%
    .shift(0, 0) // Optional. The number of blocks the height map should be shifted east and south respectively (negative numbers shift west and north). Default value: 0, 0
    .applyToTerrain()
    .fromLevel(0).toTerrain(0) // Optional. Repeatable. Specifies that a single value from the image must be mapped to a single terrain type (see below)
    .fromLevels(0, 255).toTerrain(0) // Optional. Repeatable. Specifies that a range of values from the image must be mapped to a single terrain type (see below)
    .fromColour(0, 0, 0).toTerrain(0) // Optional. Repeatable. Specificies that a single colour, in the form of red, green and blue components from 0 to 255 (inclusive), from the image must be mapped to a single terrain type (see below). The alpha value is assumed to be 255 (fully opaque)
    .fromColour(0, 0, 0, 0).toTerrain(0) // Optional. Repeatable. Specificies that a single colour, in the form of alpha, red, green and blue components from 0 to 255 (inclusive), from the image must be mapped to a single terrain type (see below)
    .go();

About the mapping:

You may map EITHER grey scale values (using fromLevel() and fromLevels()) OR colour values (using fromColour()), but you may not mix both. Mapping colour values obviously is only useful if the height map was derived from a colour image. Note that the colours are only matched exactly as specified. Slightly different colours don't match. Therefore you must make sure that your input image contains only solid areas of discrete colours and has no anti-aliasing, smoothing, mixing of colours, gradients, etc.

For applying a height map to the terrain, the mapping is to arbitrary terrain type indices which correspond to different terrain types. It depends on the type of height map what kind of mapping makes sense. If it is a genuine height map (i.e. it corresponds to surface heights) then you can use it to map different height ranges to different terrain types, and it makes sense to use the ranged setter (fromLevels().toLevel()) to set up the mapping.

If instead the "height map" is a value map or mask which directly indicates which terrain types must be used then using the ranged setter does not make sense and it would be better to use the one on one setter (fromLevel().toLevel() or fromColour().toLevel()) repeatedly to set up each mapping of a "height map" value or colour to a terrain type.

For an overview of the actual terrain type indices to use and the terrain types to which they correspond, see this page. Note that if you want to include Custom Terrain types which aren't already present in the world, you must install the Custom Terrain type on the world first (see "Installing a Custom Terrain" above) and that operation will return the terrain index to use for that particular Custom Terrain.

Applying a Layer Directly

A layer can also be applied to a world directly, without a height map but optionally with a filter:

wp.applyLayer(layer) // See "Loading a Layer"
    .toWorld(world) // See "Loading a World" or "Creating a World from a Height Map"
    .toLevel(0) // Optional. The level to which to set the layer. The default is half the maximum for the layer type (or "on" for 1-bit layers such as Frost). See the discussion above under Applying a Height Map as a Layer
    .withFilter(filter) // Optional. Specifies conditions for where the layer will be applied. See below for details about creating a filter
    .applyToSurface() // Optional. Mutually exclusive with applyToNether() and applyToEnd(). Indicates that the layer should be applied to the Surface dimension. This is the default
    .applyToNether() // Optional. Mutually exclusive with applyToSurface() and applyToEnd(). Indicates that the layer should be applied to the Nether dimension
    .applyToEnd() // Optional. Mutually exclusive with applyToSurface() and applyToNether(). Indicates that the layer should be applied to the End dimension
    .setAlways() // Optional. Mutually exclusive with setWhenLower() and setWhenHigher(). Indicates that the layer intensity must always be overridden, no matter what it was before. This is the default
    .setWhenLower() // Optional. Mutually exclusive with setAlways() and setWhenHigher(). Indicates that the layer intensity must only be overridden if the value from the image is lower than what was already there in the world
    .setWhenHigher() // Optional. Mutually exclusive with setAlways() and setWhenLower(). Indicates that the layer intensity must only be overridden if the value from the image is higher than what was already there in the world
    .go();

For the layer value to specify with toLevel(), see the discussion above under Applying a Height Map as a Layer

Applying a Terrain Type Directly

A terrain type can also be applied to a world directly, without a height map but optionally with a filter:

wp.applyTerrain(0) // The terrain type index to set
    .toWorld(world) // See "Loading a World" or "Creating a World from a Height Map"
    .withFilter(filter) // Optional. Specifies conditions for where the layer will be applied. See below for details about creating a filter
    .applyToSurface() // Optional. Mutually exclusive with applyToNether() and applyToEnd(). Indicates that the layer should be applied to the Surface dimension. This is the default
    .applyToNether() // Optional. Mutually exclusive with applyToSurface() and applyToEnd(). Indicates that the layer should be applied to the Nether dimension
    .applyToEnd() // Optional. Mutually exclusive with applyToSurface() and applyToNether(). Indicates that the layer should be applied to the End dimension
    .go();

For an overview of the actual terrain type indices to use in applyTerrain() and the terrain types to which they correspond, see this page. Note that if you want to include Custom Terrain types which aren't already present in the world, you must install the Custom Terrain type on the world first (see "Installing a Custom Terrain" above) and that operation will return the terrain index to use for that particular Custom Terrain.

Creating a Filter

The height map, layer and terrain application operations described above can take a filter. Here is how you create one:

var filter = wp.createFilter()
    .aboveLevel(0) // Optional. Apply the operation only at and above the specified terrain level
    .belowLevel(255) // Optional. Apply the operation only at or below the specified terrain level
    .feather() // Optional. When applying a continuously-valued layer, let it fade out around the specified terrain levels, instead of being cut off sharply
    .aboveDegrees(0) // Optional. Mutuatlly exclusive with belowDegrees(). Specifies the slope in degrees above which the operation must be applied. PLEASE NOTE: only works well with worlds created from high res (16-bit) height maps or sculpted manually in WorldPainter!
    .belowDegrees(0) // Optional. Mutuatlly exclusive with aboveDegrees(). Specifies the slope in degrees below which the operation must be applied. PLEASE NOTE: only works well with worlds created from high res (16-bit) height maps or sculpted manually in WorldPainter!
    .onlyOnTerrain(0) // Optional. Mutually exclusive with all other onlyOn* and exceptOn* conditions. Specifies the terrain index of the terrain on which the operation should only be applied
    .onlyOnLayer(layer) // Optional. Mutually exclusive with all other onlyOn* and exceptOn* conditions. Specifies the layer which must be present for the operation to be applied
    .onlyOnBiome(0) // Optional. Mutually exclusive with all other onlyOn* and exceptOn* conditions. Specifies the biome ID of the manually painted biome on which the operation should only be applied
    .onlyOnAutoBiome(0) // Optional. Mutually exclusive with all other onlyOn* and exceptOn* conditions. Specifies the biome ID of the automatically set biome on which the operation should only be applied
    .onlyOnAutoBiomes() // Optional. Mutually exclusive with all other onlyOn* and exceptOn* conditions. Specifies that the operation must only be applied on automatically set biomes
    .onlyOnWater() // Optional. Mutually exclusive with all other onlyOn* and exceptOn* conditions. Specifies that the operation must only be applied on flooded areas
    .onlyOnLand() // Optional. Mutually exclusive with all other onlyOn* and exceptOn* conditions. Specifies that the operation must only be applied on dry areas
    .exceptOnTerrain(0) // Optional. Mutually exclusive with all other onlyOn* and exceptOn* conditions. Specifies the terrain index of the terrain on which the operation must NOT be applied
    .exceptOnLayer(layer) // Optional. Mutually exclusive with all other onlyOn* and exceptOn* conditions. Specifies the layer which must NOT be present for the operation to be applied
    .exceptOnBiome(0) // Optional. Mutually exclusive with all other onlyOn* and exceptOn* conditions. Specifies the biome ID of the manually painted biome on which the operation should NOT be applied
    .exceptOnAutoBiome(0) // Optional. Mutually exclusive with all other onlyOn* and exceptOn* conditions. Specifies the biome ID of the automatically set biome on which the operation should NOT be applied
    .exceptOnAutoBiomes() // Optional. Mutually exclusive with all other onlyOn* and exceptOn* conditions. Specifies that the operation must only be applied on manually painted biomes
    .exceptOnWater() // Optional. Mutually exclusive with all other onlyOn* and exceptOn* conditions. Specifies that the operation must only be applied on dry areas
    .exceptOnLand() // Optional. Mutually exclusive with all other onlyOn* and exceptOn* conditions. Specifies that the operation must only be applied on flooded areas
    .go();

For an overview of the actual terrain type indices to use in onlyOnTerrain() or exceptOnTerrain() and the terrain types to which they correspond, see this page. For an overview of the biome IDs to use in onlyOnBiome(), onlyOnAutoBiome(), exceptOnBiome() or exceptOnAutoBiome() see this page.

Last modified 20 months ago Last modified on 05/07/23 16:27:39