Full Data Source half done!

This commit is contained in:
TomTheFurry
2022-06-23 18:30:33 +08:00
parent bc194f8e6c
commit 0df4011a9a
12 changed files with 219 additions and 46 deletions
@@ -16,6 +16,7 @@ public interface LodDataSource {
byte getDataVersion();
// Saving related
void saveData(ILevel level, DataMetaFile file, OutputStream dataStream) throws IOException;
default File generateFilePathAndName(File levelFolderPath, ILevel level, DhSectionPos sectionPos) {
@@ -3,9 +3,11 @@ package com.seibel.lod.core.a7.datatype.full;
import com.seibel.lod.core.a7.datatype.full.accessor.FullArrayView;
public class ChunkSizedData extends FullArrayView {
private final long[][] chunkDataArray = new long[16*16][];
public ChunkSizedData() {
super(new IdBiomeBlockStateMap(), new long[16*16][0], 16);
}
public ChunkSizedData(long[][] dataArrays) {
super(dataArrays, 16);
public void setSingleColumn(long[] data, int x, int z) {
dataArrays[x*16+z] = data;
}
}
@@ -1,5 +1,7 @@
package com.seibel.lod.core.a7.datatype.full;
import com.seibel.lod.core.a7.datatype.column.ColumnRenderSource;
import com.seibel.lod.core.a7.datatype.full.accessor.FullArrayView;
import com.seibel.lod.core.a7.level.ILevel;
import com.seibel.lod.core.a7.save.io.file.DataMetaFile;
import com.seibel.lod.core.a7.datatype.LodDataSource;
@@ -12,11 +14,15 @@ import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
public class FullDataSource implements LodDataSource { // 1 chunk
private DhSectionPos sectionPos;
ArrayList<String> idMap;
protected FullDataSource() {
idMap = new ArrayList<String>();
public class FullDataSource extends FullArrayView implements LodDataSource { // 1 chunk
public static final byte SECTION_SIZE_OFFSET = ColumnRenderSource.SECTION_SIZE_OFFSET;
public static final int SECTION_SIZE = 1 << SECTION_SIZE_OFFSET;
public static final byte LATEST_VERSION = 0;
private final DhSectionPos sectionPos;
private int localVersion = 0;
protected FullDataSource(DhSectionPos sectionPos) {
super(new IdBiomeBlockStateMap(), new long[SECTION_SIZE*SECTION_SIZE][0], SECTION_SIZE);
this.sectionPos = sectionPos;
}
@Override
@@ -26,36 +32,21 @@ public class FullDataSource implements LodDataSource { // 1 chunk
@Override
public byte getDataDetail() {
return 0;
return (byte) (sectionPos.sectionDetail-SECTION_SIZE_OFFSET);
}
@Override
public void setLocalVersion(int localVer) {
localVersion = localVer;
}
@Override
public byte getDataVersion() {
return 0;
return LATEST_VERSION;
}
@Override
public void saveData(ILevel level, DataMetaFile file, OutputStream dataStream) throws IOException {
}
public static FullDataSource createNewFromChunk(IChunkWrapper chunk) {
FullDataSource dataContainer = new FullDataSource();
HashMap<String, Integer> idMap = new HashMap<String, Integer>();
idMap.put(IdMappingUtil.BLOCKSTATE_ID_AIR, 0);
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
int y = chunk.getMaxY(x, z);
String currentBlockState = IdMappingUtil.BLOCKSTATE_ID_AIR;
// FIXME: Move LodBuilder code to here
}
}
return dataContainer;
//TODO
}
}
@@ -2,35 +2,42 @@ package com.seibel.lod.core.a7.datatype.full;
// Static class for the data format:
// ID: blockState id Y: Height(signed) DP: Depth(signed?)
// BL: Block light SL: Sky light
// =======Bit layout=======
// __ __ __ __ __ __ __ __ <-- Top bits
// BL BL BL BL SL SL SL SL <-- Top bits
// YY YY YY YY YY YY YY YY
// YY YY YY YY DP DP
// DP DP DP DP DP DP DP DP DP DP
// YY YY YY YY DP DP DP DP
// DP DP DP DP DP DP DP DP
// ID ID ID ID ID ID IO ID
// ID ID ID ID ID ID IO ID
// ID ID ID ID ID ID IO ID
// ID ID ID ID ID ID IO ID <-- Bottom bits
//
import org.jetbrains.annotations.Contract;
public class FullFormat {
public static final int ID_WIDTH = 32;
public static final int DP_WIDTH = 12;
public static final int Y_WIDTH = 12;
public static final int LIGHT_WIDTH = 8;
public static final int ID_OFFSET = 0;
public static final int DP_OFFSET = ID_OFFSET + ID_WIDTH;
public static final int Y_OFFSET = DP_OFFSET + DP_WIDTH;
public static final int LIGHT_OFFSET = Y_OFFSET + Y_WIDTH;
public static final int ID_MASK = (int)Math.pow(2, ID_WIDTH) - 1;
public static final long ID_MASK = Integer.MAX_VALUE;
public static final long INVERSE_ID_MASK = ~ID_MASK;
public static final int DP_MASK = (int)Math.pow(2, DP_WIDTH) - 1;
public static final int Y_MASK = (int)Math.pow(2, Y_WIDTH) - 1;
public static long encode(int id, int depth, int y) {
public static long encode(int id, int depth, int y, byte lightPair) {
long data = 0;
data |= id & ID_MASK;
data |= (long) (depth & DP_MASK) << DP_OFFSET;
data |= (long) (y & Y_MASK) << Y_OFFSET;
data |= (long) lightPair << LIGHT_OFFSET;
return data;
}
@@ -46,4 +53,12 @@ public class FullFormat {
return (int) (data << (64 - Y_OFFSET - Y_WIDTH) >> Y_OFFSET);
}
public static byte getLight(long data) {
return (byte) (data << (64 - LIGHT_OFFSET - LIGHT_WIDTH) >> LIGHT_OFFSET);
}
@Contract(pure = true)
public static long remap(int[] mapping, long data) {
return (data & INVERSE_ID_MASK) | mapping[(int)data];
}
}
@@ -0,0 +1,57 @@
package com.seibel.lod.core.a7.datatype.full;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
// WARNING: This is not THREAD-SAFE!
public class IdBiomeBlockStateMap {
public static final class Entry {
public final IBiomeWrapper biome;
public final IBlockStateWrapper blockState;
public Entry(IBiomeWrapper biome, IBlockStateWrapper blockState) {
this.biome = biome;
this.blockState = blockState;
}
@Override
public int hashCode() {
return Objects.hash(biome, blockState);
}
}
final ArrayList<Entry> entries = new ArrayList<>();
final HashMap<Entry, Integer> idMap = new HashMap<>();
public Entry get(int id) {
return entries.get(id);
}
public int setAndGetId(IBiomeWrapper biome, IBlockStateWrapper blockState) {
return idMap.computeIfAbsent(new Entry(biome, blockState), (e) -> {
int id = entries.size();
entries.add(e);
return id;
});
}
public int setAndGetId(Entry biomeBlockStateEntry) {
return idMap.computeIfAbsent(biomeBlockStateEntry, (e) -> {
int id = entries.size();
entries.add(e);
return id;
});
}
public int[] computeAndMergeMapFrom(IdBiomeBlockStateMap target) {
ArrayList<Entry> mergeEntry = target.entries;
int[] mapper = new int[mergeEntry.size()];
for (int i=0; i<mergeEntry.size(); i++) {
mapper[i] = setAndGetId(mergeEntry.get(i));
}
return mapper;
}
//TODO: Serialization & Deserialization
}
@@ -1,16 +1,21 @@
package com.seibel.lod.core.a7.datatype.full.accessor;
public class FullArrayView implements IFullDataView {
private final long[][] dataArrays;
private final int offset;
private final int size;
import com.seibel.lod.core.a7.datatype.full.FullFormat;
import com.seibel.lod.core.a7.datatype.full.IdBiomeBlockStateMap;
public FullArrayView(long[][] dataArrays, int size) {
public class FullArrayView implements IFullDataView {
protected final long[][] dataArrays;
protected final int offset;
protected final int size;
protected final IdBiomeBlockStateMap mapping;
public FullArrayView(IdBiomeBlockStateMap mapping, long[][] dataArrays, int size) {
if (dataArrays.length != size*size)
throw new IllegalArgumentException(
"tried constructing dataArrayView with invalid input!");
this.dataArrays = dataArrays;
this.size = size;
this.mapping = mapping;
offset = 0;
}
public FullArrayView(FullArrayView source, int size, int offsetX, int offsetZ) {
@@ -19,17 +24,23 @@ public class FullArrayView implements IFullDataView {
"tried constructing dataArrayView subview with invalid input!");
dataArrays = source.dataArrays;
this.size = size;
mapping = source.mapping;
offset = source.offset + offsetX * size + offsetZ;
}
@Override
public IdBiomeBlockStateMap getMapping() {
return mapping;
}
@Override
public SingleFullArrayView get(int index) {
return new SingleFullArrayView(dataArrays, index + offset);
return new SingleFullArrayView(mapping, dataArrays, index + offset);
}
@Override
public SingleFullArrayView get(int x, int z) {
return new SingleFullArrayView(dataArrays, x*size + z + offset);
return new SingleFullArrayView(mapping, dataArrays, x*size + z + offset);
}
@Override
@@ -42,12 +53,28 @@ public class FullArrayView implements IFullDataView {
return new FullArrayView(this, size, ox, oz);
}
public void copyTo(FullArrayView target) {
//WARNING: It will potentially share the underlying array object!
public void shadowCopyTo(FullArrayView target) {
if (target.size != size)
throw new IllegalArgumentException("Target view must have same size as this view");
for (int x=0; x<size; x++) {
System.arraycopy(dataArrays, offset+x*size,
target.dataArrays, offset+x*size, size);
if (target.mapping.equals(mapping)) {
for (int x = 0; x < size; x++) {
System.arraycopy(dataArrays, offset + x * size,
target.dataArrays, offset + x * size, size);
}
}
else {
int[] map = target.mapping.computeAndMergeMapFrom(mapping);
for (int x = 0; x < size; x++) {
for (int o=x*size; o<x*size+size; o++) {
long[] sourceData = dataArrays[offset+o];
long[] newData = new long[sourceData.length];
for (int i = 0; i < newData.length; i++) {
newData[i] = FullFormat.remap(map, sourceData[i]);
}
target.dataArrays[target.offset+o] = newData;
}
}
}
}
}
@@ -1,8 +1,12 @@
package com.seibel.lod.core.a7.datatype.full.accessor;
import com.seibel.lod.core.a7.datatype.full.IdBiomeBlockStateMap;
import java.util.Iterator;
public interface IFullDataView {
IdBiomeBlockStateMap getMapping();
SingleFullArrayView get(int index);
SingleFullArrayView get(int x, int z);
int width();
@@ -1,17 +1,27 @@
package com.seibel.lod.core.a7.datatype.full.accessor;
import com.seibel.lod.core.a7.datatype.full.FullFormat;
import com.seibel.lod.core.a7.datatype.full.IdBiomeBlockStateMap;
public class SingleFullArrayView implements IFullDataView {
private final long[][] dataArrays;
private final int offset;
public SingleFullArrayView(long[][] dataArrays, int offset) {
private final IdBiomeBlockStateMap mapping;
public SingleFullArrayView(IdBiomeBlockStateMap mapping, long[][] dataArrays, int offset) {
this.dataArrays = dataArrays;
this.offset = offset;
this.mapping = mapping;
}
public boolean doesItExist() {
return dataArrays[offset].length!=0;
}
@Override
public IdBiomeBlockStateMap getMapping() {
return mapping;
}
@Override
public SingleFullArrayView get(int index) {
if (index != 0) throw new IllegalArgumentException("Only contains 1 column of full data!");
@@ -46,4 +56,19 @@ public class SingleFullArrayView implements IFullDataView {
return this;
}
//WARNING: It will potentially share the underlying array object!
public void shadowCopyTo(SingleFullArrayView target) {
if (target.mapping.equals(mapping)) {
target.dataArrays[target.offset] = dataArrays[offset];
}
else {
int[] map = target.mapping.computeAndMergeMapFrom(mapping);
long[] sourceData = dataArrays[offset];
long[] newData = new long[sourceData.length];
for (int i = 0; i < newData.length; i++) {
newData[i] = FullFormat.remap(map, sourceData[i]);
}
target.dataArrays[target.offset] = newData;
}
}
}
@@ -1,13 +1,57 @@
package com.seibel.lod.core.a7.datatype.transform;
import com.seibel.lod.core.a7.datatype.full.ChunkSizedData;
import com.seibel.lod.core.a7.datatype.full.FullFormat;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
import it.unimi.dsi.fastutil.longs.LongArrayList;
public class LodDataBuilder {
public static ChunkSizedData createChunkData(IChunkWrapper chunk) {
if (!canGenerateLodFromChunk(chunk)) return null;
ChunkSizedData chunkData = new ChunkSizedData();
for (int x=0; x<16; x++) {
for (int z=0; z<16; z++) {
LongArrayList longs = new LongArrayList(chunk.getHeight()/4);
int lastY = chunk.getMaxBuildHeight();
IBiomeWrapper biome = chunk.getBiome(x, lastY, z);
IBlockStateWrapper blockState = IBlockStateWrapper.AIR;
int mappedId = chunkData.getMapping().setAndGetId(biome, blockState);
byte light = (byte) (chunk.getBlockLight(x,lastY,z) << 4 + chunk.getSkyLight(x,lastY,z));
int y=chunk.getMaxY(x, z);
for (; y>=chunk.getMinBuildHeight(); y--) {
IBiomeWrapper newBiome = chunk.getBiome(x, y, z);
IBlockStateWrapper newBlockState = chunk.getBlockState(x, y, z);
byte newLight = (byte) (chunk.getBlockLight(x,y,z) << 4 + chunk.getSkyLight(x,y,z));
if (!newBiome.equals(biome) || !newBlockState.equals(blockState)) {
longs.add(FullFormat.encode(mappedId, lastY-y+1, y+1, light));
biome = newBiome;
blockState = newBlockState;
mappedId = chunkData.getMapping().setAndGetId(biome, blockState);
light = newLight;
lastY = y;
} else if (newLight != light) {
longs.add(FullFormat.encode(mappedId, lastY-y+1, y+1, light));
light = newLight;
lastY = y;
}
}
longs.add(FullFormat.encode(mappedId, lastY-y+1, y+1, light));
chunkData.setSingleColumn(longs.toArray((long[]) null), x, z);
}
}
return chunkData;
}
public static boolean canGenerateLodFromChunk(IChunkWrapper chunk)
{
return chunk != null &&
chunk.isLightCorrect();
}
}
@@ -215,7 +215,6 @@ public class LodBuilder
return chunk != null && chunk.isLightCorrect() && chunk.doesNearbyChunksExist();
}
private boolean writeAllLodNodeData(LodDimension lodDim, LodRegion region, int chunkX, int chunkZ,
long[] data, LodBuilderConfig config, boolean override)
{
@@ -0,0 +1,5 @@
package com.seibel.lod.core.wrapperInterfaces.block;
public interface IBlockStateWrapper {
IBlockStateWrapper AIR = null;
}
@@ -23,6 +23,7 @@ import com.seibel.lod.core.enums.ELodDirection;
import com.seibel.lod.core.handlers.dependencyInjection.IBindable;
import com.seibel.lod.core.util.LodUtil;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockDetailWrapper;
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
/**
@@ -99,4 +100,6 @@ public interface IChunkWrapper extends IBindable
return hash;
}
IBlockStateWrapper getBlockState(int x, int y, int z);
}