Search in sources :

Example 1 with FileInUseException

use of org.pepsoft.worldpainter.util.FileInUseException in project WorldPainter by Captain-Chaos.

the class JavaWorldMerger method mergeBiomes.

/**
 * Merge only the biomes, leave everything else the same.
 */
public void mergeBiomes(File backupDir, ProgressReceiver progressReceiver) throws IOException, ProgressReceiver.OperationCancelled {
    // Read existing level.dat file and perform sanity checks
    Level level = performSanityChecks(true);
    // Backup existing level
    File worldDir = levelDatFile.getParentFile();
    if (!worldDir.renameTo(backupDir)) {
        throw new FileInUseException("Could not move " + worldDir + " to " + backupDir);
    }
    if (!worldDir.mkdirs()) {
        throw new IOException("Could not create " + worldDir);
    }
    // Copy everything that we are not going to generate (this includes the
    // Nether and End dimensions)
    File[] files = backupDir.listFiles();
    // noinspection ConstantConditions // Cannot happen because we previously loaded level.dat from it
    for (File file : files) {
        if ((!file.getName().equalsIgnoreCase("session.lock")) && (!file.getName().equalsIgnoreCase("region"))) {
            if (file.isFile()) {
                FileUtils.copyFileToDir(file, worldDir);
            } else if (file.isDirectory()) {
                FileUtils.copyDir(file, new File(worldDir, file.getName()));
            } else {
                logger.warn("Not copying " + file + "; not a regular file or directory");
            }
        }
    }
    // Write session.lock file
    File sessionLockFile = new File(worldDir, "session.lock");
    try (DataOutputStream sessionOut = new DataOutputStream(new FileOutputStream(sessionLockFile))) {
        sessionOut.writeLong(System.currentTimeMillis());
    }
    // Process all chunks and copy just the biomes
    if (progressReceiver != null) {
        progressReceiver.setMessage("Merging biomes");
    }
    // Find all the region files of the existing level
    File oldRegionDir = new File(backupDir, "region");
    final Pattern regionFilePattern = Pattern.compile("r\\.-?\\d+\\.-?\\d+\\.mca");
    File[] oldRegionFiles = oldRegionDir.listFiles((dir, name) -> regionFilePattern.matcher(name).matches());
    // Process each region file, copying every chunk unmodified, except
    // for the biomes
    // Can only happen for corrupted maps
    @SuppressWarnings("ConstantConditions") int totalChunkCount = oldRegionFiles.length * 32 * 32, chunkCount = 0;
    File newRegionDir = new File(worldDir, "region");
    newRegionDir.mkdirs();
    Dimension dimension = world.getDimension(DIM_NORMAL);
    for (File file : oldRegionFiles) {
        try (RegionFile oldRegion = new RegionFile(file)) {
            String[] parts = file.getName().split("\\.");
            int regionX = Integer.parseInt(parts[1]);
            int regionZ = Integer.parseInt(parts[2]);
            File newRegionFile = new File(newRegionDir, "r." + regionX + "." + regionZ + ".mca");
            try (RegionFile newRegion = new RegionFile(newRegionFile)) {
                for (int x = 0; x < 32; x++) {
                    for (int z = 0; z < 32; z++) {
                        if (oldRegion.containsChunk(x, z)) {
                            ChunkImpl2 chunk;
                            try (NBTInputStream in = new NBTInputStream(oldRegion.getChunkDataInputStream(x, z))) {
                                CompoundTag tag = (CompoundTag) in.readTag();
                                chunk = new ChunkImpl2(tag, level.getMaxHeight());
                            }
                            int chunkX = chunk.getxPos(), chunkZ = chunk.getzPos();
                            for (int xx = 0; xx < 16; xx++) {
                                for (int zz = 0; zz < 16; zz++) {
                                    chunk.setBiome(xx, zz, dimension.getLayerValueAt(Biome.INSTANCE, (chunkX << 4) | xx, (chunkZ << 4) | zz));
                                }
                            }
                            try (NBTOutputStream out = new NBTOutputStream(newRegion.getChunkDataOutputStream(x, z))) {
                                out.writeTag(chunk.toNBT());
                            }
                        }
                        chunkCount++;
                        if (progressReceiver != null) {
                            progressReceiver.setProgress((float) chunkCount / totalChunkCount);
                        }
                    }
                }
            }
        }
    }
    // Rewrite session.lock file
    try (DataOutputStream sessionOut = new DataOutputStream(new FileOutputStream(sessionLockFile))) {
        sessionOut.writeLong(System.currentTimeMillis());
    }
}
Also used : FileInUseException(org.pepsoft.worldpainter.util.FileInUseException) Pattern(java.util.regex.Pattern) Dimension(org.pepsoft.worldpainter.Dimension) NBTOutputStream(org.jnbt.NBTOutputStream) NBTInputStream(org.jnbt.NBTInputStream) CompoundTag(org.jnbt.CompoundTag)

