跳转至

维度与结构生成(Dimension & Structure)

让服务器拥有自定义维度自定义结构,并用 KubeJS 把它们变成可玩的玩法(传送面板、生成命令、点击生成器)。

⚠️ 先读这一条(1.20.1 的真相):KubeJS 6.1 的 WorldgenEvents 只能做生物群系内的矿石/湖等小修改(见 08 · Worldgen),官方 wiki 已明确 1.20.1 无法用脚本直接注册维度与结构。正确姿势 = 数据包 JSON + KubeJS 联动

  • 注册(维度/结构本体)→ JSON 数据包,放进 kubejs/data/ 即可被自动加载(原理见 10 · 加载资源与数据:KubeJS 的 data 文件夹与数据包 data 完全一致)
  • 玩法(传送、生成、菜单)→ 用本章的 KubeJS 脚本串联起来

联动章节27 · 箱子 UI(本章的传送/生成面板全靠它)、30 · 自定义命令(注册 /dimtp /structplace)、08 · Worldgen(往维度里加矿石)、10 · 数据包加载


1. 自定义维度(Custom Dimension)

1.1 要建哪些文件

kubejs/data/ 下按下面结构放两个 JSON(<ns> 换成你自己的命名空间,如 ffgs):

kubejs/data/<ns>/
├── dimension_type/<dim_id>.json   ← 维度的"规则"(能不能睡觉、天空、高度…)
└── dimension/<dim_id>.json        ← 维度的"本体"(用哪个规则 + 地形怎么生成)

1.2 先建维度规则 dimension_type

示例 kubejs/data/ffgs/dimension_type/void_world.json(超平坦虚空城维度规则):

{
  "ultrawarm": false,                  // 是否为地狱式炎热(水会蒸发)
  "natural": true,                     // 是否算"主世界式"(能睡觉、有昼夜)
  "coordinate_scale": 1.0,             // 坐标缩放比例(1.0 = 与主世界 1:1)
  "has_skylight": true,                // 是否有天空光照(昼夜变化)
  "has_ceiling": false,                // 是否有基岩天花板
  "ambient_light": 0.0,                // 环境光亮度
  "fixed_time": 6000,                  // 固定时间(可选,写了就永远是正午)
  "bed_works": true,                   // 能否用床睡觉 / 设重生点
  "respawn_anchor_works": false,       // 重生锚是否有效
  "min_y": 0,                          // 世界最低 Y(1.20.1 范围 -64 ~ 2032)
  "height": 256,                       // 世界总高度
  "logical_height": 256,               // 能传送到的高度上限
  "infiniburn": "#minecraft:infiniburn_overworld",  // 下界传送门点火用什么可燃
  "effects": "minecraft:overworld"     // 天空/云雾效果(overworld / the_nether / the_end)
}

1.3 再建维度本体 dimension

示例 kubejs/data/ffgs/dimension/void_world.json

{
  "type": "ffgs:void_world",           // 引用上面那个维度规则
  "generator": {
    "type": "minecraft:flat",          // 平坦地形生成器
    "settings": {
      "biome": "minecraft:plains",     // 这个维度里的生物群系
      "lakes": false,
      "features": false,
      "layers": [
        { "block": "minecraft:bedrock", "height": 1 },   // 最底层 1 格基岩
        { "block": "minecraft:stone", "height": 3 }
      ],
      "structure_overrides": []        // 不在平坦世界上生成原版结构
    }
  }
}

💡 想要主世界式地形?把 generator 换成噪声预设即可,例如: "generator": { "type": "minecraft:noise", "settings": "minecraft:overworld", "biome_source": { "type": "minecraft:multi_noise", "preset": "minecraft:overworld" } } 想要完全空岛式 → "type": "minecraft:flat" + "layers": [{ "block": "minecraft:air", "height": 1 }]

1.4 生效与验证

  1. 重启服务端(维度在开服时加载,/reload 不会重新注册维度);
  2. 进服后测试:/execute in ffgs:void_world run tp @p 0 80 0
  3. 成功了恭喜——你已经有一个全新的维度了!

2. 自定义结构(Structure)

2.1 结构的三种来源

来源 说明 能不能 place
原版结构 minecraft:village_plainsminecraft:igloo /place structure minecraft:igloo
结构方块导出的 .nbt kubejs/data/<ns>/structures/<name>.nbt ✅ 用 /place template <ns>:<name>
数据包注册的完整结构 worldgen/structure + structure_set + template_pool /place structure <ns>:<name>

