MinecraftForge/MinecraftForge — pull request #255 by CowedOffACliff (2012-11-16 04:19:48+00:00)
Title: Added a new constructor to Chunk.java that provides for generating a world with 256 block high terrain.

While we have been capable of placing blocks at heights up to 256 for quite some time now, the default terrain generation has not been modified to match that capability. As an unfortunate side effect of that, the capability for any part of the terrain generation phase involving the byte array of block index to generate above that height was never fully implemented. On my recent quest to generate my own dimension's terrain in the full available height I encountered this bug/limitation, and devised a solution. The problem and solution are as follows:

**The problem:**
Anyone who has spent a reasonable amount of time looking inside ChunkProvider is aware that the default game uses an array of bytes with a size equivalent to (16 * 16 * 128), or 32,768, to generate and store the block IDs that represent the blocks for that Chunk. However, the knowledge of how block IDs are placed in the array in such a way as to represent coordinates is much less common.

Essentially, to store the coordinates the game uses this:
*(0 through 3 + 0 through 3 * 4 << 11 | 0 + 0 through 3 * 4 << 7 | 0 through 15 * 8 + 0 through 7)*

This results in *(0 through 30,720 | 0 through 1,536 | 0 through 127)*, or 32,383, with the maximum possible values just shy of the maximum size of the array.
This works perfectly well for a (16 * 16 * 128) array, but does not work for anything else. In order to change it so that it works with an array of size (16 * 16 * 256), or 65,536, is to make it left shift the X coordinate by 12 instead of 11, make the Z coordinate left shift by 8 instead of 7, and change the Y coordinate to 0 through 31 instead of 0 through 16. However, despite the solution being known and correctly implemented by a dimension mod writer, the world still cannot be properly generated in a height of 256. If this is attempted the world will instead generate as what is effectively the correct generation, but with every other row of blocks non-existent.

This is caused by what occurs in the constructor of Chunk when the block ID array is passed in. When Chunk breaks down the array into parts in preparation for an ExtendedBlockStorage, it does something similar to the original function. It gets the coordinates by looping X and Z for 16 values (0-15) and then shifts X by 11 and Z by 7 just like it did during generation. It does at least get the correct Y height value, but that is not enough. Basically, when it does this to an array of size (16 * 16 * 256), it effectively halves the array and creates gaps between X and Z coordinates due to the way Y values are represented (Every column of Y coordinates is 0 through height, so it goes 0, 128, 256, 384, etc., for each X coordinate), and the other half of the array not being placed in an ExtendedBlockStorage.

**The solution:**
The most straightforward solution is to add a new constructor to Chunk that accepts parameters for changing how much the bits are shifted, so that is what I did.

I added the constructor:
*Chunk(World world, byte[] ids, byte[] metadata, int chunkX, int chunkZ, int xShift, int zShift)*,
where all of the parameters are the same as the original constructor supplied by Forge to handle metadata, while adding the parameters needed for the solution. In addition to implementing the solution, the metadata array can be passed in as null in order to avoid unneeded code duplication; if null, it will just be ignored.

I also changed the original Forge-supplied metadata constructor to pass its parameters to my new one, but with the correct (original) values for default world generation.

The net result is a pure gain in functionality. Backwards compatibility is maintained by not removing the original metadata constructor, and no performance is lost unless directly caused by a mod that uses the new height capabilities. This loss in performance should not be a problem, seeing as it is should be expected (more blocks = more memory), and usage should be purely the responsibility of the mod writer and users.

**Notes:**
Patch built against 1.4.4, tested against 1.4.2. Nothing changed in the ChunkProvider -> Chunk interaction between updates, and nothing changed in the Chunk constructors, so it should still work exactly as it did previously.

Also chmod a+x'd the install.sh script so that it's marked executable by default for systems that use UNIX file permissions.