Skip to content

世界生成器 ​

Minecraft 世界生成是分阶段的复杂过程。Bukkit 提供了在生成阶段介入的 API,让你往世界里塞自定义内容(比如草地上撒钻石块)。

世界生成的两个阶段 ​

世界以**区块(Chunk)**为单位生成。每个区块经历两个阶段:

Generation 阶段(绘制地形) ​

  1. 取该 Chunk 所有生物群系,按群系绘制基本地形(以高度 63 为水平面,先只有空气、水、石头)
  2. 在高度 0~5 生成基岩,给各群系加特有方块(平原加草和泥土、沙漠加沙)
  3. 生成跨区块的大型地形(洞穴、村庄、矿井)
  4. 收尾准备

Population 阶段(点缀内容) ​

Generation 完成后世界结构定型,但还缺"点缀":

  1. 完善实体、生成方块实体(箱子等)
  2. 生成小型地形(水坑、岩浆池、地牢)
  3. 按规则生成矿物
  4. 加地面点缀(甘蔗、荷叶、蘑菇、树木)和基础生物

两个阶段结束后,Chunk 数据存储并显示。

介入 Population 阶段 ​

世界初始化时触发 WorldInitEvent。监听它,给世界加 BlockPopulator:

java
public class WorldListener implements Listener {
    @EventHandler
    public void onWorldInit(WorldInitEvent e) {
        if (e.getWorld().getName().equals("world")) {
            e.getWorld().getPopulators().add(new DiamondPopulator());
        }
    }
}

BlockPopulator ​

BlockPopulator 在每个区块的 Population 阶段被调用,可往区块里塞方块:

java
class DiamondPopulator extends BlockPopulator {
    @Override
    public void populate(World world, Random random, Chunk chunk) {
        // 在这个区块的草方块上随机撒钻石块
        for (int x = 0; x < 16; x++) {
            for (int z = 0; z < 16; z++) {
                int y = world.getHighestBlockYAt(
                    chunk.getX() * 16 + x,
                    chunk.getZ() * 16 + z
                );
                Block b = chunk.getBlock(x, y - 1, z);
                if (b.getType() == Material.GRASS_BLOCK && random.nextInt(10) == 0) {
                    b.setType(Material.DIAMOND_BLOCK);
                }
            }
        }
    }
}

只对新区块生效

BlockPopulator 只在区块首次生成时跑。已经生成过的区块不会重新 populate——要改已存在区块得用别的方式(如命令或定时任务)。

注册监听 ​

别忘了在 onEnable 注册 WorldListener:

java
@Override
public void onEnable() {
    Bukkit.getPluginManager().registerEvents(new WorldListener(), this);
}

ChunkGenerator 完全自定义生成 ​

若要彻底替换世界的地形生成逻辑(如做一个平坦世界、空岛世界),用 ChunkGenerator:

java
public class FlatGenerator extends ChunkGenerator {
    @Override
    public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, BiomeGrid biome) {
        ChunkData data = createChunkData(world);
        for (int x = 0; x < 16; x++) {
            for (int z = 0; z < 16; z++) {
                data.setBlock(x, 0, z, Material.BEDROCK);
                data.setBlock(x, 1, z, Material.STONE);
                data.setBlock(x, 2, z, Material.GRASS_BLOCK);
            }
        }
        return data;
    }
}

创建世界时指定:

java
WorldCreator wc = new WorldCreator("myworld");
wc.generator(new FlatGenerator());
World world = wc.createWorld();

用哪个?

  • 只想往原版世界加点料(撒矿、加结构)→ BlockPopulator
  • 想完全控制地形(自定义世界类型)→ ChunkGenerator

注意事项 ​

  • 性能敏感:生成器每个区块都跑,逻辑要轻,避免重计算
  • 坐标换算:chunk.getX()*16 + x 才是世界坐标,别直接用区块内坐标
  • BiomeGrid:generateChunkData 的 BiomeGrid 参数可设置每个格子的生物群系
  • Material.GRASS(旧版)vs Material.GRASS_BLOCK(1.13+)注意版本差异

下一篇Title 与 ActionBar。