Guide 1 Docs 2 Reference 3

Guide 5 of 5

A dungeon dimension

Add a world of your own beside the main one: a dungeon under a castle. It has its own type (no sky, a roof, no weather), its own terrain, and its own folder on disk if the server keeps one. A carpet in the yard is the gate.

What you build

  • A castle yard of stone bricks with a square of blue carpet in it.
  • dungeon, a second world: bedrock at both ends, mossy walls, two crossing corridors. A client draws it with the Nether’s dark sky.
  • Step on the carpet and you arrive in the dungeon. /leave brings you back.

This guide builds on Your first pack: world.on_generate and commands.add.

1. Declare the dimension

A pack adds a world in citadel.yml, under dimensions:. The name is its id inside the pack, so this one is castle:dungeon:

# citadel.yml
name: castle
entry: main.luau
motd: A castle with a dungeon under it
spawn_point: [0.5, 65.0, 0.5]
gamemode: 2
mode: lite
world: script
dimensions:
  dungeon:
    type: { has_skylight: false, has_ceiling: true, weather: false }
    world: script
  • type says how the world behaves. Every field is optional and starts from the main world’s: has_skylight, has_ceiling, weather, ultrawarm, bed_works, respawn_anchor_works, coordinate_scale, fixed_time and effects.
  • A world with a roof looks like the Nether to a client, one with no sky and no roof like the End. effects chooses one of the three yourself.
  • world: script means the pack makes its chunks. void leaves them empty.

The dungeon is a world of the server’s group: it ticks after the main world and, on a server that keeps its world, saves to world_dungeon beside it.

2. The yard

The main world, as in the first guide:

-- main.luau
-- The castle yard: a stone floor, and a square of blue carpet in the middle.
world.on_generate(function(chunk)
    chunk:fill(vec3(chunk.min.x, 64, chunk.min.z), vec3(chunk.max.x, 64, chunk.max.z), "stone_bricks")
    chunk:fill(vec3(4, 65, 4), vec3(5, 65, 5), "light_blue_carpet")
end)

3. The dungeon’s terrain

world.dimension(name) is that world’s own world table. Its on_generate fills the dungeon’s chunks:

-- main.luau
-- The dungeon: bedrock below and above, dark corridors in between.
local dungeon = world.dimension("dungeon")
dungeon.on_generate(function(chunk)
    chunk:fill(vec3(chunk.min.x, 63, chunk.min.z), vec3(chunk.max.x, 63, chunk.max.z), "bedrock")
    chunk:fill(vec3(chunk.min.x, 64, chunk.min.z), vec3(chunk.max.x, 68, chunk.max.z), "mossy_cobblestone")
    chunk:fill(vec3(chunk.min.x, 64, chunk.min.z + 6), vec3(chunk.max.x, 66, chunk.min.z + 9), "air")
    chunk:fill(vec3(chunk.min.x + 6, 64, chunk.min.z), vec3(chunk.min.x + 9, 66, chunk.max.z), "air")
    chunk:fill(vec3(chunk.min.x, 69, chunk.min.z), vec3(chunk.max.x, 69, chunk.max.z), "bedrock")
end)

4. The gate

A route is how a player gets from one world to another. This one starts in the overworld, and the trigger is standing in a block:

-- main.luau
-- Step on the carpet and you are in the dungeon.
routes.add{
    from = "overworld",
    to = "dungeon",
    trigger = { block = "light_blue_carpet" },
    placement = { x = 7.5, y = 64, z = 7.5 },
}
  • trigger = { block = "light_blue_carpet" } fires on the first tick a player stands in carpet. ticks = 80 would make them wait, as a Nether portal does.
  • placement is where they arrive. Leave it out and they arrive at the dungeon’s spawn.
  • After a trip a player must step out of the trigger block for half a second before it can fire again.

5. The way back

player:travel(dimension, pos) sends a player to any world of the group, at pos or, without it, at its spawn:

-- main.luau
-- `/leave` goes back up, to the yard's spawn.
commands.add("leave", function(player)
    player:travel("overworld")
end)

Try it

Run the pack, step on the carpet, look up at the roof, and type /leave.