interactive schematic/brush list

This commit is contained in:
Jesse Boyd 2017-08-02 16:46:59 +10:00
parent 914165b428
commit b685680340
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
4 changed files with 70 additions and 47 deletions

View File

@ -791,6 +791,12 @@ public class MainUtil {
} }
} }
public static boolean isInSubDirectory(File dir, File file) {
if (file == null) return false;
if (file.equals(dir)) return true;
return isInSubDirectory(dir, file.getParentFile());
}
public static void iterateFiles(File directory, RunnableVal<File> task) { public static void iterateFiles(File directory, RunnableVal<File> task) {
if (directory.exists()) { if (directory.exists()) {
File[] files = directory.listFiles(); File[] files = directory.listFiles();

View File

@ -2,6 +2,7 @@ package com.sk89q.worldedit.command;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Commands;
import com.boydti.fawe.object.brush.BrushSettings; import com.boydti.fawe.object.brush.BrushSettings;
import com.boydti.fawe.object.brush.TargetMode; import com.boydti.fawe.object.brush.TargetMode;
import com.boydti.fawe.object.brush.scroll.ScrollAction; import com.boydti.fawe.object.brush.scroll.ScrollAction;
@ -137,8 +138,9 @@ public class BrushOptionsCommands extends MethodCommands {
) )
@CommandPermissions("worldedit.brush.list") @CommandPermissions("worldedit.brush.list")
public void list(Actor actor, CommandContext args, @Switch('p') @Optional("1") int page) throws WorldEditException { public void list(Actor actor, CommandContext args, @Switch('p') @Optional("1") int page) throws WorldEditException {
String baseCmd = Commands.getAlias(BrushCommands.class, "brush") + " " + Commands.getAlias(BrushOptionsCommands.class, "loadbrush");
File dir = MainUtil.getFile(Fawe.imp().getDirectory(), "brushes"); File dir = MainUtil.getFile(Fawe.imp().getDirectory(), "brushes");
UtilityCommands.list(dir, actor, args, page, null, true); UtilityCommands.list(dir, actor, args, page, null, true, baseCmd);
} }
@Command( @Command(

View File

@ -21,11 +21,13 @@ package com.sk89q.worldedit.command;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Commands;
import com.boydti.fawe.config.Settings; import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.clipboard.ClipboardRemapper; import com.boydti.fawe.object.clipboard.ClipboardRemapper;
import com.boydti.fawe.object.clipboard.MultiClipboardHolder; import com.boydti.fawe.object.clipboard.MultiClipboardHolder;
import com.boydti.fawe.object.schematic.StructureFormat; import com.boydti.fawe.object.schematic.StructureFormat;
import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.chat.Message;
import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandException;
@ -61,22 +63,15 @@ import java.nio.file.Files;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* Commands that work with schematic files. * Commands that work with schematic files.
*/ */
@Command(aliases = {"schematic", "schem", "/schematic", "/schem"}, desc = "Commands that work with schematic files") @Command(aliases = {"schematic", "schem", "/schematic", "/schem"}, desc = "Commands that work with schematic files")
public class SchematicCommands { public class SchematicCommands extends MethodCommands {
/**
* 9 schematics per page fits in the MC chat window.
*/
private static final Logger log = Logger.getLogger(SchematicCommands.class.getCanonicalName()); private static final Logger log = Logger.getLogger(SchematicCommands.class.getCanonicalName());
private final WorldEdit worldEdit;
/** /**
* Create a new instance. * Create a new instance.
@ -84,8 +79,7 @@ public class SchematicCommands {
* @param worldEdit reference to WorldEdit * @param worldEdit reference to WorldEdit
*/ */
public SchematicCommands(final WorldEdit worldEdit) { public SchematicCommands(final WorldEdit worldEdit) {
checkNotNull(worldEdit); super(worldEdit);
this.worldEdit = worldEdit;
} }
@Command( @Command(
@ -137,7 +131,7 @@ public class SchematicCommands {
@Command(aliases = {"load"}, usage = "[<format>] <filename>", desc = "Load a schematic into your clipboard") @Command(aliases = {"load"}, usage = "[<format>] <filename>", desc = "Load a schematic into your clipboard")
@Deprecated @Deprecated
@CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load", "worldedit.schematic.upload", "worldedit.schematic.load.other"}) @CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load", "worldedit.schematic.upload", "worldedit.schematic.load.other"})
public void load(final Player player, final LocalSession session, @Optional("schematic") final String formatName, final String filename) throws FilenameException { public void load(final Player player, final LocalSession session, @Optional("schematic") final String formatName, String filename) throws FilenameException {
final LocalConfiguration config = this.worldEdit.getConfiguration(); final LocalConfiguration config = this.worldEdit.getConfiguration();
final ClipboardFormat format = ClipboardFormat.findByAlias(formatName); final ClipboardFormat format = ClipboardFormat.findByAlias(formatName);
if (format == null) { if (format == null) {
@ -161,13 +155,25 @@ public class SchematicCommands {
BBC.NO_PERM.send(player, "worldedit.clipboard.load"); BBC.NO_PERM.send(player, "worldedit.clipboard.load");
return; return;
} }
if (filename.contains("../") && !player.hasPermission("worldedit.schematic.load.other")) { File working = this.worldEdit.getWorkingDirectoryFile(config.saveDir);
File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, player.getUniqueId().toString()) : working;
File f;
if (filename.startsWith("#")) {
f = player.openFileOpenDialog(new String[] { format.getExtension() });
if (!f.exists()) {
player.printError("Schematic " + filename + " does not exist!");
return;
}
} 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(filename).find() && !player.hasPermission("worldedit.schematic.load.other")) {
BBC.NO_PERM.send(player, "worldedit.schematic.load.other"); BBC.NO_PERM.send(player, "worldedit.schematic.load.other");
return; return;
} }
File working = this.worldEdit.getWorkingDirectoryFile(config.saveDir); if (!filename.matches(".*\\.[\\w].*")) {
File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, player.getUniqueId().toString()) : working; filename += "." + format.getExtension();
File f = this.worldEdit.getSafeSaveFile(player, dir, filename, format.getExtension(), format.getExtension()); }
f = new File(dir, filename);
}
if (f.getName().replaceAll("." + format.getExtension(), "").isEmpty()) { if (f.getName().replaceAll("." + format.getExtension(), "").isEmpty()) {
File directory = f.getParentFile(); File directory = f.getParentFile();
if (directory.exists()) { if (directory.exists()) {
@ -178,20 +184,15 @@ public class SchematicCommands {
} }
} }
if (!f.exists()) { if (!f.exists()) {
if ((!filename.contains("/") && !filename.contains("\\")) || player.hasPermission("worldedit.schematic.load.other")) { if (!filename.contains("../")) {
dir = this.worldEdit.getWorkingDirectoryFile(config.saveDir); dir = this.worldEdit.getWorkingDirectoryFile(config.saveDir);
f = this.worldEdit.getSafeSaveFile(player, dir, filename, format.getExtension(), format.getExtension()); f = this.worldEdit.getSafeSaveFile(player, dir, filename, format.getExtension(), format.getExtension());
} }
if (!f.exists()) { }
if (!f.exists() || !MainUtil.isInSubDirectory(working, f)) {
player.printError("Schematic " + filename + " does not exist!"); player.printError("Schematic " + filename + " does not exist!");
return; return;
} }
}
final String filePath = f.getCanonicalPath();
final String dirPath = dir.getCanonicalPath();
if (!filePath.substring(0, dirPath.length()).equals(dirPath)) {
player.printError("Clipboard file could not read or it does not exist.");
}
in = new FileInputStream(f); in = new FileInputStream(f);
} }
final ClipboardReader reader = format.getReader(in); final ClipboardReader reader = format.getReader(in);
@ -222,7 +223,7 @@ public class SchematicCommands {
} }
} }
@Command(aliases = {"save"}, usage = "[<format>] <filename>", desc = "Save a schematic into your clipboard") @Command(aliases = {"save"}, usage = "[format] <filename>", desc = "Save a schematic into your clipboard")
@Deprecated @Deprecated
@CommandPermissions({"worldedit.clipboard.save", "worldedit.schematic.save", "worldedit.schematic.save.other"}) @CommandPermissions({"worldedit.clipboard.save", "worldedit.schematic.save", "worldedit.schematic.save.other"})
public void save(final Player player, final LocalSession session, @Optional("schematic") final String formatName, String filename) throws CommandException, WorldEditException { public void save(final Player player, final LocalSession session, @Optional("schematic") final String formatName, String filename) throws CommandException, WorldEditException {
@ -323,10 +324,11 @@ public class SchematicCommands {
@CommandPermissions("worldedit.schematic.formats") @CommandPermissions("worldedit.schematic.formats")
public void formats(final Actor actor) throws WorldEditException { public void formats(final Actor actor) throws WorldEditException {
BBC.SCHEMATIC_FORMAT.send(actor); BBC.SCHEMATIC_FORMAT.send(actor);
StringBuilder builder; Message m = new Message(BBC.SCHEMATIC_FORMAT).newline();
String baseCmd = Commands.getAlias(SchematicCommands.class, "schematic") + " " + Commands.getAlias(SchematicCommands.class, "save");
boolean first = true; boolean first = true;
for (final ClipboardFormat format : ClipboardFormat.values()) { for (final ClipboardFormat format : ClipboardFormat.values()) {
builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append(format.name()).append(": "); builder.append(format.name()).append(": ");
for (final String lookupName : format.getAliases()) { for (final String lookupName : format.getAliases()) {
if (!first) { if (!first) {
@ -335,9 +337,11 @@ public class SchematicCommands {
builder.append(lookupName); builder.append(lookupName);
first = false; first = false;
} }
String cmd = baseCmd + " " + format.name() + " <filename>";
m.text(builder).suggestTip(cmd).newline();
first = true; first = true;
actor.print(BBC.getPrefix() + builder.toString());
} }
m.send(actor);
} }
// schem list all|mine|global page // schem list all|mine|global page
@ -355,8 +359,9 @@ public class SchematicCommands {
) )
@CommandPermissions("worldedit.schematic.list") @CommandPermissions("worldedit.schematic.list")
public void list(Actor actor, CommandContext args, @Switch('p') @Optional("1") int page, @Switch('f') String formatName) throws WorldEditException { public void list(Actor actor, CommandContext args, @Switch('p') @Optional("1") int page, @Switch('f') String formatName) throws WorldEditException {
String baseCmd = Commands.getAlias(SchematicCommands.class, "schematic") + " " + Commands.getAlias(SchematicCommands.class, "load");
File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().saveDir); File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().saveDir);
UtilityCommands.list(dir, actor, args, page, formatName, Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS); UtilityCommands.list(dir, actor, args, page, formatName, Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS, baseCmd);
} }
public static Class<?> inject() { public static Class<?> inject() {

View File

@ -632,7 +632,7 @@ public class UtilityCommands extends MethodCommands {
return null; return null;
} }
public static void list(File dir, Actor actor, CommandContext args, @Range(min = 0) int page, String formatName, boolean playerFolder) { public static void list(File dir, Actor actor, CommandContext args, @Range(min = 0) int page, String formatName, boolean playerFolder, String onClickCmd) {
List<File> fileList = new ArrayList<>(); List<File> fileList = new ArrayList<>();
int len = args.argsLength(); int len = args.argsLength();
List<String> filters = new ArrayList<>(); List<String> filters = new ArrayList<>();
@ -715,21 +715,30 @@ public class UtilityCommands extends MethodCommands {
} }
}); });
List<String> schematics = listFiles(dir, files, playerFolder ? actor.getUniqueId() : null); List<String[]> schematics = listFiles(dir, files, playerFolder ? actor.getUniqueId() : null);
int offset = (page - 1) * perPage; int offset = (page - 1) * perPage;
StringBuilder build = new StringBuilder();
int limit = Math.min(offset + perPage, schematics.size()); int limit = Math.min(offset + perPage, schematics.size());
for (int i = offset; i < limit; ) {
build.append(schematics.get(i));
if (++i != limit) {
build.append("\n");
}
}
String heading = BBC.SCHEMATIC_LIST.f(page, pageCount);
actor.print(BBC.getPrefix() + heading + "\n" + build.toString());
}
String fullArgs = (String) args.getLocals().get("arguments");
String baseCmd = null;
if (fullArgs != null) {
baseCmd = fullArgs.endsWith(" " + page) ? fullArgs.substring(0, fullArgs.length() - (" " + page).length()) : fullArgs;
}
Message m = new Message(BBC.SCHEMATIC_LIST, page, pageCount);
for (int i = offset; i < limit; i++) {
String[] fileinfo = schematics.get(i);
String fileName = fileinfo[0];
String fileFormat = fileinfo[1];
m.newline().text(BBC.SCHEMATIC_LIST_ELEM, fileName, formatName);
if (onClickCmd != null) m.cmdTip(onClickCmd + " " + fileName);
}
if (baseCmd != null) {
m.newline().paginate(baseCmd, page, pageCount);
}
m.send(actor);
}
private static List<File> allFiles(File root, boolean recursive) { private static List<File> allFiles(File root, boolean recursive) {
File[] files = root.listFiles(); File[] files = root.listFiles();
@ -749,14 +758,15 @@ public class UtilityCommands extends MethodCommands {
return fileList; return fileList;
} }
private static List<String> listFiles(File root, File[] files, UUID uuid) { private static List<String[]> listFiles(File root, File[] files, UUID uuid) {
// List Elem [ File Name, Format Name ]
File dir; File dir;
if (uuid != null) { if (uuid != null) {
dir = new File(root, uuid.toString()); dir = new File(root, uuid.toString());
} else { } else {
dir = root; dir = root;
} }
List<String> result = new ArrayList<String>(); List<String[]> result = new ArrayList<>();
for (File file : files) { for (File file : files) {
ClipboardFormat format = ClipboardFormat.findByFile(file); ClipboardFormat format = ClipboardFormat.findByFile(file);
URI relative = dir.toURI().relativize(file.toURI()); URI relative = dir.toURI().relativize(file.toURI());
@ -773,7 +783,7 @@ public class UtilityCommands extends MethodCommands {
} else { } else {
formatName = format.toString(); formatName = format.toString();
} }
result.add(BBC.SCHEMATIC_LIST_ELEM.f(name, formatName)); result.add(new String[] {name, formatName} );
} }
return result; return result;
} }