From a082f2ae86859fc328fee18cc462c2424798e662 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Fri, 30 Sep 2022 20:20:22 -0500 Subject: [PATCH] basic reformatting --- .../lod/core/datatype/ILodDataSource.java | 2 +- .../core/datatype/full/ChunkSizedData.java | 64 +-- .../core/datatype/full/FullDataLoader.java | 9 +- .../core/datatype/full/FullDataSource.java | 446 ++++++++++-------- .../datatype/full/IdBiomeBlockStateMap.java | 200 ++++---- .../datatype/full/accessor/FullArrayView.java | 195 ++++---- .../datatype/full/accessor/IFullDataView.java | 58 ++- .../full/accessor/SingleFullArrayView.java | 195 ++++---- 8 files changed, 639 insertions(+), 530 deletions(-) diff --git a/core/src/main/java/com/seibel/lod/core/datatype/ILodDataSource.java b/core/src/main/java/com/seibel/lod/core/datatype/ILodDataSource.java index 02df54985..35d90e003 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/ILodDataSource.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/ILodDataSource.java @@ -20,6 +20,6 @@ public interface ILodDataSource boolean isEmpty(); - // Saving related void saveData(IDhLevel level, DataMetaFile file, OutputStream dataStream) throws IOException; + } diff --git a/core/src/main/java/com/seibel/lod/core/datatype/full/ChunkSizedData.java b/core/src/main/java/com/seibel/lod/core/datatype/full/ChunkSizedData.java index f78754f92..85badb245 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/full/ChunkSizedData.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/full/ChunkSizedData.java @@ -3,34 +3,38 @@ package com.seibel.lod.core.datatype.full; import com.seibel.lod.core.datatype.full.accessor.FullArrayView; import com.seibel.lod.core.pos.DhLodPos; -public class ChunkSizedData extends FullArrayView { - public final byte dataDetail; - public final int x; - public final int z; - public ChunkSizedData(byte dataDetail, int x, int z) { - super(new IdBiomeBlockStateMap(), new long[16*16][0], 16); - this.dataDetail = dataDetail; - this.x = x; - this.z = z; - } - - public void setSingleColumn(long[] data, int x, int z) { - dataArrays[x*16+z] = data; - } - - public long nonEmptyCount() { - long count = 0; - for (long[] data : dataArrays) { - if (data.length != 0) - count += 1; - } - return count; - } - public long emptyCount() { - return 16*16 - nonEmptyCount(); - } - - public DhLodPos getBBoxLodPos() { - return new DhLodPos((byte) (dataDetail+4), x, z); - } +public class ChunkSizedData extends FullArrayView +{ + public final byte dataDetail; + public final int x; + public final int z; + + public ChunkSizedData(byte dataDetail, int x, int z) + { + super(new IdBiomeBlockStateMap(), new long[16 * 16][0], 16); + this.dataDetail = dataDetail; + this.x = x; + this.z = z; + } + + public void setSingleColumn(long[] data, int x, int z) + { + dataArrays[x * 16 + z] = data; + } + + public long nonEmptyCount() + { + long count = 0; + for (long[] data : dataArrays) + { + if (data.length != 0) + count += 1; + } + return count; + } + + public long emptyCount() { return 16 * 16 - nonEmptyCount(); } + + public DhLodPos getBBoxLodPos() { return new DhLodPos((byte) (dataDetail + 4), x, z); } + } \ No newline at end of file diff --git a/core/src/main/java/com/seibel/lod/core/datatype/full/FullDataLoader.java b/core/src/main/java/com/seibel/lod/core/datatype/full/FullDataLoader.java index 90d883268..9b7d96e80 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/full/FullDataLoader.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/full/FullDataLoader.java @@ -10,13 +10,16 @@ import java.io.InputStream; public class FullDataLoader extends AbstractDataSourceLoader { - public FullDataLoader() { + public FullDataLoader() + { super(FullDataSource.class, FullDataSource.TYPE_ID, new byte[]{FullDataSource.LATEST_VERSION}); } - + @Override - public ILodDataSource loadData(DataMetaFile dataFile, InputStream data, IDhLevel level) throws IOException { + public ILodDataSource loadData(DataMetaFile dataFile, InputStream data, IDhLevel level) throws IOException + { //TODO: Add decompressor here return FullDataSource.loadData(dataFile, data, level); } + } diff --git a/core/src/main/java/com/seibel/lod/core/datatype/full/FullDataSource.java b/core/src/main/java/com/seibel/lod/core/datatype/full/FullDataSource.java index b20074367..732dab911 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/full/FullDataSource.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/full/FullDataSource.java @@ -17,223 +17,263 @@ import java.io.*; public class FullDataSource extends FullArrayView implements ILodDataSource { // 1 chunk + private static final Logger LOGGER = DhLoggerBuilder.getLogger(); public static final byte SECTION_SIZE_OFFSET = 6; public static final int SECTION_SIZE = 1 << SECTION_SIZE_OFFSET; public static final byte LATEST_VERSION = 0; public static final long TYPE_ID = "FullDataSource".hashCode(); + private final DhSectionPos sectionPos; private boolean isEmpty = true; - protected FullDataSource(DhSectionPos sectionPos) { + + + + protected FullDataSource(DhSectionPos sectionPos) + { super(new IdBiomeBlockStateMap(), new long[SECTION_SIZE*SECTION_SIZE][0], SECTION_SIZE); this.sectionPos = sectionPos; } + + + + @Override + public DhSectionPos getSectionPos() { return sectionPos; } + @Override + public byte getDataDetail() { return (byte) (sectionPos.sectionDetail-SECTION_SIZE_OFFSET); } @Override - public DhSectionPos getSectionPos() { - return sectionPos; - } - @Override - public byte getDataDetail() { - return (byte) (sectionPos.sectionDetail-SECTION_SIZE_OFFSET); - } + public byte getDataVersion() { return LATEST_VERSION; } + + @Override + public void update(ChunkSizedData data) + { + LodUtil.assertTrue(sectionPos.getSectionBBoxPos().overlaps(data.getBBoxLodPos())); + if (data.dataDetail == 0 && getDataDetail() == 0) + { + DhBlockPos2D chunkBlockPos = new DhBlockPos2D(data.x * 16, data.z * 16); + DhBlockPos2D blockOffset = chunkBlockPos.subtract(sectionPos.getCorner().getCorner()); + LodUtil.assertTrue(blockOffset.x >= 0 && blockOffset.x < SECTION_SIZE && blockOffset.z >= 0 && blockOffset.z < SECTION_SIZE); + isEmpty = false; + data.shadowCopyTo(this.subView(16, blockOffset.x, blockOffset.z)); + { // DEBUG ASSERTION + for (int x = 0; x < 16; x++) + { + for (int z = 0; z < 16; z++) + { + SingleFullArrayView column = this.get(x + blockOffset.x, z + blockOffset.z); + LodUtil.assertTrue(column.doesItExist()); + } + } + } + } + else if (data.dataDetail == 0 && getDataDetail() < 4) + { + int dataPerFull = 1 << getDataDetail(); + int fullSize = 16 / dataPerFull; + DhLodPos dataOffset = data.getBBoxLodPos().getCorner(getDataDetail()); + DhLodPos baseOffset = sectionPos.getCorner(getDataDetail()); + int offsetX = dataOffset.x - baseOffset.x; + int offsetZ = dataOffset.z - baseOffset.z; + LodUtil.assertTrue(offsetX >= 0 && offsetX < SECTION_SIZE && offsetZ >= 0 && offsetZ < SECTION_SIZE); + isEmpty = false; + for (int ox = 0; ox < fullSize; ox++) + { + for (int oz = 0; oz < fullSize; oz++) + { + SingleFullArrayView column = this.get(ox + offsetX, oz + offsetZ); + column.downsampleFrom(data.subView(dataPerFull, ox * dataPerFull, oz * dataPerFull)); + } + } + } + else if (data.dataDetail == 0 && getDataDetail() >= 4) + { + //FIXME: TEMPORARY + int chunkPerFull = 1 << (getDataDetail() - 4); + if (data.x % chunkPerFull != 0 || data.z % chunkPerFull != 0) + return; + DhLodPos baseOffset = sectionPos.getCorner(getDataDetail()); + DhLodPos dataOffset = data.getBBoxLodPos().convertUpwardsTo(getDataDetail()); + int offsetX = dataOffset.x - baseOffset.x; + int offsetZ = dataOffset.z - baseOffset.z; + LodUtil.assertTrue(offsetX >= 0 && offsetX < SECTION_SIZE && offsetZ >= 0 && offsetZ < SECTION_SIZE); + isEmpty = false; + data.get(0, 0).deepCopyTo(get(offsetX, offsetZ)); + } + else + { + LodUtil.assertNotReach(); + //TODO; + } + + } @Override - public byte getDataVersion() { - return LATEST_VERSION; - } + public boolean isEmpty() { return isEmpty; } + public void markNotEmpty() { isEmpty = false; } + + @Override + public void saveData(IDhLevel level, DataMetaFile file, OutputStream dataStream) throws IOException + { + DataOutputStream dos = new DataOutputStream(dataStream); // DO NOT CLOSE + { + dos.writeInt(getDataDetail()); + dos.writeInt(size); + dos.writeInt(level.getMinY()); + if (isEmpty) + { + dos.writeInt(0x00000001); + return; + } + dos.writeInt(0xFFFFFFFF); + // Data array length + for (int x = 0; x < size; x++) + { + for (int z = 0; z < size; z++) + { + dos.writeByte(get(x, z).getSingleLength()); + } + } + // Data array content (only on non-empty columns) + dos.writeInt(0xFFFFFFFF); + for (int x = 0; x < size; x++) + { + for (int z = 0; z < size; z++) + { + SingleFullArrayView column = get(x, z); + if (!column.doesItExist()) + continue; + long[] raw = column.getRaw(); + for (long l : raw) + { + dos.writeLong(l); + } + } + } + // Id mapping + dos.writeInt(0xFFFFFFFF); + mapping.serialize(dos); + dos.writeInt(0xFFFFFFFF); + } + } + + + public static FullDataSource loadData(DataMetaFile dataFile, InputStream dataStream, IDhLevel level) throws IOException + { + DataInputStream dos = new DataInputStream(dataStream); // DO NOT CLOSE + { + int dataDetail = dos.readInt(); + if (dataDetail != dataFile.metaData.dataLevel) + throw new IOException(LodUtil.formatLog("Data level mismatch: {} != {}", dataDetail, dataFile.metaData.dataLevel)); + int size = dos.readInt(); + if (size != SECTION_SIZE) + throw new IOException(LodUtil.formatLog( + "Section size mismatch: {} != {} (Currently only 1 section size is supported)", size, SECTION_SIZE)); + int minY = dos.readInt(); + if (minY != level.getMinY()) + LOGGER.warn("Data minY mismatch: {} != {}. Will ignore data's y level", minY, level.getMinY()); + int end = dos.readInt(); + // Data array length + if (end == 0x00000001) + { + // Section is empty + return new FullDataSource(dataFile.pos); + } + // Non-empty section + if (end != 0xFFFFFFFF) + throw new IOException("invalid header end guard"); + long[][] data = new long[size * size][]; + for (int x = 0; x < size; x++) + { + for (int z = 0; z < size; z++) + { + data[x * size + z] = new long[dos.readByte()]; + } + } + // Data array content (only on non-empty columns) + end = dos.readInt(); + if (end != 0xFFFFFFFF) + throw new IOException("invalid data length end guard"); + for (int i = 0; i < data.length; i++) + { + if (data[i].length == 0) + continue; + for (int j = 0; j < data[i].length; j++) + { + data[i][j] = dos.readLong(); + } + } + // Id mapping + end = dos.readInt(); + if (end != 0xFFFFFFFF) + throw new IOException("invalid data content end guard"); + IdBiomeBlockStateMap mapping = IdBiomeBlockStateMap.deserialize(new UnclosableInputStream(dos)); + end = dos.readInt(); + if (end != 0xFFFFFFFF) + throw new IOException("invalid id mapping end guard"); + return new FullDataSource(dataFile.pos, mapping, data); + } + } + + private FullDataSource(DhSectionPos pos, IdBiomeBlockStateMap mapping, long[][] data) + { + super(mapping, data, SECTION_SIZE); + LodUtil.assertTrue(data.length == SECTION_SIZE * SECTION_SIZE); + this.sectionPos = pos; + isEmpty = false; + } - @Override - public void update(ChunkSizedData data) { - LodUtil.assertTrue(sectionPos.getSectionBBoxPos().overlaps(data.getBBoxLodPos())); - if (data.dataDetail == 0 && getDataDetail() == 0) { - DhBlockPos2D chunkBlockPos = new DhBlockPos2D(data.x * 16, data.z * 16); - DhBlockPos2D blockOffset = chunkBlockPos.subtract(sectionPos.getCorner().getCorner()); - LodUtil.assertTrue(blockOffset.x >= 0 && blockOffset.x < SECTION_SIZE && blockOffset.z >= 0 && blockOffset.z < SECTION_SIZE); - isEmpty = false; - data.shadowCopyTo(this.subView(16, blockOffset.x, blockOffset.z)); - { // DEBUG ASSERTION - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - SingleFullArrayView column = this.get(x + blockOffset.x, z + blockOffset.z); - LodUtil.assertTrue(column.doesItExist()); - } - } - } - } else if (data.dataDetail == 0 && getDataDetail() < 4) { - int dataPerFull = 1 << getDataDetail(); - int fullSize = 16 / dataPerFull; - DhLodPos dataOffset = data.getBBoxLodPos().getCorner(getDataDetail()); - DhLodPos baseOffset = sectionPos.getCorner(getDataDetail()); - int offsetX = dataOffset.x - baseOffset.x; - int offsetZ = dataOffset.z - baseOffset.z; - LodUtil.assertTrue(offsetX >= 0 && offsetX < SECTION_SIZE && offsetZ >= 0 && offsetZ < SECTION_SIZE); - isEmpty = false; - for (int ox = 0; ox < fullSize; ox++) { - for (int oz = 0; oz < fullSize; oz++) { - SingleFullArrayView column = this.get(ox + offsetX, oz + offsetZ); - column.downsampleFrom(data.subView(dataPerFull, ox * dataPerFull, oz * dataPerFull)); - } - } - } else if (data.dataDetail == 0 && getDataDetail() >= 4) { - //FIXME: TEMPORARY - int chunkPerFull = 1 << (getDataDetail() - 4); - if (data.x % chunkPerFull != 0 || data.z % chunkPerFull != 0) return; - DhLodPos baseOffset = sectionPos.getCorner(getDataDetail()); - DhLodPos dataOffset = data.getBBoxLodPos().convertUpwardsTo(getDataDetail()); - int offsetX = dataOffset.x - baseOffset.x; - int offsetZ = dataOffset.z - baseOffset.z; - LodUtil.assertTrue(offsetX >= 0 && offsetX < SECTION_SIZE && offsetZ >= 0 && offsetZ < SECTION_SIZE); - isEmpty = false; - data.get(0,0).deepCopyTo(get(offsetX, offsetZ)); - } else { - LodUtil.assertNotReach(); - //TODO; - } - - } - - @Override - public boolean isEmpty() { - return isEmpty; - } - public void markNotEmpty() { - isEmpty = false; - } - - @Override - public void saveData(IDhLevel level, DataMetaFile file, OutputStream dataStream) throws IOException { - DataOutputStream dos = new DataOutputStream(dataStream); // DO NOT CLOSE - { - dos.writeInt(getDataDetail()); - dos.writeInt(size); - dos.writeInt(level.getMinY()); - if (isEmpty) { - dos.writeInt(0x00000001); - return; - } - dos.writeInt(0xFFFFFFFF); - // Data array length - for (int x = 0; x < size; x++) { - for (int z = 0; z < size; z++) { - dos.writeByte(get(x, z).getSingleLength()); - } - } - // Data array content (only on non-empty columns) - dos.writeInt(0xFFFFFFFF); - for (int x = 0; x < size; x++) { - for (int z = 0; z < size; z++) { - SingleFullArrayView column = get(x, z); - if (!column.doesItExist()) continue; - long[] raw = column.getRaw(); - for (long l : raw) { - dos.writeLong(l); - } - } - } - // Id mapping - dos.writeInt(0xFFFFFFFF); - mapping.serialize(dos); - dos.writeInt(0xFFFFFFFF); - } - } - - - public static FullDataSource loadData(DataMetaFile dataFile, InputStream dataStream, IDhLevel level) throws IOException { - DataInputStream dos = new DataInputStream(dataStream); // DO NOT CLOSE - { - int dataDetail = dos.readInt(); - if(dataDetail != dataFile.metaData.dataLevel) - throw new IOException(LodUtil.formatLog("Data level mismatch: {} != {}", dataDetail, dataFile.metaData.dataLevel)); - int size = dos.readInt(); - if (size != SECTION_SIZE) - throw new IOException(LodUtil.formatLog( - "Section size mismatch: {} != {} (Currently only 1 section size is supported)", size, SECTION_SIZE)); - int minY = dos.readInt(); - if (minY != level.getMinY()) - LOGGER.warn("Data minY mismatch: {} != {}. Will ignore data's y level", minY, level.getMinY()); - int end = dos.readInt(); - // Data array length - if (end == 0x00000001) { - // Section is empty - return new FullDataSource(dataFile.pos); - } - // Non-empty section - if (end != 0xFFFFFFFF) throw new IOException("invalid header end guard"); - long[][] data = new long[size*size][]; - for (int x = 0; x < size; x++) { - for (int z = 0; z < size; z++) { - data[x*size+z] = new long[dos.readByte()]; - } - } - // Data array content (only on non-empty columns) - end = dos.readInt(); - if (end != 0xFFFFFFFF) throw new IOException("invalid data length end guard"); - for (int i = 0; i < data.length; i++) { - if (data[i].length == 0) continue; - for (int j = 0; j < data[i].length; j++) { - data[i][j] = dos.readLong(); - } - } - // Id mapping - end = dos.readInt(); - if (end != 0xFFFFFFFF) throw new IOException("invalid data content end guard"); - IdBiomeBlockStateMap mapping = IdBiomeBlockStateMap.deserialize(new UnclosableInputStream(dos)); - end = dos.readInt(); - if (end != 0xFFFFFFFF) throw new IOException("invalid id mapping end guard"); - return new FullDataSource(dataFile.pos, mapping, data); - } - } - - private FullDataSource(DhSectionPos pos, IdBiomeBlockStateMap mapping, long[][] data) { - super(mapping, data, SECTION_SIZE); - LodUtil.assertTrue(data.length == SECTION_SIZE*SECTION_SIZE); - this.sectionPos = pos; - isEmpty = false; - } - - public static FullDataSource createEmpty(DhSectionPos pos) { - return new FullDataSource(pos); - } - - public static boolean neededForPosition(DhSectionPos posToWrite, DhSectionPos posToTest) { - if (!posToWrite.overlaps(posToTest)) return false; - if (posToTest.sectionDetail > posToWrite.sectionDetail) return false; - if (posToWrite.sectionDetail - posToTest.sectionDetail <= SECTION_SIZE_OFFSET) return true; - byte sectPerData = (byte) (1 << (posToWrite.sectionDetail - posToTest.sectionDetail - SECTION_SIZE_OFFSET)); - return posToTest.sectionX % sectPerData == 0 && posToTest.sectionZ % sectPerData == 0; - } - - public void writeFromLower(FullDataSource subData) { - LodUtil.assertTrue(sectionPos.overlaps(subData.sectionPos)); - LodUtil.assertTrue(subData.sectionPos.sectionDetail < sectionPos.sectionDetail); - if (!neededForPosition(sectionPos, subData.sectionPos)) return; - DhSectionPos lowerSectPos = subData.sectionPos; - byte detailDiff = (byte) (sectionPos.sectionDetail - subData.sectionPos.sectionDetail); - byte targetDataDetail = getDataDetail(); - DhLodPos minDataPos = sectionPos.getCorner(targetDataDetail); - if (detailDiff <= SECTION_SIZE_OFFSET) { - int count = 1 << detailDiff; - int dataPerCount = SECTION_SIZE / count; - DhLodPos subDataPos = lowerSectPos.getSectionBBoxPos().getCorner(targetDataDetail); - int dataOffsetX = subDataPos.x - minDataPos.x; - int dataOffsetZ = subDataPos.z - minDataPos.z; - LodUtil.assertTrue(dataOffsetX >= 0 && dataOffsetX < SECTION_SIZE && dataOffsetZ >= 0 && dataOffsetZ < SECTION_SIZE); - - for (int ox = 0; ox < count; ox++) { - for (int oz = 0; oz < count; oz++) { - SingleFullArrayView column = this.get(ox + dataOffsetX, oz + dataOffsetZ); - column.downsampleFrom(subData.subView(dataPerCount, ox * dataPerCount, oz * dataPerCount)); - } - } - } else { - // Count == 1 - DhLodPos subDataPos = lowerSectPos.getSectionBBoxPos().convertUpwardsTo(targetDataDetail); - int dataOffsetX = subDataPos.x - minDataPos.x; - int dataOffsetZ = subDataPos.z - minDataPos.z; - LodUtil.assertTrue(dataOffsetX >= 0 && dataOffsetX < SECTION_SIZE && dataOffsetZ >= 0 && dataOffsetZ < SECTION_SIZE); - subData.get(0,0).deepCopyTo(get(dataOffsetX, dataOffsetZ)); - } - } + public static FullDataSource createEmpty(DhSectionPos pos) { return new FullDataSource(pos); } + + public static boolean neededForPosition(DhSectionPos posToWrite, DhSectionPos posToTest) + { + if (!posToWrite.overlaps(posToTest)) + return false; + if (posToTest.sectionDetail > posToWrite.sectionDetail) + return false; + if (posToWrite.sectionDetail - posToTest.sectionDetail <= SECTION_SIZE_OFFSET) + return true; + byte sectPerData = (byte) (1 << (posToWrite.sectionDetail - posToTest.sectionDetail - SECTION_SIZE_OFFSET)); + return posToTest.sectionX % sectPerData == 0 && posToTest.sectionZ % sectPerData == 0; + } + + public void writeFromLower(FullDataSource subData) + { + LodUtil.assertTrue(sectionPos.overlaps(subData.sectionPos)); + LodUtil.assertTrue(subData.sectionPos.sectionDetail < sectionPos.sectionDetail); + if (!neededForPosition(sectionPos, subData.sectionPos)) + return; + DhSectionPos lowerSectPos = subData.sectionPos; + byte detailDiff = (byte) (sectionPos.sectionDetail - subData.sectionPos.sectionDetail); + byte targetDataDetail = getDataDetail(); + DhLodPos minDataPos = sectionPos.getCorner(targetDataDetail); + if (detailDiff <= SECTION_SIZE_OFFSET) + { + int count = 1 << detailDiff; + int dataPerCount = SECTION_SIZE / count; + DhLodPos subDataPos = lowerSectPos.getSectionBBoxPos().getCorner(targetDataDetail); + int dataOffsetX = subDataPos.x - minDataPos.x; + int dataOffsetZ = subDataPos.z - minDataPos.z; + LodUtil.assertTrue(dataOffsetX >= 0 && dataOffsetX < SECTION_SIZE && dataOffsetZ >= 0 && dataOffsetZ < SECTION_SIZE); + + for (int ox = 0; ox < count; ox++) + { + for (int oz = 0; oz < count; oz++) + { + SingleFullArrayView column = this.get(ox + dataOffsetX, oz + dataOffsetZ); + column.downsampleFrom(subData.subView(dataPerCount, ox * dataPerCount, oz * dataPerCount)); + } + } + } + else + { + // Count == 1 + DhLodPos subDataPos = lowerSectPos.getSectionBBoxPos().convertUpwardsTo(targetDataDetail); + int dataOffsetX = subDataPos.x - minDataPos.x; + int dataOffsetZ = subDataPos.z - minDataPos.z; + LodUtil.assertTrue(dataOffsetX >= 0 && dataOffsetX < SECTION_SIZE && dataOffsetZ >= 0 && dataOffsetZ < SECTION_SIZE); + subData.get(0, 0).deepCopyTo(get(dataOffsetX, dataOffsetZ)); + } + } } diff --git a/core/src/main/java/com/seibel/lod/core/datatype/full/IdBiomeBlockStateMap.java b/core/src/main/java/com/seibel/lod/core/datatype/full/IdBiomeBlockStateMap.java index 0179cb3cf..6473b0dcd 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/full/IdBiomeBlockStateMap.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/full/IdBiomeBlockStateMap.java @@ -11,99 +11,121 @@ import java.util.HashMap; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; -// WARNING: This is not THREAD-SAFE! -public class IdBiomeBlockStateMap { - public static final IWrapperFactory FACTORY = SingletonInjector.INSTANCE.get(IWrapperFactory.class); - - 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); - } - @Override - public boolean equals(Object other) { - if (other == this) return true; - if (!(other instanceof Entry)) return false; - return ((Entry) other).biome.equals(biome) && ((Entry) other).blockState.equals(blockState); - } - - public String serialize() { - return biome.serialize() + " " + blockState.serialize(); - } - - public static Entry deserialize(String str) throws IOException { - String[] strs = str.split(" "); - if (strs.length != 2) throw new IOException("Failed to deserialize BiomeBlockStateEntry"); - IBiomeWrapper biome = FACTORY.deserializeBiomeWrapper(strs[0]); - IBlockStateWrapper blockState = FACTORY.deserializeBlockStateWrapper(strs[1]); - return new Entry(biome, blockState); - } - } - - - final ArrayList entries = new ArrayList<>(); - final ConcurrentHashMap idMap = new ConcurrentHashMap<>(); // FIXME: Improve performance - - 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 mergeEntry = target.entries; - int[] mapper = new int[mergeEntry.size()]; - for (int i=0; i entries = new ArrayList<>(); + final ConcurrentHashMap idMap = new ConcurrentHashMap<>(); // FIXME: Improve performance + + 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 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; + } + + void serialize(OutputStream os) throws IOException + { + DataOutputStream dos = new DataOutputStream(os); // DO NOT CLOSE! + dos.writeInt(entries.size()); + for (Entry e : entries) + { + dos.writeUTF(e.serialize()); + } + } + + static IdBiomeBlockStateMap deserialize(InputStream is) throws IOException + { + DataInputStream dis = new DataInputStream(is); // DO NOT CLOSE! + int size = dis.readInt(); + IdBiomeBlockStateMap map = new IdBiomeBlockStateMap(); + for (int i = 0; i < size; i++) + { + map.entries.add(Entry.deserialize(dis.readUTF())); + } + return map; + } + + @Override + public boolean equals(Object other) + { + if (other == this) + return true; // if (!(other instanceof IdBiomeBlockStateMap)) return false; // IdBiomeBlockStateMap otherMap = (IdBiomeBlockStateMap) other; // if (entries.size() != otherMap.entries.size()) return false; // for (int i=0; i size && source.size % size == 0); - int dataPerUnit = source.size / size; - for (int ox = 0; ox < size; ox++) { - for (int oz = 0; oz < size; oz++) { - SingleFullArrayView column = get(ox, oz); - column.downsampleFrom(source.subView(dataPerUnit, ox * dataPerUnit, oz * dataPerUnit)); - } - } - } +public class FullArrayView implements IFullDataView +{ + protected final long[][] dataArrays; + protected final int offset; + protected final int size; + protected final int dataSize; + 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.dataSize = size; + this.mapping = mapping; + offset = 0; + } + + public FullArrayView(FullArrayView source, int size, int offsetX, int offsetZ) + { + if (source.size < size || source.size < size + offsetX || source.size < size + offsetZ) + throw new IllegalArgumentException( + "tried constructing dataArrayView subview with invalid input!"); + dataArrays = source.dataArrays; + this.size = size; + this.dataSize = source.dataSize; + mapping = source.mapping; + offset = source.offset + offsetX * dataSize + offsetZ; + } + + @Override + public IdBiomeBlockStateMap getMapping() + { + return mapping; + } + + @Override + public SingleFullArrayView get(int index) + { + return get(index / size, index % size); + } + + @Override + public SingleFullArrayView get(int x, int z) + { + return new SingleFullArrayView(mapping, dataArrays, x * size + z + offset); + } + + @Override + public int width() + { + return size; + } + + @Override + public FullArrayView subView(int size, int ox, int oz) + { + return new FullArrayView(this, size, ox, oz); + } + + /** 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"); + if (target.mapping.equals(mapping)) + { + for (int x = 0; x < size; x++) + { + System.arraycopy(dataArrays, offset + x * dataSize, + target.dataArrays, target.offset + x * target.dataSize, size); + } + } + else + { + int[] map = target.mapping.computeAndMergeMapFrom(mapping); + for (int x = 0; x < size; x++) + { + for (int o = 0; o < size; o++) + { + long[] sourceData = dataArrays[offset + x * dataSize + 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 + x * target.dataSize + o] = newData; + } + } + } + } + + public void downsampleFrom(FullArrayView source) + { + LodUtil.assertTrue(source.size > size && source.size % size == 0); + int dataPerUnit = source.size / size; + for (int ox = 0; ox < size; ox++) + { + for (int oz = 0; oz < size; oz++) + { + SingleFullArrayView column = get(ox, oz); + column.downsampleFrom(source.subView(dataPerUnit, ox * dataPerUnit, oz * dataPerUnit)); + } + } + } } diff --git a/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/IFullDataView.java b/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/IFullDataView.java index 424600ed5..440c2241a 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/IFullDataView.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/IFullDataView.java @@ -5,27 +5,39 @@ import com.seibel.lod.core.util.LodUtil; import java.util.Iterator; -public interface IFullDataView { - IdBiomeBlockStateMap getMapping(); - - SingleFullArrayView get(int index); - SingleFullArrayView get(int x, int z); - int width(); - default Iterator iterator() { - return new Iterator() { - private int index = 0; - private final int size = width()*width(); - @Override - public boolean hasNext() { - return index < size; - } - - @Override - public SingleFullArrayView next() { - LodUtil.assertTrue(hasNext(), "No more data to iterate!"); - return get(index++); - } - }; - } - IFullDataView subView(int size, int ox, int oz); +public interface IFullDataView +{ + IdBiomeBlockStateMap getMapping(); + + SingleFullArrayView get(int index); + + SingleFullArrayView get(int x, int z); + + int width(); + + /** Returns an iterator that */ + default Iterator iterator() + { + return new Iterator() + { + private int index = 0; + private final int size = width() * width(); + + @Override + public boolean hasNext() + { + return index < size; + } + + @Override + public SingleFullArrayView next() + { + LodUtil.assertTrue(hasNext(), "No more data to iterate!"); + return get(index++); + } + }; + } + + IFullDataView subView(int size, int ox, int oz); + } diff --git a/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/SingleFullArrayView.java b/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/SingleFullArrayView.java index 2d9cd3677..e74d5ac2d 100644 --- a/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/SingleFullArrayView.java +++ b/core/src/main/java/com/seibel/lod/core/datatype/full/accessor/SingleFullArrayView.java @@ -3,97 +3,106 @@ package com.seibel.lod.core.datatype.full.accessor; import com.seibel.lod.core.datatype.full.FullFormat; import com.seibel.lod.core.datatype.full.IdBiomeBlockStateMap; -public class SingleFullArrayView implements IFullDataView { - private final long[][] dataArrays; - private final 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!"); - return this; - } - - @Override - public SingleFullArrayView get(int x, int z) { - if (x != 0 || z != 0) throw new IllegalArgumentException("Only contains 1 column of full data!"); - return this; - } - public long[] getRaw() { - return dataArrays[offset]; - } - - public long getSingle(int yIndex) { - return dataArrays[offset][yIndex]; - } - public void setSingle(int yIndex, long value) { - dataArrays[offset][yIndex] = value; - } - public void setNew(long[] newArray) { - dataArrays[offset] = newArray; - } - - public int getSingleLength() { return dataArrays[offset].length; } - - @Override - public int width() { - return 1; - } - - @Override - public IFullDataView subView(int size, int ox, int oz) { - if (size != 1 || ox != 1 || oz != 1) - throw new IllegalArgumentException("Getting invalid range of subView from SingleFullArrayView!"); - return this; - } - - //WARNING: It may 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; - } - } - public void deepCopyTo(SingleFullArrayView target) { - if (target.mapping.equals(mapping)) { - target.dataArrays[target.offset] = dataArrays[offset].clone(); - } - 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; - } - } - - public void downsampleFrom(IFullDataView source) { - //TODO: Temp downsample method - SingleFullArrayView firstColumn = source.get(0); - firstColumn.deepCopyTo(this); - } +public class SingleFullArrayView implements IFullDataView +{ + private final long[][] dataArrays; + private final 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!"); + + return this; + } + + @Override + public SingleFullArrayView get(int x, int z) + { + if (x != 0 || z != 0) + throw new IllegalArgumentException("Only contains 1 column of full data!"); + + return this; + } + + public long[] getRaw() { return dataArrays[offset]; } + + public long getSingle(int yIndex) { return dataArrays[offset][yIndex]; } + public void setSingle(int yIndex, long value) { dataArrays[offset][yIndex] = value; } + + public void setNew(long[] newArray) { dataArrays[offset] = newArray; } + + public int getSingleLength() { return dataArrays[offset].length; } + + @Override + public int width() { return 1; } + + @Override + public IFullDataView subView(int size, int ox, int oz) + { + if (size != 1 || ox != 1 || oz != 1) + throw new IllegalArgumentException("Getting invalid range of subView from SingleFullArrayView!"); + return this; + } + + /** WARNING: It may 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; + } + } + + public void deepCopyTo(SingleFullArrayView target) + { + if (target.mapping.equals(mapping)) + { + target.dataArrays[target.offset] = dataArrays[offset].clone(); + } + 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; + } + } + + public void downsampleFrom(IFullDataView source) + { + //TODO: Temp downsample method + SingleFullArrayView firstColumn = source.get(0); + firstColumn.deepCopyTo(this); + } + }