New save structure. No more multi folders for Generation Mode

This also includes a converter that runs on "Joining World..." text. It
may stuck on that screen for a while, but it is indeed merging and
updating the old saves.

The old saves file after update is not deleted. Instead, the folders are
renamed so that you still have a way to recover old saves in case the
converter failed.
This commit is contained in:
tom lee
2022-01-19 23:28:56 +08:00
parent 22e47b9734
commit 914a76297d
6 changed files with 383 additions and 62 deletions
@@ -195,7 +195,7 @@ public class LodBuilder
region.isWriting++;
try {
if (region.getMinDetailLevel()!= 0) {
LodRegion newRegion = lodDim.getRegionFromFile(region, (byte)0, region.getGenerationMode(), region.getVerticalQuality());
LodRegion newRegion = lodDim.getRegionFromFile(region, (byte)0, region.getVerticalQuality());
assert(region==newRegion);
}
if (region.addChunkOfData((byte)0, chunk.getMinX(), chunk.getMinZ(), 16, 16, data, maxVerticalData, true)) {
@@ -168,7 +168,7 @@ public class LodWorldGenerator
IWorldWrapper serverWorld = LodUtil.getServerWorldFromDimension(lodDim.dimension);
PosToGenerateContainer posToGenerate = lodDim.getPosToGenerate(
maxChunkGenRequests, playerPosX, playerPosZ, priority);
maxChunkGenRequests, playerPosX, playerPosZ, priority, mode);
byte detailLevel;
int posX;
@@ -24,12 +24,15 @@ import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.HashSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
import org.apache.commons.compress.compressors.xz.XZCompressorOutputStream;
@@ -59,7 +62,7 @@ public class LodDimensionFileHandler
/** This is the dimension that owns this file handler */
private final LodDimension lodDimension;
private final File dimensionDataSaveFolder;
public final File dimensionDataSaveFolder;
/** lod */
private static final String FILE_NAME_PREFIX = "lod";
@@ -101,9 +104,68 @@ public class LodDimensionFileHandler
dimensionDataSaveFolder = newSaveFolder;
lodDimension = newLodDimension;
checkForOldSaveStructure();
}
private ReentrantLock mergeOldFileLock = new ReentrantLock();
private void checkForOldSaveStructure()
{
File file = new File(getFileBasePath());
if (!file.exists())
return;
File[] vertQualFiles = file.listFiles();
for (File vertQualFile : vertQualFiles)
{
if (!vertQualFile.isDirectory())
continue;
if (vertQualFile.getName().equals("HIGH") ||
vertQualFile.getName().equals("MEDIUM") ||
vertQualFile.getName().equals("LOW"))
{
File[] subFiles = vertQualFile.listFiles();
for (File subFile : subFiles)
{
if (!subFile.isDirectory())
continue;
if (subFile.getName().equals("FULL") ||
subFile.getName().equals("FEATURES") ||
subFile.getName().equals("SURFACE") ||
subFile.getName().equals("BIOME_ONLY_SIMULATE_HEIGHT") ||
subFile.getName().equals("BIOME_ONLY") ||
subFile.getName().equals("NONE"))
{
ClientApi.LOGGER.info("Noticed old save structure files. Starting merge process...");
LodDimensionOldFileStructureHandler oldFileStructHandler = new LodDimensionOldFileStructureHandler(this);
if (mergeOldFileLock.tryLock())
{
// I got the lock to merge file.
ClientApi.LOGGER.info("Updating VerticalQuality LOW...");
oldFileStructHandler.mergeOldFileStructureForVertQuality(VerticalQuality.LOW);
ClientApi.LOGGER.info("Updating VerticalQuality MEDIUM...");
oldFileStructHandler.mergeOldFileStructureForVertQuality(VerticalQuality.MEDIUM);
ClientApi.LOGGER.info("Updating VerticalQuality HIGH...");
oldFileStructHandler.mergeOldFileStructureForVertQuality(VerticalQuality.HIGH);
ClientApi.LOGGER.info("Update completed.");
}
else
{
// Someone is already doing it. I just need to wait until he is done.
mergeOldFileLock.lock();
mergeOldFileLock.unlock();
}
ClientApi.LOGGER.info("Merge process completed.");
return;
}
}
}
}
}
@@ -115,27 +177,26 @@ public class LodDimensionFileHandler
* Returns a new LodRegion at the given coordinates.
* Returns an empty region if the file doesn't exist.
*/
public LodRegion loadRegionFromFile(byte detailLevel, RegionPos regionPos, DistanceGenerationMode generationMode, VerticalQuality verticalQuality)
public LodRegion loadRegionFromFile(byte detailLevel, RegionPos regionPos, VerticalQuality verticalQuality)
{
// Get one from the region hot cache
LodRegion region = regionToSave.get(regionPos);
if (region!=null && region.getMinDetailLevel()<=detailLevel &&
region.getGenerationMode().compareTo(generationMode)>=0 &&
region.getVerticalQuality().compareTo(verticalQuality)>=0)
return region; // The current hot cache to-be-saved region match our requirement.
region = new LodRegion((byte) (LodUtil.REGION_DETAIL_LEVEL+1), regionPos, generationMode, verticalQuality);
return loadRegionFromFile(detailLevel, region, generationMode, verticalQuality);
region = new LodRegion((byte) (LodUtil.REGION_DETAIL_LEVEL+1), regionPos, verticalQuality);
return loadRegionFromFile(detailLevel, region, verticalQuality);
}
/**
* Returns the LodRegion that is filled at the given coordinates.
* Returns an empty region if the file doesn't exist.
*/
public LodRegion loadRegionFromFile(byte detailLevel, LodRegion region, DistanceGenerationMode generationMode, VerticalQuality verticalQuality)
public LodRegion loadRegionFromFile(byte detailLevel, LodRegion region, VerticalQuality verticalQuality)
{
if (region.getGenerationMode().compareTo(generationMode)<0 || region.getVerticalQuality().compareTo(verticalQuality)<0) {
if (region.getVerticalQuality().compareTo(verticalQuality)<0) {
regionToSave.put(region.getRegionPos(), region); //FIXME: The hashMap key should prob be a {regionPos,VertQual} pair.
region = new LodRegion((byte) (LodUtil.REGION_DETAIL_LEVEL+1), region.getRegionPos(), generationMode, verticalQuality);
region = new LodRegion((byte) (LodUtil.REGION_DETAIL_LEVEL+1), region.getRegionPos(), verticalQuality);
}
int regionX = region.regionPosX;
int regionZ = region.regionPosZ;
@@ -143,7 +204,7 @@ public class LodDimensionFileHandler
for (byte tempDetailLevel = (byte) (region.getMinDetailLevel()-1); tempDetailLevel >= detailLevel; tempDetailLevel--)
{
File file = getBestMatchingRegionFile(tempDetailLevel, regionX, regionZ, generationMode, verticalQuality);
File file = getBestMatchingRegionFile(tempDetailLevel, regionX, regionZ, verticalQuality);
if (file == null) {
region.addLevelContainer(new VerticalLevelContainer(tempDetailLevel));
continue; // Failed to find the file for this detail level. continue and try next one
@@ -221,6 +282,38 @@ public class LodDimensionFileHandler
// Save to File //
//==============//
public void saveDirect(int posX, int posZ, VerticalQuality vertQual, VerticalLevelContainer dataContainer) {
File file = new File(getFileBasePath() + vertQual + File.separatorChar +
DETAIL_FOLDER_NAME_PREFIX + dataContainer.detailLevel + File.separatorChar +
FILE_NAME_PREFIX + "." + posX + "." + posZ + FILE_EXTENSION);
if (file.exists())
throw new IllegalStateException("saveDirect(...) should only be used for converting old save structure!");
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
try {
file.createNewFile();
} catch (IOException e) {
ClientApi.LOGGER.error("LOD file write error. Unable to create parent directory for [" + file + "] error [" + e.getMessage() + "]: ");
e.printStackTrace();
return;
}
try (FileOutputStream fileOutStream = new FileOutputStream(file))
{
XZCompressorOutputStream outputStream = new XZCompressorOutputStream(fileOutStream, 3);
// add the version of this file
outputStream.write(LOD_SAVE_FILE_VERSION);
// add each LodChunk to the file
dataContainer.writeData(new DataOutputStream(outputStream));
outputStream.close();
}
catch (IOException e)
{
ClientApi.LOGGER.error("LOD file write error. Unable to write to temp file [" + file + "] error [" + e.getMessage() + "]: ");
e.printStackTrace();
}
}
public void addRegionsToSave(LodRegion r) {
regionToSave.put(r.getRegionPos(), r);
}
@@ -330,7 +423,7 @@ public class LodDimensionFileHandler
for (byte detailLevel = region.getMinDetailLevel(); detailLevel <= LodUtil.REGION_DETAIL_LEVEL; detailLevel++)
{
// Get the old file
File oldFile = getRegionFile(region.regionPosX, region.regionPosZ, region.getGenerationMode(), detailLevel, region.getVerticalQuality());
File oldFile = getRegionFile(region.regionPosX, region.regionPosZ, detailLevel, region.getVerticalQuality());
ClientApi.LOGGER.debug("saving region [" + region.regionPosX + ", " + region.regionPosZ + "] detail "+detailLevel+" to file.");
boolean isFileFullyGened = false;
@@ -448,25 +541,19 @@ public class LodDimensionFileHandler
}
}
private File getRegionFile(int regionX, int regionZ, DistanceGenerationMode genMode, byte detail, VerticalQuality vertQuality) {
private File getRegionFile(int regionX, int regionZ, byte detail, VerticalQuality vertQuality) {
return new File(getFileBasePath() + vertQuality + File.separatorChar +
genMode + File.separatorChar +
DETAIL_FOLDER_NAME_PREFIX + detail + File.separatorChar +
FILE_NAME_PREFIX + "." + regionX + "." + regionZ + FILE_EXTENSION);
}
// Return null if no file found
private File getBestMatchingRegionFile(byte detailLevel, int regionX, int regionZ, DistanceGenerationMode targetGenMode, VerticalQuality targetVertQuality) {
DistanceGenerationMode genMode = DistanceGenerationMode.FULL;
// Search from least GenMode to max GenMode, than least vertQuality to max vertQuality
private File getBestMatchingRegionFile(byte detailLevel, int regionX, int regionZ, VerticalQuality targetVertQuality) {
// Search from least vertQuality to max vertQuality
do {
File file = getRegionFile(regionX, regionZ, genMode, detailLevel, targetVertQuality);
File file = getRegionFile(regionX, regionZ, detailLevel, targetVertQuality);
if (file.exists()) return file; // Found target file.
genMode = DistanceGenerationMode.previous(genMode);
if (genMode==null || genMode==DistanceGenerationMode.previous(targetGenMode)) { // Failed to find any files for this vertQuality. Try next one up.
genMode = DistanceGenerationMode.FULL;
targetVertQuality = VerticalQuality.next(targetVertQuality);
}
targetVertQuality = VerticalQuality.next(targetVertQuality);
} while (targetVertQuality != null);
return null;
}
@@ -0,0 +1,244 @@
package com.seibel.lod.core.handlers;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
import com.seibel.lod.core.enums.config.VerticalQuality;
import com.seibel.lod.core.objects.lod.RegionPos;
import com.seibel.lod.core.objects.lod.VerticalLevelContainer;
import com.seibel.lod.core.util.LodUtil;
public class LodDimensionOldFileStructureHandler
{
/** This is the dimension that owns this file handler */
private final File dimensionDataSaveFolder;
private final LodDimensionFileHandler newFileHandler;
/** lod */
private static final String FILE_NAME_PREFIX = "lod";
/** .txt */
private static final String FILE_EXTENSION = ".xz";
/** detail- */
private static final String DETAIL_FOLDER_NAME_PREFIX = "detail-";
private static final String RETIRED_OLD_STRUCT_POSTFIX = "-RETIRED-CAN-BE-DELETED";
public static final int LOD_SAVE_FILE_VERSION = 8;
public static final ExecutorService mergerThreads = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
private static class TempLodRegion {
final VerticalLevelContainer[] containers;
final VerticalQuality vertQual;
final int posX;
final int posZ;
TempLodRegion(VerticalQuality vertQual, RegionPos pos) {
this.vertQual = vertQual;
posX = pos.x;
posZ = pos.z;
containers = new VerticalLevelContainer[LodUtil.REGION_DETAIL_LEVEL+1];
}
}
public LodDimensionOldFileStructureHandler(LodDimensionFileHandler fileHandler)
{
dimensionDataSaveFolder = fileHandler.dimensionDataSaveFolder;
newFileHandler = fileHandler;
}
private void loadGenModeToRegion(TempLodRegion region, DistanceGenerationMode genMode)
{
int regionX = region.posX;
int regionZ = region.posZ;
for (byte detail = LodUtil.REGION_DETAIL_LEVEL; detail >= 0; detail--) {
File file = new File(getFileBasePath() + region.vertQual + File.separatorChar +
genMode + File.separatorChar + DETAIL_FOLDER_NAME_PREFIX + detail + File.separatorChar +
FILE_NAME_PREFIX + "." + regionX + "." + regionZ + FILE_EXTENSION);
if (!file.exists()) continue;
if (!file.isFile()) continue;
long fileSize = file.length();
if (fileSize == 0) continue;
try (FileInputStream fileInStream = new FileInputStream(file))
{
XZCompressorInputStream inputStream = new XZCompressorInputStream(fileInStream);
int fileVersion;
fileVersion = inputStream.read();
// check if this file can be read by this file handler
if (fileVersion < 6)
{
// the file we are reading is too old.
// close the reader and delete the file.
inputStream.close();
ClientApi.LOGGER.info("Outdated LOD region file for region: (" + regionX + "," + regionZ + ")"
+ " version found: " + fileVersion
+ ", version requested: " + LOD_SAVE_FILE_VERSION
+ ". this region file will not be read and merged into the new save structure.");
continue;
}
else if (fileVersion > LOD_SAVE_FILE_VERSION)
{
// the file we are reading is a newer version,
// close the reader and ignore the file, we don't
// want to accidentally delete anything the user may want.
inputStream.close();
ClientApi.LOGGER.info("Unexpected newer LOD region file for region: (" + regionX + "," + regionZ + ")"
+ " version found: " + fileVersion
+ ", version requested: " + LOD_SAVE_FILE_VERSION
+ " this region file will not be read and merged into the new save structure.");
continue;
}
else if (fileVersion < LOD_SAVE_FILE_VERSION)
{
ClientApi.LOGGER.debug("Old LOD region file for region: (" + regionX + "," + regionZ + ")"
+ " version found: " + fileVersion
+ ", version requested: " + LOD_SAVE_FILE_VERSION
+ ". this region file be read, updated, and merged into the new save structure.");
}
VerticalLevelContainer data = new VerticalLevelContainer(new DataInputStream(inputStream), fileVersion, detail);
if (region.containers[detail] == null) {
region.containers[detail] = data;
} else {
region.containers[detail].addChunkOfData(data.dataContainer, 0, 0, data.size, data.size, false);
}
inputStream.close();
}
catch (IOException ioEx)
{
ClientApi.LOGGER.error("LOD file read error. Unable to read xz compressed file [" + file + "] error [" + ioEx.getMessage() + "]: ");
ioEx.printStackTrace();
}
}
}
private void saveRegion(TempLodRegion region) {
for (int detail=0; detail<=LodUtil.REGION_DETAIL_LEVEL; detail++) {
if (region.containers[detail] == null) continue;
newFileHandler.saveDirect(region.posX, region.posZ, region.vertQual, region.containers[detail]);
}
}
private void loadAndMergeAndSaveRegion(VerticalQuality verticalQuality, RegionPos regionPos)
{
ClientApi.LOGGER.info("Merging region "+regionPos+" at "+verticalQuality+"...");
TempLodRegion region = new TempLodRegion(verticalQuality, regionPos);
ClientApi.LOGGER.info("Reading data...");
loadGenModeToRegion(region, DistanceGenerationMode.FULL);
loadGenModeToRegion(region, DistanceGenerationMode.FEATURES);
loadGenModeToRegion(region, DistanceGenerationMode.SURFACE);
loadGenModeToRegion(region, DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT);
loadGenModeToRegion(region, DistanceGenerationMode.BIOME_ONLY);
loadGenModeToRegion(region, DistanceGenerationMode.NONE);
ClientApi.LOGGER.info("Writing data...");
saveRegion(region);
ClientApi.LOGGER.info("region "+regionPos+" at "+verticalQuality+" merged");
}
private RegionPos parseFileName(String fileName) {
if (!fileName.endsWith(FILE_EXTENSION)) return null;
if (!fileName.startsWith(FILE_NAME_PREFIX)) return null;
String[] array = fileName.split("\\."); // Array content: "lod", "-1", "1", ".xz"
if (array.length!=4) return null;
try {
return new RegionPos(Integer.parseInt(array[1]), Integer.parseInt(array[2]));
} catch (NumberFormatException e) {
return null;
}
}
private HashSet<RegionPos> scanOldRegionFiles(VerticalQuality vertQual, DistanceGenerationMode genMode) {
HashSet<RegionPos> result = new HashSet<RegionPos>();
File baseBaseFolder = new File(getFileBasePath() + vertQual + File.separatorChar + genMode);
if (!baseBaseFolder.exists()) return result;
for (byte detail=0; detail <= LodUtil.REGION_DETAIL_LEVEL; detail++) {
File baseFolder = new File(getFileBasePath() + vertQual + File.separatorChar +
genMode + File.separatorChar + DETAIL_FOLDER_NAME_PREFIX + detail);
if (!baseFolder.exists()) continue;
if (!baseFolder.isDirectory()) continue;
File[] subFiles = baseFolder.listFiles();
for (File subFile : subFiles) {
if (!subFile.isFile()) continue;
if (!subFile.canRead()) continue;
RegionPos pos = parseFileName(subFile.getName());
if (pos != null) result.add(pos);
}
}
return result;
}
private void renameOldFileStructure(VerticalQuality vertQual, DistanceGenerationMode genMode) {
File baseBaseFolder = new File(getFileBasePath() + vertQual + File.separatorChar + genMode);
if (!baseBaseFolder.exists()) return;
baseBaseFolder.renameTo(new File(getFileBasePath() + vertQual + File.separatorChar + genMode + RETIRED_OLD_STRUCT_POSTFIX));
}
public void mergeOldFileStructureForVertQuality(VerticalQuality vertQual) {
File baseFile = new File(getFileBasePath() + vertQual);
if (!baseFile.exists()) return;
if (!baseFile.isDirectory()) return;
HashSet<RegionPos> totalPos = new HashSet<RegionPos>();
totalPos.addAll(scanOldRegionFiles(vertQual, DistanceGenerationMode.NONE));
totalPos.addAll(scanOldRegionFiles(vertQual, DistanceGenerationMode.BIOME_ONLY));
totalPos.addAll(scanOldRegionFiles(vertQual, DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT));
totalPos.addAll(scanOldRegionFiles(vertQual, DistanceGenerationMode.SURFACE));
totalPos.addAll(scanOldRegionFiles(vertQual, DistanceGenerationMode.FEATURES));
totalPos.addAll(scanOldRegionFiles(vertQual, DistanceGenerationMode.FULL));
ArrayList<Future<?>> futures = new ArrayList<Future<?>>();
for (RegionPos pos : totalPos) {
futures.add(mergerThreads.submit(() -> {
loadAndMergeAndSaveRegion(vertQual, pos);
return true;
}));
}
futures.forEach(t ->
{
try
{
t.get();
}
catch (Exception e)
{
e.printStackTrace();
}
});
renameOldFileStructure(vertQual, DistanceGenerationMode.NONE);
renameOldFileStructure(vertQual, DistanceGenerationMode.BIOME_ONLY);
renameOldFileStructure(vertQual, DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT);
renameOldFileStructure(vertQual, DistanceGenerationMode.SURFACE);
renameOldFileStructure(vertQual, DistanceGenerationMode.FEATURES);
renameOldFileStructure(vertQual, DistanceGenerationMode.FULL);
}
private String getFileBasePath() {
try {
return dimensionDataSaveFolder.getCanonicalPath() + File.separatorChar;
} catch (IOException e) {
ClientApi.LOGGER.warn("Unable to get the base save file path. One possible cause is that"
+ " the process failed to read the current path location due to security configs.");
throw new RuntimeException("DistantHorizons Get Save File Path Failure");
}
}
}
@@ -420,7 +420,6 @@ public class LodDimension
if (isExpanding) return;
isExpanding = true;
DistanceGenerationMode generationMode = CONFIG.client().worldGenerator().getDistanceGenerationMode();
VerticalQuality verticalQuality = CONFIG.client().graphics().quality().getVerticalQuality();
DropoffQuality dropoffQuality = CONFIG.client().graphics().quality().getDropoffQuality();
if (dropoffQuality == DropoffQuality.AUTO)
@@ -455,14 +454,13 @@ public class LodDimension
boolean updated = false;
if (region == null) {
region = getRegionFromFile(regionPos, minDetail, generationMode, verticalQuality);
region = getRegionFromFile(regionPos, minDetail, verticalQuality);
regions[x][z] = region;
updated = true;
} else if (region.getGenerationMode().compareTo(generationMode) < 0 ||
region.getVerticalQuality() != verticalQuality ||
} else if (region.getVerticalQuality() != verticalQuality ||
region.getMinDetailLevel() > minDetail) {
// The 'getRegionFromFile' will flush and save the region if it returns a new one
region = getRegionFromFile(regions[x][z], minDetail, generationMode, verticalQuality);
region = getRegionFromFile(regions[x][z], minDetail, verticalQuality);
regions[x][z] = region;
updated = true;
} else if (minDetail <= dropoffSwitch && region.lastMaxDetailLevel != maxDetail) {
@@ -518,7 +516,8 @@ public class LodDimension
/**
* Returns every position that need to be generated based on the position of the player
*/
public PosToGenerateContainer getPosToGenerate(int maxDataToGenerate, int playerBlockPosX, int playerBlockPosZ, GenerationPriority priority)
public PosToGenerateContainer getPosToGenerate(int maxDataToGenerate, int playerBlockPosX, int playerBlockPosZ,
GenerationPriority priority, DistanceGenerationMode genMode)
{
PosToGenerateContainer posToGenerate;
posToGenerate = new PosToGenerateContainer((byte) 8, maxDataToGenerate, playerBlockPosX, playerBlockPosZ);
@@ -527,7 +526,7 @@ public class LodDimension
//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, genMode,
isCloseRange);
});
return posToGenerate;
@@ -651,31 +650,29 @@ public class LodDimension
}
/** Returns true if a region exists at the given LevelPos */
public boolean doesDataExist(byte detailLevel, int posX, int posZ)
public boolean doesDataExist(byte detailLevel, int posX, int posZ, DistanceGenerationMode requiredMode)
{
LodRegion region = getRegion(detailLevel, posX, posZ);
return region != null && region.doesDataExist(detailLevel, posX, posZ);
return region != null && region.doesDataExist(detailLevel, posX, posZ, requiredMode);
}
/**
* Loads the region at the given RegionPos from file,
* if a file exists for that region.
*/
public LodRegion getRegionFromFile(RegionPos regionPos, byte detailLevel,
DistanceGenerationMode generationMode, VerticalQuality verticalQuality)
public LodRegion getRegionFromFile(RegionPos regionPos, byte detailLevel, VerticalQuality verticalQuality)
{
return fileHandler != null ? fileHandler.loadRegionFromFile(detailLevel, regionPos, generationMode, verticalQuality) :
new LodRegion(detailLevel, regionPos, generationMode, verticalQuality);
return fileHandler != null ? fileHandler.loadRegionFromFile(detailLevel, regionPos, verticalQuality) :
new LodRegion(detailLevel, regionPos, verticalQuality);
}
/**
* Loads the region at the given region from file,
* if a file exists for that region.
*/
public LodRegion getRegionFromFile(LodRegion existingRegion, byte detailLevel,
DistanceGenerationMode generationMode, VerticalQuality verticalQuality)
public LodRegion getRegionFromFile(LodRegion existingRegion, byte detailLevel, VerticalQuality verticalQuality)
{
return fileHandler != null ? fileHandler.loadRegionFromFile(detailLevel, existingRegion, generationMode, verticalQuality) :
new LodRegion(detailLevel, existingRegion.getRegionPos(), generationMode, verticalQuality);
return fileHandler != null ? fileHandler.loadRegionFromFile(detailLevel, existingRegion, verticalQuality) :
new LodRegion(detailLevel, existingRegion.getRegionPos(), verticalQuality);
}
/** Save all dirty regions in this LodDimension to file. */
@@ -58,8 +58,6 @@ public class LodRegion {
/** This chunk Pos has been generated */
// private final boolean[] preGeneratedChunkPos;
/** the generation mode for this region */
private final DistanceGenerationMode generationMode;
/** the vertical quality of this region */
private final VerticalQuality verticalQuality;
@@ -72,13 +70,11 @@ public class LodRegion {
public volatile boolean needSaving = false;
public volatile int isWriting = 0;
public LodRegion(byte minDetailLevel, RegionPos regionPos, DistanceGenerationMode generationMode,
VerticalQuality verticalQuality) {
public LodRegion(byte minDetailLevel, RegionPos regionPos, VerticalQuality verticalQuality) {
this.minDetailLevel = minDetailLevel;
this.regionPosX = regionPos.x;
this.regionPosZ = regionPos.z;
this.verticalQuality = verticalQuality;
this.generationMode = generationMode;
dataContainer = new LevelContainer[POSSIBLE_LOD];
// Initialize all the different matrices
@@ -189,8 +185,8 @@ public class LodRegion {
* understand
*/
public void getPosToGenerate(PosToGenerateContainer posToGenerate, int playerBlockPosX, int playerBlockPosZ,
GenerationPriority priority, boolean shouldSort) {
getPosToGenerate(posToGenerate, LodUtil.REGION_DETAIL_LEVEL, 0, 0, playerBlockPosX, playerBlockPosZ, priority, shouldSort);
GenerationPriority priority, DistanceGenerationMode genMode, boolean shouldSort) {
getPosToGenerate(posToGenerate, LodUtil.REGION_DETAIL_LEVEL, 0, 0, playerBlockPosX, playerBlockPosZ, priority, genMode, shouldSort);
}
@@ -202,7 +198,7 @@ public class LodRegion {
* understand
*/
private void getPosToGenerate(PosToGenerateContainer posToGenerate, byte detailLevel, int childOffsetPosX,
int childOffsetPosZ, int playerPosX, int playerPosZ, GenerationPriority priority, boolean shouldSort) {
int childOffsetPosZ, int playerPosX, int playerPosZ, GenerationPriority priority, DistanceGenerationMode genMode, boolean shouldSort) {
// equivalent to 2^(...)
int size = 1 << (LodUtil.REGION_DETAIL_LEVEL - detailLevel);
@@ -219,26 +215,26 @@ public class LodRegion {
byte targetDetailLevel = DetailDistanceUtil.getGenerationDetailFromDistance(minDistance);
if (targetDetailLevel <= detailLevel) {
if (targetDetailLevel == detailLevel) {
if (!doesDataExist(detailLevel, childOffsetPosX, childOffsetPosZ))
if (!doesDataExist(detailLevel, childOffsetPosX, childOffsetPosZ, genMode))
posToGenerate.addPosToGenerate(detailLevel, childOffsetPosX + regionPosX * size,
childOffsetPosZ + regionPosZ * size, shouldSort);
} else {
if (priority == GenerationPriority.FAR_FIRST && detailLevel >= posToGenerate.farMinDetail
&& !doesDataExist(detailLevel, childOffsetPosX, childOffsetPosZ)) {
&& !doesDataExist(detailLevel, childOffsetPosX, childOffsetPosZ, genMode)) {
posToGenerate.addPosToGenerate(detailLevel, childOffsetPosX + regionPosX * 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, shouldSort);
playerPosZ, priority, genMode, 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, shouldSort);
priority, genMode, shouldSort);
}
}
}
@@ -309,7 +305,7 @@ public class LodRegion {
for (int x = 0; x <= 1; x++) {
for (int z = 0; z <= 1; z++) {
if (doesDataExist(childDetailLevel, childPosX + x, childPosZ + z)) {
if (doesDataExist(childDetailLevel, childPosX + x, childPosZ + z, DistanceGenerationMode.NONE)) {
if (!requireCorrectDetailLevel)
childrenCount++;
else
@@ -352,7 +348,7 @@ public class LodRegion {
for (int x = 0; x <= 1; x++) {
for (int z = 0; z <= 1; z++) {
if (doesDataExist(childDetailLevel, childPosX + x, childPosZ + z)) {
if (doesDataExist(childDetailLevel, childPosX + x, childPosZ + z, DistanceGenerationMode.NONE)) {
if (!requireCorrectDetailLevel)
childrenCount++;
else
@@ -451,14 +447,15 @@ public class LodRegion {
/**
* Returns if data exists at the given relative Pos.
*/
public boolean doesDataExist(byte detailLevel, int posX, int posZ) {
public boolean doesDataExist(byte detailLevel, int posX, int posZ, DistanceGenerationMode requiredMode) {
if (detailLevel < minDetailLevel || dataContainer[detailLevel] == null)
return false;
posX = LevelPosUtil.getRegionModule(detailLevel, posX);
posZ = LevelPosUtil.getRegionModule(detailLevel, posZ);
return dataContainer[detailLevel].doesItExist(posX, posZ);
if (!dataContainer[detailLevel].doesItExist(posX, posZ)) return false;
byte mode = DataPointUtil.getGenerationMode(dataContainer[detailLevel].getSingleData(posX, posZ));
return (mode>=requiredMode.complexity);
}
/**
@@ -571,10 +568,6 @@ public class LodRegion {
return verticalQuality;
}
public DistanceGenerationMode getGenerationMode() {
return generationMode;
}
public int getMaxVerticalData(byte detailLevel) {
return dataContainer[detailLevel].getVerticalSize();
}