Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-09-06 08:02:50 +02:00
Schem file limits (#773)
* added filesize/file count checks for /schematic save * fixed /schematic save, added filesize component to /schematic list * improved /schematics list total filesize output need to add automatic conversion into Mb in the future * temporary fix for page wrap from MessageBox * reverted changed to MessageBox * applied FAWE's checkstyle where applicable * crude fix for worldedit MessageBox line wrapping happening sometimes * small visual adjustments * Update worldedit-core/src/main/java/com/boydti/fawe/config/Settings.java Co-authored-by: NotMyFault <mc.cache@web.de> * Update worldedit-core/src/main/java/com/boydti/fawe/config/Settings.java Co-authored-by: NotMyFault <mc.cache@web.de> * Update worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java Co-authored-by: NotMyFault <mc.cache@web.de> * Update worldedit-core/src/main/java/com/boydti/fawe/config/Settings.java Co-authored-by: NotMyFault <mc.cache@web.de> * Update worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java Co-authored-by: NotMyFault <mc.cache@web.de> * Update worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java Co-authored-by: NotMyFault <mc.cache@web.de> * Update worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java Co-authored-by: NotMyFault <mc.cache@web.de> * Update worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java Co-authored-by: NotMyFault <mc.cache@web.de> * Update worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java Co-authored-by: NotMyFault <mc.cache@web.de> * Update worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java Co-authored-by: NotMyFault <mc.cache@web.de> * Update worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java Co-authored-by: NotMyFault <mc.cache@web.de> * Update worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java Co-authored-by: NotMyFault <mc.cache@web.de> * Update worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java Co-authored-by: NotMyFault <mc.cache@web.de> * Update worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java Co-authored-by: NotMyFault <mc.cache@web.de> * Update worldedit-core/src/main/java/com/boydti/fawe/config/Settings.java Co-authored-by: NotMyFault <mc.cache@web.de> * fixed settings variable names * Improved `/schematic save` success/error notifications fixed local variable names * removed unneeded comment * fixed typo * made schematics in subdirectories count towards file limit Co-authored-by: NotMyFault <mc.cache@web.de>
Dieser Commit ist enthalten in:
Ursprung
26e3e56988
Commit
bfc657d3f6
@ -394,6 +394,18 @@ public class Settings extends Config {
|
||||
" - Requires combine_stages = true"
|
||||
})
|
||||
public boolean SEND_BEFORE_HISTORY = false;
|
||||
|
||||
@Comment({
|
||||
"Sets a maximum limit (in kb) for the size of a player's schematics directory (per-player mode only)",
|
||||
"Set to -1 to disable"
|
||||
})
|
||||
public int PER_PLAYER_FILE_SIZE_LIMIT = -1;
|
||||
|
||||
@Comment({
|
||||
"Sets a maximum limit for the amount of schematics in a player's schematics directory (per-player mode only)",
|
||||
"Set to -1 to disable"
|
||||
})
|
||||
public int PER_PLAYER_FILE_NUM_LIMIT = -1;
|
||||
}
|
||||
|
||||
public static class PLOTSQUARED_INTEGRATION {
|
||||
|
@ -80,6 +80,7 @@ import java.net.URL;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@ -94,7 +95,6 @@ import static com.boydti.fawe.util.ReflectionUtils.as;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
//import com.boydti.fawe.object.schematic.visualizer.SchemVis;
|
||||
|
||||
/**
|
||||
* Commands that work with schematic files.
|
||||
@ -115,6 +115,31 @@ public class SchematicCommands {
|
||||
this.worldEdit = worldEdit;
|
||||
}
|
||||
|
||||
//TODO filtering for directories, global, and private scheamtics needs to be reimplemented here
|
||||
private static List<File> getFiles(File root, String filter, ClipboardFormat format) {
|
||||
File[] files = root.listFiles();
|
||||
if (files == null) {
|
||||
return null;
|
||||
}
|
||||
//Only get the files that match the format parameter
|
||||
if (format != null) {
|
||||
files = Arrays.stream(files).filter(format::isFormat).toArray(File[]::new);
|
||||
}
|
||||
List<File> fileList = new ArrayList<>();
|
||||
for (File f : files) {
|
||||
if (f.isDirectory()) {
|
||||
List<File> subFiles = getFiles(f, filter, format);
|
||||
if (subFiles == null) {
|
||||
continue; // empty subdir
|
||||
}
|
||||
fileList.addAll(subFiles);
|
||||
} else {
|
||||
fileList.add(f);
|
||||
}
|
||||
}
|
||||
return fileList;
|
||||
}
|
||||
|
||||
@Command(
|
||||
name = "loadall",
|
||||
desc = "Load multiple clipboards (paste will randomly choose one)"
|
||||
@ -122,12 +147,12 @@ public class SchematicCommands {
|
||||
@Deprecated
|
||||
@CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load", "worldedit.schematic.load.web", "worldedit.schematic.load.asset"})
|
||||
public void loadall(Player player, LocalSession session,
|
||||
@Arg(desc = "Format name.", def = "schematic")
|
||||
String formatName,
|
||||
@Arg(desc = "File name.")
|
||||
String filename,
|
||||
@Switch(name = 'r', desc = "Apply random rotation")
|
||||
boolean randomRotate) throws FilenameException {
|
||||
@Arg(desc = "Format name.", def = "schematic")
|
||||
String formatName,
|
||||
@Arg(desc = "File name.")
|
||||
String filename,
|
||||
@Switch(name = 'r', desc = "Apply random rotation")
|
||||
boolean randomRotate) throws FilenameException {
|
||||
final ClipboardFormat format = ClipboardFormats.findByAlias(formatName);
|
||||
if (format == null) {
|
||||
player.print(Caption.of("fawe.worldedit.clipboard.clipboard.invalid.format", formatName));
|
||||
@ -355,19 +380,19 @@ public class SchematicCommands {
|
||||
if (parent != null && !parent.exists()) {
|
||||
if (!parent.mkdirs()) {
|
||||
throw new StopExecutionException(TranslatableComponent.of(
|
||||
"worldedit.schematic.save.failed-directory"));
|
||||
"worldedit.schematic.save.failed-directory"));
|
||||
}
|
||||
}
|
||||
|
||||
ClipboardHolder holder = session.getClipboard();
|
||||
|
||||
SchematicSaveTask task = new SchematicSaveTask(actor, f, format, holder, overwrite);
|
||||
SchematicSaveTask task = new SchematicSaveTask(actor, f, dir, format, holder, overwrite);
|
||||
AsyncCommandBuilder.wrap(task, actor)
|
||||
.registerWithSupervisor(worldEdit.getSupervisor(), "Saving schematic " + filename)
|
||||
.sendMessageAfterDelay(TranslatableComponent.of("worldedit.schematic.save.saving"))
|
||||
.onSuccess(filename + " saved" + (overwrite ? " (overwriting previous file)." : "."), null)
|
||||
.onFailure("Failed to save schematic", worldEdit.getPlatformManager().getPlatformCommandManager().getExceptionConverter())
|
||||
.buildAndExec(worldEdit.getExecutorService());
|
||||
.registerWithSupervisor(worldEdit.getSupervisor(), "Saving schematic " + filename)
|
||||
.sendMessageAfterDelay(TranslatableComponent.of("worldedit.schematic.save.saving"))
|
||||
.onSuccess(filename + " saved" + (overwrite ? " (overwriting previous file)." : "."), null)
|
||||
.onFailure("Failed to save schematic", worldEdit.getPlatformManager().getPlatformCommandManager().getExceptionConverter())
|
||||
.buildAndExec(worldEdit.getExecutorService());
|
||||
}
|
||||
|
||||
@Command(
|
||||
@ -531,22 +556,22 @@ public class SchematicCommands {
|
||||
|
||||
if (loaded) {
|
||||
msg.append(TextComponent.of("[-]", TextColor.RED)
|
||||
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, unload + " " + path))
|
||||
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Unload"))));
|
||||
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, unload + " " + path))
|
||||
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Unload"))));
|
||||
} else {
|
||||
msg.append(TextComponent.of("[+]", TextColor.GREEN)
|
||||
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, loadMulti + " " + path))
|
||||
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Add to clipboard"))));
|
||||
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, loadMulti + " " + path))
|
||||
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Add to clipboard"))));
|
||||
}
|
||||
if (type != UtilityCommands.URIType.DIRECTORY) {
|
||||
msg.append(TextComponent.of("[X]", TextColor.DARK_RED)
|
||||
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, delete + " " + path))
|
||||
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("delete")))
|
||||
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, delete + " " + path))
|
||||
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("delete")))
|
||||
);
|
||||
} else if (hasShow) {
|
||||
msg.append(TextComponent.of("[O]", TextColor.DARK_AQUA)
|
||||
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, showCmd + " " + path))
|
||||
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("visualize")))
|
||||
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, showCmd + " " + path))
|
||||
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("visualize")))
|
||||
);
|
||||
}
|
||||
TextComponent msgElem = TextComponent.of(name, color);
|
||||
@ -559,173 +584,44 @@ public class SchematicCommands {
|
||||
}
|
||||
msg.append(msgElem);
|
||||
|
||||
if (type == UtilityCommands.URIType.FILE) {
|
||||
long filesize = 0;
|
||||
try {
|
||||
filesize = Files.size(Paths.get(dir.getAbsolutePath() + File.separator
|
||||
+ (playerFolder ? (uuid.toString() + File.separator) : "") + path));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
TextComponent sizeElem = TextComponent.of(String.format(" (%.1f kb)", filesize / 1000.0), TextColor.GRAY);
|
||||
msg.append(sizeElem);
|
||||
}
|
||||
return msg.create();
|
||||
});
|
||||
PaginationBox paginationBox = PaginationBox.fromComponents("Available schematics", pageCommand, components);
|
||||
|
||||
long totalBytes = 0;
|
||||
File parentDir = new File(dir.getAbsolutePath() + (playerFolder ? File.separator + uuid.toString() : ""));
|
||||
try {
|
||||
for (File schem : getFiles(parentDir, null, null)) {
|
||||
if (schem.getName().endsWith(".schem") || schem.getName().endsWith(".schematic")) {
|
||||
totalBytes += Files.size(Paths.get(schem.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
String headerBytesElem = String.format("%.1fkb", totalBytes / 1000.0);
|
||||
|
||||
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && Settings.IMP.EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT > -1) {
|
||||
headerBytesElem += String.format(" / %dkb",
|
||||
Settings.IMP.EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT );
|
||||
}
|
||||
|
||||
String fullHeader = "| Schematics: " + headerBytesElem + " |";
|
||||
PaginationBox paginationBox = PaginationBox.fromComponents(fullHeader, pageCommand, components);
|
||||
actor.print(paginationBox.create(page));
|
||||
}
|
||||
|
||||
private static class SchematicLoadTask implements Callable<ClipboardHolder> {
|
||||
private final Actor actor;
|
||||
private final File file;
|
||||
private final ClipboardFormat format;
|
||||
|
||||
SchematicLoadTask(Actor actor, File file, ClipboardFormat format) {
|
||||
this.actor = actor;
|
||||
this.file = file;
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClipboardHolder call() throws Exception {
|
||||
try (Closer closer = Closer.create()) {
|
||||
FileInputStream fis = closer.register(new FileInputStream(file));
|
||||
BufferedInputStream bis = closer.register(new BufferedInputStream(fis));
|
||||
ClipboardReader reader = closer.register(format.getReader(bis));
|
||||
|
||||
Clipboard clipboard = reader.read();
|
||||
log.info(actor.getName() + " loaded " + file.getCanonicalPath());
|
||||
return new ClipboardHolder(clipboard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class SchematicSaveTask implements Callable<Void> {
|
||||
private final Actor actor;
|
||||
private final File file;
|
||||
private final ClipboardFormat format;
|
||||
private final ClipboardHolder holder;
|
||||
private final boolean overwrite;
|
||||
|
||||
SchematicSaveTask(Actor actor, File file, ClipboardFormat format, ClipboardHolder holder, boolean overwrite) {
|
||||
this.actor = actor;
|
||||
this.file = file;
|
||||
this.format = format;
|
||||
this.holder = holder;
|
||||
this.overwrite = overwrite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
Clipboard clipboard = holder.getClipboard();
|
||||
Transform transform = holder.getTransform();
|
||||
Clipboard target;
|
||||
|
||||
// If we have a transform, bake it into the copy
|
||||
if (transform.isIdentity()) {
|
||||
target = clipboard;
|
||||
} else {
|
||||
FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform);
|
||||
target = new BlockArrayClipboard(result.getTransformedRegion());
|
||||
target.setOrigin(clipboard.getOrigin());
|
||||
Operations.completeLegacy(result.copyTo(target));
|
||||
}
|
||||
|
||||
try (Closer closer = Closer.create()) {
|
||||
FileOutputStream fos = closer.register(new FileOutputStream(file));
|
||||
BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos));
|
||||
ClipboardWriter writer = closer.register(format.getWriter(bos));
|
||||
URI uri = null;
|
||||
if (holder instanceof URIClipboardHolder) {
|
||||
uri = ((URIClipboardHolder) holder).getURI(clipboard);
|
||||
}
|
||||
if (new ActorSaveClipboardEvent(actor, clipboard, uri, file.toURI()).call()) {
|
||||
if (writer instanceof MinecraftStructure) {
|
||||
((MinecraftStructure) writer).write(target, actor.getName());
|
||||
} else {
|
||||
writer.write(target);
|
||||
}
|
||||
log.info(actor.getName() + " saved " + file.getCanonicalPath());
|
||||
actor.print(Caption.of("fawe.worldedit.schematic.schematic.saved", file.getName()));
|
||||
} else {
|
||||
actor.printError(TranslatableComponent.of("fawe.cancel.worldedit.cancel.reason.manual"));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SchematicListTask implements Callable<Component> {
|
||||
private final String prefix;
|
||||
private final int sortType;
|
||||
private final int page;
|
||||
private final File rootDir;
|
||||
private final String pageCommand;
|
||||
private final String filter;
|
||||
private String formatName;
|
||||
|
||||
SchematicListTask(String prefix, int sortType, int page, String pageCommand,
|
||||
String filter, String formatName) {
|
||||
this.prefix = prefix;
|
||||
this.sortType = sortType;
|
||||
this.page = page;
|
||||
this.rootDir = WorldEdit.getInstance().getWorkingDirectoryFile(prefix);
|
||||
this.pageCommand = pageCommand;
|
||||
this.filter = filter;
|
||||
this.formatName = formatName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component call() throws Exception {
|
||||
ClipboardFormat format = ClipboardFormats.findByAlias(formatName);
|
||||
List<File> fileList = getFiles(rootDir,filter,format);
|
||||
|
||||
if (fileList == null || fileList.isEmpty()) {
|
||||
return ErrorFormat.wrap("No schematics found.");
|
||||
}
|
||||
|
||||
File[] files = new File[fileList.size()];
|
||||
fileList.toArray(files);
|
||||
// cleanup file list
|
||||
Arrays.sort(files, (f1, f2) -> {
|
||||
// http://stackoverflow.com/questions/203030/best-way-to-list-files-in-java-sorted-by-date-modified
|
||||
int res;
|
||||
if (sortType == 0) { // use name by default
|
||||
int p = f1.getParent().compareTo(f2.getParent());
|
||||
if (p == 0) { // same parent, compare names
|
||||
res = f1.getName().compareTo(f2.getName());
|
||||
} else { // different parent, sort by that
|
||||
res = p;
|
||||
}
|
||||
} else {
|
||||
res = Long.compare(f1.lastModified(), f2.lastModified()); // use date if there is a flag
|
||||
if (sortType == 1) {
|
||||
res = -res; // flip date for newest first instead of oldest first
|
||||
}
|
||||
}
|
||||
return res;
|
||||
});
|
||||
|
||||
PaginationBox paginationBox = new SchematicPaginationBox(prefix, files, pageCommand);
|
||||
return paginationBox.create(page);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO filtering for directories, global, and private scheamtics needs to be reimplemented here
|
||||
private static List<File> getFiles(File root, String filter, ClipboardFormat format) {
|
||||
File[] files = root.listFiles();
|
||||
if (files == null) {
|
||||
return null;
|
||||
}
|
||||
//Only get the files that match the format parameter
|
||||
if (format != null) {
|
||||
files = Arrays.stream(files).filter(format::isFormat).toArray(File[]::new);
|
||||
}
|
||||
List<File> fileList = new ArrayList<>();
|
||||
for (File f : files) {
|
||||
if (f.isDirectory()) {
|
||||
List<File> subFiles = getFiles(f, filter, format);
|
||||
if (subFiles == null) {
|
||||
continue; // empty subdir
|
||||
}
|
||||
fileList.addAll(subFiles);
|
||||
} else {
|
||||
fileList.add(f);
|
||||
}
|
||||
}
|
||||
return fileList;
|
||||
}
|
||||
|
||||
@Command(
|
||||
name = "delete",
|
||||
aliases = {"d"},
|
||||
@ -776,6 +672,246 @@ public class SchematicCommands {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class SchematicLoadTask implements Callable<ClipboardHolder> {
|
||||
private final Actor actor;
|
||||
private final ClipboardFormat format;
|
||||
private final File file;
|
||||
|
||||
SchematicLoadTask(Actor actor, File file, ClipboardFormat format) {
|
||||
this.actor = actor;
|
||||
this.file = file;
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClipboardHolder call() throws Exception {
|
||||
try (Closer closer = Closer.create()) {
|
||||
FileInputStream fis = closer.register(new FileInputStream(file));
|
||||
BufferedInputStream bis = closer.register(new BufferedInputStream(fis));
|
||||
ClipboardReader reader = closer.register(format.getReader(bis));
|
||||
|
||||
Clipboard clipboard = reader.read();
|
||||
log.info(actor.getName() + " loaded " + file.getCanonicalPath());
|
||||
return new ClipboardHolder(clipboard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class SchematicSaveTask implements Callable<Void> {
|
||||
private final Actor actor;
|
||||
private final ClipboardFormat format;
|
||||
private final ClipboardHolder holder;
|
||||
private final boolean overwrite;
|
||||
private final File rootDir;
|
||||
private File file;
|
||||
|
||||
SchematicSaveTask(Actor actor, File file, File rootDir, ClipboardFormat format, ClipboardHolder holder, boolean overwrite) {
|
||||
this.actor = actor;
|
||||
this.file = file;
|
||||
this.rootDir = rootDir;
|
||||
this.format = format;
|
||||
this.holder = holder;
|
||||
this.overwrite = overwrite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
Clipboard clipboard = holder.getClipboard();
|
||||
Transform transform = holder.getTransform();
|
||||
Clipboard target;
|
||||
|
||||
boolean checkFilesize = false;
|
||||
|
||||
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS
|
||||
&& Settings.IMP.EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT > -1) {
|
||||
checkFilesize = true;
|
||||
}
|
||||
|
||||
double directorysizeKb = 0;
|
||||
String curFilepath = file.getAbsolutePath();
|
||||
final String SCHEMATIC_NAME = file.getName();
|
||||
|
||||
double oldKbOverwritten = 0;
|
||||
String overwrittenPath = curFilepath;
|
||||
|
||||
int numFiles = -1;
|
||||
if (checkFilesize) {
|
||||
File parentDir = new File(file.getParent());
|
||||
|
||||
for (File child : getFiles(rootDir, null, null)) {
|
||||
if (child.getName().endsWith(".schem") || child.getName().endsWith(".schematic")) {
|
||||
directorysizeKb += Files.size(Paths.get(child.getAbsolutePath())) / 1000.0;
|
||||
numFiles++;
|
||||
}
|
||||
}
|
||||
|
||||
if (overwrite) {
|
||||
oldKbOverwritten = Files.size(Paths.get(file.getAbsolutePath())) / 1000.0;
|
||||
int iter = 1;
|
||||
while (new File(overwrittenPath + "." + iter + "." + format.getPrimaryFileExtension()).exists()) {
|
||||
iter++;
|
||||
}
|
||||
file = new File(overwrittenPath + "." + iter + "." + format.getPrimaryFileExtension());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && Settings.IMP.EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT > -1) {
|
||||
|
||||
if (numFiles == -1) {
|
||||
numFiles = 0;
|
||||
for (File child : getFiles(rootDir, null, null)) {
|
||||
if (child.getName().endsWith(".schem") || child.getName().endsWith(".schematic")) {
|
||||
numFiles++;
|
||||
}
|
||||
}
|
||||
}
|
||||
int limit = Settings.IMP.EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT;
|
||||
|
||||
if (numFiles >= limit) {
|
||||
TextComponent noSlotsErr = TextComponent.of( //TODO - to be moved into captions/translatablecomponents
|
||||
String.format("You have " + numFiles + "/" + limit + " saved schematics. Delete some to save this one!",
|
||||
TextColor.RED));
|
||||
log.info(actor.getName() + " failed to save " + file.getCanonicalPath() + " - too many schematics!");
|
||||
throw new WorldEditException(noSlotsErr) {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a transform, bake it into the copy
|
||||
if (transform.isIdentity()) {
|
||||
target = clipboard;
|
||||
} else {
|
||||
FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform);
|
||||
target = new BlockArrayClipboard(result.getTransformedRegion());
|
||||
target.setOrigin(clipboard.getOrigin());
|
||||
Operations.completeLegacy(result.copyTo(target));
|
||||
}
|
||||
|
||||
try (Closer closer = Closer.create()) {
|
||||
FileOutputStream fos = closer.register(new FileOutputStream(file));
|
||||
BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos));
|
||||
ClipboardWriter writer = closer.register(format.getWriter(bos));
|
||||
URI uri = null;
|
||||
if (holder instanceof URIClipboardHolder) {
|
||||
uri = ((URIClipboardHolder) holder).getURI(clipboard);
|
||||
}
|
||||
if (new ActorSaveClipboardEvent(actor, clipboard, uri, file.toURI()).call()) {
|
||||
if (writer instanceof MinecraftStructure) {
|
||||
((MinecraftStructure) writer).write(target, actor.getName());
|
||||
} else {
|
||||
writer.write(target);
|
||||
}
|
||||
|
||||
closer.close(); // release the new .schem file so that its size can be measured
|
||||
double filesizeKb = Files.size(Paths.get(file.getAbsolutePath())) / 1000.0;
|
||||
|
||||
TextComponent filesizeNotif = TextComponent.of( //TODO - to be moved into captions/translatablecomponents
|
||||
SCHEMATIC_NAME + " size: " + String.format("%.1f", filesizeKb) + "kb", TextColor.GRAY);
|
||||
actor.print(filesizeNotif);
|
||||
|
||||
if (checkFilesize) {
|
||||
|
||||
double curKb = filesizeKb + directorysizeKb;
|
||||
int allocatedKb = Settings.IMP.EXPERIMENTAL.PER_PLAYER_FILE_SIZE_LIMIT;
|
||||
|
||||
if (overwrite) {
|
||||
curKb -= oldKbOverwritten;
|
||||
}
|
||||
|
||||
if ((curKb) > allocatedKb) {
|
||||
file.delete();
|
||||
TextComponent notEnoughKbErr = TextComponent.of( //TODO - to be moved into captions/translatablecomponents
|
||||
"You're about to be at " + String.format("%.1f", curKb) + "kb of schematics. ("
|
||||
+ String.format("%dkb", allocatedKb) + " available) Delete some first to save this one!",
|
||||
TextColor.RED);
|
||||
log.info(actor.getName() + " failed to save " + SCHEMATIC_NAME + " - not enough space!");
|
||||
throw new WorldEditException(notEnoughKbErr) {
|
||||
};
|
||||
}
|
||||
if (overwrite) {
|
||||
new File(curFilepath).delete();
|
||||
file.renameTo(new File(curFilepath));
|
||||
} else {
|
||||
numFiles++;
|
||||
}
|
||||
TextComponent kbRemainingNotif = TextComponent.of( //TODO - to be moved into captions/translatablecomponents
|
||||
"You have " + String.format("%.1f", (allocatedKb - curKb)) + "kb left for schematics.", TextColor.GRAY);
|
||||
actor.print(kbRemainingNotif);
|
||||
}
|
||||
|
||||
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && Settings.IMP.EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT > -1) {
|
||||
|
||||
TextComponent slotsRemainingNotif = TextComponent.of( //TODO - to be moved into captions/translatablecomponents
|
||||
"You have " + (Settings.IMP.EXPERIMENTAL.PER_PLAYER_FILE_NUM_LIMIT - numFiles)
|
||||
+ " schematic file slots left.", TextColor.GRAY);
|
||||
actor.print(slotsRemainingNotif);
|
||||
}
|
||||
log.info(actor.getName() + " saved " + file.getCanonicalPath());
|
||||
} else {
|
||||
actor.printError(TranslatableComponent.of("fawe.cancel.worldedit.cancel.reason.manual"));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SchematicListTask implements Callable<Component> {
|
||||
private final String prefix;
|
||||
private final int sortType;
|
||||
private final int page;
|
||||
private final File rootDir;
|
||||
private final String pageCommand;
|
||||
private final String filter;
|
||||
private final String formatName;
|
||||
|
||||
SchematicListTask(String prefix, int sortType, int page, String pageCommand,
|
||||
String filter, String formatName) {
|
||||
this.prefix = prefix;
|
||||
this.sortType = sortType;
|
||||
this.page = page;
|
||||
this.rootDir = WorldEdit.getInstance().getWorkingDirectoryFile(prefix);
|
||||
this.pageCommand = pageCommand;
|
||||
this.filter = filter;
|
||||
this.formatName = formatName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component call() throws Exception {
|
||||
ClipboardFormat format = ClipboardFormats.findByAlias(formatName);
|
||||
List<File> fileList = getFiles(rootDir, filter, format);
|
||||
|
||||
if (fileList == null || fileList.isEmpty()) {
|
||||
return ErrorFormat.wrap("No schematics found.");
|
||||
}
|
||||
|
||||
File[] files = new File[fileList.size()];
|
||||
fileList.toArray(files);
|
||||
// cleanup file list
|
||||
Arrays.sort(files, (f1, f2) -> {
|
||||
// http://stackoverflow.com/questions/203030/best-way-to-list-files-in-java-sorted-by-date-modified
|
||||
int res;
|
||||
if (sortType == 0) { // use name by default
|
||||
int p = f1.getParent().compareTo(f2.getParent());
|
||||
if (p == 0) { // same parent, compare names
|
||||
res = f1.getName().compareTo(f2.getName());
|
||||
} else { // different parent, sort by that
|
||||
res = p;
|
||||
}
|
||||
} else {
|
||||
res = Long.compare(f1.lastModified(), f2.lastModified()); // use date if there is a flag
|
||||
if (sortType == 1) {
|
||||
res = -res; // flip date for newest first instead of oldest first
|
||||
}
|
||||
}
|
||||
return res;
|
||||
});
|
||||
|
||||
PaginationBox paginationBox = new SchematicPaginationBox(prefix, files, pageCommand);
|
||||
return paginationBox.create(page);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SchematicPaginationBox extends PaginationBox {
|
||||
private final String prefix;
|
||||
private final File[] files;
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren