Optimize schem paste + add MCAWriter to anvil

This commit is contained in:
Jesse Boyd 2017-03-29 06:57:01 +11:00
parent 11327d49e1
commit bb56a39792
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
20 changed files with 628 additions and 551 deletions

View File

@ -19,6 +19,7 @@ import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.blocks.BlockType;
import com.sk89q.worldedit.blocks.ImmutableBlock;
import com.sk89q.worldedit.blocks.ImmutableDatalessBlock;
import com.sk89q.worldedit.blocks.ImmutableNBTBlock;
import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.registry.BundledBlockData;
import java.awt.Color;
@ -176,7 +177,9 @@ public class FaweCache {
for (int i = 0; i < Character.MAX_VALUE; i++) {
int id = i >> 4;
int data = i & 0xf;
if (FaweCache.hasData(id)) {
if (FaweCache.hasNBT(id)) {
CACHE_BLOCK[i] = new ImmutableNBTBlock(id, data);
} else if (FaweCache.hasData(id)) {
CACHE_BLOCK[i] = new ImmutableBlock(id, data);
} else {
CACHE_BLOCK[i] = new ImmutableDatalessBlock(id);

View File

@ -2,6 +2,8 @@ package com.boydti.fawe.jnbt;
import com.boydti.fawe.object.RunnableVal2;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import java.io.IOException;
import java.util.HashMap;

View File

@ -2,8 +2,6 @@ package com.boydti.fawe.jnbt.anvil;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MutableBlockVector;
@ -22,17 +20,19 @@ import com.sk89q.worldedit.world.registry.WorldData;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import java.util.zip.Deflater;
public class HeightMapMCAGenerator implements Extent {
public class HeightMapMCAGenerator extends MCAWriter implements Extent {
private final MutableBlockVector mutable = new MutableBlockVector();
private final ForkJoinPool pool = new ForkJoinPool();
final Int2ObjectOpenHashMap<char[][][]> blocks = new Int2ObjectOpenHashMap<>();
private final ThreadLocal<int[]> indexStore = new ThreadLocal<int[]>() {
@Override
protected int[] initialValue() {
return new int[256];
}
};
private final Int2ObjectOpenHashMap<char[][][]> blocks = new Int2ObjectOpenHashMap<>();
private final byte[] heights;
private final byte[] biomes;
@ -40,11 +40,6 @@ public class HeightMapMCAGenerator implements Extent {
private final char[] main;
private char[] overlay;
private final File folder;
private final int length;
private final int width;
private final int area;
private boolean modifiedMain = false;
public HeightMapMCAGenerator(BufferedImage img, File regionFolder) {
@ -53,17 +48,12 @@ public class HeightMapMCAGenerator implements Extent {
}
public HeightMapMCAGenerator(int width, int length, File regionFolder) {
if (!regionFolder.exists()) {
regionFolder.mkdirs();
}
this.folder = regionFolder;
this.width = width;
this.length = length;
this.area = width * length;
heights = new byte[area];
biomes = new byte[area];
floor = new char[area];
main = new char[area];
super(width, length, regionFolder);
int area = getArea();
heights = new byte[getArea()];
biomes = new byte[getArea()];
floor = new char[getArea()];
main = new char[getArea()];
char stone = (char) FaweCache.getCombined(1, 0);
char grass = (char) FaweCache.getCombined(2, 0);
Arrays.fill(main, stone);
@ -72,30 +62,30 @@ public class HeightMapMCAGenerator implements Extent {
public void setHeight(BufferedImage img) {
int index = 0;
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++, index++){
for (int z = 0; z < getLength(); z++) {
for (int x = 0; x < getWidth(); x++, index++){
heights[index] = (byte) img.getRGB(x, z);
}
}
}
public void addCaves() throws WorldEditException {
CuboidRegion region = new CuboidRegion(new Vector(0, 0, 0), new Vector(width, 255, length));
CuboidRegion region = new CuboidRegion(new Vector(0, 0, 0), new Vector(getWidth(), 255, getLength()));
addCaves(region);
}
public void addSchems(Mask mask, WorldData worldData, ClipboardHolder[] clipboards, int rarity, boolean rotate) throws WorldEditException{
CuboidRegion region = new CuboidRegion(new Vector(0, 0, 0), new Vector(width, 255, length));
CuboidRegion region = new CuboidRegion(new Vector(0, 0, 0), new Vector(getWidth(), 255, getLength()));
addSchems(region, mask, worldData, clipboards, rarity, rotate);
}
public void addOre(Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException {
CuboidRegion region = new CuboidRegion(new Vector(0, 0, 0), new Vector(width, 255, length));
CuboidRegion region = new CuboidRegion(new Vector(0, 0, 0), new Vector(getWidth(), 255, getLength()));
addOre(region, mask, material, size, frequency, rarity, minY, maxY);
}
public void addDefaultOres(Mask mask) throws WorldEditException {
addOres(new CuboidRegion(new Vector(0, 0, 0), new Vector(width, 255, length)), mask);
addOres(new CuboidRegion(new Vector(0, 0, 0), new Vector(getWidth(), 255, getLength())), mask);
}
@Override
@ -105,7 +95,7 @@ public class HeightMapMCAGenerator implements Extent {
@Override
public Vector getMaximumPoint() {
return new Vector(width - 1, 255, length - 1);
return new Vector(getWidth() - 1, 255, getLength() - 1);
}
@Override
@ -115,7 +105,7 @@ public class HeightMapMCAGenerator implements Extent {
@Override
public boolean setBiome(Vector2D position, BaseBiome biome) {
int index = position.getBlockZ() * width + position.getBlockX();
int index = position.getBlockZ() * getWidth() + position.getBlockX();
if (index < 0 || index >= heights.length) return false;
biomes[index] = (byte) biome.getId();
return true;
@ -123,14 +113,14 @@ public class HeightMapMCAGenerator implements Extent {
@Override
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
int index = z * width + x;
int index = z * getWidth() + x;
if (index < 0 || index >= heights.length) return false;
int height = heights[index] & 0xFF;
char combined = (char) FaweCache.getCombined(block);
if (y > height) {
if (y == height + 1) {
if (overlay == null) {
overlay = new char[area];
overlay = new char[getArea()];
}
overlay[index] = combined;
return true;
@ -174,7 +164,7 @@ public class HeightMapMCAGenerator implements Extent {
@Override
public BaseBiome getBiome(Vector2D position) {
int index = position.getBlockZ() * width + position.getBlockX();
int index = position.getBlockZ() * getWidth() + position.getBlockX();
if (index < 0 || index >= heights.length) return EditSession.nullBiome;
return FaweCache.CACHE_BIOME[biomes[index] & 0xFF];
}
@ -191,7 +181,7 @@ public class HeightMapMCAGenerator implements Extent {
@Override
public BaseBlock getLazyBlock(int x, int y, int z) {
int index = z * width + x;
int index = z * getWidth() + x;
if (index < 0 || index >= heights.length) return EditSession.nullBlock;
int height = heights[index] & 0xFF;
if (y > height) {
@ -232,23 +222,23 @@ public class HeightMapMCAGenerator implements Extent {
@Override
public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
int index = z * width + x;
int index = z * getWidth() + x;
if (index < 0 || index >= heights.length) return y;
return ((heights[index] & 0xFF) << 3) + (floor[index] & 0xFF) + 1;
}
@Override
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
int index = z * width + x;
int index = z * getWidth() + x;
if (index < 0 || index >= heights.length) return y;
return heights[index] & 0xFF;
}
public void setBiome(BufferedImage img, byte biome, boolean white) {
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
if (img.getWidth() != getWidth() || img.getHeight() != getLength()) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
int index = 0;
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++, index++){
for (int z = 0; z < getLength(); z++) {
for (int x = 0; x < getWidth(); x++, index++){
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
biomes[index] = biome;
@ -258,11 +248,11 @@ public class HeightMapMCAGenerator implements Extent {
}
private void setOverlay(BufferedImage img, char combined, boolean white) {
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
if (overlay == null) overlay = new char[area];
if (img.getWidth() != getWidth() || img.getHeight() != getLength()) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
if (overlay == null) overlay = new char[getArea()];
int index = 0;
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++, index++){
for (int z = 0; z < getLength(); z++) {
for (int x = 0; x < getWidth(); x++, index++){
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
overlay[index] = combined;
@ -272,11 +262,11 @@ public class HeightMapMCAGenerator implements Extent {
}
private void setMain(BufferedImage img, char combined, boolean white) {
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
if (img.getWidth() != getWidth() || img.getHeight() != getLength()) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
modifiedMain = true;
int index = 0;
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++, index++){
for (int z = 0; z < getLength(); z++) {
for (int x = 0; x < getWidth(); x++, index++){
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
main[index] = combined;
@ -286,10 +276,10 @@ public class HeightMapMCAGenerator implements Extent {
}
private void setFloor(BufferedImage img, char combined, boolean white) {
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
if (img.getWidth() != getWidth() || img.getHeight() != getLength()) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
int index = 0;
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++, index++){
for (int z = 0; z < getLength(); z++) {
for (int x = 0; x < getWidth(); x++, index++){
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
floor[index] = combined;
@ -299,11 +289,11 @@ public class HeightMapMCAGenerator implements Extent {
}
private void setColumn(BufferedImage img, char combined, boolean white) {
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
if (img.getWidth() != getWidth() || img.getHeight() != getLength()) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
modifiedMain = true;
int index = 0;
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++, index++){
for (int z = 0; z < getLength(); z++) {
for (int x = 0; x < getWidth(); x++, index++){
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
main[index] = combined;
@ -315,9 +305,9 @@ public class HeightMapMCAGenerator implements Extent {
public void setBiome(Mask mask, byte biome) {
int index = 0;
for (int z = 0; z < length; z++) {
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < width; x++, index++){
for (int x = 0; x < getWidth(); x++, index++){
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
@ -330,10 +320,10 @@ public class HeightMapMCAGenerator implements Extent {
private void setOverlay(Mask mask, char combined) {
int index = 0;
if (overlay == null) overlay = new char[area];
for (int z = 0; z < length; z++) {
if (overlay == null) overlay = new char[getArea()];
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < width; x++, index++){
for (int x = 0; x < getWidth(); x++, index++){
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
@ -346,9 +336,9 @@ public class HeightMapMCAGenerator implements Extent {
private void setFloor(Mask mask, char combined) {
int index = 0;
for (int z = 0; z < length; z++) {
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < width; x++, index++){
for (int x = 0; x < getWidth(); x++, index++){
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
@ -362,9 +352,9 @@ public class HeightMapMCAGenerator implements Extent {
private void setMain(Mask mask, char combined) {
modifiedMain = true;
int index = 0;
for (int z = 0; z < length; z++) {
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < width; x++, index++){
for (int x = 0; x < getWidth(); x++, index++){
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
@ -378,9 +368,9 @@ public class HeightMapMCAGenerator implements Extent {
private void setColumn(Mask mask, char combined) {
modifiedMain = true;
int index = 0;
for (int z = 0; z < length; z++) {
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < width; x++, index++){
for (int x = 0; x < getWidth(); x++, index++){
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
@ -397,12 +387,12 @@ public class HeightMapMCAGenerator implements Extent {
setOverlay(img, (char) ((BlockPattern) pattern).getBlock().getCombined(), white);
return;
}
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
if (overlay == null) overlay = new char[area];
if (img.getWidth() != getWidth() || img.getHeight() != getLength()) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
if (overlay == null) overlay = new char[getArea()];
int index = 0;
for (int z = 0; z < length; z++) {
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < width; x++, index++){
for (int x = 0; x < getWidth(); x++, index++){
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
mutable.mutX(x);
@ -418,12 +408,12 @@ public class HeightMapMCAGenerator implements Extent {
setMain(img, (char) ((BlockPattern) pattern).getBlock().getCombined(), white);
return;
}
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
if (img.getWidth() != getWidth() || img.getHeight() != getLength()) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
modifiedMain = true;
int index = 0;
for (int z = 0; z < length; z++) {
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < width; x++, index++){
for (int x = 0; x < getWidth(); x++, index++){
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
mutable.mutX(x);
@ -439,11 +429,11 @@ public class HeightMapMCAGenerator implements Extent {
setFloor(img, (char) ((BlockPattern) pattern).getBlock().getCombined(), white);
return;
}
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
if (img.getWidth() != getWidth() || img.getHeight() != getLength()) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
int index = 0;
for (int z = 0; z < length; z++) {
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < width; x++, index++){
for (int x = 0; x < getWidth(); x++, index++){
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
mutable.mutX(x);
@ -459,12 +449,12 @@ public class HeightMapMCAGenerator implements Extent {
setColumn(img, (char) ((BlockPattern) pattern).getBlock().getCombined(), white);
return;
}
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
if (img.getWidth() != getWidth() || img.getHeight() != getLength()) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
modifiedMain = true;
int index = 0;
for (int z = 0; z < length; z++) {
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < width; x++, index++){
for (int x = 0; x < getWidth(); x++, index++){
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
mutable.mutX(x);
@ -483,10 +473,10 @@ public class HeightMapMCAGenerator implements Extent {
return;
}
int index = 0;
if (overlay == null) overlay = new char[area];
for (int z = 0; z < length; z++) {
if (overlay == null) overlay = new char[getArea()];
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < width; x++, index++){
for (int x = 0; x < getWidth(); x++, index++){
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
@ -503,9 +493,9 @@ public class HeightMapMCAGenerator implements Extent {
return;
}
int index = 0;
for (int z = 0; z < length; z++) {
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < width; x++, index++){
for (int x = 0; x < getWidth(); x++, index++){
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
@ -523,9 +513,9 @@ public class HeightMapMCAGenerator implements Extent {
}
modifiedMain = true;
int index = 0;
for (int z = 0; z < length; z++) {
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < width; x++, index++){
for (int x = 0; x < getWidth(); x++, index++){
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
@ -543,9 +533,9 @@ public class HeightMapMCAGenerator implements Extent {
}
modifiedMain = true;
int index = 0;
for (int z = 0; z < length; z++) {
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < width; x++, index++){
for (int x = 0; x < getWidth(); x++, index++){
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
@ -577,7 +567,7 @@ public class HeightMapMCAGenerator implements Extent {
}
private void setOverlay(int value) {
if (overlay == null) overlay = new char[area];
if (overlay == null) overlay = new char[getArea()];
Arrays.fill(overlay, (char) value);
}
@ -587,9 +577,9 @@ public class HeightMapMCAGenerator implements Extent {
return;
}
int index = 0;
for (int z = 0; z < length; z++) {
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < width; x++, index++) {
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
@ -604,9 +594,9 @@ public class HeightMapMCAGenerator implements Extent {
return;
}
int index = 0;
for (int z = 0; z < length; z++) {
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < width; x++, index++) {
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
@ -623,9 +613,9 @@ public class HeightMapMCAGenerator implements Extent {
return;
}
int index = 0;
for (int z = 0; z < length; z++) {
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < width; x++, index++) {
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
@ -635,15 +625,15 @@ public class HeightMapMCAGenerator implements Extent {
}
public void setOverlay(Pattern value) {
if (overlay == null) overlay = new char[area];
if (overlay == null) overlay = new char[getArea()];
if (value instanceof BlockPattern) {
setOverlay(((BlockPattern) value).getBlock().getCombined());
return;
}
int index = 0;
for (int z = 0; z < length; z++) {
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < width; x++, index++) {
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
@ -656,321 +646,194 @@ public class HeightMapMCAGenerator implements Extent {
Arrays.fill(heights, (byte) value);
}
public void generate() throws IOException {
int bcx = 0;
int bcz = 0;
int tcx = (width - 1) >> 4;
int tcz = (length - 1) >> 4;
final ThreadLocal<MCAChunk> chunkStore = new ThreadLocal<MCAChunk>() {
@Override
protected MCAChunk initialValue() {
MCAChunk chunk = new MCAChunk(null, 0, 0);
chunk.biomes = new byte[256];
return chunk;
@Override
public boolean shouldWrite(int chunkX, int chunkZ) {
return true;
}
@Override
public MCAChunk write(MCAChunk chunk, int csx, int cex, int csz, int cez) {
int cx = chunk.getX();
int cz = chunk.getZ();
int[] indexes = indexStore.get();
for (int i = 0; i < chunk.ids.length; i++) {
byte[] idsArray = chunk.ids[i];
if (idsArray != null) {
Arrays.fill(idsArray, (byte) 0);
Arrays.fill(chunk.data[i], (byte) 0);
}
};
final ThreadLocal<byte[]> byteStore1 = new ThreadLocal<byte[]>() {
@Override
protected byte[] initialValue() {
return new byte[500000];
}
int index = 0;
int maxY = 0;
int minY = Integer.MAX_VALUE;
int[] heightMap = chunk.getHeightMapArray();
int globalIndex;
for (int z = csz; z <= cez; z++) {
globalIndex = z * getWidth() + csx;
for (int x = csx; x <= cex; x++, index++, globalIndex++) {
indexes[index] = globalIndex;
int height = heights[globalIndex] & 0xFF;
heightMap[index] = height;
maxY = Math.max(maxY, height);
minY = Math.min(minY, height);
}
};
final ThreadLocal<byte[]> byteStore2 = new ThreadLocal<byte[]>() {
@Override
protected byte[] initialValue() {
return new byte[500000];
}
};
final ThreadLocal<Deflater> deflateStore = new ThreadLocal<Deflater>() {
@Override
protected Deflater initialValue() {
Deflater deflater = new Deflater(1, false);
return deflater;
}
};
final ThreadLocal<int[]> indexStore = new ThreadLocal<int[]>() {
@Override
protected int[] initialValue() {
return new int[256];
}
};
}
boolean hasOverlay = this.overlay != null;
byte[] fileBuf = new byte[1 << 16];
for (int mcaZ = 0; mcaZ <= (length >> 9); mcaZ++) {
for (int mcaX = 0; mcaX <= (width >> 9); mcaX++) {
final int fmcaX = mcaX;
final int fmcaZ = mcaZ;
File file = new File(folder, "r." + mcaX + "." + mcaZ + ".mca");
if (!file.exists()) {
file.createNewFile();
}
final BufferedRandomAccessFile raf = new BufferedRandomAccessFile(file, "rw", fileBuf);
final byte[] header = new byte[4096];
final byte[][] compressed = new byte[1024][];
int bx = mcaX << 9;
int bz = mcaZ << 9;
int scx = bx >> 4;
int ecx = Math.min(scx + 31, tcx);
int scz = bz >> 4;
int ecz = Math.min(scz + 31, tcz);
short pair = MathMan.pairByte(mcaX, mcaZ);
for (int cz = scz; cz <= ecz; cz++) {
final int csz = cz << 4;
final int cez = Math.min(csz + 15, length - 1);
for (int cx = scx; cx <= ecx; cx++) {
final int csx = cx << 4;
final int cex = Math.min(csx + 15, width - 1);
final int fcx = cx;
final int fcz = cz;
int chunkPair = MathMan.pair((short) cx, (short) cz);
final char[][][] localBlocks = blocks.get(chunkPair);
pool.submit(new Runnable() {
@Override
public void run() {
try {
MCAChunk chunk = chunkStore.get();
int[] indexes = indexStore.get();
for (int i = 0; i < chunk.ids.length; i++) {
byte[] idsArray = chunk.ids[i];
if (idsArray != null) {
Arrays.fill(idsArray, (byte) 0);
}
byte[] dataArray = chunk.data[i];
if (dataArray != null) {
Arrays.fill(dataArray, (byte) 0);
}
}
int index = 0;
int maxY = 0;
int minY = Integer.MAX_VALUE;
int[] heightMap = chunk.getHeightMapArray();
int globalIndex;
for (int z = csz; z <= cez; z++) {
globalIndex = z * width + csx;
for (int x = csx; x <= cex; x++, index++, globalIndex++) {
indexes[index] = globalIndex;
int height = heights[globalIndex] & 0xFF;
heightMap[index] = height;
maxY = Math.max(maxY, height);
minY = Math.min(minY, height);
}
}
if (hasOverlay) {
maxY++;
}
int maxLayer = maxY >> 4;
int fillLayers = Math.max(0, (minY - 1)) >> 4;
for (int layer = 0; layer <= maxLayer; layer++) {
if (chunk.ids[layer] == null) {
chunk.ids[layer] = new byte[4096];
chunk.data[layer] = new byte[2048];
chunk.skyLight[layer] = new byte[2048];
chunk.blockLight[layer] = new byte[2048];
}
}
if (modifiedMain) { // If the main block is modified, we can't short circuit this
for (int layer = 0; layer < fillLayers; layer++) {
index = 0;
byte[] layerIds = chunk.ids[layer];
byte[] layerDatas = chunk.data[layer];
for (int z = csz; z <= cez; z++) {
for (int x = csx; x <= cex; x++, index++) {
globalIndex = indexes[index];
char mainCombined = main[globalIndex];
byte id = (byte) FaweCache.getId(mainCombined);
int data = FaweCache.getData(mainCombined);
if (data != 0) {
for (int y = 0; y < 16; y++) {
int mainIndex = index + (y << 8);
chunk.setNibble(mainIndex, layerDatas, data);
}
}
for (int y = 0; y < 16; y++) {
layerIds[index + (y << 8)] = id;
}
}
}
}
} else {
for (int layer = 0; layer < fillLayers; layer++) {
Arrays.fill(chunk.ids[layer], (byte) 1);
}
}
for (int layer = fillLayers; layer <= maxLayer; layer++) {
Arrays.fill(chunk.skyLight[layer], (byte) 255);
byte[] layerIds = chunk.ids[layer];
byte[] layerDatas = chunk.data[layer];
index = 0;
int startY = layer << 4;
int endY = startY + 15;
for (int z = csz; z <= cez; z++) {
for (int x = csx; x <= cex; x++, index++) {
globalIndex = indexes[index];
int height = heightMap[index];
int diff;
if (height > endY) {
diff = 16;
} else if (height >= startY) {
diff = height - startY;
char floorCombined = floor[globalIndex];
int id = FaweCache.getId(floorCombined);
int floorIndex = index + ((height & 15) << 8);
layerIds[floorIndex] = (byte) id;
int data = FaweCache.getData(floorCombined);
if (data != 0) {
chunk.setNibble(floorIndex, layerDatas, data);
}
if (hasOverlay && height >= startY - 1 && height < endY) {
char overlayCombined = overlay[globalIndex];
id = FaweCache.getId(overlayCombined);
int overlayIndex = index + (((height + 1) & 15) << 8);
layerIds[overlayIndex] = (byte) id;
data = FaweCache.getData(overlayCombined);
if (data != 0) {
chunk.setNibble(overlayIndex, layerDatas, data);
}
}
} else if (hasOverlay && height == startY - 1) {
char overlayCombined = overlay[globalIndex];
int id = FaweCache.getId(overlayCombined);
int overlayIndex = index + (((height + 1) & 15) << 8);
layerIds[overlayIndex] = (byte) id;
int data = FaweCache.getData(overlayCombined);
if (data != 0) {
chunk.setNibble(overlayIndex, layerDatas, data);
}
continue;
} else {
continue;
}
char mainCombined = main[globalIndex];
byte id = (byte) FaweCache.getId(mainCombined);
int data = FaweCache.getData(mainCombined);
if (data != 0) {
for (int y = 0; y < diff; y++) {
int mainIndex = index + (y << 8);
chunk.setNibble(mainIndex, layerDatas, data);
}
}
for (int y = 0; y < diff; y++) {
layerIds[index + (y << 8)] = id;
}
}
}
}
int maxYMod = 15 + (maxLayer << 4);
for (int layer = (maxY >> 4) + 1; layer < 16; layer++) {
chunk.ids[layer] = null;
chunk.data[layer] = null;
}
index = 0;
{ // Bedrock
byte[] layerIds = chunk.ids[0];
for (int z = csz; z <= cez; z++) {
for (int x = csx; x <= cex; x++) {
layerIds[index++] = (byte) 7;
}
}
}
if (localBlocks != null) {
for (int layer = 0; layer < 16; layer++) {
int by = layer << 4;
int ty = by + 15;
index = 0;
for (int y = by; y <= ty; y++, index += 256) {
char[][] yBlocks = localBlocks[y];
if (yBlocks != null) {
if (chunk.ids[layer] == null) {
chunk.ids[layer] = new byte[4096];
chunk.data[layer] = new byte[2048];
chunk.skyLight[layer] = new byte[2048];
chunk.blockLight[layer] = new byte[2048];
}
byte[] idsLayer = chunk.ids[layer];
byte[] dataLayer = chunk.data[layer];
for (int z = 0; z < yBlocks.length; z++) {
char[] zBlocks = yBlocks[z];
if (zBlocks != null) {
int zIndex = index + (z << 4);
for (int x = 0; x < zBlocks.length; x++, zIndex++) {
char combined = zBlocks[x];
if (combined == 0) continue;
int id = FaweCache.getId(combined);
if (!FaweCache.hasData(id)) {
chunk.setIdUnsafe(idsLayer, zIndex, (byte) id);
} else {
chunk.setBlockUnsafe(idsLayer, dataLayer, zIndex, (byte) id, FaweCache.getData(combined));
}
}
}
}
}
}
}
}
chunk.setLoc(null, fcx, fcz);
byte[] bytes = chunk.toBytes(byteStore1.get());
byte[] compressedBytes = MainUtil.compress(bytes, byteStore2.get(), deflateStore.get());
int blocks = (compressed.length + 4095) >> 12;
compressed[((fcx & 31)) + ((fcz & 31) << 5)] = compressedBytes.clone();
} catch (Throwable e) {
e.printStackTrace();
}
if (hasOverlay) {
maxY++;
}
int maxLayer = maxY >> 4;
int fillLayers = Math.max(0, (minY - 1)) >> 4;
for (int layer = 0; layer <= maxLayer; layer++) {
if (chunk.ids[layer] == null) {
chunk.ids[layer] = new byte[4096];
chunk.data[layer] = new byte[2048];
chunk.skyLight[layer] = new byte[2048];
chunk.blockLight[layer] = new byte[2048];
}
}
if (modifiedMain) { // If the main block is modified, we can't short circuit this
for (int layer = 0; layer < fillLayers; layer++) {
index = 0;
byte[] layerIds = chunk.ids[layer];
byte[] layerDatas = chunk.data[layer];
for (int z = csz; z <= cez; z++) {
for (int x = csx; x <= cex; x++, index++) {
globalIndex = indexes[index];
char mainCombined = main[globalIndex];
byte id = (byte) FaweCache.getId(mainCombined);
int data = FaweCache.getData(mainCombined);
if (data != 0) {
for (int y = 0; y < 16; y++) {
int mainIndex = index + (y << 8);
chunk.setNibble(mainIndex, layerDatas, data);
}
});
}
for (int y = 0; y < 16; y++) {
layerIds[index + (y << 8)] = id;
}
}
}
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
pool.submit(new Runnable() {
@Override
public void run() {
try {
int totalLength = 8192;
for (int i = 0; i < compressed.length; i++) {
byte[] compressedBytes = compressed[i];
if (compressedBytes != null) {
int blocks = ((4095 + compressedBytes.length + 5) / 4096) * 4096;
totalLength += blocks;
}
}
} else {
for (int layer = 0; layer < fillLayers; layer++) {
Arrays.fill(chunk.ids[layer], (byte) 1);
}
}
for (int layer = fillLayers; layer <= maxLayer; layer++) {
Arrays.fill(chunk.skyLight[layer], (byte) 255);
byte[] layerIds = chunk.ids[layer];
byte[] layerDatas = chunk.data[layer];
index = 0;
int startY = layer << 4;
int endY = startY + 15;
for (int z = csz; z <= cez; z++) {
for (int x = csx; x <= cex; x++, index++) {
globalIndex = indexes[index];
int height = heightMap[index];
int diff;
if (height > endY) {
diff = 16;
} else if (height >= startY) {
diff = height - startY;
char floorCombined = floor[globalIndex];
int id = FaweCache.getId(floorCombined);
int floorIndex = index + ((height & 15) << 8);
layerIds[floorIndex] = (byte) id;
int data = FaweCache.getData(floorCombined);
if (data != 0) {
chunk.setNibble(floorIndex, layerDatas, data);
}
if (hasOverlay && height >= startY - 1 && height < endY) {
char overlayCombined = overlay[globalIndex];
id = FaweCache.getId(overlayCombined);
int overlayIndex = index + (((height + 1) & 15) << 8);
layerIds[overlayIndex] = (byte) id;
data = FaweCache.getData(overlayCombined);
if (data != 0) {
chunk.setNibble(overlayIndex, layerDatas, data);
}
raf.setLength(totalLength);
int offset = 8192;
for (int i = 0; i < compressed.length; i++) {
byte[] compressedBytes = compressed[i];
if (compressedBytes != null) {
// Set header
int index = i << 2;
int offsetMedium = offset >> 12;
int blocks = ((4095 + compressedBytes.length + 5) / 4096);
header[index] = (byte) (offsetMedium >> 16);
header[index + 1] = (byte) ((offsetMedium >> 8));
header[index + 2] = (byte) ((offsetMedium >> 0));
header[index + 3] = (byte) (blocks);
// Write bytes
int cx = (fmcaX << 5) + (i & 31);
int cz = (fmcaZ << 5) + (i >> 5);
raf.seek(offset);
raf.writeInt(compressedBytes.length);
raf.write(2);
raf.write(compressedBytes);
offset += blocks * 4096;
}
} else if (hasOverlay && height == startY - 1) {
char overlayCombined = overlay[globalIndex];
int id = FaweCache.getId(overlayCombined);
int overlayIndex = index + (((height + 1) & 15) << 8);
layerIds[overlayIndex] = (byte) id;
int data = FaweCache.getData(overlayCombined);
if (data != 0) {
chunk.setNibble(overlayIndex, layerDatas, data);
}
continue;
} else {
continue;
}
char mainCombined = main[globalIndex];
byte id = (byte) FaweCache.getId(mainCombined);
int data = FaweCache.getData(mainCombined);
if (data != 0) {
for (int y = 0; y < diff; y++) {
int mainIndex = index + (y << 8);
chunk.setNibble(mainIndex, layerDatas, data);
}
}
for (int y = 0; y < diff; y++) {
layerIds[index + (y << 8)] = id;
}
}
}
}
int maxYMod = 15 + (maxLayer << 4);
for (int layer = (maxY >> 4) + 1; layer < 16; layer++) {
chunk.ids[layer] = null;
chunk.data[layer] = null;
}
index = 0;
{ // Bedrock
byte[] layerIds = chunk.ids[0];
for (int z = csz; z <= cez; z++) {
for (int x = csx; x <= cex; x++) {
layerIds[index++] = (byte) 7;
}
}
}
int chunkPair = MathMan.pair((short) cx, (short) cz);
char[][][] localBlocks = blocks.get(chunkPair);
if (localBlocks != null) {
for (int layer = 0; layer < 16; layer++) {
int by = layer << 4;
int ty = by + 15;
index = 0;
for (int y = by; y <= ty; y++, index += 256) {
char[][] yBlocks = localBlocks[y];
if (yBlocks != null) {
if (chunk.ids[layer] == null) {
chunk.ids[layer] = new byte[4096];
chunk.data[layer] = new byte[2048];
chunk.skyLight[layer] = new byte[2048];
chunk.blockLight[layer] = new byte[2048];
}
byte[] idsLayer = chunk.ids[layer];
byte[] dataLayer = chunk.data[layer];
for (int z = 0; z < yBlocks.length; z++) {
char[] zBlocks = yBlocks[z];
if (zBlocks != null) {
int zIndex = index + (z << 4);
for (int x = 0; x < zBlocks.length; x++, zIndex++) {
char combined = zBlocks[x];
if (combined == 0) continue;
int id = FaweCache.getId(combined);
if (!FaweCache.hasData(id)) {
chunk.setIdUnsafe(idsLayer, zIndex, (byte) id);
} else {
chunk.setBlockUnsafe(idsLayer, dataLayer, zIndex, (byte) id, FaweCache.getData(combined));
}
}
}
raf.seek(0);
raf.write(header);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
}
}
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
return chunk;
}
}

View File

@ -0,0 +1,183 @@
package com.boydti.fawe.jnbt.anvil;
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import java.util.zip.Deflater;
public abstract class MCAWriter {
private final File folder;
private final int length;
private final int width;
private final int area;
public MCAWriter(int width, int length, File regionFolder) {
if (!regionFolder.exists()) {
regionFolder.mkdirs();
}
this.folder = regionFolder;
this.width = width;
this.length = length;
this.area = width * length;
}
public final File getFolder() {
return folder;
}
public final int getWidth() {
return width;
}
public final int getLength() {
return length;
}
public final int getArea() {
return area;
}
public abstract boolean shouldWrite(int chunkX, int chunkZ);
public abstract MCAChunk write(MCAChunk input, int startX, int endX, int startZ, int endZ);
public void generate() throws IOException {
final ForkJoinPool pool = new ForkJoinPool();
int bcx = 0;
int bcz = 0;
int tcx = (width - 1) >> 4;
int tcz = (length - 1) >> 4;
final ThreadLocal<MCAChunk> chunkStore = new ThreadLocal<MCAChunk>() {
@Override
protected MCAChunk initialValue() {
MCAChunk chunk = new MCAChunk(null, 0, 0);
chunk.biomes = new byte[256];
return chunk;
}
};
final ThreadLocal<byte[]> byteStore1 = new ThreadLocal<byte[]>() {
@Override
protected byte[] initialValue() {
return new byte[500000];
}
};
final ThreadLocal<byte[]> byteStore2 = new ThreadLocal<byte[]>() {
@Override
protected byte[] initialValue() {
return new byte[500000];
}
};
final ThreadLocal<Deflater> deflateStore = new ThreadLocal<Deflater>() {
@Override
protected Deflater initialValue() {
Deflater deflater = new Deflater(Deflater.BEST_SPEED, false);
return deflater;
}
};
byte[] fileBuf = new byte[1 << 16];
for (int mcaZ = 0; mcaZ <= (length >> 9); mcaZ++) {
for (int mcaX = 0; mcaX <= (width >> 9); mcaX++) {
final int fmcaX = mcaX;
final int fmcaZ = mcaZ;
File file = new File(folder, "r." + mcaX + "." + mcaZ + ".mca");
if (!file.exists()) {
file.createNewFile();
}
final BufferedRandomAccessFile raf = new BufferedRandomAccessFile(file, "rw", fileBuf);
final byte[] header = new byte[4096];
final byte[][] compressed = new byte[1024][];
int bx = mcaX << 9;
int bz = mcaZ << 9;
int scx = bx >> 4;
int ecx = Math.min(scx + 31, tcx);
int scz = bz >> 4;
int ecz = Math.min(scz + 31, tcz);
short pair = MathMan.pairByte(mcaX, mcaZ);
for (int cz = scz; cz <= ecz; cz++) {
final int csz = cz << 4;
final int cez = Math.min(csz + 15, length - 1);
for (int cx = scx; cx <= ecx; cx++) {
final int csx = cx << 4;
final int cex = Math.min(csx + 15, width - 1);
final int fcx = cx;
final int fcz = cz;
if (shouldWrite(cx, cz)) {
pool.submit(new Runnable() {
@Override
public void run() {
try {
MCAChunk chunk = chunkStore.get();
chunk.setLoc(null, fcx, fcz);
chunk = write(chunk, csx, cex, csz, cez);
if (chunk != null) {
byte[] bytes = chunk.toBytes(byteStore1.get());
byte[] compressedBytes = MainUtil.compress(bytes, byteStore2.get(), deflateStore.get());
int blocks = (compressed.length + 4095) >> 12;
compressed[((fcx & 31)) + ((fcz & 31) << 5)] = compressedBytes.clone();
}
} catch (Throwable e) {
e.printStackTrace();
}
}
});
}
}
}
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
pool.submit(new Runnable() {
@Override
public void run() {
try {
int totalLength = 8192;
for (int i = 0; i < compressed.length; i++) {
byte[] compressedBytes = compressed[i];
if (compressedBytes != null) {
int blocks = ((4095 + compressedBytes.length + 5) / 4096) * 4096;
totalLength += blocks;
}
}
raf.setLength(totalLength);
int offset = 8192;
for (int i = 0; i < compressed.length; i++) {
byte[] compressedBytes = compressed[i];
if (compressedBytes != null) {
// Set header
int index = i << 2;
int offsetMedium = offset >> 12;
int blocks = ((4095 + compressedBytes.length + 5) / 4096);
header[index] = (byte) (offsetMedium >> 16);
header[index + 1] = (byte) ((offsetMedium >> 8));
header[index + 2] = (byte) ((offsetMedium >> 0));
header[index + 3] = (byte) (blocks);
// Write bytes
int cx = (fmcaX << 5) + (i & 31);
int cz = (fmcaZ << 5) + (i >> 5);
raf.seek(offset);
raf.writeInt(compressedBytes.length);
raf.write(2);
raf.write(compressedBytes);
offset += blocks * 4096;
}
}
raf.seek(0);
raf.write(header);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
}
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
}
}

View File

@ -2,7 +2,6 @@ package com.boydti.fawe.object.brush;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.object.clipboard.CPUOptimizedClipboard;
import com.boydti.fawe.object.clipboard.FaweClipboard;
import com.boydti.fawe.object.clipboard.OffsetFaweClipboard;
@ -61,10 +60,10 @@ public class ErodeBrush implements Brush {
}
FaweClipboard finalBuffer = swap % 2 == 0 ? buffer1 : buffer2;
finalBuffer.forEach(new RunnableVal2<Vector, BaseBlock>() {
finalBuffer.forEach(new FaweClipboard.BlockReader() {
@Override
public void run(Vector pos, BaseBlock block) {
es.setBlock(pos.getBlockX() + bx, pos.getBlockY() + by, pos.getBlockZ() + bz, block);
public void run(int x, int y, int z, BaseBlock block) {
es.setBlock(x + bx, y + by, z + bz, block);
}
}, true);
}

View File

@ -1,7 +1,6 @@
package com.boydti.fawe.object.clipboard;
import com.boydti.fawe.jnbt.NBTStreamer;
import com.boydti.fawe.object.RunnableVal2;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
@ -78,7 +77,7 @@ public class AbstractDelegateFaweClipboard extends FaweClipboard {
}
@Override
public void forEach(RunnableVal2<Vector, BaseBlock> task, boolean air) {
public void forEach(BlockReader task, boolean air) {
parent.forEach(task, air);
}

View File

@ -3,7 +3,6 @@ package com.boydti.fawe.object.clipboard;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.jnbt.NBTStreamer;
import com.boydti.fawe.object.IntegerTrio;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.util.ReflectionUtils;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntTag;
@ -156,19 +155,15 @@ public class CPUOptimizedClipboard extends FaweClipboard {
}
@Override
public void forEach(final RunnableVal2<Vector,BaseBlock> task, boolean air) {
task.value1 = new Vector(0, 0, 0);
public void forEach(final BlockReader task, boolean air) {
for (int y = 0, index = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++, index++) {
task.value2 = getBlock(index);
if (!air && task.value2.getId() == 0) {
BaseBlock block = getBlock(index);
if (!air && block.getId() == 0) {
continue;
}
task.value1.mutX(x);
task.value1.mutY(y);
task.value1.mutZ(z);
task.run();
task.run(x, y, z, block);
}
}
}

View File

@ -5,14 +5,12 @@ import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.jnbt.NBTStreamer;
import com.boydti.fawe.object.IntegerTrio;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.ReflectionUtils;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
@ -233,6 +231,33 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
}
}
public static long start;
public static void main(String[] args) throws Throwable {
BaseBlock block = FaweCache.getBlock(0, 0);
DiskOptimizedClipboard clip = new DiskOptimizedClipboard(443, 256, 443, new File("test"));
start = System.currentTimeMillis();
clip.forEach(new BlockReader() {
@Override
public void run(int x, int y, int z, BaseBlock value2) {
}
}, true);
clip.close();
// BufferedRandomAccessFile raf = new BufferedRandomAccessFile(new File("test"), "rw");
// int len = 50000000;
// raf.setLength(len * 2);
// long start = System.currentTimeMillis();
// long total = 0;
// for (int i = 0; i < len; i++) {
// total += raf.readChar();
// }
// raf.close();
System.out.println(System.currentTimeMillis() - start + "ms");
// System.out.println("Total " + total);
System.exit(1);
}
@Override
public void streamDatas(NBTStreamer.ByteReader task) {
try {
@ -257,29 +282,38 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
}
@Override
public void forEach(final RunnableVal2<Vector,BaseBlock> task, boolean air) {
public void forEach(final BlockReader task, boolean air) {
try {
raf.seek(HEADER_SIZE);
BlockVector pos = new BlockVector(0, 0, 0);
IntegerTrio trio = new IntegerTrio();
final boolean hasTile = !nbtMap.isEmpty();
if (air) {
for (int y = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++) {
int combinedId = raf.readChar();
BaseBlock block = FaweCache.CACHE_BLOCK[combinedId];
if (FaweCache.hasNBT(block.getId())) {
trio.set(x, y, z);
CompoundTag nbt = nbtMap.get(trio);
if (nbt != null) {
block = new BaseBlock(block.getId(), block.getData());
block.setNbtData(nbt);
if (hasTile) {
for (int y = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++) {
char combinedId = raf.readChar();
BaseBlock block = FaweCache.CACHE_BLOCK[combinedId];
if (block.canStoreNBTData()) {
trio.set(x, y, z);
CompoundTag nbt = nbtMap.get(trio);
if (nbt != null) {
block = new BaseBlock(block.getId(), block.getData());
block.setNbtData(nbt);
}
}
task.run(x, y, z, block);
}
}
}
} else {
for (int y = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++) {
char combinedId = raf.readChar();
BaseBlock block = FaweCache.CACHE_BLOCK[combinedId];
task.run(x, y, z, block);
}
pos.mutX(x);
pos.mutY(y);
pos.mutZ(z);
task.run(pos, block);
}
}
}
@ -298,10 +332,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
block.setNbtData(nbt);
}
}
pos.mutX(x);
pos.mutY(y);
pos.mutZ(z);
task.run(pos, block);
task.run(x, y, z, block);
}
}
}

View File

@ -1,7 +1,6 @@
package com.boydti.fawe.object.clipboard;
import com.boydti.fawe.jnbt.NBTStreamer;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.util.ReflectionUtils;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntTag;
@ -50,23 +49,27 @@ public abstract class FaweClipboard {
* @param task
* @param air
*/
public abstract void forEach(final RunnableVal2<Vector,BaseBlock> task, boolean air);
public abstract void forEach(BlockReader task, boolean air);
public static abstract class BlockReader {
public abstract void run(int x, int y, int z, BaseBlock block);
}
public void streamIds(final NBTStreamer.ByteReader task) {
forEach(new RunnableVal2<Vector, BaseBlock>() {
forEach(new BlockReader() {
private int index = 0;
@Override
public void run(Vector pos, BaseBlock block) {
public void run(int x, int y, int z, BaseBlock block) {
task.run(index++, block.getId());
}
}, true);
}
public void streamDatas(final NBTStreamer.ByteReader task) {
forEach(new RunnableVal2<Vector, BaseBlock>() {
forEach(new BlockReader() {
private int index = 0;
@Override
public void run(Vector pos, BaseBlock block) {
public void run(int x, int y, int z, BaseBlock block) {
task.run(index++, block.getData());
}
}, true);
@ -74,16 +77,16 @@ public abstract class FaweClipboard {
public List<CompoundTag> getTileEntities() {
final List<CompoundTag> tiles = new ArrayList<>();
forEach(new RunnableVal2<Vector, BaseBlock>() {
forEach(new BlockReader() {
private int index = 0;
@Override
public void run(Vector pos, BaseBlock block) {
public void run(int x, int y, int z, BaseBlock block) {
CompoundTag tag = block.getNbtData();
if (tag != null) {
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
values.put("x", new IntTag(pos.getBlockX()));
values.put("y", new IntTag(pos.getBlockY()));
values.put("z", new IntTag(pos.getBlockZ()));
values.put("x", new IntTag(x));
values.put("y", new IntTag(y));
values.put("z", new IntTag(z));
tiles.add(tag);
}
}

View File

@ -4,7 +4,6 @@ import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.jnbt.NBTStreamer;
import com.boydti.fawe.object.IntegerTrio;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.ReflectionUtils;
import com.sk89q.jnbt.CompoundTag;
@ -377,20 +376,26 @@ public class MemoryOptimizedClipboard extends FaweClipboard {
}
@Override
public void forEach(final RunnableVal2<Vector,BaseBlock> task, boolean air) {
public void forEach(final BlockReader task, final boolean air) {
// Fawe.debug("Compressed: " + size() + "b | Uncompressed: " + (volume << 0x5) + "b");
task.value1 = new Vector(0, 0, 0);
for (int y = 0, index = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++, index++) {
task.value2 = getBlock(index);
if (!air && task.value2.getId() == 0) {
continue;
if (air) {
for (int y = 0, index = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++, index++) {
BaseBlock block = getBlock(index);
task.run(x, y, z, block);
}
}
}
} else {
for (int y = 0, index = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++, index++) {
BaseBlock block = getBlock(index);
if (block.getId() == 0) {
task.run(x, y, z, block);
}
}
task.value1.mutX(x);
task.value1.mutY(y);
task.value1.mutZ(z);
task.run();
}
}
}

View File

@ -1,8 +1,6 @@
package com.boydti.fawe.object.clipboard;
import com.boydti.fawe.object.RunnableVal2;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
public class OffsetFaweClipboard extends AbstractDelegateFaweClipboard {
@ -35,14 +33,11 @@ public class OffsetFaweClipboard extends AbstractDelegateFaweClipboard {
}
@Override
public void forEach(final RunnableVal2<Vector, BaseBlock> task, boolean air) {
super.forEach(new RunnableVal2<Vector, BaseBlock>() {
public void forEach(final BlockReader task, boolean air) {
super.forEach(new BlockReader() {
@Override
public void run(Vector value, BaseBlock block) {
value.mutX(value.getX() - ox);
value.mutY(value.getY() - oy);
value.mutZ(value.getZ() - oz);
task.run(value, block);
public void run(int x, int y, int z, BaseBlock block) {
task.run(x - ox, y - oy, z - oz, block);
}
}, air);
}

View File

@ -1,6 +1,5 @@
package com.boydti.fawe.object.clipboard;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.util.ReflectionUtils;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntTag;
@ -47,7 +46,7 @@ public class WorldCopyClipboard extends ReadOnlyClipboard {
}
@Override
public void forEach(final RunnableVal2<Vector, BaseBlock> task, boolean air) {
public void forEach(BlockReader task, boolean air) {
Vector min = region.getMinimumPoint();
Vector max = region.getMaximumPoint();
final Vector pos = new Vector();
@ -57,21 +56,18 @@ public class WorldCopyClipboard extends ReadOnlyClipboard {
RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() {
@Override
public boolean apply(Vector pos) throws WorldEditException {
int x = pos.getBlockX();
int y = pos.getBlockY();
int z = pos.getBlockZ();
BaseBlock block = getBlockAbs(x, y, z);
pos.mutX(x - mx);
pos.mutY(y - my);
pos.mutZ(z - mz);
BaseBlock block = getBlockAbs(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ());
int x = pos.getBlockX() - mx;
int y = pos.getBlockY() - my;
int z = pos.getBlockZ() - mz;
CompoundTag tag = block.getNbtData();
if (tag != null) {
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
values.put("x", new IntTag(pos.getBlockX()));
values.put("y", new IntTag(pos.getBlockY()));
values.put("z", new IntTag(pos.getBlockZ()));
values.put("x", new IntTag(x));
values.put("y", new IntTag(y));
values.put("z", new IntTag(z));
}
task.run(pos, block);
task.run(x, y, z, block);
return true;
}
}, editSession);
@ -82,27 +78,21 @@ public class WorldCopyClipboard extends ReadOnlyClipboard {
RegionVisitor visitor = new RegionVisitor(cuboidEquivalent, new RegionFunction() {
@Override
public boolean apply(Vector pos) throws WorldEditException {
int x = pos.getBlockX() - mx;
int y = pos.getBlockY() - my;
int z = pos.getBlockZ() - mz;
if (region.contains(pos)) {
int x = pos.getBlockX();
int y = pos.getBlockY();
int z = pos.getBlockZ();
BaseBlock block = getBlockAbs(x, y, z);
pos.mutX(x - mx);
pos.mutY(y - my);
pos.mutZ(z - mz);
BaseBlock block = getBlockAbs(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ());
CompoundTag tag = block.getNbtData();
if (tag != null) {
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
values.put("x", new IntTag(pos.getBlockX()));
values.put("y", new IntTag(pos.getBlockY()));
values.put("z", new IntTag(pos.getBlockZ()));
values.put("x", new IntTag(x));
values.put("y", new IntTag(y));
values.put("z", new IntTag(z));
}
task.run(pos, block);
task.run(x, y, z, block);
} else {
pos.mutX(pos.getBlockX() - mx);
pos.mutY(pos.getBlockY() - my);
pos.mutZ(pos.getBlockZ() - mz);
task.run(pos, EditSession.nullBlock);
task.run(x, y, z, EditSession.nullBlock);
}
return true;
}
@ -111,32 +101,29 @@ public class WorldCopyClipboard extends ReadOnlyClipboard {
}
} else {
for (int y = min.getBlockY(); y <= max.getBlockY(); y++) {
pos.mutY(y);
int yy = pos.getBlockY() - my;
for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
pos.mutZ(z);
int zz = pos.getBlockZ() - mz;
for (int x = min.getBlockX(); x <= max.getBlockX(); x++) {
pos.mutX(x);
pos.mutY(y);
pos.mutZ(z);
int xx = pos.getBlockX() - mx;
if (region.contains(pos)) {
BaseBlock block = getBlockAbs(x, y, z);
if (!air && block == EditSession.nullBlock) {
continue;
}
pos.mutX(pos.getX() - mx);
pos.mutY(pos.getY() - my);
pos.mutZ(pos.getZ() - mz);
CompoundTag tag = block.getNbtData();
if (tag != null) {
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
values.put("x", new IntTag(pos.getBlockX()));
values.put("y", new IntTag(pos.getBlockY()));
values.put("z", new IntTag(pos.getBlockZ()));
values.put("x", new IntTag(xx));
values.put("y", new IntTag(yy));
values.put("z", new IntTag(zz));
}
task.run(pos, block);
task.run(xx, yy, zz, block);
} else if (air) {
pos.mutX(pos.getX() - mx);
pos.mutY(pos.getY() - my);
pos.mutZ(pos.getZ() - mz);
task.run(pos, EditSession.nullBlock);
task.run(xx, yy, zz, EditSession.nullBlock);
}
}
}

View File

@ -28,7 +28,7 @@ public class WorldCutClipboard extends WorldCopyClipboard {
}
@Override
public void forEach(RunnableVal2<Vector, BaseBlock> task, boolean air) {
public void forEach(BlockReader task, boolean air) {
super.forEach(task, air);
editSession.flushQueue();
}

View File

@ -1,7 +1,7 @@
package com.boydti.fawe.object.schematic;
import com.boydti.fawe.object.HasFaweQueue;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.object.clipboard.FaweClipboard;
import com.boydti.fawe.object.clipboard.ReadOnlyClipboard;
import com.boydti.fawe.util.EditSessionBuilder;
import com.boydti.fawe.util.MaskTraverser;
@ -167,18 +167,13 @@ public class Schematic {
final int rely = to.getBlockY() + bot.getBlockY() - origin.getBlockY();
final int relz = to.getBlockZ() + bot.getBlockZ() - origin.getBlockZ();
BlockArrayClipboard bac = (BlockArrayClipboard) clipboard;
bac.IMP.forEach(new RunnableVal2<Vector, BaseBlock>() {
bac.IMP.forEach(new FaweClipboard.BlockReader() {
@Override
public void run(Vector mutable, BaseBlock block) {
mutable.mutX(mutable.getX() + relx);
mutable.mutY(mutable.getY() + rely);
mutable.mutZ(mutable.getZ() + relz);
if (mutable.getY() >= 0 && mutable.getY() <= maxY) {
try {
extent.setBlock(mutable, block);
} catch (WorldEditException e) {
throw new RuntimeException(e);
}
public void run(int x, int y, int z, BaseBlock block) {
try {
extent.setBlock(x + relx, y + rely, z + relz, block);
} catch (WorldEditException e) {
throw new RuntimeException(e);
}
}
}, pasteAir);
@ -194,12 +189,7 @@ public class Schematic {
if (block == EditSession.nullBlock && !pasteAir) {
return false;
}
mutable.mutX(mutable.getX() + relx);
mutable.mutY(mutable.getY() + rely);
mutable.mutZ(mutable.getZ() + relz);
if (mutable.getY() >= 0 && mutable.getY() <= maxY) {
return extent.setBlock(mutable, block);
}
extent.setBlock(mutable.getBlockX() + relx, mutable.getBlockY() + rely, mutable.getBlockZ() + relz, block);
return false;
}
}, (HasFaweQueue) (extent instanceof HasFaweQueue ? extent : null));

View File

@ -250,7 +250,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
if (combineStages == null) {
combineStages = Settings.IMP.HISTORY.COMBINE_STAGES && !(queue instanceof MCAQueue);
}
if (limit.FAST_PLACEMENT) {
if (!limit.FAST_PLACEMENT) {
combineStages = false;
}
if (checkMemory) {
@ -314,6 +314,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
if (this.blockBag != null && limit.INVENTORY_MODE > 0) {
changeSet = new BlockBagChangeSet(changeSet, blockBag, limit.INVENTORY_MODE == 1);
}
System.out.println("Combine stages " + combineStages);
if (combineStages) {
changeTask = changeSet;
changeSet.addChangeTask(queue);
@ -3213,17 +3214,13 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
}
@Override
public boolean clearContainerBlockContents(Vector position) {
BaseBlock block = getBlock(position);
public boolean clearContainerBlockContents(Vector pos) {
BaseBlock block = getBlock(pos);
CompoundTag nbt = block.getNbtData();
if (nbt != null) {
if (nbt.containsKey("items")) {
block.setNbtData(null);
try {
return setBlock(position, block);
} catch (WorldEditException e) {
e.printStackTrace();
}
return setBlock(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(), block);
}
}
return false;

View File

@ -237,6 +237,11 @@ public class BaseBlock extends Block implements TileEntityBlock, Pattern {
return getNbtData() != null;
}
public boolean canStoreNBTData() {
return FaweCache.hasNBT(getId());
}
@Override
public String getNbtId() {
CompoundTag nbtData = getNbtData();

View File

@ -29,6 +29,11 @@ public class ImmutableBlock extends BaseBlock {
return clone.flip(direction);
}
@Override
public boolean canStoreNBTData() {
return false;
}
@Override
public boolean isImmutable() {
return true;

View File

@ -23,4 +23,9 @@ public class ImmutableDatalessBlock extends ImmutableBlock {
return false;
}
}
@Override
public boolean canStoreNBTData() {
return false;
}
}

View File

@ -0,0 +1,12 @@
package com.sk89q.worldedit.blocks;
public class ImmutableNBTBlock extends ImmutableBlock {
public ImmutableNBTBlock(int id, int data) {
super(id, data);
}
@Override
public boolean canStoreNBTData() {
return true;
}
}

View File

@ -2,7 +2,6 @@ package com.sk89q.worldedit.extent.clipboard.io;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.jnbt.NBTStreamer;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.object.clipboard.FaweClipboard;
import com.boydti.fawe.util.ReflectionUtils;
import com.sk89q.jnbt.ByteArrayTag;
@ -54,7 +53,7 @@ public class SchematicWriter implements ClipboardWriter {
this.outputStream = outputStream;
}
private static class ForEach extends RunnableVal2<Vector, BaseBlock> {
private static class ForEach extends FaweClipboard.BlockReader {
int x = -1;
int y = 0;
int z = 0;
@ -76,10 +75,7 @@ public class SchematicWriter implements ClipboardWriter {
}
@Override
public void run(Vector point, BaseBlock block) {
int x = (int) point.getX();
int y = (int) point.getY();
int z = (int) point.getZ();
public void run(int x, int y, int z, BaseBlock block) {
if (this.x == x - 1 && this.y == y && this.z == z) {
this.x++;
index++;
@ -164,6 +160,7 @@ public class SchematicWriter implements ClipboardWriter {
public void run(int index, int byteValue) {
try {
if (byteValue >= 256) {
System.out.println("Add block");
hasAdd = true;
}
if (FaweCache.hasData(byteValue)) {
@ -205,6 +202,7 @@ public class SchematicWriter implements ClipboardWriter {
@Override
public void run(int index, int byteValue) {
try {
System.out.println("Add " + (byteValue >> 8));
rawStream.writeByte(byteValue >> 8);
} catch (IOException e) {
e.printStackTrace();
@ -312,10 +310,10 @@ public class SchematicWriter implements ClipboardWriter {
MutableBlockVector mutable = new MutableBlockVector(0, 0, 0);
ForEach forEach = new ForEach(yarea, zwidth, blocks, blockData, tileEntities);
for (Vector point : region) {
mutable.mutX((point.getX() - mx));
mutable.mutY((point.getY() - my));
mutable.mutZ((point.getZ() - mz));
forEach.run(mutable, clipboard.getBlock(point));
int x = (point.getBlockX() - mx);
int y = (point.getBlockY() - my);
int z = (point.getBlockZ() - mz);
forEach.run(x, y, z, clipboard.getBlock(point));
}
addBlocks = forEach.addBlocks;
}