Summary
Add a core lib to define custom world generation from Lua — procedural chunk
generation callbacks plus declarative presets (flat layers, noise settings,
biome sources). Registered generators are consumed by the dimensions API.
local worldgen = require "core:worldgen"
worldgen.register("mypack:custom", {
generator = "lua",
biome = "minecraft:plains",
generate = function(ctx)
ctx:fill(ctx.x0, ctx.minY, ctx.z0, ctx.x1, 63, ctx.z1, "minecraft:stone")
end,
})
local dimension = require "core:dimension"
local arena = dimension.register("mypack:arena", { type = "mypack:custom" })
Related: dimension proposal, #7, #5.
API
Core lib require "core:worldgen".
Registration
worldgen.register(id, config)
Same idempotent, never-auto-deleted semantics as the dimension registry.
First registration wins; re-registering the same id with different config
logs a warning and keeps the original. worldgen.get(id) and
worldgen.list() provide introspection.
Generator modes
| Mode |
Description |
"lua" |
Full control via a generate(ctx) callback |
"flat" |
Superflat with declarative layers |
"noise" |
Noise-based terrain with declarative settings |
Default is "noise". Only one mode per registration.
Lua generator (generator = "lua")
worldgen.register("mypack:custom", {
generator = "lua",
biome = "minecraft:plains",
generate = function(ctx)
-- ctx: chunk generation context — writes only (no reads guaranteed)
-- ctx.x, ctx.z — chunk coordinates
-- ctx.x0 .. ctx.z1 — world-coordinate bounds of the chunk
-- ctx.minY, ctx.maxY — vertical bounds
-- Block placement (world coordinates):
ctx:setBlock(x, y, z, "minecraft:diamond_block")
ctx:fill(x1, y1, z1, x2, y2, z2, "minecraft:stone")
-- Place a vanilla placed feature at a location:
ctx:placeFeature("minecraft:oak", x, y, z)
end,
})
The callback runs once per chunk during worldgen, synchronously on the
server thread. Additional context helpers (getBiome, setBiome, getNoise,
decorate) can be added iteratively.
Flat generator (generator = "flat")
worldgen.register("mypack:flat", {
generator = "flat",
biome = "minecraft:plains",
layers = {
{ block = "minecraft:bedrock", height = 1 },
{ block = "minecraft:stone", height = 59 },
{ block = "minecraft:grass_block", height = 1 },
},
})
block resolves with the usual minecraft: default if un-namespaced.
Noise generator (generator = "noise")
worldgen.register("mypack:noise", {
generator = "noise",
biome = { plains = 1, desert = 0.5 }, -- weighted multi-biome
-- or biome = "minecraft:plains" -- fixed single biome
noise = {
sea_level = 63,
default_block = "minecraft:stone",
default_fluid = "minecraft:water",
min_y = -64, height = 384,
aquifers = true, ore_veins = true,
},
density = "minecraft:overworld", -- noise router preset
surface = "minecraft:overworld", -- surface rule preset
features = { "minecraft:village_plains" },
structures = { "minecraft:mineshaft", "minecraft:stronghold" },
})
biome accepts a string (single biome) or a table of
<biome_id> = <weight> for weighted multi-biome selection. density and
surface reference existing presets; a builder API for customising them is
deferred. features and structures reference vanilla or datapack placed-
feature / structure ids.
Discovery
worldgen.get("mypack:custom") -> table | nil
worldgen.list() -> { id, ... }
Registration order
Worldgen types must be declared before any dimension that references
them. If both registries are deferred to end-of-load this ordering
constraint is enforced automatically; if they execute at module level,
require "core:worldgen" must appear before require "core:dimension"
in load order.
Non-goals (v1)
- Multi-threaded or async chunk generation
- Exposing raw NBT or codec APIs for density functions / surface rules
- Custom block-entity generation from the callback
- Client-side custom rendering
Acceptance criteria
- Lua
generate callback fires per chunk and produces visible blocks
ctx:fill and ctx:setBlock place blocks correctly
- Flat layers produce the requested stack with the declared biome
- Noise generator respects sea level, default block/fluid, height, and
toggles
- Weighted multi-biome sources select biomes correctly
- Referenced vanilla features and structures spawn in the generated world
worldgen.get / worldgen.list return correct data
- Reloading a script that re-registers the same type is a no-op
Open questions
- Should
generate return before the chunk is fully populated (yield /
async)?
- How to handle
ctx:placeFeature crossing chunk boundaries — should it be
deferred to a post-generate decorate phase or handled when neighbour chunks
exist?
- For
density / surface: keep as preset references in v1 or provide a
builder API?
- Should
generate have access to the world wrapper (for reads / neighbor
chunk queries) or a restricted generation-only view?
Summary
Add a core lib to define custom world generation from Lua — procedural chunk
generation callbacks plus declarative presets (flat layers, noise settings,
biome sources). Registered generators are consumed by the dimensions API.
Related: dimension proposal, #7, #5.
API
Core lib
require "core:worldgen".Registration
Same idempotent, never-auto-deleted semantics as the dimension registry.
First registration wins; re-registering the same id with different config
logs a warning and keeps the original.
worldgen.get(id)andworldgen.list()provide introspection.Generator modes
"lua"generate(ctx)callback"flat"layers"noise"Default is
"noise". Only one mode per registration.Lua generator (
generator = "lua")The callback runs once per chunk during worldgen, synchronously on the
server thread. Additional context helpers (getBiome, setBiome, getNoise,
decorate) can be added iteratively.
Flat generator (
generator = "flat")blockresolves with the usualminecraft:default if un-namespaced.Noise generator (
generator = "noise")biomeaccepts a string (single biome) or a table of<biome_id> = <weight>for weighted multi-biome selection.densityandsurfacereference existing presets; a builder API for customising them isdeferred.
featuresandstructuresreference vanilla or datapack placed-feature / structure ids.
Discovery
Registration order
Worldgen types must be declared before any dimension that references
them. If both registries are deferred to end-of-load this ordering
constraint is enforced automatically; if they execute at module level,
require "core:worldgen"must appear beforerequire "core:dimension"in load order.
Non-goals (v1)
Acceptance criteria
generatecallback fires per chunk and produces visible blocksctx:fillandctx:setBlockplace blocks correctlytoggles
worldgen.get/worldgen.listreturn correct dataOpen questions
generatereturn before the chunk is fully populated (yield /async)?
ctx:placeFeaturecrossing chunk boundaries — should it bedeferred to a post-generate decorate phase or handled when neighbour chunks
exist?
density/surface: keep as preset references in v1 or provide abuilder API?
generatehave access to the world wrapper (for reads / neighborchunk queries) or a restricted generation-only view?