WIP on 1.13 CFI

This commit is contained in:
Jesse Boyd 2019-04-10 18:32:21 +10:00
parent 435a8ad6f2
commit 31797d4231
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
9 changed files with 895 additions and 447 deletions

View File

@ -293,11 +293,6 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
return result;
}
@Override
public IntFaweChunk getPrevious(IntFaweChunk fs, CHUNKSECTIONS sections, Map<?, ?> tiles, Collection<?>[] entities, Set<UUID> createdEntities, boolean all) throws Exception {
return fs;
}
@Override
public boolean hasSky() {
World world = getWorld();

View File

@ -349,8 +349,6 @@ public class BukkitQueue_All extends BukkitQueue_0<ChunkSnapshot, ChunkSnapshot,
return super.supports(capability);
}
private int skip;
@Override
public void startSet(boolean parallel) {
super.startSet(true);

View File

@ -222,6 +222,4 @@ public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> ex
public abstract void setBlockLight(SECTION section, int x, int y, int z, int value);
public abstract void refreshChunk(FaweChunk fs);
public abstract IntFaweChunk getPrevious(IntFaweChunk fs, CHUNKSECTION sections, Map<?, ?> tiles, Collection<?>[] entities, Set<UUID> createdEntities, boolean all) throws Exception;
}

View File

@ -0,0 +1,163 @@
package com.boydti.fawe.jnbt.anvil;
public final class BitArray4096 {
private final int bitsPerEntry;
private final int maxSeqLocIndex;
private final int maxEntryValue;
private final long[] data;
private final int longLen;
public BitArray4096(long[] buffer, int bitsPerEntry) {
this.bitsPerEntry = bitsPerEntry;
this.maxSeqLocIndex = 64 - bitsPerEntry;
maxEntryValue = (1 << bitsPerEntry) - 1;
this.longLen = (this.bitsPerEntry * 4096) >> 6;
if (buffer.length < longLen) {
System.out.println("Invalid buffer " + buffer.length + " | " + longLen);
this.data = new long[longLen];
} else {
this.data = buffer;
}
}
public BitArray4096(int bitsPerEntry) {
this.bitsPerEntry = bitsPerEntry;
this.maxSeqLocIndex = 64 - bitsPerEntry;
maxEntryValue = (1 << bitsPerEntry) - 1;
this.longLen = (this.bitsPerEntry * 4096) >> 6;
this.data = new long[longLen];
}
public final void setAt(int index, int value) {
if (longLen == 0) return;
int bitIndexStart = index * bitsPerEntry;
int longIndexStart = bitIndexStart >> 6;
int localBitIndexStart = bitIndexStart & 63;
this.data[longIndexStart] = this.data[longIndexStart] & ~((long) maxEntryValue << localBitIndexStart) | ((long) value) << localBitIndexStart;
if(localBitIndexStart > maxSeqLocIndex) {
int longIndexEnd = longIndexStart + 1;
int localShiftStart = 64 - localBitIndexStart;
int localShiftEnd = bitsPerEntry - localShiftStart;
this.data[longIndexEnd] = this.data[longIndexEnd] >>> localShiftEnd << localShiftEnd | (((long) value) >> localShiftStart);
}
}
public final int getAt(int index) {
if (longLen == 0) return 0;
int bitIndexStart = index * bitsPerEntry;
int longIndexStart = bitIndexStart >> 6;
int localBitIndexStart = bitIndexStart & 63;
if(localBitIndexStart <= maxSeqLocIndex) {
return (int)(this.data[longIndexStart] >>> localBitIndexStart & maxEntryValue);
} else {
int localShift = 64 - localBitIndexStart;
return (int) ((this.data[longIndexStart] >>> localBitIndexStart | this.data[longIndexStart + 1] << localShift) & maxEntryValue);
}
}
public int getLength() {
return longLen;
}
public final void fromRawSlow(char[] arr) {
for (int i = 0; i < arr.length; i++) {
setAt(i, arr[i]);
}
}
public final void fromRaw(int[] arr, int offset) {
final long[] data = this.data;
final int bitsPerEntry = this.bitsPerEntry;
final int maxEntryValue = this.maxEntryValue;
final int maxSeqLocIndex = this.maxSeqLocIndex;
int localStart = 0;
int lastVal;
int arrI = offset;
long l = 0;
long nextVal;
for (int i = 0; i < longLen; i++) {
for (; localStart <= maxSeqLocIndex; localStart += bitsPerEntry) {
lastVal = arr[arrI++];
l |= ((long) lastVal << localStart);
}
if (localStart < 64) {
if (i != longLen - 1) {
lastVal = arr[arrI++];
int shift = 64 - localStart;
nextVal = lastVal >> shift;
l |= ((lastVal - (nextVal << shift)) << localStart);
data[i] = l;
data[i + 1] = l = nextVal;
localStart -= maxSeqLocIndex;
}
} else {
localStart = 0;
data[i] = l;
l = 0;
}
}
}
public BitArray4096 growSlow(int bitsPerEntry) {
BitArray4096 newBitArray = new BitArray4096(bitsPerEntry);
for (int i = 0; i < 4096; i++) {
newBitArray.setAt(i, getAt(i));
}
return newBitArray;
}
public final char[] toRawSlow() {
char[] arr = new char[4096];
for (int i = 0; i < arr.length; i++) {
arr[i] = (char) getAt(i);
}
return arr;
}
public final char[] toRaw() {
return toRaw(new char[4096]);
}
protected final char[] toRaw(char[] buffer) {
final long[] data = this.data;
final int dataLength = longLen;
final int bitsPerEntry = this.bitsPerEntry;
final int maxEntryValue = this.maxEntryValue;
final int maxSeqLocIndex = this.maxSeqLocIndex;
int localStart = 0;
char lastVal;
int arrI = 0;
long l;
for (int i = 0; i < dataLength; i++) {
l = data[i];
for (; localStart <= maxSeqLocIndex; localStart += bitsPerEntry) {
lastVal = (char) (l >>> localStart & maxEntryValue);
buffer[arrI++] = lastVal;
}
if (localStart < 64) {
if (i != dataLength - 1) {
lastVal = (char) (l >>> localStart);
localStart -= maxSeqLocIndex;
l = data[i + 1];
int localShift = bitsPerEntry - localStart;
lastVal |= l << localShift;
lastVal &= maxEntryValue;
buffer[arrI++] = lastVal;
}
} else {
localStart = 0;
}
}
return buffer;
}
}

