Files
Documentation/content/world/worldgen/chunk-generation.en.md
2026-01-20 20:33:59 +01:00

5.6 KiB

title, type, weight
title type weight
Chunk Generation docs 4

Chunk generation handles the block-by-block creation of terrain within each 16x16 chunk.

Package: com.hypixel.hytale.server.worldgen.chunk

ChunkGenerator

The ChunkGenerator creates terrain blocks:

public class ChunkGenerator {
    // Generate terrain for chunk
    public void generate(GenerationContainer container, int chunkX, int chunkZ);

    // Get height at position
    public int getHeight(int x, int z);

    // Get block at position
    public BlockType getBlock(int x, int y, int z);
}

Generation Stages

Chunk generation occurs in stages:

Generation Stages
├── 1. Height Map
│   └── Calculate surface heights
├── 2. Base Terrain
│   └── Fill solid blocks
├── 3. Surface Layer
│   └── Apply biome surface blocks
├── 4. Carving
│   └── Remove blocks for caves/features
└── 5. Decoration
    └── Add vegetation, ores, etc.

Height Map Generation

public class HeightMapGenerator {
    private NoiseGenerator baseNoise;
    private NoiseGenerator detailNoise;

    public int getHeight(int x, int z) {
        // Base terrain height
        float base = baseNoise.noise2D(x * 0.01f, z * 0.01f);

        // Detail variation
        float detail = detailNoise.noise2D(x * 0.1f, z * 0.1f) * 0.3f;

        // Convert to block height
        int height = (int) ((base + detail + 1.0f) * 32.0f) + 64;
        return Math.clamp(height, 1, 255);
    }
}

Terrain Fill

public class TerrainFiller {
    public void fill(GenerationContainer container, int x, int z, int height) {
        Biome biome = container.getBiome(x, z);

        for (int y = 0; y < height; y++) {
            BlockType block;

            if (y == 0) {
                block = BlockTypes.BEDROCK;
            } else if (y < height - 4) {
                block = biome.getStoneBlock();
            } else if (y < height - 1) {
                block = biome.getSubsurfaceBlock();
            } else {
                block = biome.getSurfaceBlock();
            }

            container.setBlock(x, y, z, block);
        }
    }
}

Surface Decoration

public class SurfaceDecorator {
    public void decorate(GenerationContainer container, int x, int z) {
        int surfaceY = container.getHeight(x, z);
        Biome biome = container.getBiome(x, z);

        // Add surface features based on biome
        for (SurfaceFeature feature : biome.getSurfaceFeatures()) {
            if (random.nextFloat() < feature.getDensity()) {
                feature.place(container, x, surfaceY + 1, z);
            }
        }
    }
}

Block Palette

Chunks use a block palette for efficient storage:

public class BlockPalette {
    private List<BlockType> palette;
    private short[] blockData;

    // Get block at local position
    public BlockType getBlock(int localX, int localY, int localZ) {
        int index = localX + localZ * 16 + localY * 256;
        short paletteIndex = blockData[index];
        return palette.get(paletteIndex);
    }

    // Set block at local position
    public void setBlock(int localX, int localY, int localZ, BlockType type) {
        int index = localX + localZ * 16 + localY * 256;
        int paletteIndex = palette.indexOf(type);
        if (paletteIndex == -1) {
            paletteIndex = palette.size();
            palette.add(type);
        }
        blockData[index] = (short) paletteIndex;
    }
}

Section-Based Generation

Chunks are divided into 16-block tall sections:

public class ChunkSection {
    private static final int SIZE = 16 * 16 * 16;
    private BlockPalette palette;
    private byte[] lightData;

    public boolean isEmpty() {
        return palette.size() == 1 && palette.get(0) == BlockTypes.AIR;
    }
}

Ore Generation

public class OreGenerator {
    public void generateOres(GenerationContainer container, int chunkX, int chunkZ) {
        for (OreConfig ore : oreConfigs) {
            int count = random.nextInt(ore.maxVeins - ore.minVeins) + ore.minVeins;

            for (int i = 0; i < count; i++) {
                int x = chunkX * 16 + random.nextInt(16);
                int y = random.nextInt(ore.maxY - ore.minY) + ore.minY;
                int z = chunkZ * 16 + random.nextInt(16);

                generateOreVein(container, x, y, z, ore);
            }
        }
    }

    private void generateOreVein(GenerationContainer container, int x, int y, int z, OreConfig ore) {
        int size = random.nextInt(ore.maxSize - ore.minSize) + ore.minSize;
        // Generate blob of ore blocks
        for (int i = 0; i < size; i++) {
            int dx = random.nextInt(3) - 1;
            int dy = random.nextInt(3) - 1;
            int dz = random.nextInt(3) - 1;
            if (container.getBlock(x + dx, y + dy, z + dz) == ore.replaceBlock) {
                container.setBlock(x + dx, y + dy, z + dz, ore.oreBlock);
            }
        }
    }
}

Configuration

# worldgen/chunk_config.yaml
ChunkGeneration:
  HeightNoise:
    Octaves: 6
    Persistence: 0.5
    Scale: 0.01
  SeaLevel: 64
  BedrockLayers: 5
  Ores:
    - Type: iron_ore
      MinY: 0
      MaxY: 64
      VeinsPerChunk: 20
      VeinSize: 9
    - Type: diamond_ore
      MinY: 0
      MaxY: 16
      VeinsPerChunk: 1
      VeinSize: 8

Best Practices

{{< callout type="info" >}} Chunk Guidelines:

  • Use noise for natural terrain variation
  • Apply biome-specific blocks to surfaces
  • Generate features after base terrain
  • Use palettes for memory efficiency
  • Consider section-based optimizations {{< /callout >}}