Forcefully integrate a mangled DataPalette from NMS into a NBTMCA API

This commit is contained in:
cyberpwn 2021-08-24 23:16:01 -04:00
parent 861e11a713
commit d5da8e4e2b
6 changed files with 77 additions and 268 deletions

View File

@ -688,14 +688,4 @@ public class Chunk {
public int sectionCount() {
return sections.length();
}
public void runLighting() {
for (int s = 15; s >= 0; s--) {
Section section = getSection(s);
if (section != null) {
section.runLighting();
}
}
}
}

View File

@ -20,12 +20,13 @@ package com.volmit.iris.util.nbt.mca;
import com.volmit.iris.Iris;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.nbt.mca.palettes.DataPaletteBlock;
import com.volmit.iris.util.nbt.tag.ByteArrayTag;
import com.volmit.iris.util.nbt.tag.CompoundTag;
import com.volmit.iris.util.nbt.tag.ListTag;
import com.volmit.iris.util.nbt.tag.LongArrayTag;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import net.minecraft.world.level.chunk.DataPaletteGlobal;
import net.minecraft.world.level.chunk.Chunk;
import java.util.ArrayList;
import java.util.HashMap;
@ -35,10 +36,8 @@ import java.util.concurrent.atomic.AtomicLongArray;
public class Section {
private CompoundTag data;
private Map<String, List<PaletteIndex>> valueIndexedPalette = new KMap<>();
private ListTag<CompoundTag> palette;
private DataPaletteBlock<CompoundTag> palette;
private byte[] blockLight;
private AtomicLongArray blockStates;
private byte[] skyLight;
private int dataVersion;
@ -53,72 +52,18 @@ public class Section {
if (rawPalette == null) {
return;
}
palette = rawPalette.asCompoundTagList();
for (int i = 0; i < palette.size(); i++) {
CompoundTag data = palette.get(i);
putValueIndexedPalette(data, i);
}
palette.makeAtomic();
ByteArrayTag blockLight = sectionRoot.getByteArrayTag("BlockLight");
palette = new DataPaletteBlock<>();
LongArrayTag blockStates = sectionRoot.getLongArrayTag("BlockStates");
palette.a((ListTag<CompoundTag>) rawPalette, blockStates.getValue());
ByteArrayTag blockLight = sectionRoot.getByteArrayTag("BlockLight");
ByteArrayTag skyLight = sectionRoot.getByteArrayTag("SkyLight");
if ((loadFlags & LoadFlags.BLOCK_LIGHTS) != 0) {
this.blockLight = blockLight != null ? blockLight.getValue() : null;
}
if ((loadFlags & LoadFlags.BLOCK_STATES) != 0) {
this.blockStates = blockStates != null ? new AtomicLongArray(blockStates.getValue()) : null;
}
if ((loadFlags & LoadFlags.SKY_LIGHT) != 0) {
this.skyLight = skyLight != null ? skyLight.getValue() : null;
}
}
Section() {
}
void putValueIndexedPalette(CompoundTag data, int index) {
PaletteIndex leaf = new PaletteIndex(data, index);
String name = data.getString("Name");
List<PaletteIndex> leaves = valueIndexedPalette.get(name);
if (leaves == null) {
leaves = new ArrayList<>(1);
leaves.add(leaf);
valueIndexedPalette.put(name, leaves);
} else {
for (PaletteIndex pal : leaves) {
if (pal.data.equals(data)) {
return;
}
}
leaves.add(leaf);
}
}
PaletteIndex getValueIndexedPalette(CompoundTag data) {
List<PaletteIndex> leaves = valueIndexedPalette.get(data.getString("Name"));
if (leaves == null) {
return null;
}
for (PaletteIndex leaf : leaves) {
if (leaf.data.equals(data)) {
return leaf;
}
}
return null;
}
public void runLighting() {
for (int x = 1; x < 14; x++) {
for (int z = 1; z < 14; z++) {
for (int y = 0; y < 16; y++) {
}
}
}
}
@SuppressWarnings("ClassCanBeRecord")
private static class PaletteIndex {
@ -150,16 +95,7 @@ public class Section {
* @return The block state data of this block.
*/
public synchronized CompoundTag getBlockStateAt(int blockX, int blockY, int blockZ) {
try {
int index = getBlockIndex(blockX, blockY, blockZ);
int paletteIndex = getPaletteIndex(index);
return palette.get(paletteIndex);
} catch (Throwable ignored) {
Iris.reportError(ignored);
}
return null;
return palette.a(blockX, blockY, blockZ);
}
/**
@ -169,52 +105,17 @@ public class Section {
* @param blockY The y-coordinate of the block in this Section
* @param blockZ The z-coordinate of the block in this Section
* @param state The block state to be set
* @param cleanup When <code>true</code>, it will cleanup the palette of this section.
* This option should only be used moderately to avoid unnecessary recalculation of the palette indices.
* Recalculating the Palette should only be executed once right before saving the Section to file.
*/
public synchronized void setBlockStateAt(int blockX, int blockY, int blockZ, CompoundTag state, boolean cleanup) {
int paletteIndex = addToPalette(state);
int paletteSizeBefore = palette.size();
//power of 2 --> bits must increase, but only if the palette size changed
//otherwise we would attempt to update all blockstates and the entire palette
//every time an existing blockstate was added while having 2^x blockstates in the palette
if (paletteSizeBefore != palette.size() && (paletteIndex & (paletteIndex - 1)) == 0) {
adjustBlockStateBits(null, blockStates);
cleanup = true;
if(cleanup)
{
palette.setBlock(blockX, blockY, blockZ, state);
}
setPaletteIndex(getBlockIndex(blockX, blockY, blockZ), paletteIndex, blockStates);
if (cleanup) {
cleanupPaletteAndBlockStates();
}
}
/**
* Returns the index of the block data in the palette.
*
* @param blockStateIndex The index of the block in this section, ranging from 0-4095.
* @return The index of the block data in the palette.
*/
public synchronized int getPaletteIndex(int blockStateIndex) {
int bits = blockStates.length() >> 6;
if (dataVersion < 2527) {
double blockStatesIndex = blockStateIndex / (4096D / blockStates.length());
int longIndex = (int) blockStatesIndex;
int startBit = (int) ((blockStatesIndex - Math.floor(blockStatesIndex)) * 64D);
if (startBit + bits > 64) {
long prev = bitRange(blockStates.get(longIndex), startBit, 64);
long next = bitRange(blockStates.get(longIndex + 1), 0, startBit + bits - 64);
return (int) ((next << 64 - startBit) + prev);
} else {
return (int) bitRange(blockStates.get(longIndex), startBit, startBit + bits);
}
} else {
int indicesPerLong = (int) (64D / bits);
int blockStatesIndex = blockStateIndex / indicesPerLong;
int startBit = (blockStateIndex % indicesPerLong) * bits;
return (int) bitRange(blockStates.get(blockStatesIndex), startBit, startBit + bits);
else
{
palette.b(blockX, blockY, blockZ, state);
}
}
@ -246,25 +147,6 @@ public class Section {
}
}
/**
* Fetches the palette of this Section.
*
* @return The palette of this Section.
*/
public synchronized ListTag<CompoundTag> getPalette() {
return palette;
}
synchronized int addToPalette(CompoundTag data) {
PaletteIndex index;
if ((index = getValueIndexedPalette(data)) != null) {
return index.index;
}
palette.add(data);
putValueIndexedPalette(data, palette.size() - 1);
return palette.size() - 1;
}
int getBlockIndex(int blockX, int blockY, int blockZ) {
return (blockY & 0xF) * 256 + (blockZ & 0xF) * 16 + (blockX & 0xF);
}
@ -285,63 +167,8 @@ public class Section {
* This should only be used moderately to avoid unnecessary recalculation of the palette indices.
* Recalculating the Palette should only be executed once right before saving the Section to file.
*/
public synchronized void cleanupPaletteAndBlockStates() {
Map<Integer, Integer> oldToNewMapping = cleanupPalette();
adjustBlockStateBits(oldToNewMapping, blockStates);
}
public void cleanupPaletteAndBlockStates() {
private synchronized Map<Integer, Integer> cleanupPalette() {
//create index - palette mapping
Map<Integer, Integer> allIndices = new Int2IntOpenHashMap();
for (int i = 0; i < 4096; i++) {
int paletteIndex = getPaletteIndex(i);
allIndices.put(paletteIndex, paletteIndex);
}
//delete unused blocks from palette
//start at index 1 because we need to keep minecraft:air
int index = 1;
valueIndexedPalette = new HashMap<>(valueIndexedPalette.size());
putValueIndexedPalette(palette.get(0), 0);
for (int i = 1; i < palette.size(); i++) {
if (!allIndices.containsKey(index)) {
palette.remove(i);
i--;
} else {
putValueIndexedPalette(palette.get(i), i);
allIndices.put(index, i);
}
index++;
}
return allIndices;
}
synchronized void adjustBlockStateBits(Map<Integer, Integer> oldToNewMapping, AtomicLongArray blockStates) {
//increases or decreases the amount of bits used per BlockState
//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().
int newBits = 32 - Integer.numberOfLeadingZeros(palette.size() - 1);
newBits = Math.max(newBits, 4);
AtomicLongArray newBlockStates;
if (dataVersion < 2527) {
newBlockStates = newBits == blockStates.length() / 64 ? blockStates : new AtomicLongArray(newBits * 64);
} else {
int newLength = (int) Math.ceil(4096D / (64D / newBits));
newBlockStates = newBits == blockStates.length() / 64 ? blockStates : new AtomicLongArray(newLength);
}
if (oldToNewMapping != null) {
for (int i = 0; i < 4096; i++) {
setPaletteIndex(i, oldToNewMapping.get(getPaletteIndex(i)), newBlockStates);
}
} else {
for (int i = 0; i < 4096; i++) {
setPaletteIndex(i, getPaletteIndex(i), newBlockStates);
}
}
this.blockStates = newBlockStates;
}
/**
@ -364,29 +191,6 @@ public class Section {
this.blockLight = blockLight;
}
/**
* @return The indices of the block states of this Section.
*/
public synchronized AtomicLongArray getBlockStates() {
return blockStates;
}
/**
* Sets the block state indices to a custom value.
*
* @param blockStates The block state indices.
* @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
*/
public void setBlockStates(AtomicLongArray blockStates) {
if (blockStates == null) {
throw new NullPointerException("BlockStates cannot be null");
} 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");
}
this.blockStates = blockStates;
}
/**
* @return The sky light values of this Section
*/
@ -414,11 +218,7 @@ public class Section {
*/
public static Section newSection() {
Section s = new Section();
s.blockStates = new AtomicLongArray(256);
s.palette = new ListTag<>(CompoundTag.class);
CompoundTag air = new CompoundTag();
air.putString("Name", "minecraft:air");
s.palette.add(air);
s.palette = new DataPaletteBlock<>();
s.data = new CompoundTag();
return s;
}
@ -434,20 +234,12 @@ public class Section {
public synchronized CompoundTag updateHandle(int y) {
data.putByte("Y", (byte) y);
if (palette != null) {
data.put("Palette", palette);
data.put("Palette", palette.getK().getPalette());
data.putLongArray("BlockStates", palette.getC().a());
}
if (blockLight != null) {
data.putByteArray("BlockLight", blockLight);
}
if (blockStates != null) {
long[] c = new long[blockStates.length()];
for (int i = 0; i < c.length; i++) {
c[i] = blockStates.get(i);
}
data.putLongArray("BlockStates", c);
}
if (skyLight != null) {
data.putByteArray("SkyLight", skyLight);
}

View File

@ -35,4 +35,6 @@ public interface DataPalette<T> {
int b();
void a(ListTag<CompoundTag> t);
ListTag<CompoundTag> getPalette();
}

View File

@ -19,16 +19,20 @@
package com.volmit.iris.util.nbt.mca.palettes;
import com.volmit.iris.util.math.MathHelper;
import com.volmit.iris.util.nbt.mca.NBTWorld;
import com.volmit.iris.util.nbt.tag.CompoundTag;
import com.volmit.iris.util.nbt.tag.ListTag;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import lombok.Getter;
import net.minecraft.network.PacketDataSerializer;
import org.bukkit.Material;
import java.util.concurrent.Semaphore;
import java.util.function.Function;
import java.util.function.Predicate;
@Getter
public class DataPaletteBlock<T> implements DataPaletteExpandable<T> {
private static final int d = 4096;
public static final int a = 9;
@ -41,16 +45,26 @@ public class DataPaletteBlock<T> implements DataPaletteExpandable<T> {
private final Function<CompoundTag, T> h;
private final Function<T, CompoundTag> i;
private final T j;
private static final RegistryBlockID<CompoundTag> registry = new RegistryBlockID<>();
private static final CompoundTag air = NBTWorld.getCompound(Material.AIR.createBlockData());
protected DataBits c;
private DataPalette<T> k;
private int l;
private int bits;
private final Semaphore m = new Semaphore(1);
public void b() {
this.m.release();
}
public DataPaletteBlock(DataPalette<T> var0, RegistryBlockID<T> var1, Function<CompoundTag, T> var2, Function<T, CompoundTag> var3, T var4) {
public DataPaletteBlock() {
this(null, (RegistryBlockID<T>) registry, (i) -> (T) i, (i) -> (CompoundTag) i, (T) air);
}
public DataPaletteBlock(DataPalette<T> var0,
RegistryBlockID<T> var1,
Function<CompoundTag, T> var2,
Function<T, CompoundTag> var3,
T var4) {
this.e = var0;
this.g = var1;
this.h = var2;
@ -64,20 +78,20 @@ public class DataPaletteBlock<T> implements DataPaletteExpandable<T> {
}
private void b(int var0) {
if (var0 != this.l) {
this.l = var0;
if (this.l <= 4) {
this.l = 4;
this.k = new DataPaletteLinear<T>(this.g, this.l, this, this.h);
} else if (this.l < 9) {
this.k = new DataPaletteHash<T>(this.g, this.l, this, this.h, this.i);
if (var0 != this.bits) {
this.bits = var0;
if (this.bits <= 4) {
this.bits = 4;
this.k = new DataPaletteLinear<T>(this.g, this.bits, this, this.h);
} else if (this.bits < 9) {
this.k = new DataPaletteHash<T>(this.g, this.bits, this, this.h, this.i);
} else {
this.k = this.e;
this.l = MathHelper.e(this.g.a());
this.bits = MathHelper.e(this.g.a());
}
this.k.a(this.j);
this.c = new DataBits(this.l, 4096);
this.c = new DataBits(this.bits, 4096);
}
}
@ -140,27 +154,27 @@ public class DataPaletteBlock<T> implements DataPaletteExpandable<T> {
return var1 == null ? this.j : var1;
}
public void a(ListTag<CompoundTag> var0, long[] var1) {
public void a(ListTag<CompoundTag> palettedata, long[] databits) {
try {
int var2 = Math.max(4, MathHelper.e(var0.size()));
if (var2 != this.l) {
int var2 = Math.max(4, MathHelper.e(palettedata.size()));
if (var2 != this.bits) {
this.b(var2);
}
this.k.a(var0);
int var3 = var1.length * 64 / 4096;
this.k.a(palettedata);
int var3 = databits.length * 64 / 4096;
if (this.k == this.e) {
DataPalette<T> var4 = new DataPaletteHash(this.g, var2, this.f, this.h, this.i);
var4.a(var0);
DataBits var5 = new DataBits(var2, 4096, var1);
DataPalette<T> var4 = new DataPaletteHash<T>(this.g, var2, this.f, this.h, this.i);
var4.a(palettedata);
DataBits var5 = new DataBits(var2, 4096, databits);
for (int var6 = 0; var6 < 4096; ++var6) {
this.c.b(var6, this.e.a(var4.a(var5.a(var6))));
}
} else if (var3 == this.l) {
System.arraycopy(var1, 0, this.c.a(), 0, var1.length);
} else if (var3 == this.bits) {
System.arraycopy(databits, 0, this.c.a(), 0, databits.length);
} else {
DataBits var4 = new DataBits(var3, 4096, var1);
DataBits var4 = new DataBits(var3, 4096, databits);
for (int var5 = 0; var5 < 4096; ++var5) {
this.c.b(var5, var4.a(var5));
@ -169,12 +183,11 @@ public class DataPaletteBlock<T> implements DataPaletteExpandable<T> {
} finally {
this.b();
}
}
public void a(CompoundTag var0, String var1, String var2) {
try {
DataPaletteHash<T> var3 = new DataPaletteHash(this.g, this.l, this.f, this.h, this.i);
DataPaletteHash<T> var3 = new DataPaletteHash(this.g, this.bits, this.f, this.h, this.i);
T var4 = this.j;
int var5 = var3.a(this.j);
int[] var6 = new int[4096];
@ -215,12 +228,8 @@ public class DataPaletteBlock<T> implements DataPaletteExpandable<T> {
public void a(DataPaletteBlock.a<T> var0) {
Int2IntMap var1 = new Int2IntOpenHashMap();
this.c.a((var1x) -> {
var1.put(var1x, var1.get(var1x) + 1);
});
var1.int2IntEntrySet().forEach((var1x) -> {
var0.accept(this.k.a(var1x.getIntKey()), var1x.getIntValue());
});
this.c.a((var1x) -> var1.put(var1x, var1.get(var1x) + 1));
var1.int2IntEntrySet().forEach((var1x) -> var0.accept(this.k.a(var1x.getIntKey()), var1x.getIntValue()));
}
@FunctionalInterface

View File

@ -110,6 +110,11 @@ public class DataPaletteHash<T> implements DataPalette<T> {
}
}
@Override
public ListTag<CompoundTag> getPalette() {
return null;
}
public void b(ListTag<CompoundTag> var0) {
for (int var1 = 0; var1 < this.b(); ++var1) {
var0.add(this.e.apply(this.b.fromId(var1)));

View File

@ -112,4 +112,15 @@ public class DataPaletteLinear<T> implements DataPalette<T> {
this.f = var0.size();
}
@Override
public ListTag<CompoundTag> getPalette() {
ListTag<CompoundTag> c = (ListTag<CompoundTag>) ListTag.createUnchecked(CompoundTag.class);
for(T i : b)
{
c.add((CompoundTag) i);
}
return c;
}
}