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());
}
}
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);
}
}
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;
}
Aggregations