2016-08-20 05:33:56 +02:00
|
|
|
package com.boydti.fawe.jnbt.anvil;
|
|
|
|
|
|
|
|
import com.boydti.fawe.FaweCache;
|
|
|
|
import com.boydti.fawe.jnbt.NBTStreamer;
|
|
|
|
import com.boydti.fawe.object.FaweChunk;
|
|
|
|
import com.boydti.fawe.object.FaweQueue;
|
|
|
|
import com.boydti.fawe.object.RunnableVal2;
|
2017-03-26 20:14:28 +02:00
|
|
|
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
|
2017-04-04 12:14:51 +02:00
|
|
|
import com.boydti.fawe.util.ArrayUtil;
|
2016-08-20 05:33:56 +02:00
|
|
|
import com.boydti.fawe.util.MainUtil;
|
|
|
|
import com.boydti.fawe.util.MathMan;
|
2017-06-26 09:56:07 +02:00
|
|
|
import com.boydti.fawe.util.ReflectionUtils;
|
2016-08-20 05:33:56 +02:00
|
|
|
import com.sk89q.jnbt.CompoundTag;
|
2017-06-26 09:56:07 +02:00
|
|
|
import com.sk89q.jnbt.IntTag;
|
2016-08-20 05:33:56 +02:00
|
|
|
import com.sk89q.jnbt.ListTag;
|
2017-03-26 20:14:28 +02:00
|
|
|
import com.sk89q.jnbt.NBTConstants;
|
2016-08-20 05:33:56 +02:00
|
|
|
import com.sk89q.jnbt.NBTInputStream;
|
2017-03-26 20:14:28 +02:00
|
|
|
import com.sk89q.jnbt.NBTOutputStream;
|
2017-06-26 09:56:07 +02:00
|
|
|
import com.sk89q.jnbt.Tag;
|
2017-07-28 07:12:41 +02:00
|
|
|
import java.io.DataOutput;
|
2017-03-26 20:14:28 +02:00
|
|
|
import java.io.DataOutputStream;
|
2016-08-20 05:33:56 +02:00
|
|
|
import java.io.IOException;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.HashSet;
|
2017-04-03 12:07:57 +02:00
|
|
|
import java.util.Iterator;
|
2016-08-20 05:33:56 +02:00
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Set;
|
|
|
|
import java.util.UUID;
|
|
|
|
|
|
|
|
public class MCAChunk extends FaweChunk<Void> {
|
|
|
|
|
|
|
|
// ids: byte[16][4096]
|
|
|
|
// data: byte[16][2048]
|
|
|
|
// skylight: byte[16][2048]
|
|
|
|
// blocklight: byte[16][2048]
|
2016-12-02 07:03:57 +01:00
|
|
|
// entities: Map<Short, CompoundTag>
|
2016-08-20 05:33:56 +02:00
|
|
|
// tiles: List<CompoundTag>
|
|
|
|
// biomes: byte[256]
|
|
|
|
// compressedSize: int
|
|
|
|
// modified: boolean
|
|
|
|
// deleted: boolean
|
|
|
|
|
|
|
|
public byte[][] ids;
|
|
|
|
public byte[][] data;
|
|
|
|
public byte[][] skyLight;
|
|
|
|
public byte[][] blockLight;
|
|
|
|
public byte[] biomes;
|
2016-12-02 07:03:57 +01:00
|
|
|
public Map<Short, CompoundTag> tiles = new HashMap<>();
|
2016-08-20 05:33:56 +02:00
|
|
|
public Map<UUID, CompoundTag> entities = new HashMap<>();
|
|
|
|
private long inhabitedTime;
|
|
|
|
private long lastUpdate;
|
|
|
|
private int[] heightMap;
|
|
|
|
|
2017-04-03 12:07:57 +02:00
|
|
|
private int modified;
|
2016-08-20 05:33:56 +02:00
|
|
|
private boolean deleted;
|
|
|
|
|
2017-04-10 17:50:40 +02:00
|
|
|
public MCAChunk(FaweQueue queue, int x, int z) {
|
|
|
|
super(queue, x, z);
|
|
|
|
this.ids = new byte[16][];
|
|
|
|
this.data = new byte[16][];
|
|
|
|
this.skyLight = new byte[16][];
|
|
|
|
this.blockLight = new byte[16][];
|
|
|
|
this.biomes = new byte[256];
|
|
|
|
this.tiles = new HashMap<>();
|
|
|
|
this.entities = new HashMap<>();
|
|
|
|
this.lastUpdate = System.currentTimeMillis();
|
|
|
|
this.heightMap = new int[256];
|
|
|
|
this.setModified();
|
|
|
|
}
|
|
|
|
|
|
|
|
public MCAChunk(MCAChunk parent, boolean shallow) {
|
|
|
|
super(parent.getParent(), parent.getX(), parent.getZ());
|
|
|
|
if (shallow) {
|
|
|
|
this.ids = parent.ids;
|
|
|
|
this.data = parent.data;
|
|
|
|
this.skyLight = parent.skyLight;
|
|
|
|
this.blockLight = parent.blockLight;
|
|
|
|
this.biomes = parent.biomes;
|
|
|
|
this.tiles = parent.tiles;
|
|
|
|
this.entities = parent.entities;
|
|
|
|
this.inhabitedTime = parent.inhabitedTime;
|
|
|
|
this.lastUpdate = parent.lastUpdate;
|
|
|
|
this.heightMap = parent.heightMap;
|
|
|
|
this.modified = parent.modified;
|
|
|
|
this.deleted = parent.deleted;
|
|
|
|
} else {
|
|
|
|
this.ids = (byte[][]) MainUtil.copyNd(parent.ids);
|
|
|
|
this.data = (byte[][]) MainUtil.copyNd(parent.data);
|
|
|
|
this.skyLight = (byte[][]) MainUtil.copyNd(parent.skyLight);
|
|
|
|
this.blockLight = (byte[][]) MainUtil.copyNd(parent.blockLight);
|
|
|
|
this.biomes = parent.biomes.clone();
|
|
|
|
this.tiles = new HashMap<>(parent.tiles);
|
|
|
|
this.entities = new HashMap<>(parent.entities);
|
|
|
|
this.inhabitedTime = parent.inhabitedTime;
|
|
|
|
this.lastUpdate = parent.lastUpdate;
|
|
|
|
this.heightMap = parent.heightMap.clone();
|
|
|
|
this.modified = parent.modified;
|
|
|
|
this.deleted = parent.deleted;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-26 20:14:28 +02:00
|
|
|
public byte[] toBytes(byte[] buffer) throws IOException {
|
|
|
|
if (buffer == null) {
|
|
|
|
buffer = new byte[8192];
|
|
|
|
}
|
|
|
|
FastByteArrayOutputStream buffered = new FastByteArrayOutputStream(buffer);
|
|
|
|
DataOutputStream dataOut = new DataOutputStream(buffered);
|
2017-07-28 07:12:41 +02:00
|
|
|
NBTOutputStream nbtOut = new NBTOutputStream((DataOutput) dataOut);
|
2017-03-26 20:14:28 +02:00
|
|
|
nbtOut.writeNamedTagName("", NBTConstants.TYPE_COMPOUND);
|
|
|
|
nbtOut.writeLazyCompoundTag("Level", new NBTOutputStream.LazyWrite() {
|
|
|
|
@Override
|
|
|
|
public void write(NBTOutputStream out) throws IOException {
|
|
|
|
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<CompoundTag>(entities.values())));
|
|
|
|
}
|
|
|
|
if (tiles.isEmpty()) {
|
|
|
|
out.writeNamedEmptyList("TileEntities");
|
|
|
|
} else {
|
|
|
|
out.writeNamedTag("TileEntities", new ListTag(CompoundTag.class, new ArrayList<CompoundTag>(tiles.values())));
|
|
|
|
}
|
|
|
|
out.writeNamedTag("InhabitedTime", inhabitedTime);
|
|
|
|
out.writeNamedTag("LastUpdate", lastUpdate);
|
|
|
|
if (biomes != null) {
|
|
|
|
out.writeNamedTag("Biomes", biomes);
|
|
|
|
}
|
|
|
|
out.writeNamedTag("HeightMap", heightMap);
|
|
|
|
out.writeNamedTagName("Sections", NBTConstants.TYPE_LIST);
|
|
|
|
dataOut.writeByte(NBTConstants.TYPE_COMPOUND);
|
|
|
|
int len = 0;
|
|
|
|
for (int layer = 0; layer < ids.length; layer++) {
|
|
|
|
if (ids[layer] != null) len++;
|
|
|
|
}
|
|
|
|
dataOut.writeInt(len);
|
|
|
|
for (int layer = 0; layer < ids.length; layer++) {
|
|
|
|
byte[] idLayer = ids[layer];
|
|
|
|
if (idLayer == null) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
out.writeNamedTag("Y", (byte) layer);
|
|
|
|
out.writeNamedTag("BlockLight", blockLight[layer]);
|
|
|
|
out.writeNamedTag("SkyLight", skyLight[layer]);
|
|
|
|
out.writeNamedTag("Blocks", idLayer);
|
|
|
|
out.writeNamedTag("Data", data[layer]);
|
|
|
|
out.writeEndTag();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
nbtOut.writeEndTag();
|
|
|
|
nbtOut.close();
|
|
|
|
return buffered.toByteArray();
|
|
|
|
}
|
|
|
|
|
2017-04-10 14:57:54 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-04-04 12:14:51 +02:00
|
|
|
public void copyFrom(MCAChunk other, int minX, int maxX, int minY, int maxY, int minZ, int maxZ, int offsetX, int offsetY, int offsetZ) {
|
|
|
|
minY = Math.max(-offsetY - minY, minY);
|
|
|
|
maxY = Math.min(255 - offsetY, maxY);
|
|
|
|
minZ = Math.max(-offsetZ - minZ, minZ);
|
|
|
|
maxZ = Math.min(15 - offsetZ, maxZ);
|
|
|
|
minX = Math.max(-offsetX - minX, minX);
|
|
|
|
maxX = Math.min(15 - offsetX, maxX);
|
|
|
|
if (minX > maxX || minZ > maxZ || minY > maxY) return;
|
|
|
|
int startLayer = minY >> 4;
|
|
|
|
int endLayer = maxY >> 4;
|
|
|
|
for (int otherY = minY, thisY = minY + offsetY; otherY <= maxY; otherY++, thisY++) {
|
|
|
|
int thisLayer = thisY >> 4;
|
|
|
|
int otherLayer = otherY >> 4;
|
|
|
|
byte[] thisIds = ids[thisLayer];
|
|
|
|
byte[] otherIds = other.ids[otherLayer];
|
|
|
|
if (otherIds == null) {
|
|
|
|
if (thisIds != null) {
|
|
|
|
int indexY = (thisY & 15) << 8;
|
|
|
|
byte[] thisData = data[thisLayer];
|
|
|
|
byte[] thisSkyLight = skyLight[thisLayer];
|
|
|
|
byte[] thisBlockLight = blockLight[thisLayer];
|
|
|
|
for (int otherZ = minZ, thisZ = minZ + offsetZ; otherZ <= maxZ; otherZ++, thisZ++) {
|
|
|
|
int startIndex = indexY + (thisZ << 4) + minX + offsetX;
|
|
|
|
int endIndex = startIndex + maxX - minX;
|
|
|
|
ArrayUtil.fill(thisIds, startIndex, endIndex + 1, (byte) 0);
|
|
|
|
int startIndexShift = startIndex >> 1;
|
|
|
|
int endIndexShift = endIndex >> 1;
|
|
|
|
if ((startIndex & 1) != 0) {
|
|
|
|
startIndexShift++;
|
|
|
|
setNibble(startIndex, thisData, (byte) 0);
|
|
|
|
setNibble(startIndex, thisSkyLight, (byte) 0);
|
|
|
|
setNibble(startIndex, thisBlockLight, (byte) 0);
|
|
|
|
}
|
|
|
|
if ((endIndex & 1) != 1) {
|
|
|
|
endIndexShift--;
|
|
|
|
setNibble(endIndex, thisData, (byte) 0);
|
|
|
|
setNibble(endIndex, thisSkyLight, (byte) 0);
|
|
|
|
setNibble(endIndex, thisBlockLight, (byte) 0);
|
|
|
|
}
|
|
|
|
ArrayUtil.fill(thisData, startIndexShift, endIndexShift + 1, (byte) 0);
|
|
|
|
ArrayUtil.fill(thisSkyLight, startIndexShift, endIndexShift + 1, (byte) 0);
|
|
|
|
ArrayUtil.fill(thisBlockLight, startIndexShift, endIndexShift + 1, (byte) 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
} else if (thisIds == null) {
|
|
|
|
ids[thisLayer] = thisIds = new byte[4096];
|
|
|
|
data[thisLayer] = new byte[2048];
|
|
|
|
skyLight[thisLayer] = new byte[2048];
|
|
|
|
blockLight[thisLayer] = new byte[2048];
|
|
|
|
}
|
|
|
|
int indexY = (thisY & 15) << 8;
|
|
|
|
int otherIndexY = (otherY & 15) << 8;
|
|
|
|
byte[] thisData = data[thisLayer];
|
|
|
|
byte[] thisSkyLight = skyLight[thisLayer];
|
|
|
|
byte[] thisBlockLight = blockLight[thisLayer];
|
|
|
|
byte[] otherData = other.data[otherLayer];
|
|
|
|
byte[] otherSkyLight = other.skyLight[otherLayer];
|
|
|
|
byte[] otherBlockLight = other.blockLight[otherLayer];
|
|
|
|
for (int otherZ = minZ, thisZ = minZ + offsetZ; otherZ <= maxZ; otherZ++, thisZ++) {
|
|
|
|
int startIndex = indexY + (thisZ << 4) + minX + offsetX;
|
|
|
|
int endIndex = startIndex + maxX - minX;
|
|
|
|
int otherStartIndex = otherIndexY + (otherZ << 4) + minX;
|
|
|
|
int otherEndIndex = otherStartIndex + maxX - minX;
|
|
|
|
System.arraycopy(otherIds, otherStartIndex, thisIds, startIndex, endIndex - startIndex + 1);
|
|
|
|
if ((startIndex & 1) == (otherStartIndex & 1)) {
|
|
|
|
int startIndexShift = startIndex >> 1;
|
|
|
|
int endIndexShift = endIndex >> 1;
|
|
|
|
int otherStartIndexShift = otherStartIndex >> 1;
|
|
|
|
int otherEndIndexShift = otherEndIndex >> 1;
|
|
|
|
if ((startIndex & 1) != 0) {
|
|
|
|
startIndexShift++;
|
|
|
|
otherStartIndexShift++;
|
|
|
|
setNibble(startIndex, thisData, getNibble(otherStartIndex, otherData));
|
|
|
|
setNibble(startIndex, thisSkyLight, getNibble(otherStartIndex, otherSkyLight));
|
|
|
|
setNibble(startIndex, thisBlockLight, getNibble(otherStartIndex, otherBlockLight));
|
|
|
|
}
|
|
|
|
if ((endIndex & 1) != 1) {
|
|
|
|
endIndexShift--;
|
|
|
|
otherEndIndexShift--;
|
|
|
|
setNibble(endIndex, thisData, getNibble(otherEndIndex, otherData));
|
|
|
|
setNibble(endIndex, thisSkyLight, getNibble(otherEndIndex, otherSkyLight));
|
|
|
|
setNibble(endIndex, thisBlockLight, getNibble(otherEndIndex, otherBlockLight));
|
|
|
|
}
|
|
|
|
System.arraycopy(otherData, otherStartIndexShift, thisData, startIndexShift, endIndexShift - startIndexShift + 1);
|
|
|
|
System.arraycopy(otherSkyLight, otherStartIndexShift, thisSkyLight, startIndexShift, endIndexShift - startIndexShift + 1);
|
|
|
|
System.arraycopy(otherBlockLight, otherStartIndexShift, thisBlockLight, startIndexShift, endIndexShift - startIndexShift + 1);
|
2017-04-03 12:07:57 +02:00
|
|
|
} else {
|
2017-04-04 12:14:51 +02:00
|
|
|
for (int thisIndex = startIndex, otherIndex = otherStartIndex; thisIndex <= endIndex; thisIndex++, otherIndex++) {
|
|
|
|
setNibble(thisIndex, thisData, getNibble(otherIndex, otherData));
|
|
|
|
setNibble(thisIndex, thisSkyLight, getNibble(otherIndex, otherSkyLight));
|
|
|
|
setNibble(thisIndex, thisBlockLight, getNibble(otherIndex, otherBlockLight));
|
|
|
|
}
|
2017-04-03 12:07:57 +02:00
|
|
|
}
|
2017-04-04 12:14:51 +02:00
|
|
|
}
|
|
|
|
}
|
2017-06-26 09:56:07 +02:00
|
|
|
if (!other.tiles.isEmpty()) {
|
|
|
|
for (Map.Entry<Short, CompoundTag> entry : other.tiles.entrySet()) {
|
|
|
|
int key = entry.getKey();
|
|
|
|
int x = MathMan.untripleBlockCoordX(key);
|
|
|
|
int y = MathMan.untripleBlockCoordY(key);
|
|
|
|
int z = MathMan.untripleBlockCoordZ(key);
|
|
|
|
if (x < minX || x > maxX) continue;
|
|
|
|
if (z < minZ || z > maxZ) continue;
|
|
|
|
if (y < minY || y > maxY) continue;
|
|
|
|
x += offsetX;
|
|
|
|
y += offsetY;
|
|
|
|
z += offsetZ;
|
|
|
|
short pair = MathMan.tripleBlockCoord(x, y, z);
|
|
|
|
CompoundTag tag = entry.getValue();
|
|
|
|
Map<String, Tag> map = ReflectionUtils.getMap(tag.getValue());
|
|
|
|
map.put("x", new IntTag(x + (getX() << 4)));
|
|
|
|
map.put("y", new IntTag(y));
|
|
|
|
map.put("z", new IntTag(z + (getZ() << 4)));
|
|
|
|
tiles.put(pair, tag);
|
|
|
|
}
|
|
|
|
}
|
2017-04-04 12:14:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public void copyFrom(MCAChunk other, int minY, int maxY, int offsetY) {
|
|
|
|
minY = Math.max(-offsetY - minY, minY);
|
|
|
|
maxY = Math.min(255 - offsetY, maxY);
|
|
|
|
if (minY > maxY) return;
|
|
|
|
if ((offsetY & 15) == 0) {
|
|
|
|
int offsetLayer = offsetY >> 4;
|
|
|
|
int startLayer = minY >> 4;
|
|
|
|
int endLayer = maxY >> 4;
|
2017-04-05 01:59:40 +02:00
|
|
|
for (int thisLayer = startLayer + offsetLayer, otherLayer = startLayer; thisLayer <= endLayer; thisLayer++, otherLayer++) {
|
2017-04-04 12:14:51 +02:00
|
|
|
byte[] otherIds = other.ids[otherLayer];
|
|
|
|
byte[] currentIds = ids[thisLayer];
|
|
|
|
int by = otherLayer << 4;
|
2017-04-05 01:59:40 +02:00
|
|
|
int ty = by + 15;
|
2017-04-04 12:14:51 +02:00
|
|
|
if (by >= minY && ty <= maxY) {
|
|
|
|
if (otherIds != null) {
|
|
|
|
ids[thisLayer] = otherIds;
|
|
|
|
data[thisLayer] = other.data[otherLayer];
|
|
|
|
skyLight[thisLayer] = other.skyLight[otherLayer];
|
|
|
|
blockLight[thisLayer] = other.blockLight[otherLayer];
|
|
|
|
} else {
|
|
|
|
ids[thisLayer] = null;
|
2017-04-03 12:07:57 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-04-04 12:14:51 +02:00
|
|
|
by = Math.max(by, minY) & 15;
|
|
|
|
ty = Math.min(ty, maxY) & 15;
|
|
|
|
int indexStart = by << 8;
|
|
|
|
int indexEnd = 256 + (ty << 8);
|
|
|
|
int indexStartShift = indexStart >> 1;
|
|
|
|
int indexEndShift = indexEnd >> 1;
|
|
|
|
if (otherIds == null) {
|
|
|
|
if (currentIds != null) {
|
|
|
|
ArrayUtil.fill(currentIds, indexStart, indexEnd, (byte) 0);
|
|
|
|
ArrayUtil.fill(data[thisLayer], indexStartShift, indexEndShift, (byte) 0);
|
|
|
|
ArrayUtil.fill(skyLight[thisLayer], indexStartShift, indexEndShift, (byte) 0);
|
|
|
|
ArrayUtil.fill(blockLight[thisLayer], indexStartShift, indexEndShift, (byte) 0);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (currentIds == null) {
|
|
|
|
currentIds = this.ids[thisLayer] = new byte[4096];
|
|
|
|
this.data[thisLayer] = new byte[2048];
|
|
|
|
this.skyLight[thisLayer] = new byte[2048];
|
|
|
|
this.blockLight[thisLayer] = new byte[2048];
|
|
|
|
}
|
|
|
|
System.arraycopy(other.ids[otherLayer], indexStart, currentIds, indexStart, indexEnd - indexStart);
|
|
|
|
System.arraycopy(other.data[otherLayer], indexStartShift, data[thisLayer], indexStartShift, indexEndShift - indexStartShift);
|
|
|
|
System.arraycopy(other.skyLight[otherLayer], indexStartShift, skyLight[thisLayer], indexStartShift, indexEndShift - indexStartShift);
|
|
|
|
System.arraycopy(other.blockLight[otherLayer], indexStartShift, blockLight[thisLayer], indexStartShift, indexEndShift - indexStartShift);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (int otherY = minY, thisY = minY + offsetY; otherY <= maxY; otherY++, thisY++) {
|
|
|
|
int otherLayer = otherY >> 4;
|
|
|
|
int thisLayer = thisY >> 4;
|
|
|
|
byte[] thisIds = this.ids[thisLayer];
|
|
|
|
byte[] otherIds = other.ids[otherLayer];
|
|
|
|
int thisStartIndex = (thisY & 15) << 8;
|
|
|
|
int thisStartIndexShift = thisStartIndex >> 1;
|
|
|
|
if (otherIds == null) {
|
|
|
|
if (thisIds == null) {
|
|
|
|
continue;
|
2017-04-03 12:07:57 +02:00
|
|
|
}
|
2017-04-04 12:14:51 +02:00
|
|
|
ArrayUtil.fill(thisIds, thisStartIndex, thisStartIndex + 256, (byte) 0);
|
|
|
|
ArrayUtil.fill(this.data[thisLayer], thisStartIndexShift, thisStartIndexShift + 128, (byte) 0);
|
|
|
|
ArrayUtil.fill(this.skyLight[thisLayer], thisStartIndexShift, thisStartIndexShift + 128, (byte) 0);
|
|
|
|
ArrayUtil.fill(this.blockLight[thisLayer], thisStartIndexShift, thisStartIndexShift + 128, (byte) 0);
|
|
|
|
continue;
|
|
|
|
} else if (thisIds == null) {
|
|
|
|
ids[thisLayer] = thisIds = new byte[4096];
|
|
|
|
data[thisLayer] = new byte[2048];
|
|
|
|
skyLight[thisLayer] = new byte[2048];
|
|
|
|
blockLight[thisLayer] = new byte[2048];
|
2017-04-03 12:07:57 +02:00
|
|
|
}
|
2017-04-04 12:14:51 +02:00
|
|
|
int otherStartIndex = (otherY & 15) << 8;
|
|
|
|
int otherStartIndexShift = otherStartIndex >> 1;
|
|
|
|
System.arraycopy(other.ids[otherLayer], otherStartIndex, thisIds, thisStartIndex, 256);
|
|
|
|
System.arraycopy(other.data[otherLayer], otherStartIndexShift, data[thisLayer], thisStartIndexShift, 128);
|
|
|
|
System.arraycopy(other.skyLight[otherLayer], otherStartIndexShift, skyLight[thisLayer], thisStartIndexShift, 128);
|
|
|
|
System.arraycopy(other.blockLight[otherLayer], otherStartIndexShift, blockLight[thisLayer], thisStartIndexShift, 128);
|
2017-04-03 12:07:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Copy nbt
|
2017-04-04 12:14:51 +02:00
|
|
|
int thisMinY = minY + offsetY;
|
|
|
|
int thisMaxY = maxY + offsetY;
|
2017-04-03 12:07:57 +02:00
|
|
|
if (!tiles.isEmpty()) {
|
|
|
|
Iterator<Map.Entry<Short, CompoundTag>> iter = tiles.entrySet().iterator();
|
|
|
|
while (iter.hasNext()) {
|
|
|
|
int y = MathMan.untripleBlockCoordY(iter.next().getKey());
|
2017-04-04 12:14:51 +02:00
|
|
|
if (y >= thisMinY && y <= thisMaxY) iter.remove();
|
2017-04-03 12:07:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!other.tiles.isEmpty()) {
|
|
|
|
for (Map.Entry<Short, CompoundTag> entry : other.tiles.entrySet()) {
|
2017-04-04 12:14:51 +02:00
|
|
|
int key = entry.getKey();
|
2017-04-03 12:07:57 +02:00
|
|
|
int y = MathMan.untripleBlockCoordY(key);
|
|
|
|
if (y >= minY && y <= maxY) {
|
2017-04-04 12:14:51 +02:00
|
|
|
tiles.put((short) (key + offsetY), entry.getValue());
|
2017-04-03 12:07:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!other.entities.isEmpty()) {
|
|
|
|
for (Map.Entry<UUID, CompoundTag> entry : other.entities.entrySet()) {
|
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getMinLayer() {
|
|
|
|
for (int layer = 0; layer < ids.length; layer++) {
|
|
|
|
if (ids[layer] != null) {
|
|
|
|
return layer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Integer.MAX_VALUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getMaxLayer() {
|
|
|
|
for (int layer = ids.length - 1; layer >= 0; layer--) {
|
|
|
|
if (ids[layer] != null) {
|
|
|
|
return layer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Integer.MIN_VALUE;
|
|
|
|
}
|
|
|
|
|
2017-04-05 01:59:40 +02:00
|
|
|
/**
|
|
|
|
* Deprecated, use the toBytes method
|
2017-06-20 11:00:30 +02:00
|
|
|
*
|
2017-04-05 01:59:40 +02:00
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
@Deprecated
|
2016-08-20 05:33:56 +02:00
|
|
|
public CompoundTag toTag() {
|
|
|
|
if (deleted) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
// e.g. by precalculating the length
|
|
|
|
HashMap<String, Object> level = new HashMap<String, Object>();
|
|
|
|
level.put("Entities", new ListTag(CompoundTag.class, new ArrayList<CompoundTag>(entities.values())));
|
|
|
|
level.put("TileEntities", new ListTag(CompoundTag.class, new ArrayList<CompoundTag>(tiles.values())));
|
|
|
|
level.put("InhabitedTime", inhabitedTime);
|
|
|
|
level.put("LastUpdate", lastUpdate);
|
|
|
|
level.put("LightPopulated", (byte) 0);
|
|
|
|
level.put("TerrainPopulated", (byte) 1);
|
|
|
|
level.put("V", (byte) 1);
|
|
|
|
level.put("xPos", getX());
|
|
|
|
level.put("zPos", getZ());
|
|
|
|
if (biomes != null) {
|
|
|
|
level.put("Biomes", biomes);
|
|
|
|
}
|
|
|
|
level.put("HeightMap", heightMap);
|
|
|
|
ArrayList<HashMap<String, Object>> sections = new ArrayList<>();
|
|
|
|
for (int layer = 0; layer < ids.length; layer++) {
|
|
|
|
byte[] idLayer = ids[layer];
|
|
|
|
if (idLayer == null) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
HashMap<String, Object> map = new HashMap<String, Object>();
|
|
|
|
map.put("Y", (byte) layer);
|
|
|
|
map.put("BlockLight", blockLight[layer]);
|
|
|
|
map.put("SkyLight", skyLight[layer]);
|
|
|
|
map.put("Blocks", idLayer);
|
|
|
|
map.put("Data", data[layer]);
|
|
|
|
sections.add(map);
|
|
|
|
}
|
|
|
|
level.put("Sections", sections);
|
|
|
|
HashMap<String, Object> root = new HashMap<>();
|
|
|
|
root.put("Level", level);
|
|
|
|
return FaweCache.asTag(root);
|
|
|
|
}
|
|
|
|
|
|
|
|
public MCAChunk(NBTInputStream nis, FaweQueue parent, int x, int z, int compressedSize) throws IOException {
|
|
|
|
super(parent, x, z);
|
|
|
|
ids = new byte[16][];
|
|
|
|
data = new byte[16][];
|
|
|
|
skyLight = new byte[16][];
|
|
|
|
blockLight = new byte[16][];
|
|
|
|
NBTStreamer streamer = new NBTStreamer(nis);
|
|
|
|
streamer.addReader(".Level.InhabitedTime", new RunnableVal2<Integer, Long>() {
|
|
|
|
@Override
|
|
|
|
public void run(Integer index, Long value) {
|
|
|
|
inhabitedTime = value;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
streamer.addReader(".Level.LastUpdate", new RunnableVal2<Integer, Long>() {
|
|
|
|
@Override
|
|
|
|
public void run(Integer index, Long value) {
|
|
|
|
lastUpdate = value;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
streamer.addReader(".Level.Sections.#", new RunnableVal2<Integer, CompoundTag>() {
|
|
|
|
@Override
|
|
|
|
public void run(Integer index, CompoundTag tag) {
|
|
|
|
int layer = tag.getByte("Y");
|
|
|
|
ids[layer] = tag.getByteArray("Blocks");
|
|
|
|
data[layer] = tag.getByteArray("Data");
|
|
|
|
skyLight[layer] = tag.getByteArray("SkyLight");
|
|
|
|
blockLight[layer] = tag.getByteArray("BlockLight");
|
|
|
|
}
|
|
|
|
});
|
2017-03-26 20:14:28 +02:00
|
|
|
streamer.addReader(".Level.TileEntities.#", new RunnableVal2<Integer, CompoundTag>() {
|
2016-08-20 05:33:56 +02:00
|
|
|
@Override
|
|
|
|
public void run(Integer index, CompoundTag tile) {
|
|
|
|
int x = tile.getInt("x") & 15;
|
|
|
|
int y = tile.getInt("y");
|
|
|
|
int z = tile.getInt("z") & 15;
|
2016-12-02 07:03:57 +01:00
|
|
|
short pair = MathMan.tripleBlockCoord(x, y, z);
|
2016-08-20 05:33:56 +02:00
|
|
|
tiles.put(pair, tile);
|
|
|
|
}
|
|
|
|
});
|
2017-03-26 20:14:28 +02:00
|
|
|
streamer.addReader(".Level.Entities.#", new RunnableVal2<Integer, CompoundTag>() {
|
2016-08-20 05:33:56 +02:00
|
|
|
@Override
|
|
|
|
public void run(Integer index, CompoundTag entityTag) {
|
|
|
|
if (entities == null) {
|
|
|
|
entities = new HashMap<UUID, CompoundTag>();
|
|
|
|
}
|
2017-03-26 20:14:28 +02:00
|
|
|
|
2016-08-20 05:33:56 +02:00
|
|
|
long least = entityTag.getLong("UUIDLeast");
|
|
|
|
long most = entityTag.getLong("UUIDMost");
|
|
|
|
entities.put(new UUID(most, least), entityTag);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
streamer.addReader(".Level.Biomes", new RunnableVal2<Integer, byte[]>() {
|
|
|
|
@Override
|
|
|
|
public void run(Integer index, byte[] value) {
|
|
|
|
biomes = value;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
streamer.addReader(".Level.HeightMap", new RunnableVal2<Integer, int[]>() {
|
|
|
|
@Override
|
|
|
|
public void run(Integer index, int[] value) {
|
|
|
|
heightMap = value;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
streamer.readFully();
|
|
|
|
}
|
|
|
|
|
2016-10-24 14:43:11 +02:00
|
|
|
public int[] getHeightMapArray() {
|
|
|
|
return heightMap;
|
|
|
|
}
|
|
|
|
|
2016-08-25 09:21:12 +02:00
|
|
|
public void setDeleted(boolean deleted) {
|
|
|
|
setModified();
|
|
|
|
this.deleted = deleted;
|
|
|
|
}
|
2016-08-23 08:25:31 +02:00
|
|
|
|
2016-10-02 07:20:12 +02:00
|
|
|
public boolean isDeleted() {
|
|
|
|
return deleted;
|
|
|
|
}
|
|
|
|
|
2016-08-20 05:33:56 +02:00
|
|
|
public boolean isModified() {
|
2017-04-03 12:07:57 +02:00
|
|
|
return modified != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getModified() {
|
2016-08-20 05:33:56 +02:00
|
|
|
return modified;
|
|
|
|
}
|
|
|
|
|
2016-08-24 16:34:07 +02:00
|
|
|
@Deprecated
|
2017-03-26 20:14:28 +02:00
|
|
|
public final void setModified() {
|
2017-04-03 12:07:57 +02:00
|
|
|
this.modified++;
|
2016-08-24 16:34:07 +02:00
|
|
|
}
|
|
|
|
|
2016-08-20 05:33:56 +02:00
|
|
|
@Override
|
|
|
|
public int getBitMask() {
|
|
|
|
int bitMask = 0;
|
|
|
|
for (int section = 0; section < ids.length; section++) {
|
|
|
|
if (ids[section] != null) {
|
|
|
|
bitMask += 1 << section;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return bitMask;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void setTile(int x, int y, int z, CompoundTag tile) {
|
2017-04-03 12:07:57 +02:00
|
|
|
setModified();
|
2016-12-02 07:03:57 +01:00
|
|
|
short pair = MathMan.tripleBlockCoord(x, y, z);
|
2016-08-24 16:34:07 +02:00
|
|
|
if (tile != null) {
|
|
|
|
tiles.put(pair, tile);
|
|
|
|
} else {
|
|
|
|
tiles.remove(pair);
|
|
|
|
}
|
2016-08-20 05:33:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void setEntity(CompoundTag entityTag) {
|
2017-04-03 12:07:57 +02:00
|
|
|
setModified();
|
2016-08-20 05:33:56 +02:00
|
|
|
long least = entityTag.getLong("UUIDLeast");
|
|
|
|
long most = entityTag.getLong("UUIDMost");
|
|
|
|
entities.put(new UUID(most, least), entityTag);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-01-28 23:25:53 +01:00
|
|
|
public void setBiome(int x, int z, byte biome) {
|
2017-04-03 12:07:57 +02:00
|
|
|
setModified();
|
2017-01-28 23:25:53 +01:00
|
|
|
biomes[x + (z << 4)] = biome;
|
2016-08-20 05:33:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Set<CompoundTag> getEntities() {
|
|
|
|
return new HashSet<>(entities.values());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2016-12-02 07:03:57 +01:00
|
|
|
public Map<Short, CompoundTag> getTiles() {
|
|
|
|
return tiles == null ? new HashMap<Short, CompoundTag>() : tiles;
|
2016-08-20 05:33:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public CompoundTag getTile(int x, int y, int z) {
|
|
|
|
if (tiles == null || tiles.isEmpty()) {
|
|
|
|
return null;
|
|
|
|
}
|
2016-12-02 07:03:57 +01:00
|
|
|
short pair = MathMan.tripleBlockCoord(x, y, z);
|
2016-08-20 05:33:56 +02:00
|
|
|
return tiles.get(pair);
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean doesSectionExist(int cy) {
|
|
|
|
return ids[cy] != null;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public FaweChunk<Void> copy(boolean shallow) {
|
|
|
|
return new MCAChunk(this, shallow);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getBlockCombinedId(int x, int y, int z) {
|
|
|
|
int layer = y >> 4;
|
|
|
|
byte[] idLayer = ids[layer];
|
|
|
|
if (idLayer == null) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
int j = FaweCache.CACHE_J[y][z & 15][x & 15];
|
2016-08-20 14:01:43 +02:00
|
|
|
int id = idLayer[j] & 0xFF;
|
2016-08-20 05:33:56 +02:00
|
|
|
if (FaweCache.hasData(id)) {
|
|
|
|
byte[] dataLayer = data[layer];
|
|
|
|
if (dataLayer != null) {
|
2016-08-20 14:01:43 +02:00
|
|
|
return (id << 4) + getNibble(j, dataLayer);
|
2016-08-20 05:33:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return id << 4;
|
|
|
|
}
|
|
|
|
|
2017-01-28 23:25:53 +01:00
|
|
|
@Override
|
|
|
|
public byte[] getBiomeArray() {
|
|
|
|
return this.biomes;
|
|
|
|
}
|
|
|
|
|
2016-08-20 05:33:56 +02:00
|
|
|
@Override
|
|
|
|
public Set<UUID> getEntityRemoves() {
|
|
|
|
return new HashSet<>();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setSkyLight(int x, int y, int z, int value) {
|
2017-04-03 12:07:57 +02:00
|
|
|
setModified();
|
2016-08-20 05:33:56 +02:00
|
|
|
int layer = y >> 4;
|
|
|
|
byte[] skyLayer = skyLight[layer];
|
|
|
|
if (skyLayer == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int index = FaweCache.CACHE_J[y][z & 15][x & 15];
|
|
|
|
setNibble(index, skyLayer, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setBlockLight(int x, int y, int z, int value) {
|
2017-04-03 12:07:57 +02:00
|
|
|
setModified();
|
2016-08-20 05:33:56 +02:00
|
|
|
int layer = y >> 4;
|
|
|
|
byte[] blockLayer = blockLight[layer];
|
|
|
|
if (blockLayer == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int index = FaweCache.CACHE_J[y][z & 15][x & 15];
|
|
|
|
setNibble(index, blockLayer, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getSkyLight(int x, int y, int z) {
|
|
|
|
int layer = y >> 4;
|
|
|
|
byte[] skyLayer = skyLight[layer];
|
|
|
|
if (skyLayer == null) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
int index = FaweCache.CACHE_J[y][z & 15][x & 15];
|
|
|
|
return getNibble(index, skyLayer);
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getBlockLight(int x, int y, int z) {
|
|
|
|
int layer = y >> 4;
|
|
|
|
byte[] blockLayer = blockLight[layer];
|
|
|
|
if (blockLayer == null) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
int index = FaweCache.CACHE_J[y][z & 15][x & 15];
|
|
|
|
return getNibble(index, blockLayer);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setFullbright() {
|
2017-04-03 12:07:57 +02:00
|
|
|
setModified();
|
2016-08-20 05:33:56 +02:00
|
|
|
for (byte[] array : skyLight) {
|
|
|
|
if (array != null) {
|
|
|
|
Arrays.fill(array, (byte) 255);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void removeLight() {
|
|
|
|
for (int i = 0; i < skyLight.length; i++) {
|
|
|
|
byte[] array1 = skyLight[i];
|
|
|
|
if (array1 == null) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
byte[] array2 = blockLight[i];
|
|
|
|
Arrays.fill(array1, (byte) 0);
|
|
|
|
Arrays.fill(array2, (byte) 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-24 16:34:07 +02:00
|
|
|
public int getNibble(int index, byte[] array) {
|
2016-08-20 05:33:56 +02:00
|
|
|
int indexShift = index >> 1;
|
2017-06-20 11:00:30 +02:00
|
|
|
if ((index & 1) == 0) {
|
2016-08-24 16:34:07 +02:00
|
|
|
return array[indexShift] & 15;
|
2016-08-20 05:33:56 +02:00
|
|
|
} else {
|
2016-08-24 16:34:07 +02:00
|
|
|
return array[indexShift] >> 4 & 15;
|
2016-08-20 05:33:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-24 16:34:07 +02:00
|
|
|
public void setNibble(int index, byte[] array, int value) {
|
2016-08-20 05:33:56 +02:00
|
|
|
int indexShift = index >> 1;
|
2017-03-26 20:14:28 +02:00
|
|
|
byte existing = array[indexShift];
|
|
|
|
int valueShift = value << 4;
|
|
|
|
if (existing == value + valueShift) {
|
|
|
|
return;
|
|
|
|
}
|
2017-06-20 11:00:30 +02:00
|
|
|
if ((index & 1) == 0) {
|
|
|
|
array[indexShift] = (byte) (existing & 240 | value);
|
2016-08-20 05:33:56 +02:00
|
|
|
} else {
|
2017-06-20 11:00:30 +02:00
|
|
|
array[indexShift] = (byte) (existing & 15 | valueShift);
|
2016-08-20 05:33:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-26 21:16:27 +02:00
|
|
|
public void setIdUnsafe(byte[] idsLayer, int index, byte id) {
|
2017-03-26 20:14:28 +02:00
|
|
|
idsLayer[index] = id;
|
|
|
|
}
|
|
|
|
|
2017-03-26 21:16:27 +02:00
|
|
|
public void setBlockUnsafe(byte[] idsLayer, byte[] dataLayer, int index, byte id, int data) {
|
2017-03-26 20:14:28 +02:00
|
|
|
idsLayer[index] = id;
|
|
|
|
setNibble(index, dataLayer, data);
|
|
|
|
}
|
|
|
|
|
2016-08-20 05:33:56 +02:00
|
|
|
@Override
|
|
|
|
public void setBlock(int x, int y, int z, int id, int data) {
|
2017-04-03 12:07:57 +02:00
|
|
|
setModified();
|
2016-08-20 05:33:56 +02:00
|
|
|
int layer = y >> 4;
|
|
|
|
byte[] idsLayer = ids[layer];
|
|
|
|
if (idsLayer == null) {
|
2016-08-20 17:07:20 +02:00
|
|
|
idsLayer = this.ids[layer] = new byte[4096];
|
|
|
|
this.data[layer] = new byte[2048];
|
2017-03-14 14:42:28 +01:00
|
|
|
this.skyLight[layer] = new byte[2048];
|
|
|
|
this.blockLight[layer] = new byte[2048];
|
2016-08-20 05:33:56 +02:00
|
|
|
}
|
|
|
|
int j = FaweCache.CACHE_J[y][z & 15][x & 15];
|
|
|
|
idsLayer[j] = (byte) id;
|
|
|
|
byte[] dataLayer = this.data[layer];
|
2016-08-20 14:01:43 +02:00
|
|
|
setNibble(j, dataLayer, data);
|
2016-08-20 05:33:56 +02:00
|
|
|
}
|
|
|
|
|
2017-03-26 20:14:28 +02:00
|
|
|
@Override
|
|
|
|
public void setBiome(byte biome) {
|
|
|
|
Arrays.fill(biomes, biome);
|
|
|
|
}
|
|
|
|
|
2016-08-20 05:33:56 +02:00
|
|
|
@Override
|
|
|
|
public void removeEntity(UUID uuid) {
|
2017-04-03 12:07:57 +02:00
|
|
|
setModified();
|
2016-08-20 05:33:56 +02:00
|
|
|
entities.remove(uuid);
|
|
|
|
}
|
|
|
|
|
2017-06-26 09:56:07 +02:00
|
|
|
private final boolean idsEqual(byte[] a, byte[] b) {
|
|
|
|
// Assumes both are null, or none are (idsEqual - 2d array)
|
|
|
|
// Assumes length is 4096
|
|
|
|
if (a == b) return true;
|
|
|
|
for (char i = 0; i < 4096; i++) {
|
|
|
|
if (a[i] != b[i]) return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private final boolean idsEqual(byte[][] a, byte[][] b, boolean matchNullToAir) {
|
|
|
|
// Assumes length is 16
|
|
|
|
for (byte i = 0; i < 16; i++) {
|
|
|
|
if ((a[i] == null) != (b[i] == null)) {
|
|
|
|
if (matchNullToAir) {
|
|
|
|
if (b[i] != null) {
|
|
|
|
for (byte c : b[i]) {
|
|
|
|
if (c != 0) return false;
|
|
|
|
}
|
|
|
|
} else if (a[i] != null) {
|
|
|
|
for (byte c : a[i]) {
|
|
|
|
if (c != 0) return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Check the chunks close to the ground first
|
|
|
|
for (byte i = 4; i < 8; i++) {
|
|
|
|
if (!idsEqual(a[i], b[i])) return false;
|
|
|
|
}
|
|
|
|
for (byte i = 3; i >= 0; i--) {
|
|
|
|
if (!idsEqual(a[i], b[i])) return false;
|
|
|
|
}
|
|
|
|
for (byte i = 8; i < 16; i++) {
|
|
|
|
if (!idsEqual(a[i], b[i])) return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the ids match the ids in the other chunk
|
|
|
|
* @param other
|
|
|
|
* @param matchNullToAir
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
public boolean idsEqual(MCAChunk other, boolean matchNullToAir) {
|
|
|
|
return idsEqual(other.ids, this.ids, matchNullToAir);
|
|
|
|
}
|
|
|
|
|
2016-08-20 05:33:56 +02:00
|
|
|
@Override
|
|
|
|
public Void getChunk() {
|
|
|
|
throw new UnsupportedOperationException("Not applicable for this");
|
|
|
|
}
|
2016-09-13 07:43:23 +02:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public FaweChunk call() {
|
|
|
|
throw new UnsupportedOperationException("Not supported");
|
|
|
|
}
|
2016-08-20 05:33:56 +02:00
|
|
|
}
|