Example 2 with FileInUseException

use of org.pepsoft.worldpainter.util.FileInUseException in project WorldPainter by Captain-Chaos.

the class JavaWorldMerger method merge.

public void merge(File backupDir, ProgressReceiver progressReceiver) throws IOException, ProgressReceiver.OperationCancelled {
    logger.info("Merging world " + world.getName() + " with map at " + levelDatFile.getParentFile());
    // Read existing level.dat file and perform sanity checks
    Level level = performSanityChecks(false);
    // Record start of export
    long start = System.currentTimeMillis();
    // Backup existing level
    File worldDir = levelDatFile.getParentFile();
    if (!worldDir.renameTo(backupDir)) {
        throw new FileInUseException("Could not move " + worldDir + " to " + backupDir);
    }
    if (!worldDir.mkdirs()) {
        throw new IOException("Could not create " + worldDir);
    }
    // Set the world to the same Minecraft version as the existing map, in
    // case it has changed. This affects the type of chunks created in the
    // first pass
    int version = level.getVersion();
    Platform platform = (version == SUPPORTED_VERSION_1) ? DefaultPlugin.JAVA_MCREGION : DefaultPlugin.JAVA_ANVIL;
    world.setPlatform(platform);
    // Modify it if necessary and write it to the the new level
    if ((selectedDimensions == null) || selectedDimensions.contains(DIM_NORMAL)) {
        Dimension surfaceDimension = world.getDimension(DIM_NORMAL);
        level.setSeed(surfaceDimension.getMinecraftSeed());
        Point spawnPoint = world.getSpawnPoint();
        level.setSpawnX(spawnPoint.x);
        level.setSpawnY(Math.max(surfaceDimension.getIntHeightAt(spawnPoint), surfaceDimension.getWaterLevelAt(spawnPoint)));
        level.setSpawnZ(spawnPoint.y);
    }
    // Save the level.dat file. This will also create a session.lock file, hopefully kicking out any Minecraft
    // instances which may have the map open:
    level.save(worldDir);
    // Copy everything that we are not going to generate
    File[] files = backupDir.listFiles();
    // noinspection ConstantConditions // Cannot happen because we previously loaded level.dat from it
    for (File file : files) {
        if ((!file.getName().equalsIgnoreCase("level.dat")) && (!file.getName().equalsIgnoreCase("level.dat_old")) && (!file.getName().equalsIgnoreCase("session.lock")) && (((selectedDimensions != null) && (!selectedDimensions.contains(DIM_NORMAL))) || (!file.getName().equalsIgnoreCase("region"))) && (!file.getName().equalsIgnoreCase("maxheight.txt")) && (!file.getName().equalsIgnoreCase("Height.txt")) && (((selectedDimensions != null) && (!selectedDimensions.contains(DIM_NETHER))) || (!file.getName().equalsIgnoreCase("DIM-1"))) && (((selectedDimensions != null) && (!selectedDimensions.contains(DIM_END))) || (!file.getName().equalsIgnoreCase("DIM1")))) {
            if (file.isFile()) {
                FileUtils.copyFileToDir(file, worldDir);
            } else if (file.isDirectory()) {
                FileUtils.copyDir(file, new File(worldDir, file.getName()));
            } else {
                logger.warn("Not copying " + file + "; not a regular file or directory");
            }
        }
    }
    if ((selectedDimensions == null) ? (world.getDimension(DIM_NORMAL) != null) : selectedDimensions.contains(DIM_NORMAL)) {
        mergeDimension(worldDir, backupDir, world.getDimension(DIM_NORMAL), platform, progressReceiver);
    }
    if ((selectedDimensions == null) ? (world.getDimension(DIM_NETHER) != null) : selectedDimensions.contains(DIM_NETHER)) {
        mergeDimension(worldDir, backupDir, world.getDimension(DIM_NETHER), platform, progressReceiver);
    }
    if ((selectedDimensions == null) ? (world.getDimension(DIM_END) != null) : selectedDimensions.contains(DIM_END)) {
        mergeDimension(worldDir, backupDir, world.getDimension(DIM_END), platform, progressReceiver);
    }
    // Update the session.lock file, hopefully kicking out any Minecraft instances which may have tried to open the
    // map in the mean time:
    File sessionLockFile = new File(worldDir, "session.lock");
    try (DataOutputStream sessionOut = new DataOutputStream(new FileOutputStream(sessionLockFile))) {
        sessionOut.writeLong(System.currentTimeMillis());
    }
    // Record the merge in the world history
    if (selectedDimensions == null) {
        world.addHistoryEntry(HistoryEntry.WORLD_MERGED_FULL, level.getName(), worldDir);
    } else {
        String dimNames = selectedDimensions.stream().map(dim -> {
            switch(dim) {
                case DIM_NORMAL:
                    return "Surface";
                case DIM_NETHER:
                    return "Nether";
                case DIM_END:
                    return "End";
                default:
                    return Integer.toString(dim);
            }
        }).collect(Collectors.joining(", "));
        world.addHistoryEntry(HistoryEntry.WORLD_MERGED_PARTIAL, level.getName(), worldDir, dimNames);
    }
    if (!levelDatFile.equals(world.getMergedWith())) {
        world.setMergedWith(levelDatFile);
    }
    // Log an event
    Configuration config = Configuration.getInstance();
    if (config != null) {
        EventVO event = new EventVO(EVENT_KEY_ACTION_MERGE_WORLD).duration(System.currentTimeMillis() - start);
        event.setAttribute(EventVO.ATTRIBUTE_TIMESTAMP, new Date(start));
        event.setAttribute(ATTRIBUTE_KEY_MAX_HEIGHT, world.getMaxHeight());
        event.setAttribute(ATTRIBUTE_KEY_PLATFORM, world.getPlatform().displayName);
        event.setAttribute(ATTRIBUTE_KEY_MAP_FEATURES, world.isMapFeatures());
        event.setAttribute(ATTRIBUTE_KEY_GAME_TYPE_NAME, world.getGameType().name());
        event.setAttribute(ATTRIBUTE_KEY_ALLOW_CHEATS, world.isAllowCheats());
        event.setAttribute(ATTRIBUTE_KEY_GENERATOR, world.getGenerator().name());
        if (world.getPlatform().equals(DefaultPlugin.JAVA_ANVIL) && (world.getGenerator() == Generator.FLAT)) {
            event.setAttribute(ATTRIBUTE_KEY_GENERATOR_OPTIONS, world.getGeneratorOptions());
        }
        if ((selectedDimensions == null) || selectedDimensions.contains(DIM_NORMAL)) {
            Dimension surfaceDimension = world.getDimension(0);
            event.setAttribute(ATTRIBUTE_KEY_TILES, surfaceDimension.getTiles().size());
            logLayers(surfaceDimension, event, "");
        }
        if (world.getImportedFrom() == null) {
            event.setAttribute(ATTRIBUTE_KEY_IMPORTED_WORLD, false);
        }
        config.logEvent(event);
    }
}
Also used : FileInUseException(org.pepsoft.worldpainter.util.FileInUseException) java.util(java.util) org.pepsoft.minecraft(org.pepsoft.minecraft) BLOCKS(org.pepsoft.minecraft.Block.BLOCKS) EventVO(org.pepsoft.worldpainter.vo.EventVO) ParallelProgressManager(org.pepsoft.util.ParallelProgressManager) org.pepsoft.worldpainter.layers(org.pepsoft.worldpainter.layers) NBTOutputStream(org.jnbt.NBTOutputStream) SubProgressReceiver(org.pepsoft.util.SubProgressReceiver) PlatformManager(org.pepsoft.worldpainter.plugins.PlatformManager) org.pepsoft.worldpainter.exporting(org.pepsoft.worldpainter.exporting) ThreadFactory(java.util.concurrent.ThreadFactory) ExecutorService(java.util.concurrent.ExecutorService) org.pepsoft.worldpainter(org.pepsoft.worldpainter) Constants(org.pepsoft.worldpainter.Constants) HistoryEntry(org.pepsoft.worldpainter.history.HistoryEntry) FileInUseException(org.pepsoft.worldpainter.util.FileInUseException) Collectors(java.util.stream.Collectors) Executors(java.util.concurrent.Executors) NBTInputStream(org.jnbt.NBTInputStream) Dimension(org.pepsoft.worldpainter.Dimension) java.awt(java.awt) TimeUnit(java.util.concurrent.TimeUnit) CompoundTag(org.jnbt.CompoundTag) List(java.util.List) java.io(java.io) Constants(org.pepsoft.minecraft.Constants) ProgressReceiver(org.pepsoft.util.ProgressReceiver) Tag(org.jnbt.Tag) FileUtils(org.pepsoft.util.FileUtils) Pattern(java.util.regex.Pattern) Dimension(org.pepsoft.worldpainter.Dimension) EventVO(org.pepsoft.worldpainter.vo.EventVO)

Example 3 with FileInUseException

use of org.pepsoft.worldpainter.util.FileInUseException in project WorldPainter by Captain-Chaos.

the class JavaWorldExporter method export.

@Override
public Map<Integer, ChunkFactory.Stats> export(File baseDir, String name, File backupDir, ProgressReceiver progressReceiver) throws IOException, ProgressReceiver.OperationCancelled {
    // Sanity checks
    if ((selectedTiles == null) && (selectedDimensions != null)) {
        throw new IllegalArgumentException("Exporting a subset of dimensions not supported");
    }
    // Backup existing level
    File worldDir = new File(baseDir, FileUtils.sanitiseName(name));
    logger.info("Exporting world " + world.getName() + " to map at " + worldDir);
    if (worldDir.isDirectory()) {
        if (backupDir != null) {
            logger.info("Directory already exists; backing up to " + backupDir);
            if (!worldDir.renameTo(backupDir)) {
                throw new FileInUseException("Could not move " + worldDir + " to " + backupDir);
            }
        } else {
            throw new IllegalStateException("Directory already exists and no backup directory specified");
        }
    }
    // Record start of export
    long start = System.currentTimeMillis();
    // Export dimensions
    Dimension dim0 = world.getDimension(0);
    Level level = new Level(world.getMaxHeight(), world.getPlatform());
    level.setSeed(dim0.getMinecraftSeed());
    level.setName(name);
    Point spawnPoint = world.getSpawnPoint();
    level.setSpawnX(spawnPoint.x);
    level.setSpawnY(Math.max(dim0.getIntHeightAt(spawnPoint), dim0.getWaterLevelAt(spawnPoint)));
    level.setSpawnZ(spawnPoint.y);
    if (world.getGameType() == GameType.HARDCORE) {
        level.setGameType(GAME_TYPE_SURVIVAL);
        level.setHardcore(true);
        level.setDifficulty(DIFFICULTY_HARD);
        level.setDifficultyLocked(true);
        level.setAllowCommands(false);
    } else {
        level.setGameType(world.getGameType().ordinal());
        level.setHardcore(false);
        level.setDifficulty(world.getDifficulty());
        level.setAllowCommands(world.isAllowCheats());
    }
    Dimension.Border dim0Border = dim0.getBorder();
    boolean endlessBorder = (dim0Border != null) && dim0Border.isEndless();
    if (endlessBorder) {
        StringBuilder generatorOptions = new StringBuilder("3;");
        switch(dim0Border) {
            case ENDLESS_LAVA:
            case ENDLESS_WATER:
                boolean bottomless = dim0.isBottomless();
                int borderLevel = dim0.getBorderLevel();
                int oceanDepth = Math.min(borderLevel / 2, 20);
                int dirtDepth = borderLevel - oceanDepth - (bottomless ? 1 : 0);
                if (!bottomless) {
                    generatorOptions.append("1*minecraft:bedrock,");
                }
                generatorOptions.append(dirtDepth);
                generatorOptions.append("*minecraft:dirt,");
                generatorOptions.append(oceanDepth);
                generatorOptions.append((dim0Border == Dimension.Border.ENDLESS_WATER) ? "*minecraft:water;0;" : "*minecraft:lava;1;");
                break;
            case ENDLESS_VOID:
                generatorOptions.append("1*minecraft:air;1;");
                break;
        }
        generatorOptions.append(DEFAULT_GENERATOR_OPTIONS);
        level.setMapFeatures(false);
        level.setGenerator(Generator.FLAT);
        level.setGeneratorOptions(generatorOptions.toString());
    } else {
        level.setMapFeatures(world.isMapFeatures());
        level.setGenerator(world.getGenerator());
    }
    if (world.getPlatform().equals(DefaultPlugin.JAVA_ANVIL)) {
        if ((!endlessBorder) && (world.getGenerator() == Generator.FLAT) && (world.getGeneratorOptions() != null)) {
            level.setGeneratorOptions(world.getGeneratorOptions());
        }
        World2.BorderSettings borderSettings = world.getBorderSettings();
        level.setBorderCenterX(borderSettings.getCentreX());
        level.setBorderCenterZ(borderSettings.getCentreY());
        level.setBorderSize(borderSettings.getSize());
        level.setBorderSafeZone(borderSettings.getSafeZone());
        level.setBorderWarningBlocks(borderSettings.getWarningBlocks());
        level.setBorderWarningTime(borderSettings.getWarningTime());
        level.setBorderSizeLerpTarget(borderSettings.getSizeLerpTarget());
        level.setBorderSizeLerpTime(borderSettings.getSizeLerpTime());
        level.setBorderDamagePerBlock(borderSettings.getDamagePerBlock());
    }
    // Save the level.dat file. This will also create a session.lock file, hopefully kicking out any Minecraft
    // instances which may have the map open:
    level.save(worldDir);
    Map<Integer, ChunkFactory.Stats> stats = new HashMap<>();
    int selectedDimension;
    if (selectedTiles == null) {
        selectedDimension = -1;
        boolean first = true;
        for (Dimension dimension : world.getDimensions()) {
            if (dimension.getDim() < 0) {
                // dimension, so skip it
                continue;
            }
            if (first) {
                first = false;
            } else if (progressReceiver != null) {
                progressReceiver.reset();
            }
            stats.put(dimension.getDim(), exportDimension(worldDir, dimension, world.getPlatform(), progressReceiver));
        }
    } else {
        selectedDimension = selectedDimensions.iterator().next();
        stats.put(selectedDimension, exportDimension(worldDir, world.getDimension(selectedDimension), world.getPlatform(), progressReceiver));
    }
    // Update the session.lock file, hopefully kicking out any Minecraft instances which may have tried to open the
    // map in the mean time:
    File sessionLockFile = new File(worldDir, "session.lock");
    try (DataOutputStream sessionOut = new DataOutputStream(new FileOutputStream(sessionLockFile))) {
        sessionOut.writeLong(System.currentTimeMillis());
    }
    // Record the export in the world history
    if (selectedTiles == null) {
        world.addHistoryEntry(HistoryEntry.WORLD_EXPORTED_FULL, name, worldDir);
    } else {
        world.addHistoryEntry(HistoryEntry.WORLD_EXPORTED_PARTIAL, name, worldDir, world.getDimension(selectedDimension).getName());
    }
    // Log an event
    Configuration config = Configuration.getInstance();
    if (config != null) {
        EventVO event = new EventVO(EVENT_KEY_ACTION_EXPORT_WORLD).duration(System.currentTimeMillis() - start);
        event.setAttribute(EventVO.ATTRIBUTE_TIMESTAMP, new Date(start));
        event.setAttribute(ATTRIBUTE_KEY_MAX_HEIGHT, world.getMaxHeight());
        event.setAttribute(ATTRIBUTE_KEY_PLATFORM, world.getPlatform().displayName);
        event.setAttribute(ATTRIBUTE_KEY_MAP_FEATURES, world.isMapFeatures());
        event.setAttribute(ATTRIBUTE_KEY_GAME_TYPE_NAME, world.getGameType().name());
        event.setAttribute(ATTRIBUTE_KEY_ALLOW_CHEATS, world.isAllowCheats());
        event.setAttribute(ATTRIBUTE_KEY_GENERATOR, world.getGenerator().name());
        if (world.getPlatform().equals(DefaultPlugin.JAVA_ANVIL) && (world.getGenerator() == Generator.FLAT)) {
            event.setAttribute(ATTRIBUTE_KEY_GENERATOR_OPTIONS, world.getGeneratorOptions());
        }
        Dimension dimension = world.getDimension(0);
        event.setAttribute(ATTRIBUTE_KEY_TILES, dimension.getTiles().size());
        logLayers(dimension, event, "");
        dimension = world.getDimension(1);
        if (dimension != null) {
            event.setAttribute(ATTRIBUTE_KEY_NETHER_TILES, dimension.getTiles().size());
            logLayers(dimension, event, "nether.");
        }
        dimension = world.getDimension(2);
        if (dimension != null) {
            event.setAttribute(ATTRIBUTE_KEY_END_TILES, dimension.getTiles().size());
            logLayers(dimension, event, "end.");
        }
        if (selectedDimension != -1) {
            event.setAttribute(ATTRIBUTE_KEY_EXPORTED_DIMENSION, selectedDimension);
            event.setAttribute(ATTRIBUTE_KEY_EXPORTED_DIMENSION_TILES, selectedTiles.size());
        }
        if (world.getImportedFrom() != null) {
            event.setAttribute(ATTRIBUTE_KEY_IMPORTED_WORLD, true);
        }
        config.logEvent(event);
    }
    return stats;
}
Also used : FileInUseException(org.pepsoft.worldpainter.util.FileInUseException) DataOutputStream(java.io.DataOutputStream) Dimension(org.pepsoft.worldpainter.Dimension) FileOutputStream(java.io.FileOutputStream) Level(org.pepsoft.minecraft.Level) File(java.io.File) EventVO(org.pepsoft.worldpainter.vo.EventVO)

Aggregations

Dimension (org.pepsoft.worldpainter.Dimension)3 FileInUseException (org.pepsoft.worldpainter.util.FileInUseException)3 Pattern (java.util.regex.Pattern)2 CompoundTag (org.jnbt.CompoundTag)2 NBTInputStream (org.jnbt.NBTInputStream)2 NBTOutputStream (org.jnbt.NBTOutputStream)2 EventVO (org.pepsoft.worldpainter.vo.EventVO)2 java.awt (java.awt)1 java.io (java.io)1 DataOutputStream (java.io.DataOutputStream)1 File (java.io.File)1 FileOutputStream (java.io.FileOutputStream)1 java.util (java.util)1 List (java.util.List)1 ExecutorService (java.util.concurrent.ExecutorService)1 Executors (java.util.concurrent.Executors)1 ThreadFactory (java.util.concurrent.ThreadFactory)1 TimeUnit (java.util.concurrent.TimeUnit)1 Collectors (java.util.stream.Collectors)1 Tag (org.jnbt.Tag)1