🧱 最快路径:单人世界用结构方块把建筑存成 .nbt,拷到 kubejs/data/<ns>/structures/,服务端就能直接 /place template不需要写任何结构 JSON

2.2 手动放置命令(1.20.1 原版)

/place structure <命名空间:结构id> [x y z]     ← 放置已注册的结构(含原版结构)
/place template  <命名空间:nbt文件名> [x y z]  ← 直接放置 structures/ 下的 .nbt 模板
/place feature   <命名空间:地物id>             ← 放置地物(configured feature)

⚠️ /place 需要 OP(权限 2 级)。但用 KubeJS 的 server.runCommandSilent(...) 执行时是以服务端身份运行,不占玩家权限——所以面板/按钮给普通玩家点也没问题(见下文)。

2.3 让结构"自然生成"(数据包完整注册)

想让它像村庄一样自动刷在世界里,需要三个 JSON(<ns> = 命名空间,<pool> = 结构池名):

kubejs/data/<ns>/worldgen/template_pool/<pool>.json —— 结构池(决定 .nbt 从哪来、能否拼接):

{
  "fallback": "minecraft:empty",
  "elements": [
    {
      "weight": 1,
      "element": {
        "element_type": "minecraft:single_pool_element",
        "projection": "rigid",
        "location": "<ns>:<nbt文件名>",     // 指向 structures/ 下的 .nbt
        "processors": "minecraft:empty"
      }
    }
  ]
}

kubejs/data/<ns>/worldgen/structure/<name>.json —— 结构定义(一个结构引用一个起始池):

{
  "type": "minecraft:jigsaw",
  "biomes": "#minecraft:is_overworld",     // 在哪些生物群系生成
  "step": "surface_structures",
  "terrain_adaptation": "beard_thin",
  "spawn_overrides": {},
  "start_pool": "<ns>:<pool>",
  "size": 1,
  "start_height": { "absolute": 0 },
  "use_expansion_hack": false
}

kubejs/data/<ns>/worldgen/structure_set/<name>.json —— 结构集(决定生成间距,让世界生成器"发现"它):

{
  "structures": [
    { "structure": "<ns>:<name>", "weight": 1 }
  ],
  "placement": {
    "type": "minecraft:random_spread",
    "spacing": 24,        // 每隔多少区块尝试一次
    "separation": 12,     // 两个结构之间的最小间隔
    "salt": 123456789
  }
}

💡 手写容易错?用 Misode 的 Worldgen 生成器(https://misode.github.io/worldgen/)选 structure/pool 预设改,跟 08 章推荐的是同一个工具。生成后同样重启服务端生效。


3. 联动 ① 命令(30 章):/dimtp 与 /structplace

注册两个实用命令,语法全部来自 30 · 自定义命令注册commandRegistry / event.arguments.DIMENSION / suggests)。

// server_scripts/dim_commands.js —— 维度传送 + 结构生成命令
ServerEvents.commandRegistry(event => {
  const { commands } = event

  // /dimtp <维度> —— 把自己传送到某个维度(默认传送到该维度的出生点 0 80 0)
  event.register(
    commands.literal('dimtp')
      .requires(src => src.hasPermission(2))
      .then(
        commands.argument('dim', event.arguments.DIMENSION)          // 维度参数(30章参数表)
          .suggests((ctx, builder) =>                               // Tab 补全常用维度
            event.builtinSuggestions.suggest(
              ['minecraft:overworld', 'minecraft:the_nether', 'minecraft:the_end', 'ffgs:void_world'],
              builder)
          )
          .executes(ctx => {
            let player = ctx.source.player
            let dim = ctx.arguments.dim
            player.server.runCommandSilent(`execute in ${dim} run tp ${player.username} 0 80 0`)
            player.tell('§a已传送到维度:' + dim)
            return 1
          })
      )
  )

  // /structplace <结构id> —— 在玩家位置生成结构(服务端执行,玩家无需 OP)
  event.register(
    commands.literal('structplace')
      .requires(src => src.hasPermission(2))
      .then(
        commands.argument('struct', event.arguments.RESOURCE_LOCATION)  // 资源位置参数
          .executes(ctx => {
            let player = ctx.source.player
            let struct = ctx.arguments.struct
            player.server.runCommandSilent(`place structure ${struct} ${player.x} ${player.y} ${player.z}`)
            player.tell('§a已在你的位置生成结构:' + struct)
            return 1
          })
      )
  )
})

