维度与结构生成(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 生效与验证¶
- 重启服务端(维度在开服时加载,
/reload不会重新注册维度); - 进服后测试:
/execute in ffgs:void_world run tp @p 0 80 0; - 成功了恭喜——你已经有一个全新的维度了!
2. 自定义结构(Structure)¶
2.1 结构的三种来源¶
| 来源 | 说明 | 能不能 place |
|---|---|---|
| 原版结构 | minecraft:village_plains、minecraft: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 tp;RESOURCE_LOCATION参数类型见 30 章参数表。两个命令都设了requires(2)(OP 专用),想开放给玩家请把整段requires去掉。
4. 联动 ② 箱子 UI(27 章):维度传送面板 & 结构生成器¶
两个面板全部用 27 · 箱子 UI 的 openChestGUI 实现——能点、有物品图标、还能放按钮回调,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.add 里 ore.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 推荐工具。