diff --git a/src/main/java/net/minecraft/server/ChunkSection.java b/src/main/java/net/minecraft/server/ChunkSection.java index c96e146ee6..6478d275ac 100644 --- a/src/main/java/net/minecraft/server/ChunkSection.java +++ b/src/main/java/net/minecraft/server/ChunkSection.java @@ -19,6 +19,20 @@ public class ChunkSection { this.g = new NibbleArray(this.d.length, 4); } + // CraftBukkit start + public ChunkSection(int y, byte[] blkData, byte[] extBlkData) { + this.a = y; + this.d = blkData; + if (extBlkData != null) { + this.e = new NibbleArray(extBlkData, 4); + } + this.f = new NibbleArray(this.d.length, 4); + this.h = new NibbleArray(this.d.length, 4); + this.g = new NibbleArray(this.d.length, 4); + this.d(); + } + // CraftBukkit end + public int a(int i, int j, int k) { int l = this.d[j << 8 | k << 4 | i] & 255; diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java index a224153890..f0652c6f96 100644 --- a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java +++ b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java @@ -5,18 +5,19 @@ import java.util.Random; import net.minecraft.server.BiomeBase; import net.minecraft.server.Chunk; -import net.minecraft.server.ChunkCoordIntPair; import net.minecraft.server.ChunkPosition; +import net.minecraft.server.ChunkSection; import net.minecraft.server.EnumCreatureType; import net.minecraft.server.IChunkProvider; import net.minecraft.server.IProgressUpdate; import net.minecraft.server.World; -import net.minecraft.server.WorldChunkManager; import net.minecraft.server.WorldGenStronghold; import net.minecraft.server.WorldServer; +import org.bukkit.block.Biome; import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.ChunkGenerator; +import org.bukkit.craftbukkit.block.CraftBlock; public class CustomChunkGenerator extends InternalChunkGenerator { private final ChunkGenerator generator; @@ -24,6 +25,18 @@ public class CustomChunkGenerator extends InternalChunkGenerator { private final Random random; private final WorldGenStronghold strongholdGen = new WorldGenStronghold(); + private static class CustomBiomeGrid implements BiomeGrid { + BiomeBase[] biome; + + public Biome getBiome(int x, int z) { + return CraftBlock.biomeBaseToBiome(biome[(z << 4) | x]); + } + + public void setBiome(int x, int z, Biome bio) { + biome[(z << 4) | x] = CraftBlock.biomeToBiomeBase(bio); + } + } + public CustomChunkGenerator(World world, long seed, ChunkGenerator generator) { this.world = (WorldServer) world; this.generator = generator; @@ -37,10 +50,114 @@ public class CustomChunkGenerator extends InternalChunkGenerator { public Chunk getOrCreateChunk(int x, int z) { random.setSeed((long) x * 341873128712L + (long) z * 132897987541L); - byte[] types = generator.generate(world.getWorld(), random, x, z); - Chunk chunk = new Chunk(world, types, x, z); + Chunk chunk; + // Get default biome data for chunk + CustomBiomeGrid biomegrid = new CustomBiomeGrid(); + biomegrid.biome = new BiomeBase[256]; + world.getWorldChunkManager().getBiomeBlock(biomegrid.biome, x << 4, z << 4, 16, 16); + + // Try extended block method (1.2+) + short[][] xbtypes = generator.generateExtBlockSections(this.world.getWorld(), this.random, x, z, biomegrid); + if (xbtypes != null) { + chunk = new Chunk(this.world, x, z); + + ChunkSection[] csect = chunk.h(); + int scnt = Math.min(csect.length, xbtypes.length); + + // Loop through returned sections + for (int sec = 0; sec < scnt; sec++) { + if (xbtypes[sec] == null) { + continue; + } + byte[] secBlkID = new byte[4096]; // Allocate blk ID bytes + byte[] secExtBlkID = (byte[]) null; // Delay getting extended ID nibbles + short[] bdata = xbtypes[sec]; + // Loop through data, 2 blocks at a time + for (int i = 0, j = 0; i < bdata.length; i += 2, j++) { + short b1 = bdata[i]; + short b2 = bdata[i + 1]; + byte extb = (byte) ((b1 >> 8) | ((b2 >> 4) & 0xF0)); + + secBlkID[i] = (byte) b1; + secBlkID[(i + 1)] = (byte) b2; + + if (extb != 0) { // If extended block ID data + if (secExtBlkID == null) { // Allocate if needed + secExtBlkID = new byte[2048]; + } + secExtBlkID[j] = extb; + } + } + // Build chunk section + csect[sec] = new ChunkSection(sec << 4, secBlkID, secExtBlkID); + } + } + else { // Else check for byte-per-block section data + byte[][] btypes = generator.generateBlockSections(this.world.getWorld(), this.random, x, z, biomegrid); + + if (btypes != null) { + chunk = new Chunk(this.world, x, z); + + ChunkSection[] csect = chunk.h(); + int scnt = Math.min(csect.length, btypes.length); + + for (int sec = 0; sec < scnt; sec++) { + if (btypes[sec] == null) { + continue; + } + csect[sec] = new ChunkSection(sec << 4, btypes[sec], null); + } + } + else { // Else, fall back to pre 1.2 method + @SuppressWarnings("deprecation") + byte[] types = generator.generate(this.world.getWorld(), this.random, x, z); + int ydim = types.length / 256; + int scnt = ydim / 16; + + chunk = new Chunk(this.world, x, z); // Create empty chunk + + ChunkSection[] csect = chunk.h(); + + scnt = Math.min(scnt, csect.length); + // Loop through sections + for (int sec = 0; sec < scnt; sec++) { + ChunkSection cs = null; // Add sections when needed + byte[] csbytes = (byte[]) null; + + for (int cy = 0; cy < 16; cy++) { + int cyoff = cy | (sec << 4); + + for (int cx = 0; cx < 16; cx++) { + int cxyoff = (cx * ydim * 16) + cyoff; + + for (int cz = 0; cz < 16; cz++) { + byte blk = types[cxyoff + (cz * ydim)]; + + if (blk != 0) { // If non-empty + if (cs == null) { // If no section yet, get one + cs = csect[sec] = new ChunkSection(sec << 4); + csbytes = cs.g(); + } + csbytes[(cy << 8) | (cz << 4) | cx] = blk; + } + } + } + } + // If section built, finish prepping its state + if (cs != null) { + cs.d(); + } + } + } + } + // Set biome grid + byte[] biomeIndex = chunk.l(); + for (int i = 0; i < biomeIndex.length; i++) { + biomeIndex[i] = (byte) (biomegrid.biome[i].id & 0xFF); + } + // Initialize lighting chunk.initLighting(); return chunk; @@ -62,10 +179,19 @@ public class CustomChunkGenerator extends InternalChunkGenerator { return true; } + @SuppressWarnings("deprecation") public byte[] generate(org.bukkit.World world, Random random, int x, int z) { return generator.generate(world, random, x, z); } + public byte[][] generateBlockSections(org.bukkit.World world, Random random, int x, int z, BiomeGrid biomes) { + return generator.generateBlockSections(world, random, x, z, biomes); + } + + public short[][] generateExtBlockSections(org.bukkit.World world, Random random, int x, int z, BiomeGrid biomes) { + return generator.generateExtBlockSections(world, random, x, z, biomes); + } + public Chunk getChunkAt(int x, int z) { return getOrCreateChunk(x, z); }