From 961c936f92e7e63f5cf32fcf61252573c3e9ffce Mon Sep 17 00:00:00 2001 From: Morippi Date: Wed, 4 May 2022 23:18:34 +0200 Subject: [PATCH] Started working on lodSection, LodQUadTree and DhChunk (not completed) --- .../seibel/lod/core/objects/a7/DhChunk.java | 49 +++ .../lod/core/objects/a7/LodQuadTree.java | 22 +- .../lod/core/objects/a7/LodSection.java | 371 ++++++++++++++++++ 3 files changed, 435 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/seibel/lod/core/objects/a7/DhChunk.java create mode 100644 src/main/java/com/seibel/lod/core/objects/a7/LodSection.java diff --git a/src/main/java/com/seibel/lod/core/objects/a7/DhChunk.java b/src/main/java/com/seibel/lod/core/objects/a7/DhChunk.java new file mode 100644 index 000000000..a0f4843c8 --- /dev/null +++ b/src/main/java/com/seibel/lod/core/objects/a7/DhChunk.java @@ -0,0 +1,49 @@ +package com.seibel.lod.core.objects.a7; + +import com.seibel.lod.core.objects.a7.io.DHFolderHandler; +import com.seibel.lod.core.objects.a7.io.LevelToFileMatcher; +import com.seibel.lod.core.wrapperInterfaces.block.IBlockDetailWrapper; +import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper; +import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper; + +import java.io.File; +import java.util.HashMap; + +public class DhChunk +{ + public int CHUNK_SIZE = 16; + public IBlockDetailWrapper[] blockData; + public IBiomeWrapper[] biomeData; + public int[] verticalData; + public int verticalSize; + public int chunkPosX; + public int chunkPosZ; + public byte generationMode; + + public DhChunk(byte generationMode, int chunkPosX, int chunkPosZ, int verticalSize) + { + this.verticalSize = verticalSize; + this.chunkPosX = chunkPosX; + this.chunkPosZ = chunkPosZ; + this.generationMode = generationMode; + + this.blockData = new IBlockDetailWrapper[CHUNK_SIZE*CHUNK_SIZE*verticalSize]; + this.biomeData = new IBiomeWrapper[CHUNK_SIZE*CHUNK_SIZE*verticalSize]; + this.verticalData = new int[CHUNK_SIZE*CHUNK_SIZE*verticalSize]; + } + + public void addData(IBlockDetailWrapper block, IBiomeWrapper biome, int singelVerticalData, int relPosX, int relPosZ, int verticalIndex) + { + int index = CHUNK_SIZE*verticalSize*relPosX + verticalSize*relPosZ + verticalIndex; + blockData[index] = block; + biomeData[index] = biome; + verticalData[index] = singelVerticalData; + } + + public long[] getData() + { + long[] data = new long[3]; + //long data = something created using block biome and singelVerticalData; + return data; + } +} diff --git a/src/main/java/com/seibel/lod/core/objects/a7/LodQuadTree.java b/src/main/java/com/seibel/lod/core/objects/a7/LodQuadTree.java index 6b3cf1730..94435935b 100644 --- a/src/main/java/com/seibel/lod/core/objects/a7/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/core/objects/a7/LodQuadTree.java @@ -1,24 +1,32 @@ package com.seibel.lod.core.objects.a7; import com.seibel.lod.core.util.DetailDistanceUtil; -import com.seibel.lod.core.util.LodUtil; import com.seibel.lod.core.util.gridList.MovableGridRingList; // QuadTree built from several layers of 2d ring buffers public class LodQuadTree { public final int maxPossibleDetailLevel; - private final MovableGridRingList[] ringLists; + private final MovableGridRingList[] ringLists; public LodQuadTree(int viewDistance, int initialPlayerX, int initialPlayerZ) { maxPossibleDetailLevel = DetailDistanceUtil.getDetailLevelFromDistance(viewDistance*Math.sqrt(2)); ringLists = new MovableGridRingList[maxPossibleDetailLevel]; - for (int i = 0; i < maxPossibleDetailLevel; i++) { - double distance = DetailDistanceUtil.getDrawDistanceFromDetail(i); - int blockCount = ((int)Math.ceil(distance / (1 << i))); - ringLists[i] = new MovableGridRingList( - blockCount, initialPlayerX >> i, initialPlayerZ >> i); + int size; + for (int detailLevel = 0; detailLevel < maxPossibleDetailLevel; detailLevel++) { + double distance = DetailDistanceUtil.getDrawDistanceFromDetail(detailLevel); + int blockCount = ((int)Math.ceil(distance / (1 << detailLevel))); + ringLists[detailLevel] = new MovableGridRingList(blockCount, initialPlayerX >> detailLevel, initialPlayerZ >> detailLevel); + size = ringLists[detailLevel].getSize(); + for(int sectionIndexX = 0; sectionIndexX < size; sectionIndexX++) + { + for(int sectionIndexZ = 0; sectionIndexZ < size; sectionIndexZ++) + { + ringLists[detailLevel].set(sectionIndexX, sectionIndexZ, new LodSection(sectionIndexX)) + } + } } + } diff --git a/src/main/java/com/seibel/lod/core/objects/a7/LodSection.java b/src/main/java/com/seibel/lod/core/objects/a7/LodSection.java new file mode 100644 index 000000000..ed3b3b927 --- /dev/null +++ b/src/main/java/com/seibel/lod/core/objects/a7/LodSection.java @@ -0,0 +1,371 @@ +package com.seibel.lod.core.objects.a7; + +import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler; +import com.seibel.lod.core.objects.LodDataView; +import com.seibel.lod.core.objects.lod.LevelContainer; +import com.seibel.lod.core.objects.lod.VerticalLevelContainer; +import com.seibel.lod.core.util.DataPointUtil; +import com.seibel.lod.core.util.DetailDistanceUtil; +import com.seibel.lod.core.util.LodUtil; +import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; + +public class LodSection +{ + public static final boolean DO_SAFETY_CHECKS = true; + + private final short minHeight; + public final byte detailLevel; + public final int SECTION_SIZE = 128; + public final int verticalSize; + + public final long[] dataContainer; + + public LodSection(byte detailLevel) + { + this.detailLevel = detailLevel; + verticalSize = DetailDistanceUtil.getMaxVerticalData(detailLevel); + dataContainer = new long[SECTION_SIZE * SECTION_SIZE * DetailDistanceUtil.getMaxVerticalData(detailLevel)]; + minHeight = SingletonHandler.get(IMinecraftClientWrapper.class).getWrappedClientWorld().getMinHeight(); + } + + public byte getDetailLevel() + { + return detailLevel; + } + + public void clear(int posX, int posZ) + { + for (int verticalIndex = 0; verticalIndex < verticalSize; verticalIndex++) + dataContainer[posX * SECTION_SIZE * verticalSize + posZ * verticalSize + verticalIndex] = DataPointUtil.EMPTY_DATA; + } + + public boolean addData(long data, int posX, int posZ, int verticalIndex) + { + dataContainer[posX * SECTION_SIZE * verticalSize + posZ * verticalSize + verticalIndex] = data; + return true; + } + + private void forceWriteVerticalData(long[] data, int posX, int posZ) + { + int index = posX * SECTION_SIZE * verticalSize + posZ * verticalSize; + if (verticalSize >= 0) System.arraycopy(data, 0, dataContainer, index + 0, verticalSize); + } + + public boolean addVerticalData(long[] data, int posX, int posZ, boolean override) + { + int index = posX * SECTION_SIZE * verticalSize + posZ * verticalSize; + int compare = DataPointUtil.compareDatapointPriority(data[0], dataContainer[index]); + if (override) { + if (compare<0) return false; + } else { + if (compare<=0) return false; + } + forceWriteVerticalData(data, posX, posZ); + return true; + } + + public boolean copyVerticalData(LodDataView data, int posX, int posZ, boolean override) { + if (DO_SAFETY_CHECKS) { + if (data.size() != verticalSize) + throw new IllegalArgumentException("data size not the same as vertical size"); + if (posX < 0 || posX >= SECTION_SIZE) + throw new IllegalArgumentException("X position is out of bounds"); + if (posZ < 0 || posZ >= SECTION_SIZE) + throw new IllegalArgumentException("Z position is out of bounds"); + } + int index = posX * SECTION_SIZE * verticalSize + posZ * verticalSize; + int compare = DataPointUtil.compareDatapointPriority(data.get(0), dataContainer[index]); + if (override) { + if (compare<0) return false; + } else { + if (compare<=0) return false; + } + data.copyTo(dataContainer, index); + return true; + } + + public boolean addChunkOfData(long[] data, int posX, int posZ, int widthX, int widthZ, boolean override) + { + boolean anyChange = false; + if (posX+widthX > SECTION_SIZE || posZ+widthZ > SECTION_SIZE) + throw new IndexOutOfBoundsException("addChunkOfData param not inside valid range"); + if (widthX*widthZ*verticalSize != data.length) + throw new IndexOutOfBoundsException("addChunkOfData data array not sized correctly to contain the data to be copied"); + if (posX<0 || posZ<0 || widthX<0 || widthZ<0) + throw new IndexOutOfBoundsException("addChunkOfData param is negative"); + + for (int ox=0; ox SECTION_SIZE || posZ+widthZ > SECTION_SIZE) + throw new IndexOutOfBoundsException("addChunkOfData param not inside valid range"); + if (widthX*widthZ*verticalSize != data.size()) + throw new IndexOutOfBoundsException("addChunkOfData data array not sized correctly to contain the data to be copied"); + if (posX<0 || posZ<0 || widthX<0 || widthZ<0) + throw new IndexOutOfBoundsException("addChunkOfData param is negative"); + + for (int ox=0; ox tLocalVerticalUpdateArrays = ThreadLocal.withInitial(() -> + { + return new long[LodUtil.DETAIL_OPTIONS - 1][]; + }); + + public void updateData(LevelContainer lowerLevelContainer, int posX, int posZ) + { + //We reset the array + long[][] verticalUpdateArrays = tLocalVerticalUpdateArrays.get(); + long[] dataToMerge = verticalUpdateArrays[detailLevel-1]; + int arrayLength = DetailDistanceUtil.getMaxVerticalData(detailLevel-1) * 4; + if (dataToMerge == null || dataToMerge.length != arrayLength) { + dataToMerge = new long[arrayLength]; + verticalUpdateArrays[detailLevel-1] = dataToMerge; + } else Arrays.fill(dataToMerge, 0); + + int lowerMaxVertical = dataToMerge.length / 4; + int childPosX; + int childPosZ; + long[] data; + boolean anyDataExist = false; + for (int x = 0; x <= 1; x++) + { + for (int z = 0; z <= 1; z++) + { + childPosX = 2 * posX + x; + childPosZ = 2 * posZ + z; + if (lowerLevelContainer.doesItExist(childPosX, childPosZ)) anyDataExist = true; + for (int verticalIndex = 0; verticalIndex < lowerMaxVertical; verticalIndex++) + dataToMerge[(z * 2 + x) * lowerMaxVertical + verticalIndex] = lowerLevelContainer.getData(childPosX, childPosZ, verticalIndex); + } + } + data = DataPointUtil.mergeMultiData(dataToMerge, lowerMaxVertical, getVerticalSize()); + if (!anyDataExist) + throw new RuntimeException("Update data called but no child datapoint exist!"); + + if ((!DataPointUtil.doesItExist(data[0])) && anyDataExist) + throw new RuntimeException("Update data called but higher level datapoint doesn't exist even though child data does exist!"); + + //FIXME: Disabled check if genMode for old data is already invalid due to having genMode 0. + if (DataPointUtil.getGenerationMode(data[0]) != DataPointUtil.getGenerationMode(lowerLevelContainer.getSingleData(posX*2, posZ*2))) + throw new RuntimeException("Update data called but higher level datapoint does not have the same GenerationMode as the top left corner child datapoint!"); + + forceWriteVerticalData(data, posX, posZ); + } + + public boolean writeData(DataOutputStream output) throws IOException { + output.writeByte(detailLevel); + output.writeByte((byte) verticalSize); + output.writeByte((byte) (minHeight & 0xFF)); + output.writeByte((byte) ((minHeight >> 8) & 0xFF)); + boolean allGenerated = true; + int x = SECTION_SIZE * SECTION_SIZE; + for (int i = 0; i < x; i++) + { + for (int j = 0; j < verticalSize; j++) + { + long current = dataContainer[i * verticalSize + j]; + output.writeLong(Long.reverseBytes(current)); + } + if (!DataPointUtil.doesItExist(dataContainer[i])) + allGenerated = false; + } + return allGenerated; + } + + public String toString() + { + String LINE_DELIMITER = "\n"; + String DATA_DELIMITER = " "; + String SUBDATA_DELIMITER = ","; + StringBuilder stringBuilder = new StringBuilder(); + int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel); + stringBuilder.append(detailLevel); + stringBuilder.append(LINE_DELIMITER); + for (int z = 0; z < size; z++) + { + for (int x = 0; x < size; x++) + { + for (int y = 0; y < verticalSize; y++) { + //Converting the dataToHex + stringBuilder.append(Long.toHexString(getData(x,z,y))); + if (y != verticalSize) stringBuilder.append(SUBDATA_DELIMITER); + } + if (x != size) stringBuilder.append(DATA_DELIMITER); + } + if (z != size) stringBuilder.append(LINE_DELIMITER); + } + return stringBuilder.toString(); + } + + public int getMaxNumberOfLods() + { + return SECTION_SIZE * SECTION_SIZE * getVerticalSize(); + } + + public long getRoughRamUsage() + { + return dataContainer.length * Long.BYTES; + } + + +}