Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-07 20:10:06 +01: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"
|
" - Requires combine_stages = true"
|
||||||
})
|
})
|
||||||
public boolean SEND_BEFORE_HISTORY = false;
|
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 {
|
public static class PLOTSQUARED_INTEGRATION {
|
||||||
|
@ -80,6 +80,7 @@ import java.net.URL;
|
|||||||
import java.nio.channels.Channels;
|
import java.nio.channels.Channels;
|
||||||
import java.nio.channels.ReadableByteChannel;
|
import java.nio.channels.ReadableByteChannel;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
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.checkArgument;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
//import com.boydti.fawe.object.schematic.visualizer.SchemVis;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Commands that work with schematic files.
|
* Commands that work with schematic files.
|
||||||
@ -115,6 +115,31 @@ public class SchematicCommands {
|
|||||||
this.worldEdit = worldEdit;
|
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(
|
@Command(
|
||||||
name = "loadall",
|
name = "loadall",
|
||||||
desc = "Load multiple clipboards (paste will randomly choose one)"
|
desc = "Load multiple clipboards (paste will randomly choose one)"
|
||||||
@ -361,7 +386,7 @@ public class SchematicCommands {
|
|||||||
|
|
||||||
ClipboardHolder holder = session.getClipboard();
|
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)
|
AsyncCommandBuilder.wrap(task, actor)
|
||||||
.registerWithSupervisor(worldEdit.getSupervisor(), "Saving schematic " + filename)
|
.registerWithSupervisor(worldEdit.getSupervisor(), "Saving schematic " + filename)
|
||||||
.sendMessageAfterDelay(TranslatableComponent.of("worldedit.schematic.save.saving"))
|
.sendMessageAfterDelay(TranslatableComponent.of("worldedit.schematic.save.saving"))
|
||||||
@ -559,173 +584,44 @@ public class SchematicCommands {
|
|||||||
}
|
}
|
||||||
msg.append(msgElem);
|
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();
|
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));
|
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(
|
@Command(
|
||||||
name = "delete",
|
name = "delete",
|
||||||
aliases = {"d"},
|
aliases = {"d"},
|
||||||
@ -776,6 +672,246 @@ public class SchematicCommands {
|
|||||||
return false;
|
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 static class SchematicPaginationBox extends PaginationBox {
|
||||||
private final String prefix;
|
private final String prefix;
|
||||||
private final File[] files;
|
private final File[] files;
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren