Trash ThreadMapUtil replaced by ThreadLocal. Trash an unused class
This commit is contained in:
@@ -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()
|
||||
|
||||
+19
-5
@@ -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<VertexOptimizer> tLocalVertexOptimizer = ThreadLocal.withInitial(VertexOptimizer::new);
|
||||
private static HashMap<LodDirection,long[]> makeAdjData(int verticalData) {
|
||||
HashMap<LodDirection,long[]> 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<Map<LodDirection, long[]>> tLocalAdjData = new ThreadLocal<Map<LodDirection, long[]>>();
|
||||
|
||||
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<LodDirection, long[]> adjData = ThreadMapUtil.getAdjDataArray(maxVerticalData);
|
||||
Map<LodDirection, long[]> 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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<long[][]> 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;
|
||||
|
||||
@@ -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<short[]> tLocalHeightAndDepth = new ThreadLocal<short[]>();
|
||||
private static final ThreadLocal<long[]> tMaxVerticalData = new ThreadLocal<long[]>();
|
||||
/**
|
||||
* 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;
|
||||
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<String, long[]> threadSingleUpdateMap = new ConcurrentHashMap<>();
|
||||
public static final ConcurrentMap<String, long[][]> threadBuilderArrayMap = new ConcurrentHashMap<>();
|
||||
public static final ConcurrentMap<String, long[][]> threadBuilderVerticalArrayMap = new ConcurrentHashMap<>();
|
||||
public static final ConcurrentMap<String, long[]> threadVerticalAddDataMap = new ConcurrentHashMap<>();
|
||||
public static final ConcurrentMap<String, short[]> projectionArrayMap = new ConcurrentHashMap<>();
|
||||
public static final ConcurrentMap<String, short[]> heightAndDepthMap = new ConcurrentHashMap<>();
|
||||
public static final ConcurrentMap<String, long[]> singleDataToMergeMap = new ConcurrentHashMap<>();
|
||||
public static final ConcurrentMap<String, long[][]> verticalUpdate = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
//________________________//
|
||||
// used in BufferBuilder //
|
||||
//________________________//
|
||||
|
||||
public static final ConcurrentMap<String, boolean[]> adjShadeDisabled = new ConcurrentHashMap<>();
|
||||
public static final ConcurrentMap<String, Map<LodDirection, long[]>> adjDataMap = new ConcurrentHashMap<>();
|
||||
public static final ConcurrentMap<String, VertexOptimizer> 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<LodDirection, long[]> 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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user