View File

@ -1,7 +1,11 @@
package com.boydti.fawe.jnbt.anvil;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.example.SimpleIntFaweChunk;
import com.boydti.fawe.jnbt.anvil.HeightMapMCADrawer;
import com.boydti.fawe.jnbt.anvil.MCAChunk;
import com.boydti.fawe.jnbt.anvil.MCAWriter;
import com.boydti.fawe.object.*;
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
import com.boydti.fawe.object.change.StreamChange;
@ -77,7 +81,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
protected boolean randomVariation = true;
protected int biomePriority = 0;
protected int waterId = BlockTypes.WATER.getInternalId();
protected int bedrockId = 7;
protected int bedrockId = BlockID.BEDROCK;
protected boolean modifiedMain = false;
@Override
@ -210,7 +214,6 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
public HeightMapMCAGenerator(int width, int length, File regionFolder) {
super(width, length, regionFolder);
int area = getArea();
blocks = new DifferentialBlockBuffer(width, length);
heights = new DifferentialArray(new byte[getArea()]);
@ -296,7 +299,6 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
int ecx = Math.min(lenCX - 1, pcx + 15);
int ecz = Math.min(lenCZ - 1, pcz + 15);
MCAChunk chunk = new MCAChunk(this, 0, 0);
for (int cz = scz; cz <= ecz; cz++) {
for (int cx = scx; cx <= ecx; cx++) {
final int finalCX = cx;
@ -517,7 +519,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
.nextInt(256) <= height) {
.nextInt(256) <= height) {
int newHeight = table.average(x, z, index);
setLayerHeightRaw(index, newHeight);
}
@ -767,16 +769,15 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
return getSnapshot(null, chunkX, chunkZ);
}
private FaweChunk getSnapshot(final MCAChunk chunk, int chunkX, int chunkZ) {
return new LazyFaweChunk<MCAChunk>(this, chunkX, chunkZ) {
private FaweChunk getSnapshot(final WritableMCAChunk chunk, int chunkX, int chunkZ) {
return new LazyFaweChunk<WritableMCAChunk>(this, chunkX, chunkZ) {
@Override
public MCAChunk getChunk() {
MCAChunk tmp = chunk;
public WritableMCAChunk getChunk() {
WritableMCAChunk tmp = chunk;
if (tmp == null) {
tmp = new MCAChunk(HeightMapMCAGenerator.this, chunkX, chunkZ);
} else {
tmp.setLoc(HeightMapMCAGenerator.this, chunkX, chunkZ);
tmp = new WritableMCAChunk();
}
tmp.setLoc(HeightMapMCAGenerator.this, chunkX, chunkZ);
int cbx = chunkX << 4;
int cbz = chunkZ << 4;
int csx = Math.max(0, cbx);
@ -790,7 +791,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
@Override
public void addToQueue() {
MCAChunk cached = getCachedChunk();
WritableMCAChunk cached = getCachedChunk();
if (cached != null) setChunk(cached);
}
};
@ -1091,7 +1092,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
.nextInt(256) <= height) {
.nextInt(256) <= height) {
biomeArr[index] = biomeByte;
}
}
@ -1143,7 +1144,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
if (imgMask != null) {
int height = imgMask.getRGB(x, z) & 0xFF;
if (height != 255 && (height <= 0 || !whiteOnly || ThreadLocalRandom
.current().nextInt(256) > height)) continue;
.current().nextInt(256) > height)) continue;
}
int color = img.getRGB(x, z);
if (textureUtil.getIsBlockCloserThanBiome(buffer, color, primtives.biomePriority)) {
@ -1228,7 +1229,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
for (int x = 0; x < getWidth(); x++, index++) {
int height = mask.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
.nextInt(256) <= height) {
.nextInt(256) <= height) {
int color = img.getRGB(x, z);
BlockType block = textureUtil.getNearestBlock(color);
if (block != null) {
@ -1347,7 +1348,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
if (pattern instanceof BlockStateHolder) {
setOverlay(img, ((BlockStateHolder) pattern).getInternalId(), white);
} else if (pattern instanceof BlockType) {
setOverlay(img, ((BlockType) pattern).getInternalId(), white);
setOverlay(img, ((BlockType) pattern).getInternalId(), white);
} else {
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
@ -1363,7 +1364,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
.nextInt(256) <= height) {
.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
overlayArr[index] = pattern.apply(mutable).getInternalId();
@ -1391,7 +1392,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
.nextInt(256) <= height) {
.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
mainArr[index] = pattern.apply(mutable).getInternalId();
@ -1417,7 +1418,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
.nextInt(256) <= height) {
.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
floorArr[index] = pattern.apply(mutable).getInternalId();
@ -1445,7 +1446,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
.nextInt(256) <= height) {
.nextInt(256) <= height) {
mutable.mutX(x);
mutable.mutY(height);
int combined = pattern.apply(mutable).getInternalId();
@ -1649,328 +1650,159 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
}
@Override
public MCAChunk write(MCAChunk chunk, int csx, int cex, int csz, int cez) {
// TODO FIXME
// byte[] heights = this.heights.get();
// byte[] biomes = this.biomes.get();
// int[] main = this.main.get();
// int[] floor = this.floor.get();
// int[] overlay = this.overlay != null ? this.overlay.get() : null;
// try {
// 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);
// }
// }
// int index;
// 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;
// index = (z & 15) << 4;
// 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);
// }
// }
// boolean hasOverlay = this.overlay != null;
// 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 (primtives.waterHeight != 0) {
// maxY = Math.max(maxY, primtives.waterHeight);
// int maxWaterLayer = ((primtives.waterHeight + 15) >> 4);
// for (int layer = 0; layer < maxWaterLayer; layer++) {
// boolean fillAll = (layer << 4) + 15 <= primtives.waterHeight;
// byte[] ids = chunk.ids[layer];
// if (ids == null) {
// chunk.ids[layer] = ids = new byte[4096];
// chunk.data[layer] = new byte[2048];
// chunk.skyLight[layer] = new byte[2048];
// chunk.blockLight[layer] = new byte[2048];
// Arrays.fill(chunk.skyLight[layer], (byte) 255);
// }
// if (fillAll) {
// Arrays.fill(ids, primtives.waterId);
// } else {
// int maxIndex = (primtives.waterHeight & 15) << 8;
// Arrays.fill(ids, 0, maxIndex, primtives.waterId);
// }
// }
// }
//
// if (primtives.modifiedMain) { // If the main block is modified, we can't short circuit this
// for (int layer = 0; layer < fillLayers; layer++) {
// byte[] layerIds = chunk.ids[layer];
// byte[] layerDatas = chunk.data[layer];
// for (int z = csz; z <= cez; z++) {
// index = (z & 15) << 4;
// 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];
// int startY = layer << 4;
// int endY = startY + 15;
// for (int z = csz; z <= cez; z++) {
// index = (z & 15) << 4;
// 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;
// }
//
// if (primtives.bedrockId != 0) { // Bedrock
// byte[] layerIds = chunk.ids[0];
// for (int z = csz; z <= cez; z++) {
// index = (z & 15) << 4;
// for (int x = csx; x <= cex; x++) {
// layerIds[index++] = primtives.bedrockId;
// }
// }
// }
//
// char[][][] localBlocks = getChunkArray(chunk.getX(), chunk.getZ());
// 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];
// Arrays.fill(chunk.skyLight[layer], (byte) 255);
// }
// 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);
// int data = FaweCache.getData(combined);
// if (data == 0) {
// chunk.setIdUnsafe(idsLayer, zIndex, (byte) id);
// } else {
// chunk.setBlockUnsafe(idsLayer, dataLayer, zIndex, (byte) id, FaweCache.getData(combined));
// }
// }
// }
// }
// }
// }
// }
// }
//
// if (primtives.floorThickness != 0 || primtives.worldThickness != 0) {
// // Use biomes array as temporary buffer
// byte[] minArr = chunk.biomes;
// for (int z = csz; z <= cez; z++) {
// index = (z & 15) << 4;
// for (int x = csx; x <= cex; x++, index++) {
// int gi = indexes[index];
// int height = heightMap[index];
// int min = height;
// if (x > 0) min = Math.min(heights[gi - 1] & 0xFF, min);
// if (x < getWidth() - 1) min = Math.min(heights[gi + 1] & 0xFF, min);
// if (z > 0) min = Math.min(heights[gi - getWidth()] & 0xFF, min);
// if (z < getLength() - 1) min = Math.min(heights[gi + getWidth()] & 0xFF, min);
// minArr[index] = (byte) min;
// }
// }
//
// int minLayer = Math.max(0, (minY - primtives.floorThickness) >> 4);
//
// if (primtives.floorThickness != 0) {
// for (int layer = minLayer; layer <= maxLayer; layer++) {
// byte[] layerIds = chunk.ids[layer];
// byte[] layerDatas = chunk.data[layer];
// int startY = layer << 4;
// int endY = startY + 15;
// for (int z = csz; z <= cez; z++) {
// index = (z & 15) << 4;
// for (int x = csx; x <= cex; x++, index++) {
// globalIndex = indexes[index];
// int height = heightMap[index];
//
// int min = (minArr[index] & 0xFF) - primtives.floorThickness;
// int localMin = min - startY;
//
// int max = height + 1;
// if (min < startY) min = startY;
// if (max > endY) max = endY + 1;
//
//
// if (min < max) {
// char floorCombined = floor[globalIndex];
// final byte id = (byte) FaweCache.getId(floorCombined);
// final int data = FaweCache.getData(floorCombined);
// for (int y = min; y < max; y++) {
// int floorIndex = index + ((y & 15) << 8);
// layerIds[floorIndex] = id;
// if (data != 0) {
// chunk.setNibble(floorIndex, layerDatas, data);
// }
// }
// }
//
// }
// }
// }
// }
// if (primtives.worldThickness != 0) {
// for (int layer = 0; layer < minLayer; layer++) {
// chunk.ids[layer] = null;
// chunk.data[layer] = null;
// }
// for (int layer = minLayer; layer <= maxLayer; layer++) {
// byte[] layerIds = chunk.ids[layer];
// byte[] layerDatas = chunk.data[layer];
// int startY = layer << 4;
// int endY = startY + 15;
// for (int z = csz; z <= cez; z++) {
// index = (z & 15) << 4;
// for (int x = csx; x <= cex; x++, index++) {
// globalIndex = indexes[index];
// int height = heightMap[index];
//
// int min = (minArr[index] & 0xFF) - primtives.worldThickness;
// int localMin = min - startY;
// if (localMin > 0) {
// char floorCombined = floor[globalIndex];
// final byte id = (byte) FaweCache.getId(floorCombined);
// final int data = FaweCache.getData(floorCombined);
//
// for (int y = 0; y < localMin; y++) {
// int floorIndex = index + ((y & 15) << 8);
// layerIds[floorIndex] = 0;
// if (data != 0) {
// chunk.setNibble(floorIndex, layerDatas, 0);
// }
// }
// }
// }
// }
// }
// }
//
// for (int layer = fillLayers; layer <= maxLayer; layer++) {
// Arrays.fill(chunk.skyLight[layer], (byte) 255);
//
// }
// }
//
// for (int i = 0; i < 256; i++) {
// chunk.biomes[i] = biomes[indexes[i]];
// }
//
//
// } catch (Throwable e) {
// e.printStackTrace();
// }
public WritableMCAChunk write(WritableMCAChunk chunk, int csx, int cex, int csz, int cez) {
byte[] heights = this.heights.get();
byte[] biomes = this.biomes.get();
int[] main = this.main.get();
int[] floor = this.floor.get();
int[] overlay = this.overlay != null ? this.overlay.get() : null;
try {
int[] indexes = indexStore.get();
int index;
int maxY = 0;
int minY = Integer.MAX_VALUE;
int[] heightMap = chunk.biomes;
int globalIndex;
for (int z = csz; z <= cez; z++) {
globalIndex = z * getWidth() + csx;
index = (z & 15) << 4;
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);
}
}
boolean hasOverlay = this.overlay != null;
if (hasOverlay) {
maxY++;
}
int maxLayer = maxY >> 4;
for (int layer = 0; layer <= maxLayer; layer++) {
chunk.hasSections[layer] = true;
}
if (primtives.waterHeight != 0) {
maxY = Math.max(maxY, primtives.waterHeight);
int maxIndex = (primtives.waterHeight) << 8;
Arrays.fill(chunk.blocks, 0, maxIndex, primtives.waterId);
}
if (primtives.modifiedMain) { // If the main block is modified, we can't short circuit this
for (int z = csz; z <= cez; z++) {
index = (z & 15) << 4;
for (int x = csx; x <= cex; x++, index++) {
globalIndex = indexes[index];
int mainCombined = main[globalIndex];
for (int y = 0; y < minY; y++) {
chunk.blocks[index + (y << 8)] = mainCombined;
}
}
}
} else {
int maxIndex = minY << 8;
Arrays.fill(chunk.blocks, 0, maxIndex, BlockID.STONE);
}
final boolean hasFloorThickness = primtives.floorThickness != 0 || primtives.worldThickness != 0;
if (primtives.worldThickness != 0) {
int endLayer = ((minY - primtives.worldThickness + 1) >> 4);
for (int layer = 0; layer < endLayer; layer++) {
chunk.hasSections[layer] = false;
}
}
for (int z = csz; z <= cez; z++) {
index = (z & 15) << 4;
for (int x = csx; x <= cex; x++, index++) {
globalIndex = indexes[index];
int height = heightMap[index];
int maxMainY = height;
int minMainY = minY;
int mainCombined = main[globalIndex];
int floorCombined = floor[globalIndex];
if (hasFloorThickness) {
if (x > 0) maxMainY = Math.min(heights[globalIndex - 1] & 0xFF, maxMainY);
if (x < getWidth() - 1) maxMainY = Math.min(heights[globalIndex + 1] & 0xFF, maxMainY);
if (z > 0) maxMainY = Math.min(heights[globalIndex - getWidth()] & 0xFF, maxMainY);
if (z < getLength() - 1) maxMainY = Math.min(heights[globalIndex + getWidth()] & 0xFF, maxMainY);
int min = maxMainY;
if (primtives.floorThickness != 0) {
maxMainY = Math.max(0, maxMainY - (primtives.floorThickness - 1));
for (int y = maxMainY; y <= height; y++) {
chunk.blocks[index + (y << 8)] = floorCombined;
}
}
else {
chunk.blocks[index + ((height) << 8)] = floorCombined;
}
if (primtives.worldThickness != 0) {
minMainY = Math.max(minY, min - primtives.worldThickness + 1);
for (int y = minY; y < minMainY; y++) {
chunk.blocks[index + (y << 8)] = BlockID.AIR;
}
}
} else {
chunk.blocks[index + ((height) << 8)] = floorCombined;
}
for (int y = minMainY; y < maxMainY; y++) {
chunk.blocks[index + (y << 8)] = mainCombined;
}
if (hasOverlay) {
int overlayCombined = overlay[globalIndex];
int overlayIndex = index + ((height + 1) << 8);
chunk.blocks[overlayIndex] = overlayCombined;
}
if (primtives.bedrockId != 0) {
chunk.blocks[index] = primtives.bedrockId;
}
}
}
int[][][] localBlocks = getChunkArray(chunk.getX(), chunk.getZ());
if (localBlocks != null) {
index = 0;
for (int layer = 0; layer < 16; layer++) {
int by = layer << 4;
int ty = by + 15;
for (int y = by; y <= ty; y++, index += 256) {
int[][] yBlocks = localBlocks[y];
if (yBlocks != null) {
chunk.hasSections[layer] = true;
for (int z = 0; z < yBlocks.length; z++) {
int[] zBlocks = yBlocks[z];
if (zBlocks != null) {
int zIndex = index + (z << 4);
for (int x = 0; x < zBlocks.length; x++, zIndex++) {
int combined = zBlocks[x];
if (combined == 0) continue;
chunk.blocks[zIndex] = combined;
}
}
}
}
}
}
}
for (int i = 0; i < 256; i++) {
chunk.biomes[i] = biomes[indexes[i]];
}
} catch (Throwable e) {
e.printStackTrace();
}
return chunk;
}
@ -2092,7 +1924,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && white && ThreadLocalRandom.current()
.nextInt(256) <= height) {
.nextInt(256) <= height) {
overlay.get()[index] = combined;
}
}
@ -2111,7 +1943,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
.nextInt(256) <= height) {
.nextInt(256) <= height) {
main.get()[index] = combined;
}
}
@ -2129,7 +1961,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
.nextInt(256) <= height) {
.nextInt(256) <= height) {
floor.get()[index] = combined;
}
}
@ -2148,7 +1980,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && ThreadLocalRandom.current()
.nextInt(256) <= height) {
.nextInt(256) <= height) {
main.get()[index] = combined;
floor.get()[index] = combined;
}
@ -2286,27 +2118,27 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
return false;
}
@Override
public void dropItem(Vector3 position, BaseItemStack item) {
// TODO Auto-generated method stub
}
@Override
public void dropItem(Vector3 position, BaseItemStack item) {
// TODO Auto-generated method stub
@Override
public boolean playEffect(Vector3 position, int type, int data) {
// TODO Auto-generated method stub
return false;
}
}
@Override
public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean playEffect(Vector3 position, int type, int data) {
// TODO Auto-generated method stub
return false;
}
@Override
public BlockVector3 getSpawnPosition() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException {
// TODO Auto-generated method stub
return false;
}
@Override
public BlockVector3 getSpawnPosition() {
// TODO Auto-generated method stub
return null;
}
}

