geforkt von Mirrors/FastAsyncWorldEdit
WIP on 1.13 CFI
Dieser Commit ist enthalten in:
Ursprung
435a8ad6f2
Commit
31797d4231
@ -293,11 +293,6 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public IntFaweChunk getPrevious(IntFaweChunk fs, CHUNKSECTIONS sections, Map<?, ?> tiles, Collection<?>[] entities, Set<UUID> createdEntities, boolean all) throws Exception {
|
|
||||||
return fs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasSky() {
|
public boolean hasSky() {
|
||||||
World world = getWorld();
|
World world = getWorld();
|
||||||
|
@ -349,8 +349,6 @@ public class BukkitQueue_All extends BukkitQueue_0<ChunkSnapshot, ChunkSnapshot,
|
|||||||
return super.supports(capability);
|
return super.supports(capability);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int skip;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startSet(boolean parallel) {
|
public void startSet(boolean parallel) {
|
||||||
super.startSet(true);
|
super.startSet(true);
|
||||||
|
@ -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 setBlockLight(SECTION section, int x, int y, int z, int value);
|
||||||
|
|
||||||
public abstract void refreshChunk(FaweChunk fs);
|
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;
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,11 @@
|
|||||||
package com.boydti.fawe.jnbt.anvil;
|
package com.boydti.fawe.jnbt.anvil;
|
||||||
|
|
||||||
import com.boydti.fawe.Fawe;
|
import com.boydti.fawe.Fawe;
|
||||||
|
import com.boydti.fawe.FaweCache;
|
||||||
import com.boydti.fawe.example.SimpleIntFaweChunk;
|
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.*;
|
||||||
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
|
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
|
||||||
import com.boydti.fawe.object.change.StreamChange;
|
import com.boydti.fawe.object.change.StreamChange;
|
||||||
@ -77,7 +81,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
|
|||||||
protected boolean randomVariation = true;
|
protected boolean randomVariation = true;
|
||||||
protected int biomePriority = 0;
|
protected int biomePriority = 0;
|
||||||
protected int waterId = BlockTypes.WATER.getInternalId();
|
protected int waterId = BlockTypes.WATER.getInternalId();
|
||||||
protected int bedrockId = 7;
|
protected int bedrockId = BlockID.BEDROCK;
|
||||||
protected boolean modifiedMain = false;
|
protected boolean modifiedMain = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -210,7 +214,6 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
|
|||||||
|
|
||||||
public HeightMapMCAGenerator(int width, int length, File regionFolder) {
|
public HeightMapMCAGenerator(int width, int length, File regionFolder) {
|
||||||
super(width, length, regionFolder);
|
super(width, length, regionFolder);
|
||||||
int area = getArea();
|
|
||||||
|
|
||||||
blocks = new DifferentialBlockBuffer(width, length);
|
blocks = new DifferentialBlockBuffer(width, length);
|
||||||
heights = new DifferentialArray(new byte[getArea()]);
|
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 ecx = Math.min(lenCX - 1, pcx + 15);
|
||||||
int ecz = Math.min(lenCZ - 1, pcz + 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 cz = scz; cz <= ecz; cz++) {
|
||||||
for (int cx = scx; cx <= ecx; cx++) {
|
for (int cx = scx; cx <= ecx; cx++) {
|
||||||
final int finalCX = cx;
|
final int finalCX = cx;
|
||||||
@ -767,16 +769,15 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
|
|||||||
return getSnapshot(null, chunkX, chunkZ);
|
return getSnapshot(null, chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
private FaweChunk getSnapshot(final MCAChunk chunk, int chunkX, int chunkZ) {
|
private FaweChunk getSnapshot(final WritableMCAChunk chunk, int chunkX, int chunkZ) {
|
||||||
return new LazyFaweChunk<MCAChunk>(this, chunkX, chunkZ) {
|
return new LazyFaweChunk<WritableMCAChunk>(this, chunkX, chunkZ) {
|
||||||
@Override
|
@Override
|
||||||
public MCAChunk getChunk() {
|
public WritableMCAChunk getChunk() {
|
||||||
MCAChunk tmp = chunk;
|
WritableMCAChunk tmp = chunk;
|
||||||
if (tmp == null) {
|
if (tmp == null) {
|
||||||
tmp = new MCAChunk(HeightMapMCAGenerator.this, chunkX, chunkZ);
|
tmp = new WritableMCAChunk();
|
||||||
} else {
|
|
||||||
tmp.setLoc(HeightMapMCAGenerator.this, chunkX, chunkZ);
|
|
||||||
}
|
}
|
||||||
|
tmp.setLoc(HeightMapMCAGenerator.this, chunkX, chunkZ);
|
||||||
int cbx = chunkX << 4;
|
int cbx = chunkX << 4;
|
||||||
int cbz = chunkZ << 4;
|
int cbz = chunkZ << 4;
|
||||||
int csx = Math.max(0, cbx);
|
int csx = Math.max(0, cbx);
|
||||||
@ -790,7 +791,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addToQueue() {
|
public void addToQueue() {
|
||||||
MCAChunk cached = getCachedChunk();
|
WritableMCAChunk cached = getCachedChunk();
|
||||||
if (cached != null) setChunk(cached);
|
if (cached != null) setChunk(cached);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1649,328 +1650,159 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MCAChunk write(MCAChunk chunk, int csx, int cex, int csz, int cez) {
|
public WritableMCAChunk write(WritableMCAChunk chunk, int csx, int cex, int csz, int cez) {
|
||||||
// TODO FIXME
|
byte[] heights = this.heights.get();
|
||||||
// byte[] heights = this.heights.get();
|
byte[] biomes = this.biomes.get();
|
||||||
// byte[] biomes = this.biomes.get();
|
int[] main = this.main.get();
|
||||||
// int[] main = this.main.get();
|
int[] floor = this.floor.get();
|
||||||
// int[] floor = this.floor.get();
|
int[] overlay = this.overlay != null ? this.overlay.get() : null;
|
||||||
// int[] overlay = this.overlay != null ? this.overlay.get() : null;
|
try {
|
||||||
// try {
|
int[] indexes = indexStore.get();
|
||||||
// int[] indexes = indexStore.get();
|
|
||||||
// for (int i = 0; i < chunk.ids.length; i++) {
|
int index;
|
||||||
// byte[] idsArray = chunk.ids[i];
|
int maxY = 0;
|
||||||
// if (idsArray != null) {
|
int minY = Integer.MAX_VALUE;
|
||||||
// Arrays.fill(idsArray, (byte) 0);
|
int[] heightMap = chunk.biomes;
|
||||||
// Arrays.fill(chunk.data[i], (byte) 0);
|
int globalIndex;
|
||||||
// }
|
for (int z = csz; z <= cez; z++) {
|
||||||
// }
|
globalIndex = z * getWidth() + csx;
|
||||||
// int index;
|
index = (z & 15) << 4;
|
||||||
// int maxY = 0;
|
for (int x = csx; x <= cex; x++, index++, globalIndex++) {
|
||||||
// int minY = Integer.MAX_VALUE;
|
indexes[index] = globalIndex;
|
||||||
// int[] heightMap = chunk.getHeightMapArray();
|
int height = heights[globalIndex] & 0xFF;
|
||||||
// int globalIndex;
|
heightMap[index] = height;
|
||||||
// for (int z = csz; z <= cez; z++) {
|
maxY = Math.max(maxY, height);
|
||||||
// globalIndex = z * getWidth() + csx;
|
minY = Math.min(minY, height);
|
||||||
// index = (z & 15) << 4;
|
}
|
||||||
// for (int x = csx; x <= cex; x++, index++, globalIndex++) {
|
}
|
||||||
// indexes[index] = globalIndex;
|
boolean hasOverlay = this.overlay != null;
|
||||||
// int height = heights[globalIndex] & 0xFF;
|
if (hasOverlay) {
|
||||||
// heightMap[index] = height;
|
maxY++;
|
||||||
// maxY = Math.max(maxY, height);
|
}
|
||||||
// minY = Math.min(minY, height);
|
int maxLayer = maxY >> 4;
|
||||||
// }
|
for (int layer = 0; layer <= maxLayer; layer++) {
|
||||||
// }
|
chunk.hasSections[layer] = true;
|
||||||
// boolean hasOverlay = this.overlay != null;
|
}
|
||||||
// if (hasOverlay) {
|
if (primtives.waterHeight != 0) {
|
||||||
// maxY++;
|
maxY = Math.max(maxY, primtives.waterHeight);
|
||||||
// }
|
int maxIndex = (primtives.waterHeight) << 8;
|
||||||
// int maxLayer = maxY >> 4;
|
Arrays.fill(chunk.blocks, 0, maxIndex, primtives.waterId);
|
||||||
// int fillLayers = Math.max(0, (minY - 1)) >> 4;
|
}
|
||||||
// for (int layer = 0; layer <= maxLayer; layer++) {
|
|
||||||
// if (chunk.ids[layer] == null) {
|
if (primtives.modifiedMain) { // If the main block is modified, we can't short circuit this
|
||||||
// chunk.ids[layer] = new byte[4096];
|
for (int z = csz; z <= cez; z++) {
|
||||||
// chunk.data[layer] = new byte[2048];
|
index = (z & 15) << 4;
|
||||||
// chunk.skyLight[layer] = new byte[2048];
|
for (int x = csx; x <= cex; x++, index++) {
|
||||||
// chunk.blockLight[layer] = new byte[2048];
|
globalIndex = indexes[index];
|
||||||
// }
|
int mainCombined = main[globalIndex];
|
||||||
// }
|
for (int y = 0; y < minY; y++) {
|
||||||
// if (primtives.waterHeight != 0) {
|
chunk.blocks[index + (y << 8)] = mainCombined;
|
||||||
// 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;
|
} else {
|
||||||
// byte[] ids = chunk.ids[layer];
|
int maxIndex = minY << 8;
|
||||||
// if (ids == null) {
|
Arrays.fill(chunk.blocks, 0, maxIndex, BlockID.STONE);
|
||||||
// chunk.ids[layer] = ids = new byte[4096];
|
}
|
||||||
// chunk.data[layer] = new byte[2048];
|
|
||||||
// chunk.skyLight[layer] = new byte[2048];
|
final boolean hasFloorThickness = primtives.floorThickness != 0 || primtives.worldThickness != 0;
|
||||||
// chunk.blockLight[layer] = new byte[2048];
|
if (primtives.worldThickness != 0) {
|
||||||
// Arrays.fill(chunk.skyLight[layer], (byte) 255);
|
int endLayer = ((minY - primtives.worldThickness + 1) >> 4);
|
||||||
// }
|
for (int layer = 0; layer < endLayer; layer++) {
|
||||||
// if (fillAll) {
|
chunk.hasSections[layer] = false;
|
||||||
// Arrays.fill(ids, primtives.waterId);
|
}
|
||||||
// } else {
|
}
|
||||||
// int maxIndex = (primtives.waterHeight & 15) << 8;
|
|
||||||
// Arrays.fill(ids, 0, maxIndex, primtives.waterId);
|
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];
|
||||||
// if (primtives.modifiedMain) { // If the main block is modified, we can't short circuit this
|
int maxMainY = height;
|
||||||
// for (int layer = 0; layer < fillLayers; layer++) {
|
int minMainY = minY;
|
||||||
// byte[] layerIds = chunk.ids[layer];
|
|
||||||
// byte[] layerDatas = chunk.data[layer];
|
int mainCombined = main[globalIndex];
|
||||||
// for (int z = csz; z <= cez; z++) {
|
|
||||||
// index = (z & 15) << 4;
|
int floorCombined = floor[globalIndex];
|
||||||
// for (int x = csx; x <= cex; x++, index++) {
|
if (hasFloorThickness) {
|
||||||
// globalIndex = indexes[index];
|
if (x > 0) maxMainY = Math.min(heights[globalIndex - 1] & 0xFF, maxMainY);
|
||||||
// char mainCombined = main[globalIndex];
|
if (x < getWidth() - 1) maxMainY = Math.min(heights[globalIndex + 1] & 0xFF, maxMainY);
|
||||||
// byte id = (byte) FaweCache.getId(mainCombined);
|
if (z > 0) maxMainY = Math.min(heights[globalIndex - getWidth()] & 0xFF, maxMainY);
|
||||||
// int data = FaweCache.getData(mainCombined);
|
if (z < getLength() - 1) maxMainY = Math.min(heights[globalIndex + getWidth()] & 0xFF, maxMainY);
|
||||||
// if (data != 0) {
|
|
||||||
// for (int y = 0; y < 16; y++) {
|
int min = maxMainY;
|
||||||
// int mainIndex = index + (y << 8);
|
|
||||||
// chunk.setNibble(mainIndex, layerDatas, data);
|
if (primtives.floorThickness != 0) {
|
||||||
// }
|
maxMainY = Math.max(0, maxMainY - (primtives.floorThickness - 1));
|
||||||
// }
|
for (int y = maxMainY; y <= height; y++) {
|
||||||
// for (int y = 0; y < 16; y++) {
|
chunk.blocks[index + (y << 8)] = floorCombined;
|
||||||
// layerIds[index + (y << 8)] = id;
|
}
|
||||||
// }
|
}
|
||||||
// }
|
else {
|
||||||
// }
|
chunk.blocks[index + ((height) << 8)] = floorCombined;
|
||||||
// }
|
}
|
||||||
// } else {
|
|
||||||
// for (int layer = 0; layer < fillLayers; layer++) {
|
if (primtives.worldThickness != 0) {
|
||||||
// Arrays.fill(chunk.ids[layer], (byte) 1);
|
minMainY = Math.max(minY, min - primtives.worldThickness + 1);
|
||||||
// }
|
for (int y = minY; y < minMainY; y++) {
|
||||||
// }
|
chunk.blocks[index + (y << 8)] = BlockID.AIR;
|
||||||
//
|
}
|
||||||
// for (int layer = fillLayers; layer <= maxLayer; layer++) {
|
}
|
||||||
// Arrays.fill(chunk.skyLight[layer], (byte) 255);
|
|
||||||
// byte[] layerIds = chunk.ids[layer];
|
} else {
|
||||||
// byte[] layerDatas = chunk.data[layer];
|
chunk.blocks[index + ((height) << 8)] = floorCombined;
|
||||||
// int startY = layer << 4;
|
}
|
||||||
// int endY = startY + 15;
|
|
||||||
// for (int z = csz; z <= cez; z++) {
|
for (int y = minMainY; y < maxMainY; y++) {
|
||||||
// index = (z & 15) << 4;
|
chunk.blocks[index + (y << 8)] = mainCombined;
|
||||||
// for (int x = csx; x <= cex; x++, index++) {
|
}
|
||||||
// globalIndex = indexes[index];
|
|
||||||
// int height = heightMap[index];
|
if (hasOverlay) {
|
||||||
// int diff;
|
int overlayCombined = overlay[globalIndex];
|
||||||
// if (height > endY) {
|
int overlayIndex = index + ((height + 1) << 8);
|
||||||
// diff = 16;
|
chunk.blocks[overlayIndex] = overlayCombined;
|
||||||
// } else if (height >= startY) {
|
}
|
||||||
// diff = height - startY;
|
|
||||||
// char floorCombined = floor[globalIndex];
|
if (primtives.bedrockId != 0) {
|
||||||
// int id = FaweCache.getId(floorCombined);
|
chunk.blocks[index] = primtives.bedrockId;
|
||||||
// int floorIndex = index + ((height & 15) << 8);
|
}
|
||||||
// layerIds[floorIndex] = (byte) id;
|
}
|
||||||
// int data = FaweCache.getData(floorCombined);
|
}
|
||||||
// if (data != 0) {
|
|
||||||
// chunk.setNibble(floorIndex, layerDatas, data);
|
int[][][] localBlocks = getChunkArray(chunk.getX(), chunk.getZ());
|
||||||
// }
|
if (localBlocks != null) {
|
||||||
// if (hasOverlay && height >= startY - 1 && height < endY) {
|
index = 0;
|
||||||
// char overlayCombined = overlay[globalIndex];
|
for (int layer = 0; layer < 16; layer++) {
|
||||||
// id = FaweCache.getId(overlayCombined);
|
int by = layer << 4;
|
||||||
// int overlayIndex = index + (((height + 1) & 15) << 8);
|
int ty = by + 15;
|
||||||
// layerIds[overlayIndex] = (byte) id;
|
for (int y = by; y <= ty; y++, index += 256) {
|
||||||
// data = FaweCache.getData(overlayCombined);
|
int[][] yBlocks = localBlocks[y];
|
||||||
// if (data != 0) {
|
if (yBlocks != null) {
|
||||||
// chunk.setNibble(overlayIndex, layerDatas, data);
|
chunk.hasSections[layer] = true;
|
||||||
// }
|
for (int z = 0; z < yBlocks.length; z++) {
|
||||||
// }
|
int[] zBlocks = yBlocks[z];
|
||||||
// } else if (hasOverlay && height == startY - 1) {
|
if (zBlocks != null) {
|
||||||
// char overlayCombined = overlay[globalIndex];
|
int zIndex = index + (z << 4);
|
||||||
// int id = FaweCache.getId(overlayCombined);
|
for (int x = 0; x < zBlocks.length; x++, zIndex++) {
|
||||||
// int overlayIndex = index + (((height + 1) & 15) << 8);
|
int combined = zBlocks[x];
|
||||||
// layerIds[overlayIndex] = (byte) id;
|
if (combined == 0) continue;
|
||||||
// int data = FaweCache.getData(overlayCombined);
|
chunk.blocks[zIndex] = combined;
|
||||||
// if (data != 0) {
|
}
|
||||||
// chunk.setNibble(overlayIndex, layerDatas, data);
|
}
|
||||||
// }
|
}
|
||||||
// continue;
|
}
|
||||||
// } else {
|
}
|
||||||
// continue;
|
}
|
||||||
// }
|
}
|
||||||
// char mainCombined = main[globalIndex];
|
|
||||||
// byte id = (byte) FaweCache.getId(mainCombined);
|
for (int i = 0; i < 256; i++) {
|
||||||
// int data = FaweCache.getData(mainCombined);
|
chunk.biomes[i] = biomes[indexes[i]];
|
||||||
// if (data != 0) {
|
}
|
||||||
// for (int y = 0; y < diff; y++) {
|
|
||||||
// int mainIndex = index + (y << 8);
|
|
||||||
// chunk.setNibble(mainIndex, layerDatas, data);
|
} catch (Throwable e) {
|
||||||
// }
|
e.printStackTrace();
|
||||||
// }
|
}
|
||||||
// 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();
|
|
||||||
// }
|
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,8 +3,10 @@ package com.boydti.fawe.jnbt.anvil;
|
|||||||
import com.boydti.fawe.object.collection.IterableThreadLocal;
|
import com.boydti.fawe.object.collection.IterableThreadLocal;
|
||||||
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
|
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
|
||||||
import com.boydti.fawe.util.MainUtil;
|
import com.boydti.fawe.util.MainUtil;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.ForkJoinPool;
|
import java.util.concurrent.ForkJoinPool;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.zip.Deflater;
|
import java.util.zip.Deflater;
|
||||||
@ -67,22 +69,20 @@ public abstract class MCAWriter {
|
|||||||
|
|
||||||
public abstract boolean shouldWrite(int chunkX, int chunkZ);
|
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 {
|
public void generate() throws IOException {
|
||||||
if (!folder.exists()) {
|
if (!folder.exists()) {
|
||||||
folder.mkdirs();
|
folder.mkdirs();
|
||||||
}
|
}
|
||||||
final ForkJoinPool pool = new ForkJoinPool();
|
final ForkJoinPool pool = new ForkJoinPool();
|
||||||
int bcx = 0;
|
|
||||||
int bcz = 0;
|
|
||||||
int tcx = (width - 1) >> 4;
|
int tcx = (width - 1) >> 4;
|
||||||
int tcz = (length - 1) >> 4;
|
int tcz = (length - 1) >> 4;
|
||||||
final ThreadLocal<MCAChunk> chunkStore = new ThreadLocal<MCAChunk>() {
|
final ThreadLocal<WritableMCAChunk> chunkStore = new ThreadLocal<WritableMCAChunk>() {
|
||||||
@Override
|
@Override
|
||||||
protected MCAChunk initialValue() {
|
protected WritableMCAChunk initialValue() {
|
||||||
MCAChunk chunk = new MCAChunk(null, 0, 0);
|
WritableMCAChunk chunk = new WritableMCAChunk();
|
||||||
chunk.biomes = new byte[256];
|
Arrays.fill(chunk.skyLight, (byte) 255);
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -111,16 +111,15 @@ public abstract class MCAWriter {
|
|||||||
int mcaXMax = mcaXMin + ((width - 1) >> 9);
|
int mcaXMax = mcaXMin + ((width - 1) >> 9);
|
||||||
int mcaZMax = mcaZMin + ((length - 1) >> 9);
|
int mcaZMax = mcaZMin + ((length - 1) >> 9);
|
||||||
|
|
||||||
|
final byte[] header = new byte[4096];
|
||||||
|
|
||||||
for (int mcaZ = mcaXMin; mcaZ <= mcaZMax; mcaZ++) {
|
for (int mcaZ = mcaXMin; mcaZ <= mcaZMax; mcaZ++) {
|
||||||
for (int mcaX = mcaXMin; mcaX <= mcaXMax; mcaX++) {
|
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");
|
File file = new File(folder, "r." + (mcaX + (getOffsetX() >> 9)) + "." + (mcaZ + (getOffsetZ() >> 9)) + ".mca");
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
file.createNewFile();
|
file.createNewFile();
|
||||||
}
|
}
|
||||||
final BufferedRandomAccessFile raf = new BufferedRandomAccessFile(file, "rw", fileBuf);
|
final BufferedRandomAccessFile raf = new BufferedRandomAccessFile(file, "rw", fileBuf);
|
||||||
final byte[] header = new byte[4096];
|
|
||||||
final byte[][] compressed = new byte[1024][];
|
final byte[][] compressed = new byte[1024][];
|
||||||
int bx = mcaX << 9;
|
int bx = mcaX << 9;
|
||||||
int bz = mcaZ << 9;
|
int bz = mcaZ << 9;
|
||||||
@ -137,34 +136,31 @@ public abstract class MCAWriter {
|
|||||||
final int fcx = cx;
|
final int fcx = cx;
|
||||||
final int fcz = cz;
|
final int fcz = cz;
|
||||||
if (shouldWrite(cx, cz)) {
|
if (shouldWrite(cx, cz)) {
|
||||||
pool.submit(new Runnable() {
|
pool.submit(() -> {
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
try {
|
||||||
MCAChunk chunk = chunkStore.get();
|
WritableMCAChunk chunk = chunkStore.get();
|
||||||
chunk.setLoc(null, fcx, fcz);
|
chunk.clear(fcx, fcz);
|
||||||
chunk = write(chunk, csx, cex, csz, cez);
|
chunk = write(chunk, csx, cex, csz, cez);
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
// Generation offset
|
// Generation offset
|
||||||
chunk.setLoc(null, fcx + (getOffsetX() >> 4), fcz + (getOffsetZ() >> 4));
|
chunk.setLoc( fcx + (getOffsetX() >> 4), fcz + (getOffsetZ() >> 4));
|
||||||
|
|
||||||
// Compress
|
// Compress
|
||||||
byte[] bytes = chunk.toBytes(byteStore1.get());
|
byte[] bytes = chunk.toBytes(byteStore1.get());
|
||||||
byte[] compressedBytes = MainUtil.compress(bytes, byteStore2.get(), deflateStore.get());
|
byte[] compressedBytes = MainUtil.compress(bytes, byteStore2.get(), deflateStore.get());
|
||||||
int blocks = (compressed.length + 4095) >> 12;
|
|
||||||
|
// 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();
|
compressed[((fcx & 31)) + ((fcz & 31) << 5)] = compressedBytes.clone();
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||||
pool.submit(new Runnable() {
|
pool.submit(() -> {
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
try {
|
||||||
int totalLength = 8192;
|
int totalLength = 8192;
|
||||||
for (int i = 0; i < compressed.length; i++) {
|
for (int i = 0; i < compressed.length; i++) {
|
||||||
@ -188,8 +184,6 @@ public abstract class MCAWriter {
|
|||||||
header[index + 2] = (byte) ((offsetMedium >> 0));
|
header[index + 2] = (byte) ((offsetMedium >> 0));
|
||||||
header[index + 3] = (byte) (blocks);
|
header[index + 3] = (byte) (blocks);
|
||||||
// Write bytes
|
// Write bytes
|
||||||
int cx = (fmcaX << 5) + (i & 31);
|
|
||||||
int cz = (fmcaZ << 5) + (i >> 5);
|
|
||||||
raf.seek(offset);
|
raf.seek(offset);
|
||||||
raf.writeInt(compressedBytes.length + 1);
|
raf.writeInt(compressedBytes.length + 1);
|
||||||
raf.write(2);
|
raf.write(2);
|
||||||
@ -208,7 +202,6 @@ public abstract class MCAWriter {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
@ -39,7 +39,7 @@ import java.util.Map;
|
|||||||
* found at <a href="http://www.minecraft.net/docs/NBT.txt">
|
* found at <a href="http://www.minecraft.net/docs/NBT.txt">
|
||||||
* http://www.minecraft.net/docs/NBT.txt</a>.</p>
|
* 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.
|
* The output stream.
|
||||||
@ -426,11 +426,82 @@ public final class NBTOutputStream implements Closeable {
|
|||||||
if (os instanceof Closeable) ((Closeable) os).close();
|
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.
|
* Flush output.
|
||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void flush() throws IOException {
|
public void flush() throws IOException {
|
||||||
if (os instanceof Flushable) ((Flushable) os).flush();
|
if (os instanceof Flushable) ((Flushable) os).flush();
|
||||||
}
|
}
|
||||||
|
@ -974,7 +974,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
|
|||||||
BBC.WORLDEDIT_SOME_FAILS_BLOCKBAG.send(player, str.toString());
|
BBC.WORLDEDIT_SOME_FAILS_BLOCKBAG.send(player, str.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new HashMap<>();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren