From d65bfd408e87355302336ab244742caa50a485fd Mon Sep 17 00:00:00 2001 From: Leonardo Date: Wed, 22 Sep 2021 19:38:04 +0200 Subject: [PATCH] Fixed the artifacts (was caused by wrong array initialisation) and added the reset to while changing dimension --- .../com/seibel/lod/builders/LodBuilder.java | 23 ++++--- .../worldGeneration/LodNodeGenWorker.java | 4 ++ .../java/com/seibel/lod/config/LodConfig.java | 2 +- .../com/seibel/lod/objects/LodDimension.java | 26 ++------ .../lod/objects/SingleLevelContainer.java | 20 +++--- .../lod/objects/VerticalLevelContainer.java | 17 ++++-- .../com/seibel/lod/proxy/ClientProxy.java | 23 ++++++- .../com/seibel/lod/util/DataPointUtil.java | 40 ++++++++---- .../com/seibel/lod/util/ThreadMapUtil.java | 61 +++++++++---------- 9 files changed, 127 insertions(+), 89 deletions(-) diff --git a/src/main/java/com/seibel/lod/builders/LodBuilder.java b/src/main/java/com/seibel/lod/builders/LodBuilder.java index 124b85dc8..3ce05e760 100644 --- a/src/main/java/com/seibel/lod/builders/LodBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBuilder.java @@ -18,7 +18,6 @@ package com.seibel.lod.builders; import java.awt.Color; -import java.util.Arrays; import java.util.List; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; @@ -42,13 +41,11 @@ import com.seibel.lod.util.LodUtil; import com.seibel.lod.util.ThreadMapUtil; import com.seibel.lod.wrappers.MinecraftWrapper; -import net.minecraft.block.AbstractPlantBlock; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.BushBlock; import net.minecraft.block.GrassBlock; -import net.minecraft.block.IGrowable; import net.minecraft.block.LeavesBlock; import net.minecraft.block.material.MaterialColor; import net.minecraft.client.renderer.model.BakedQuad; @@ -69,8 +66,6 @@ import net.minecraft.world.gen.Heightmap; import net.minecraftforge.client.extensions.IForgeBakedModel; import net.minecraftforge.client.model.data.ModelDataMap; -import javax.xml.crypto.Data; - /** * This object is in charge of creating Lod related objects. (specifically: Lod * World, Dimension, and Region objects) @@ -156,6 +151,7 @@ public class LodBuilder if (lodWorld.getLodDimension(dim) == null) { lodDim = new LodDimension(dim, lodWorld, defaultDimensionWidthInRegions); + ThreadMapUtil.clearMaps(); lodWorld.addLodDimension(lodDim); lodDim.treeGenerator(playerPosX, playerPosZ); } else @@ -238,7 +234,7 @@ public class LodBuilder break; case MULTI_LOD: long[] dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ, endX, endZ); - data = DataPointUtil.mergeMultiData(dataToMergeVertical, DataPointUtil.WORLD_HEIGHT, DetailDistanceUtil.getMaxVerticalData(detailLevel)); + data = DataPointUtil.mergeMultiData(dataToMergeVertical, DataPointUtil.worldHeight, DetailDistanceUtil.getMaxVerticalData(detailLevel)); //lodDim.clear(detailLevel, posX, posZ); @@ -271,12 +267,19 @@ public class LodBuilder private long[] createVerticalDataToMerge(HorizontalResolution detail, IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX, int endZ) { + int size = 1 << detail.detailLevel; + long[] dataToMerge = ThreadMapUtil.getBuilderVerticalArray()[detail.detailLevel]; - Arrays.fill(dataToMerge, DataPointUtil.EMPTY_DATA); - int verticalData = DataPointUtil.WORLD_HEIGHT; + + 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; ChunkPos chunkPos = chunk.getPos(); - int size = 1 << detail.detailLevel; int height; int depth; int color; @@ -304,7 +307,7 @@ public class LodBuilder zAbs = chunkPos.getMinBlockZ() + zRel; //Calculate the height of the lod - yAbs = DataPointUtil.WORLD_HEIGHT+2; + yAbs = DataPointUtil.worldHeight +2; int count = 0; boolean topBlock = true; while (yAbs > 0) 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 97c339317..fb7b5f08d 100644 --- a/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java +++ b/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java @@ -111,6 +111,10 @@ 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/config/LodConfig.java b/src/main/java/com/seibel/lod/config/LodConfig.java index cbebe2040..c7a22a1e7 100644 --- a/src/main/java/com/seibel/lod/config/LodConfig.java +++ b/src/main/java/com/seibel/lod/config/LodConfig.java @@ -125,7 +125,7 @@ public class LodConfig + DetailDropOff.BY_BLOCK + " in chunks circles around the player (best quality option, may cause stuttering)\n" + DetailDropOff.BY_REGION_FANCY + " in regions circles around the player (quality option)\n" + DetailDropOff.BY_REGION_FAST + " in regions circles around the player (performance option)\n") - .defineEnum("detailDropOff", DetailDropOff.BY_REGION_FAST); + .defineEnum("detailDropOff", DetailDropOff.BY_BLOCK); drawResolution = builder .comment("\n\n" diff --git a/src/main/java/com/seibel/lod/objects/LodDimension.java b/src/main/java/com/seibel/lod/objects/LodDimension.java index 1eba4da93..0ac2ce1b0 100644 --- a/src/main/java/com/seibel/lod/objects/LodDimension.java +++ b/src/main/java/com/seibel/lod/objects/LodDimension.java @@ -28,11 +28,7 @@ import com.seibel.lod.enums.GenerationPriority; import com.seibel.lod.enums.LodTemplate; import com.seibel.lod.enums.VerticalQuality; import com.seibel.lod.handlers.LodDimensionFileHandler; -import com.seibel.lod.util.DataPointUtil; -import com.seibel.lod.util.DetailDistanceUtil; -import com.seibel.lod.util.LevelPosUtil; -import com.seibel.lod.util.LodThreadFactory; -import com.seibel.lod.util.LodUtil; +import com.seibel.lod.util.*; import com.seibel.lod.wrappers.MinecraftWrapper; import net.minecraft.util.math.ChunkPos; @@ -535,23 +531,9 @@ public class LodDimension int posX; int posZ; long data; - int numbChunksWide = (width) * 32; - //int circleLimit = Integer.MAX_VALUE; + int numbChunksWide = (width) * 32 * 2; for (int i = 0; i < numbChunksWide * numbChunksWide; i++) { - // use this for square generation - if (maxDataToGenerate <= 0) - { - break; - } - - // use this for circular generation - /*if (circleLimit < Math.abs(x) && circleLimit < Math.abs(z)) - break; - if (maxDataToGenerate == 0) - { - circleLimit = (int) (Math.abs(x) * 1.6f); - }*/ xChunkToCheck = x + playerChunkX; @@ -568,8 +550,8 @@ public class LodDimension if (DataPointUtil.getGenerationMode(data) < LodConfig.CLIENT.worldGenerator.distanceGenerationMode.get().complexity) { posToGenerate.addPosToGenerate(detailLevel, posX, posZ); - if (maxDataToGenerate >= 0) - maxDataToGenerate--; + //if (maxDataToGenerate >= 0) + // maxDataToGenerate--; } if ((x == z) || ((x < 0) && (x == -z)) || ((x > 0) && (x == 1 - z))) { diff --git a/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java b/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java index 19c5c091a..6ec2a0509 100644 --- a/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java +++ b/src/main/java/com/seibel/lod/objects/SingleLevelContainer.java @@ -88,8 +88,7 @@ public class SingleLevelContainer implements LevelContainer { newData = 3; index++; - } - else if (index + 7 >= inputData.length) + } else if (index + 7 >= inputData.length) break; else { @@ -126,7 +125,8 @@ public class SingleLevelContainer implements LevelContainer addSingleData(data, posX, posZ); } - public int getMaxVerticalData(){ + public int getMaxVerticalData() + { return 1; } @@ -142,7 +142,11 @@ public class SingleLevelContainer implements LevelContainer { int index = 0; int tempIndex; - byte[] tempData = ThreadMapUtil.getSaveContainer(1 + (size * size * 8)); + 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); tempData[index] = detailLevel; index++; for (int x = 0; x < size; x++) @@ -177,11 +181,13 @@ public class SingleLevelContainer implements LevelContainer } - public int getMaxNumberOfLods(){ - return size*size*getMaxVerticalData(); + public int getMaxNumberOfLods() + { + return size * size * getMaxVerticalData(); } - public int getMaxMemoryUse(){ + public int getMaxMemoryUse() + { return getMaxNumberOfLods() * 2; //2 byte } } diff --git a/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java b/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java index 0c1442bb4..5e044b834 100644 --- a/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java +++ b/src/main/java/com/seibel/lod/objects/VerticalLevelContainer.java @@ -133,9 +133,13 @@ public class VerticalLevelContainer implements LevelContainer public void updateData(LevelContainer lowerLevelContainer, int posX, int posZ) { //We reset the array - int lowerMaxVerticalData = lowerLevelContainer.getMaxVerticalData(); - long[] dataToMerge = ThreadMapUtil.getVerticalUpdateArray(detailLevel); - Arrays.fill(dataToMerge, DataPointUtil.EMPTY_DATA); + 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); + int lowerMaxVertical = dataToMerge.length/4; int childPosX; int childPosZ; @@ -170,7 +174,12 @@ public class VerticalLevelContainer implements LevelContainer byte last = -1; int x = size * size * maxVerticalData; int tempIndex; - byte[] tempData = ThreadMapUtil.getSaveContainer(2 + (x * 8)); + byte[] tempData = ThreadMapUtil.getSaveContainer(); + if(tempData == null || tempData.length != (2 + (x * 8))) + tempData = new byte[2 + (x * 8)]; + else + Arrays.fill(tempData, (byte) 0); + tempData[index] = detailLevel; index++; tempData[index] = (byte) maxVerticalData; diff --git a/src/main/java/com/seibel/lod/proxy/ClientProxy.java b/src/main/java/com/seibel/lod/proxy/ClientProxy.java index ac8de0fc6..c0e2c46cf 100644 --- a/src/main/java/com/seibel/lod/proxy/ClientProxy.java +++ b/src/main/java/com/seibel/lod/proxy/ClientProxy.java @@ -17,6 +17,9 @@ */ package com.seibel.lod.proxy; +import com.seibel.lod.util.DataPointUtil; +import com.seibel.lod.util.ThreadMapUtil; +import net.minecraft.world.DimensionType; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.glfw.GLFW; @@ -85,7 +88,7 @@ public class ClientProxy * to the LOD view distance */ private boolean recalculateWidths = false; - + private DimensionType currentDimension = null; public ClientProxy() { @@ -112,9 +115,15 @@ public class ClientProxy // only run the first time setup once if (!firstTimeSetupComplete) { + ThreadMapUtil.clearMaps(); firstFrameSetup(); } + if(mc.getCurrentDimension() != currentDimension) + { + currentDimension = mc.getCurrentDimension(); + reset(); + } DetailDistanceUtil.updateSettings(); if (mc == null || mc.getPlayer() == null || !lodWorld.getIsWorldLoaded()) @@ -235,6 +244,7 @@ public class ClientProxy @SubscribeEvent public void worldLoadEvent(WorldEvent.Load event) { + DataPointUtil.worldHeight = event.getWorld().getHeight(); // the player just loaded a new world/dimension lodWorld.selectWorld(LodUtil.getWorldID(event.getWorld())); // make sure the correct LODs are being rendered @@ -360,8 +370,15 @@ public class ClientProxy firstTimeSetupComplete = true; } - - + + + public static void reset() + { + lodBufferBuilder = new LodBufferBuilder(); + renderer = new LodRenderer(lodBufferBuilder); + LodNodeGenWorker.resetGenerator(); + ThreadMapUtil.clearMaps(); + } //================// // public getters // diff --git a/src/main/java/com/seibel/lod/util/DataPointUtil.java b/src/main/java/com/seibel/lod/util/DataPointUtil.java index 03872bbc4..3b255f606 100644 --- a/src/main/java/com/seibel/lod/util/DataPointUtil.java +++ b/src/main/java/com/seibel/lod/util/DataPointUtil.java @@ -31,7 +31,7 @@ public class DataPointUtil //public final static int MIN_DEPTH = -64; //public final static int MIN_HEIGHT = -64; public final static int EMPTY_DATA = 0; - public final static int WORLD_HEIGHT = 256; + public static int worldHeight = 256; public final static int ALPHA_DOWNSIZE_SHIFT = 4; @@ -279,14 +279,32 @@ public class DataPointUtil public static long[] mergeMultiData(long[] dataToMerge, int inputVerticalData, int maxVerticalData) { int size = dataToMerge.length / inputVerticalData; - short[] projection = ThreadMapUtil.getProjectionShort((WORLD_HEIGHT) / 16 + 2); - short[] heightAndDepth = ThreadMapUtil.getHeightAndDepth((WORLD_HEIGHT + 1) * 2); - long[] singleDataToMerge = ThreadMapUtil.getSingleAddDataToMerge(size); - long[] dataPoint = ThreadMapUtil.verticalDataArray(WORLD_HEIGHT + 1); - Arrays.fill(projection, (short) 0); - Arrays.fill(heightAndDepth, (short) 0); - Arrays.fill(singleDataToMerge, EMPTY_DATA); - Arrays.fill(dataPoint, EMPTY_DATA); + + //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(); + + 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; @@ -355,7 +373,7 @@ public class DataPointUtil if (i == projection.length) //solid to WORLD_HEIGHT { heightAndDepth[count * 2] = depth; - heightAndDepth[count * 2 + 1] = WORLD_HEIGHT - 1; + heightAndDepth[count * 2 + 1] = (short) (worldHeight - 1); break; } while ((((projection[i] >>> ii) & 1) == 1)) ii++; @@ -370,7 +388,7 @@ public class DataPointUtil int j = 0; while (count > maxVerticalData) { - ii = WORLD_HEIGHT; + ii = worldHeight; for (i = 0; i < count - 1; i++) { if (heightAndDepth[(i + 1) * 2] - heightAndDepth[i * 2 + 1] < ii) diff --git a/src/main/java/com/seibel/lod/util/ThreadMapUtil.java b/src/main/java/com/seibel/lod/util/ThreadMapUtil.java index 6adb8c30e..7da3e3729 100644 --- a/src/main/java/com/seibel/lod/util/ThreadMapUtil.java +++ b/src/main/java/com/seibel/lod/util/ThreadMapUtil.java @@ -19,7 +19,7 @@ public class ThreadMapUtil { if (!threadSingleUpdateMap.containsKey(Thread.currentThread().getName()) || (threadSingleUpdateMap.get(Thread.currentThread().getName()) == null)) { - threadSingleUpdateMap.put(Thread.currentThread().getName(), new long[4]); + threadSingleUpdateMap.put(Thread.currentThread().getName(), new long[0]); } return threadSingleUpdateMap.get(Thread.currentThread().getName()); } @@ -39,71 +39,70 @@ public class ThreadMapUtil if (!threadBuilderVerticalArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMap.get(Thread.currentThread().getName()) == null)) { long[][] array = new long[5][]; - for(int i = 0; i < array.length; i++) - { - int size = 1 << i; - array[i] = new long[size * size * DataPointUtil.WORLD_HEIGHT]; - } threadBuilderVerticalArrayMap.put(Thread.currentThread().getName(), array); } return threadBuilderVerticalArrayMap.get(Thread.currentThread().getName()); } - public static long[] verticalDataArray(int count) + public static long[] verticalDataArray() { if (!threadVerticalAddDataMap.containsKey(Thread.currentThread().getName()) || (threadVerticalAddDataMap.get(Thread.currentThread().getName()) == null)) { - threadVerticalAddDataMap.put(Thread.currentThread().getName(), new long[count]); - } - for(int i = 0; i < threadVerticalAddDataMap.get(Thread.currentThread().getName()).length ; i++) - { - threadVerticalAddDataMap.get(Thread.currentThread().getName())[i] = DataPointUtil.EMPTY_DATA; + threadVerticalAddDataMap.put(Thread.currentThread().getName(), new long[0]); } return threadVerticalAddDataMap.get(Thread.currentThread().getName()); } - public static short[] getProjectionShort(int size){ - if(!projectionShortMap.containsKey(Thread.currentThread().getName()) || (projectionShortMap.get(Thread.currentThread().getName()) == null) || (projectionShortMap.get(Thread.currentThread().getName()).length != size)) + public static short[] getProjectionShort(){ + if(!projectionShortMap.containsKey(Thread.currentThread().getName()) || (projectionShortMap.get(Thread.currentThread().getName()) == null)) { - projectionShortMap.put(Thread.currentThread().getName(), new short[size]); + projectionShortMap.put(Thread.currentThread().getName(), new short[0]); } return projectionShortMap.get(Thread.currentThread().getName()); } - public static short[] getHeightAndDepth(int size){ - if(!heightAndDepthMap.containsKey(Thread.currentThread().getName()) || (heightAndDepthMap.get(Thread.currentThread().getName()) == null) || (heightAndDepthMap.get(Thread.currentThread().getName()).length != size)) + public static short[] getHeightAndDepth(){ + if(!heightAndDepthMap.containsKey(Thread.currentThread().getName()) || (heightAndDepthMap.get(Thread.currentThread().getName()) == null)) { - heightAndDepthMap.put(Thread.currentThread().getName(), new short[size]); + heightAndDepthMap.put(Thread.currentThread().getName(), new short[0]); } return heightAndDepthMap.get(Thread.currentThread().getName()); } - public static byte[] getSaveContainer(int size){ - if(!saveContainer.containsKey(Thread.currentThread().getName()) || (saveContainer.get(Thread.currentThread().getName()) == null) || (saveContainer.get(Thread.currentThread().getName()).length != size)) + public static byte[] getSaveContainer(){ + if(!saveContainer.containsKey(Thread.currentThread().getName()) || (saveContainer.get(Thread.currentThread().getName()) == null)) { - saveContainer.put(Thread.currentThread().getName(), new byte[size]); + saveContainer.put(Thread.currentThread().getName(), new byte[0]); } return saveContainer.get(Thread.currentThread().getName()); } - public static long[] getVerticalUpdateArray(byte detailLevel){ - if(!verticalUpdate.containsKey(Thread.currentThread().getName()) || (verticalUpdate.get(Thread.currentThread().getName()) == null) || (verticalUpdate.get(Thread.currentThread().getName())[detailLevel].length != 4*DetailDistanceUtil.getMaxVerticalData(detailLevel))) + public static long[][] getVerticalUpdateArray(){ + if(!verticalUpdate.containsKey(Thread.currentThread().getName()) || (verticalUpdate.get(Thread.currentThread().getName()) == null)) { long[][] array = new long[10][]; - for(int i = 0; i < array.length; i++) - { - array[i] = new long[4 * DetailDistanceUtil.getMaxVerticalData(detailLevel)]; - } verticalUpdate.put(Thread.currentThread().getName(), array); } - return verticalUpdate.get(Thread.currentThread().getName())[detailLevel]; + return verticalUpdate.get(Thread.currentThread().getName()); } - public static long[] getSingleAddDataToMerge(int size){ - if(!singleDataToMergeMap.containsKey(Thread.currentThread().getName()) || (singleDataToMergeMap.get(Thread.currentThread().getName()) == null) || (singleDataToMergeMap.get(Thread.currentThread().getName()).length != size)) + public static long[] getSingleAddDataToMerge(){ + if(!singleDataToMergeMap.containsKey(Thread.currentThread().getName()) || (singleDataToMergeMap.get(Thread.currentThread().getName()) == null)) { - singleDataToMergeMap.put(Thread.currentThread().getName(), new long[size]); + singleDataToMergeMap.put(Thread.currentThread().getName(), new long[0]); } return singleDataToMergeMap.get(Thread.currentThread().getName()); } + + public static void clearMaps(){ + threadSingleUpdateMap.clear(); + threadBuilderArrayMap.clear(); + threadBuilderVerticalArrayMap.clear(); + threadVerticalAddDataMap.clear(); + saveContainer.clear(); + projectionShortMap.clear(); + heightAndDepthMap.clear(); + singleDataToMergeMap.clear(); + verticalUpdate.clear(); + } }