Repository navigation
API Worldgen Features and Placements
Lua API / World generation / Features and placements
Features describe reusable bounded terrain changes. Placements decide when, where, and in what order a feature is attempted in newly populated chunks.
Compiles a feature and returns a reference. Keys normalize to namespace:feature/path; get returns a reference or
nil, and getRequired raises an error.
local clayPatch = betamoon.worldgen.features:add {
key = "mymod:clay_patch",
type = "block_patch",
block = 82,
radius = 4,
tries = 32,
replace = { 12, 13 }
}| Type | Fields and behavior |
|---|---|
ore_vein |
Required block, size 1–128, and replace; optional metadata = 0. |
block_patch |
Required block; radius = 4, tries = 64, replace = { air }, metadata = 0. |
column |
Required block and height 1–32; direction = "up" or "down", replace = { air }, metadata = 0. Invalid direction strings are rejected. |
disk |
Required block, radius, and replace; halfHeight = 1 accepts 0–8; metadata = 0. |
weighted |
Required nonempty features = { { feature, weight }, ... }; one child is selected per invocation. Every weight is positive. |
sequence |
Required nonempty features; every child plans in declaration order into the same atomic plan. |
no_op |
Makes no changes; useful as an explicit disabled target. |
Integer/range fields accept an integer or { min = n, max = n }. Composite maxBlocks and maxRadius fields are
required safety declarations when the automatic limits are unsuitable; they are not measurements calculated from
the children. A sequence child failure rejects the complete combined plan. A weighted feature runs only its selected
child.
A local feature may change at most 8192 blocks within radius 32. Unknown dependencies and feature cycles reject the
mod's new declarations while the previously active declarations remain available. References expose getKey() and
can be reused by placements and composites.
Schedules a feature and returns a placement reference.
betamoon.worldgen.placements:add {
key = "mymod:clay_patch",
feature = clayPatch,
stage = "underground_features",
dimensions = { "overworld" },
attempts = {
perChunk = { min = 1, max = 2 },
extraChance = 0.25,
rarity = 3
},
successLimit = 2,
position = {
horizontal = "chunk",
height = { type = "ocean_floor" }
},
conditions = {
ground = { 12, 13 },
water = true
}
}| Field | Default / behavior |
|---|---|
key |
Required stable key, normalized to namespace:placement/path. |
feature |
Required feature, tree, or local-structure reference/key. |
stage |
surface_features; also underground_features, entities, and post_process. |
dimensions |
Overworld; accepts canonical names and overworld, nether/hell, both, or all. |
attempts |
1; integer/range 0–256 or the extended table below. |
successLimit |
256; accepts 1–256 and stops further attempts after that many successful placements. |
position |
Horizontal and height sampling. |
conditions |
Origin block, medium, light, sky, biome, and optional structure-site checks. |
biomes |
List or { include, exclude, includeTags, excludeTags }. |
before, after
|
Same-stage placement dependencies. Cross-stage edges and cycles are rejected. |
priority |
0; lower values run first after dependency ordering. |
salt |
0; extra deterministic seed input. |
Placement references expose getKey() and getFeature(). The registry provides get and getRequired.
attempts = {
perChunk = { min = 2, max = 4 },
extraChance = 0.3,
probability = 0.5,
rarity = 8
}For each chunk:
- Sample the
probabilityorraritygate once. - Sample
perChunkonce when it is a range. -
extraChancemay add one attempt. - Sample a position and conditions independently for each attempt.
- Stop after
successLimitsuccessful placements.
extraChance accepts 0 inclusive through 1 exclusive. probability accepts 0–1. rarity = n means probability
1/n; explicit probability takes precedence if both are present. Zero attempts are valid and keep a placement
registered without generating it.
horizontal = "chunk" samples random X/Z coordinates in the chunk. "grid" uses deterministic cells separated by
gridSpacing 1–16. Attempts may revisit a grid cell when the attempt count exceeds the available cells.
| Height type | Defaults and behavior |
|---|---|
uniform |
Uniform integer from min = 0 through max = 127. |
triangular / normal
|
Average of two uniform samples, concentrating results toward the middle. |
fixed |
Uses value; when omitted, uses min. |
surface / world_surface
|
Samples the world surface plus optional offset. |
solid_surface |
Finds the first position above solid terrain, ignoring fluids. |
ocean_floor |
Finds the floor beneath a fluid column. |
fluid_surface |
Finds the first position above the fluid column. |
underground |
Samples 8–32 blocks below solid_surface by default; configure minDepth and maxDepth. |
cave_floor |
Searches Y 1–96 by default for a floor with minimumClearance = 3. |
ceiling |
Scans downward for air directly below a non-air block; accepts min and max. |
When a height provider cannot find a candidate, that attempt is skipped.
ground checks the block immediately below the sampled origin. air, water, and lava are booleans: true
requires that medium at the origin and false rejects it. minLight and maxLight accept 0–15.
Ordinary requireSky supports requiring sky access. To require no sky across a structure footprint or clearance mask,
use conditions.site.requireSky = false; see structure terrain placement.
Returns the nearest chunk whose deterministic probability/rarity roll permits the placement, or nil. It is
read-only and does not load or generate chunks.
local candidate = shrinePlacement:locateCandidate(ctx.world, ctx.position.x, ctx.position.z, 64)
if candidate then
betamoon.chat:send("Eligible chunk center: %i, %i", candidate.x, candidate.z)
end| Field | Meaning |
|---|---|
x, z
|
Candidate chunk-center block coordinates. |
chunkX, chunkZ
|
Chunk coordinates. |
loaded |
Whether the chunk is currently loaded, not whether placement succeeded. |
maxChunks defaults to 32 and accepts 0–128. The lookup reproduces only the chunk gate. Terrain, positions,
conditions, feature planning, and collisions may still reject every attempt. Ordinary placements are not saved or
indexed as structure starts.
Builds and validates the same plan as place without mutating the world.
local result = structure:preview(ctx.world, x, y, z, {
seed = 42,
rotation = "clockwise_90",
mirror = "left_right"
})| Field | Behavior |
|---|---|
seed |
Additional deterministic salt. Reuse it for a matching place. |
rotation |
Optional transform override for structures and structure-backed trees. |
mirror |
Optional mirror override for structures and structure-backed trees. |
World changes between preview and placement can still change or reject the later plan.
Plans and commits the complete feature from an active authoritative callback. The world must be that callback's live action-world handle, coordinates are separate integers, and Y must be 0–127. Successful runtime placement publishes render and neighbor updates only after the complete block transaction has committed.
The result contains placed, blocksChanged, optional reason, optional bounds = { min, max }, and optional
terrain details. Common details include the requested/resolved anchor, sampled height range, support and site ratios,
terrain mode/surface, and planned write totals. Structure terrain policies add focused aggregates:
| Policy | Detail fields |
|---|---|
| Foundation |
foundationCoreCells, foundationCoreWrites, foundationEdgeWrites, foundationMaximumDepth, foundationBounds
|
| Terrace |
terraceCoreCells, terraceTransitionCells, terraceCutBlocks, terraceFillBlocks, terraceBounds
|
| Conform |
conformSource, conformSupportColumns, conformSelectedColumns, conformComponents, conformMinimumDisplacement, conformMaximumDisplacement
|
| Excavation |
excavationVolumeCells, excavationRemoved, excavationPreserved, excavationAdaptationOverlaps
|
| Combined plan |
terrainWritesPlanned, terrainStructureOverlaps, structureWritesPlanned, totalWritesPlanned, and the first terrainRejectedPosition when relevant |
| Reason group | Values |
|---|---|
| General |
blocked, out_of_bounds, unloaded_chunk, invalid_ground, protected, budget_exceeded, no_changes, runtime_error
|
| Terrain fitting |
terrain_unreadable, terrain_slope, terrain_step, terrain_support, terrain_protected_block, terrain_tile_collision, terrain_mutation_budget
|
| Foundation |
foundation_invalid_footprint, foundation_too_deep, foundation_protected_block, foundation_tile_collision, foundation_fluid_collision
|
| Terrace |
terrace_invalid_footprint, terrace_cut_limit, terrace_fill_limit, terrace_grade_limit, terrace_protected_block, terrace_tile_collision, terrace_fluid_collision
|
| Conform |
conform_path_failed, conform_empty_selection, conform_unknown_mask, conform_selector_invalid, conform_displacement_limit, conform_step_limit, conform_column_collision
|
| Excavation |
excavation_invalid_volume, excavation_too_large, excavation_unreadable, excavation_protected_block, excavation_tile_collision, excavation_fluid_collision
|
| Site |
site_wrong_surface_relation, site_wrong_medium, site_fluid_coverage, site_fluid_depth, site_depth, site_insufficient_cover, site_insufficient_cavity, site_sky_mismatch
|
| Loot |
loot_target_missing, loot_inventory_size, loot_existing_contents, loot_overflow, loot_mutation_failed
|
Loot reasons are explained under structure inventory loot. A rejected local plan makes no block changes and does not load neighboring chunks.
Examples: simple feature placement, direct feature placement, and composite features.
- Installation
- Install scripts
- Getting started
- VS Code and LuaLS
- Examples
- Reload and compatibility
- Troubleshooting
- Changelog
Scripts and shared values
- Script lifecycle
- Packaged Lua mods
- Modules
- References and stacks
- Queries
- Overrides
- Minecraft constants
- Chat and positions
- Structured data
- Script configuration
- Particles
Blocks and items
- Multiblocks
- Blocks
- Block state and placement
- Block shapes and rendering
- Block callbacks
- Block ticks and redstone
- Items
- Fluids
- Item callbacks
- Tools and armor
- Materials
- Textures
Entities
- Entities
- Entity access and movement
- Entity lifecycle and data
- Entity health and loot
- Entity inventories and relationships
- Projectiles and pickups
- Entity presentation and sounds
- Living entities and AI
- Entity parts and sensors
Assets and audio
- Assets
- Models and animations
- Built-in Minecraft models
- Model appearances
- Blockbench workflow
- Audio
- Texture-pack overrides
Events and world actions
World generation
World systems
Inventories and screens
Recipes