package org.pepsoft.worldpainter; import org.pepsoft.minecraft.Direction; import org.pepsoft.util.PluginManager; import org.pepsoft.util.WPCustomObjectInputStream; import org.pepsoft.worldpainter.history.HistoryEntry; import org.pepsoft.worldpainter.layers.Layer; import org.pepsoft.worldpainter.layers.Resources; import org.pepsoft.worldpainter.layers.exporters.ExporterSettings; import org.pepsoft.worldpainter.layers.exporters.ResourcesExporter; import org.pepsoft.worldpainter.objects.AbstractObject; import org.pepsoft.worldpainter.plugins.Plugin; import org.pepsoft.worldpainter.plugins.WPPluginManager; import org.pepsoft.worldpainter.vo.EventVO; import java.io.*; import java.util.*; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import java.util.zip.ZipException; import static org.pepsoft.minecraft.Constants.*; /** * Created by Pepijn Schmitz on 02-07-15. */ public class WorldIO { public WorldIO() { // Do nothing } public WorldIO(World2 world) { this.world = world; } public World2 getWorld() { return world; } public void setWorld(World2 world) { this.world = world; } /** * Save the world to a binary stream, such that it can later be loaded using * {@link #load(InputStream)}. The stream is closed before returning. * * @param out The stream to which to save the world. * @throws IOException If an I/O error occurred saving the world. */ public void save(OutputStream out) throws IOException { try (ObjectOutputStream wrappedOut = new ObjectOutputStream(new GZIPOutputStream(out))) { Map<String, Object> metadata = new HashMap<>(); metadata.put(World2.METADATA_KEY_WP_VERSION, Version.VERSION); metadata.put(World2.METADATA_KEY_WP_BUILD, Version.BUILD); metadata.put(World2.METADATA_KEY_TIMESTAMP, new Date()); if (WPPluginManager.getInstance() != null) { List<String[]> pluginArray = new ArrayList<>(); for (Plugin plugin : WPPluginManager.getInstance().getAllPlugins()) { if (plugin.getName().equals("Default") || plugin.getName().equals("DefaultLayerEditorProvider")) { // Don't include the system plugins continue; } pluginArray.add(new String[]{plugin.getName(), plugin.getVersion()}); } if (! pluginArray.isEmpty()) { metadata.put(World2.METADATA_KEY_PLUGINS, pluginArray.toArray(new String[pluginArray.size()][])); } } wrappedOut.writeObject(metadata); wrappedOut.writeObject(world); } } /** * Load a world from a binary stream to which it was previously saved by * {@link #save(OutputStream)}, or by a previous version of WorldPainter. * The stream is closed before returning. * * @param in The stream from which to load the world. * @throws IOException If an I/O error occurred loading the world. * @throws UnloadableWorldException If some other error occurred loading the * world. If metadata was present and could be loaded it will be stored * in the exception. */ @SuppressWarnings("unchecked") // Guaranteed by WorldPainter public void load(InputStream in) throws IOException, UnloadableWorldException { Map<String, Object> metadata = null; world = null; try { try (WPCustomObjectInputStream wrappedIn = new WPCustomObjectInputStream(new GZIPInputStream(in), PluginManager.getPluginClassLoader(), AbstractObject.class)) { Object object = wrappedIn.readObject(); if (object instanceof Map) { metadata = (Map<String, Object>) object; object = wrappedIn.readObject(); } if (object instanceof World2) { world = (World2) object; } else if (object instanceof World) { world = migrate(object); } else { throw new UnloadableWorldException("Object of unexpected type " + object.getClass() + " encountered", metadata); } } } catch (ZipException e) { throw new UnloadableWorldException("ZipException while loading world", e, metadata); } catch (StreamCorruptedException e) { throw new UnloadableWorldException("StreamCorruptedException while loading world", e, metadata); } catch (EOFException e) { throw new UnloadableWorldException("EOFException while loading world", e, metadata); } catch (InvalidClassException e) { throw new UnloadableWorldException("InvalidClassException while loading world", e, metadata); } catch (IOException e) { if (e.getMessage().equals("Not in GZIP format")) { throw new UnloadableWorldException("Not in GZIP format", e, metadata); } else { throw e; } } catch (ClassNotFoundException e) { throw new UnloadableWorldException("ClassNotFoundException while loading world", e, metadata); } catch (IllegalArgumentException e) { throw new UnloadableWorldException("IllegalArgumentException while loading world", e, metadata); } if (metadata != null) { world.setMetadata(metadata); } } private World2 migrate(Object object) { if (object instanceof World) { World oldWorld = (World) object; World2 newWorld = new World2(oldWorld.getMinecraftSeed(), oldWorld.getTileFactory(), 128); newWorld.setCreateGoodiesChest(oldWorld.isCreateGoodiesChest()); newWorld.setImportedFrom(oldWorld.getImportedFrom()); newWorld.setName(oldWorld.getName()); newWorld.setSpawnPoint(oldWorld.getSpawnPoint()); Dimension dim0 = newWorld.getDimension(0); Generator generator = Generator.DEFAULT; TileFactory tileFactory = dim0.getTileFactory(); if ((tileFactory instanceof HeightMapTileFactory) && (((HeightMapTileFactory) tileFactory).getWaterHeight() < 32) && (((HeightMapTileFactory) tileFactory).getBaseHeight() < 32)) { // Low level generator = Generator.FLAT; } newWorld.setGenerator(generator); newWorld.setAskToConvertToAnvil(true); newWorld.setUpIs(Direction.WEST); newWorld.setAskToRotate(true); newWorld.setAllowMerging(false); dim0.setEventsInhibited(true); try { dim0.setBedrockWall(oldWorld.isBedrockWall()); dim0.setBorder((oldWorld.getBorder() != null) ? Dimension.Border.valueOf(oldWorld.getBorder().name()) : null); dim0.setDarkLevel(oldWorld.isDarkLevel()); for (Map.Entry<Layer, ExporterSettings> entry: oldWorld.getAllLayerSettings().entrySet()) { dim0.setLayerSettings(entry.getKey(), entry.getValue()); } dim0.setMinecraftSeed(oldWorld.getMinecraftSeed()); dim0.setPopulate(oldWorld.isPopulate()); dim0.setContoursEnabled(false); Terrain subsurfaceMaterial = oldWorld.getSubsurfaceMaterial(); ResourcesExporter.ResourcesExporterSettings resourcesSettings = (ResourcesExporter.ResourcesExporterSettings) dim0.getLayerSettings(Resources.INSTANCE); if (subsurfaceMaterial == Terrain.RESOURCES) { dim0.setSubsurfaceMaterial(Terrain.STONE); } else { dim0.setSubsurfaceMaterial(subsurfaceMaterial); resourcesSettings.setMinimumLevel(0); } // Load legacy settings resourcesSettings.setChance(BLK_GOLD_ORE, 1); resourcesSettings.setChance(BLK_IRON_ORE, 5); resourcesSettings.setChance(BLK_COAL, 9); resourcesSettings.setChance(BLK_LAPIS_LAZULI_ORE, 1); resourcesSettings.setChance(BLK_DIAMOND_ORE, 1); resourcesSettings.setChance(BLK_REDSTONE_ORE, 6); resourcesSettings.setChance(BLK_WATER, 1); resourcesSettings.setChance(BLK_LAVA, 1); resourcesSettings.setChance(BLK_DIRT, 9); resourcesSettings.setChance(BLK_GRAVEL, 9); resourcesSettings.setChance(BLK_EMERALD_ORE, 0); resourcesSettings.setMaxLevel(BLK_GOLD_ORE, Terrain.GOLD_LEVEL); resourcesSettings.setMaxLevel(BLK_IRON_ORE, Terrain.IRON_LEVEL); resourcesSettings.setMaxLevel(BLK_COAL, Terrain.COAL_LEVEL); resourcesSettings.setMaxLevel(BLK_LAPIS_LAZULI_ORE, Terrain.LAPIS_LAZULI_LEVEL); resourcesSettings.setMaxLevel(BLK_DIAMOND_ORE, Terrain.DIAMOND_LEVEL); resourcesSettings.setMaxLevel(BLK_REDSTONE_ORE, Terrain.REDSTONE_LEVEL); resourcesSettings.setMaxLevel(BLK_WATER, Terrain.WATER_LEVEL); resourcesSettings.setMaxLevel(BLK_LAVA, Terrain.LAVA_LEVEL); resourcesSettings.setMaxLevel(BLK_DIRT, Terrain.DIRT_LEVEL); resourcesSettings.setMaxLevel(BLK_GRAVEL, Terrain.GRAVEL_LEVEL); resourcesSettings.setMaxLevel(BLK_EMERALD_ORE, Terrain.GOLD_LEVEL); oldWorld.getTiles().forEach(dim0::addTile); } finally { dim0.setEventsInhibited(false); } newWorld.setDirty(false); // Log event Configuration config = Configuration.getInstance(); if (config != null) { config.logEvent(new EventVO(Constants.EVENT_KEY_ACTION_MIGRATE_WORLD).addTimestamp()); } // Record origin of world in history newWorld.addHistoryEntry(HistoryEntry.WORLD_LEGACY_PRE_0_2); return newWorld; } else { throw new IllegalArgumentException("Don't know how to migrate object of type " + object.getClass()); } } private World2 world; private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(WorldIO.class); }