diff --git a/worldedit-core/src/main/java/com/boydti/fawe/command/CFICommands.java b/worldedit-core/src/main/java/com/boydti/fawe/command/CFICommands.java index 47b8d23bc..e5cb2539b 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/command/CFICommands.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/command/CFICommands.java @@ -501,7 +501,7 @@ public class CFICommands extends MethodCommands { HeightMapMCAGenerator gen = assertSettings(fp).getGenerator(); World world = fp.getWorld(); - MultiClipboardHolder multi = ClipboardFormat.SCHEMATIC.loadAllFromInput(fp.getPlayer(), schematic, true); + MultiClipboardHolder multi = ClipboardFormat.SCHEMATIC.loadAllFromInput(fp.getPlayer(), schematic, null, true); if (multi == null) { return; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollAction.java b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollAction.java index b12111586..12ebb41dd 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollAction.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollAction.java @@ -34,7 +34,7 @@ public abstract class ScrollAction implements ScrollTool { } String filename = split[1]; try { - MultiClipboardHolder multi = ClipboardFormat.SCHEMATIC.loadAllFromInput(player, filename, message); + MultiClipboardHolder multi = ClipboardFormat.SCHEMATIC.loadAllFromInput(player, filename, null, message); if (multi == null) { return null; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/MainUtil.java b/worldedit-core/src/main/java/com/boydti/fawe/util/MainUtil.java index 5b845346f..90d60c551 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/MainUtil.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/MainUtil.java @@ -11,6 +11,7 @@ import com.github.luben.zstd.ZstdInputStream; import com.github.luben.zstd.ZstdOutputStream; import com.sk89q.jnbt.*; import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.history.changeset.ChangeSet; import com.sk89q.worldedit.util.Location; import java.awt.Graphics2D; @@ -35,6 +36,7 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.regex.Pattern; import java.util.zip.*; +import javax.annotation.Nullable; import javax.imageio.ImageIO; import net.jpountz.lz4.*; @@ -884,9 +886,29 @@ public class MainUtil { return res; } - public static boolean isInSubDirectory(File dir, File file) { + public static File resolve(File dir, String filename, @Nullable ClipboardFormat format, boolean allowDir) { + if (format != null) { + if (!filename.matches(".*\\.[\\w].*")) { + filename = filename + "." + format.getExtension(); + } + return MainUtil.resolveRelative(new File(dir, filename)); + } + if (allowDir) { + File file = MainUtil.resolveRelative(new File(dir, filename)); + if (file.exists() && file.isDirectory()) return file; + } + for (ClipboardFormat f : ClipboardFormat.values) { + File file = MainUtil.resolveRelative(new File(dir, filename + "." + f.getExtension())); + if (file.exists()) return file; + } + return null; + } + + public static boolean isInSubDirectory(File dir, File file) throws IOException { if (file == null) return false; if (file.equals(dir)) return true; + file = file.getCanonicalFile(); + dir = dir.getCanonicalFile(); return isInSubDirectory(dir, file.getParentFile()); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index 9a263fd6e..9af1ef1aa 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -458,7 +458,7 @@ public class BrushCommands extends BrushProcessor { try { - MultiClipboardHolder clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(player, clipboard, true); + MultiClipboardHolder clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(player, clipboard, null, true); if (clipboards == null) { BBC.SCHEMATIC_NOT_FOUND.send(player, clipboard); return null; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java index 4f7aa536f..b46ffe82e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java @@ -190,7 +190,7 @@ public class PatternCommands extends MethodCommands { clipboards = Collections.singletonList(clipboard); break; default: - MultiClipboardHolder multi = ClipboardFormat.SCHEMATIC.loadAllFromInput(player, location, true); + MultiClipboardHolder multi = ClipboardFormat.SCHEMATIC.loadAllFromInput(player, location, null, true); clipboards = multi != null ? multi.getHolders() : null; break; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 54e1b8979..57de81adb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -97,7 +97,7 @@ public class SchematicCommands extends MethodCommands { desc = "Load multiple clipboards (paste will randomly choose one)" ) @Deprecated - @CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load", "worldedit.schematic.upload"}) + @CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load", "worldedit.schematic.load.web", "worldedit.schematic.load.asset"}) public void loadall(final Player player, final LocalSession session, @Optional("schematic") final String formatName, final String filename, @Switch('r') boolean randomRotate) throws FilenameException { final ClipboardFormat format = ClipboardFormat.findByAlias(formatName); if (format == null) { @@ -105,7 +105,7 @@ public class SchematicCommands extends MethodCommands { return; } try { - MultiClipboardHolder all = format.loadAllFromInput(player, filename, true); + MultiClipboardHolder all = format.loadAllFromInput(player, filename, null, true); if (all != null) { session.addClipboard(all); BBC.SCHEMATIC_LOADED.send(player, filename); @@ -187,24 +187,9 @@ public class SchematicCommands extends MethodCommands { player.print(BBC.getPrefix() + "Remapped schematic"); } - - private File resolve(File dir, String filename, @Nullable ClipboardFormat format) { - if (format != null) { - if (!filename.matches(".*\\.[\\w].*")) { - filename = filename + "." + format.getExtension(); - } - return MainUtil.resolveRelative(new File(dir, filename)); - } - for (ClipboardFormat f : ClipboardFormat.values) { - File file = MainUtil.resolveRelative(new File(dir, filename + "." + f.getExtension())); - if (file.exists()) return file; - } - return null; - } - @Command(aliases = {"load"}, usage = "[] ", desc = "Load a schematic into your clipboard") @Deprecated - @CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load", "worldedit.schematic.upload", "worldedit.schematic.load.other"}) + @CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load", "worldedit.schematic.load.asset", "worldedit.schematic.load.web", "worldedit.schematic.load.other"}) public void load(final Player player, final LocalSession session, @Optional() final String formatName, String filename) throws FilenameException { final LocalConfiguration config = this.worldEdit.getConfiguration(); ClipboardFormat format = formatName == null ? null : ClipboardFormat.findByAlias(formatName); @@ -212,8 +197,8 @@ public class SchematicCommands extends MethodCommands { try { URI uri; if (filename.startsWith("url:")) { - if (!player.hasPermission("worldedit.schematic.upload")) { - BBC.NO_PERM.send(player, "worldedit.schematic.upload"); + if (!player.hasPermission("worldedit.schematic.load.web")) { + BBC.NO_PERM.send(player, "worldedit.schematic.load.web"); return; } UUID uuid = UUID.fromString(filename.substring(4)); @@ -252,12 +237,12 @@ public class SchematicCommands extends MethodCommands { String extension = filename.substring(filename.lastIndexOf('.') + 1, filename.length()); format = ClipboardFormat.findByExtension(extension); } - f = resolve(dir, filename, format); + f = MainUtil.resolve(dir, filename, format, false); } if (f == null || !f.exists()) { if (!filename.contains("../")) { dir = this.worldEdit.getWorkingDirectoryFile(config.saveDir); - f = resolve(dir, filename, format); + f = MainUtil.resolve(dir, filename, format, false); } } if (f == null || !f.exists() || !MainUtil.isInSubDirectory(working, f)) { @@ -383,7 +368,7 @@ public class SchematicCommands extends MethodCommands { @Command(aliases = {"move", "m"}, usage = "", desc = "Move your loaded schematic", help = "Move your currently loaded schematics", min = 1, max = 1) @CommandPermissions({"worldedit.schematic.move", "worldedit.schematic.move.other"}) - public void move(final Player player, final LocalSession session, String directory) throws WorldEditException { + public void move(final Player player, final LocalSession session, String directory) throws WorldEditException, IOException { final LocalConfiguration config = this.worldEdit.getConfiguration(); final File working = this.worldEdit.getWorkingDirectoryFile(config.saveDir); final File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, player.getUniqueId().toString()) : working; @@ -429,7 +414,7 @@ public class SchematicCommands extends MethodCommands { @Command(aliases = {"delete", "d"}, usage = "", desc = "Delete a saved schematic", help = "Delete a schematic from the schematic list", min = 1, max = 1) @CommandPermissions({"worldedit.schematic.delete", "worldedit.schematic.delete.other"}) - public void delete(final Player player, final LocalSession session, final CommandContext args) throws WorldEditException { + public void delete(final Player player, final LocalSession session, final CommandContext args) throws WorldEditException, IOException { final LocalConfiguration config = this.worldEdit.getConfiguration(); final File working = this.worldEdit.getWorkingDirectoryFile(config.saveDir); final File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, player.getUniqueId().toString()) : working; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionTypeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionTypeCommands.java new file mode 100644 index 000000000..72b590c51 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionTypeCommands.java @@ -0,0 +1,5 @@ +package com.sk89q.worldedit.command; + +public class SelectionTypeCommands { + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java index de1e3ad37..0415b5ed2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java @@ -56,6 +56,7 @@ import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import java.util.zip.ZipEntry; @@ -318,16 +319,24 @@ public enum ClipboardFormat { }); } - public MultiClipboardHolder loadAllFromInput(Actor player, String input, boolean message) throws IOException { + public static MultiClipboardHolder loadAllFromInput(Actor player, String input, ClipboardFormat format, boolean message) throws IOException { checkNotNull(player); checkNotNull(input); WorldEdit worldEdit = WorldEdit.getInstance(); LocalConfiguration config = worldEdit.getConfiguration(); if (input.startsWith("url:")) { + if (!player.hasPermission("worldedit.schematic.load.web")) { + if (message) BBC.NO_PERM.send(player, "worldedit.schematic.load.web"); + return null; + } URL base = new URL(Settings.IMP.WEB.URL); input = new URL(base, "uploads/" + input.substring(4) + ".schematic").toString(); } if (input.startsWith("http")) { + if (!player.hasPermission("worldedit.schematic.load.asset")) { + if (message) BBC.NO_PERM.send(player, "worldedit.schematic.load.asset"); + return null; + } URL url = new URL(input); URL webInterface = new URL(Settings.IMP.WEB.ASSETS); if (!url.getHost().equalsIgnoreCase(webInterface.getHost())) { @@ -337,68 +346,89 @@ public enum ClipboardFormat { MultiClipboardHolder clipboards = loadAllFromUrl(url); return clipboards; } else { - if (input.contains("../") && !player.hasPermission("worldedit.schematic.load.other")) { - if (message) BBC.NO_PERM.send(player, "worldedit.schematic.load.other"); + if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}").matcher(input).find() && !player.hasPermission("worldedit.schematic.load.other")) { + BBC.NO_PERM.send(player, "worldedit.schematic.load.other"); return null; } File working = worldEdit.getWorkingDirectoryFile(config.saveDir); - File dir = new File(working, (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? (player.getUniqueId().toString() + File.separator) : "") + input); - if (!dir.exists()) { - dir = new File(dir + "." + getExtension()); - } - if (!dir.exists()) { - if ((!input.contains("/") && !input.contains("\\")) || player.hasPermission("worldedit.schematic.load.other")) { - dir = new File(worldEdit.getWorkingDirectoryFile(config.saveDir), input); + File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, player.getUniqueId().toString()) : working; + File f; + if (input.startsWith("#")) { + String[] extensions; + if (format != null) { + extensions = format.getFileExtensions().toArray(new String[0]); + } else { + extensions = ClipboardFormats.getFileExtensionArray(); } - if (!dir.exists()) { - dir = new File(dir + "." + getExtension()); + f = player.openFileOpenDialog(extensions); + if (f == null || !f.exists()) { + if (message) player.printError("Schematic " + input + " does not exist! (" + f + ")"); + return null; + } + } else { + if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}").matcher(input).find() && !player.hasPermission("worldedit.schematic.load.other")) { + if (message) BBC.NO_PERM.send(player, "worldedit.schematic.load.other"); + return null; + } + if (format == null && input.matches(".*\\.[\\w].*")) { + String extension = input.substring(input.lastIndexOf('.') + 1, input.length()); + format = ClipboardFormat.findByExtension(extension); + } + f = MainUtil.resolve(dir, input, format, true); + } + if (f == null || !f.exists()) { + if (!input.contains("../")) { + dir = worldEdit.getWorkingDirectoryFile(config.saveDir); + f = MainUtil.resolve(dir, input, format, true); } } - if(!dir.exists()) { - for(ClipboardFormat format : values) { - if(new File(working, (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? (player.getUniqueId().toString() + File.separator) : "") + input + "." + format.getExtension()).exists()) { - return format.loadAllFromInput(player, input, message); - } - } + if (f == null || !f.exists() || !MainUtil.isInSubDirectory(working, f)) { + if (message) player.printError("Schematic " + input + " does not exist! (" + ((f == null) ? false : f.exists()) + "|" + f + "|" + (f == null ? false : !MainUtil.isInSubDirectory(working, f)) + ")"); + return null; } - if (!dir.exists()) { + if (format == null && f.isFile()) { + format = ClipboardFormat.findByFile(f); + if (format == null) { + BBC.CLIPBOARD_INVALID_FORMAT.send(player, f.getName()); + return null; + } + } + if (!f.exists()) { if (message) BBC.SCHEMATIC_NOT_FOUND.send(player, input); return null; } - if (!dir.isDirectory()) { - if(!findByFile(dir).getExtension().equals(getExtension())) { - return findByFile(dir).loadAllFromInput(player, input, message); - } - ByteSource source = Files.asByteSource(dir); - URI uri = dir.toURI(); - return new MultiClipboardHolder(uri, new LazyClipboardHolder(dir.toURI(), source, this, null)); + if (!f.isDirectory()) { + ByteSource source = Files.asByteSource(f); + URI uri = f.toURI(); + return new MultiClipboardHolder(uri, new LazyClipboardHolder(f.toURI(), source, format, null)); } - URIClipboardHolder[] clipboards = loadAllFromDirectory(dir); + URIClipboardHolder[] clipboards = loadAllFromDirectory(f); if (clipboards.length < 1) { if (message) BBC.SCHEMATIC_NOT_FOUND.send(player, input); return null; } - return new MultiClipboardHolder(dir.toURI(), clipboards); + return new MultiClipboardHolder(f.toURI(), clipboards); } } - public URIClipboardHolder[] loadAllFromDirectory(File dir) { - File[] files = dir.listFiles(new FileFilter() { - @Override - public boolean accept(File pathname) { - return pathname.getName().endsWith(".schematic"); - } + public static URIClipboardHolder[] loadAllFromDirectory(File dir) { + HashSet extensions = new HashSet<>(Arrays.asList(ClipboardFormats.getFileExtensionArray())); + File[] files = dir.listFiles(pathname -> { + String input = pathname.getName(); + String extension = input.substring(input.lastIndexOf('.') + 1, input.length()); + return (extensions.contains(extension.toLowerCase())); }); LazyClipboardHolder[] clipboards = new LazyClipboardHolder[files.length]; for (int i = 0; i < files.length; i++) { File file = files[i]; ByteSource source = Files.asByteSource(file); - clipboards[i] = new LazyClipboardHolder(file.toURI(), source, this, null); + ClipboardFormat format = ClipboardFormat.findByFile(file); + clipboards[i] = new LazyClipboardHolder(file.toURI(), source, format, null); } return clipboards; } - public MultiClipboardHolder loadAllFromUrl(URL url) throws IOException { + public static MultiClipboardHolder loadAllFromUrl(URL url) throws IOException { List clipboards = new ArrayList<>(); try (ReadableByteChannel rbc = Channels.newChannel(url.openStream())) { try (InputStream in = Channels.newInputStream(rbc)) { @@ -406,7 +436,10 @@ public enum ClipboardFormat { ZipEntry entry; byte[] buffer = new byte[8192]; while ((entry = zip.getNextEntry()) != null) { - if (entry.getName().endsWith(".schematic")) { + String filename = entry.getName(); + String extension = filename.substring(filename.lastIndexOf('.') + 1, filename.length()); + ClipboardFormat format = findByExtension(filename); + if (format != null) { FastByteArrayOutputStream out = new FastByteArrayOutputStream(); int len = 0; while ((len = zip.read(buffer)) > 0) { @@ -414,7 +447,7 @@ public enum ClipboardFormat { } byte[] array = out.toByteArray(); ByteSource source = ByteSource.wrap(array); - LazyClipboardHolder clipboard = new LazyClipboardHolder(url.toURI(), source, this, null); + LazyClipboardHolder clipboard = new LazyClipboardHolder(url.toURI(), source, format, null); clipboards.add(clipboard); } }