The Edge of the Far Lands — Java Bug Hunt

Modelled on Minecraft's Far Lands (Java Edition before Beta 1.8): about 12.55 million blocks from spawn, the terrain generator broke down into towering…

  • Language: Java
  • Layer: Backend
  • Difficulty: Medium
  • Concepts: Overflow
  • Modelled on: Minecraft · Far Lands
  • Visible tests: columns near spawn sample normally; a column past 12.56 million blocks keeps its coordinate
  • Reward: 50 XP for a complete fix

Briefing

Modelled on Minecraft's Far Lands (Java Edition before Beta 1.8): about 12.55 million blocks from spawn, the terrain generator broke down into towering walls of distorted, repeating terrain. The cause was numeric — the noise generator scaled block coordinates up for its octaves, and far enough out those values no longer fit the 32-bit integer arithmetic the generator relied on.

This project is a reconstruction. TerrainSampler.noiseCoord multiplies a block column by the noise scale in int arithmetic before widening the result, so just past 12,558,383 blocks the product wraps negative and the lattice lookups jump to the far side of the noise field.

Fix the sampler so the coordinate is computed without overflow.

Bug report

BUG-MC-FARLANDS · Priority: Medium · Reported by: explorers

For every int blockX (the whole int range is a legal column):

  • noiseCoord(blockX) == (long) blockX * Noise.SCALE, exactly
  • cell(blockX) == floorDiv(noiseCoord(blockX), Noise.CELL)
  • height(blockX) interpolates Noise.lattice(cell) and Noise.lattice(cell + 1) by floorMod(noiseCoord, CELL) as the code already does
  • consecutive columns never jump: cell(x + 1) - cell(x) is 0 or 1

Observed: at x = 12,558,384 the cell index jumps from about 2.1 million to about -2.1 million and the terrain turns into walls.

Logs

[worldgen] chunk x=784899 cell=2097151 -> cell=-2097152 at column 12558384
[worldgen] heightmap discontinuity 71 -> 12 over one block

The code as shipped

src/world/TerrainSampler.java (editable)

class TerrainSampler {
    // Position of a block column along the noise axis.
    static long noiseCoord(int blockX) {
        return blockX * Noise.SCALE;
    }

    static long cell(int blockX) {
        return Math.floorDiv(noiseCoord(blockX), (long) Noise.CELL);
    }

    static int height(int blockX) {
        long n = noiseCoord(blockX);
        long c = Math.floorDiv(n, (long) Noise.CELL);
        int frac = (int) Math.floorMod(n, (long) Noise.CELL);
        int a = Noise.lattice(c);
        int b = Noise.lattice(c + 1);
        return 64 + a + (b - a) * frac / Noise.CELL;
    }
}

Read-only context: src/world/Noise.java.

Open the hunt to edit the files, run the visible tests and submit against the hidden ones. More Java bug hunts.