From ab3880a5e56b7238522fd598696e9fe5ee2f67b6 Mon Sep 17 00:00:00 2001 From: tom lee Date: Sun, 23 Jan 2022 23:15:08 +0800 Subject: [PATCH] Trash ThreadMapUtil replaced by ThreadLocal. Trash an unused class --- .../com/seibel/lod/core/api/EventApi.java | 2 - .../LodBufferBuilderFactory.java | 24 +- .../lod/core/dataFormat/BlockDataFormat.java | 502 ------------------ .../objects/lod/VerticalLevelContainer.java | 14 +- .../seibel/lod/core/util/DataPointUtil.java | 22 +- .../seibel/lod/core/util/ThreadMapUtil.java | 202 ------- 6 files changed, 50 insertions(+), 716 deletions(-) delete mode 100644 src/main/java/com/seibel/lod/core/dataFormat/BlockDataFormat.java delete mode 100644 src/main/java/com/seibel/lod/core/util/ThreadMapUtil.java diff --git a/src/main/java/com/seibel/lod/core/api/EventApi.java b/src/main/java/com/seibel/lod/core/api/EventApi.java index a7468bc6a..e6e7778f8 100644 --- a/src/main/java/com/seibel/lod/core/api/EventApi.java +++ b/src/main/java/com/seibel/lod/core/api/EventApi.java @@ -32,7 +32,6 @@ 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.util.SingletonHandler; -import com.seibel.lod.core.util.ThreadMapUtil; import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton; import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper; @@ -134,7 +133,6 @@ public class EventApi if (isCurrentlyOnSinglePlayerServer && world.getWorldType() == WorldType.ClientWorld) return; // the player just unloaded a world/dimension - ThreadMapUtil.clearMaps(); checkIfDisconnectedFromServer(); } private void checkIfDisconnectedFromServer() diff --git a/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java b/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java index 8db125649..820351b31 100644 --- a/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java +++ b/src/main/java/com/seibel/lod/core/builders/bufferBuilding/LodBufferBuilderFactory.java @@ -23,6 +23,7 @@ import java.nio.ByteBuffer; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; @@ -35,7 +36,6 @@ import java.util.concurrent.locks.ReentrantLock; import org.lwjgl.opengl.GL32; import org.lwjgl.opengl.GL44; -import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.seibel.lod.core.api.ClientApi; import com.seibel.lod.core.enums.LodDirection; import com.seibel.lod.core.enums.config.GpuUploadMethod; @@ -58,7 +58,6 @@ import com.seibel.lod.core.util.LodThreadFactory; import com.seibel.lod.core.util.LodUtil; import com.seibel.lod.core.util.MovableGridList; import com.seibel.lod.core.util.SingletonHandler; -import com.seibel.lod.core.util.ThreadMapUtil; import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton; import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper; @@ -414,6 +413,17 @@ public class LodBufferBuilderFactory } } + private static final ThreadLocal tLocalVertexOptimizer = ThreadLocal.withInitial(VertexOptimizer::new); + private static HashMap makeAdjData(int verticalData) { + HashMap map = new HashMap<>(); + map.put(LodDirection.UP, new long[1]); + map.put(LodDirection.DOWN, new long[1]); + for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS) + map.put(lodDirection, new long[verticalData]); + return map; + } + private static final ThreadLocal> tLocalAdjData = new ThreadLocal>(); + private boolean makeLodRenderData(LodDimension lodDim, RegionPos regPos, int playerX, int playerZ, int vboX, int vboZ, byte minDetail, int cullingRangeX, int cullingRangeZ) { @@ -421,15 +431,19 @@ public class LodBufferBuilderFactory int playerChunkX = LevelPosUtil.convert(LodUtil.BLOCK_DETAIL_LEVEL,playerX,LodUtil.CHUNK_DETAIL_LEVEL); int playerChunkZ = LevelPosUtil.convert(LodUtil.BLOCK_DETAIL_LEVEL,playerZ,LodUtil.CHUNK_DETAIL_LEVEL); DebugMode debugMode = CONFIG.client().advanced().debugging().getDebugMode(); - VertexOptimizer vertexOptimizer = ThreadMapUtil.getBox(); - boolean[] adjShadeDisabled = ThreadMapUtil.getAdjShadeDisabledArray(); + VertexOptimizer vertexOptimizer = tLocalVertexOptimizer.get(); + boolean[] adjShadeDisabled = new boolean[VertexOptimizer.DIRECTIONS.length]; LodBufferBuilder currentBuffer = buildableBuffers.get(regPos.x, regPos.z); // determine how many LODs we can stack vertically int maxVerticalData = DetailDistanceUtil.getMaxVerticalData((byte) 0); //we get or create the map that will contain the adj data - Map adjData = ThreadMapUtil.getAdjDataArray(maxVerticalData); + Map adjData = tLocalAdjData.get(); + if (adjData==null || adjData.get(LodDirection.NORTH).length != maxVerticalData) { + adjData = makeAdjData(maxVerticalData); + tLocalAdjData.set(adjData); + } //We ask the lod dimension which block we have to render given the player position PosToRenderContainer posToRender = setsToRender.get(regPos.x, regPos.z); diff --git a/src/main/java/com/seibel/lod/core/dataFormat/BlockDataFormat.java b/src/main/java/com/seibel/lod/core/dataFormat/BlockDataFormat.java deleted file mode 100644 index f20ac4d6c..000000000 --- a/src/main/java/com/seibel/lod/core/dataFormat/BlockDataFormat.java +++ /dev/null @@ -1,502 +0,0 @@ -package com.seibel.lod.core.dataFormat; - -import com.seibel.lod.core.enums.config.DistanceGenerationMode; -import com.seibel.lod.core.util.ColorUtil; -import com.seibel.lod.core.util.DetailDistanceUtil; -import com.seibel.lod.core.util.ThreadMapUtil; - -import static com.seibel.lod.core.builders.bufferBuilding.LodBufferBuilderFactory.skyLightPlayer; - -public class BlockDataFormat -{ - /* - |a |a |a |a |r |r |r |r | - - |r |r |r |r |g |g |g |g | - - |g |g |g |g |b |b |b |b | - - |b |b |b |b |h |h |h |h | - - |h |h |h |h |h |h |d |d | - - |d |d |d |d |d |d |d |d | - - |bl |bl |bl |bl |sl |sl |sl |sl | - - |l |l |f |g |g |g |v |e | - - - */ - - // Reminder: bytes have range of [-128, 127]. - // When converting to or from an int a 128 should be added or removed. - // If there is a bug with color then it's probably caused by this. - - //To be used in the future for negative value - //public final static int MIN_DEPTH = -64; - //public final static int MIN_HEIGHT = -64; - public final static int EMPTY_DATA = 0; - public static final short VERTICAL_OFFSET = -64; - public static int WORLD_HEIGHT = 1024; - - public final static int ALPHA_DOWNSIZE_SHIFT = 4; - - //public final static int BLUE_COLOR_SHIFT = 0; - //public final static int GREEN_COLOR_SHIFT = 8; - //public final static int RED_COLOR_SHIFT = 16; - //public final static int ALPHA_COLOR_SHIFT = 24; - - public final static int BLUE_SHIFT = 36; - public final static int GREEN_SHIFT = BLUE_SHIFT + 8; - public final static int RED_SHIFT = BLUE_SHIFT + 16; - public final static int ALPHA_SHIFT = BLUE_SHIFT + 24; - - public final static int COLOR_SHIFT = 36; - - public final static int HEIGHT_SHIFT = 26; - public final static int DEPTH_SHIFT = 16; - public final static int BLOCK_LIGHT_SHIFT = 12; - public final static int SKY_LIGHT_SHIFT = 8; - //public final static int LIGHTS_SHIFT = SKY_LIGHT_SHIFT; - //public final static int VERTICAL_INDEX_SHIFT = 6; - public final static int FLAG_SHIFT = 5; - public final static int GEN_TYPE_SHIFT = 2; - public final static int VOID_SHIFT = 1; - public final static int EXISTENCE_SHIFT = 0; - - public final static long ALPHA_MASK = 0b1111; - public final static long RED_MASK = 0b1111_1111; - public final static long GREEN_MASK = 0b1111_1111; - public final static long BLUE_MASK = 0b1111_1111; - public final static long COLOR_MASK = 0b11111111_11111111_11111111; - public final static long HEIGHT_MASK = 0b11_1111_1111; - public final static long DEPTH_MASK = 0b11_1111_1111; - //public final static long LIGHTS_MASK = 0b1111_1111; - public final static long BLOCK_LIGHT_MASK = 0b1111; - public final static long SKY_LIGHT_MASK = 0b1111; - //public final static long VERTICAL_INDEX_MASK = 0b11; - public final static long FLAG_MASK = 0b1; - public final static long GEN_TYPE_MASK = 0b111; - public final static long VOID_MASK = 1; - public final static long EXISTENCE_MASK = 1; - - - public static long createVoidDataPoint(int generationMode) - { - long dataPoint = 0; - dataPoint += (generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT; - dataPoint += VOID_MASK << VOID_SHIFT; - dataPoint += EXISTENCE_MASK << EXISTENCE_SHIFT; - return dataPoint; - } - - public static long createDataPoint(int height, int depth, int color, int lightSky, int lightBlock, int generationMode, boolean flag) - { - return createDataPoint( - ColorUtil.getAlpha(color), - ColorUtil.getRed(color), - ColorUtil.getGreen(color), - ColorUtil.getBlue(color), - height, depth, lightSky, lightBlock, generationMode, flag); - } - - public static long createDataPoint(int alpha, int red, int green, int blue, int height, int depth, int lightSky, int lightBlock, int generationMode, boolean flag) - { - long dataPoint = 0; - dataPoint += (long) (alpha >>> ALPHA_DOWNSIZE_SHIFT) << ALPHA_SHIFT; - dataPoint += (red & RED_MASK) << RED_SHIFT; - dataPoint += (green & GREEN_MASK) << GREEN_SHIFT; - dataPoint += (blue & BLUE_MASK) << BLUE_SHIFT; - dataPoint += (height & HEIGHT_MASK) << HEIGHT_SHIFT; - dataPoint += (depth & DEPTH_MASK) << DEPTH_SHIFT; - dataPoint += (lightBlock & BLOCK_LIGHT_MASK) << BLOCK_LIGHT_SHIFT; - dataPoint += (lightSky & SKY_LIGHT_MASK) << SKY_LIGHT_SHIFT; - dataPoint += (generationMode & GEN_TYPE_MASK) << GEN_TYPE_SHIFT; - if (flag) - dataPoint += FLAG_MASK << FLAG_SHIFT; - dataPoint += EXISTENCE_MASK << EXISTENCE_SHIFT; - - return dataPoint; - } - - public static short getHeight(long dataPoint) - { - return (short) ((dataPoint >>> HEIGHT_SHIFT) & HEIGHT_MASK); - } - - public static short getDepth(long dataPoint) - { - return (short) ((dataPoint >>> DEPTH_SHIFT) & DEPTH_MASK); - } - - public static short getAlpha(long dataPoint) - { - return (short) ((((dataPoint >>> ALPHA_SHIFT) & ALPHA_MASK) << ALPHA_DOWNSIZE_SHIFT) | 0b1111); - } - - public static short getRed(long dataPoint) - { - return (short) ((dataPoint >>> RED_SHIFT) & RED_MASK); - } - - public static short getGreen(long dataPoint) - { - return (short) ((dataPoint >>> GREEN_SHIFT) & GREEN_MASK); - } - - public static short getBlue(long dataPoint) - { - return (short) ((dataPoint >>> BLUE_SHIFT) & BLUE_MASK); - } - - public static byte getLightSky(long dataPoint) - { - return (byte) ((dataPoint >>> SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK); - } - - public static byte getLightSkyAlt(long dataPoint) - { - if (skyLightPlayer == 0 && ((dataPoint >>> FLAG_SHIFT) & FLAG_MASK) == 1) - return 0; - else - return (byte) ((dataPoint >>> SKY_LIGHT_SHIFT) & SKY_LIGHT_MASK); - } - - public static byte getLightBlock(long dataPoint) - { - return (byte) ((dataPoint >>> BLOCK_LIGHT_SHIFT) & BLOCK_LIGHT_MASK); - } - - public static boolean getFlag(long dataPoint) - { - return ((dataPoint >>> FLAG_SHIFT) & FLAG_MASK) == 1; - } - - public static byte getGenerationMode(long dataPoint) - { - return (byte) ((dataPoint >>> GEN_TYPE_SHIFT) & GEN_TYPE_MASK); - } - - - public static boolean isVoid(long dataPoint) - { - return (((dataPoint >>> VOID_SHIFT) & VOID_MASK) == 1); - } - - public static boolean doesItExist(long dataPoint) - { - return (((dataPoint >>> EXISTENCE_SHIFT) & EXISTENCE_MASK) == 1); - } - - public static int getColor(long dataPoint) - { - return (int) (((dataPoint >>> COLOR_SHIFT) & COLOR_MASK) | (/*((dataPoint >>> (ALPHA_SHIFT - ALPHA_DOWNSIZE_SHIFT)) | 0b1111)*/255 << 24)); - } - - /** This is used to convert a dataPoint to string (useful for the print function) */ - @SuppressWarnings("unused") - public static String toString(long dataPoint) - { - return getHeight(dataPoint) + " " + - getDepth(dataPoint) + " " + - getAlpha(dataPoint) + " " + - getRed(dataPoint) + " " + - getBlue(dataPoint) + " " + - getGreen(dataPoint) + " " + - getLightBlock(dataPoint) + " " + - getLightSky(dataPoint) + " " + - getGenerationMode(dataPoint) + " " + - isVoid(dataPoint) + " " + - doesItExist(dataPoint) + '\n'; - } - - 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 - * @return one column of correctly parsed data - */ - public static long[] mergeMultiData(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((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 (doesItExist(singleData)) - { - genMode = Math.min(genMode, getGenerationMode(singleData)); - allEmpty = false; - if (!isVoid(singleData)) - { - allVoid = false; - depth = getDepth(singleData); - height = 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 dataPoint; - if (allVoid) - { - dataPoint[0] = createVoidDataPoint(genMode); - return dataPoint; - } - - //we limit the vertical portion to maxVerticalData - int j = 0; - while (count > maxVerticalData) - { - ii = WORLD_HEIGHT - 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--) - { - 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 (doesItExist(singleData) && !isVoid(singleData)) - { - - if ((depth <= getDepth(singleData) && getDepth(singleData) <= height) - || (depth <= getHeight(singleData) && getHeight(singleData) <= height)) - { - if (getHeight(singleData) > getHeight(data)) - data = singleData; - } - } - else - break; - } - if (!doesItExist(data)) - { - singleData = dataToMerge[index * inputVerticalData]; - data = createVoidDataPoint(getGenerationMode(singleData)); - } - - if (doesItExist(data)) - { - allEmpty = false; - if (!isVoid(data)) - { - numberOfChildren++; - allVoid = false; - tempAlpha += getAlpha(data); - tempRed += getRed(data); - tempGreen += getGreen(data); - tempBlue += getBlue(data); - tempLightBlock += getLightBlock(data); - tempLightSky += getLightSky(data); - if (!getFlag(data)) - allDefault = false; - } - tempGenMode = (byte) Math.min(tempGenMode, getGenerationMode(data)); - } - else - tempGenMode = (byte) Math.min(tempGenMode, DistanceGenerationMode.NONE.complexity); - } - - if (allEmpty) - //no child has been initialized - dataPoint[j] = EMPTY_DATA; - else if (allVoid) - //all the children are void - dataPoint[j] = 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; - dataPoint[j] = createDataPoint(tempAlpha, tempRed, tempGreen, tempBlue, height, depth, tempLightSky, tempLightBlock, tempGenMode, allDefault); - } - } - return dataPoint; - } -} 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 1589bfea1..4a6d29ac3 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 @@ -24,6 +24,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.Arrays; import com.seibel.lod.core.dataFormat.*; import com.seibel.lod.core.enums.config.DistanceGenerationMode; @@ -1141,11 +1142,22 @@ public class VerticalLevelContainer implements LevelContainer return new VerticalLevelContainer((byte) (getDetailLevel() - 1)); } + private static final ThreadLocal tLocalVerticalUpdateArrays = ThreadLocal.withInitial(() -> + { + return new long[LodUtil.DETAIL_OPTIONS - 1][]; + }); + @Override public void updateData(LevelContainer lowerLevelContainer, int posX, int posZ) { //We reset the array - long[] dataToMerge = ThreadMapUtil.getVerticalUpdateArray(detailLevel); + 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; 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 e9bebe65e..43b4234a7 100644 --- a/src/main/java/com/seibel/lod/core/util/DataPointUtil.java +++ b/src/main/java/com/seibel/lod/core/util/DataPointUtil.java @@ -19,6 +19,8 @@ package com.seibel.lod.core.util; +import java.util.Arrays; + import com.seibel.lod.core.enums.config.DistanceGenerationMode; @@ -307,7 +309,9 @@ public class DataPointUtil } return anyChange; } - + + private static final ThreadLocal tLocalHeightAndDepth = new ThreadLocal(); + private static final ThreadLocal tMaxVerticalData = new ThreadLocal(); /** * This method merge column of multiple data together * @param dataToMerge one or more columns of data @@ -318,10 +322,20 @@ public class DataPointUtil public static long[] mergeMultiData(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((WORLD_HEIGHT + 1) * 2); - long[] dataPoint = ThreadMapUtil.getVerticalDataArray(DetailDistanceUtil.getMaxVerticalData(0)); + int heightAndDepthLength = (WORLD_HEIGHT / 2 + 1) * 2; + short[] heightAndDepth = tLocalHeightAndDepth.get(); + if (heightAndDepth==null || heightAndDepth.length != heightAndDepthLength) { + heightAndDepth = new short[heightAndDepthLength]; + tLocalHeightAndDepth.set(heightAndDepth); + } + int dataPointLength = DetailDistanceUtil.getMaxVerticalData(0); + long[] dataPoint = tMaxVerticalData.get(); + if (dataPoint==null || dataPoint.length != dataPointLength) { + dataPoint = new long[dataPointLength]; + tMaxVerticalData.set(dataPoint); + } else Arrays.fill(dataPoint, 0); int genMode = getGenerationMode(dataToMerge[0]); boolean allEmpty = true; diff --git a/src/main/java/com/seibel/lod/core/util/ThreadMapUtil.java b/src/main/java/com/seibel/lod/core/util/ThreadMapUtil.java deleted file mode 100644 index 466426d98..000000000 --- a/src/main/java/com/seibel/lod/core/util/ThreadMapUtil.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * This file is part of the Distant Horizon mod (formerly the LOD Mod), - * licensed under the GNU GPL v3 License. - * - * Copyright (C) 2020 James Seibel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.seibel.lod.core.util; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import com.seibel.lod.core.enums.LodDirection; -import com.seibel.lod.core.objects.VertexOptimizer; - -// FIXME: Nuke this whole thing and use ThreadLocal instead. And no more redundant get() please! - -/** - * Holds data used by specific threads so - * the data doesn't have to be recreated every - * time it is needed. - * - * @author Leonardo Amato - * @version 9-25-2021 - */ -public class ThreadMapUtil -{ - public static final ConcurrentMap threadSingleUpdateMap = new ConcurrentHashMap<>(); - public static final ConcurrentMap threadBuilderArrayMap = new ConcurrentHashMap<>(); - public static final ConcurrentMap threadBuilderVerticalArrayMap = new ConcurrentHashMap<>(); - public static final ConcurrentMap threadVerticalAddDataMap = new ConcurrentHashMap<>(); - public static final ConcurrentMap projectionArrayMap = new ConcurrentHashMap<>(); - public static final ConcurrentMap heightAndDepthMap = new ConcurrentHashMap<>(); - public static final ConcurrentMap singleDataToMergeMap = new ConcurrentHashMap<>(); - public static final ConcurrentMap verticalUpdate = new ConcurrentHashMap<>(); - - - //________________________// - // used in BufferBuilder // - //________________________// - - public static final ConcurrentMap adjShadeDisabled = new ConcurrentHashMap<>(); - public static final ConcurrentMap> adjDataMap = new ConcurrentHashMap<>(); - public static final ConcurrentMap boxMap = new ConcurrentHashMap<>(); - - - - /** returns the array NOT cleared every time */ - public static boolean[] getAdjShadeDisabledArray() - { - if (!adjShadeDisabled.containsKey(Thread.currentThread().getName()) - || (adjShadeDisabled.get(Thread.currentThread().getName()) == null)) - { - adjShadeDisabled.put(Thread.currentThread().getName(), new boolean[VertexOptimizer.DIRECTIONS.length]); - } - Arrays.fill(adjShadeDisabled.get(Thread.currentThread().getName()), false); - return adjShadeDisabled.get(Thread.currentThread().getName()); - } - - /** returns the array NOT cleared every time */ - public static Map getAdjDataArray(int verticalData) - { - if (!adjDataMap.containsKey(Thread.currentThread().getName()) - || (adjDataMap.get(Thread.currentThread().getName()) == null) - || (adjDataMap.get(Thread.currentThread().getName()).get(LodDirection.NORTH) == null) - || (adjDataMap.get(Thread.currentThread().getName()).get(LodDirection.NORTH).length != verticalData)) - { - adjDataMap.put(Thread.currentThread().getName(), new HashMap<>()); - adjDataMap.get(Thread.currentThread().getName()).put(LodDirection.UP, new long[1]); - adjDataMap.get(Thread.currentThread().getName()).put(LodDirection.DOWN, new long[1]); - for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS) - adjDataMap.get(Thread.currentThread().getName()).put(lodDirection, new long[verticalData]); - } - else - { - - for (LodDirection lodDirection : VertexOptimizer.ADJ_DIRECTIONS) - Arrays.fill(adjDataMap.get(Thread.currentThread().getName()).get(lodDirection), DataPointUtil.EMPTY_DATA); - } - return adjDataMap.get(Thread.currentThread().getName()); - } - - public static VertexOptimizer getBox() - { - if (!boxMap.containsKey(Thread.currentThread().getName()) - || (boxMap.get(Thread.currentThread().getName()) == null)) - { - boxMap.put(Thread.currentThread().getName(), new VertexOptimizer()); - } - boxMap.get(Thread.currentThread().getName()).reset(); - return boxMap.get(Thread.currentThread().getName()); - } - - //________________________// - // used in DataPointUtil // - // mergeVerticalData // - //________________________// - - - //________________________// - // used in DataPointUtil // - // mergeSingleData // - //________________________// - - - - //TODO: Maybe use actual valid total world height instead of always assuming the worse and alloc 1024 blocks. - /** returns the array filled with 0's */ - public static long[] getBuilderVerticalArray(int detailLevel) - { - if (!threadBuilderVerticalArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMap.get(Thread.currentThread().getName()) == null)) - { - long[][] array = new long[5][]; - int size; - for (int i = 0; i < 5; i++) - { - size = 1 << i; - array[i] = new long[size * size * (DataPointUtil.WORLD_HEIGHT / 2 + 1)]; - } - threadBuilderVerticalArrayMap.put(Thread.currentThread().getName(), array); - } - Arrays.fill(threadBuilderVerticalArrayMap.get(Thread.currentThread().getName())[detailLevel], 0); - return threadBuilderVerticalArrayMap.get(Thread.currentThread().getName())[detailLevel]; - } - - /** returns the array filled with 0's */ - public static long[] getVerticalDataArray(int arrayLength) - { - long[] array = threadVerticalAddDataMap.get(Thread.currentThread().getName()); - if (array == null || array.length != arrayLength) - { - array = new long[arrayLength]; - threadVerticalAddDataMap.put(Thread.currentThread().getName(), array); - } - else - Arrays.fill(array, 0); - return array; - } - - - //FIXME: If the arrayLength change, this may return incorrect sized array - /** returns the array NOT cleared every time */ - public static short[] getHeightAndDepth(int arrayLength) - { - if (!heightAndDepthMap.containsKey(Thread.currentThread().getName()) || (heightAndDepthMap.get(Thread.currentThread().getName()) == null)) - { - heightAndDepthMap.put(Thread.currentThread().getName(), new short[arrayLength]); - } - return heightAndDepthMap.get(Thread.currentThread().getName()); - } - - - /** returns the array filled with 0's */ - public static long[] getVerticalUpdateArray(int detailLevel) - { - detailLevel--; //we are asking for a place to fit lower level detail, so this will never get called with value of 0 - long[][] arrays = verticalUpdate.get(Thread.currentThread().getName()); - if (arrays == null) - { - arrays = new long[LodUtil.DETAIL_OPTIONS - 1][]; - verticalUpdate.put(Thread.currentThread().getName(), arrays); - } - long[] array = arrays[detailLevel]; - int arrayLength = DetailDistanceUtil.getMaxVerticalData(detailLevel) * 4; - if (array == null || array.length != arrayLength) - array = new long[arrayLength]; - else - Arrays.fill(array, 0); - return array; - } - - /** clears all arrays so they will have to be rebuilt */ - public static void clearMaps() - { - adjShadeDisabled.clear(); - adjDataMap.clear(); - boxMap.clear(); - threadSingleUpdateMap.clear(); - threadBuilderArrayMap.clear(); - threadBuilderVerticalArrayMap.clear(); - threadVerticalAddDataMap.clear(); - projectionArrayMap.clear(); - heightAndDepthMap.clear(); - singleDataToMergeMap.clear(); - verticalUpdate.clear(); - } -}