use of org.jnbt.Tag in project WorldPainter by Captain-Chaos.
the class Bo3Object method loadTileEntity.
private static TileEntity loadTileEntity(File bo3File, String nbtFileName) throws IOException {
File nbtFile = new File(bo3File.getParentFile(), nbtFileName);
try (NBTInputStream in = new NBTInputStream(new GZIPInputStream(new FileInputStream(nbtFile)))) {
CompoundTag tag = (CompoundTag) in.readTag();
Map<String, Tag> map = tag.getValue();
if ((map.size() == 1) && (map.values().iterator().next() instanceof CompoundTag)) {
// contains the data
return TileEntity.fromNBT((CompoundTag) tag.getValue().values().iterator().next());
} else {
return TileEntity.fromNBT(tag);
}
}
}
use of org.jnbt.Tag in project WorldPainter by Captain-Chaos.
the class JavaWorldMerger method thirdPass.
private String thirdPass(MinecraftWorld minecraftWorld, File oldRegionDir, Dimension dimension, Point regionCoords, ProgressReceiver progressReceiver) throws IOException, ProgressReceiver.OperationCancelled {
if (progressReceiver != null) {
progressReceiver.setMessage("Merging existing blocks with new");
}
int lowestChunkX = (regionCoords.x << 5) - 1;
int highestChunkX = (regionCoords.x << 5) + 32;
int lowestChunkY = (regionCoords.y << 5) - 1;
int highestChunkY = (regionCoords.y << 5) + 32;
Platform platform = dimension.getWorld().getPlatform();
int maxHeight = dimension.getMaxHeight();
Map<Point, RegionFile> regionFiles = new HashMap<>();
Set<Point> damagedRegions = new HashSet<>();
StringBuilder reportBuilder = new StringBuilder();
try {
int chunkNo = 0;
for (int chunkX = lowestChunkX; chunkX <= highestChunkX; chunkX++) {
for (int chunkY = lowestChunkY; chunkY <= highestChunkY; chunkY++) {
chunkNo++;
if (progressReceiver != null) {
progressReceiver.setProgress((float) chunkNo / 1156);
}
Chunk newChunk;
if (dimension.getTile(chunkX >> 3, chunkY >> 3) == null) {
// The tile for this chunk does not exist in the new
// world, so the chunk from the existing world should
// be copied
newChunk = null;
} else {
newChunk = minecraftWorld.getChunk(chunkX, chunkY);
}
if (replaceChunks && (newChunk != null)) {
// as is
continue;
}
int regionX = chunkX >> 5;
int regionY = chunkY >> 5;
Point coords = new Point(regionX, regionY);
if (damagedRegions.contains(coords)) {
// reported and logged earlier
continue;
}
RegionFile regionFile = regionFiles.get(coords);
if (regionFile == null) {
File file = new File(oldRegionDir, "r." + regionX + "." + regionY + (platform.equals(DefaultPlugin.JAVA_ANVIL) ? ".mca" : ".mcr"));
try {
regionFile = new RegionFile(file);
regionFiles.put(coords, regionFile);
} catch (IOException e) {
reportBuilder.append("I/O error while opening region file " + file + " (message: \"" + e.getMessage() + "\"); skipping region" + EOL);
logger.error("I/O error while opening region file " + file + "; skipping region", e);
damagedRegions.add(coords);
continue;
}
}
int chunkXInRegion = chunkX & 0x1f;
int chunkYInRegion = chunkY & 0x1f;
if (regionFile.containsChunk(chunkXInRegion, chunkYInRegion)) {
Tag tag;
try {
DataInputStream chunkData = regionFile.getChunkDataInputStream(chunkXInRegion, chunkYInRegion);
if (chunkData == null) {
// This should never happen, since we checked with
// isChunkPresent(), but in practice it does. Perhaps
// corrupted data?
reportBuilder.append("Missing chunk data in existing map for chunk " + chunkXInRegion + ", " + chunkYInRegion + " in " + regionFile + "; skipping chunk" + EOL);
logger.warn("Missing chunk data in existing map for chunk " + chunkXInRegion + ", " + chunkYInRegion + " in " + regionFile + "; skipping chunk");
continue;
}
try (NBTInputStream in = new NBTInputStream(chunkData)) {
tag = in.readTag();
}
} catch (IOException e) {
reportBuilder.append("I/O error while reading chunk in existing map " + chunkXInRegion + ", " + chunkYInRegion + " from file " + regionFile + " (message: \"" + e.getMessage() + "\"); skipping chunk" + EOL);
logger.error("I/O error while reading chunk in existing map " + chunkXInRegion + ", " + chunkYInRegion + " from file " + regionFile + "; skipping chunk", e);
continue;
} catch (IllegalArgumentException e) {
reportBuilder.append("Illegal argument exception while reading chunk in existing map " + chunkXInRegion + ", " + chunkYInRegion + " from file " + regionFile + " (message: \"" + e.getMessage() + "\"); skipping chunk" + EOL);
logger.error("Illegal argument exception while reading chunk in existing map " + chunkXInRegion + ", " + chunkYInRegion + " from file " + regionFile + "; skipping chunk", e);
continue;
}
Chunk existingChunk = platform.equals(DefaultPlugin.JAVA_ANVIL) ? new ChunkImpl2((CompoundTag) tag, maxHeight) : new ChunkImpl((CompoundTag) tag, maxHeight);
if (newChunk != null) {
// Chunk exists in existing and new world; merge it
// Do any necessary processing of the existing chunk
// (clearing trees, etc.) No need to check for
// read-only; if the chunk was read-only it
// wouldn't exist in the new map and we wouldn't
// be here
processExistingChunk(existingChunk);
try {
newChunk = mergeChunk(existingChunk, newChunk, dimension);
minecraftWorld.addChunk(newChunk);
} catch (NullPointerException e) {
reportBuilder.append("Null pointer exception while reading chunk in existing map " + chunkXInRegion + ", " + chunkYInRegion + " from file " + regionFile + "; skipping chunk" + EOL);
logger.error("Null pointer exception while reading chunk in existing map " + chunkXInRegion + ", " + chunkYInRegion + " from file " + regionFile + "; skipping chunk", e);
continue;
} catch (ArrayIndexOutOfBoundsException e) {
reportBuilder.append("Array index out of bounds while reading chunk in existing map " + chunkXInRegion + ", " + chunkYInRegion + " from file " + regionFile + " (message: \"" + e.getMessage() + "\"); skipping chunk" + EOL);
logger.error("Array index out of bounds while reading chunk in existing map " + chunkXInRegion + ", " + chunkYInRegion + " from file " + regionFile + "; skipping chunk", e);
continue;
}
} else {
// Chunk exists in existing world, but not in new
// one, copy old to new
minecraftWorld.addChunk(existingChunk);
}
}
}
}
} finally {
for (RegionFile regionFile : regionFiles.values()) {
regionFile.close();
}
}
if (progressReceiver != null) {
progressReceiver.setProgress(1.0f);
}
return reportBuilder.length() != 0 ? reportBuilder.toString() : null;
}
use of org.jnbt.Tag in project WorldPainter by Captain-Chaos.
the class JavaMapImporter method importDimension.
private String importDimension(File regionDir, Dimension dimension, int version, ProgressReceiver progressReceiver) throws IOException, ProgressReceiver.OperationCancelled {
if (progressReceiver != null) {
progressReceiver.setMessage(dimension.getName() + " dimension");
}
final int maxHeight = dimension.getMaxHeight();
final int maxY = maxHeight - 1;
final Pattern regionFilePattern = (version == SUPPORTED_VERSION_1) ? Pattern.compile("r\\.-?\\d+\\.-?\\d+\\.mcr") : Pattern.compile("r\\.-?\\d+\\.-?\\d+\\.mca");
final File[] regionFiles = regionDir.listFiles((dir, name) -> regionFilePattern.matcher(name).matches());
if ((regionFiles == null) || (regionFiles.length == 0)) {
throw new RuntimeException("The " + dimension.getName() + " dimension of this map has no region files!");
}
final Set<Point> newChunks = new HashSet<>();
// final SortedSet<Material> manMadeBlockTypes = new TreeSet<Material>();
final boolean importBiomes = (version == SUPPORTED_VERSION_2) && (dimension.getDim() == DIM_NORMAL);
final int total = regionFiles.length * 1024;
int count = 0;
final StringBuilder reportBuilder = new StringBuilder();
for (File file : regionFiles) {
try {
RegionFile regionFile = new RegionFile(file);
try {
for (int x = 0; x < 32; x++) {
for (int z = 0; z < 32; z++) {
if (progressReceiver != null) {
progressReceiver.setProgress((float) count / total);
count++;
}
final Point chunkCoords = new Point((regionFile.getX() << 5) | x, (regionFile.getZ() << 5) | z);
if ((chunksToSkip != null) && chunksToSkip.contains(chunkCoords)) {
continue;
}
if (regionFile.containsChunk(x, z)) {
final Tag tag;
try {
final InputStream chunkData = regionFile.getChunkDataInputStream(x, z);
if (chunkData == null) {
// This should never happen, since we checked
// with isChunkPresent(), but in practice it
// does. Perhaps corrupted data?
reportBuilder.append("Missing chunk data for chunk " + x + ", " + z + " in " + file + "; skipping chunk" + EOL);
logger.warn("Missing chunk data for chunk " + x + ", " + z + " in " + file + "; skipping chunk");
continue;
}
try (NBTInputStream in = new NBTInputStream(chunkData)) {
tag = in.readTag();
}
} catch (IOException e) {
reportBuilder.append("I/O error while reading chunk " + x + ", " + z + " from file " + file + " (message: \"" + e.getMessage() + "\"); skipping chunk" + EOL);
logger.error("I/O error while reading chunk " + x + ", " + z + " from file " + file + "; skipping chunk", e);
continue;
} catch (IllegalArgumentException e) {
reportBuilder.append("Illegal argument exception while reading chunk " + x + ", " + z + " from file " + file + " (message: \"" + e.getMessage() + "\"); skipping chunk" + EOL);
logger.error("Illegal argument exception while reading chunk " + x + ", " + z + " from file " + file + "; skipping chunk", e);
continue;
} catch (NegativeArraySizeException e) {
reportBuilder.append("Negative array size exception while reading chunk " + x + ", " + z + " from file " + file + " (message: \"" + e.getMessage() + "\"); skipping chunk" + EOL);
logger.error("Negative array size exception while reading chunk " + x + ", " + z + " from file " + file + "; skipping chunk", e);
continue;
}
final Chunk chunk = (version == SUPPORTED_VERSION_1) ? new ChunkImpl((CompoundTag) tag, maxHeight) : new ChunkImpl2((CompoundTag) tag, maxHeight);
final Point tileCoords = new Point(chunk.getxPos() >> 3, chunk.getzPos() >> 3);
Tile tile = dimension.getTile(tileCoords);
if (tile == null) {
tile = dimension.getTileFactory().createTile(tileCoords.x, tileCoords.y);
for (int xx = 0; xx < 8; xx++) {
for (int yy = 0; yy < 8; yy++) {
newChunks.add(new Point((tileCoords.x << TILE_SIZE_BITS) | (xx << 4), (tileCoords.y << TILE_SIZE_BITS) | (yy << 4)));
}
}
dimension.addTile(tile);
}
newChunks.remove(new Point(chunk.getxPos() << 4, chunk.getzPos() << 4));
boolean manMadeStructuresBelowGround = false;
boolean manMadeStructuresAboveGround = false;
try {
for (int xx = 0; xx < 16; xx++) {
for (int zz = 0; zz < 16; zz++) {
float height = -1.0f;
int waterLevel = 0;
boolean floodWithLava = false, frost = false;
Terrain terrain = Terrain.BEDROCK;
for (int y = maxY; y >= 0; y--) {
int blockType = chunk.getBlockType(xx, y, zz);
int data = chunk.getDataValue(xx, y, zz);
if (!NATURAL_BLOCKS.get(blockType)) {
if (height == -1.0f) {
manMadeStructuresAboveGround = true;
} else {
manMadeStructuresBelowGround = true;
}
// manMadeBlockTypes.add(Material.get(blockType, data));
}
if ((blockType == BLK_SNOW) || (blockType == BLK_ICE)) {
frost = true;
}
if (((blockType == BLK_ICE) || (blockType == BLK_FROSTED_ICE) || (((blockType == BLK_STATIONARY_WATER) || (blockType == BLK_WATER) || (blockType == BLK_STATIONARY_LAVA) || (blockType == BLK_LAVA)) && (data == 0))) && (waterLevel == 0)) {
waterLevel = y;
if ((blockType == BLK_LAVA) || (blockType == BLK_STATIONARY_LAVA)) {
floodWithLava = true;
}
} else if (height == -1.0f) {
final Material material = Material.get(blockType, data);
if (SPECIAL_TERRAIN_MAPPING.containsKey(material)) {
// Special terrain found
// Value that falls in the middle of the lowest one eigthth which will still round to the same integer value and will receive a one layer thick smooth snow block (principle of least surprise)
height = y - 0.4375f;
terrain = SPECIAL_TERRAIN_MAPPING.get(material);
} else if (TERRAIN_MAPPING.containsKey(blockType)) {
// Terrain found
// Value that falls in the middle of the lowest one eigthth which will still round to the same integer value and will receive a one layer thick smooth snow block (principle of least surprise)
height = y - 0.4375f;
terrain = TERRAIN_MAPPING.get(blockType);
}
}
}
// Use smooth snow, if present, to better approximate world height, so smooth snow will survive merge
final int intHeight = (int) (height + 0.5f);
if ((height != -1.0f) && (intHeight < maxY) && (chunk.getBlockType(xx, intHeight + 1, zz) == BLK_SNOW)) {
int data = chunk.getDataValue(xx, intHeight + 1, zz);
height += data * 0.125;
}
if ((waterLevel == 0) && (height >= 61.5f)) {
waterLevel = 62;
}
final int blockX = (chunk.getxPos() << 4) | xx;
final int blockY = (chunk.getzPos() << 4) | zz;
final Point coords = new Point(blockX, blockY);
dimension.setTerrainAt(coords, terrain);
dimension.setHeightAt(coords, Math.max(height, 0.0f));
dimension.setWaterLevelAt(blockX, blockY, waterLevel);
if (frost) {
dimension.setBitLayerValueAt(Frost.INSTANCE, blockX, blockY, true);
}
if (floodWithLava) {
dimension.setBitLayerValueAt(FloodWithLava.INSTANCE, blockX, blockY, true);
}
if (height == -1.0f) {
dimension.setBitLayerValueAt(org.pepsoft.worldpainter.layers.Void.INSTANCE, blockX, blockY, true);
}
if (importBiomes && chunk.isBiomesAvailable()) {
final int biome = chunk.getBiome(xx, zz);
// adjust the biome when the user makes changes
if ((biome != 255) && (biome != dimension.getAutoBiome(blockX, blockY))) {
dimension.setLayerValueAt(Biome.INSTANCE, blockX, blockY, biome);
}
}
}
}
} catch (NullPointerException e) {
reportBuilder.append("Null pointer exception while reading chunk " + x + ", " + z + " from file " + file + "; skipping chunk" + EOL);
logger.error("Null pointer exception while reading chunk " + x + ", " + z + " from file " + file + "; skipping chunk", e);
continue;
} catch (ArrayIndexOutOfBoundsException e) {
reportBuilder.append("Array index out of bounds while reading chunk " + x + ", " + z + " from file " + file + " (message: \"" + e.getMessage() + "\"); skipping chunk" + EOL);
logger.error("Array index out of bounds while reading chunk " + x + ", " + z + " from file " + file + "; skipping chunk", e);
continue;
}
if (((readOnlyOption == ReadOnlyOption.MAN_MADE) && (manMadeStructuresBelowGround || manMadeStructuresAboveGround)) || ((readOnlyOption == ReadOnlyOption.MAN_MADE_ABOVE_GROUND) && manMadeStructuresAboveGround) || (readOnlyOption == ReadOnlyOption.ALL)) {
dimension.setBitLayerValueAt(ReadOnly.INSTANCE, chunk.getxPos() << 4, chunk.getzPos() << 4, true);
}
}
}
}
} finally {
regionFile.close();
}
} catch (IOException e) {
reportBuilder.append("I/O error while opening region file " + file + " (message: \"" + e.getMessage() + "\"); skipping region" + EOL);
logger.error("I/O error while opening region file " + file + "; skipping region", e);
}
}
// Process chunks that were only added to fill out a tile
for (Point newChunkCoords : newChunks) {
dimension.setBitLayerValueAt(NotPresent.INSTANCE, newChunkCoords.x, newChunkCoords.y, true);
if (populateNewChunks) {
dimension.setBitLayerValueAt(Populate.INSTANCE, newChunkCoords.x, newChunkCoords.y, true);
}
}
if (progressReceiver != null) {
progressReceiver.setProgress(1.0f);
}
return reportBuilder.length() != 0 ? reportBuilder.toString() : null;
}
use of org.jnbt.Tag in project WorldPainter by Captain-Chaos.
the class Statistics method main.
public static void main(String[] args) throws IOException {
File levelDatFile = new File(args[0]);
Level level = Level.load(levelDatFile);
if ((level.getVersion() != SUPPORTED_VERSION_1) && (level.getVersion() != SUPPORTED_VERSION_2)) {
throw new UnsupportedOperationException("Level format version " + level.getVersion() + " not supported");
}
int maxHeight = level.getMaxHeight();
int maxY = maxHeight - 1;
File worldDir = levelDatFile.getParentFile();
File regionDir = new File(worldDir, "region");
int version = level.getVersion();
final Pattern regionFilePattern = (version == SUPPORTED_VERSION_1) ? Pattern.compile("r\\.-?\\d+\\.-?\\d+\\.mcr") : Pattern.compile("r\\.-?\\d+\\.-?\\d+\\.mca");
File[] regionFiles = regionDir.listFiles((dir, name) -> {
return regionFilePattern.matcher(name).matches();
});
int[][] blockTypeCounts = new int[maxHeight >> 4][4096];
int[][] blockTypeTotals = new int[maxHeight >> 4][4096];
// int totalBlockCount = 0, totalBlocksPerLevel = 0;
System.out.println("Scanning " + worldDir);
System.out.print('|');
for (int i = 0; i < regionFiles.length - 2; i++) {
System.out.print('-');
}
System.out.println('|');
for (File file : regionFiles) {
RegionFile regionFile = new RegionFile(file);
try {
for (int x = 0; x < 32; x++) {
for (int z = 0; z < 32; z++) {
if (regionFile.containsChunk(x, z)) {
// totalBlocksPerLevel += 256;
// System.out.println("Chunk " + x + ", " + z);
// System.out.print('.');
Tag tag;
try (NBTInputStream in = new NBTInputStream(regionFile.getChunkDataInputStream(x, z))) {
tag = in.readTag();
}
Chunk chunk = (version == SUPPORTED_VERSION_1) ? new ChunkImpl((CompoundTag) tag, maxHeight) : new ChunkImpl2((CompoundTag) tag, maxHeight);
for (int xx = 0; xx < 16; xx++) {
for (int zz = 0; zz < 16; zz++) {
for (int y = maxY; y >= 0; y--) {
int blockType = chunk.getBlockType(xx, y, zz);
int dataValue = chunk.getDataValue(xx, y, zz);
blockTypeCounts[y >> 4][(blockType << 4) | dataValue]++;
blockTypeTotals[y >> 4][(blockType << 4) | dataValue]++;
// totalBlockCount++;
}
}
}
}
}
}
// System.out.println();
} finally {
regionFile.close();
}
System.out.print('#');
}
System.out.println();
System.out.println("\tGranite\tDiorite\tAndesite");
for (int y = 0; y < maxHeight >> 4; y++) {
int stoneLikeTotal = blockTypeTotals[y][Material.STONE.index] + blockTypeTotals[y][Material.GRANITE.index] + blockTypeTotals[y][Material.DIORITE.index] + blockTypeTotals[y][Material.ANDESITE.index];
// System.out.println("Total stonelike blocks: " + stoneLikeTotal);
System.out.print(y + "\t");
System.out.printf("%6.2f‰\t", ((float) blockTypeTotals[y][Material.GRANITE.index] / stoneLikeTotal * 1000));
System.out.printf("%6.2f‰\t", ((float) blockTypeTotals[y][Material.DIORITE.index] / stoneLikeTotal * 1000));
System.out.printf("%6.2f‰%n", ((float) blockTypeTotals[y][Material.ANDESITE.index] / stoneLikeTotal * 1000));
}
}
use of org.jnbt.Tag in project WorldPainter by Captain-Chaos.
the class RegressionIT method verifyJavaDimension.
protected void verifyJavaDimension(File worldDir, Dimension dimension, int... expectedBlocks) throws IOException {
World2 world = dimension.getWorld();
logger.info("Verifying dimension {} of map {}", dimension.getName(), world.getName());
boolean checkBounds;
Rectangle expectedBounds = null;
if (!dimension.containsOneOf(NotPresent.INSTANCE)) {
checkBounds = true;
int lowestTileX, highestTileX, lowestTileY, highestTileY;
if (dimension.getWorld().getTilesToExport() != null) {
lowestTileX = Integer.MAX_VALUE;
highestTileX = Integer.MIN_VALUE;
lowestTileY = Integer.MAX_VALUE;
highestTileY = Integer.MIN_VALUE;
for (Point tile : dimension.getWorld().getTilesToExport()) {
if (tile.x < lowestTileX) {
lowestTileX = tile.x;
}
if (tile.x > highestTileX) {
highestTileX = tile.x;
}
if (tile.y < lowestTileY) {
lowestTileY = tile.y;
}
if (tile.y > highestTileY) {
highestTileY = tile.y;
}
}
} else {
lowestTileX = dimension.getLowestX();
highestTileX = dimension.getHighestX();
lowestTileY = dimension.getLowestY();
highestTileY = dimension.getHighestY();
}
int expectedLowestChunkX = lowestTileX << 3;
int expectedHighestChunkX = ((highestTileX + 1) << 3) - 1;
int expectedLowestChunkZ = lowestTileY << 3;
int expectedHighestChunkZ = ((highestTileY + 1) << 3) - 1;
expectedBounds = new Rectangle(expectedLowestChunkX, expectedLowestChunkZ, expectedHighestChunkX - expectedLowestChunkX + 1, expectedHighestChunkZ - expectedLowestChunkZ + 1);
} else {
checkBounds = false;
logger.warn("Skipping bounds check for dimension which contains the NotReady layer");
}
File regionDir;
switch(dimension.getDim()) {
case DIM_NORMAL:
regionDir = new File(worldDir, "region");
break;
case DIM_NETHER:
regionDir = new File(worldDir, "DIM-1/region");
break;
case DIM_END:
regionDir = new File(worldDir, "DIM1/region");
break;
default:
throw new IllegalArgumentException();
}
Platform platform = world.getPlatform();
int maxHeight = dimension.getMaxHeight();
Pattern regionFilePattern = platform.equals(DefaultPlugin.JAVA_MCREGION) ? Pattern.compile("r\\.(-?\\d+)\\.(-?\\d+)\\.mcr") : Pattern.compile("r\\.(-?\\d+)\\.(-?\\d+)\\.mca");
int lowestChunkX = Integer.MAX_VALUE, highestChunkX = Integer.MIN_VALUE;
int lowestChunkZ = Integer.MAX_VALUE, highestChunkZ = Integer.MIN_VALUE;
BitSet blockTypes = new BitSet(256);
for (File file : regionDir.listFiles()) {
Matcher matcher = regionFilePattern.matcher(file.getName());
if (matcher.matches()) {
int regionX = Integer.parseInt(matcher.group(1));
int regionZ = Integer.parseInt(matcher.group(2));
try (RegionFile regionFile = new RegionFile(file, true)) {
for (int chunkX = 0; chunkX < 32; chunkX++) {
for (int chunkZ = 0; chunkZ < 32; chunkZ++) {
if (regionFile.containsChunk(chunkX, chunkZ)) {
int absChunkX = (regionX << 5) + chunkX;
int absChunkZ = (regionZ << 5) + chunkZ;
if (absChunkX < lowestChunkX) {
lowestChunkX = absChunkX;
}
if (absChunkX > highestChunkX) {
highestChunkX = absChunkX;
}
if (absChunkZ < lowestChunkZ) {
lowestChunkZ = absChunkZ;
}
if (absChunkZ > highestChunkZ) {
highestChunkZ = absChunkZ;
}
Chunk chunk;
try (NBTInputStream in = new NBTInputStream(regionFile.getChunkDataInputStream(chunkX, chunkZ))) {
Tag tag = in.readTag();
chunk = platform.equals(DefaultPlugin.JAVA_MCREGION) ? new ChunkImpl((CompoundTag) tag, maxHeight, true) : new ChunkImpl2((CompoundTag) tag, maxHeight, true);
}
// all block types present
for (int x = 0; x < 16; x++) {
for (int y = 0; y < maxHeight; y++) {
for (int z = 0; z < 16; z++) {
blockTypes.set(chunk.getBlockType(x, y, z));
}
}
}
}
}
}
}
}
}
if (checkBounds) {
assertEquals(expectedBounds, new Rectangle(lowestChunkX, lowestChunkZ, highestChunkX - lowestChunkX + 1, highestChunkZ - lowestChunkZ + 1));
}
// types and layers used
for (int expectedBlock : expectedBlocks) {
assertTrue("expected block type " + Block.BLOCKS[expectedBlock].name + " missing", blockTypes.get(expectedBlock));
}
}
Aggregations