世界生成流程

基本信息

属性 值
世界生成器 greymerk.roguelike.DungeonGenerator implements IWorldGenerator(DungeonGenerator.java:10)
注册 GameRegistry.registerWorldGenerator(worldGen, 0)(Roguelike.java:34)
优先级 0
实例 Roguelike.worldGen = new DungeonGenerator()(Roguelike.java:30)
同名类 ⚠️ 仓库里有两个 DungeonGenerator,见下文
维度支持 不限维度;跨维度开关由 dimensionWL / dimensionBL 与 biome 白名单控制

⚠️ 两个同名 DungeonGenerator

find . -name 'DungeonGenerator.java' 命中两个文件,二者无继承关系、职责完全不同:

全限定名 行数 角色
greymerk.roguelike.DungeonGenerator 21 实现 IWorldGenerator,是唯一被注册的世界生成器
greymerk.roguelike.dungeon.DungeonGenerator 66 内部编排器,负责逐层调用 LevelGenerator 并在末尾建塔

引用时必须带包名。仅写 DungeonGenerator 会有歧义。

功能

自然生成链路:

IWorldGenerator.generate(random, chunkX, chunkZ, world, cg, cp)   DungeonGenerator.java:13
  └─ new WorldEditor(world)
  └─ new Dungeon(editor)
  └─ dungeon.spawnInChunk(random, chunkX, chunkZ)                  Dungeon.java:146
       └─ Dungeon.canSpawnInChunk(chunkX, chunkZ, editor)          Dungeon.java:112
       └─ generateNear(rand, chunkX*16+4, chunkZ*16+4)              Dungeon.java:149-152

spawnInChunk 把区块坐标换算成方块坐标并固定偏移 +4(Dungeon.java:149-150),因此地牢不会贴着区块边界生成。

真正的生成入口是 dungeon/DungeonGenerator.generate(:24-61):自 TOPLEVEL = 50(:16)起,每层向下 VERTICAL_SPACING = 10(:15),逐层 level.generate(...),全部完成后再在 (inX, 50, inZ) 建塔。

区块网格算法

Dungeon.canSpawnInChunk(dungeon/Dungeon.java:112-144)用确定性网格决定哪些区块出地牢:

步骤 公式 来源
频率取值 frequency = RogueConfig.getInt(SPAWNFREQUENCY) Dungeon.java:118
网格下界 min = 8 * frequency / 10,再 min < 2 ? 2 : min :119,122
网格上界 max = 32 * frequency / 10,再 max < 8 ? 8 : max :120,123
负坐标修正 tempX = chunkX < 0 ? chunkX - (max - 1) : chunkX(Z 同样) :125-126
网格索引 m = tempX / max,n = tempZ / max :128-129
种子随机 editor.getSeededRandom(m, n, 10387312) :131
命中判定 chunkX == m && chunkZ == n 才返回 true :139-141

用默认值 spawnFrequency = 10 代入:min = 8、max = 32,即每 8×8 至 32×32 个区块的网格内随机命中 1 个区块。种子固定为 10387312 且只依赖网格索引 (m, n),因此同一世界内地牢位置可复现,且与玩家是否探索过无关。

选址合法性

Dungeon.validLocation(dungeon/Dungeon.java:165-189)逐项排除:

检查 规则 来源
biome 黑名单 RIVER、BEACH、MUSHROOM、OCEAN 四类命中即否决 :168-174
起始高度 upperLimit = RogueConfig.getInt(UPPERLIMIT)(默认 100) :176,179
起点必须是空气 if (!editor.isAirBlock(cursor)) return false; :181-183
向下找地面 循环 validGroundBlock + Cardinal.DOWN,跌破 lowerLimit(默认 60)即否决 :185-187
水中否决 途经方块 Material.water 即否决 :188

楼层难度分层

Dungeon.getLevel(int y)(dungeon/Dungeon.java:156-163)按 Y 高度返回 0–4 的难度层级:

Y 区间 getLevel()
y >= 45 0
35 <= y < 45 1
25 <= y < 35 2
15 <= y < 25 3
y < 15 4

该值作为 level 参数传入 Loot.addEquipment(treasure/loot/Loot.java:109)与各类战利品 provider,决定装备品质与附魔强度。

数值

数值名 值 来源
塔基 Y TOPLEVEL = 50 dungeon/DungeonGenerator.java:16
楼层垂直间距 VERTICAL_SPACING = 10 dungeon/DungeonGenerator.java:15
网格随机种子 10387312 dungeon/Dungeon.java:131
区块内偏移 +4 / +4 dungeon/Dungeon.java:149-150
最低网格下界 2 dungeon/Dungeon.java:122
最低网格上界 8 dungeon/Dungeon.java:123
难度层级数 5(0–4) dungeon/Dungeon.java:156-163
最高可用房间数 levelMaxRooms,默认 30 dungeon/base/DungeonFactory.java:61

交互

触发 行为
区块加载 DungeonGenerator.generate → 网格判定 → 命中则生成
/roguelike dungeon ... 跳过网格判定,直接在指定坐标走同一套 Dungeon.generate
doNaturalSpawn = false canSpawnInChunk 第一行即返回 false,自然生成完全关闭(dungeon/Dungeon.java:114-116)
单层生成抛异常 catch (Exception e) { e.printStackTrace(); }(dungeon/DungeonGenerator.java:45-47)后继续下一层;该层仍被加入 levels 列表(:55),随后 generator.getEnd() 被调用(:50)——若异常发生在 getEnd() 就绪之前会连带失败

相关条目