Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-12-24 18:10:08 +01:00
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;
|
||||
}
|
||||
|
||||
@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();
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
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;
|
||||
@ -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);
|
||||
}
|
||||
};
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,34 +136,31 @@ public abstract class MCAWriter {
|
||||
final int fcx = cx;
|
||||
final int fcz = cz;
|
||||
if (shouldWrite(cx, cz)) {
|
||||
pool.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
pool.submit(() -> {
|
||||
try {
|
||||
MCAChunk chunk = chunkStore.get();
|
||||
chunk.setLoc(null, fcx, fcz);
|
||||
WritableMCAChunk chunk = chunkStore.get();
|
||||
chunk.clear(fcx, fcz);
|
||||
chunk = write(chunk, csx, cex, csz, cez);
|
||||
if (chunk != null) {
|
||||
// Generation offset
|
||||
chunk.setLoc(null, fcx + (getOffsetX() >> 4), fcz + (getOffsetZ() >> 4));
|
||||
chunk.setLoc( 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;
|
||||
|
||||
// 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++) {
|
||||
@ -188,8 +184,6 @@ public abstract class MCAWriter {
|
||||
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);
|
||||
@ -208,7 +202,6 @@ public abstract class MCAWriter {
|
||||
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">
|
||||
* 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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren