diff --git a/src/main/java/com/sk89q/worldedit/LocalConfiguration.java b/src/main/java/com/sk89q/worldedit/LocalConfiguration.java index f43608660..c52d3c23e 100644 --- a/src/main/java/com/sk89q/worldedit/LocalConfiguration.java +++ b/src/main/java/com/sk89q/worldedit/LocalConfiguration.java @@ -19,11 +19,11 @@ package com.sk89q.worldedit; +import com.sk89q.worldedit.snapshots.SnapshotRepository; import java.io.File; import java.util.HashSet; import java.util.Set; -import com.sk89q.worldedit.snapshots.SnapshotRepository; /** * Represents WorldEdit's configuration. diff --git a/src/main/java/com/sk89q/worldedit/LocalWorld.java b/src/main/java/com/sk89q/worldedit/LocalWorld.java index 6fcc8c09b..29b1bad29 100644 --- a/src/main/java/com/sk89q/worldedit/LocalWorld.java +++ b/src/main/java/com/sk89q/worldedit/LocalWorld.java @@ -34,6 +34,13 @@ public abstract class LocalWorld { * Random generator. */ protected Random random = new Random(); + + /** + * Get the name of the world. + * + * @return + */ + public abstract String getName(); /** * Set block type. diff --git a/src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java b/src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java index 6b10681e5..3a12469d6 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java +++ b/src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java @@ -86,10 +86,8 @@ public class BukkitConfiguration extends LocalConfiguration { LocalSession.EXPIRATION_GRACE = config.getInt("history.expiration", 10) * 60 * 1000; String snapshotsDir = config.getString("snapshots.directory", ""); - if (!snapshotsDir.trim().equals("")) { + if (!snapshotsDir.isEmpty()){ snapshotRepo = new SnapshotRepository(snapshotsDir); - } else { - snapshotRepo = null; } String type = config.getString("shell-save-type", "").trim(); diff --git a/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index ebb73e6c0..c071a6d95 100644 --- a/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -69,6 +69,15 @@ public class BukkitWorld extends LocalWorld { public World getWorld() { return world; } + + /** + * Get the name of the world + * + * @return + */ + public String getName() { + return world.getName(); + } /** * Set block type. diff --git a/src/main/java/com/sk89q/worldedit/commands/SnapshotCommands.java b/src/main/java/com/sk89q/worldedit/commands/SnapshotCommands.java index 546ce6f8c..54ffd7e2b 100644 --- a/src/main/java/com/sk89q/worldedit/commands/SnapshotCommands.java +++ b/src/main/java/com/sk89q/worldedit/commands/SnapshotCommands.java @@ -15,8 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -*/ - + */ package com.sk89q.worldedit.commands; import java.io.File; @@ -30,6 +29,7 @@ import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.*; +import com.sk89q.worldedit.data.MissingWorldException; import com.sk89q.worldedit.snapshots.InvalidSnapshotException; import com.sk89q.worldedit.snapshots.Snapshot; @@ -39,69 +39,72 @@ import com.sk89q.worldedit.snapshots.Snapshot; * @author sk89q */ public class SnapshotCommands { + private static Logger logger = Logger.getLogger("Minecraft.WorldEdit"); private static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); - - @Command( - aliases = {"list"}, - usage = "[num]", - desc = "List snapshots", - min = 0, - max = 1 - ) + + @Command(aliases = {"list"}, + usage = "[num]", + desc = "List snapshots", + min = 0, + max = 1) @CommandPermissions({"worldedit.snapshots.list"}) public static void list(CommandContext args, WorldEdit we, LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { - - LocalConfiguration config = we.getConfiguration(); - - int num = args.argsLength() > 0 ? - Math.min(40, Math.max(5, args.getInteger(0))) : 5; - if (config.snapshotRepo != null) { - List snapshots = config.snapshotRepo.getSnapshots(true); + LocalConfiguration config = we.getConfiguration(); + + if (config.snapshotRepo == null) { + player.printError("Snapshot/backup restore is not configured."); + return; + } + + try { + List snapshots = config.snapshotRepo.getSnapshots(true, player.getWorld().getName()); if (snapshots.size() > 0) { - for (byte i = 0; i < Math.min(num, snapshots.size()); ++i) { + + int num = args.argsLength() > 0 ? Math.min(40, Math.max(5, args.getInteger(0))) : 5; + + player.print("Snapshots for world: '" + player.getWorld().getName() + "'"); + for (byte i = 0; i < Math.min(num, snapshots.size()); i++) { player.print((i + 1) + ". " + snapshots.get(i).getName()); } player.print("Use /snap use [snapshot] or /snap use latest."); } else { player.printError("No snapshots are available. See console for details."); - + // Okay, let's toss some debugging information! File dir = config.snapshotRepo.getDirectory(); - + try { - logger.info("WorldEdit found no snapshots: looked in: " + - dir.getCanonicalPath()); + logger.info("WorldEdit found no snapshots: looked in: " + + dir.getCanonicalPath()); } catch (IOException e) { logger.info("WorldEdit found no snapshots: looked in " - + "(NON-RESOLVABLE PATH - does it exist?): " + - dir.getPath()); + + "(NON-RESOLVABLE PATH - does it exist?): " + + dir.getPath()); } } - } else { - player.printError("Snapshot/backup restore is not configured."); + } catch (MissingWorldException ex) { + player.printError("No snapshots were found for this world."); } } - - @Command( - aliases = {"use"}, - usage = "", - desc = "Choose a snapshot to use", - min = 1, - max = 1 - ) + + @Command(aliases = {"use"}, + usage = "", + desc = "Choose a snapshot to use", + min = 1, + max = 1) @CommandPermissions({"worldedit.snapshots.restore"}) public static void use(CommandContext args, WorldEdit we, LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { - + LocalConfiguration config = we.getConfiguration(); - + if (config.snapshotRepo == null) { player.printError("Snapshot/backup restore is not configured."); return; @@ -111,13 +114,17 @@ public class SnapshotCommands { // Want the latest snapshot? if (name.equalsIgnoreCase("latest")) { - Snapshot snapshot = config.snapshotRepo.getDefaultSnapshot(); + try { + Snapshot snapshot = config.snapshotRepo.getDefaultSnapshot(player.getWorld().getName()); - if (snapshot != null) { - session.setSnapshot(null); - player.print("Now using newest snapshot."); - } else { - player.printError("No snapshots were found."); + if (snapshot != null) { + session.setSnapshot(null); + player.print("Now using newest snapshot."); + } else { + player.printError("No snapshots were found."); + } + } catch (MissingWorldException ex) { + player.printError("No snapshots were found for this world."); } } else { try { @@ -128,77 +135,80 @@ public class SnapshotCommands { } } } - - @Command( - aliases = {"before"}, - usage = "", - desc = "Choose the nearest snapshot before a date", - min = 1, - max = -1 - ) + + @Command(aliases = {"before"}, + usage = "", + desc = "Choose the nearest snapshot before a date", + min = 1, + max = -1) @CommandPermissions({"worldedit.snapshots.restore"}) public static void before(CommandContext args, WorldEdit we, LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { - + LocalConfiguration config = we.getConfiguration(); - + if (config.snapshotRepo == null) { player.printError("Snapshot/backup restore is not configured."); return; } - + Calendar date = session.detectDate(args.getJoinedStrings(0)); - + if (date == null) { player.printError("Could not detect the date inputted."); } else { - dateFormat.setTimeZone(session.getTimeZone()); - - Snapshot snapshot = config.snapshotRepo.getSnapshotBefore(date); - if (snapshot == null) { - player.printError("Couldn't find a snapshot before " - + dateFormat.format(date.getTime()) + "."); - } else { - session.setSnapshot(snapshot); - player.print("Snapshot set to: " + snapshot.getName()); + try { + Snapshot snapshot = config.snapshotRepo.getSnapshotBefore(date, player.getWorld().getName()); + + if (snapshot == null) { + dateFormat.setTimeZone(session.getTimeZone()); + player.printError("Couldn't find a snapshot before " + + dateFormat.format(date.getTime()) + "."); + } else { + session.setSnapshot(snapshot); + player.print("Snapshot set to: " + snapshot.getName()); + } + } catch (MissingWorldException ex) { + player.printError("No snapshots were found for this world."); } } } - - @Command( - aliases = {"after"}, - usage = "", - desc = "Choose the nearest snapshot after a date", - min = 1, - max = -1 - ) + + @Command(aliases = {"after"}, + usage = "", + desc = "Choose the nearest snapshot after a date", + min = 1, + max = -1) @CommandPermissions({"worldedit.snapshots.restore"}) public static void after(CommandContext args, WorldEdit we, LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { - + LocalConfiguration config = we.getConfiguration(); - + if (config.snapshotRepo == null) { player.printError("Snapshot/backup restore is not configured."); return; } - + Calendar date = session.detectDate(args.getJoinedStrings(0)); - + if (date == null) { player.printError("Could not detect the date inputted."); } else { - dateFormat.setTimeZone(session.getTimeZone()); - - Snapshot snapshot = config.snapshotRepo.getSnapshotAfter(date); - if (snapshot == null) { - player.printError("Couldn't find a snapshot after " - + dateFormat.format(date.getTime()) + "."); - } else { - session.setSnapshot(snapshot); - player.print("Snapshot set to: " + snapshot.getName()); + try { + Snapshot snapshot = config.snapshotRepo.getSnapshotAfter(date, player.getWorld().getName()); + if (snapshot == null) { + dateFormat.setTimeZone(session.getTimeZone()); + player.printError("Couldn't find a snapshot after " + + dateFormat.format(date.getTime()) + "."); + } else { + session.setSnapshot(snapshot); + player.print("Snapshot set to: " + snapshot.getName()); + } + } catch (MissingWorldException ex) { + player.printError("No snapshots were found for this world."); } } } diff --git a/src/main/java/com/sk89q/worldedit/commands/SnapshotUtilCommands.java b/src/main/java/com/sk89q/worldedit/commands/SnapshotUtilCommands.java index f7178bf4a..672e3bd4f 100644 --- a/src/main/java/com/sk89q/worldedit/commands/SnapshotUtilCommands.java +++ b/src/main/java/com/sk89q/worldedit/commands/SnapshotUtilCommands.java @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -*/ + */ package com.sk89q.worldedit.commands; @@ -34,36 +34,34 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.data.ChunkStore; import com.sk89q.worldedit.data.DataException; +import com.sk89q.worldedit.data.MissingWorldException; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.snapshots.InvalidSnapshotException; import com.sk89q.worldedit.snapshots.Snapshot; import com.sk89q.worldedit.snapshots.SnapshotRestore; public class SnapshotUtilCommands { + private static Logger logger = Logger.getLogger("Minecraft.WorldEdit"); - - @Command( - aliases = {"snapshot", "snap"}, - desc = "Snapshot commands" - ) + + @Command(aliases = {"snapshot", "snap"}, + desc = "Snapshot commands") @NestedCommand({SnapshotCommands.class}) public static void snapshot(CommandContext args, WorldEdit we, LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { } - @Command( - aliases = {"restore", "/restore"}, - usage = "[snapshot]", - desc = "Restore the selection from a snapshot", - min = 0, - max = 1 - ) + @Command(aliases = {"restore", "/restore"}, + usage = "[snapshot]", + desc = "Restore the selection from a snapshot", + min = 0, + max = 1) @CommandPermissions({"worldedit.snapshots.restore"}) public static void restore(CommandContext args, WorldEdit we, LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { - + LocalConfiguration config = we.getConfiguration(); if (config.snapshotRepo == null) { @@ -84,32 +82,37 @@ public class SnapshotUtilCommands { } else { snapshot = session.getSnapshot(); } - - ChunkStore chunkStore = null; // No snapshot set? if (snapshot == null) { - snapshot = config.snapshotRepo.getDefaultSnapshot(); + try { + snapshot = config.snapshotRepo.getDefaultSnapshot(player.getWorld().getName()); - if (snapshot == null) { - player.printError("No snapshots were found. See console for details."); - - // Okay, let's toss some debugging information! - File dir = config.snapshotRepo.getDirectory(); - - try { - logger.info("WorldEdit found no snapshots: looked in: " + - dir.getCanonicalPath()); - } catch (IOException e) { - logger.info("WorldEdit found no snapshots: looked in " - + "(NON-RESOLVABLE PATH - does it exist?): " + - dir.getPath()); + if (snapshot == null) { + player.printError("No snapshots were found. See console for details."); + + // Okay, let's toss some debugging information! + File dir = config.snapshotRepo.getDirectory(); + + try { + logger.info("WorldEdit found no snapshots: looked in: " + + dir.getCanonicalPath()); + } catch (IOException e) { + logger.info("WorldEdit found no snapshots: looked in " + + "(NON-RESOLVABLE PATH - does it exist?): " + + dir.getPath()); + } + + return; } - + } catch (MissingWorldException ex) { + player.printError("No snapshots were found for this world."); return; } } + ChunkStore chunkStore = null; + // Load chunk store try { chunkStore = snapshot.getChunkStore(); diff --git a/src/main/java/com/sk89q/worldedit/data/ChunkStore.java b/src/main/java/com/sk89q/worldedit/data/ChunkStore.java index d7c956b72..7ac24f1b0 100644 --- a/src/main/java/com/sk89q/worldedit/data/ChunkStore.java +++ b/src/main/java/com/sk89q/worldedit/data/ChunkStore.java @@ -50,7 +50,7 @@ public abstract class ChunkStore { * @throws DataException * @throws IOException */ - public abstract CompoundTag getChunkTag(Vector2D pos) + public abstract CompoundTag getChunkTag(Vector2D pos, String world) throws DataException, IOException; /** @@ -62,9 +62,9 @@ public abstract class ChunkStore { * @throws IOException * @throws DataException */ - public Chunk getChunk(Vector2D pos) + public Chunk getChunk(Vector2D pos, String world) throws DataException, IOException { - return new Chunk(getChunkTag(pos)); + return new Chunk(getChunkTag(pos, world)); } /** diff --git a/src/main/java/com/sk89q/worldedit/data/FileMcRegionChunkStore.java b/src/main/java/com/sk89q/worldedit/data/FileMcRegionChunkStore.java index f6c2ce33f..21835491c 100644 --- a/src/main/java/com/sk89q/worldedit/data/FileMcRegionChunkStore.java +++ b/src/main/java/com/sk89q/worldedit/data/FileMcRegionChunkStore.java @@ -42,13 +42,16 @@ public class FileMcRegionChunkStore extends McRegionChunkStore { } @Override - protected InputStream getInputStream(String name) throws IOException, + protected InputStream getInputStream(String name, String world) throws IOException, DataException { - - String file = "region" + File.separator + name; + String fileName = "region" + File.separator + name; + File file = new File(path, fileName); + if (!file.exists()) { + file = new File(path, "DIM-1" + File.separator + fileName); + } try { - return new FileInputStream(new File(path, file)); + return new FileInputStream(file); } catch (FileNotFoundException e) { throw new MissingChunkException(); } @@ -56,7 +59,8 @@ public class FileMcRegionChunkStore extends McRegionChunkStore { @Override public boolean isValid() { - return new File(path, "region").isDirectory(); + return new File(path, "region").isDirectory() || + new File(path, "DIM-1" + File.separator + "region").isDirectory(); } } diff --git a/src/main/java/com/sk89q/worldedit/data/LegacyChunkStore.java b/src/main/java/com/sk89q/worldedit/data/LegacyChunkStore.java index 7ae24c515..fbec3a74b 100644 --- a/src/main/java/com/sk89q/worldedit/data/LegacyChunkStore.java +++ b/src/main/java/com/sk89q/worldedit/data/LegacyChunkStore.java @@ -74,7 +74,7 @@ public abstract class LegacyChunkStore extends ChunkStore { * @throws IOException */ @Override - public CompoundTag getChunkTag(Vector2D pos) + public CompoundTag getChunkTag(Vector2D pos, String world) throws DataException, IOException { int x = pos.getBlockX(); int z = pos.getBlockZ(); diff --git a/src/main/java/com/sk89q/worldedit/data/McRegionChunkStore.java b/src/main/java/com/sk89q/worldedit/data/McRegionChunkStore.java index c98050701..dfc958c1f 100644 --- a/src/main/java/com/sk89q/worldedit/data/McRegionChunkStore.java +++ b/src/main/java/com/sk89q/worldedit/data/McRegionChunkStore.java @@ -46,7 +46,7 @@ public abstract class McRegionChunkStore extends ChunkStore { return filename; } - protected McRegionReader getReader(Vector2D pos) throws DataException, IOException { + protected McRegionReader getReader(Vector2D pos, String worldname) throws DataException, IOException { String filename = getFilename(pos); if (curFilename != null) { if (curFilename.equals(filename)) { @@ -58,17 +58,17 @@ public abstract class McRegionChunkStore extends ChunkStore { } } } - InputStream stream = getInputStream(filename); + InputStream stream = getInputStream(filename, worldname); cachedReader = new McRegionReader(stream); //curFilename = filename; return cachedReader; } @Override - public CompoundTag getChunkTag(Vector2D pos) throws DataException, + public CompoundTag getChunkTag(Vector2D pos, String worldname) throws DataException, IOException { - McRegionReader reader = getReader(pos); + McRegionReader reader = getReader(pos, worldname); InputStream stream = reader.getChunkInputStream(pos); NBTInputStream nbt = new NBTInputStream(stream); Tag tag; @@ -113,7 +113,7 @@ public abstract class McRegionChunkStore extends ChunkStore { * @return * @throws IOException */ - protected abstract InputStream getInputStream(String name) + protected abstract InputStream getInputStream(String name, String worldname) throws IOException, DataException; diff --git a/src/main/java/com/sk89q/worldedit/data/MissingWorldException.java b/src/main/java/com/sk89q/worldedit/data/MissingWorldException.java new file mode 100644 index 000000000..a04b7c2ba --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/data/MissingWorldException.java @@ -0,0 +1,54 @@ +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.data; + +/** + * + * @author sk89q + */ +public class MissingWorldException extends ChunkStoreException { + + private static final long serialVersionUID = 6487395784195658467L; + + private String worldname; + + public MissingWorldException() { + super(); + } + + public MissingWorldException(String worldname) { + super(); + this.worldname = worldname; + } + + public MissingWorldException(String msg, String worldname) { + super(msg); + this.worldname = worldname; + } + + /** + * Get name of the world in question. May be null if unknown. + * + * @return + */ + public String getWorldname() { + return worldname; + } +} diff --git a/src/main/java/com/sk89q/worldedit/data/TrueZipMcRegionChunkStore.java b/src/main/java/com/sk89q/worldedit/data/TrueZipMcRegionChunkStore.java index b066d73d2..8aec143d3 100644 --- a/src/main/java/com/sk89q/worldedit/data/TrueZipMcRegionChunkStore.java +++ b/src/main/java/com/sk89q/worldedit/data/TrueZipMcRegionChunkStore.java @@ -15,8 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -*/ - + */ package com.sk89q.worldedit.data; import java.io.*; @@ -32,6 +31,7 @@ import de.schlichtherle.util.zip.*; * @author sk89q */ public class TrueZipMcRegionChunkStore extends McRegionChunkStore { + /** * ZIP file. */ @@ -59,7 +59,7 @@ public class TrueZipMcRegionChunkStore extends McRegionChunkStore { throws IOException, ZipException { this.zipFile = zipFile; this.folder = folder; - + zip = new ZipFile(zipFile); } @@ -88,57 +88,49 @@ public class TrueZipMcRegionChunkStore extends McRegionChunkStore { */ @Override @SuppressWarnings("unchecked") - protected InputStream getInputStream(String name) + protected InputStream getInputStream(String name, String worldname) throws IOException, DataException { - String file = "region/" + name; // Detect subfolder for the world's files if (folder != null) { if (!folder.equals("")) { - file = folder + "/" + file; + name = folder + "/" + name; } } else { - ZipEntry testEntry = zip.getEntry("level.dat"); - - // So, the data is not in the root directory - if (testEntry == null) { - // Let's try a world/ sub-directory - testEntry = getEntry("world/level.dat"); - - Pattern pattern = Pattern.compile(".*[\\\\/]level\\.dat$"); - - // So not there either... - if (testEntry == null) { - for (Enumeration e = zip.entries(); - e.hasMoreElements(); ) { - - testEntry = e.nextElement(); - - // Whoo, found level.dat! - if (pattern.matcher(testEntry.getName()).matches()) { - folder = testEntry.getName().replaceAll("level\\.dat$", ""); - folder = folder.substring(0, folder.length() - 1); - file = folder + file; - break; - } + Pattern pattern = Pattern.compile(".*\\.mcr$"); + // World pattern + Pattern worldPattern = Pattern.compile(worldname + "\\$"); + for (Enumeration e = zip.entries(); + e.hasMoreElements();) { + ZipEntry testEntry = (ZipEntry) e.nextElement(); + // Check for world + if (worldPattern.matcher(worldname).matches()) { + // Check for file + if (pattern.matcher(testEntry.getName()).matches()) { + folder = testEntry.getName().substring(0, testEntry.getName().lastIndexOf("/")); + name = folder + "/" + name; + break; } - } else { - file = "world/" + file; } } + + // Check if world is found + if (folder == null) { + throw new MissingWorldException("Target world is not present in ZIP.", worldname); + } } - ZipEntry entry = getEntry(file); + ZipEntry entry = getEntry(name); if (entry == null) { throw new MissingChunkException(); } try { return zip.getInputStream(entry); } catch (ZipException e) { - throw new IOException("Failed to read " + file + " in ZIP"); + throw new IOException("Failed to read " + name + " in ZIP"); } } - + /** * Get an entry from the ZIP, trying both types of slashes. * @@ -167,15 +159,15 @@ public class TrueZipMcRegionChunkStore extends McRegionChunkStore { @SuppressWarnings("unchecked") public boolean isValid() { for (Enumeration e = zip.entries(); - e.hasMoreElements(); ) { - + e.hasMoreElements();) { + ZipEntry testEntry = e.nextElement(); - + if (testEntry.getName().matches(".*\\.mcr$")) { return true; } } - + return false; } } diff --git a/src/main/java/com/sk89q/worldedit/data/ZippedMcRegionChunkStore.java b/src/main/java/com/sk89q/worldedit/data/ZippedMcRegionChunkStore.java index 124b43c02..32dd1b9e0 100644 --- a/src/main/java/com/sk89q/worldedit/data/ZippedMcRegionChunkStore.java +++ b/src/main/java/com/sk89q/worldedit/data/ZippedMcRegionChunkStore.java @@ -15,8 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -*/ - + */ package com.sk89q.worldedit.data; import java.io.*; @@ -30,6 +29,7 @@ import java.util.Enumeration; * @author sk89q */ public class ZippedMcRegionChunkStore extends McRegionChunkStore { + /** * ZIP file. */ @@ -57,7 +57,7 @@ public class ZippedMcRegionChunkStore extends McRegionChunkStore { throws IOException, ZipException { this.zipFile = zipFile; this.folder = folder; - + zip = new ZipFile(zipFile); } @@ -85,57 +85,47 @@ public class ZippedMcRegionChunkStore extends McRegionChunkStore { * @throws DataException */ @Override - protected InputStream getInputStream(String name) + protected InputStream getInputStream(String name, String worldname) throws IOException, DataException { - String file = "region/" + name; // Detect subfolder for the world's files if (folder != null) { if (!folder.equals("")) { - file = folder + "/" + file; + name = folder + "/" + name; } } else { - ZipEntry testEntry = zip.getEntry("level.dat"); - - // So, the data is not in the root directory - if (testEntry == null) { - // Let's try a world/ sub-directory - testEntry = getEntry("world/level.dat"); - - Pattern pattern = Pattern.compile(".*[\\\\/]level\\.dat$"); - - // So not there either... - if (testEntry == null) { - for (Enumeration e = zip.entries(); - e.hasMoreElements(); ) { - - testEntry = (ZipEntry)e.nextElement(); - - // Whoo, found level.dat! - if (pattern.matcher(testEntry.getName()).matches()) { - folder = testEntry.getName().replaceAll("level\\.dat$", ""); - folder = folder.substring(0, folder.length() - 1); - file = folder + file; - break; - } + Pattern pattern = Pattern.compile(".*\\.mcr$"); + for (Enumeration e = zip.entries(); + e.hasMoreElements();) { + ZipEntry testEntry = (ZipEntry) e.nextElement(); + // Check for world + if (testEntry.getName().startsWith(worldname + "/")) { + if (pattern.matcher(testEntry.getName()).matches()) { + folder = testEntry.getName().substring(0, testEntry.getName().lastIndexOf("/")); + name = folder + "/" + name; + break; } - } else { - file = "world/" + file; + } } + + // Check if world is found + if (folder == null) { + throw new MissingWorldException("Target world is not present in ZIP.", worldname); + } } - ZipEntry entry = getEntry(file); + ZipEntry entry = getEntry(name); if (entry == null) { throw new MissingChunkException(); } try { return zip.getInputStream(entry); } catch (ZipException e) { - throw new IOException("Failed to read " + file + " in ZIP"); + throw new IOException("Failed to read " + name + " in ZIP"); } } - + /** * Get an entry from the ZIP, trying both types of slashes. * @@ -163,15 +153,15 @@ public class ZippedMcRegionChunkStore extends McRegionChunkStore { @Override public boolean isValid() { for (Enumeration e = zip.entries(); - e.hasMoreElements(); ) { - + e.hasMoreElements();) { + ZipEntry testEntry = e.nextElement(); - + if (testEntry.getName().matches(".*\\.mcr$")) { return true; } } - + return false; } } diff --git a/src/main/java/com/sk89q/worldedit/snapshots/Snapshot.java b/src/main/java/com/sk89q/worldedit/snapshots/Snapshot.java index 255727655..1b995afad 100644 --- a/src/main/java/com/sk89q/worldedit/snapshots/Snapshot.java +++ b/src/main/java/com/sk89q/worldedit/snapshots/Snapshot.java @@ -15,22 +15,22 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -*/ - + */ package com.sk89q.worldedit.snapshots; import com.sk89q.worldedit.data.*; import java.io.*; import java.util.Calendar; import java.util.logging.Logger; +import java.util.zip.ZipFile; /** * * @author sk89q */ public class Snapshot implements Comparable { + protected static Logger logger = Logger.getLogger("Minecraft.WorldEdit"); - /** * Stores snapshot file. */ @@ -64,10 +64,10 @@ public class Snapshot implements Comparable { */ public ChunkStore getChunkStore() throws IOException, DataException { ChunkStore chunkStore = _getChunkStore(); - + logger.info("WorldEdit: Using " + chunkStore.getClass().getCanonicalName() + " for loading snapshot '" + file.getAbsolutePath() + "'"); - + return chunkStore; } @@ -82,19 +82,19 @@ public class Snapshot implements Comparable { if (file.getName().toLowerCase().endsWith(".zip")) { try { ChunkStore chunkStore = new TrueZipMcRegionChunkStore(file); - + if (!chunkStore.isValid()) { return new TrueZipLegacyChunkStore(file); } - + return chunkStore; } catch (NoClassDefFoundError e) { ChunkStore chunkStore = new ZippedMcRegionChunkStore(file); - + if (!chunkStore.isValid()) { return new ZippedLegacyChunkStore(file); } - + return chunkStore; } } else if (file.getName().toLowerCase().endsWith(".tar.bz2") @@ -102,26 +102,60 @@ public class Snapshot implements Comparable { || file.getName().toLowerCase().endsWith(".tar")) { try { ChunkStore chunkStore = new TrueZipMcRegionChunkStore(file); - + if (!chunkStore.isValid()) { return new TrueZipLegacyChunkStore(file); } - + return chunkStore; } catch (NoClassDefFoundError e) { throw new DataException("TrueZIP is required for .tar support"); } } else { ChunkStore chunkStore = new FileMcRegionChunkStore(file); - + if (!chunkStore.isValid()) { return new FileLegacyChunkStore(file); } - + return chunkStore; } } + /** + * Check the zip/tar file it contains the given world. + * + * @return true if the zip/tar file contains the given world + */ + public boolean containsWorld(String worldname) { + try { + if (file.getName().toLowerCase().endsWith(".zip")) { + ZipFile entry = new ZipFile(file); + return entry.getEntry(worldname) != null; + } else if (file.getName().toLowerCase().endsWith(".tar.bz2") + || file.getName().toLowerCase().endsWith(".tar.gz") + || file.getName().toLowerCase().endsWith(".tar")) { + try { + de.schlichtherle.util.zip.ZipFile entry = new de.schlichtherle.util.zip.ZipFile(file); + + return entry.getEntry(worldname) != null; + } catch (NoClassDefFoundError e) { + throw new DataException("TrueZIP is required for .tar support"); + } + } else { + return (file.getName().equalsIgnoreCase(worldname)); + } + } catch (IOException ex) { + // Skip the file, but print an error + logger.info("Could not load snapshot: " + + file.getPath()); + } catch (DataException ex) { + // No truezip, so tar file not supported. + // Dont print, just skip the file. + } + return false; + } + /** * Get the snapshot's name. * @@ -130,7 +164,7 @@ public class Snapshot implements Comparable { public String getName() { return name; } - + /** * Get the file for the snapshot. * @@ -139,7 +173,7 @@ public class Snapshot implements Comparable { public File getFile() { return file; } - + /** * Get the date associated with this snapshot. * @@ -148,7 +182,7 @@ public class Snapshot implements Comparable { public Calendar getDate() { return date; } - + /** * Set the date of the snapshot. * @@ -160,12 +194,14 @@ public class Snapshot implements Comparable { public int compareTo(Snapshot o) { if (o.date == null || date == null) { - return name.compareTo(o.name); + // Remove the folder from the name + int i = name.indexOf("/"), j = o.name.indexOf("/"); + return name.substring((i > 0 ? 0 : i)).compareTo(o.name.substring((j > 0 ? 0 : j))); } else { return date.compareTo(o.date); } } - + @Override public boolean equals(Object o) { if (o instanceof Snapshot) { diff --git a/src/main/java/com/sk89q/worldedit/snapshots/SnapshotRepository.java b/src/main/java/com/sk89q/worldedit/snapshots/SnapshotRepository.java index 9472e4de5..2c4ee67ab 100644 --- a/src/main/java/com/sk89q/worldedit/snapshots/SnapshotRepository.java +++ b/src/main/java/com/sk89q/worldedit/snapshots/SnapshotRepository.java @@ -15,10 +15,10 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -*/ - + */ package com.sk89q.worldedit.snapshots; +import com.sk89q.worldedit.data.MissingWorldException; import java.io.*; import java.util.ArrayList; import java.util.Calendar; @@ -30,16 +30,15 @@ import java.util.List; * @author sk89q */ public class SnapshotRepository { + /** * Stores the directory the snapshots come from. */ protected File dir; - /** * List of date parsers. */ - protected List dateParsers - = new ArrayList(); + protected List dateParsers = new ArrayList(); /** * Create a new instance of a repository. @@ -48,6 +47,8 @@ public class SnapshotRepository { */ public SnapshotRepository(File dir) { this.dir = dir; + // If folder dont exist, make it. + dir.mkdirs(); dateParsers.add(new YYMMDDHHIISSParser()); dateParsers.add(new ModificationTimerParser()); @@ -69,7 +70,7 @@ public class SnapshotRepository { * @param newestFirst * @return */ - public List getSnapshots(boolean newestFirst) { + public List getSnapshots(boolean newestFirst, String worldname) throws MissingWorldException { FilenameFilter filter = new FilenameFilter() { public boolean accept(File dir, String name) { File f = new File(dir, name); @@ -77,13 +78,23 @@ public class SnapshotRepository { } }; - String[] snapshotNames = dir.list(filter); - List list = new ArrayList(snapshotNames.length); - - for (String name : snapshotNames) { - Snapshot snapshot = new Snapshot(this, name); - detectDate(snapshot); - list.add(snapshot); + File[] snapshotFiles = dir.listFiles(); + List list = new ArrayList(snapshotFiles.length); + + for (File file : snapshotFiles) { + if (isValidSnapshot(file)) { + Snapshot snapshot = new Snapshot(this, file.getName()); + if (snapshot.containsWorld(worldname)) { + detectDate(snapshot); + list.add(snapshot); + } + } else if (file.isDirectory() && file.getName().equalsIgnoreCase(worldname)) { + for (String name : file.list(filter)) { + Snapshot snapshot = new Snapshot(this, file.getName() + "/" + name); + detectDate(snapshot); + list.add(snapshot); + } + } } if (newestFirst) { @@ -94,50 +105,50 @@ public class SnapshotRepository { return list; } - + /** * Get the first snapshot after a date. * * @param date * @return */ - public Snapshot getSnapshotAfter(Calendar date) { - List snapshots = getSnapshots(true); + public Snapshot getSnapshotAfter(Calendar date, String world) throws MissingWorldException { + List snapshots = getSnapshots(true, world); Snapshot last = null; - + for (Snapshot snapshot : snapshots) { if (snapshot.getDate() != null && snapshot.getDate().before(date)) { return last; } - + last = snapshot; } - + return last; } - + /** * Get the first snapshot before a date. * * @param date * @return */ - public Snapshot getSnapshotBefore(Calendar date) { - List snapshots = getSnapshots(false); + public Snapshot getSnapshotBefore(Calendar date, String world) throws MissingWorldException { + List snapshots = getSnapshots(false, world); Snapshot last = null; - + for (Snapshot snapshot : snapshots) { if (snapshot.getDate().after(date)) { return last; } - + last = snapshot; } - + return last; } - + /** * Attempt to detect a snapshot's date and assign it. * @@ -151,7 +162,7 @@ public class SnapshotRepository { return; } } - + snapshot.setDate(null); } @@ -160,8 +171,8 @@ public class SnapshotRepository { * * @return */ - public Snapshot getDefaultSnapshot() { - List snapshots = getSnapshots(true); + public Snapshot getDefaultSnapshot(String world) throws MissingWorldException { + List snapshots = getSnapshots(true, world); if (snapshots.size() == 0) { return null; @@ -186,18 +197,16 @@ public class SnapshotRepository { * @param f * @return whether it is a valid snapshot */ - public boolean isValidSnapshot(File f) { + protected boolean isValidSnapshot(File f) { if (!f.getName().matches("^[A-Za-z0-9_\\- \\./\\\\'\\$@~!%\\^\\*\\(\\)\\[\\]\\+\\{\\},\\?]+$")) { return false; } return (f.isDirectory() && (new File(f, "level.dat")).exists()) - || (f.isFile() && ( - f.getName().toLowerCase().endsWith(".zip") - || f.getName().toLowerCase().endsWith(".tar.bz2") - || f.getName().toLowerCase().endsWith(".tar.gz") - || f.getName().toLowerCase().endsWith(".tar") - )); + || (f.isFile() && (f.getName().toLowerCase().endsWith(".zip") + || f.getName().toLowerCase().endsWith(".tar.bz2") + || f.getName().toLowerCase().endsWith(".tar.gz") + || f.getName().toLowerCase().endsWith(".tar"))); } /** diff --git a/src/main/java/com/sk89q/worldedit/snapshots/SnapshotRestore.java b/src/main/java/com/sk89q/worldedit/snapshots/SnapshotRestore.java index 6c4d3cbb8..f916fb1ca 100644 --- a/src/main/java/com/sk89q/worldedit/snapshots/SnapshotRestore.java +++ b/src/main/java/com/sk89q/worldedit/snapshots/SnapshotRestore.java @@ -147,7 +147,7 @@ public class SnapshotRestore { Chunk chunk; try { - chunk = chunkStore.getChunk(chunkPos); + chunk = chunkStore.getChunk(chunkPos, editSession.getWorld().getName()); // Good, the chunk could be at least loaded // Now just copy blocks! @@ -157,6 +157,9 @@ public class SnapshotRestore { } } catch (MissingChunkException me) { missingChunks.add(chunkPos); + } catch (MissingWorldException me) { + errorChunks.add(chunkPos); + lastErrorMessage = me.getMessage(); } catch (DataException de) { errorChunks.add(chunkPos); lastErrorMessage = de.getMessage(); diff --git a/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java b/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java index dc52eb82b..6ad62c81a 100644 --- a/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java +++ b/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java @@ -15,8 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -*/ - + */ package com.sk89q.worldedit.util; import java.io.*; @@ -35,9 +34,10 @@ import com.sk89q.worldedit.snapshots.SnapshotRepository; * @author sk89q */ public class PropertiesConfiguration extends LocalConfiguration { + protected Properties properties; protected File path; - + /** * Construct the object. The configuration isn't loaded yet. * @@ -45,10 +45,10 @@ public class PropertiesConfiguration extends LocalConfiguration { */ public PropertiesConfiguration(File path) { this.path = path; - + properties = new Properties(); } - + /** * Load the configuration file. */ @@ -69,7 +69,7 @@ public class PropertiesConfiguration extends LocalConfiguration { } } } - + profile = getBool("profile", profile); disallowedBlocks = getIntSet("disallowed-blocks", defaultDisallowedBlocks); defaultChangeLimit = getInt("default-max-changed-blocks", defaultChangeLimit); @@ -89,16 +89,14 @@ public class PropertiesConfiguration extends LocalConfiguration { navigationWand = getInt("nav-wand-item", navigationWand); navigationWandMaxDistance = getInt("nav-wand-distance", navigationWandMaxDistance); scriptTimeout = getInt("scripting-timeout", scriptTimeout); - + LocalSession.MAX_HISTORY_SIZE = Math.max(15, getInt("history-size", 15)); - + String snapshotsDir = getString("snapshots-dir", ""); - if (!snapshotsDir.trim().equals("")) { + if (!snapshotsDir.isEmpty()) { snapshotRepo = new SnapshotRepository(snapshotsDir); - } else { - snapshotRepo = null; } - + OutputStream output = null; path.getParentFile().mkdirs(); try { @@ -117,7 +115,7 @@ public class PropertiesConfiguration extends LocalConfiguration { } } } - + /** * Get a string value. * @@ -137,7 +135,7 @@ public class PropertiesConfiguration extends LocalConfiguration { return val; } } - + /** * Get a boolean value. * @@ -229,5 +227,4 @@ public class PropertiesConfiguration extends LocalConfiguration { return set; } } - }