💡 维度参数 DIMENSION 取出来是资源位置(ResourceLocation),可以直接拼进 execute in ... run tpRESOURCE_LOCATION 参数类型见 30 章参数表。两个命令都设了 requires(2)(OP 专用),想开放给玩家请把整段 requires 去掉。


4. 联动 ② 箱子 UI(27 章):维度传送面板 & 结构生成器

两个面板全部用 27 · 箱子 UIopenChestGUI 实现——能点、有物品图标、还能放按钮回调,1.20.1 内置无需插件。

4.1 维度传送面板(一个法杖打开,点格子换维度)

// server_scripts/dim_panel.js —— 右键「维度法杖」打开传送面板
ItemEvents.rightClicked('kubejs:dim_wand', event => {   // 前提:用 03 章方法注册 kubejs:dim_wand
  let player = event.player

  player.openChestGUI('维度传送', 2, gui => {
    // 每个按钮 = 一个可传送的维度(x/y/z = 目标坐标)
    let dims = [
      { key: '主世界',  dim: 'minecraft:overworld',    icon: 'minecraft:grass_block', x: 0,  y: 100, z: 0 },
      { key: '下界',    dim: 'minecraft:the_nether',   icon: 'minecraft:netherrack',  x: 0,  y: 80,  z: 0 },
      { key: '末地',    dim: 'minecraft:the_end',      icon: 'minecraft:end_stone',   x: 0,  y: 80,  z: 0 },
      { key: '虚空城',  dim: 'ffgs:void_world',        icon: 'minecraft:structure_void', x: 0, y: 80, z: 0 }
    ]

    dims.forEach((d, i) => {
      let x = i % 4, y = Math.floor(i / 4)              // 4 列排布
      gui.button(x, y, d.icon, '§b' + d.key + '\n§7点击传送到 ' + d.dim, click => {
        let p = click.slot.gui.player
        // 用 execute in 跨维度传送(runCommandSilent 由服务端执行)
        p.server.runCommandSilent(`execute in ${d.dim} run tp ${p.username} ${d.x} ${d.y} ${d.z}`)
        p.tell('§a已传送到:' + d.key)
      })
    })
  })
})

💡 button(x, y, 物品, 名称, 回调) 里名称支持 \n 换行、§ 颜色代码(27 章速查表同款语法)。跨维度必须用 execute in <维度> run tp,普通 tp 只能同维度内传送。

4.2 结构生成器面板(点按钮,在脚下生成建筑)

// server_scripts/struct_panel.js —— 右键「建筑工法杖」打开生成面板
ItemEvents.rightClicked('kubejs:struct_wand', event => {
  let player = event.player

  player.openChestGUI('结构生成器', 1, gui => {
    let structs = [
      { key: '雪屋',        id: 'minecraft:igloo',             icon: 'minecraft:snow_block' },
      { key: '掠夺者前哨站', id: 'minecraft:pillager_outpost', icon: 'minecraft:dark_oak_log' },
      { key: '沙漠神殿',    id: 'minecraft:desert_pyramid',    icon: 'minecraft:sandstone' },
      { key: '自定义塔楼',  id: 'ffgs:my_tower',               icon: 'minecraft:structure_block' }  // 2.3 注册的结构
    ]

    structs.forEach((s, i) => {
      gui.button(i, 0, s.icon, '§b' + s.key + '\n§7点击生成', click => {
        let p = click.slot.gui.player
        // 在玩家坐标生成(服务端执行,普通玩家点了也算数)
        p.server.runCommandSilent(`place structure ${s.id} ${p.x} ${p.y} ${p.z}`)
        p.tell('§a已生成结构:' + s.key + ',稍等片刻建筑就位!')
      })
    })
  })
})

💡 生成瞬间建筑可能"卡着加载",因为结构按区块异步生成;传送走再回来或等几秒即可看到。想精确控制朝向/位置可改用 /place template + 坐标参数。

4.3 组合拳:一个面板同时管"维度 + 结构"

把 4.1 和 4.2 合成 6 行面板(上面 4 行放维度、下面 2 行放结构),就是完整的「次元传送门·建筑工坊」:

