diff --git a/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java b/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java index 753edc8b9..edc8b8a8e 100644 --- a/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java +++ b/src/main/java/com/seibel/lod/core/builders/lodBuilding/LodBuilder.java @@ -79,7 +79,7 @@ public class LodBuilder * How wide LodDimensions should be in regions
* Is automatically set before the first frame in ClientProxy. */ - public int defaultDimensionWidthInRegions = 0; + public int defaultDimensionWidthInRegions = 1; //public static final boolean useExperimentalLighting = true; @@ -150,52 +150,6 @@ public class LodBuilder }); lodGenThreadPool.execute(thread); } - - public void generateLodNodeDirect(IChunkWrapper chunk, LodWorld lodWorld, IDimensionTypeWrapper dim, DistanceGenerationMode generationMode, boolean override) - { - if (lodWorld == null || lodWorld.getIsWorldNotLoaded()) - return; - - // don't try to create an LOD object - // if for some reason we aren't - // given a valid chunk object - if (chunk == null) - return; - - //noinspection GrazieInspection - try - { - // we need a loaded client world in order to - // get the textures for blocks - if (MC.getWrappedClientWorld() == null) - return; - - // don't try to generate LODs if the user isn't in the world anymore - // (this happens a lot when the user leaves a world/server) - if (!MC.hasSinglePlayerServer() && !MC.connectedToServer()) - return; - - // make sure the dimension exists - LodDimension lodDim; - if (lodWorld.getLodDimension(dim) == null) - { - lodDim = new LodDimension(dim, lodWorld, defaultDimensionWidthInRegions); - lodWorld.addLodDimension(lodDim); - } - else - { - lodDim = lodWorld.getLodDimension(dim); - } - generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig(generationMode), override); - } - catch (IllegalArgumentException | NullPointerException e) - { - e.printStackTrace(); - // if the world changes while LODs are being generated - // they will throw errors as they try to access things that no longer - // exist. - } - } /** * Creates a LodNode for a chunk in the given world. diff --git a/src/main/java/com/seibel/lod/core/objects/PosToGenerateContainer.java b/src/main/java/com/seibel/lod/core/objects/PosToGenerateContainer.java index ad098aafc..e5ff4a1a8 100644 --- a/src/main/java/com/seibel/lod/core/objects/PosToGenerateContainer.java +++ b/src/main/java/com/seibel/lod/core/objects/PosToGenerateContainer.java @@ -56,7 +56,7 @@ public class PosToGenerateContainer // TODO what is going on in this method? - public void addPosToGenerate(byte detailLevel, int posX, int posZ) + public void addPosToGenerate(byte detailLevel, int posX, int posZ, boolean sort) { int distance = LevelPosUtil.minDistance(detailLevel, posX, posZ, playerPosX, playerPosZ); int index; @@ -67,25 +67,22 @@ public class PosToGenerateContainer if (farSize < farPosToGenerate.length) farSize++; - + index = farSize - 1; - while (index > 0 && LevelPosUtil.compareDistance(distance, farPosToGenerate[index - 1][3]) <= 0) - { - farPosToGenerate[index][0] = farPosToGenerate[index - 1][0]; - farPosToGenerate[index][1] = farPosToGenerate[index - 1][1]; - farPosToGenerate[index][2] = farPosToGenerate[index - 1][2]; - farPosToGenerate[index][3] = farPosToGenerate[index - 1][3]; - index--; - } - - - if (index != farSize - 1 || farSize != farPosToGenerate.length) - { - farPosToGenerate[index][0] = detailLevel + 1; - farPosToGenerate[index][1] = posX; - farPosToGenerate[index][2] = posZ; - farPosToGenerate[index][3] = distance; + if (sort) { + while (index > 0 && LevelPosUtil.compareDistance(distance, farPosToGenerate[index - 1][3]) <= 0) + { + farPosToGenerate[index][0] = farPosToGenerate[index - 1][0]; + farPosToGenerate[index][1] = farPosToGenerate[index - 1][1]; + farPosToGenerate[index][2] = farPosToGenerate[index - 1][2]; + farPosToGenerate[index][3] = farPosToGenerate[index - 1][3]; + index--; + } } + farPosToGenerate[index][0] = detailLevel + 1; + farPosToGenerate[index][1] = posX; + farPosToGenerate[index][2] = posZ; + farPosToGenerate[index][3] = distance; } else { @@ -95,26 +92,27 @@ public class PosToGenerateContainer nearSize++; index = nearSize - 1; - while (index > 0 && LevelPosUtil.compareDistance(distance, nearPosToGenerate[index - 1][3]) <= 0) - { - nearPosToGenerate[index][0] = nearPosToGenerate[index - 1][0]; - nearPosToGenerate[index][1] = nearPosToGenerate[index - 1][1]; - nearPosToGenerate[index][2] = nearPosToGenerate[index - 1][2]; - nearPosToGenerate[index][3] = nearPosToGenerate[index - 1][3]; - index--; - } - - - if (index != nearSize - 1 || nearSize != nearPosToGenerate.length) - { - nearPosToGenerate[index][0] = detailLevel + 1; - nearPosToGenerate[index][1] = posX; - nearPosToGenerate[index][2] = posZ; - nearPosToGenerate[index][3] = distance; + if (sort) { + while (index > 0 && LevelPosUtil.compareDistance(distance, nearPosToGenerate[index - 1][3]) <= 0) + { + nearPosToGenerate[index][0] = nearPosToGenerate[index - 1][0]; + nearPosToGenerate[index][1] = nearPosToGenerate[index - 1][1]; + nearPosToGenerate[index][2] = nearPosToGenerate[index - 1][2]; + nearPosToGenerate[index][3] = nearPosToGenerate[index - 1][3]; + index--; + } } + nearPosToGenerate[index][0] = detailLevel + 1; + nearPosToGenerate[index][1] = posX; + nearPosToGenerate[index][2] = posZ; + nearPosToGenerate[index][3] = distance; } } + public boolean isFull() { + return nearSize == nearPosToGenerate.length && farSize == farPosToGenerate.length; + } + public int getNumberOfPos() diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java b/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java index 404cc4bf0..9d8d7475c 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/LodDimension.java @@ -21,6 +21,8 @@ package com.seibel.lod.core.objects.lod; import java.io.File; import java.io.IOException; +import java.util.Arrays; +import java.util.Comparator; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -75,6 +77,8 @@ public class LodDimension // which is a safer way to get the width then directly asking the arrays /** stores all the regions in this dimension */ public volatile LodRegion[][] regions; + //NOTE: This list pos is relative to center + private volatile RegionPos[] iteratorList = null; /** stores if the region at the given x and z index needs to be saved to disk */ /** stores if the region at the given x and z index needs to be regenerated */ @@ -95,6 +99,7 @@ public class LodDimension private final ExecutorService cutAndExpandThread = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName() + " - Cut and Expand")); + /** * Creates the dimension centered at (0,0) * @param newWidth in regions @@ -139,6 +144,28 @@ public class LodDimension regions = new LodRegion[width][width]; center = new RegionPos(0, 0); + generateIteratorList(); + } + + private void generateIteratorList() { + iteratorList = null; + RegionPos[] list = new RegionPos[width*width]; + + int i = 0; + for (int ix=-halfWidth; ix<=halfWidth; ix++) { + for (int iz=-halfWidth; iz<=halfWidth; iz++) { + list[i] = new RegionPos(ix, iz); + i++; + } + } + Arrays.sort(list, (a, b) -> { + RegionPos posA = (RegionPos)a; + RegionPos posB = (RegionPos)b; + double disSqrA = posA.x*posA.x+posA.z*posA.z; + double disSqrB = posB.x*posB.x+posB.z*posB.z; + return Double.compare(disSqrA, disSqrB); + }); + iteratorList = list; } @@ -333,12 +360,21 @@ public class LodDimension oy += dy; } } + public void iterateByDistance(PosComsumer r) { + if (iteratorList==null) return; + for (RegionPos relativePos : iteratorList) { + r.run(relativePos.x+halfWidth, relativePos.z+halfWidth); + } + + } /** * Deletes nodes that are a higher detail then necessary, freeing * up memory. */ + private int totalDirtiedRegions = 0; + public void cutRegionNodesAsync(int playerPosX, int playerPosZ) { if (isCutting) return; @@ -347,7 +383,7 @@ public class LodDimension // for the same location Runnable thread = () -> { //ClientApi.LOGGER.info("LodDim cut Region: " + playerPosX + "," + playerPosZ); - + totalDirtiedRegions = 0; // go over every region in the dimension iterateWithSpiral((int x, int z) -> { int regionX; @@ -357,6 +393,7 @@ public class LodDimension regionX = (x + center.x) - halfWidth; regionZ = (z + center.z) - halfWidth; LodRegion region = regions[x][z]; + if (region != null && region.needSaving) totalDirtiedRegions++; if (region != null && !region.needSaving && region.isWriting==0) { // check what detail level this region should be // and cut it if it is higher then that @@ -371,8 +408,12 @@ public class LodDimension } } }); + if (totalDirtiedRegions > 8) this.saveDirtyRegionsToFile(false); + //ClientApi.LOGGER.info("LodDim cut Region complete: " + playerPosX + "," + playerPosZ); isCutting = false; + + // See if we need to save and flush some data out. }; cutAndExpandThread.execute(thread); } @@ -485,11 +526,12 @@ public class LodDimension { PosToGenerateContainer posToGenerate; posToGenerate = new PosToGenerateContainer((byte) 8, maxDataToGenerate, playerBlockPosX, playerBlockPosZ); - iterateWithSpiral((int x, int z) -> { + iterateByDistance((int x, int z) -> { + if (posToGenerate.isFull()) return; //All of this is handled directly by the region, which scan every pos from top to bottom of the quad tree LodRegion lodRegion = regions[x][z]; if (lodRegion != null) - lodRegion.getPosToGenerate(posToGenerate, playerBlockPosX, playerBlockPosZ, priority); + lodRegion.getPosToGenerate(posToGenerate, playerBlockPosX, playerBlockPosZ, priority, (Math.abs(x)+Math.abs(z)<2)); }); return posToGenerate; } @@ -698,6 +740,7 @@ public class LodDimension halfWidth = width/ 2; regions = new LodRegion[width][width]; + generateIteratorList(); } diff --git a/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java b/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java index fd17822de..90ecbe205 100644 --- a/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java +++ b/src/main/java/com/seibel/lod/core/objects/lod/LodRegion.java @@ -166,8 +166,8 @@ public class LodRegion { * understand */ public void getPosToGenerate(PosToGenerateContainer posToGenerate, int playerBlockPosX, int playerBlockPosZ, - GenerationPriority priority) { - getPosToGenerate(posToGenerate, LodUtil.REGION_DETAIL_LEVEL, 0, 0, playerBlockPosX, playerBlockPosZ, priority); + GenerationPriority priority, boolean shouldSort) { + getPosToGenerate(posToGenerate, LodUtil.REGION_DETAIL_LEVEL, 0, 0, playerBlockPosX, playerBlockPosZ, priority, shouldSort); } @@ -179,7 +179,7 @@ public class LodRegion { * understand */ private void getPosToGenerate(PosToGenerateContainer posToGenerate, byte detailLevel, int childOffsetPosX, - int childOffsetPosZ, int playerPosX, int playerPosZ, GenerationPriority priority) { + int childOffsetPosZ, int playerPosX, int playerPosZ, GenerationPriority priority, boolean shouldSort) { // equivalent to 2^(...) int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel); @@ -198,24 +198,24 @@ public class LodRegion { if (targetDetailLevel == detailLevel) { if (!doesDataExist(detailLevel, childOffsetPosX, childOffsetPosZ)) posToGenerate.addPosToGenerate(detailLevel, childOffsetPosX + regionPosX * size, - childOffsetPosZ + regionPosZ * size); + childOffsetPosZ + regionPosZ * size, shouldSort); } else { if (priority == GenerationPriority.FAR_FIRST && detailLevel >= posToGenerate.farMinDetail && !doesDataExist(detailLevel, childOffsetPosX, childOffsetPosZ)) { posToGenerate.addPosToGenerate(detailLevel, childOffsetPosX + regionPosX * size, - childOffsetPosZ + regionPosZ * size); + childOffsetPosZ + regionPosZ * size, shouldSort); } else if (detailLevel > LodUtil.CHUNK_DETAIL_LEVEL) { for (int x = 0; x <= 1; x++) for (int z = 0; z <= 1; z++) getPosToGenerate(posToGenerate, childDetailLevel, childPosX + x, childPosZ + z, playerPosX, - playerPosZ, priority); + playerPosZ, priority, shouldSort); } else { // we want at max one request per chunk (since the world generator creates // chunks). // So for lod smaller than a chunk, only recurse down // the top right child getPosToGenerate(posToGenerate, childDetailLevel, childPosX, childPosZ, playerPosX, playerPosZ, - priority); + priority, shouldSort); } } }