diff --git a/src/main/java/com/seibel/lod/builders/LodBuilder.java b/src/main/java/com/seibel/lod/builders/LodBuilder.java index 5216effdc..9e549ee87 100644 --- a/src/main/java/com/seibel/lod/builders/LodBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBuilder.java @@ -275,13 +275,8 @@ public class LodBuilder { int size = 1 << detail.detailLevel; - long[] dataToMerge = ThreadMapUtil.getBuilderVerticalArray()[detail.detailLevel]; + long[] dataToMerge = ThreadMapUtil.getFreshBuilderVerticalArray(size * size * DataPointUtil.worldHeight + 1, detail.detailLevel); - if (dataToMerge == null || dataToMerge.length != size * size * DataPointUtil.worldHeight + 1) - dataToMerge = new long[size * size * DataPointUtil.worldHeight + 1]; - - for (int i = 0; i < dataToMerge.length; i++) - dataToMerge[i] = DataPointUtil.EMPTY_DATA; int verticalData = DataPointUtil.worldHeight; @@ -429,7 +424,7 @@ public class LodBuilder private long[] createSingleDataToMerge(HorizontalResolution detail, IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX, int endZ) { - long[] dataToMerge = ThreadMapUtil.getBuilderArray()[detail.detailLevel]; + long[] dataToMerge = ThreadMapUtil.getBuilderArray(detail.detailLevel); ChunkPos chunkPos = chunk.getPos(); int size = 1 << detail.detailLevel; diff --git a/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java b/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java index fb7b5f08d..96cf4e4a6 100644 --- a/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java +++ b/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java @@ -38,7 +38,6 @@ import com.seibel.lod.util.LodUtil; import net.minecraft.block.Block; import net.minecraft.block.BlockState; -import net.minecraft.util.WeightedList.Entry; import net.minecraft.util.math.ChunkPos; import net.minecraft.util.palette.UpgradeData; import net.minecraft.util.registry.Registry; @@ -74,7 +73,6 @@ import net.minecraftforge.common.WorldWorkerManager.IWorker; public class LodNodeGenWorker implements IWorker { public static ExecutorService genThreads = Executors.newFixedThreadPool(LodConfig.CLIENT.threading.numberOfWorldGenerationThreads.get(), new ThreadFactoryBuilder().setNameFormat("Gen-Worker-Thread-%d").build()); - //public static ExecutorService genThreads = Executors.newFixedThreadPool(LodConfig.CLIENT.threading.numberOfWorldGenerationThreads.get(), new LodThreadFactory(LodNodeGenWorker.class.getSimpleName())); private boolean threadStarted = false; private LodChunkGenThread thread; @@ -111,10 +109,6 @@ public class LodNodeGenWorker implements IWorker newLodDimension, newServerWorld); } - public static void resetGenerator(){ - ExecutorService genThreads = Executors.newFixedThreadPool(LodConfig.CLIENT.threading.numberOfWorldGenerationThreads.get(), new ThreadFactoryBuilder().setNameFormat("Gen-Worker-Thread-%d").build()); - } - @Override public boolean doWork() { diff --git a/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java b/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java index ba0bf0dd2..b242bf1f7 100644 --- a/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java +++ b/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java @@ -155,11 +155,8 @@ public class SingleLevelContainer implements LevelContainer { int index = 0; int tempIndex; - byte[] tempData = ThreadMapUtil.getSaveContainer(); - if (tempData == null || tempData.length != (1 + (size * size * 8))) - tempData = new byte[1 + (size * size * 8)]; - else - Arrays.fill(tempData, (byte) 0); + byte[] tempData = ThreadMapUtil.getFreshSaveContainer(1 + (size * size * 8)); + tempData[index] = detailLevel; index++; for (int x = 0; x < size; x++) diff --git a/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java b/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java index e79950a44..c4e0da35d 100644 --- a/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java +++ b/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java @@ -1,9 +1,13 @@ package com.seibel.lod.objects; -import com.seibel.lod.util.*; - import java.util.Arrays; +import com.seibel.lod.util.DataPointUtil; +import com.seibel.lod.util.DetailDistanceUtil; +import com.seibel.lod.util.LevelPosUtil; +import com.seibel.lod.util.LodUtil; +import com.seibel.lod.util.ThreadMapUtil; + public class VerticalLevelContainer implements LevelContainer { @@ -27,6 +31,7 @@ public class VerticalLevelContainer implements LevelContainer return detailLevel; } + @Override public void clear(int posX, int posZ){ posX = LevelPosUtil.getRegionModule(detailLevel, posX); @@ -36,6 +41,7 @@ public class VerticalLevelContainer implements LevelContainer } } + @Override public boolean addData(long data, int posX, int posZ, int verticalIndex){ posX = LevelPosUtil.getRegionModule(detailLevel, posX); @@ -44,20 +50,24 @@ public class VerticalLevelContainer implements LevelContainer return true; } + @Override public boolean addSingleData(long data, int posX, int posZ){ return addData(data, posX, posZ, 0); } + @Override public long getData(int posX, int posZ, int verticalIndex){ posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); return dataContainer[posX*size*maxVerticalData + posZ*maxVerticalData + verticalIndex]; } + @Override public long getSingleData(int posX, int posZ){ return getData(posX,posZ,0); } + @Override public int getMaxVerticalData(){ return maxVerticalData; } @@ -66,6 +76,7 @@ public class VerticalLevelContainer implements LevelContainer return size; } + @Override public boolean doesItExist(int posX, int posZ){ posX = LevelPosUtil.getRegionModule(detailLevel, posX); posZ = LevelPosUtil.getRegionModule(detailLevel, posZ); @@ -126,19 +137,16 @@ public class VerticalLevelContainer implements LevelContainer } } + @Override public LevelContainer expand(){ return new VerticalLevelContainer((byte) (getDetailLevel() - 1)); } + @Override public void updateData(LevelContainer lowerLevelContainer, int posX, int posZ) { //We reset the array - long[] dataToMerge = ThreadMapUtil.getVerticalUpdateArray()[detailLevel]; - - if(dataToMerge == null || dataToMerge.length != 4*lowerLevelContainer.getMaxVerticalData()) - dataToMerge = new long[4 * lowerLevelContainer.getMaxVerticalData()]; - else - Arrays.fill(dataToMerge, DataPointUtil.EMPTY_DATA); + long[] dataToMerge = ThreadMapUtil.getFreshVerticalUpdateArray(4 * lowerLevelContainer.getMaxVerticalData(), detailLevel); int lowerMaxVertical = dataToMerge.length/4; int childPosX; @@ -157,7 +165,7 @@ public class VerticalLevelContainer implements LevelContainer } } data = DataPointUtil.mergeMultiData(dataToMerge, lowerMaxVertical, getMaxVerticalData()); - + for(int verticalIndex = 0; (verticalIndex < data.length) && (verticalIndex < maxVerticalData); verticalIndex++) { addData(data[verticalIndex], @@ -167,6 +175,7 @@ public class VerticalLevelContainer implements LevelContainer } } + @Override public byte[] toDataString() { int index = 0; @@ -174,12 +183,9 @@ public class VerticalLevelContainer implements LevelContainer byte last = -1; int x = size * size * maxVerticalData; int tempIndex; - byte[] tempData = ThreadMapUtil.getSaveContainer(); long current; - if(tempData == null || tempData.length != (2 + (x * 8))) - tempData = new byte[2 + (x * 8)]; - else - Arrays.fill(tempData, (byte) 0); + + byte[] tempData = ThreadMapUtil.getFreshSaveContainer(2 + (x * 8)); tempData[index] = detailLevel; index++; @@ -243,10 +249,12 @@ public class VerticalLevelContainer implements LevelContainer return " "; } + @Override public int getMaxNumberOfLods(){ return size*size*getMaxVerticalData(); } + @Override public int getMaxMemoryUse(){ return getMaxNumberOfLods() * 2; //2 byte } diff --git a/src/main/java/com/seibel/lod/util/DataPointUtil.java b/src/main/java/com/seibel/lod/util/DataPointUtil.java index bf6652081..ba0a777ac 100644 --- a/src/main/java/com/seibel/lod/util/DataPointUtil.java +++ b/src/main/java/com/seibel/lod/util/DataPointUtil.java @@ -1,7 +1,5 @@ package com.seibel.lod.util; -import java.util.Arrays; - import com.seibel.lod.enums.DistanceGenerationMode; import net.minecraft.client.renderer.texture.NativeImage; @@ -279,31 +277,12 @@ public class DataPointUtil { int size = dataToMerge.length / inputVerticalData; - //We initialise the arrays that are going to be used - short[] projection = ThreadMapUtil.getProjectionShort(); - short[] heightAndDepth = ThreadMapUtil.getHeightAndDepth(); - long[] singleDataToMerge = ThreadMapUtil.getSingleAddDataToMerge(); - long[] dataPoint = ThreadMapUtil.verticalDataArray(); + // We initialize the arrays that are going to be used + short[] projection = ThreadMapUtil.getFreshProjectionArray((worldHeight) / 16 + 1); + short[] heightAndDepth = ThreadMapUtil.getFreshHeightAndDepth((worldHeight + 1) * 2); + long[] singleDataToMerge = ThreadMapUtil.getFreshSingleAddDataToMerge(size); + long[] dataPoint = ThreadMapUtil.getFreshVerticalDataArray(worldHeight + 1); - if (projection == null || projection.length != (worldHeight) / 16 + 1) - projection = new short[(worldHeight) / 16 + 1]; - else - Arrays.fill(projection, (short) 0); - - if (heightAndDepth == null || heightAndDepth.length != (worldHeight + 1) * 2) - heightAndDepth = new short[(worldHeight + 1) * 2]; - else - Arrays.fill(heightAndDepth, (short) 0); - - if (singleDataToMerge == null || singleDataToMerge.length != size) - singleDataToMerge = new long[size]; - else - Arrays.fill(singleDataToMerge, EMPTY_DATA); - - if (dataPoint == null || dataPoint.length != worldHeight + 1) - dataPoint = new long[worldHeight + 1]; - else - Arrays.fill(dataPoint, EMPTY_DATA); int genMode = DistanceGenerationMode.SERVER.complexity; boolean allEmpty = true; diff --git a/src/main/java/com/seibel/lod/util/ThreadMapUtil.java b/src/main/java/com/seibel/lod/util/ThreadMapUtil.java index e77b87377..6901e7393 100644 --- a/src/main/java/com/seibel/lod/util/ThreadMapUtil.java +++ b/src/main/java/com/seibel/lod/util/ThreadMapUtil.java @@ -1,8 +1,17 @@ package com.seibel.lod.util; +import java.util.Arrays; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +/** + * 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<>(); @@ -10,11 +19,20 @@ public class ThreadMapUtil public static final ConcurrentMap threadBuilderVerticalArrayMap = new ConcurrentHashMap<>(); public static final ConcurrentMap threadVerticalAddDataMap = new ConcurrentHashMap<>(); public static final ConcurrentMap saveContainer = new ConcurrentHashMap<>(); - public static final ConcurrentMap projectionShortMap = 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<>(); - + + + + /** returns the array filled with 0's */ + public static long[] getFreshSingleUpdateArray(int arrayLength) + { + long[] array = getSingleUpdateArray(); + clearOrCreateArray(array, arrayLength); + return array; + } public static long[] getSingleUpdateArray() { if (!threadSingleUpdateMap.containsKey(Thread.currentThread().getName()) || (threadSingleUpdateMap.get(Thread.currentThread().getName()) == null)) @@ -23,28 +41,52 @@ public class ThreadMapUtil } return threadSingleUpdateMap.get(Thread.currentThread().getName()); } - - public static long[][] getBuilderArray() + + + /** returns the array filled with 0's */ + public static long[] getFreshBuilderArray(int arrayLength, int detailLevel) + { + long[] array = getBuilderArray(detailLevel); + clearOrCreateArray(array, arrayLength); + return array; + } + public static long[] getBuilderArray(int detailLevel) { if (!threadBuilderArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderArrayMap.get(Thread.currentThread().getName()) == null)) { long[][] array = new long[5][]; threadBuilderArrayMap.put(Thread.currentThread().getName(), array); } - return threadBuilderArrayMap.get(Thread.currentThread().getName()); + return threadBuilderArrayMap.get(Thread.currentThread().getName())[detailLevel]; } - - public static long[][] getBuilderVerticalArray() + + + /** returns the array filled with 0's */ + public static long[] getFreshBuilderVerticalArray(int arrayLength, int detailLevel) + { + long[] array = getBuilderVerticalArray(detailLevel); + clearOrCreateArray(array, arrayLength); + return array; + } + public static long[] getBuilderVerticalArray(int detailLevel) { if (!threadBuilderVerticalArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMap.get(Thread.currentThread().getName()) == null)) { long[][] array = new long[5][]; threadBuilderVerticalArrayMap.put(Thread.currentThread().getName(), array); } - return threadBuilderVerticalArrayMap.get(Thread.currentThread().getName()); + return threadBuilderVerticalArrayMap.get(Thread.currentThread().getName())[detailLevel]; } - - public static long[] verticalDataArray() + + + /** returns the array filled with 0's */ + public static long[] getFreshVerticalDataArray(int arrayLength) + { + long[] array = getVerticalDataArray(); + clearOrCreateArray(array, arrayLength); + return array; + } + public static long[] getVerticalDataArray() { if (!threadVerticalAddDataMap.containsKey(Thread.currentThread().getName()) || (threadVerticalAddDataMap.get(Thread.currentThread().getName()) == null)) { @@ -52,57 +94,148 @@ public class ThreadMapUtil } return threadVerticalAddDataMap.get(Thread.currentThread().getName()); } - - public static short[] getProjectionShort(){ - if(!projectionShortMap.containsKey(Thread.currentThread().getName()) || (projectionShortMap.get(Thread.currentThread().getName()) == null)) - { - projectionShortMap.put(Thread.currentThread().getName(), new short[0]); - } - return projectionShortMap.get(Thread.currentThread().getName()); + + + + /** returns the array filled with 0's */ + public static short[] getFreshProjectionArray(int arrayLength) + { + short[] array = getProjectionArray(); + clearOrCreateArray(array, arrayLength); + return array; } - - public static short[] getHeightAndDepth(){ - if(!heightAndDepthMap.containsKey(Thread.currentThread().getName()) || (heightAndDepthMap.get(Thread.currentThread().getName()) == null)) + public static short[] getProjectionArray() + { + if (!projectionArrayMap.containsKey(Thread.currentThread().getName()) || (projectionArrayMap.get(Thread.currentThread().getName()) == null)) + { + projectionArrayMap.put(Thread.currentThread().getName(), new short[0]); + } + return projectionArrayMap.get(Thread.currentThread().getName()); + } + + + /** returns the array filled with 0's */ + public static short[] getFreshHeightAndDepth(int arrayLength) + { + short[] array = getHeightAndDepth(); + clearOrCreateArray(array, arrayLength); + return array; + } + public static short[] getHeightAndDepth() + { + if (!heightAndDepthMap.containsKey(Thread.currentThread().getName()) || (heightAndDepthMap.get(Thread.currentThread().getName()) == null)) { heightAndDepthMap.put(Thread.currentThread().getName(), new short[0]); } return heightAndDepthMap.get(Thread.currentThread().getName()); } - - public static byte[] getSaveContainer(){ - if(!saveContainer.containsKey(Thread.currentThread().getName()) || (saveContainer.get(Thread.currentThread().getName()) == null)) + + + /** returns the array filled with 0's */ + public static byte[] getFreshSaveContainer(int arrayLength) + { + byte[] array = getSaveContainer(); + clearOrCreateArray(array, arrayLength); + return array; + } + public static byte[] getSaveContainer() + { + if (!saveContainer.containsKey(Thread.currentThread().getName()) || (saveContainer.get(Thread.currentThread().getName()) == null)) { saveContainer.put(Thread.currentThread().getName(), new byte[0]); } return saveContainer.get(Thread.currentThread().getName()); } - - public static long[][] getVerticalUpdateArray(){ - if(!verticalUpdate.containsKey(Thread.currentThread().getName()) || (verticalUpdate.get(Thread.currentThread().getName()) == null)) + + /** returns the array filled with 0's */ + public static long[] getFreshVerticalUpdateArray(int arrayLength, int detailLevel) + { + long[] array = ThreadMapUtil.getVerticalUpdateArray(detailLevel); + clearOrCreateArray(array, arrayLength); + return array; + } + public static long[] getVerticalUpdateArray(int detailLevel) + { + if (!verticalUpdate.containsKey(Thread.currentThread().getName()) || (verticalUpdate.get(Thread.currentThread().getName()) == null)) { long[][] array = new long[10][]; verticalUpdate.put(Thread.currentThread().getName(), array); } - return verticalUpdate.get(Thread.currentThread().getName()); + return verticalUpdate.get(Thread.currentThread().getName())[detailLevel]; } - - public static long[] getSingleAddDataToMerge(){ - if(!singleDataToMergeMap.containsKey(Thread.currentThread().getName()) || (singleDataToMergeMap.get(Thread.currentThread().getName()) == null)) + + + /** returns the array filled with 0's */ + public static long[] getFreshSingleAddDataToMerge(int arrayLength) + { + long[] array = getSingleAddDataToMerge(); + clearOrCreateArray(array, arrayLength); + return array; + } + public static long[] getSingleAddDataToMerge() + { + if (!singleDataToMergeMap.containsKey(Thread.currentThread().getName()) || (singleDataToMergeMap.get(Thread.currentThread().getName()) == null)) { singleDataToMergeMap.put(Thread.currentThread().getName(), new long[0]); } return singleDataToMergeMap.get(Thread.currentThread().getName()); } - - public static void clearMaps(){ + + + + + /** clears all arrays so they will have to be rebuilt */ + public static void clearMaps() + { threadSingleUpdateMap.clear(); threadBuilderArrayMap.clear(); threadBuilderVerticalArrayMap.clear(); threadVerticalAddDataMap.clear(); saveContainer.clear(); - projectionShortMap.clear(); + projectionArrayMap.clear(); heightAndDepthMap.clear(); singleDataToMergeMap.clear(); verticalUpdate.clear(); } + + + + + /** fills the array with 0's */ + private static void clearOrCreateArray(long[] array, int arrayLength) + { + if (array == null || array.length != arrayLength) + array = new long[arrayLength]; + else + Arrays.fill(array, 0); + } + + /** fills the array with 0's */ + @SuppressWarnings("unused") + private static void clearOrCreateArray(int[] array, int arrayLength) + { + if (array == null || array.length != arrayLength) + array = new int[arrayLength]; + else + Arrays.fill(array, 0); + } + + /** fills the array with 0's */ + private static void clearOrCreateArray(short[] array, int arrayLength) + { + if (array == null || array.length != arrayLength) + array = new short[arrayLength]; + else + Arrays.fill(array, (short) 0); + } + + /** fills the array with 0's */ + private static void clearOrCreateArray(byte[] array, int arrayLength) + { + if (array == null || array.length != arrayLength) + array = new byte[arrayLength]; + else + Arrays.fill(array, (byte) 0); + } + }