Atomic MCA Data

This commit is contained in:
Daniel Mills 2021-07-22 20:27:15 -04:00
parent 7d56164882
commit 42e02a6129

View File

@ -25,18 +25,22 @@ import com.volmit.iris.engine.data.nbt.tag.ListTag;
import com.volmit.iris.engine.data.nbt.tag.LongArrayTag; import com.volmit.iris.engine.data.nbt.tag.LongArrayTag;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicLongArray;
public class Section { public class Section {
private static final Field longArrayStealer = getLongArrayValueField();
private CompoundTag data; private CompoundTag data;
private Map<String, List<PaletteIndex>> valueIndexedPalette = new KMap<>(); private Map<String, List<PaletteIndex>> valueIndexedPalette = new KMap<>();
private ListTag<CompoundTag> palette; private ListTag<CompoundTag> palette;
private byte[] blockLight; private byte[] blockLight;
private long[] blockStates; private AtomicLongArray blockStates;
private byte[] skyLight; private byte[] skyLight;
private int dataVersion; private int dataVersion;
@ -65,7 +69,7 @@ public class Section {
this.blockLight = blockLight != null ? blockLight.getValue() : null; this.blockLight = blockLight != null ? blockLight.getValue() : null;
} }
if ((loadFlags & LoadFlags.BLOCK_STATES) != 0) { if ((loadFlags & LoadFlags.BLOCK_STATES) != 0) {
this.blockStates = blockStates != null ? blockStates.getValue() : null; this.blockStates = blockStates != null ? new AtomicLongArray(blockStates.getValue()) : null;
} }
if ((loadFlags & LoadFlags.SKY_LIGHT) != 0) { if ((loadFlags & LoadFlags.SKY_LIGHT) != 0) {
this.skyLight = skyLight != null ? skyLight.getValue() : null; this.skyLight = skyLight != null ? skyLight.getValue() : null;
@ -185,24 +189,24 @@ public class Section {
* @return The index of the block data in the palette. * @return The index of the block data in the palette.
*/ */
public int getPaletteIndex(int blockStateIndex) { public int getPaletteIndex(int blockStateIndex) {
int bits = blockStates.length >> 6; int bits = blockStates.length() >> 6;
if (dataVersion < 2527) { if (dataVersion < 2527) {
double blockStatesIndex = blockStateIndex / (4096D / blockStates.length); double blockStatesIndex = blockStateIndex / (4096D / blockStates.length());
int longIndex = (int) blockStatesIndex; int longIndex = (int) blockStatesIndex;
int startBit = (int) ((blockStatesIndex - Math.floor(blockStatesIndex)) * 64D); int startBit = (int) ((blockStatesIndex - Math.floor(blockStatesIndex)) * 64D);
if (startBit + bits > 64) { if (startBit + bits > 64) {
long prev = bitRange(blockStates[longIndex], startBit, 64); long prev = bitRange(blockStates.get(longIndex), startBit, 64);
long next = bitRange(blockStates[longIndex + 1], 0, startBit + bits - 64); long next = bitRange(blockStates.get(longIndex + 1), 0, startBit + bits - 64);
return (int) ((next << 64 - startBit) + prev); return (int) ((next << 64 - startBit) + prev);
} else { } else {
return (int) bitRange(blockStates[longIndex], startBit, startBit + bits); return (int) bitRange(blockStates.get(longIndex), startBit, startBit + bits);
} }
} else { } else {
int indicesPerLong = (int) (64D / bits); int indicesPerLong = (int) (64D / bits);
int blockStatesIndex = blockStateIndex / indicesPerLong; int blockStatesIndex = blockStateIndex / indicesPerLong;
int startBit = (blockStateIndex % indicesPerLong) * bits; int startBit = (blockStateIndex % indicesPerLong) * bits;
return (int) bitRange(blockStates[blockStatesIndex], startBit, startBit + bits); return (int) bitRange(blockStates.get(blockStatesIndex), startBit, startBit + bits);
} }
} }
@ -213,24 +217,24 @@ public class Section {
* @param paletteIndex The block state to be set (index of block data in the palette). * @param paletteIndex The block state to be set (index of block data in the palette).
* @param blockStates The block states to be updated. * @param blockStates The block states to be updated.
*/ */
public void setPaletteIndex(int blockIndex, int paletteIndex, long[] blockStates) { public void setPaletteIndex(int blockIndex, int paletteIndex, AtomicLongArray blockStates) {
int bits = blockStates.length >> 6; int bits = blockStates.length() >> 6;
if (dataVersion < 2527) { if (dataVersion < 2527) {
double blockStatesIndex = blockIndex / (4096D / blockStates.length); double blockStatesIndex = blockIndex / (4096D / blockStates.length());
int longIndex = (int) blockStatesIndex; int longIndex = (int) blockStatesIndex;
int startBit = (int) ((blockStatesIndex - Math.floor(longIndex)) * 64D); int startBit = (int) ((blockStatesIndex - Math.floor(longIndex)) * 64D);
if (startBit + bits > 64) { if (startBit + bits > 64) {
blockStates[longIndex] = updateBits(blockStates[longIndex], paletteIndex, startBit, 64); blockStates.set(longIndex, updateBits(blockStates.get(longIndex), paletteIndex, startBit, 64));
blockStates[longIndex + 1] = updateBits(blockStates[longIndex + 1], paletteIndex, startBit - 64, startBit + bits - 64); blockStates.set(longIndex + 1, updateBits(blockStates.get(longIndex + 1), paletteIndex, startBit - 64, startBit + bits - 64));
} else { } else {
blockStates[longIndex] = updateBits(blockStates[longIndex], paletteIndex, startBit, startBit + bits); blockStates.set(longIndex, updateBits(blockStates.get(longIndex), paletteIndex, startBit, startBit + bits));
} }
} else { } else {
int indicesPerLong = (int) (64D / bits); int indicesPerLong = (int) (64D / bits);
int blockStatesIndex = blockIndex / indicesPerLong; int blockStatesIndex = blockIndex / indicesPerLong;
int startBit = (blockIndex % indicesPerLong) * bits; int startBit = (blockIndex % indicesPerLong) * bits;
blockStates[blockStatesIndex] = updateBits(blockStates[blockStatesIndex], paletteIndex, startBit, startBit + bits); blockStates.set(blockStatesIndex, updateBits(blockStates.get(blockStatesIndex), paletteIndex, startBit, startBit + bits));
} }
} }
@ -304,7 +308,7 @@ public class Section {
return allIndices; return allIndices;
} }
void adjustBlockStateBits(Map<Integer, Integer> oldToNewMapping, long[] blockStates) { void adjustBlockStateBits(Map<Integer, Integer> oldToNewMapping, AtomicLongArray blockStates) {
//increases or decreases the amount of bits used per BlockState //increases or decreases the amount of bits used per BlockState
//based on the size of the palette. oldToNewMapping can be used to update indices //based on the size of the palette. oldToNewMapping can be used to update indices
//if the palette had been cleaned up before using MCAFile#cleanupPalette(). //if the palette had been cleaned up before using MCAFile#cleanupPalette().
@ -312,13 +316,13 @@ public class Section {
int newBits = 32 - Integer.numberOfLeadingZeros(palette.size() - 1); int newBits = 32 - Integer.numberOfLeadingZeros(palette.size() - 1);
newBits = Math.max(newBits, 4); newBits = Math.max(newBits, 4);
long[] newBlockStates; AtomicLongArray newBlockStates;
if (dataVersion < 2527) { if (dataVersion < 2527) {
newBlockStates = newBits == blockStates.length / 64 ? blockStates : new long[newBits * 64]; newBlockStates = newBits == blockStates.length() / 64 ? blockStates : new AtomicLongArray(newBits * 64);
} else { } else {
int newLength = (int) Math.ceil(4096D / (64D / newBits)); int newLength = (int) Math.ceil(4096D / (64D / newBits));
newBlockStates = newBits == blockStates.length / 64 ? blockStates : new long[newLength]; newBlockStates = newBits == blockStates.length() / 64 ? blockStates : new AtomicLongArray(newLength);
} }
if (oldToNewMapping != null) { if (oldToNewMapping != null) {
for (int i = 0; i < 4096; i++) { for (int i = 0; i < 4096; i++) {
@ -355,7 +359,7 @@ public class Section {
/** /**
* @return The indices of the block states of this Section. * @return The indices of the block states of this Section.
*/ */
public long[] getBlockStates() { public AtomicLongArray getBlockStates() {
return blockStates; return blockStates;
} }
@ -366,10 +370,10 @@ public class Section {
* @throws NullPointerException If <code>blockStates</code> is <code>null</code> * @throws NullPointerException If <code>blockStates</code> is <code>null</code>
* @throws IllegalArgumentException When <code>blockStates</code>' length is &lt; 256 or &gt; 4096 and is not a multiple of 64 * @throws IllegalArgumentException When <code>blockStates</code>' length is &lt; 256 or &gt; 4096 and is not a multiple of 64
*/ */
public void setBlockStates(long[] blockStates) { public void setBlockStates(AtomicLongArray blockStates) {
if (blockStates == null) { if (blockStates == null) {
throw new NullPointerException("BlockStates cannot be null"); throw new NullPointerException("BlockStates cannot be null");
} else if (blockStates.length % 64 != 0 || blockStates.length < 256 || blockStates.length > 4096) { } else if (blockStates.length() % 64 != 0 || blockStates.length() < 256 || blockStates.length() > 4096) {
throw new IllegalArgumentException("BlockStates must have a length > 255 and < 4097 and must be divisible by 64"); throw new IllegalArgumentException("BlockStates must have a length > 255 and < 4097 and must be divisible by 64");
} }
this.blockStates = blockStates; this.blockStates = blockStates;
@ -402,7 +406,7 @@ public class Section {
*/ */
public static Section newSection() { public static Section newSection() {
Section s = new Section(); Section s = new Section();
s.blockStates = new long[256]; s.blockStates = new AtomicLongArray(256);
s.palette = new ListTag<>(CompoundTag.class); s.palette = new ListTag<>(CompoundTag.class);
CompoundTag air = new CompoundTag(); CompoundTag air = new CompoundTag();
air.putString("Name", "minecraft:air"); air.putString("Name", "minecraft:air");
@ -428,11 +432,27 @@ public class Section {
data.putByteArray("BlockLight", blockLight); data.putByteArray("BlockLight", blockLight);
} }
if (blockStates != null) { if (blockStates != null) {
data.putLongArray("BlockStates", blockStates); try {
data.putLongArray("BlockStates", (long[]) longArrayStealer.get(blockStates));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} }
if (skyLight != null) { if (skyLight != null) {
data.putByteArray("SkyLight", skyLight); data.putByteArray("SkyLight", skyLight);
} }
return data; return data;
} }
private static Field getLongArrayValueField() {
Field f = null;
try {
f = AtomicLongArray.class.getDeclaredField("array");
f.setAccessible(true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return f;
}
} }