From 783c0c97a11954638ff32be204cfbc79a64c451f Mon Sep 17 00:00:00 2001 From: Leonardo Date: Fri, 27 Aug 2021 11:28:29 +0200 Subject: [PATCH] Preparing the BufferBuilder for new system --- .../seibel/lod/builders/LodBufferBuilder.java | 100 +++++++++++++----- .../seibel/lod/objects/LevelPos/LevelPos.java | 88 ++++++++++++--- .../com/seibel/lod/objects/LodDimension.java | 30 ++---- .../com/seibel/lod/objects/LodRegion.java | 100 +++++++++--------- .../seibel/lod/util/DetailDistanceUtil.java | 2 +- 5 files changed, 210 insertions(+), 110 deletions(-) diff --git a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java index a3c701f1b..b0999c4d3 100644 --- a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java @@ -21,10 +21,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; +import java.util.concurrent.*; import java.util.concurrent.locks.ReentrantLock; import com.seibel.lod.objects.DataPoint; @@ -156,6 +153,7 @@ public class LodBufferBuilder long startTime = System.currentTimeMillis(); + ArrayList> nodeToRenderThreads = new ArrayList<>(lodDim.regions.length * lodDim.regions.length); ArrayList> builderThreads = new ArrayList<>(lodDim.regions.length * lodDim.regions.length); startBuffers(); @@ -163,6 +161,68 @@ public class LodBufferBuilder // =====================// // RENDERING PART // // =====================// + Object[][] nodeToRenderMatrix = new Object[lodDim.regions.length][lodDim.regions.length]; + + for (int xRegion = 0; xRegion < lodDim.regions.length; xRegion++) + { + for (int zRegion = 0; zRegion < lodDim.regions.length; zRegion++) + { + nodeToRenderMatrix[xRegion][zRegion] = new ConcurrentSkipListMap<>(LevelPos.getComparator()); + RegionPos regionPos = new RegionPos(xRegion + lodDim.getCenterX() - lodDim.getWidth() / 2, zRegion + lodDim.getCenterZ() - lodDim.getWidth() / 2); + + // local position in the vbo and bufferBuilder arrays + BufferBuilder currentBuffer = buildableBuffers[xRegion][zRegion]; + + // make sure the buffers weren't + // changed while we were running this method + if (currentBuffer == null || (currentBuffer != null && !currentBuffer.building())) + return; + + byte detailLevel = LodConfig.CLIENT.maxGenerationDetail.get().detailLevel; + final int xR = xRegion; + final int zR = zRegion; + Callable dataToRenderThread = () -> + { + byte detailToRender; + boolean zFix; + + for (byte detail = detailLevel; detail <= LodUtil.REGION_DETAIL_LEVEL; detail++) + { + detailToRender = detail; + lodDim.getDataToRender( + (ConcurrentSkipListMap>) nodeToRenderMatrix[xR][zR], + regionPos, + playerBlockPosRounded.getX(), + playerBlockPosRounded.getZ(), + DetailDistanceUtil.getDistanceRendering(detail), + DetailDistanceUtil.getDistanceRendering(detail + 1), + detailToRender, + true); + } + // the thread executed successfully + return true; + };// buffer builder worker thread + + + nodeToRenderThreads.add(dataToRenderThread); + + }// region z + }// region z + + long renderStart = System.currentTimeMillis(); + // wait for all threads to finish + List> futures = bufferBuilderThreads.invokeAll(nodeToRenderThreads); + for (Future future : futures) + { + // the future will be false if its thread failed + if (!future.get()) + { + ClientProxy.LOGGER.warn("LodBufferBuilder ran into trouble and had to start over."); + closeBuffers(); + return; + } + } + long renderEnd = System.currentTimeMillis(); for (int xRegion = 0; xRegion < lodDim.regions.length; xRegion++) { @@ -181,28 +241,12 @@ public class LodBufferBuilder byte detailLevel = LodConfig.CLIENT.maxGenerationDetail.get().detailLevel; + final int xR = xRegion; + final int zR = zRegion; Callable bufferBuildingThread = () -> { - byte detailToRender; - boolean zFix; LevelPos adjPos = new LevelPos(); - Set setOfPosToRender = new HashSet<>(); - - for (byte detail = detailLevel; detail <= LodUtil.REGION_DETAIL_LEVEL; detail++) - { - detailToRender = detail; - setOfPosToRender.addAll(lodDim.getDataToRender( - regionPos, - playerBlockPosRounded.getX(), - playerBlockPosRounded.getZ(), - DetailDistanceUtil.getDistanceRendering(detail), - DetailDistanceUtil.getDistanceRendering(detail + 1), - detailToRender, - true)); - } - - - for (LevelPos posToRender : setOfPosToRender) + for (LevelPos posToRender : ((ConcurrentSkipListMap>) nodeToRenderMatrix[xR][zR]).keySet()) { LevelPos chunkPos = posToRender.getConvertedLevelPos(LodUtil.CHUNK_DETAIL_LEVEL); // skip any chunks that Minecraft is going to render @@ -252,10 +296,10 @@ public class LodBufferBuilder }// region z }// region z - long renderStart = System.currentTimeMillis(); + long renderBufferStart = System.currentTimeMillis(); // wait for all threads to finish - List> futures = bufferBuilderThreads.invokeAll(builderThreads); - for (Future future : futures) + List> futuresBuffer = bufferBuilderThreads.invokeAll(builderThreads); + for (Future future : futuresBuffer) { // the future will be false if its thread failed if (!future.get()) @@ -265,7 +309,7 @@ public class LodBufferBuilder return; } } - long renderEnd = System.currentTimeMillis(); + long renderBufferEnd = System.currentTimeMillis(); // finish the buffer building @@ -436,4 +480,4 @@ public class LodBufferBuilder } -} \ No newline at end of file +} diff --git a/src/main/java/com/seibel/lod/objects/LevelPos/LevelPos.java b/src/main/java/com/seibel/lod/objects/LevelPos/LevelPos.java index 0f47c1f2d..e7fff0ab9 100644 --- a/src/main/java/com/seibel/lod/objects/LevelPos/LevelPos.java +++ b/src/main/java/com/seibel/lod/objects/LevelPos/LevelPos.java @@ -3,12 +3,10 @@ package com.seibel.lod.objects.LevelPos; import com.seibel.lod.objects.RegionPos; import com.seibel.lod.util.LodUtil; import net.minecraft.util.math.ChunkPos; -import net.minecraft.world.chunk.Chunk; import java.util.Comparator; -import java.util.Map; -public class LevelPos implements Cloneable, ImmutableLevelPos, MutableLevelPos +public class LevelPos implements Cloneable, ImmutableLevelPos, MutableLevelPos, Comparable { public byte detailLevel; public int posX; @@ -117,6 +115,18 @@ public class LevelPos implements Cloneable, ImmutableLevelPos, MutableLevelPos Math.floorDiv(posZ, width)); } + public int getRegionPosX() + { + int width = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel); + return Math.floorDiv(posX, width); + } + + public int getRegionPosZ() + { + int width = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel); + return Math.floorDiv(posZ, width); + } + public ChunkPos getChunkPos() { if (LodUtil.CHUNK_DETAIL_LEVEL >= detailLevel) @@ -244,21 +254,23 @@ public class LevelPos implements Cloneable, ImmutableLevelPos, MutableLevelPos } } - public static LevelPosComparator getPosComparator(int playerPosX, int playerPosZ) + public static LevelPosDistanceComparator getPosComparator(int playerPosX, int playerPosZ) { - return new LevelPosComparator(playerPosX,playerPosZ); + return new LevelPosDistanceComparator(playerPosX, playerPosZ); } public static LevelPosDetailComparator getPosAndDetailComparator(int playerPosX, int playerPosZ) { - return new LevelPosDetailComparator(playerPosX,playerPosZ); + return new LevelPosDetailComparator(playerPosX, playerPosZ); } - public static class LevelPosComparator implements Comparator + public static class LevelPosDistanceComparator implements Comparator { int playerPosX; int playerPosZ; - public LevelPosComparator(int playerPosX, int playerPosZ){ + + public LevelPosDistanceComparator(int playerPosX, int playerPosZ) + { this.playerPosX = playerPosX; this.playerPosZ = playerPosZ; } @@ -267,8 +279,8 @@ public class LevelPos implements Cloneable, ImmutableLevelPos, MutableLevelPos public int compare(LevelPos first, LevelPos second) { return Integer.compare( - first.minDistance(playerPosX,playerPosZ), - second.minDistance(playerPosX,playerPosZ)); + first.minDistance(playerPosX, playerPosZ), + second.minDistance(playerPosX, playerPosZ)); } } @@ -276,7 +288,9 @@ public class LevelPos implements Cloneable, ImmutableLevelPos, MutableLevelPos { int playerPosX; int playerPosZ; - public LevelPosDetailComparator(int playerPosX, int playerPosZ){ + + public LevelPosDetailComparator(int playerPosX, int playerPosZ) + { this.playerPosX = playerPosX; this.playerPosZ = playerPosZ; } @@ -285,16 +299,62 @@ public class LevelPos implements Cloneable, ImmutableLevelPos, MutableLevelPos public int compare(LevelPos first, LevelPos second) { int compareResult = Integer.compare(first.detailLevel, second.detailLevel); - if (compareResult != 0) + if (compareResult == 0) { compareResult = Integer.compare( - first.minDistance(playerPosX,playerPosZ), - second.minDistance(playerPosX,playerPosZ)); + first.minDistance(playerPosX, playerPosZ), + second.minDistance(playerPosX, playerPosZ)); } return compareResult; } } + public static LevelPosComparator getComparator() + { + return new LevelPosComparator(); + } + + public static class LevelPosComparator implements Comparator + { + @Override + public int compare(LevelPos first, LevelPos second) + { + int compareResult = Integer.compare(first.detailLevel, second.detailLevel); + if (compareResult == 0) + { + compareResult = Integer.compare( + first.posX, + second.posX); + } + if (compareResult == 0) + { + compareResult = Integer.compare( + first.posZ, + second.posZ); + } + return compareResult; + } + } + + @Override + public int compareTo(LevelPos other) + { + int compareResult = Integer.compare(this.detailLevel, other.detailLevel); + if (compareResult == 0) + { + compareResult = Integer.compare( + this.posX, + other.posX); + } + if (compareResult == 0) + { + compareResult = Integer.compare( + this.posZ, + other.posZ); + } + return compareResult; + } + @Override public LevelPos clone() diff --git a/src/main/java/com/seibel/lod/objects/LodDimension.java b/src/main/java/com/seibel/lod/objects/LodDimension.java index 4e006cca8..cda6409db 100644 --- a/src/main/java/com/seibel/lod/objects/LodDimension.java +++ b/src/main/java/com/seibel/lod/objects/LodDimension.java @@ -20,10 +20,8 @@ package com.seibel.lod.objects; import java.io.File; import java.io.IOException; import java.security.InvalidParameterException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.concurrent.ConcurrentNavigableMap; import java.util.stream.Collectors; import com.seibel.lod.enums.DistanceGenerationMode; @@ -311,7 +309,7 @@ public class LodDimension { int regionX; int regionZ; - LevelPos levelPos; + LevelPos levelPos = new LevelPos(); for (int x = 0; x < regions.length; x++) { @@ -319,7 +317,7 @@ public class LodDimension { regionX = (x + center.x) - halfWidth; regionZ = (z + center.z) - halfWidth; - levelPos = new LevelPos(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ); + levelPos.changeParameters(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ); //we start checking from the first circle. If the whole region is in the circle //we proceed to cut all the level lower than the level of circle 1 and we break //if this is not the case w @@ -348,7 +346,7 @@ public class LodDimension { int regionX; int regionZ; - LevelPos levelPos; + LevelPos levelPos = new LevelPos(); RegionPos regionPos; LodRegion region; byte targetDetailLevel; @@ -358,7 +356,7 @@ public class LodDimension { regionX = (x + center.x) - halfWidth; regionZ = (z + center.z) - halfWidth; - levelPos = new LevelPos(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ); + levelPos.changeParameters(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ); regionPos = new RegionPos(regionX, regionZ); for(byte index = LodUtil.BLOCK_DETAIL_LEVEL; index <= LodUtil.REGION_DETAIL_LEVEL; index++){ @@ -445,7 +443,7 @@ public class LodDimension int zIndex; LodRegion region; RegionPos regionPos; - LevelPos regionLevelPos; + LevelPos regionLevelPos = new LevelPos(); List listOfData = new ArrayList<>(); for (int xRegion = 0; xRegion < n; xRegion++) { @@ -456,7 +454,7 @@ public class LodDimension xIndex = (xRegion + center.x) - halfWidth; zIndex = (zRegion + center.z) - halfWidth; regionPos = new RegionPos(xIndex, zIndex); - regionLevelPos = new LevelPos(LodUtil.REGION_DETAIL_LEVEL, regionPos.x, regionPos.z); + regionLevelPos.changeParameters(LodUtil.REGION_DETAIL_LEVEL, regionPos.x, regionPos.z); if (end >= regionLevelPos.minDistance(playerPosX, playerPosZ) && start <= regionLevelPos.maxDistance(playerPosX, playerPosZ)) { @@ -481,15 +479,13 @@ public class LodDimension return levelMinPosList; } - /** * method to get all the nodes that have to be rendered based on the position of the player * * @return list of nodes */ - public List getDataToRender(RegionPos regionPos, int playerPosX, int playerPosZ, int start, int end, byte detailLevel, boolean zFix) + public void getDataToRender(ConcurrentNavigableMap> dataToRender, RegionPos regionPos, int playerPosX, int playerPosZ, int start, int end, byte detailLevel, boolean zFix) { - List listOfData = new ArrayList<>(); LevelPos regionLevelPos = new LevelPos(LodUtil.REGION_DETAIL_LEVEL, regionPos.x, regionPos.z); try { @@ -497,14 +493,10 @@ public class LodDimension start <= regionLevelPos.maxDistance(playerPosX, playerPosZ)) { LodRegion region = getRegion(new LevelPos(LodUtil.REGION_DETAIL_LEVEL, regionPos.x, regionPos.z).getConvertedLevelPos(detailLevel)); - listOfData.addAll(region.getDataToRender(playerPosX, playerPosZ, start, end, detailLevel,zFix)); + region.getDataToRender(dataToRender,playerPosX, playerPosZ, start, end, detailLevel,zFix); } }catch (Exception e){ - //e.printStackTrace(); - }finally - { - - return listOfData; + e.printStackTrace(); } } diff --git a/src/main/java/com/seibel/lod/objects/LodRegion.java b/src/main/java/com/seibel/lod/objects/LodRegion.java index dc0009991..93f2c5d7f 100644 --- a/src/main/java/com/seibel/lod/objects/LodRegion.java +++ b/src/main/java/com/seibel/lod/objects/LodRegion.java @@ -1,9 +1,8 @@ package com.seibel.lod.objects; import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; +import java.util.concurrent.ConcurrentNavigableMap; import com.seibel.lod.builders.LodBuilder; import com.seibel.lod.enums.DistanceGenerationMode; @@ -298,76 +297,81 @@ public class LodRegion implements Serializable /** * @return */ - public List getDataToRender(int playerPosX, int playerPosZ, int start, int end, byte detailLevel, boolean zFix) + public void getDataToRender(ConcurrentNavigableMap> dataToRender, int playerPosX, int playerPosZ, int start, int end, byte detailLevel, boolean zFix) { LevelPos levelPos = new LevelPos(LodUtil.REGION_DETAIL_LEVEL, 0, 0); - return getDataToRender(levelPos, playerPosX, playerPosZ, start, end, detailLevel, zFix); + getDataToRender(dataToRender, levelPos, playerPosX, playerPosZ, start, end, detailLevel, zFix); } /** * @return */ - private List getDataToRender(LevelPos levelPos, int playerPosX, int playerPosZ, int start, int end, byte detailLevel, boolean zFix) + private void getDataToRender(ConcurrentNavigableMap> dataToRender, LevelPos levelPos, int playerPosX, int playerPosZ, int start, int end, byte detailLevel, boolean zFix) { - List levelPosList = new ArrayList<>(); - int size = (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - levelPos.detailLevel); - int width = (int) Math.pow(2, levelPos.detailLevel); - - //here i calculate the the LevelPos is in range - //This is important to avoid any kind of hole in the rendering - int maxDistance = levelPos.maxDistance(playerPosX, playerPosZ, regionPosX, regionPosZ); - int minDistance = levelPos.minDistance(playerPosX, playerPosZ, regionPosX, regionPosZ); - - //To avoid z fighting: if the pos is touching the end radius at detailLevel + 1 then we stop - //cause this area will be occupied by bigger block - if (levelPos.detailLevel == detailLevel + 1 && end <= maxDistance && minDistance <= end && zFix) + try { - return levelPosList; - } + int size = (int) Math.pow(2, LodUtil.REGION_DETAIL_LEVEL - levelPos.detailLevel); + int width = (int) Math.pow(2, levelPos.detailLevel); - if (!(start <= maxDistance && minDistance < end) || levelPos.detailLevel < detailLevel) - { - return levelPosList; - } + //here i calculate the the LevelPos is in range + //This is important to avoid any kind of hole in the rendering + int maxDistance = levelPos.maxDistance(playerPosX, playerPosZ, regionPosX, regionPosZ); + int minDistance = levelPos.minDistance(playerPosX, playerPosZ, regionPosX, regionPosZ); - //we have reached the target detail level - if (detailLevel == levelPos.detailLevel) - { - levelPosList.add(new LevelPos(levelPos.detailLevel, levelPos.posX + regionPosX * size, levelPos.posZ + regionPosZ * size)); - } else - { - int childPosX = levelPos.posX * 2; - int childPosZ = levelPos.posZ * 2; - LevelPos childPos; - int childrenCount = 0; - for (int x = 0; x <= 1; x++) + //To avoid z fighting: if the pos is touching the end radius at detailLevel + 1 then we stop + //cause this area will be occupied by bigger block + if (levelPos.detailLevel == detailLevel + 1 && end <= maxDistance && minDistance <= end && zFix) { - for (int z = 0; z <= 1; z++) - { - childPos = new LevelPos((byte) (levelPos.detailLevel - 1), childPosX + x, childPosZ + z); - if (doesDataExist(childPos)) childrenCount++; - } + return; } - //If all the four children exist we go deeper - if (childrenCount == 4) + if (!(start <= maxDistance && minDistance < end) || levelPos.detailLevel < detailLevel) { - levelPosList.clear(); + return; + } + + //we have reached the target detail level + if (detailLevel == levelPos.detailLevel) + { + dataToRender.put(new LevelPos(levelPos.detailLevel, levelPos.posX + regionPosX * size, levelPos.posZ + regionPosZ * size), new ArrayList<>()); + } else + { + int childPosX = levelPos.posX * 2; + int childPosZ = levelPos.posZ * 2; + LevelPos childPos; + int childrenCount = 0; for (int x = 0; x <= 1; x++) { for (int z = 0; z <= 1; z++) { childPos = new LevelPos((byte) (levelPos.detailLevel - 1), childPosX + x, childPosZ + z); - levelPosList.addAll(getDataToRender(childPos, playerPosX, playerPosZ, start, end, detailLevel, zFix)); + if (doesDataExist(childPos)) childrenCount++; } } - } else - { - levelPosList.add(new LevelPos(levelPos.detailLevel, levelPos.posX + regionPosX * size, levelPos.posZ + regionPosZ * size)); + + //If all the four children exist we go deeper + if (childrenCount == 4) + { + for (int x = 0; x <= 1; x++) + { + for (int z = 0; z <= 1; z++) + { + childPos = new LevelPos((byte) (levelPos.detailLevel - 1), childPosX + x, childPosZ + z); + getDataToRender(dataToRender, childPos, playerPosX, playerPosZ, start, end, detailLevel, zFix); + } + } + } else + { + dataToRender.put(new LevelPos(levelPos.detailLevel, levelPos.posX + regionPosX * size, levelPos.posZ + regionPosZ * size), new ArrayList<>()); + } } + return; + }catch(ClassCastException e){ + System.out.println(dataToRender); + e.printStackTrace(); + throw e; } - return levelPosList; } /** diff --git a/src/main/java/com/seibel/lod/util/DetailDistanceUtil.java b/src/main/java/com/seibel/lod/util/DetailDistanceUtil.java index 0754b82ac..5e08f43a0 100644 --- a/src/main/java/com/seibel/lod/util/DetailDistanceUtil.java +++ b/src/main/java/com/seibel/lod/util/DetailDistanceUtil.java @@ -16,7 +16,7 @@ public class DetailDistanceUtil private static int maxDistance = LodConfig.CLIENT.lodChunkRenderDistance.get() * 16; - private static DistanceGenerationMode[] distancesGenerators = { + private static DistanceGenerationMode[] distancesGenerators = { DistanceGenerationMode.SURFACE, DistanceGenerationMode.SURFACE, DistanceGenerationMode.SURFACE,