Summary
Add a core lib for custom dimensions — create, open, manage, and delete
dimensions from Lua. Dimensions persist at world/dimensions/<ns>/<path>,
survive script removal and reloads, and compose with the existing mc.world,
world-wrapper, and player:teleport APIs.
local dimension = require "core:dimension"
local arena = dimension.register("mypack:arena", {
type = "void",
seed = 42,
own_rules = true,
})
dimension.get("mypack:arena"):teleport(player)
mc.on("player_changed_dimension", function(player, from, to)
end)
Related: worldgen proposal, #7, #13 (lifecycle), #20.
API
Core lib require "core:dimension".
Registration
dimension.register(id, opts?) -> Dimension
| Key |
Type |
Default |
Meaning |
type |
string |
"overworld" |
Preset (overworld,nether,end,flat,void), vanilla dimension-type id, or worldgen-registered type |
seed |
number |
world seed |
Used only on first creation; ignored after the world has chunks |
own_rules |
boolean |
true |
true — independent game rules; false — shares rules live with the overworld |
- Idempotent. Re-registering the same id returns the existing handle.
Config is frozen on first creation — a conflicting declaration logs a
warning and returns the existing dimension.
- Never auto-deleted. Removing a script, reloading, or hot-reloading
never deletes dimension data. Only delete removes a dimension.
minecraft:* ids are reserved.
- The returned handle has a live
.world immediately.
Discovery
dimension.get(id) -> Dimension | nil
dimension.list() -> { Dimension, ... }
Deletion
dimension.delete(id, force?)
- Teleports all players out first. Removes region files from disk.
force defaults to false (confirmation required, like Multiverse's
confirm prompt); force = true skips it. Irreversible.
Dimension handle
dim.id -- "mypack:arena"
dim.world -- existing World wrapper (all block/entity/weather APIs)
dim:teleport(player, pos?) -- enter the dimension; defaults to world.spawn
dim:delete(force?)
Events
mc.on("player_changed_dimension", function(player, from, to)
end)
from / to are dimension id strings, or nil when entering/leaving
the server.
World spawn (companion change)
The existing world wrapper gains world.spawn — a read/write {x, y, z}
property. dim:teleport(player) resolves to world.spawn (or
{0, 64, 0} if not set).
Registration & lifecycle
- Dimensions are opened at game time during module-level script load.
Runtime ServerWorld creation is proven on 1.21.8–1.21.11 by the
Multiverse mod (Fabric, server-side, using Arcade's dimensions module).
- On
/ignis reload: commands, events, the scheduler, regions, holograms
etc. all clear — but the dimension registry is additive and persistent.
Existing worlds stay open. Changed configs are ignored (warn). Removed
scripts do not delete worlds.
- Data lives at
world/dimensions/<ns>/<path> — same layout as vanilla
datapack dimensions.
Non-goals (v1)
- Defining custom dimension types from Lua — see the worldgen proposal.
- Portal-linked custom overworld/nether/end triples.
- Per-dimension tick rate.
- Unloading a world without deleting it.
Acceptance criteria
- Every preset and worldgen-registered type produces a live, reachable world.
dim:teleport(player) and player:teleport(x,y,z,id) work.
- The full
world wrapper works inside custom dimensions.
mc.world(id) returns the custom world.
own_rules = true isolates gamerules; own_rules = false mirrors the
overworld live.
- Chunks persist across restarts and reloads.
- Reloading/removing a script never deletes or crashes a dimension.
- Reserved / duplicate / bad-type ids error clearly.
delete removes the world, its region files, and evicts players safely.
Open questions
- Should the seed be mutable before the first chunk generates?
- Should
dimension.list() include on-disk-only worlds that aren't currently
open?
Summary
Add a core lib for custom dimensions — create, open, manage, and delete
dimensions from Lua. Dimensions persist at
world/dimensions/<ns>/<path>,survive script removal and reloads, and compose with the existing
mc.world,world-wrapper, and
player:teleportAPIs.Related: worldgen proposal, #7, #13 (lifecycle), #20.
API
Core lib
require "core:dimension".Registration
type"overworld"overworld,nether,end,flat,void), vanilla dimension-type id, or worldgen-registered typeseedown_rulestrue— independent game rules;false— shares rules live with the overworldConfig is frozen on first creation — a conflicting declaration logs a
warning and returns the existing dimension.
never deletes dimension data. Only
deleteremoves a dimension.minecraft:*ids are reserved..worldimmediately.Discovery
Deletion
forcedefaults tofalse(confirmation required, like Multiverse'sconfirm prompt);
force = trueskips it. Irreversible.Dimension handle
Events
from/toare dimension id strings, ornilwhen entering/leavingthe server.
World spawn (companion change)
The existing
worldwrapper gainsworld.spawn— a read/write{x, y, z}property.
dim:teleport(player)resolves toworld.spawn(or{0, 64, 0}if not set).Registration & lifecycle
Runtime
ServerWorldcreation is proven on 1.21.8–1.21.11 by theMultiverse mod (Fabric, server-side, using Arcade's dimensions module).
/ignis reload: commands, events, the scheduler, regions, hologramsetc. all clear — but the dimension registry is additive and persistent.
Existing worlds stay open. Changed configs are ignored (warn). Removed
scripts do not delete worlds.
world/dimensions/<ns>/<path>— same layout as vanilladatapack dimensions.
Non-goals (v1)
Acceptance criteria
dim:teleport(player)andplayer:teleport(x,y,z,id)work.worldwrapper works inside custom dimensions.mc.world(id)returns the custom world.own_rules = trueisolates gamerules;own_rules = falsemirrors theoverworld live.
deleteremoves the world, its region files, and evicts players safely.Open questions
dimension.list()include on-disk-only worlds that aren't currentlyopen?