// server_scripts/dimstruct_panel.js —— 全合一控制台(6 行 = 54 格)
ItemEvents.rightClicked('kubejs:portal_wand', event => {
  let player = event.player

  player.openChestGUI('次元控制台', 6, gui => {
    // 第 0~3 行:维度传送
    let dims = [
      { key: '主世界', dim: 'minecraft:overworld',  icon: 'minecraft:grass_block',     x: 0,  y: 100, z: 0 },
      { key: '下界',   dim: 'minecraft:the_nether', icon: 'minecraft:netherrack',      x: 0,  y: 80,  z: 0 },
      { key: '末地',   dim: 'minecraft:the_end',    icon: 'minecraft:end_stone',       x: 0,  y: 80,  z: 0 },
      { key: '虚空城', dim: 'ffgs:void_world',      icon: 'minecraft:structure_void', x: 0,  y: 80,  z: 0 }
    ]
    dims.forEach((d, i) => {
      gui.button(i % 9, Math.floor(i / 9), d.icon, '§b传送:' + d.key, click => {
        let p = click.slot.gui.player
        p.server.runCommandSilent(`execute in ${d.dim} run tp ${p.username} ${d.x} ${d.y} ${d.z}`)
      })
    })

    // 第 4~5 行:结构生成
    let structs = [
      { key: '雪屋',       id: 'minecraft:igloo',             icon: 'minecraft:snow_block' },
      { key: '沙漠神殿',   id: 'minecraft:desert_pyramid',    icon: 'minecraft:sandstone' },
      { key: '自定义塔楼', id: 'ffgs:my_tower',               icon: 'minecraft:structure_block' }
    ]
    structs.forEach((s, i) => {
      gui.button(i % 9, 4 + Math.floor(i / 9), s.icon, '§e生成:' + s.key, click => {
        let p = click.slot.gui.player
        p.server.runCommandSilent(`place structure ${s.id} ${p.x} ${p.y} ${p.z}`)
      })
    })

    // 放个"确认提示条"(27 章全局回调)
    gui.anyClicked = click => {
      if (click.slot.y < 4) click.slot.gui.player.tell('§7使用中:点击上方格子传送维度,下方格子生成建筑')
    }
  })
})

💡 gui.button 只响应左键;想要右键也能触发,用 27 章的 slot.setRightClicked(...)


5. 联动 ③ 其它章节(我评估的关联)

想继续做 去哪个章节
自定义维度的生物群系里加矿石/湖(比如虚空城地底埋矿) 08 · Worldgen —— WorldgenEvents.addore.biomes = 'minecraft:plains' 改成你的维度群系 ID 即可
想给维度做专属地形(自定义生物群系) 数据包 worldgen/biome/*.json,Misode 生成器同上
想弄懂 .nbt 结构文件里存了什么、脚本里怎么读写 NBT 24 · NBT 数据操作
想理解 runCommandSilent 还能干哪些事(召唤/粒子/音效全家桶) 21 · KubeJS 进阶实战 第 6 节附近
想右键自定义方块(而不是法杖)打开上面的面板 03 · 自定义方块 注册方块 → 事件换成 BlockEvents.rightClicked
想给面板加权限开关(只有管理员能传送/生成) 30 · 自定义命令requires + 26 章式判断,或 27 章 gui.closed 里做二次校验

6. 速查表 & 常见坑

速查表

想做什么 做法
建维度规则 kubejs/data/<ns>/dimension_type/<id>.json
建维度本体 kubejs/data/<ns>/dimension/<id>.json
手动进维度 /execute in <ns>:<id> run tp @p x y z
脚本传送到维度 server.runCommandSilent(\execute in ${dim} run tp ${p.username} ...`)`
放置 .nbt 模板 /place template <ns>:<nbt名>
放置已注册结构 /place structure <ns>:<id>
结构池/结构/结构集 worldgen/template_pool + worldgen/structure + worldgen/structure_set 三个 JSON
用 UI 做传送/生成面板 player.openChestGUI(标题, 行数, gui => { gui.button(...) })
注册 /dimtp /structplace ServerEvents.commandRegistry(30 章)

常见坑 - ⚠️ 维度/结构 JSON 改动必须重启服务端/reload 不会重新注册维度和 structure_set; - ⚠️ 结构方块导出的 .nbt 一定要放在 kubejs/data/<ns>/structures//place template 才能找到; - ⚠️ /place structure 只能放已注册的结构(原版 ID 或你自己数据包的);散装 .nbt/place template; - ⚠️ 生物群系过滤写维度群系时用维度自己的群系 ID,别默认成主世界的; - ✅ runCommandSilent 以服务端身份执行 → 面板按钮给普通玩家点也不会触发"权限不足"; - ✅ 维度 JSON 的 natural: false 会让床爆炸(像下界)——做"安全虚空城"记得写 true


本章原创编写,联动 08/10/21/24/27/30 章节。API 依据 Minecraft 1.20.1 数据包格式 + KubeJS 6.1 实测;Misode 生成器为官方 wiki 推荐工具。