From f8910b0c3bdb0ebdec6487f7370828db868de79d Mon Sep 17 00:00:00 2001 From: cola98765 Date: Thu, 9 Dec 2021 19:59:50 +0100 Subject: [PATCH] move the merge --- .../core/builders/lodBuilding/LodBuilder.java | 13 +- .../worldGeneration/LodGenWorker.java | 18 +- .../lod/core/objects/lod/LevelContainer.java | 2 + .../lod/core/objects/lod/LodDimension.java | 35 +++ .../lod/core/objects/lod/LodRegion.java | 12 + .../objects/lod/VerticalLevelContainer.java | 293 +++++++++++++++++- .../seibel/lod/core/util/DataPointUtil.java | 1 + 7 files changed, 351 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java b/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java index 6351fdd1e..434c12039 100644 --- a/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java +++ b/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java @@ -198,16 +198,9 @@ import com.seibel.lod.core.wrapperInterfaces.world.IWorldWrapper; long[] data; long[] dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ); - data = DataPointUtil.mergeMultiData(dataToMergeVertical, DataPointUtil.WORLD_HEIGHT / 2 + 1, DetailDistanceUtil.getMaxVerticalData(detailLevel)); - - - //lodDim.clear(detailLevel, posX, posZ); - if (data != null && data.length != 0) - { - posX = LevelPosUtil.convert((byte) 0, chunk.getPos().getX() * 16 + startX, detail.detailLevel); - posZ = LevelPosUtil.convert((byte) 0, chunk.getPos().getZ() * 16 + startZ, detail.detailLevel); - lodDim.addVerticalData(detailLevel, posX, posZ, data, false); - } + posX = LevelPosUtil.convert((byte) 0, chunk.getPos().getX() * 16 + startX, detail.detailLevel); + posZ = LevelPosUtil.convert((byte) 0, chunk.getPos().getZ() * 16 + startZ, detail.detailLevel); + lodDim.mergeMultiData(detailLevel, posX, posZ, false, dataToMergeVertical, DataPointUtil.WORLD_HEIGHT / 2 + 1, DetailDistanceUtil.getMaxVerticalData(detailLevel)); } lodDim.updateData(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().getX(), chunk.getPos().getZ()); //executeTime = System.currentTimeMillis() - executeTime; diff --git a/src/main/java/com/seibel/lod/core/builders/worldGeneration/LodGenWorker.java b/src/main/java/com/seibel/lod/core/builders/worldGeneration/LodGenWorker.java index 77eb213b2..ede30fa71 100644 --- a/src/main/java/com/seibel/lod/core/builders/worldGeneration/LodGenWorker.java +++ b/src/main/java/com/seibel/lod/core/builders/worldGeneration/LodGenWorker.java @@ -126,7 +126,7 @@ public class LodGenWorker @Override public void run() { - try + //try { // only generate LodChunks if they can // be added to the current LodDimension @@ -172,19 +172,19 @@ public class LodGenWorker }// if in range } - catch (Exception e) - { - ClientApi.LOGGER.error(LodChunkGenThread.class.getSimpleName() + ": ran into an error: " + e.getMessage()); - e.printStackTrace(); - } - finally - { + //catch (Exception e) + //{ + // ClientApi.LOGGER.error(LodChunkGenThread.class.getSimpleName() + ": ran into an error: " + e.getMessage()); + // e.printStackTrace(); + //} + //finally + //{ // decrement how many threads are running LodWorldGenerator.INSTANCE.numberOfChunksWaitingToGenerate.addAndGet(-1); // this position is no longer being generated LodWorldGenerator.INSTANCE.positionsWaitingToBeGenerated.remove(pos); - } + //} }// run diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LevelContainer.java b/src/main/java/com/seibel/lod/core/objects/lod/LevelContainer.java index b314fbcf7..48ed1c42a 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/LevelContainer.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/LevelContainer.java @@ -112,4 +112,6 @@ public interface LevelContainer * @return data as a String */ int getMaxNumberOfLods(); + + void mergeMultiData(int posX, int posZ, long[] dataToMergeVertical, int inputVerticalData, int maxVerticalData); } diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java b/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java index 7a803a823..6cdbacd0a 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java @@ -909,4 +909,39 @@ public class LodDimension { isRegionDirty[i][j] = val; } + + public void mergeMultiData(byte detailLevel, int posX, int posZ, boolean dontSave, long[] dataToMergeVertical, int inputVerticalData, int maxVerticalData) + { + int regionPosX = LevelPosUtil.getRegion(detailLevel, posX); + int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ); + + // don't continue if the region can't be saved + LodRegion region = getRegion(regionPosX, regionPosZ); + if (region == null) + return; + + region.mergeMultiData(detailLevel, posX, posZ, dataToMergeVertical, inputVerticalData, maxVerticalData); + + // only save valid LODs to disk + if (!dontSave && fileHandler != null) + { + try + { + // mark the region as dirty, so it will be saved to disk + int xIndex = (regionPosX - center.x) + halfWidth; + int zIndex = (regionPosZ - center.z) + halfWidth; + + isRegionDirty[xIndex][zIndex] = true; + regenRegionBuffer[xIndex][zIndex] = true; + regenDimensionBuffers = true; + } + catch (ArrayIndexOutOfBoundsException e) + { + e.printStackTrace(); + // If this happens, the method was probably + // called when the dimension was changing size. + // Hopefully this shouldn't be an issue. + } + } + } } diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java b/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java index 263428ba6..ecefaa9f5 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java @@ -610,4 +610,16 @@ public class LodRegion { return getLevel(LodUtil.REGION_DETAIL_LEVEL).toString(); } + + public void mergeMultiData(byte detailLevel, int posX, int posZ, long[] dataToMergeVertical, int inputVerticalData, int maxVerticalData) + { + posX = LevelPosUtil.getRegionModule(detailLevel, posX); + posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); + // The dataContainer could have null entries if the + // detailLevel changes. + if (this.dataContainer[detailLevel] == null) + this.dataContainer[detailLevel] = new VerticalLevelContainer(detailLevel); + + this.dataContainer[detailLevel].mergeMultiData(posX, posZ, dataToMergeVertical, inputVerticalData, maxVerticalData); + } } diff --git a/src/main/java/com/seibel/lod/core/objects/lod/VerticalLevelContainer.java b/src/main/java/com/seibel/lod/core/objects/lod/VerticalLevelContainer.java index 2f1c19548..aeb651613 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/VerticalLevelContainer.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/VerticalLevelContainer.java @@ -19,6 +19,7 @@ package com.seibel.lod.core.objects.lod; +import com.seibel.lod.core.enums.config.DistanceGenerationMode; import com.seibel.lod.core.util.DataPointUtil; import com.seibel.lod.core.util.DetailDistanceUtil; import com.seibel.lod.core.util.LevelPosUtil; @@ -196,7 +197,6 @@ public class VerticalLevelContainer implements LevelContainer int lowerMaxVertical = dataToMerge.length / 4; int childPosX; int childPosZ; - long[] data; for (int x = 0; x <= 1; x++) { for (int z = 0; z <= 1; z++) @@ -207,9 +207,7 @@ public class VerticalLevelContainer implements LevelContainer dataToMerge[(z * 2 + x) * lowerMaxVertical + verticalIndex] = lowerLevelContainer.getData(childPosX, childPosZ, verticalIndex); } } - data = DataPointUtil.mergeMultiData(dataToMerge, lowerMaxVertical, getMaxVerticalData()); - - addVerticalData(data, posX, posZ); + mergeMultiData(posX, posZ, dataToMerge, lowerMaxVertical, getMaxVerticalData()); } @Override @@ -244,6 +242,293 @@ public class VerticalLevelContainer implements LevelContainer return tempData; } + public static void shrinkArray(short[] array, int packetSize, int start, int length, int arraySize) + { + start *= packetSize; + length *= packetSize; + arraySize *= packetSize; + for (int i = 0; i < arraySize - start; i++) + { + array[start + i] = array[start + length + i]; + //remove comment to not leave garbage at the end + //array[start + packetSize + i] = 0; + } + } + + public static void extendArray(short[] array, int packetSize, int start, int length, int arraySize) + { + start *= packetSize; + length *= packetSize; + arraySize *= packetSize; + for (int i = arraySize - start - 1; i >= 0; i--) + { + array[start + length + i] = array[start + i]; + array[start + i] = 0; + } + } + + /** + * This method merge column of multiple data together + * @param dataToMerge one or more columns of data + * @param inputVerticalData vertical size of an input data + * @param maxVerticalData max vertical size of the merged data + */ + public void mergeMultiData(int posX, int posZ, long[] dataToMerge, int inputVerticalData, int maxVerticalData) + { + int size = dataToMerge.length / inputVerticalData; + + // We initialize the arrays that are going to be used + short[] heightAndDepth = ThreadMapUtil.getHeightAndDepth((DataPointUtil.WORLD_HEIGHT / 2 + 1) * 2); + long[] dataPoint = ThreadMapUtil.getVerticalDataArray(DetailDistanceUtil.getMaxVerticalData(0)); + + + int genMode = DistanceGenerationMode.FULL.complexity; + boolean allEmpty = true; + boolean allVoid = true; + boolean allDefault; + long singleData; + + + short depth; + short height; + int count = 0; + int i; + int ii; + int dataIndex; + //We collect the indexes of the data, ordered by the depth + for (int index = 0; index < size; index++) + { + for (dataIndex = 0; dataIndex < inputVerticalData; dataIndex++) + { + singleData = dataToMerge[index * inputVerticalData + dataIndex]; + if (DataPointUtil.doesItExist(singleData)) + { + genMode = Math.min(genMode, DataPointUtil.getGenerationMode(singleData)); + allEmpty = false; + if (!DataPointUtil.isVoid(singleData)) + { + allVoid = false; + depth = DataPointUtil.getDepth(singleData); + height = DataPointUtil.getHeight(singleData); + + int botPos = -1; + int topPos = -1; + //values fall in between and possibly require extension of array + boolean botExtend = false; + boolean topExtend = false; + for (i = 0; i < count; i++) + { + if (depth <= heightAndDepth[i * 2] && depth >= heightAndDepth[i * 2 + 1]) + { + botPos = i; + break; + } + else if (depth < heightAndDepth[i * 2 + 1] && ((i + 1 < count && depth > heightAndDepth[(i + 1) * 2]) || i + 1 == count)) + { + botPos = i; + botExtend = true; + break; + } + } + for (i = 0; i < count; i++) + { + if (height <= heightAndDepth[i * 2] && height >= heightAndDepth[i * 2 + 1]) + { + topPos = i; + break; + } + else if (height < heightAndDepth[i * 2 + 1] && ((i + 1 < count && height > heightAndDepth[(i + 1) * 2]) || i + 1 == count)) + { + topPos = i; + topExtend = true; + break; + } + } + if (topPos == -1) + { + if (botPos == -1) + { + //whole block falls above + extendArray(heightAndDepth, 2, 0, 1, count); + heightAndDepth[0] = height; + heightAndDepth[1] = depth; + count++; + } + else if (!botExtend) + { + //only top falls above extending it there, while bottom is inside existing + shrinkArray(heightAndDepth, 2, 0, botPos, count); + heightAndDepth[0] = height; + count -= botPos; + } + else + { + //top falls between some blocks, extending those as well + shrinkArray(heightAndDepth, 2, 0, botPos, count); + heightAndDepth[0] = height; + heightAndDepth[1] = depth; + count -= botPos; + } + } + else if (!topExtend) + { + if (!botExtend) + //both top and bottom are within some exiting blocks, possibly merging them + heightAndDepth[topPos * 2 + 1] = heightAndDepth[botPos * 2 + 1]; + else + //top falls between some blocks, extending it there + heightAndDepth[topPos * 2 + 1] = depth; + shrinkArray(heightAndDepth, 2, topPos + 1, botPos - topPos, count); + count -= botPos - topPos; + } + else + { + if (!botExtend) + { + //only top is within some exiting block, extending it + topPos++; //to make it easier + heightAndDepth[topPos * 2] = height; + heightAndDepth[topPos * 2 + 1] = heightAndDepth[botPos * 2 + 1]; + shrinkArray(heightAndDepth, 2, topPos + 1, botPos - topPos, count); + count -= botPos - topPos; + } + else + { + //both top and bottom are outside existing blocks + shrinkArray(heightAndDepth, 2, topPos + 1, botPos - topPos, count); + count -= botPos - topPos; + extendArray(heightAndDepth, 2, topPos + 1, 1, count); + count++; + heightAndDepth[topPos * 2 + 2] = height; + heightAndDepth[topPos * 2 + 3] = depth; + } + } + } + } + else + break; + } + } + + //We check if there is any data that's not empty or void + if (allEmpty) + return; + if (allVoid) + { + dataPoint[0] = DataPointUtil.createVoidDataPoint(genMode); + return; + } + + //we limit the vertical portion to maxVerticalData + int j = 0; + while (count > maxVerticalData) + { + ii = DataPointUtil.WORLD_HEIGHT - DataPointUtil.VERTICAL_OFFSET; + for (i = 0; i < count - 1; i++) + { + if (heightAndDepth[i * 2 + 1] - heightAndDepth[(i + 1) * 2] <= ii) + { + ii = heightAndDepth[i * 2 + 1] - heightAndDepth[(i + 1) * 2]; + j = i; + } + } + heightAndDepth[j * 2 + 1] = heightAndDepth[(j + 1) * 2 + 1]; + for (i = j + 1; i < count - 1; i++) + { + heightAndDepth[i * 2] = heightAndDepth[(i + 1) * 2]; + heightAndDepth[i * 2 + 1] = heightAndDepth[(i + 1) * 2 + 1]; + } + //System.arraycopy(heightAndDepth, j + 1, heightAndDepth, j, count - j - 1); + count--; + } + //As standard the vertical lods are ordered from top to bottom + for (j = count - 1; j >= 0; j--) + { + final int arrayPos = posX * size * maxVerticalData + posZ * maxVerticalData + j; + height = heightAndDepth[j * 2]; + depth = heightAndDepth[j * 2 + 1]; + + if ((depth == 0 && height == 0) || j >= heightAndDepth.length / 2) + break; + + int numberOfChildren = 0; + int tempAlpha = 0; + int tempRed = 0; + int tempGreen = 0; + int tempBlue = 0; + int tempLightBlock = 0; + int tempLightSky = 0; + byte tempGenMode = DistanceGenerationMode.FULL.complexity; + allEmpty = true; + allVoid = true; + allDefault = true; + long data = 0; + + for (int index = 0; index < size; index++) + { + for (dataIndex = 0; dataIndex < inputVerticalData; dataIndex++) + { + singleData = dataToMerge[index * inputVerticalData + dataIndex]; + if (DataPointUtil.doesItExist(singleData) && !DataPointUtil.isVoid(singleData)) + { + + if ((depth <= DataPointUtil.getDepth(singleData) && DataPointUtil.getDepth(singleData) <= height) + || (depth <= DataPointUtil.getHeight(singleData) && DataPointUtil.getHeight(singleData) <= height)) + { + if (DataPointUtil.getHeight(singleData) > DataPointUtil.getHeight(data)) + data = singleData; + } + } + else + break; + } + if (!DataPointUtil.doesItExist(data)) + { + singleData = dataToMerge[index * inputVerticalData]; + data = DataPointUtil.createVoidDataPoint(DataPointUtil.getGenerationMode(singleData)); + } + + if (DataPointUtil.doesItExist(data)) + { + allEmpty = false; + if (!DataPointUtil.isVoid(data)) + { + numberOfChildren++; + allVoid = false; + tempAlpha += DataPointUtil.getAlpha(data); + tempRed += DataPointUtil.getRed(data); + tempGreen += DataPointUtil.getGreen(data); + tempBlue += DataPointUtil.getBlue(data); + tempLightBlock += DataPointUtil.getLightBlock(data); + tempLightSky += DataPointUtil.getLightSky(data); + if (!DataPointUtil.getFlag(data)) allDefault = false; + } + tempGenMode = (byte) Math.min(tempGenMode, DataPointUtil.getGenerationMode(data)); + } + else + tempGenMode = (byte) Math.min(tempGenMode, DistanceGenerationMode.NONE.complexity); + } + + if (allEmpty) + //no child has been initialized + dataContainer[arrayPos] = DataPointUtil.EMPTY_DATA; + else if (allVoid) + //all the children are void + dataContainer[arrayPos] = DataPointUtil.createVoidDataPoint(tempGenMode); + else + { + //we have at least 1 child + tempAlpha = tempAlpha / numberOfChildren; + tempRed = tempRed / numberOfChildren; + tempGreen = tempGreen / numberOfChildren; + tempBlue = tempBlue / numberOfChildren; + tempLightBlock = tempLightBlock / numberOfChildren; + tempLightSky = tempLightSky / numberOfChildren; + dataContainer[arrayPos] = DataPointUtil.createDataPoint(tempAlpha, tempRed, tempGreen, tempBlue, height, depth, tempLightSky, tempLightBlock, tempGenMode, allDefault); + } + } + } + @Override @SuppressWarnings("unused") public String toString() diff --git a/src/main/java/com/seibel/lod/core/util/DataPointUtil.java b/src/main/java/com/seibel/lod/core/util/DataPointUtil.java index 81b11c287..894420c69 100644 --- a/src/main/java/com/seibel/lod/core/util/DataPointUtil.java +++ b/src/main/java/com/seibel/lod/core/util/DataPointUtil.java @@ -263,6 +263,7 @@ public class DataPointUtil * @param maxVerticalData max vertical size of the merged data * @return one column of correctly parsed data */ + @Deprecated public static long[] mergeMultiData(long[] dataToMerge, int inputVerticalData, int maxVerticalData) { int size = dataToMerge.length / inputVerticalData;