13
0
geforkt von Mirrors/Paper

New ChunkGenerator.generate api for block ids and avoiding magic values.

Dieser Commit ist enthalten in:
Antony Riley 2015-07-28 16:22:13 +03:00 committet von md_5
Ursprung 5e85956281
Commit 880a53248e
3 geänderte Dateien mit 295 neuen und 61 gelöschten Zeilen

Datei anzeigen

@ -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() {

Datei anzeigen

@ -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;
}
}

Datei anzeigen

@ -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();
}
}
}
}