summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/bukkit
diff options
context:
space:
mode:
authorAntony Riley <antony@cyberiantiger.org>2015-07-28 16:22:13 +0300
committermd_5 <git@md-5.net>2015-08-01 21:22:29 +1000
commit880a53248e003fde93be5952574705d67155fe09 (patch)
tree2203574bf763ac99007a262aba2b5c7d28ffd1ee /src/main/java/org/bukkit
parent5e85956281ea7e75ede829a6ddea04c0bf400657 (diff)
downloadcraftbukkit-880a53248e003fde93be5952574705d67155fe09.tar
craftbukkit-880a53248e003fde93be5952574705d67155fe09.tar.gz
craftbukkit-880a53248e003fde93be5952574705d67155fe09.tar.lz
craftbukkit-880a53248e003fde93be5952574705d67155fe09.tar.xz
craftbukkit-880a53248e003fde93be5952574705d67155fe09.zip
New ChunkGenerator.generate api for block ids and avoiding magic values.
Diffstat (limited to 'src/main/java/org/bukkit')
-rw-r--r--src/main/java/org/bukkit/craftbukkit/CraftServer.java6
-rw-r--r--src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java197
-rw-r--r--src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java153
3 files changed, 295 insertions, 61 deletions
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index f5722c6c..82a41b04 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -48,6 +48,7 @@ import org.bukkit.configuration.serialization.ConfigurationSerialization;
import org.bukkit.conversations.Conversable;
import org.bukkit.craftbukkit.command.VanillaCommandWrapper;
import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.craftbukkit.generator.CraftChunkData;
import org.bukkit.craftbukkit.help.SimpleHelpMap;
import org.bukkit.craftbukkit.inventory.CraftFurnaceRecipe;
import org.bukkit.craftbukkit.inventory.CraftInventoryCustom;
@@ -1631,6 +1632,11 @@ public final class CraftServer implements Server {
return console.getIdleTimeout();
}
+ @Override
+ public ChunkGenerator.ChunkData createChunkData(World world) {
+ return new CraftChunkData(world);
+ }
+
@Deprecated
@Override
public UnsafeValues getUnsafe() {
diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java
new file mode 100644
index 00000000..438bed8c
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java
@@ -0,0 +1,197 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.bukkit.craftbukkit.generator;
+
+import java.util.Arrays;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.generator.ChunkGenerator;
+import org.bukkit.material.MaterialData;
+
+/**
+ * Data to be used for the block types and data in a newly generated chunk.
+ */
+public final class CraftChunkData implements ChunkGenerator.ChunkData {
+ private final int maxHeight;
+ private final char[][] sections;
+
+ public CraftChunkData(World world) {
+ this(world.getMaxHeight());
+ }
+
+ /* pp for tests */ CraftChunkData(int maxHeight) {
+ if (maxHeight > 256) {
+ throw new IllegalArgumentException("World height exceeded max chunk height");
+ }
+ this.maxHeight = maxHeight;
+ // Minecraft hardcodes this to 16 chunk sections.
+ sections = new char[16][];
+ }
+
+ @Override
+ public int getMaxHeight() {
+ return maxHeight;
+ }
+
+ @Override
+ public void setBlock(int x, int y, int z, Material material) {
+ setBlock(x, y, z, material.getId());
+ }
+
+ @Override
+ public void setBlock(int x, int y, int z, MaterialData material) {
+ setBlock(x, y, z, material.getItemTypeId(), material.getData());
+ }
+
+ @Override
+ public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, Material material) {
+ setRegion(xMin, yMin, zMin, xMax, yMax, zMax, material.getId());
+ }
+
+ @Override
+ public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, MaterialData material) {
+ setRegion(xMin, yMin, zMin, xMax, yMax, zMax, material.getItemTypeId(), material.getData());
+ }
+
+ @Override
+ public Material getType(int x, int y, int z) {
+ return Material.getMaterial(getTypeId(x, y, z));
+ }
+
+ @Override
+ public MaterialData getTypeAndData(int x, int y, int z) {
+ return getType(x, y, z).getNewData(getData(x, y, z));
+ }
+
+ @Override
+ public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, int blockId) {
+ setRegion(xMin, yMin, zMin, xMax, yMax, zMax, blockId, (byte) 0);
+ }
+
+ @Override
+ public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, int blockId, int data) {
+ // Clamp to sane values.
+ if (xMin > 0xf || yMin >= maxHeight || zMin > 0xf) {
+ return;
+ }
+ if (xMin < 0) {
+ xMin = 0;
+ }
+ if (yMin < 0) {
+ yMin = 0;
+ }
+ if (zMin < 0) {
+ zMin = 0;
+ }
+ if (xMax > 0x10) {
+ xMax = 0x10;
+ }
+ if (yMax > maxHeight) {
+ yMax = maxHeight;
+ }
+ if (zMax > 0x10) {
+ zMax = 0x10;
+ }
+ if (xMin >= xMax || yMin >= yMax || zMin >= zMax) {
+ return;
+ }
+ char typeChar = (char) (blockId << 4 | data);
+ if (xMin == 0 && xMax == 0x10) {
+ if (zMin == 0 && zMax == 0x10) {
+ for (int y = yMin & 0xf0; y < yMax; y += 0x10) {
+ char[] section = getChunkSection(y, true);
+ if (y <= yMin) {
+ if (y + 0x10 > yMax) {
+ // First and last chunk section
+ Arrays.fill(section, (yMin & 0xf) << 8, (yMax & 0xf) << 8, typeChar);
+ } else {
+ // First chunk section
+ Arrays.fill(section, (yMin & 0xf) << 8, 0x1000, typeChar);
+ }
+ } else if (y + 0x10 >= yMax) {
+ // Last chunk section
+ Arrays.fill(section, 0, (yMax & 0xf) << 8, typeChar);
+ } else {
+ // Full chunk section
+ Arrays.fill(section, 0, 0x1000, typeChar);
+ }
+ }
+ } else {
+ for (int y = yMin; y < yMax; y++) {
+ char[] section = getChunkSection(y, true);
+ int offsetBase = (y & 0xf) << 8;
+ int min = offsetBase | (zMin << 4);
+ int max = offsetBase | (zMax << 4);
+ Arrays.fill(section, min, max, typeChar);
+ }
+ }
+ } else {
+ for (int y = yMin; y < yMax; y++) {
+ char[] section = getChunkSection(y, true);
+ int offsetBase = (y & 0xf) << 8;
+ for (int z = zMin; z < zMax; z++) {
+ int offset = offsetBase | z << 4;
+ Arrays.fill(section, offset | xMin, offset | xMax, typeChar);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void setBlock(int x, int y, int z, int blockId) {
+ setBlock(x, y, z, blockId, (byte) 0);
+ }
+
+ @Override
+ public void setBlock(int x, int y, int z, int blockId, byte data) {
+ setBlock(x, y, z, (char) (blockId << 4 | data));
+ }
+
+ @Override
+ public int getTypeId(int x, int y, int z) {
+ if (x != (x & 0xf) || y < 0 || y >= maxHeight || z != (z & 0xf)) {
+ return 0;
+ }
+ char[] section = getChunkSection(y, false);
+ if (section == null) {
+ return 0;
+ } else {
+ return section[(y & 0xf) << 8 | z << 4 | x] >> 4;
+ }
+ }
+
+ @Override
+ public byte getData(int x, int y, int z) {
+ if (x != (x & 0xf) || y < 0 || y >= maxHeight || z != (z & 0xf)) {
+ return (byte) 0;
+ }
+ char[] section = getChunkSection(y, false);
+ if (section == null) {
+ return (byte) 0;
+ } else {
+ return (byte) (section[(y & 0xf) << 8 | z << 4 | x] & 0xf);
+ }
+ }
+
+ private void setBlock(int x, int y, int z, char type) {
+ if (x != (x & 0xf) || y < 0 || y >= maxHeight || z != (z & 0xf)) {
+ return;
+ }
+ char[] section = getChunkSection(y, true);
+ section[(y & 0xf) << 8 | z << 4 | x] = type;
+ }
+
+ private char[] getChunkSection(int y, boolean create) {
+ char[] section = sections[y >> 4];
+ if (create && section == null) {
+ sections[y >> 4] = section = new char[0x1000];
+ }
+ return section;
+ }
+
+ char[][] getRawChunkData() {
+ return sections;
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java
index 9ecdad45..04dd15db 100644
--- a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java
+++ b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java
@@ -49,91 +49,122 @@ public class CustomChunkGenerator extends InternalChunkGenerator {
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) {
+ // Try ChunkData method (1.8+)
+ CraftChunkData data = (CraftChunkData) generator.generateChunkData(this.world.getWorld(), random, x, z, biomegrid);
+ if (data != null) {
+ char[][] sections = data.getRawChunkData();
chunk = new Chunk(this.world, x, z);
-
+
ChunkSection[] csect = chunk.getSections();
- int scnt = Math.min(csect.length, xbtypes.length);
-
+ int scnt = Math.min(csect.length, sections.length);
+
// Loop through returned sections
for (int sec = 0; sec < scnt; sec++) {
- if (xbtypes[sec] == null) {
+ if(sections[sec] == null) {
continue;
}
- char[] secBlkID = new char[4096]; // Allocate blk ID bytes
- short[] bdata = xbtypes[sec];
- for (int i = 0; i < bdata.length; i++) {
- Block b = Block.getById(bdata[i]);
- secBlkID[i] = (char) Block.d.b(b.getBlockData());
+ char[] section = sections[sec];
+ char emptyTest = 0;
+ for (int i = 0; i < 4096; i++) {
+ // Filter invalid block id & data values.
+ if (Block.d.a(section[i]) == null) {
+ section[i] = 0;
+ }
+ emptyTest |= section[i];
}
// Build chunk section
- csect[sec] = new ChunkSection(sec << 4, true, secBlkID);
+ if (emptyTest != 0) {
+ csect[sec] = new ChunkSection(sec << 4, true, section);
+ }
}
}
- else { // Else check for byte-per-block section data
- byte[][] btypes = generator.generateBlockSections(this.world.getWorld(), this.random, x, z, biomegrid);
-
- if (btypes != null) {
+ else {
+ // 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.getSections();
- int scnt = Math.min(csect.length, btypes.length);
-
+ int scnt = Math.min(csect.length, xbtypes.length);
+
+ // Loop through returned sections
for (int sec = 0; sec < scnt; sec++) {
- if (btypes[sec] == null) {
+ if (xbtypes[sec] == null) {
continue;
}
-
- char[] secBlkID = new char[4096]; // Allocate block ID bytes
- for (int i = 0; i < secBlkID.length; i++) {
- Block b = Block.getById(btypes[sec][i] & 0xFF);
+ char[] secBlkID = new char[4096]; // Allocate blk ID bytes
+ short[] bdata = xbtypes[sec];
+ for (int i = 0; i < bdata.length; i++) {
+ Block b = Block.getById(bdata[i]);
secBlkID[i] = (char) Block.d.b(b.getBlockData());
}
+ // Build chunk section
csect[sec] = new ChunkSection(sec << 4, true, secBlkID);
}
}
- 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.getSections();
-
- scnt = Math.min(scnt, csect.length);
- // Loop through sections
- for (int sec = 0; sec < scnt; sec++) {
- ChunkSection cs = null; // Add sections when needed
- char[] csbytes = 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, true);
- csbytes = cs.getIdArray();
+ 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.getSections();
+ int scnt = Math.min(csect.length, btypes.length);
+
+ for (int sec = 0; sec < scnt; sec++) {
+ if (btypes[sec] == null) {
+ continue;
+ }
+
+ char[] secBlkID = new char[4096]; // Allocate block ID bytes
+ for (int i = 0; i < secBlkID.length; i++) {
+ Block b = Block.getById(btypes[sec][i] & 0xFF);
+ secBlkID[i] = (char) Block.d.b(b.getBlockData());
+ }
+ csect[sec] = new ChunkSection(sec << 4, true, secBlkID);
+ }
+ }
+ 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.getSections();
+
+ scnt = Math.min(scnt, csect.length);
+ // Loop through sections
+ for (int sec = 0; sec < scnt; sec++) {
+ ChunkSection cs = null; // Add sections when needed
+ char[] csbytes = 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, true);
+ csbytes = cs.getIdArray();
+ }
+
+ Block b = Block.getById(blk & 0xFF);
+ csbytes[(cy << 8) | (cz << 4) | cx] = (char) Block.d.b(b.getBlockData());
}
-
- Block b = Block.getById(blk & 0xFF);
- csbytes[(cy << 8) | (cz << 4) | cx] = (char) Block.d.b(b.getBlockData());
}
}
}
- }
- // If section built, finish prepping its state
- if (cs != null) {
- cs.recalcBlockCounts();
+ // If section built, finish prepping its state
+ if (cs != null) {
+ cs.recalcBlockCounts();
+ }
}
}
}