View File

@ -3,8 +3,10 @@ package com.boydti.fawe.jnbt.anvil;
import com.boydti.fawe.object.collection.IterableThreadLocal;
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
import com.boydti.fawe.util.MainUtil;
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;
@ -67,22 +69,20 @@ public abstract class MCAWriter {
public abstract boolean shouldWrite(int chunkX, int chunkZ);
public abstract MCAChunk write(MCAChunk input, int startX, int endX, int startZ, int endZ);
public abstract WritableMCAChunk write(WritableMCAChunk input, int startX, int endX, int startZ, int endZ);
public void generate() throws IOException {
if (!folder.exists()) {
folder.mkdirs();
}
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>() {
final ThreadLocal<WritableMCAChunk> chunkStore = new ThreadLocal<WritableMCAChunk>() {
@Override
protected MCAChunk initialValue() {
MCAChunk chunk = new MCAChunk(null, 0, 0);
chunk.biomes = new byte[256];
protected WritableMCAChunk initialValue() {
WritableMCAChunk chunk = new WritableMCAChunk();
Arrays.fill(chunk.skyLight, (byte) 255);
return chunk;
}
};
@ -111,16 +111,15 @@ public abstract class MCAWriter {
int mcaXMax = mcaXMin + ((width - 1) >> 9);
int mcaZMax = mcaZMin + ((length - 1) >> 9);
final byte[] header = new byte[4096];
for (int mcaZ = mcaXMin; mcaZ <= mcaZMax; mcaZ++) {
for (int mcaX = mcaXMin; mcaX <= mcaXMax; mcaX++) {
final int fmcaX = mcaX;
final int fmcaZ = mcaZ;
File file = new File(folder, "r." + (mcaX + (getOffsetX() >> 9)) + "." + (mcaZ + (getOffsetZ() >> 9)) + ".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;
@ -137,76 +136,70 @@ public abstract class MCAWriter {
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) {
// Generation offset
chunk.setLoc(null, fcx + (getOffsetX() >> 4), fcz + (getOffsetZ() >> 4));
// Compress
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.submit(() -> {
try {
WritableMCAChunk chunk = chunkStore.get();
chunk.clear(fcx, fcz);
chunk = write(chunk, csx, cex, csz, cez);
if (chunk != null) {
// Generation offset
chunk.setLoc( fcx + (getOffsetX() >> 4), fcz + (getOffsetZ() >> 4));
// Compress
byte[] bytes = chunk.toBytes(byteStore1.get());
byte[] compressedBytes = MainUtil.compress(bytes, byteStore2.get(), deflateStore.get());
// TODO optimize (avoid cloning) by add a synchronized block and write to the RAF here instead of below
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() {
pool.submit(() -> {
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
raf.seek(offset);
raf.writeInt(compressedBytes.length + 1);
raf.write(2);
raf.write(compressedBytes);
offset += blocks * 4096;
}
}
raf.seek(0);
raf.write(header);
} catch (IOException e) {
e.printStackTrace();
} finally {
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 + 1);
raf.write(2);
raf.write(compressedBytes);
offset += blocks * 4096;
}
}
raf.seek(0);
raf.write(header);
raf.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});

View File

@ -0,0 +1,398 @@
package com.boydti.fawe.jnbt.anvil;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.boydti.fawe.util.MathMan;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.NBTConstants;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
public class WritableMCAChunk extends FaweChunk<Void> {
public final boolean[] hasSections = new boolean[16];
public final byte[] skyLight = new byte[65536];
public final byte[] blockLight = new byte[65536];
public boolean hasBiomes = false;
public final int[] biomes = new int[256];
public final int[] blocks = new int[65536];
public Map<Short, CompoundTag> tiles = new HashMap<>();
public Map<UUID, CompoundTag> entities = new HashMap<>();
public long inhabitedTime = System.currentTimeMillis();
public long lastUpdate;
public int modified;
public boolean deleted;
public int chunkX, chunkZ;
protected WritableMCAChunk() {
super(null, 0, 0);
}
public int getX() {
return chunkX;
}
public int getZ() {
return chunkZ;
}
public void setLoc(int X, int Z) {
this.chunkX = X;
this.chunkZ = Z;
}
public void clear(int X, int Z) {
this.chunkX = X;
this.chunkZ = Z;
if (!tiles.isEmpty()) {
tiles.clear();
}
if (!entities.isEmpty()) {
entities.clear();
}
modified = 0;
deleted = false;
hasBiomes = false;
Arrays.fill(hasSections, false);
}
private transient final int[] blockToPalette = new int[BlockTypes.states.length];
private transient final boolean[] hasBlock = new boolean[BlockTypes.states.length];
private transient final int[] paletteToBlock = new int[Character.MAX_VALUE];
private transient final long[] blockstates = new long[2048];
public void write(NBTOutputStream nbtOut) throws IOException {
nbtOut.writeNamedTagName("", NBTConstants.TYPE_COMPOUND);
nbtOut.writeLazyCompoundTag("Level", out -> {
out.writeNamedTag("V", (byte) 1);
out.writeNamedTag("xPos", getX());
out.writeNamedTag("zPos", getZ());
out.writeNamedTag("LightPopulated", (byte) 0);
out.writeNamedTag("TerrainPopulated", (byte) 1);
if (entities.isEmpty()) {
out.writeNamedEmptyList("Entities");
} else {
out.writeNamedTag("Entities", new ListTag(CompoundTag.class, new ArrayList<>(entities.values())));
}
if (tiles.isEmpty()) {
out.writeNamedEmptyList("TileEntities");
} else {
out.writeNamedTag("TileEntities", new ListTag(CompoundTag.class,
new ArrayList<>(tiles.values())));
}
out.writeNamedTag("InhabitedTime", inhabitedTime);
out.writeNamedTag("LastUpdate", lastUpdate);
if (biomes != null) {
out.writeNamedTag("Biomes", biomes);
}
out.writeNamedTagName("Sections", NBTConstants.TYPE_LIST);
nbtOut.writeByte(NBTConstants.TYPE_COMPOUND);
int len = 0;
for (int layer = 0; layer < hasSections.length; layer++) {
if (hasSections[layer]) len++;
}
nbtOut.writeInt(len);
for (int layer = 0; layer < hasSections.length; layer++) {
if (hasSections[layer]) {
continue;
}
out.writeNamedTag("Y", (byte) layer);
out.writeNamedTagName("BlockLight", NBTConstants.TYPE_BYTE_ARRAY);
out.writeInt(2048);
out.write(blockLight, layer << 11, 1 << 11);
out.writeNamedTagName("SkyLight", NBTConstants.TYPE_BYTE_ARRAY);
out.writeInt(2048);
out.write(skyLight, layer << 11, 1 << 11);
int blockIndexStart = layer << 8;
int blockIndexEnd = blockIndexStart << 1;
int num_palette = 0;
try {
out.writeNamedTagName("Palette", NBTConstants.TYPE_LIST);
out.writeByte(NBTConstants.TYPE_COMPOUND);
out.writeInt(num_palette);
for (int i = blockIndexStart; i < blockIndexEnd; i++) {
int stateId = blocks[i];
if (!hasBlock[stateId]) {
hasBlock[stateId] = true;
blockToPalette[stateId] = num_palette;
paletteToBlock[num_palette++] = stateId;
BlockState state = BlockTypes.states[stateId];
BlockType type = state.getBlockType();
out.writeNamedTag("Name", type.getId());
// Properties
if (type.getDefaultState() == state) continue;
out.writeNamedTagName("Properties", NBTConstants.TYPE_COMPOUND);
for (Property<?> property : type.getProperties()) {
String key = property.getName();
Object value = state.getState(property);
String valueStr = value.toString();
if (Character.isUpperCase(valueStr.charAt(0))) {
System.out.println("Invalid uppercase value " + value);
valueStr = valueStr.toLowerCase();
}
out.writeNamedTag(key, valueStr);
}
out.writeByte(NBTConstants.TYPE_END);
}
}
// BlockStates
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6;
if (num_palette == 1) {
Arrays.fill(blockstates, 0, blockBitArrayEnd, 0);
}
BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry);
bitArray.fromRaw(blocks, blockIndexStart);
out.writeNamedTagName("BlockStates", NBTConstants.TYPE_LONG_ARRAY);
out.writeInt(blockBitArrayEnd);
for (int i = 0; i < blockBitArrayEnd; i++) out.writeLong(blockstates[i]);
out.writeEndTag();
// cleanup
} catch (Throwable e) {
for (int i = 0; i < num_palette; i++) {
hasBlock[i] = false;
}
throw e;
}
}
});
nbtOut.writeEndTag();
}
public byte[] toBytes(byte[] buffer) throws IOException {
if (buffer == null) {
buffer = new byte[8192];
}
FastByteArrayOutputStream buffered = new FastByteArrayOutputStream(buffer);
DataOutputStream dataOut = new DataOutputStream(buffered);
try (NBTOutputStream nbtOut = new NBTOutputStream((DataOutput) dataOut)) {
write(nbtOut);
}
return buffered.toByteArray();
}
public long getInhabitedTime() {
return inhabitedTime;
}
public long getLastUpdate() {
return lastUpdate;
}
public void setInhabitedTime(long inhabitedTime) {
this.inhabitedTime = inhabitedTime;
}
public void setLastUpdate(long lastUpdate) {
this.lastUpdate = lastUpdate;
}
public void setDeleted(boolean deleted) {
setModified();
this.deleted = deleted;
}
public boolean isDeleted() {
return deleted;
}
public boolean isModified() {
return modified != 0;
}
public int getModified() {
return modified;
}
public final void setModified() {
this.modified++;
}
public int getBitMask() {
int bitMask = 0;
for (int section = 0; section < hasSections.length; section++) {
if (hasSections[section]) {
bitMask += 1 << section;
}
}
return bitMask;
}
public void setTile(int x, int y, int z, CompoundTag tile) {
setModified();
short pair = MathMan.tripleBlockCoord(x, y, z);
if (tile != null) {
tiles.put(pair, tile);
} else {
tiles.remove(pair);
}
}
public void setEntity(CompoundTag entityTag) {
setModified();
long least = entityTag.getLong("UUIDLeast");
long most = entityTag.getLong("UUIDMost");
entities.put(new UUID(most, least), entityTag);
}
public void setBiome(int x, int z, BiomeType biome) {
setModified();
biomes[x + (z << 4)] = biome.getInternalId();
}
public Set<CompoundTag> getEntities() {
return new HashSet<>(entities.values());
}
public Map<Short, CompoundTag> getTiles() {
return tiles == null ? new HashMap<>() : tiles;
}
public CompoundTag getTile(int x, int y, int z) {
if (tiles == null || tiles.isEmpty()) {
return null;
}
short pair = MathMan.tripleBlockCoord(x, y, z);
return tiles.get(pair);
}
public boolean doesSectionExist(int cy) {
return hasSections[cy];
}
private final int getIndex(int x, int y, int z) {
return x | (z << 4) | (y << 8);
}
public int getBlockCombinedId(int x, int y, int z) {
return blocks[x | (z << 4) | (y << 8)];
}
public BiomeType[] getBiomeArray() {
return null;
}
public Set<UUID> getEntityRemoves() {
return new HashSet<>();
}
public void setSkyLight(int x, int y, int z, int value) {
setNibble(getIndex(x, y, z), skyLight, value);
}
public void setBlockLight(int x, int y, int z, int value) {
setNibble(getIndex(x, y, z), blockLight, value);
}
public int getSkyLight(int x, int y, int z) {
if (!hasSections[y >> 4]) return 0;
return getNibble(getIndex(x, y, z), skyLight);
}
public int getBlockLight(int x, int y, int z) {
if (!hasSections[y >> 4]) return 0;
return getNibble(getIndex(x, y, z), blockLight);
}
public void setFullbright() {
for (int layer = 0; layer < 16; layer++) {
if (hasSections[layer]) {
Arrays.fill(skyLight, layer << 7, ((layer + 1) << 7), (byte) 255);
}
}
}
public void removeLight() {
for (int i = 0; i < skyLight.length; i++) {
removeLight(i);
}
}
public void removeLight(int i) {
if (hasSections[i]) {
Arrays.fill(skyLight, i << 7, ((i + 1) << 7), (byte) 0);
Arrays.fill(blockLight, i << 7, ((i + 1) << 7), (byte) 0);
}
}
public int getNibble(int index, byte[] array) {
int indexShift = index >> 1;
if ((index & 1) == 0) {
return array[indexShift] & 15;
} else {
return array[indexShift] >> 4 & 15;
}
}
public void setNibble(int index, byte[] array, int value) {
int indexShift = index >> 1;
byte existing = array[indexShift];
int valueShift = value << 4;
if (existing == value + valueShift) {
return;
}
if ((index & 1) == 0) {
array[indexShift] = (byte) (existing & 240 | value);
} else {
array[indexShift] = (byte) (existing & 15 | valueShift);
}
}
public void setBlock(int x, int y, int z, int combinedId) {
blocks[getIndex(x, y, z)] = combinedId;
}
public void setBiome(BiomeType biome) {
Arrays.fill(biomes, (byte) biome.getInternalId());
}
@Override
public FaweChunk<Void> copy(boolean shallow) {
throw new UnsupportedOperationException("Unsupported");
}
public void removeEntity(UUID uuid) {
entities.remove(uuid);
}
public Void getChunk() {
throw new UnsupportedOperationException("Not applicable for this");
}
public FaweChunk call() {
throw new UnsupportedOperationException("Not supported");
}
}

View File

@ -39,7 +39,7 @@ import java.util.Map;
* found at <a href="http://www.minecraft.net/docs/NBT.txt">
* http://www.minecraft.net/docs/NBT.txt</a>.</p>
*/
public final class NBTOutputStream implements Closeable {
public final class NBTOutputStream extends OutputStream implements Closeable, DataOutput {
/**
* The output stream.
@ -426,11 +426,82 @@ public final class NBTOutputStream implements Closeable {
if (os instanceof Closeable) ((Closeable) os).close();
}
@Override
public void write(int b) throws IOException {
os.write(b);
}
@Override
public void write(byte[] b) throws IOException {
os.write(b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
os.write(b, off, len);
}
@Override
public void writeBoolean(boolean v) throws IOException {
os.writeBoolean(v);
}
@Override
public void writeByte(int v) throws IOException {
os.writeByte(v);
}
@Override
public void writeShort(int v) throws IOException {
os.writeShort(v);
}
@Override
public void writeChar(int v) throws IOException {
os.writeChar(v);
}
@Override
public void writeInt(int v) throws IOException {
os.writeInt(v);
}
@Override
public void writeLong(long v) throws IOException {
os.writeLong(v);
}
@Override
public void writeFloat(float v) throws IOException {
os.writeFloat(v);
}
@Override
public void writeDouble(double v) throws IOException {
os.writeDouble(v);
}
@Override
public void writeBytes(String s) throws IOException {
os.writeBytes(s);
}
@Override
public void writeChars(String s) throws IOException {
os.writeChars(s);
}
@Override
public void writeUTF(String s) throws IOException {
os.writeUTF(s);
}
/**
* Flush output.
*
* @throws IOException
*/
@Override
public void flush() throws IOException {
if (os instanceof Flushable) ((Flushable) os).flush();
}

View File

@ -974,7 +974,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
BBC.WORLDEDIT_SOME_FAILS_BLOCKBAG.send(player, str.toString());
}
}
return new HashMap<>();
return Collections.emptyMap();
}
/**