From 914a76297ddda6eada69602be714e71a6f720bde Mon Sep 17 00:00:00 2001 From: tom lee Date: Wed, 19 Jan 2022 23:28:56 +0800 Subject: [PATCH] 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. --- .../core/builders/lodBuilding/LodBuilder.java | 2 +- .../worldGeneration/LodWorldGenerator.java | 2 +- .../handlers/LodDimensionFileHandler.java | 131 ++++++++-- .../LodDimensionOldFileStructureHandler.java | 244 ++++++++++++++++++ .../lod/core/objects/lod/LodDimension.java | 31 +-- .../lod/core/objects/lod/LodRegion.java | 35 +-- 6 files changed, 383 insertions(+), 62 deletions(-) create mode 100644 src/main/java/com/seibel/lod/core/handlers/LodDimensionOldFileStructureHandler.java 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 4ae3405cf..c8dd9c9f7 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 @@ -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)) { diff --git a/src/main/java/com/seibel/lod/core/builders/worldGeneration/LodWorldGenerator.java b/src/main/java/com/seibel/lod/core/builders/worldGeneration/LodWorldGenerator.java index 273d6f118..729a34fea 100644 --- a/src/main/java/com/seibel/lod/core/builders/worldGeneration/LodWorldGenerator.java +++ b/src/main/java/com/seibel/lod/core/builders/worldGeneration/LodWorldGenerator.java @@ -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; diff --git a/src/main/java/com/seibel/lod/core/handlers/LodDimensionFileHandler.java b/src/main/java/com/seibel/lod/core/handlers/LodDimensionFileHandler.java index 971c3a154..9c20f3110 100644 --- a/src/main/java/com/seibel/lod/core/handlers/LodDimensionFileHandler.java +++ b/src/main/java/com/seibel/lod/core/handlers/LodDimensionFileHandler.java @@ -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; } diff --git a/src/main/java/com/seibel/lod/core/handlers/LodDimensionOldFileStructureHandler.java b/src/main/java/com/seibel/lod/core/handlers/LodDimensionOldFileStructureHandler.java new file mode 100644 index 000000000..9dc799338 --- /dev/null +++ b/src/main/java/com/seibel/lod/core/handlers/LodDimensionOldFileStructureHandler.java @@ -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 scanOldRegionFiles(VerticalQuality vertQual, DistanceGenerationMode genMode) { + HashSet result = new HashSet(); + 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 totalPos = new HashSet(); + 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> futures = new ArrayList>(); + 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"); + } + } + +} 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 b5f71760d..f12c2cd48 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 @@ -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. */ 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 ac2f7e15c..ec20e01cf 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 @@ -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(); }