Refactor LodDimension and change some error reporting in PosToRenderContainer

This commit is contained in:
James Seibel
2021-09-18 16:58:23 -05:00
parent ff5139d403
commit aa95361866
5 changed files with 184 additions and 128 deletions
@@ -26,7 +26,11 @@ import com.seibel.lod.config.LodConfig;
import com.seibel.lod.enums.DistanceGenerationMode;
import com.seibel.lod.enums.LodQualityMode;
import com.seibel.lod.handlers.LodDimensionFileHandler;
import com.seibel.lod.util.*;
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.wrappers.MinecraftWrapper;
import net.minecraft.util.math.ChunkPos;
@@ -41,13 +45,13 @@ import net.minecraft.world.server.ServerWorld;
*
* @author Leonardo Amato
* @author James Seibel
* @version 8-8-2021
* @version 9-18-2021
*/
public class LodDimension
{
public final DimensionType dimension;
/**
* measured in regions
*/
@@ -56,23 +60,28 @@ public class LodDimension
* measured in regions
*/
private volatile int halfWidth;
public volatile LodRegion regions[][];
public volatile boolean isRegionDirty[][];
public volatile boolean regen[][];
// these three variables are private to force use of the getWidth() method
// which is a safer way to get the width then directly asking the arrays
/** stores all the regions in this dimension */
private volatile LodRegion regions[][];
/** stores if the region at the given x and z index needs to be saved to disk */
private volatile boolean isRegionDirty[][];
/** stores if the region at the given x and z index needs to be regenerated */
private volatile boolean regionNeedsRegen[][];
/**
* if true that means there are regions in this dimension
* that need to have their buffers rebuilt.
*/
public volatile boolean regenDimension = false;
private volatile RegionPos center;
private volatile ChunkPos lastGenChunk;
private volatile ChunkPos lastCutChunk;
private LodDimensionFileHandler fileHandler;
private ExecutorService cutAndGenThreads = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName() + " - cutAndGen"));
/**
* Creates the dimension centered at (0,0)
*
@@ -90,14 +99,14 @@ public class LodDimension
{
try
{
File saveDir;
if (mc.hasSingleplayerServer())
{
// local world
ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(newDimension);
// provider needs a separate variable to prevent
// the compiler from complaining
ServerChunkProvider provider = serverWorld.getChunkSource();
@@ -105,11 +114,11 @@ public class LodDimension
} else
{
// connected to server
saveDir = new File(mc.getGameDirectory().getCanonicalFile().getPath() +
File.separatorChar + "lod server data" + File.separatorChar + mc.getCurrentDimensionId());
File.separatorChar + "lod server data" + File.separatorChar + mc.getCurrentDimensionId());
}
fileHandler = new LodDimensionFileHandler(saveDir, this);
} catch (IOException e)
{
@@ -117,23 +126,23 @@ public class LodDimension
// we won't be able to read or write any files
}
}
regions = new LodRegion[width][width];
isRegionDirty = new boolean[width][width];
regen = new boolean[width][width];
regionNeedsRegen = new boolean[width][width];
//treeGenerator((int) mc.player.getX(),(int) mc.player.getZ());
// populate isRegionDirty
for (int i = 0; i < width; i++)
for (int j = 0; j < width; j++)
isRegionDirty[i][j] = false;
center = new RegionPos(0, 0);
}
/**
* Move the center of this LodDimension and move all owned
* regions over by the given x and z offset. <br><br>
@@ -144,7 +153,7 @@ public class LodDimension
{
int xOffset = regionOffset.x;
int zOffset = regionOffset.z;
// if the x or z offset is equal to or greater than
// the total size, just delete the current data
// and update the centerX and/or centerZ
@@ -157,15 +166,15 @@ public class LodDimension
regions[x][z] = null;
}
}
// update the new center
center.x += xOffset;
center.z += zOffset;
return;
}
// X
if (xOffset > 0)
{
@@ -196,8 +205,8 @@ public class LodDimension
}
}
}
// Z
if (zOffset > 0)
{
@@ -226,22 +235,22 @@ public class LodDimension
}
}
}
// update the new center
center.x += xOffset;
center.z += zOffset;
}
/**
* return needed memory in byte
* return needed memory in bytes
*/
public int getMinMemoryNeeded()
{
int count = 0;
LodRegion region;
for (int x = 0; x < regions.length; x++)
{
for (int z = 0; z < regions.length; z++)
@@ -255,8 +264,8 @@ public class LodDimension
}
return count;
}
/**
* Gets the region at the given X and Z
* <br>
@@ -269,19 +278,19 @@ public class LodDimension
int zRegion = LevelPosUtil.getRegion(detailLevel, posZ);
int xIndex = (xRegion - center.x) + halfWidth;
int zIndex = (zRegion - center.z) + halfWidth;
if (!regionIsInRange(xRegion, zRegion))
return null;
//throw new ArrayIndexOutOfBoundsException("Region for level pos " + LevelPosUtil.toString(detailLevel, posX, posZ) + " out of range");
//throw new ArrayIndexOutOfBoundsException("Region for level pos " + LevelPosUtil.toString(detailLevel, posX, posZ) + " out of range");
else if (regions[xIndex][zIndex] == null)
return null;
//throw new InvalidParameterException("Region for level pos " + LevelPosUtil.toString(detailLevel, posX, posZ) + " not currently initialized");
//throw new InvalidParameterException("Region for level pos " + LevelPosUtil.toString(detailLevel, posX, posZ) + " not currently initialized");
else if (regions[xIndex][zIndex].getMinDetailLevel() > detailLevel)
return null;
//throw new InvalidParameterException("Region for level pos " + LevelPosUtil.toString(detailLevel, posX, posZ) + " currently only reach level " + regions[xIndex][zIndex].getMinDetailLevel());
return regions[xIndex][zIndex];
}
/**
* Gets the region at the given X and Z
* <br>
@@ -292,16 +301,22 @@ public class LodDimension
{
int xIndex = (regionPosX - center.x) + halfWidth;
int zIndex = (regionPosZ - center.z) + halfWidth;
if (!regionIsInRange(regionPosX, regionPosZ))
return null;
//throw new ArrayIndexOutOfBoundsException("Region " + regionPosX + " " + regionPosZ + " out of range");
//throw new ArrayIndexOutOfBoundsException("Region " + regionPosX + " " + regionPosZ + " out of range");
else if (regions[xIndex][zIndex] == null)
return null;
//throw new InvalidParameterException("Region " + regionPosX + " " + regionPosZ + " not currently initialized");
return regions[xIndex][zIndex];
}
/** Useful when needing to iterate over every region. */
public LodRegion getRegionByArrayIndex(int xIndex, int zIndex)
{
return regions[xIndex][zIndex];
}
/**
* Overwrite the LodRegion at the location of newRegion with newRegion.
*
@@ -311,15 +326,15 @@ public class LodDimension
{
int xIndex = (newRegion.regionPosX - center.x) + halfWidth;
int zIndex = (newRegion.regionPosZ - center.z) + halfWidth;
if (!regionIsInRange(newRegion.regionPosX, newRegion.regionPosZ))
// out of range
throw new ArrayIndexOutOfBoundsException("Region " + newRegion.regionPosX + ", " + newRegion.regionPosZ + " out of range");
regions[xIndex][zIndex] = newRegion;
}
/**
*
*/
@@ -338,7 +353,7 @@ public class LodDimension
int minDistance;
byte detail;
byte levelToCut;
for (int x = 0; x < regions.length; x++)
{
for (int z = 0; z < regions.length; z++)
@@ -358,15 +373,15 @@ public class LodDimension
regions[x][z].cutTree(levelToCut);
}
}
}// region z
}// region z
});
cutAndGenThreads.execute(thread);
}
}
/**
*
*/
@@ -375,7 +390,7 @@ public class LodDimension
DistanceGenerationMode generationMode = LodConfig.CLIENT.worldGenerator.distanceGenerationMode.get();
ChunkPos newPlayerChunk = new ChunkPos(LevelPosUtil.getChunkPos((byte) 0, playerPosX), LevelPosUtil.getChunkPos((byte) 0, playerPosZ));
LodQualityMode lodQualityMode = LodConfig.CLIENT.worldGenerator.lodQualityMode.get();
if (lastGenChunk == null)
lastGenChunk = new ChunkPos(newPlayerChunk.x + 1, newPlayerChunk.z - 1);
if (newPlayerChunk.x != lastGenChunk.x || newPlayerChunk.z != lastGenChunk.z)
@@ -398,25 +413,25 @@ public class LodDimension
final RegionPos regionPos = new RegionPos(regionX, regionZ);
region = regions[x][z];
//We require that the region we are checking is loaded with at least this level
minDistance = LevelPosUtil.minDistance(LodUtil.REGION_DETAIL_LEVEL, regionX, regionZ, playerPosX, playerPosZ);
detail = DetailDistanceUtil.getDistanceTreeGenInverse(minDistance);
levelToGen = DetailDistanceUtil.getLodGenDetail(detail).detailLevel;
if (region == null || region.getGenerationMode() != generationMode)
{
//First case, region has to be initialized
//We check if there is a file at the target level
regions[x][z] = getRegionFromFile(regionPos, levelToGen, generationMode, lodQualityMode);
//if there is no file we initialize the region
if (regions[x][z] == null)
{
regions[x][z] = new LodRegion(levelToGen, regionPos, generationMode, lodQualityMode);
}
regen[x][z] = true;
regionNeedsRegen[x][z] = true;
regenDimension = true;
} else if (region.getMinDetailLevel() > levelToGen)
{
//Second case, region has been initialized but at a higher level
@@ -429,7 +444,7 @@ public class LodDimension
cutAndGenThreads.execute(thread);
}
}
/**
* Add the given LOD to this dimension at the coordinate
* stored in the LOD. If an LOD already exists at the given
@@ -437,11 +452,11 @@ public class LodDimension
*/
public Boolean addData(byte detailLevel, int posX, int posZ, long[] dataPoint, boolean dontSave, boolean serverQuality)
{
// don't continue if the region can't be saved
int regionPosX = LevelPosUtil.getRegion(detailLevel, posX);
int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ);
LodRegion region = getRegion(regionPosX, regionPosZ);
if (region == null)
return false;
@@ -455,7 +470,7 @@ public class LodDimension
int xIndex = (regionPosX - center.x) + halfWidth;
int zIndex = (regionPosZ - center.z) + halfWidth;
isRegionDirty[xIndex][zIndex] = true;
regen[xIndex][zIndex] = true;
regionNeedsRegen[xIndex][zIndex] = true;
regenDimension = true;
} catch (ArrayIndexOutOfBoundsException e)
{
@@ -466,8 +481,8 @@ public class LodDimension
}
return nodeAdded;
}
/**
* Add the given LOD to this dimension at the coordinate
* stored in the LOD. If an LOD already exists at the given
@@ -475,11 +490,11 @@ public class LodDimension
*/
public Boolean addSingleData(byte detailLevel, int posX, int posZ, long dataPoint, boolean dontSave, boolean serverQuality)
{
// don't continue if the region can't be saved
int regionPosX = LevelPosUtil.getRegion(detailLevel, posX);
int regionPosZ = LevelPosUtil.getRegion(detailLevel, posZ);
LodRegion region = getRegion(regionPosX, regionPosZ);
if (region == null)
return false;
@@ -493,7 +508,7 @@ public class LodDimension
int xIndex = (regionPosX - center.x) + halfWidth;
int zIndex = (regionPosZ - center.z) + halfWidth;
isRegionDirty[xIndex][zIndex] = true;
regen[xIndex][zIndex] = true;
regionNeedsRegen[xIndex][zIndex] = true;
regenDimension = true;
} catch (ArrayIndexOutOfBoundsException e)
{
@@ -504,14 +519,14 @@ public class LodDimension
}
return nodeAdded;
}
public void setToRegen(int xRegion, int zRegion)
{
int xIndex = (xRegion - center.x) + halfWidth;
int zIndex = (zRegion - center.z) + halfWidth;
regen[xIndex][zIndex] = true;
regionNeedsRegen[xIndex][zIndex] = true;
}
/**
* method to get all the quadtree level that have to be generated based on the position of the player
*
@@ -533,12 +548,12 @@ public class LodDimension
region = getRegion(xIndex, zIndex);
if (region != null)
region.getDataToGenerate(posToGenerate, playerPosX, playerPosZ);
}
}
return posToGenerate;
}
/**
* method to get all the nodes that have to be rendered based on the position of the player
*
@@ -550,7 +565,7 @@ public class LodDimension
if (region != null)
region.getDataToRender(posToRender, playerPosX, playerPosZ);
}
/**
* Get the data point at the given X and Z coordinates
* in this dimension.
@@ -562,17 +577,17 @@ public class LodDimension
{
if (detailLevel > LodUtil.REGION_DETAIL_LEVEL)
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max.");
LodRegion region = getRegion(detailLevel, posX, posZ);
if (region == null)
{
return new long[]{DataPointUtil.EMPTY_DATA};
}
return region.getData(detailLevel, posX, posZ);
}
/**
* Get the data point at the given X and Z coordinates
* in this dimension.
@@ -584,17 +599,28 @@ public class LodDimension
{
if (detailLevel > LodUtil.REGION_DETAIL_LEVEL)
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max.");
LodRegion region = getRegion(detailLevel, posX, posZ);
if (region == null)
{
return DataPointUtil.EMPTY_DATA;
}
return region.getSingleData(detailLevel, posX, posZ);
}
public boolean getRegenByArrayIndex(int xIndex, int zIndex)
{
return regionNeedsRegen[xIndex][zIndex];
}
public void setRegenByArrayIndex(int xIndex, int zIndex, boolean newRegen)
{
regionNeedsRegen[xIndex][zIndex] = newRegen;
}
/**
* Get the data point at the given X and Z coordinates
* in this dimension.
@@ -606,32 +632,32 @@ public class LodDimension
{
if (detailLevel > LodUtil.REGION_DETAIL_LEVEL)
throw new IllegalArgumentException("getLodFromCoordinates given a level of \"" + detailLevel + "\" when \"" + LodUtil.REGION_DETAIL_LEVEL + "\" is the max.");
LodRegion region = getRegion(detailLevel, posX, posZ);
if (region == null)
{
return;
}
region.updateArea(detailLevel, posX, posZ);
}
/**
* return true if and only if the node at that position exist
*/
public boolean doesDataExist(byte detailLevel, int posX, int posZ)
{
LodRegion region = getRegion(detailLevel, posX, posZ);
if (region == null)
{
return false;
}
return region.doesDataExist(detailLevel, posX, posZ);
}
/**
* Get the region at the given X and Z coordinates from the
* RegionFileHandler.
@@ -643,7 +669,7 @@ public class LodDimension
else
return null;
}
/**
* Save all dirty regions in this LodDimension to file.
*/
@@ -651,8 +677,8 @@ public class LodDimension
{
fileHandler.saveDirtyRegionsToFileAsync();
}
/**
* Returns whether the region at the given X and Z coordinates
* is within the loaded range.
@@ -661,22 +687,22 @@ public class LodDimension
{
int xIndex = (regionX - center.x) + halfWidth;
int zIndex = (regionZ - center.z) + halfWidth;
return xIndex >= 0 && xIndex < width && zIndex >= 0 && zIndex < width;
}
public int getCenterX()
{
return center.x;
}
public int getCenterZ()
{
return center.z;
}
/** returns the width of the dimension in regions */
public int getWidth()
{
if (regions != null)
@@ -690,28 +716,29 @@ public class LodDimension
return width;
}
}
public void setRegionWidth(int newWidth)
{
width = newWidth;
halfWidth = Math.floorDiv(width, 2);
regions = new LodRegion[width][width];
isRegionDirty = new boolean[width][width];
regen = new boolean[width][width];
regionNeedsRegen = new boolean[width][width];
// populate isRegionDirty
for (int i = 0; i < width; i++)
for (int j = 0; j < width; j++)
isRegionDirty[i][j] = false;
}
@Override
public String toString()
{
LodRegion region;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Dimension : \n");
for (int x = 0; x < regions.length; x++)
@@ -723,7 +750,7 @@ public class LodDimension
{
stringBuilder.append("n");
stringBuilder.append("\t");
} else
{
stringBuilder.append(region.getMinDetailLevel());