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:
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user