use of org.pepsoft.util.ProgressReceiver.OperationCancelled in project WorldPainter by Captain-Chaos.
the class AbstractWorldExporter method parallelExportRegions.
protected final ChunkFactory.Stats parallelExportRegions(Dimension dimension, Platform platform, File worldDir, ProgressReceiver progressReceiver) throws OperationCancelled {
if (progressReceiver != null) {
progressReceiver.setMessage("Exporting " + dimension.getName() + " dimension");
}
long start = System.currentTimeMillis();
final Dimension ceiling;
switch(dimension.getDim()) {
case DIM_NORMAL:
ceiling = dimension.getWorld().getDimension(DIM_NORMAL_CEILING);
break;
case DIM_NETHER:
ceiling = dimension.getWorld().getDimension(DIM_NETHER_CEILING);
break;
case DIM_END:
ceiling = dimension.getWorld().getDimension(DIM_END_CEILING);
break;
default:
throw new IllegalArgumentException("Dimension " + dimension.getDim() + " not supported");
}
final ChunkFactory.Stats collectedStats = new ChunkFactory.Stats();
boolean wasDirty = dimension.isDirty(), ceilingWasDirty = (ceiling != null) && ceiling.isDirty();
dimension.rememberChanges();
if (ceiling != null) {
ceiling.rememberChanges();
}
try {
final Map<Layer, LayerExporter> exporters = setupDimensionForExport(dimension);
final Map<Layer, LayerExporter> ceilingExporters = (ceiling != null) ? setupDimensionForExport(ceiling) : null;
// Determine regions to export
int lowestRegionX = Integer.MAX_VALUE, highestRegionX = Integer.MIN_VALUE, lowestRegionZ = Integer.MAX_VALUE, highestRegionZ = Integer.MIN_VALUE;
final Set<Point> regions = new HashSet<>(), exportedRegions = new HashSet<>();
final boolean tileSelection = selectedTiles != null;
if (tileSelection) {
// Sanity check
assert selectedDimensions.size() == 1;
assert selectedDimensions.contains(dimension.getDim());
for (Point tile : selectedTiles) {
int regionX = tile.x >> 2;
int regionZ = tile.y >> 2;
regions.add(new Point(regionX, regionZ));
if (regionX < lowestRegionX) {
lowestRegionX = regionX;
}
if (regionX > highestRegionX) {
highestRegionX = regionX;
}
if (regionZ < lowestRegionZ) {
lowestRegionZ = regionZ;
}
if (regionZ > highestRegionZ) {
highestRegionZ = regionZ;
}
}
} else {
for (Tile tile : dimension.getTiles()) {
// Also add regions for any bedrock wall and/or border
// tiles, if present
int r = (((dimension.getBorder() != null) && (!dimension.getBorder().isEndless())) ? dimension.getBorderSize() : 0) + (((dimension.getBorder() == null) || (!dimension.getBorder().isEndless())) && dimension.isBedrockWall() ? 1 : 0);
for (int dx = -r; dx <= r; dx++) {
for (int dy = -r; dy <= r; dy++) {
int regionX = (tile.getX() + dx) >> 2;
int regionZ = (tile.getY() + dy) >> 2;
regions.add(new Point(regionX, regionZ));
if (regionX < lowestRegionX) {
lowestRegionX = regionX;
}
if (regionX > highestRegionX) {
highestRegionX = regionX;
}
if (regionZ < lowestRegionZ) {
lowestRegionZ = regionZ;
}
if (regionZ > highestRegionZ) {
highestRegionZ = regionZ;
}
}
}
}
if (ceiling != null) {
for (Tile tile : ceiling.getTiles()) {
int regionX = tile.getX() >> 2;
int regionZ = tile.getY() >> 2;
regions.add(new Point(regionX, regionZ));
if (regionX < lowestRegionX) {
lowestRegionX = regionX;
}
if (regionX > highestRegionX) {
highestRegionX = regionX;
}
if (regionZ < lowestRegionZ) {
lowestRegionZ = regionZ;
}
if (regionZ > highestRegionZ) {
highestRegionZ = regionZ;
}
}
}
}
// Sort the regions to export the first two rows together, and then
// row by row, to get the optimum tempo of performing fixups
java.util.List<Point> sortedRegions = new ArrayList<>(regions.size());
if (lowestRegionZ == highestRegionZ) {
// No point in sorting it
sortedRegions.addAll(regions);
} else {
for (int x = lowestRegionX; x <= highestRegionX; x++) {
for (int z = lowestRegionZ; z <= (lowestRegionZ + 1); z++) {
Point regionCoords = new Point(x, z);
if (regions.contains(regionCoords)) {
sortedRegions.add(regionCoords);
}
}
}
for (int z = lowestRegionZ + 2; z <= highestRegionZ; z++) {
for (int x = lowestRegionX; x <= highestRegionX; x++) {
Point regionCoords = new Point(x, z);
if (regions.contains(regionCoords)) {
sortedRegions.add(regionCoords);
}
}
}
}
final WorldPainterChunkFactory chunkFactory = new WorldPainterChunkFactory(dimension, exporters, platform, world.getMaxHeight());
final WorldPainterChunkFactory ceilingChunkFactory = (ceiling != null) ? new WorldPainterChunkFactory(ceiling, ceilingExporters, platform, world.getMaxHeight()) : null;
Runtime runtime = Runtime.getRuntime();
runtime.gc();
long totalMemory = runtime.totalMemory();
long freeMemory = runtime.freeMemory();
long memoryInUse = totalMemory - freeMemory;
long maxMemory = runtime.maxMemory();
long maxMemoryAvailable = maxMemory - memoryInUse;
int maxThreadsByMem = (int) (maxMemoryAvailable / 250000000L);
int threads;
if (System.getProperty("org.pepsoft.worldpainter.threads") != null) {
threads = Math.max(Math.min(Integer.parseInt(System.getProperty("org.pepsoft.worldpainter.threads")), sortedRegions.size()), 1);
} else {
threads = Math.max(Math.min(Math.min(maxThreadsByMem, runtime.availableProcessors()), sortedRegions.size()), 1);
}
logger.info("Using " + threads + " thread(s) for export (cores: " + runtime.availableProcessors() + ", available memory: " + (maxMemoryAvailable / 1048576L) + " MB)");
final Map<Point, List<Fixup>> fixups = new HashMap<>();
ExecutorService executor = Executors.newFixedThreadPool(threads, new ThreadFactory() {
@Override
public synchronized Thread newThread(Runnable r) {
Thread thread = new Thread(threadGroup, r, "Exporter-" + nextID++);
thread.setPriority(Thread.MIN_PRIORITY);
return thread;
}
private final ThreadGroup threadGroup = new ThreadGroup("Exporters");
private int nextID = 1;
});
final ParallelProgressManager parallelProgressManager = (progressReceiver != null) ? new ParallelProgressManager(progressReceiver, regions.size()) : null;
try {
// Export each individual region
for (Point region : sortedRegions) {
final Point regionCoords = region;
executor.execute(() -> {
ProgressReceiver progressReceiver1 = (parallelProgressManager != null) ? parallelProgressManager.createProgressReceiver() : null;
if (progressReceiver1 != null) {
try {
progressReceiver1.checkForCancellation();
} catch (OperationCancelled e) {
return;
}
}
try {
WorldRegion worldRegion = new WorldRegion(regionCoords.x, regionCoords.y, dimension.getMaxHeight(), platform);
ExportResults exportResults = null;
try {
exportResults = exportRegion(worldRegion, dimension, ceiling, platform, regionCoords, tileSelection, exporters, ceilingExporters, chunkFactory, ceilingChunkFactory, (progressReceiver1 != null) ? new SubProgressReceiver(progressReceiver1, 0.0f, 0.9f) : null);
if (logger.isDebugEnabled()) {
logger.debug("Generated region " + regionCoords.x + "," + regionCoords.y);
}
if (exportResults.chunksGenerated) {
synchronized (collectedStats) {
collectedStats.landArea += exportResults.stats.landArea;
collectedStats.surfaceArea += exportResults.stats.surfaceArea;
collectedStats.waterArea += exportResults.stats.waterArea;
}
}
} finally {
if ((exportResults != null) && exportResults.chunksGenerated) {
long saveStart = System.currentTimeMillis();
worldRegion.save(worldDir, dimension.getDim());
if (logger.isDebugEnabled()) {
logger.debug("Saving region took {} ms", System.currentTimeMillis() - saveStart);
}
}
}
synchronized (fixups) {
if ((exportResults.fixups != null) && (!exportResults.fixups.isEmpty())) {
fixups.put(new Point(regionCoords.x, regionCoords.y), exportResults.fixups);
}
exportedRegions.add(regionCoords);
}
// thread is not already doing it
if (performingFixups.tryAcquire()) {
try {
Map<Point, List<Fixup>> myFixups = new HashMap<>();
synchronized (fixups) {
for (Iterator<Map.Entry<Point, List<Fixup>>> i = fixups.entrySet().iterator(); i.hasNext(); ) {
Map.Entry<Point, List<Fixup>> entry = i.next();
Point fixupRegionCoords = entry.getKey();
if (isReadyForFixups(regions, exportedRegions, fixupRegionCoords)) {
myFixups.put(fixupRegionCoords, entry.getValue());
i.remove();
}
}
}
if (!myFixups.isEmpty()) {
performFixups(worldDir, dimension, platform, (progressReceiver1 != null) ? new SubProgressReceiver(progressReceiver1, 0.9f, 0.1f) : null, myFixups);
}
} finally {
performingFixups.release();
}
}
} catch (Throwable t) {
if (progressReceiver1 != null) {
progressReceiver1.exceptionThrown(t);
} else {
logger.error("Exception while exporting region", t);
}
}
});
}
} finally {
executor.shutdown();
try {
executor.awaitTermination(366, TimeUnit.DAYS);
} catch (InterruptedException e) {
throw new RuntimeException("Thread interrupted while waiting for all tasks to finish", e);
}
}
// performing fixups and thread B added new ones and then quit
synchronized (fixups) {
if (!fixups.isEmpty()) {
if (progressReceiver != null) {
progressReceiver.setMessage("Doing remaining fixups for " + dimension.getName());
progressReceiver.reset();
}
performFixups(worldDir, dimension, platform, progressReceiver, fixups);
}
}
// Calculate total size of dimension
collectedStats.time = System.currentTimeMillis() - start;
if (progressReceiver != null) {
progressReceiver.setProgress(1.0f);
}
} finally {
// Undo any changes we made (such as applying any combined layers)
if (dimension.undoChanges()) {
// TODO: some kind of cleverer undo mechanism (undo history
// cloning?) so we don't mess up the user's redo history
dimension.clearRedo();
dimension.armSavePoint();
}
// If the dimension wasn't dirty make sure it still isn't
dimension.setDirty(wasDirty);
if (ceiling != null) {
// Undo any changes we made (such as applying any combined layers)
if (ceiling.undoChanges()) {
// TODO: some kind of cleverer undo mechanism (undo history
// cloning?) so we don't mess up the user's redo history
ceiling.clearRedo();
ceiling.armSavePoint();
}
// If the dimension wasn't dirty make sure it still isn't
ceiling.setDirty(ceilingWasDirty);
}
}
return collectedStats;
}
use of org.pepsoft.util.ProgressReceiver.OperationCancelled in project WorldPainter by Captain-Chaos.
the class App method newWorld.
private void newWorld() {
if (!saveIfNecessary()) {
return;
}
Configuration config = Configuration.getInstance();
final NewWorldDialog dialog = new NewWorldDialog(this, strings.getString("generated.world"), World2.DEFAULT_OCEAN_SEED, config.getDefaultPlatform(), DIM_NORMAL, config.getDefaultMaxHeight());
dialog.setVisible(true);
if (!dialog.isCancelled()) {
// Free up memory of the world and the undo buffer
setWorld(null);
if (!dialog.checkMemoryRequirements(this)) {
return;
}
World2 newWorld = ProgressDialog.executeTask(this, new ProgressTask<World2>() {
@Override
public String getName() {
return strings.getString("creating.new.world");
}
@Override
public World2 execute(ProgressReceiver progressReceiver) throws OperationCancelled {
return dialog.getSelectedWorld(progressReceiver);
}
});
if (newWorld == null) {
// Operation cancelled by user
return;
}
// Log an event
EventVO event = new EventVO(EVENT_KEY_ACTION_NEW_WORLD).addTimestamp();
event.setAttribute(ATTRIBUTE_KEY_MAX_HEIGHT, newWorld.getMaxHeight());
event.setAttribute(ATTRIBUTE_KEY_TILES, newWorld.getDimension(0).getTiles().size());
config.logEvent(event);
setWorld(newWorld);
lastSelectedFile = null;
disableImportedWorldOperation();
}
}
use of org.pepsoft.util.ProgressReceiver.OperationCancelled in project WorldPainter by Captain-Chaos.
the class App method open.
public void open(final File file) {
logger.info("Loading world " + file.getAbsolutePath());
// Free up memory of the world and the undo buffer
setWorld(null);
final World2 newWorld = ProgressDialog.executeTask(this, new ProgressTask<World2>() {
@Override
public String getName() {
return strings.getString("loading.world");
}
@Override
public World2 execute(ProgressReceiver progressReceiver) throws OperationCancelled {
try {
WorldIO worldIO = new WorldIO();
worldIO.load(new FileInputStream(file));
World2 world = worldIO.getWorld();
world.addHistoryEntry(HistoryEntry.WORLD_LOADED, file);
if (logger.isDebugEnabled() && (world.getMetadata() != null)) {
logMetadataAsDebug(world.getMetadata());
}
return world;
} catch (UnloadableWorldException e) {
logger.error("Could not load world from file " + file, e);
if (e.getMetadata() != null) {
logMetadataAsError(e.getMetadata());
}
reportUnloadableWorldException(e);
return null;
} catch (IOException e) {
throw new RuntimeException("I/O error while loading world", e);
}
}
private void appendMetadata(StringBuilder sb, Map<String, Object> metadata) {
for (Map.Entry<String, Object> entry : metadata.entrySet()) {
switch(entry.getKey()) {
case World2.METADATA_KEY_WP_VERSION:
sb.append("Saved with WorldPainter ").append(entry.getValue());
String build = (String) metadata.get(World2.METADATA_KEY_WP_BUILD);
if (build != null) {
sb.append(" (").append(build).append(')');
}
sb.append('\n');
break;
case World2.METADATA_KEY_TIMESTAMP:
sb.append("Saved on ").append(SimpleDateFormat.getDateTimeInstance().format((Date) entry.getValue())).append('\n');
break;
case World2.METADATA_KEY_PLUGINS:
String[][] plugins = (String[][]) entry.getValue();
for (String[] plugin : plugins) {
sb.append("Plugin: ").append(plugin[0]).append(" (").append(plugin[1]).append(")\n");
}
break;
}
}
}
private void logMetadataAsDebug(Map<String, Object> metadata) {
StringBuilder sb = new StringBuilder("Metadata from world file:\n");
appendMetadata(sb, metadata);
logger.debug(sb.toString());
}
private void logMetadataAsError(Map<String, Object> metadata) {
StringBuilder sb = new StringBuilder("Metadata from world file:\n");
appendMetadata(sb, metadata);
logger.error(sb.toString());
}
private void reportUnloadableWorldException(UnloadableWorldException e) {
try {
String text;
if (e.getMetadata() != null) {
StringBuilder sb = new StringBuilder("WorldPainter could not load the file. The cause may be one of:\n" + "\n" + "* The file is damaged or corrupted\n" + "* The file was created with a newer version of WorldPainter\n" + "* The file was created using WorldPainter plugins which you do not have\n" + "\n");
appendMetadata(sb, e.getMetadata());
text = sb.toString();
} else {
text = "WorldPainter could not load the file. The cause may be one of:\n" + "\n" + "* The file is not a WorldPainter world\n" + "* The file is damaged or corrupted\n" + "* The file was created with a newer version of WorldPainter\n" + "* The file was created using WorldPainter plugins which you do not have";
}
SwingUtilities.invokeAndWait(() -> showMessageDialog(App.this, text, strings.getString("file.damaged"), ERROR_MESSAGE));
} catch (InterruptedException e2) {
throw new RuntimeException("Thread interrupted while reporting unloadable file " + file, e2);
} catch (InvocationTargetException e2) {
throw new RuntimeException("Invocation target exception while reporting unloadable file " + file, e2);
}
}
}, false);
if (newWorld == null) {
// The file was damaged
return;
}
if (!isBackupFile(file)) {
lastSelectedFile = file;
} else {
lastSelectedFile = null;
}
// Log an event
Configuration config = Configuration.getInstance();
EventVO event = new EventVO(EVENT_KEY_ACTION_OPEN_WORLD).addTimestamp();
event.setAttribute(ATTRIBUTE_KEY_MAX_HEIGHT, newWorld.getMaxHeight());
Dimension loadedDimension = newWorld.getDimension(0);
event.setAttribute(ATTRIBUTE_KEY_TILES, loadedDimension.getTiles().size());
logLayers(loadedDimension, event, "");
loadedDimension = newWorld.getDimension(1);
if (loadedDimension != null) {
event.setAttribute(ATTRIBUTE_KEY_NETHER_TILES, loadedDimension.getTiles().size());
logLayers(loadedDimension, event, "nether.");
}
loadedDimension = newWorld.getDimension(2);
if (loadedDimension != null) {
event.setAttribute(ATTRIBUTE_KEY_END_TILES, loadedDimension.getTiles().size());
logLayers(loadedDimension, event, "end.");
}
if (newWorld.getImportedFrom() != null) {
event.setAttribute(ATTRIBUTE_KEY_IMPORTED_WORLD, true);
}
config.logEvent(event);
Set<World2.Warning> warnings = newWorld.getWarnings();
if ((warnings != null) && (!warnings.isEmpty())) {
for (World2.Warning warning : warnings) {
switch(warning) {
case AUTO_BIOMES_DISABLED:
if (showOptionDialog(this, "Automatic Biomes were previously enabled for this world but have been disabled.\nPress More Info for more information, including how to reenable it.", "Automatic Biomes Disabled", DEFAULT_OPTION, WARNING_MESSAGE, null, new Object[] { "More Info", "OK" }, "OK") == 0) {
try {
DesktopUtils.open(new URL("https://www.worldpainter.net/doc/legacy/newautomaticbiomes"));
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
break;
case AUTO_BIOMES_ENABLED:
if (showOptionDialog(this, "Automatic Biomes were previously disabled for this world but have been enabled.\nPress More Info for more information, including how to disable it.", "Automatic Biomes Enabled", DEFAULT_OPTION, WARNING_MESSAGE, null, new Object[] { "More Info", "OK" }, "OK") == 0) {
try {
DesktopUtils.open(new URL("https://www.worldpainter.net/doc/legacy/newautomaticbiomes"));
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
break;
}
}
}
if (newWorld.isAskToConvertToAnvil() && (newWorld.getMaxHeight() == DEFAULT_MAX_HEIGHT_1) && (newWorld.getImportedFrom() == null)) {
if (showConfirmDialog(this, strings.getString("this.world.is.128.blocks.high"), strings.getString("convert.world.height"), YES_NO_OPTION) == YES_OPTION) {
ChangeHeightDialog.resizeWorld(newWorld, HeightTransform.IDENTITY, DEFAULT_MAX_HEIGHT_2, this);
newWorld.addHistoryEntry(HistoryEntry.WORLD_MAX_HEIGHT_CHANGED, DEFAULT_MAX_HEIGHT_2);
// with the old format
if (newWorld.getPlatform() != null) {
newWorld.setPlatform(DefaultPlugin.JAVA_ANVIL);
}
// Log event
config.logEvent(new EventVO(EVENT_KEY_ACTION_MIGRATE_HEIGHT).addTimestamp());
}
// Don't ask again, no matter what the user answered
newWorld.setAskToConvertToAnvil(false);
}
if (newWorld.isAskToRotate() && (newWorld.getUpIs() == Direction.WEST) && (newWorld.getImportedFrom() == null)) {
if (showConfirmDialog(this, strings.getString("this.world.was.created.when.north.was.to.the.right"), strings.getString("rotate.world"), YES_NO_OPTION) == YES_OPTION) {
ProgressDialog.executeTask(this, new ProgressTask<java.lang.Void>() {
@Override
public String getName() {
return strings.getString("rotating.world");
}
@Override
public java.lang.Void execute(ProgressReceiver progressReceiver) throws OperationCancelled {
newWorld.transform(CoordinateTransform.ROTATE_CLOCKWISE_270_DEGREES, progressReceiver);
for (Dimension dimension : newWorld.getDimensions()) {
newWorld.addHistoryEntry(HistoryEntry.WORLD_DIMENSION_ROTATED, dimension.getName(), 270);
}
return null;
}
}, false);
// Log event
config.logEvent(new EventVO(EVENT_KEY_ACTION_MIGRATE_ROTATION).addTimestamp());
}
// Don't ask again, no matter what the user answered
newWorld.setAskToRotate(false);
}
// Make sure the world name is always the same as the file name, to
// avoid confusion, unless the only difference is illegal filename
// characters changed into underscores. Do this here as well as when
// saving, because the file might have been renamed
String name = isBackupFile(file) ? getOriginalFile(file).getName() : file.getName();
int p = name.lastIndexOf('.');
if (p != -1) {
name = name.substring(0, p);
}
String worldName = newWorld.getName();
if (worldName.length() != name.length()) {
newWorld.setName(name);
} else {
for (int i = 0; i < name.length(); i++) {
if ((name.charAt(i) != '_') && (name.charAt(i) != worldName.charAt(i))) {
newWorld.setName(name);
break;
}
}
}
newWorld.setDirty(false);
setWorld(newWorld);
addRecentlyUsedWorld(file);
if (newWorld.getImportedFrom() != null) {
enableImportedWorldOperation();
} else {
disableImportedWorldOperation();
}
}
use of org.pepsoft.util.ProgressReceiver.OperationCancelled in project WorldPainter by Captain-Chaos.
the class App method importCustomItemsFromWorld.
private void importCustomItemsFromWorld(CustomItemsTreeModel.ItemType itemType) {
File dir;
Configuration config = Configuration.getInstance();
if (lastSelectedFile != null) {
dir = lastSelectedFile.getParentFile();
} else if ((config != null) && (config.getWorldDirectory() != null)) {
dir = config.getWorldDirectory();
} else {
dir = DesktopUtils.getDocumentsFolder();
}
File selectedFile = FileUtils.selectFileForOpen(this, "Select a WorldPainter world", dir, new FileFilter() {
@Override
public boolean accept(File f) {
return f.isDirectory() || f.getName().toLowerCase().endsWith(".world");
}
@Override
public String getDescription() {
return strings.getString("worldpainter.files.world");
}
});
if (selectedFile != null) {
if (!selectedFile.isFile()) {
if (logger.isDebugEnabled()) {
try {
logger.debug("Path not a file according to File.isFile(): \"" + selectedFile + "\" (directory: " + selectedFile.isDirectory() + "; length: " + selectedFile.length() + "; absolutePath: \"" + selectedFile.getAbsolutePath() + "\"; canonicalPath: \"" + selectedFile.getCanonicalPath() + "\")");
} catch (IOException e) {
logger.debug("Path not a file according to File.isFile(): \"" + selectedFile + "\" (directory: " + selectedFile.isDirectory() + "; length: " + selectedFile.length() + "; absolutePath: \"" + selectedFile.getAbsolutePath() + "\")");
logger.warn("I/O error while trying to report canonical path of file: \"" + selectedFile + "\"", e);
}
}
showMessageDialog(this, "The specified path does not exist or is not a file", "File Does Not Exist", ERROR_MESSAGE);
return;
}
if (!selectedFile.canRead()) {
showMessageDialog(this, "WorldPainter is not authorised to read the selected file", "Access Denied", ERROR_MESSAGE);
return;
}
final World2 selectedWorld = ProgressDialog.executeTask(this, new ProgressTask<World2>() {
@Override
public String getName() {
return strings.getString("loading.world");
}
@Override
public World2 execute(ProgressReceiver progressReceiver) throws OperationCancelled {
try {
WorldIO worldIO = new WorldIO();
worldIO.load(new FileInputStream(selectedFile));
World2 world = worldIO.getWorld();
return world;
} catch (UnloadableWorldException e) {
logger.error("Could not load world from file " + selectedFile, e);
if (e.getMetadata() != null) {
logMetadataAsError(e.getMetadata());
}
reportUnloadableWorldException(e);
return null;
} catch (IOException e) {
throw new RuntimeException("I/O error while loading world", e);
}
}
private void appendMetadata(StringBuilder sb, Map<String, Object> metadata) {
for (Map.Entry<String, Object> entry : metadata.entrySet()) {
switch(entry.getKey()) {
case World2.METADATA_KEY_WP_VERSION:
sb.append("Saved with WorldPainter ").append(entry.getValue());
String build = (String) metadata.get(World2.METADATA_KEY_WP_BUILD);
if (build != null) {
sb.append(" (").append(build).append(')');
}
sb.append('\n');
break;
case World2.METADATA_KEY_TIMESTAMP:
sb.append("Saved on ").append(SimpleDateFormat.getDateTimeInstance().format((Date) entry.getValue())).append('\n');
break;
case World2.METADATA_KEY_PLUGINS:
String[][] plugins = (String[][]) entry.getValue();
for (String[] plugin : plugins) {
sb.append("Plugin: ").append(plugin[0]).append(" (").append(plugin[1]).append(")\n");
}
break;
}
}
}
private void logMetadataAsError(Map<String, Object> metadata) {
StringBuilder sb = new StringBuilder("Metadata from world file:\n");
appendMetadata(sb, metadata);
logger.error(sb.toString());
}
private void reportUnloadableWorldException(UnloadableWorldException e) {
try {
String text;
if (e.getMetadata() != null) {
StringBuilder sb = new StringBuilder("WorldPainter could not load the file. The cause may be one of:\n" + "\n" + "* The file is damaged or corrupted\n" + "* The file was created with a newer version of WorldPainter\n" + "* The file was created using WorldPainter plugins which you do not have\n" + "\n");
appendMetadata(sb, e.getMetadata());
text = sb.toString();
} else {
text = "WorldPainter could not load the file. The cause may be one of:\n" + "\n" + "* The file is not a WorldPainter world\n" + "* The file is damaged or corrupted\n" + "* The file was created with a newer version of WorldPainter\n" + "* The file was created using WorldPainter plugins which you do not have";
}
SwingUtilities.invokeAndWait(() -> showMessageDialog(App.this, text, strings.getString("file.damaged"), ERROR_MESSAGE));
} catch (InterruptedException e2) {
throw new RuntimeException("Thread interrupted while reporting unloadable file " + selectedFile, e2);
} catch (InvocationTargetException e2) {
throw new RuntimeException("Invocation target exception while reporting unloadable file " + selectedFile, e2);
}
}
}, false);
if (selectedWorld == null) {
// The file was damaged
return;
}
if (CustomItemsTreeModel.hasCustomItems(selectedWorld, itemType)) {
ImportCustomItemsDialog dialog = new ImportCustomItemsDialog(this, selectedWorld, selectedColourScheme, itemType);
dialog.setVisible(true);
if (!dialog.isCancelled()) {
StringBuilder errors = new StringBuilder();
Set<CustomLayer> existingCustomLayers = null;
boolean refreshView = false, showError = false;
for (Object selectedItem : dialog.getSelectedItems()) {
if (selectedItem instanceof CustomLayer) {
if (existingCustomLayers == null) {
existingCustomLayers = getCustomLayers();
}
if (existingCustomLayers.contains(selectedItem)) {
errors.append("Custom Layer \"" + ((CustomLayer) selectedItem).getName() + "\" already exists\n");
} else {
registerCustomLayer((CustomLayer) selectedItem, false);
}
} else if (selectedItem instanceof MixedMaterial) {
MixedMaterial customMaterial = (MixedMaterial) selectedItem;
int index = findNextCustomTerrainIndex();
if (index == -1) {
errors.append("No free slots for Custom Terrain \"" + customMaterial.getName() + "\"\n");
showError = true;
continue;
}
customMaterial = MixedMaterialManager.getInstance().register(customMaterial);
addButtonForNewCustomTerrain(index, customMaterial, false);
} else if (selectedItem instanceof CustomBiome) {
CustomBiome customBiome = (CustomBiome) selectedItem;
if (!customBiomeManager.addCustomBiome(null, customBiome)) {
errors.append("ID already in use for Custom Biome " + customBiome.getId() + " (\"" + customBiome + "\")\n");
showError = true;
} else {
refreshView = true;
}
} else {
throw new InternalError("Unsupported custom item type " + selectedItem.getClass() + " encountered");
}
}
if (refreshView) {
view.refreshTiles();
}
if (errors.length() > 0) {
JOptionPane.showMessageDialog(App.this, "Not all items have been imported:\n\n" + errors, "Not All Items Imported", showError ? JOptionPane.ERROR_MESSAGE : JOptionPane.WARNING_MESSAGE);
}
}
} else {
String what;
switch(itemType) {
case ALL:
what = "layers, terrains or biomes";
break;
case BIOME:
what = "biomes";
break;
case LAYER:
what = "layers";
break;
case TERRAIN:
what = "terrains";
break;
default:
throw new InternalError();
}
showMessageDialog(this, "The selected world has no custom " + what + ".", "No Custom Items", WARNING_MESSAGE);
}
}
}
use of org.pepsoft.util.ProgressReceiver.OperationCancelled in project WorldPainter by Captain-Chaos.
the class App method save.
/**
* Save the world to the specified file, overwriting it if it already exists
* without asking for confirmation. Shows a progress indicator while saving.
*
* @param file The file to which to save the world.
*/
private boolean save(File file) {
// Check for write access to directory
if (!file.getParentFile().isDirectory()) {
showMessageDialog(this, strings.getString("the.selected.path.does.not.exist"), strings.getString("non.existant.path"), ERROR_MESSAGE);
return false;
}
if (!file.getParentFile().canWrite()) {
showMessageDialog(this, strings.getString("you.do.not.have.write.access"), strings.getString("access.denied"), ERROR_MESSAGE);
return false;
}
// Normalise the filename
String name = file.getName();
name = name.trim();
if (name.isEmpty()) {
// NOI18N
name = strings.getString("generated.world") + ".world";
} else {
name = FileUtils.sanitiseName(name);
}
final File normalisedFile = new File(file.getParentFile(), name);
// Make sure the world name is always the same as the file name, to
// avoid confusion (unless the only difference is illegal filename
// characters changed into underscores
int p = name.lastIndexOf('.');
if (p != -1) {
name = name.substring(0, p).trim();
}
String worldName = world.getName();
if (worldName.length() != name.length()) {
world.setName(name);
// NOI18N
setTitle("WorldPainter - " + name + " - " + dimension.getName());
} else {
for (int i = 0; i < name.length(); i++) {
if ((name.charAt(i) != '_') && (name.charAt(i) != worldName.charAt(i))) {
world.setName(name);
// NOI18N
setTitle("WorldPainter - " + name + " - " + dimension.getName());
break;
}
}
}
logger.info("Saving world " + world.getName() + " to " + file.getAbsolutePath());
saveCustomMaterials();
saveCustomBiomes();
// currently in use
if (!paletteManager.isEmpty()) {
List<CustomLayer> customLayers = new ArrayList<>();
for (Palette palette : paletteManager.getPalettes()) {
customLayers.addAll(palette.getLayers());
}
dimension.setCustomLayers(customLayers);
} else {
dimension.setCustomLayers(Collections.EMPTY_LIST);
}
if (dimension != null) {
Point viewPosition = view.getViewCentreInWorldCoords();
if (viewPosition != null) {
this.dimension.setLastViewPosition(viewPosition);
}
}
ProgressDialog.executeTask(this, new ProgressTask<java.lang.Void>() {
@Override
public String getName() {
return strings.getString("saving.world");
}
@Override
public java.lang.Void execute(ProgressReceiver progressReceiver) throws OperationCancelled {
try {
Configuration config = Configuration.getInstance();
if ((config.getWorldFileBackups() > 0) && normalisedFile.isFile()) {
progressReceiver.setMessage(strings.getString("creating.backup.s"));
for (int i = config.getWorldFileBackups(); i > 0; i--) {
File nextBackupFile = (i > 1) ? BackupUtil.getBackupFile(normalisedFile, i - 1) : normalisedFile;
if (nextBackupFile.isFile()) {
File backupFile = BackupUtil.getBackupFile(normalisedFile, i);
if (backupFile.isFile()) {
if (!backupFile.delete()) {
throw new RuntimeException("Could not delete old backup file " + backupFile);
}
}
if (!nextBackupFile.renameTo(backupFile)) {
throw new RuntimeException("Could not move " + nextBackupFile + " to " + backupFile);
}
}
}
progressReceiver.setMessage(null);
}
world.addHistoryEntry(HistoryEntry.WORLD_SAVED, normalisedFile);
WorldIO worldIO = new WorldIO(world);
worldIO.save(new FileOutputStream(normalisedFile));
Map<String, byte[]> layoutData = config.getJideLayoutData();
if (layoutData == null) {
layoutData = new HashMap<>();
}
layoutData.put(world.getName(), dockingManager.getLayoutRawData());
config.setJideLayoutData(layoutData);
return null;
} catch (IOException e) {
throw new RuntimeException("I/O error saving file (message: " + e.getMessage() + ")", e);
}
}
}, false);
// Log an event
Configuration config = Configuration.getInstance();
if (config != null) {
EventVO event = new EventVO(EVENT_KEY_ACTION_SAVE_WORLD).addTimestamp();
event.setAttribute(ATTRIBUTE_KEY_MAX_HEIGHT, world.getMaxHeight());
Dimension loadedDimension = world.getDimension(0);
event.setAttribute(ATTRIBUTE_KEY_TILES, loadedDimension.getTiles().size());
logLayers(loadedDimension, event, "");
loadedDimension = world.getDimension(1);
if (loadedDimension != null) {
event.setAttribute(ATTRIBUTE_KEY_NETHER_TILES, loadedDimension.getTiles().size());
logLayers(loadedDimension, event, "nether.");
}
loadedDimension = world.getDimension(2);
if (loadedDimension != null) {
event.setAttribute(ATTRIBUTE_KEY_END_TILES, loadedDimension.getTiles().size());
logLayers(loadedDimension, event, "end.");
}
if (world.getImportedFrom() != null) {
event.setAttribute(ATTRIBUTE_KEY_IMPORTED_WORLD, true);
}
config.logEvent(event);
}
if (currentUndoManager != null) {
currentUndoManager.armSavePoint();
}
world.setDirty(false);
lastSelectedFile = file;
addRecentlyUsedWorld(file);
Configuration.getInstance().setWorldDirectory(file.getParentFile());
return true;
}
Aggregations