Fix issues with generation filling up RAM
This commit is contained in:
@@ -79,7 +79,7 @@ public class LodBuilder
|
||||
* How wide LodDimensions should be in regions <br>
|
||||
* 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.
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user