mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-22 17:27:38 +00:00
feat: schematic share system, add missing Clipboard method for api compat (#2745)
* Allow plugins to register new clipboard share destinations (#1707) * Allow plugins to register new clipboard share destinations * Rename file, as per request * Don't use the base enginehub name for EH_pastebin * Address review comments * Fixed wrong usage * Use a second metadata class for clipboard shares * Newline * Address comments * Improve docs * Apply suggestions from code review Co-authored-by: Octavia Togami <octavia.togami@gmail.com> * Use a consumer so that we handle serialization * Update worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java Co-authored-by: Octavia Togami <octavia.togami@gmail.com> * Update worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestination.java Co-authored-by: Octavia Togami <octavia.togami@gmail.com> * Update worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ShareOutputConsumer.java Co-authored-by: Octavia Togami <octavia.togami@gmail.com> * Update worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ShareOutputConsumer.java Co-authored-by: Octavia Togami <octavia.togami@gmail.com> * Fixed a lot of random comments * Return a consumer from share rather than a URL, allows the share destination to control output Co-authored-by: Octavia Togami <octavia.togami@gmail.com> (cherry picked from commit 6e2b0a1df8a6077c3cf8193e38dc9817038bcbe9) * chore: cleanup cherry-pick remainders * chore/feat: add ark as (default) schematic paster / sharing endpoint * chore: default to fast schematic writer in share * chore: re-format strings.json (seems to adjusted indentation when merging) * chore: hopefully fixing strings.json (again) --------- Co-authored-by: Maddy Miller <mnmiller1@me.com>
This commit is contained in:
parent
7635eec2e4
commit
261ebfa754
@ -668,6 +668,13 @@ public class Settings extends Config {
|
|||||||
@Comment({"The web interface for clipboards", " - All schematics are anonymous and private", " - Downloads can be deleted by the user", " - Supports clipboard uploads, downloads and saves",})
|
@Comment({"The web interface for clipboards", " - All schematics are anonymous and private", " - Downloads can be deleted by the user", " - Supports clipboard uploads, downloads and saves",})
|
||||||
public String URL = "https://schem.intellectualsites.com/fawe/";
|
public String URL = "https://schem.intellectualsites.com/fawe/";
|
||||||
|
|
||||||
|
@Comment({"The url of the backend server (Arkitektonika)"})
|
||||||
|
public String ARKITEKTONIKA_BACKEND_URL = "https://api.schematic.cloud/";
|
||||||
|
@Comment({"The url used to generate a download link from.", "{key} will be replaced with the generated key"})
|
||||||
|
public String ARKITEKTONIKA_DOWNLOAD_URL = "https://schematic.cloud/download/{key}";
|
||||||
|
@Comment({"The url used to generate a deletion link from.", "{key} will be replaced with the generated key"})
|
||||||
|
public String ARKITEKTONIKA_DELETE_URL = "https://schematic.cloud/delete/{key}";
|
||||||
|
|
||||||
@Comment("The maximum amount of time in seconds the plugin can attempt to load images for.")
|
@Comment("The maximum amount of time in seconds the plugin can attempt to load images for.")
|
||||||
public int MAX_IMAGE_LOAD_TIME = 5;
|
public int MAX_IMAGE_LOAD_TIME = 5;
|
||||||
|
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
package com.fastasyncworldedit.core.util.arkitektonika;
|
||||||
|
|
||||||
|
public record ArkitektonikaResponse(String downloadKey, String deletionKey) {
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
package com.fastasyncworldedit.core.util.arkitektonika;
|
||||||
|
|
||||||
|
import com.fastasyncworldedit.core.internal.exception.FaweException;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.share.ClipboardShareMetadata;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.share.ShareOutputProvider;
|
||||||
|
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||||
|
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class ArkitektonikaSchematicUploader {
|
||||||
|
|
||||||
|
private static final String BOUNDARY_IDENTIFIER = "--";
|
||||||
|
private static final HttpClient HTTP_CLIENT = HttpClient.newHttpClient();
|
||||||
|
private final String apiUrl;
|
||||||
|
|
||||||
|
public ArkitektonikaSchematicUploader(String apiUrl) {
|
||||||
|
this.apiUrl = apiUrl.endsWith("/") ? apiUrl.substring(0, apiUrl.length() - 1) : apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArkitektonikaResponse uploadBlocking(ClipboardShareMetadata meta, ShareOutputProvider provider) throws IOException,
|
||||||
|
InterruptedException {
|
||||||
|
String boundary = UUID.randomUUID().toString();
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
provider.writeTo(outputStream);
|
||||||
|
|
||||||
|
final HttpRequest.BodyPublisher bodyPublisher = HttpRequest.BodyPublishers.concat(
|
||||||
|
HttpRequest.BodyPublishers.ofString(BOUNDARY_IDENTIFIER + boundary + "\r\n"),
|
||||||
|
HttpRequest.BodyPublishers.ofString("Content-Disposition: form-data; name=\"schematic\"; filename=\"" + meta.name() + "." + meta.format().getPrimaryFileExtension() + "\"\r\n\r\n"),
|
||||||
|
HttpRequest.BodyPublishers.ofByteArray(outputStream.toByteArray()),
|
||||||
|
HttpRequest.BodyPublishers.ofString("\r\n" + BOUNDARY_IDENTIFIER + boundary + BOUNDARY_IDENTIFIER)
|
||||||
|
);
|
||||||
|
|
||||||
|
final HttpResponse<String> response = HTTP_CLIENT.send(HttpRequest.newBuilder()
|
||||||
|
.uri(URI.create(this.apiUrl + "/upload"))
|
||||||
|
.header("Content-Type", "multipart/form-data; boundary=\"" + boundary + "\"")
|
||||||
|
.POST(bodyPublisher).build(), HttpResponse.BodyHandlers.ofString());
|
||||||
|
if (response.statusCode() != 200) {
|
||||||
|
throw new FaweException(TextComponent
|
||||||
|
.of("Arkitektonika returned status code " + response.statusCode())
|
||||||
|
.color(TextColor.RED));
|
||||||
|
}
|
||||||
|
JsonObject json = JsonParser.parseString(response.body()).getAsJsonObject();
|
||||||
|
return new ArkitektonikaResponse(
|
||||||
|
json.get("download_key").getAsString(),
|
||||||
|
json.get("delete_key").getAsString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -340,7 +340,7 @@ public class ClipboardCommands {
|
|||||||
aliases = {"/download"},
|
aliases = {"/download"},
|
||||||
desc = "Downloads your clipboard through the configured web interface"
|
desc = "Downloads your clipboard through the configured web interface"
|
||||||
)
|
)
|
||||||
@Deprecated
|
@Deprecated(forRemoval = true, since = "TODO")
|
||||||
@CommandPermissions({"worldedit.clipboard.download"})
|
@CommandPermissions({"worldedit.clipboard.download"})
|
||||||
public void download(
|
public void download(
|
||||||
final Actor actor,
|
final Actor actor,
|
||||||
@ -402,10 +402,7 @@ public class ClipboardCommands {
|
|||||||
final Clipboard target;
|
final Clipboard target;
|
||||||
// If we have a transform, bake it into the copy
|
// If we have a transform, bake it into the copy
|
||||||
if (!transform.isIdentity()) {
|
if (!transform.isIdentity()) {
|
||||||
final FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform);
|
target = clipboard.transform(transform);
|
||||||
target = new BlockArrayClipboard(result.getTransformedRegion(), actor.getUniqueId());
|
|
||||||
target.setOrigin(clipboard.getOrigin());
|
|
||||||
Operations.completeLegacy(result.copyTo(target));
|
|
||||||
} else {
|
} else {
|
||||||
target = clipboard;
|
target = clipboard;
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ import com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder;
|
|||||||
import com.fastasyncworldedit.core.extent.clipboard.URIClipboardHolder;
|
import com.fastasyncworldedit.core.extent.clipboard.URIClipboardHolder;
|
||||||
import com.fastasyncworldedit.core.extent.clipboard.io.schematic.MinecraftStructure;
|
import com.fastasyncworldedit.core.extent.clipboard.io.schematic.MinecraftStructure;
|
||||||
import com.fastasyncworldedit.core.util.MainUtil;
|
import com.fastasyncworldedit.core.util.MainUtil;
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
import com.sk89q.worldedit.LocalConfiguration;
|
import com.sk89q.worldedit.LocalConfiguration;
|
||||||
import com.sk89q.worldedit.LocalSession;
|
import com.sk89q.worldedit.LocalSession;
|
||||||
@ -38,13 +37,13 @@ import com.sk89q.worldedit.command.util.CommandPermissions;
|
|||||||
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
|
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
|
||||||
import com.sk89q.worldedit.extension.platform.Actor;
|
import com.sk89q.worldedit.extension.platform.Actor;
|
||||||
import com.sk89q.worldedit.extension.platform.Capability;
|
import com.sk89q.worldedit.extension.platform.Capability;
|
||||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
|
||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
||||||
import com.sk89q.worldedit.function.operation.Operations;
|
import com.sk89q.worldedit.extent.clipboard.io.share.ClipboardShareDestination;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.share.ClipboardShareMetadata;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||||
import com.sk89q.worldedit.math.transform.Transform;
|
import com.sk89q.worldedit.math.transform.Transform;
|
||||||
@ -61,19 +60,15 @@ import com.sk89q.worldedit.util.formatting.text.format.TextColor;
|
|||||||
import com.sk89q.worldedit.util.io.Closer;
|
import com.sk89q.worldedit.util.io.Closer;
|
||||||
import com.sk89q.worldedit.util.io.file.FilenameException;
|
import com.sk89q.worldedit.util.io.file.FilenameException;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import com.sk89q.worldedit.util.paste.EngineHubPaste;
|
|
||||||
import com.sk89q.worldedit.util.paste.PasteMetadata;
|
|
||||||
import org.enginehub.piston.annotation.Command;
|
import org.enginehub.piston.annotation.Command;
|
||||||
import org.enginehub.piston.annotation.CommandContainer;
|
import org.enginehub.piston.annotation.CommandContainer;
|
||||||
import org.enginehub.piston.annotation.param.Arg;
|
import org.enginehub.piston.annotation.param.Arg;
|
||||||
import org.enginehub.piston.annotation.param.ArgFlag;
|
import org.enginehub.piston.annotation.param.ArgFlag;
|
||||||
import org.enginehub.piston.annotation.param.Switch;
|
import org.enginehub.piston.annotation.param.Switch;
|
||||||
import org.enginehub.piston.exception.CommandException;
|
|
||||||
import org.enginehub.piston.exception.StopExecutionException;
|
import org.enginehub.piston.exception.StopExecutionException;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
@ -85,11 +80,9 @@ 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.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -98,6 +91,7 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -321,7 +315,7 @@ public class SchematicCommands {
|
|||||||
Actor actor, LocalSession session,
|
Actor actor, LocalSession session,
|
||||||
@Arg(desc = "File name.")
|
@Arg(desc = "File name.")
|
||||||
String filename,
|
String filename,
|
||||||
//FAWE start - random rotation
|
//FAWE start - use format-name, random rotation
|
||||||
@Arg(desc = "Format name.", def = "")
|
@Arg(desc = "Format name.", def = "")
|
||||||
String formatName,
|
String formatName,
|
||||||
@Switch(name = 'r', desc = "Apply random rotation to the clipboard")
|
@Switch(name = 'r', desc = "Apply random rotation to the clipboard")
|
||||||
@ -445,8 +439,8 @@ public class SchematicCommands {
|
|||||||
Actor actor, LocalSession session,
|
Actor actor, LocalSession session,
|
||||||
@Arg(desc = "File name.")
|
@Arg(desc = "File name.")
|
||||||
String filename,
|
String filename,
|
||||||
@Arg(desc = "Format name.", def = "fast")
|
@Arg(desc = "Format name.", def = "fast") //FAWE: def: sponge -> fast
|
||||||
String formatName,
|
ClipboardFormat format,
|
||||||
@Switch(name = 'f', desc = "Overwrite an existing file.")
|
@Switch(name = 'f', desc = "Overwrite an existing file.")
|
||||||
boolean allowOverwrite,
|
boolean allowOverwrite,
|
||||||
//FAWE start
|
//FAWE start
|
||||||
@ -474,12 +468,6 @@ public class SchematicCommands {
|
|||||||
dir = new File(dir, actor.getUniqueId().toString());
|
dir = new File(dir, actor.getUniqueId().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
ClipboardFormat format = ClipboardFormats.findByAlias(formatName);
|
|
||||||
if (format == null) {
|
|
||||||
actor.print(Caption.of("worldedit.schematic.unknown-format", TextComponent.of(formatName)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean other = false;
|
boolean other = false;
|
||||||
if (filename.contains("../")) {
|
if (filename.contains("../")) {
|
||||||
other = true;
|
other = true;
|
||||||
@ -551,35 +539,98 @@ public class SchematicCommands {
|
|||||||
@CommandPermissions({ "worldedit.clipboard.share", "worldedit.schematic.share" })
|
@CommandPermissions({ "worldedit.clipboard.share", "worldedit.schematic.share" })
|
||||||
public void share(Actor actor, LocalSession session,
|
public void share(Actor actor, LocalSession session,
|
||||||
@Arg(desc = "Schematic name. Defaults to name-millis", def = "")
|
@Arg(desc = "Schematic name. Defaults to name-millis", def = "")
|
||||||
String schematicName,
|
String schematicName,
|
||||||
@Arg(desc = "Format name.", def = "sponge")
|
@Arg(desc = "Share location", def = "arkitektonika") //FAWE: def: ehpaste -> arkitektonika
|
||||||
String formatName) throws WorldEditException {
|
ClipboardShareDestination destination,
|
||||||
if (true) {
|
@Arg(desc = "Format name", def = "fast") //FAWE: def: sponge -> fast
|
||||||
throw new UnsupportedOperationException("This feature is currently not implemented");
|
ClipboardFormat format) throws WorldEditException {
|
||||||
}
|
|
||||||
if (worldEdit.getPlatformManager().queryCapability(Capability.GAME_HOOKS).getDataVersion() == -1) {
|
if (worldEdit.getPlatformManager().queryCapability(Capability.GAME_HOOKS).getDataVersion() == -1) {
|
||||||
actor.printError(TranslatableComponent.of("worldedit.schematic.unsupported-minecraft-version"));
|
actor.printError(TranslatableComponent.of("worldedit.schematic.unsupported-minecraft-version"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClipboardFormat format = ClipboardFormats.findByAlias(formatName);
|
|
||||||
if (format == null) {
|
if (format == null) {
|
||||||
actor.printError(TranslatableComponent.of("worldedit.schematic.unknown-format", TextComponent.of(formatName)));
|
format = destination.getDefaultFormat();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!destination.supportsFormat(format)) {
|
||||||
|
actor.printError(Caption.of( //FAWE: TranslatableComponent -> Caption
|
||||||
|
"worldedit.schematic.share.unsupported-format",
|
||||||
|
TextComponent.of(destination.getName()),
|
||||||
|
TextComponent.of(format.getName())
|
||||||
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClipboardHolder holder = session.getClipboard();
|
ClipboardHolder holder = session.getClipboard();
|
||||||
|
|
||||||
SchematicShareTask task = new SchematicShareTask(actor, format, holder, schematicName);
|
SchematicShareTask task = new SchematicShareTask(actor, holder, destination, format, schematicName);
|
||||||
AsyncCommandBuilder.wrap(task, actor)
|
AsyncCommandBuilder.wrap(task, actor)
|
||||||
.registerWithSupervisor(worldEdit.getSupervisor(), "Sharing schematic")
|
.registerWithSupervisor(worldEdit.getSupervisor(), "Sharing schematic")
|
||||||
.setDelayMessage(TranslatableComponent.of("worldedit.schematic.save.saving"))
|
.setDelayMessage(TranslatableComponent.of("worldedit.schematic.save.saving"))
|
||||||
.setWorkingMessage(TranslatableComponent.of("worldedit.schematic.save.still-saving"))
|
.setWorkingMessage(TranslatableComponent.of("worldedit.schematic.save.still-saving"))
|
||||||
.onSuccess("Shared", (url -> actor.printInfo(TextComponent.of(url.toExternalForm() + ".schem").clickEvent(ClickEvent.openUrl(url.toExternalForm() + ".schem")))))
|
.onSuccess("Shared", (consumer -> consumer.accept(actor)))
|
||||||
.onFailure("Failed to share schematic", worldEdit.getPlatformManager().getPlatformCommandManager().getExceptionConverter())
|
.onFailure("Failed to share schematic", worldEdit.getPlatformManager().getPlatformCommandManager().getExceptionConverter())
|
||||||
.buildAndExec(worldEdit.getExecutorService());
|
.buildAndExec(worldEdit.getExecutorService());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
name = "delete",
|
||||||
|
aliases = {"d"},
|
||||||
|
desc = "Delete a saved schematic"
|
||||||
|
)
|
||||||
|
@CommandPermissions("worldedit.schematic.delete")
|
||||||
|
public void delete(
|
||||||
|
Actor actor, LocalSession session,
|
||||||
|
@Arg(desc = "File name.")
|
||||||
|
String filename
|
||||||
|
) throws WorldEditException, IOException {
|
||||||
|
LocalConfiguration config = worldEdit.getConfiguration();
|
||||||
|
//FAWE start
|
||||||
|
File working = worldEdit.getWorkingDirectoryPath(config.saveDir).toFile();
|
||||||
|
File dir = Settings.settings().PATHS.PER_PLAYER_SCHEMATICS ? new File(working, actor.getUniqueId().toString()) : working;
|
||||||
|
List<File> files = new ArrayList<>();
|
||||||
|
|
||||||
|
if (filename.equalsIgnoreCase("*")) {
|
||||||
|
files.addAll(getFiles(session.getClipboard()));
|
||||||
|
} else {
|
||||||
|
File f = MainUtil.resolveRelative(new File(dir, filename));
|
||||||
|
files.add(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (files.isEmpty()) {
|
||||||
|
actor.print(Caption.of("worldedit.schematic.delete.does-not-exist", TextComponent.of(filename)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (File f : files) {
|
||||||
|
if (!MainUtil.isInSubDirectory(working, f) || !f.exists()) {
|
||||||
|
actor.print(Caption.of("worldedit.schematic.delete.does-not-exist", TextComponent.of(filename)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && !MainUtil.isInSubDirectory(dir, f) && !actor.hasPermission(
|
||||||
|
"worldedit.schematic.delete.other")) {
|
||||||
|
actor.print(Caption.of("fawe.error.no-perm", "worldedit.schematic.delete.other"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!deleteFile(f)) {
|
||||||
|
actor.print(Caption.of("worldedit.schematic.delete.failed", TextComponent.of(filename)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
actor.print(Caption.of("worldedit.schematic.delete.deleted", filename));
|
||||||
|
}
|
||||||
|
//FAWE end
|
||||||
|
}
|
||||||
|
|
||||||
|
//FAWE start
|
||||||
|
private boolean deleteFile(File file) {
|
||||||
|
if (file.delete()) {
|
||||||
|
new File(file.getParentFile(), "." + file.getName() + ".cached").delete();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//FAWE end
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
name = "formats",
|
name = "formats",
|
||||||
aliases = {"listformats", "f"},
|
aliases = {"listformats", "f"},
|
||||||
@ -764,68 +815,11 @@ public class SchematicCommands {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(
|
|
||||||
name = "delete",
|
|
||||||
aliases = {"d"},
|
|
||||||
desc = "Delete a saved schematic"
|
|
||||||
)
|
|
||||||
@CommandPermissions("worldedit.schematic.delete")
|
|
||||||
public void delete(
|
|
||||||
Actor actor, LocalSession session,
|
|
||||||
@Arg(desc = "File name.")
|
|
||||||
String filename
|
|
||||||
) throws WorldEditException, IOException {
|
|
||||||
LocalConfiguration config = worldEdit.getConfiguration();
|
|
||||||
File working = worldEdit.getWorkingDirectoryPath(config.saveDir).toFile();
|
|
||||||
//FAWE start
|
|
||||||
File dir = Settings.settings().PATHS.PER_PLAYER_SCHEMATICS ? new File(working, actor.getUniqueId().toString()) : working;
|
|
||||||
List<File> files = new ArrayList<>();
|
|
||||||
|
|
||||||
if (filename.equalsIgnoreCase("*")) {
|
|
||||||
files.addAll(getFiles(session.getClipboard()));
|
|
||||||
} else {
|
|
||||||
File f = MainUtil.resolveRelative(new File(dir, filename));
|
|
||||||
files.add(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (files.isEmpty()) {
|
|
||||||
actor.print(Caption.of("worldedit.schematic.delete.does-not-exist", TextComponent.of(filename)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (File f : files) {
|
|
||||||
if (!MainUtil.isInSubDirectory(working, f) || !f.exists()) {
|
|
||||||
actor.print(Caption.of("worldedit.schematic.delete.does-not-exist", TextComponent.of(filename)));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (Settings.settings().PATHS.PER_PLAYER_SCHEMATICS && !MainUtil.isInSubDirectory(dir, f) && !actor.hasPermission(
|
|
||||||
"worldedit.schematic.delete.other")) {
|
|
||||||
actor.print(Caption.of("fawe.error.no-perm", "worldedit.schematic.delete.other"));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!deleteFile(f)) {
|
|
||||||
actor.print(Caption.of("worldedit.schematic.delete.failed", TextComponent.of(filename)));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
actor.print(Caption.of("worldedit.schematic.delete.deleted", filename));
|
|
||||||
}
|
|
||||||
//FAWE end
|
|
||||||
}
|
|
||||||
|
|
||||||
//FAWE start
|
|
||||||
private boolean deleteFile(File file) {
|
|
||||||
if (file.delete()) {
|
|
||||||
new File(file.getParentFile(), "." + file.getName() + ".cached").delete();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
//FAWE end
|
|
||||||
|
|
||||||
private static class SchematicLoadTask implements Callable<ClipboardHolder> {
|
private static class SchematicLoadTask implements Callable<ClipboardHolder> {
|
||||||
|
|
||||||
private final Actor actor;
|
private final Actor actor;
|
||||||
private final ClipboardFormat format;
|
|
||||||
private final File file;
|
private final File file;
|
||||||
|
private final ClipboardFormat format;
|
||||||
|
|
||||||
SchematicLoadTask(Actor actor, File file, ClipboardFormat format) {
|
SchematicLoadTask(Actor actor, File file, ClipboardFormat format) {
|
||||||
this.actor = actor;
|
this.actor = actor;
|
||||||
@ -863,19 +857,10 @@ public class SchematicCommands {
|
|||||||
this.holder = holder;
|
this.holder = holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeToOutputStream(OutputStream outputStream) throws Exception {
|
protected void writeToOutputStream(OutputStream outputStream) throws IOException, WorldEditException {
|
||||||
Clipboard clipboard = holder.getClipboard();
|
Clipboard clipboard = holder.getClipboard();
|
||||||
Transform transform = holder.getTransform();
|
Transform transform = holder.getTransform();
|
||||||
Clipboard target;
|
Clipboard target = clipboard.transform(transform);
|
||||||
// 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()) {
|
try (Closer closer = Closer.create()) {
|
||||||
OutputStream stream = closer.register(outputStream);
|
OutputStream stream = closer.register(outputStream);
|
||||||
@ -887,9 +872,10 @@ public class SchematicCommands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class SchematicSaveTask extends SchematicOutputTask<Void> {
|
private static class SchematicSaveTask extends SchematicOutputTask<Void> {
|
||||||
private File file;
|
private final Actor actor;
|
||||||
|
private File file; //FAWE: un-finalize
|
||||||
private final boolean overwrite;
|
private final boolean overwrite;
|
||||||
private final File rootDir;
|
private final File rootDir; //FAWE: add root-dir
|
||||||
|
|
||||||
SchematicSaveTask(
|
SchematicSaveTask(
|
||||||
Actor actor,
|
Actor actor,
|
||||||
@ -900,9 +886,10 @@ public class SchematicCommands {
|
|||||||
boolean overwrite
|
boolean overwrite
|
||||||
) {
|
) {
|
||||||
super(actor, format, holder);
|
super(actor, format, holder);
|
||||||
|
this.actor = actor;
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.rootDir = rootDir;
|
|
||||||
this.overwrite = overwrite;
|
this.overwrite = overwrite;
|
||||||
|
this.rootDir = rootDir; //FAWE: add root-dir
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -975,10 +962,7 @@ public class SchematicCommands {
|
|||||||
if (transform.isIdentity()) {
|
if (transform.isIdentity()) {
|
||||||
target = clipboard;
|
target = clipboard;
|
||||||
} else {
|
} else {
|
||||||
FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform);
|
target = clipboard.transform(transform);
|
||||||
target = new BlockArrayClipboard(result.getTransformedRegion());
|
|
||||||
target.setOrigin(clipboard.getOrigin());
|
|
||||||
Operations.completeLegacy(result.copyTo(target));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try (Closer closer = Closer.create()) {
|
try (Closer closer = Closer.create()) {
|
||||||
@ -1062,29 +1046,31 @@ public class SchematicCommands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class SchematicShareTask extends SchematicOutputTask<URL> {
|
private static class SchematicShareTask extends SchematicOutputTask<Consumer<Actor>> {
|
||||||
|
private final Actor actor;
|
||||||
private final String name;
|
private final String name;
|
||||||
|
private final ClipboardShareDestination destination;
|
||||||
|
|
||||||
SchematicShareTask(Actor actor, ClipboardFormat format, ClipboardHolder holder, String name) {
|
SchematicShareTask(Actor actor,
|
||||||
|
ClipboardHolder holder,
|
||||||
|
ClipboardShareDestination destination,
|
||||||
|
ClipboardFormat format,
|
||||||
|
String name) {
|
||||||
super(actor, format, holder);
|
super(actor, format, holder);
|
||||||
|
this.actor = actor;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.destination = destination;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URL call() throws Exception {
|
public Consumer<Actor> call() throws Exception {
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ClipboardShareMetadata metadata = new ClipboardShareMetadata(
|
||||||
try {
|
format,
|
||||||
writeToOutputStream(baos);
|
this.actor.getName(),
|
||||||
} catch (Exception e) {
|
name == null ? actor.getName() + "-" + System.currentTimeMillis() : name
|
||||||
throw new CommandException(TextComponent.of(e.getMessage()), e, ImmutableList.of());
|
);
|
||||||
}
|
|
||||||
|
|
||||||
EngineHubPaste pasteService = new EngineHubPaste();
|
return destination.share(metadata, this::writeToOutputStream);
|
||||||
PasteMetadata metadata = new PasteMetadata();
|
|
||||||
metadata.author = this.actor.getName();
|
|
||||||
metadata.extension = "schem";
|
|
||||||
metadata.name = name == null ? actor.getName() + "-" + System.currentTimeMillis() : name;
|
|
||||||
return pasteService.paste(new String(Base64.getEncoder().encode(baos.toByteArray()), StandardCharsets.UTF_8), metadata).call();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.command.argument;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.share.ClipboardShareDestination;
|
||||||
|
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||||
|
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||||
|
import org.enginehub.piston.CommandManager;
|
||||||
|
import org.enginehub.piston.converter.ArgumentConverter;
|
||||||
|
import org.enginehub.piston.converter.ConversionResult;
|
||||||
|
import org.enginehub.piston.converter.FailedConversion;
|
||||||
|
import org.enginehub.piston.converter.SuccessfulConversion;
|
||||||
|
import org.enginehub.piston.inject.InjectedValueAccess;
|
||||||
|
import org.enginehub.piston.inject.Key;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix;
|
||||||
|
|
||||||
|
public class ClipboardFormatConverter implements ArgumentConverter<ClipboardFormat> {
|
||||||
|
|
||||||
|
public static void register(CommandManager commandManager) {
|
||||||
|
commandManager.registerConverter(Key.of(ClipboardFormat.class),
|
||||||
|
new ClipboardFormatConverter()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final TextComponent choices;
|
||||||
|
|
||||||
|
private ClipboardFormatConverter() {
|
||||||
|
this.choices = TextComponent.of("any clipboard format");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component describeAcceptableArguments() {
|
||||||
|
return this.choices;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getSuggestions(String input, InjectedValueAccess context) {
|
||||||
|
ClipboardShareDestination destination = context.injectedValue(Key.of(ClipboardShareDestination.class)).orElse(null);
|
||||||
|
|
||||||
|
return limitByPrefix(ClipboardFormats.getAll().stream()
|
||||||
|
.filter(format -> destination == null || destination.supportsFormat(format))
|
||||||
|
.map(ClipboardFormat::getAliases)
|
||||||
|
.flatMap(Set::stream), input);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConversionResult<ClipboardFormat> convert(String s, InjectedValueAccess injectedValueAccess) {
|
||||||
|
ClipboardFormat result = ClipboardFormats.findByAlias(s);
|
||||||
|
return result == null
|
||||||
|
? FailedConversion.from(new IllegalArgumentException("Not a valid schematic format: " + s))
|
||||||
|
: SuccessfulConversion.fromSingle(result);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.command.argument;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.share.ClipboardShareDestination;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.share.ClipboardShareDestinations;
|
||||||
|
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||||
|
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||||
|
import org.enginehub.piston.CommandManager;
|
||||||
|
import org.enginehub.piston.converter.ArgumentConverter;
|
||||||
|
import org.enginehub.piston.converter.ConversionResult;
|
||||||
|
import org.enginehub.piston.converter.FailedConversion;
|
||||||
|
import org.enginehub.piston.converter.SuccessfulConversion;
|
||||||
|
import org.enginehub.piston.inject.InjectedValueAccess;
|
||||||
|
import org.enginehub.piston.inject.Key;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix;
|
||||||
|
|
||||||
|
public class ClipboardShareDestinationConverter implements ArgumentConverter<ClipboardShareDestination> {
|
||||||
|
|
||||||
|
public static void register(CommandManager commandManager) {
|
||||||
|
commandManager.registerConverter(Key.of(ClipboardShareDestination.class),
|
||||||
|
new ClipboardShareDestinationConverter()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final TextComponent choices;
|
||||||
|
|
||||||
|
private ClipboardShareDestinationConverter() {
|
||||||
|
this.choices = TextComponent.of("any clipboard share destination");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component describeAcceptableArguments() {
|
||||||
|
return this.choices;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getSuggestions(String input, InjectedValueAccess context) {
|
||||||
|
return limitByPrefix(ClipboardShareDestinations.getAll().stream()
|
||||||
|
.map(ClipboardShareDestination::getAliases)
|
||||||
|
.flatMap(Set::stream), input);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConversionResult<ClipboardShareDestination> convert(String s, InjectedValueAccess injectedValueAccess) {
|
||||||
|
ClipboardShareDestination result = ClipboardShareDestinations.findByAlias(s);
|
||||||
|
return result == null
|
||||||
|
? FailedConversion.from(new IllegalArgumentException("Not a valid clipboard share destination: " + s))
|
||||||
|
: SuccessfulConversion.fromSingle(result);
|
||||||
|
}
|
||||||
|
}
|
@ -86,6 +86,8 @@ import com.sk89q.worldedit.command.WorldEditCommandsRegistration;
|
|||||||
import com.sk89q.worldedit.command.argument.Arguments;
|
import com.sk89q.worldedit.command.argument.Arguments;
|
||||||
import com.sk89q.worldedit.command.argument.BooleanConverter;
|
import com.sk89q.worldedit.command.argument.BooleanConverter;
|
||||||
import com.sk89q.worldedit.command.argument.Chunk3dVectorConverter;
|
import com.sk89q.worldedit.command.argument.Chunk3dVectorConverter;
|
||||||
|
import com.sk89q.worldedit.command.argument.ClipboardFormatConverter;
|
||||||
|
import com.sk89q.worldedit.command.argument.ClipboardShareDestinationConverter;
|
||||||
import com.sk89q.worldedit.command.argument.CommaSeparatedValuesConverter;
|
import com.sk89q.worldedit.command.argument.CommaSeparatedValuesConverter;
|
||||||
import com.sk89q.worldedit.command.argument.DirectionConverter;
|
import com.sk89q.worldedit.command.argument.DirectionConverter;
|
||||||
import com.sk89q.worldedit.command.argument.DirectionVectorConverter;
|
import com.sk89q.worldedit.command.argument.DirectionVectorConverter;
|
||||||
@ -174,7 +176,6 @@ import java.util.stream.Stream;
|
|||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the registration and invocation of commands.
|
* Handles the registration and invocation of commands.
|
||||||
*
|
*
|
||||||
@ -272,6 +273,8 @@ public final class PlatformCommandManager {
|
|||||||
SideEffectConverter.register(commandManager);
|
SideEffectConverter.register(commandManager);
|
||||||
HeightConverter.register(commandManager);
|
HeightConverter.register(commandManager);
|
||||||
OffsetConverter.register(worldEdit, commandManager);
|
OffsetConverter.register(worldEdit, commandManager);
|
||||||
|
ClipboardFormatConverter.register(commandManager);
|
||||||
|
ClipboardShareDestinationConverter.register(commandManager);
|
||||||
//FAWE start
|
//FAWE start
|
||||||
commandManager.registerConverter(
|
commandManager.registerConverter(
|
||||||
Key.of(com.sk89q.worldedit.function.pattern.Pattern.class, Annotations.patternList()),
|
Key.of(com.sk89q.worldedit.function.pattern.Pattern.class, Annotations.patternList()),
|
||||||
@ -604,7 +607,6 @@ public final class PlatformCommandManager {
|
|||||||
void registerCommandsWith(Platform platform) {
|
void registerCommandsWith(Platform platform) {
|
||||||
LOGGER.info("Registering commands with " + platform.getClass().getCanonicalName());
|
LOGGER.info("Registering commands with " + platform.getClass().getCanonicalName());
|
||||||
|
|
||||||
|
|
||||||
LocalConfiguration config = platform.getConfiguration();
|
LocalConfiguration config = platform.getConfiguration();
|
||||||
boolean logging = config.logCommands;
|
boolean logging = config.logCommands;
|
||||||
String path = config.logFile;
|
String path = config.logFile;
|
||||||
|
@ -31,6 +31,7 @@ import com.sk89q.worldedit.EditSession;
|
|||||||
import com.sk89q.worldedit.EditSessionBuilder;
|
import com.sk89q.worldedit.EditSessionBuilder;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
import com.sk89q.worldedit.entity.Entity;
|
import com.sk89q.worldedit.entity.Entity;
|
||||||
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
import com.sk89q.worldedit.extent.Extent;
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
||||||
@ -40,6 +41,7 @@ import com.sk89q.worldedit.function.mask.Mask;
|
|||||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||||
import com.sk89q.worldedit.function.operation.Operations;
|
import com.sk89q.worldedit.function.operation.Operations;
|
||||||
import com.sk89q.worldedit.math.BlockVector2;
|
import com.sk89q.worldedit.math.BlockVector2;
|
||||||
|
import com.sk89q.worldedit.internal.util.ClipboardTransformBaker;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.math.transform.Transform;
|
import com.sk89q.worldedit.math.transform.Transform;
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
@ -98,7 +100,7 @@ public interface Clipboard extends Extent, Iterable<BlockVector3>, Closeable, Fl
|
|||||||
* - {@link DiskOptimizedClipboard}
|
* - {@link DiskOptimizedClipboard}
|
||||||
* - {@link CPUOptimizedClipboard}
|
* - {@link CPUOptimizedClipboard}
|
||||||
* - {@link MemoryOptimizedClipboard}
|
* - {@link MemoryOptimizedClipboard}
|
||||||
*
|
*
|
||||||
* @deprecated Internal use only. Use {@link BlockArrayClipboard#BlockArrayClipboard(Region, UUID)}
|
* @deprecated Internal use only. Use {@link BlockArrayClipboard#BlockArrayClipboard(Region, UUID)}
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@ -144,10 +146,9 @@ public interface Clipboard extends Extent, Iterable<BlockVector3>, Closeable, Fl
|
|||||||
void setOrigin(BlockVector3 origin);
|
void setOrigin(BlockVector3 origin);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the clipboard has biome data. This can be checked since {@link Extent#getBiome(BlockVector2)}
|
* Returns true if the clipboard has biome data. This can be checked since {@link Extent#getBiome(BlockVector3)}
|
||||||
* strongly suggests returning {@link com.sk89q.worldedit.world.biome.BiomeTypes#OCEAN} instead of {@code null}
|
* strongly suggests returning {@link com.sk89q.worldedit.world.biome.BiomeTypes#OCEAN} instead of {@code null}
|
||||||
* if biomes aren't present. However, it might not be desired to set areas to ocean if the clipboard is defaulting
|
* if biomes aren't present.
|
||||||
* to ocean, instead of having biomes explicitly set.
|
|
||||||
*
|
*
|
||||||
* @return true if the clipboard has biome data set
|
* @return true if the clipboard has biome data set
|
||||||
*/
|
*/
|
||||||
@ -155,6 +156,21 @@ public interface Clipboard extends Extent, Iterable<BlockVector3>, Closeable, Fl
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a clipboard with a given transform baked in.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Note: This method may return the same clipboard object, if a copy is needed then you should check the returned value for identity equality and copy if needed.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param transform The transform
|
||||||
|
* @return The new clipboard
|
||||||
|
* @throws WorldEditException if the copy encounters an error
|
||||||
|
*/
|
||||||
|
default Clipboard transform(Transform transform) throws WorldEditException {
|
||||||
|
return ClipboardTransformBaker.bakeTransform(this, transform);
|
||||||
|
}
|
||||||
|
|
||||||
//FAWE start
|
//FAWE start
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,7 +73,7 @@ public class ClipboardFormats {
|
|||||||
checkNotNull(format);
|
checkNotNull(format);
|
||||||
|
|
||||||
for (String key : format.getAliases()) {
|
for (String key : format.getAliases()) {
|
||||||
String lowKey = key.toLowerCase(Locale.ENGLISH);
|
String lowKey = key.toLowerCase(Locale.ROOT);
|
||||||
ClipboardFormat old = aliasMap.put(lowKey, format);
|
ClipboardFormat old = aliasMap.put(lowKey, format);
|
||||||
if (old != null) {
|
if (old != null) {
|
||||||
aliasMap.put(lowKey, old);
|
aliasMap.put(lowKey, old);
|
||||||
@ -83,7 +83,7 @@ public class ClipboardFormats {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (String ext : format.getFileExtensions()) {
|
for (String ext : format.getFileExtensions()) {
|
||||||
String lowExt = ext.toLowerCase(Locale.ENGLISH);
|
String lowExt = ext.toLowerCase(Locale.ROOT);
|
||||||
fileExtensionMap.put(lowExt, format);
|
fileExtensionMap.put(lowExt, format);
|
||||||
}
|
}
|
||||||
registeredFormats.add(format);
|
registeredFormats.add(format);
|
||||||
@ -104,7 +104,7 @@ public class ClipboardFormats {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public static ClipboardFormat findByAlias(String alias) {
|
public static ClipboardFormat findByAlias(String alias) {
|
||||||
checkNotNull(alias);
|
checkNotNull(alias);
|
||||||
return aliasMap.get(alias.toLowerCase(Locale.ENGLISH).trim());
|
return aliasMap.get(alias.toLowerCase(Locale.ROOT).trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.extent.clipboard.io.share;
|
||||||
|
|
||||||
|
import com.fastasyncworldedit.core.configuration.Caption;
|
||||||
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
|
import com.fastasyncworldedit.core.util.arkitektonika.ArkitektonikaResponse;
|
||||||
|
import com.fastasyncworldedit.core.util.arkitektonika.ArkitektonikaSchematicUploader;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.sk89q.worldedit.extension.platform.Actor;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||||
|
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||||
|
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
|
||||||
|
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
|
||||||
|
import com.sk89q.worldedit.util.paste.EngineHubPaste;
|
||||||
|
import com.sk89q.worldedit.util.paste.PasteMetadata;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A collection of natively supported clipboard share destinations.
|
||||||
|
*/
|
||||||
|
public enum BuiltInClipboardShareDestinations implements ClipboardShareDestination {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The EngineHub pastebin service, at https://paste.enginehub.org/
|
||||||
|
*/
|
||||||
|
ENGINEHUB_PASTEBIN("enginehub_paste", "ehpaste") {
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "EngineHub Paste";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Consumer<Actor> share(ClipboardShareMetadata metadata, ShareOutputProvider serializer) throws Exception {
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
serializer.writeTo(outputStream);
|
||||||
|
|
||||||
|
PasteMetadata pasteMetadata = new PasteMetadata();
|
||||||
|
pasteMetadata.author = metadata.author();
|
||||||
|
pasteMetadata.extension = "schem";
|
||||||
|
pasteMetadata.name = metadata.name();
|
||||||
|
EngineHubPaste pasteService = new EngineHubPaste();
|
||||||
|
|
||||||
|
URL url = pasteService.paste(new String(
|
||||||
|
Base64.getEncoder().encode(outputStream.toByteArray()),
|
||||||
|
StandardCharsets.UTF_8
|
||||||
|
), pasteMetadata).call();
|
||||||
|
String urlString = url.toExternalForm() + ".schem";
|
||||||
|
return actor -> actor.printInfo(TextComponent.of(urlString).clickEvent(ClickEvent.openUrl(urlString)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClipboardFormat getDefaultFormat() {
|
||||||
|
return BuiltInClipboardFormat.SPONGE_SCHEMATIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsFormat(ClipboardFormat format) {
|
||||||
|
return format == getDefaultFormat();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
//FAWE start - add arkitektonika
|
||||||
|
ARKITEKTONIKA("arkitektonika", "fawe") {
|
||||||
|
|
||||||
|
private ArkitektonikaSchematicUploader uploader;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Arkitektonika";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Consumer<Actor> share(final ClipboardShareMetadata metadata, final ShareOutputProvider serializer) throws
|
||||||
|
Exception {
|
||||||
|
if (uploader == null) {
|
||||||
|
uploader = new ArkitektonikaSchematicUploader(Settings.settings().WEB.ARKITEKTONIKA_BACKEND_URL);
|
||||||
|
}
|
||||||
|
final ArkitektonikaResponse response = uploader.uploadBlocking(metadata, serializer);
|
||||||
|
final String downloadUrl = Settings.settings().WEB.ARKITEKTONIKA_DOWNLOAD_URL.replace("{key}", response.downloadKey());
|
||||||
|
final String deletionUrl = Settings.settings().WEB.ARKITEKTONIKA_DELETE_URL.replace("{key}", response.deletionKey());
|
||||||
|
return actor -> {
|
||||||
|
actor.print(Caption.of(
|
||||||
|
"worldedit.schematic.share.response.arkitektonika.download",
|
||||||
|
Caption.of("worldedit.schematic.share.response.arkitektonika.click-here")
|
||||||
|
.color(TextColor.GREEN).clickEvent(ClickEvent.openUrl(downloadUrl))
|
||||||
|
));
|
||||||
|
actor.print(Caption.of(
|
||||||
|
"worldedit.schematic.share.response.arkitektonika.delete",
|
||||||
|
Caption.of("worldedit.schematic.share.response.arkitektonika.click-here")
|
||||||
|
.color(TextColor.RED).clickEvent(ClickEvent.openUrl(deletionUrl))
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClipboardFormat getDefaultFormat() {
|
||||||
|
return BuiltInClipboardFormat.FAST;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsFormat(final ClipboardFormat format) {
|
||||||
|
return format == BuiltInClipboardFormat.SPONGE_SCHEMATIC ||
|
||||||
|
format == BuiltInClipboardFormat.FAST ||
|
||||||
|
format == BuiltInClipboardFormat.MCEDIT_SCHEMATIC;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//FAWE end
|
||||||
|
|
||||||
|
private final ImmutableSet<String> aliases;
|
||||||
|
|
||||||
|
BuiltInClipboardShareDestinations(String... aliases) {
|
||||||
|
this.aliases = ImmutableSet.copyOf(aliases);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImmutableSet<String> getAliases() {
|
||||||
|
return this.aliases;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.extent.clipboard.io.share;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.extension.platform.Actor;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public interface ClipboardShareDestination {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of this share destination.
|
||||||
|
*
|
||||||
|
* @return The name
|
||||||
|
*/
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a set of aliases.
|
||||||
|
*
|
||||||
|
* @return a set of aliases
|
||||||
|
*/
|
||||||
|
Set<String> getAliases();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Share a clipboard output stream and return a URL.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The serialized schematic can be retrieved by providing an {@link java.io.OutputStream} to {@code serializer}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param metadata The clipboard metadata
|
||||||
|
* @param serializer A function taking the {@link java.io.OutputStream}
|
||||||
|
* @return A consumer to provide the actor with the share results
|
||||||
|
* @throws Exception if it failed to share
|
||||||
|
*/
|
||||||
|
Consumer<Actor> share(ClipboardShareMetadata metadata, ShareOutputProvider serializer) throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the default clipboard format for this share destination.
|
||||||
|
*
|
||||||
|
* @return The default format
|
||||||
|
*/
|
||||||
|
ClipboardFormat getDefaultFormat();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether the share destination supports the given format.
|
||||||
|
*
|
||||||
|
* @param format The format
|
||||||
|
* @return If it's supported
|
||||||
|
*/
|
||||||
|
boolean supportsFormat(ClipboardFormat format);
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.extent.clipboard.io.share;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
|
||||||
|
public class ClipboardShareDestinations {
|
||||||
|
|
||||||
|
private static final Map<String, ClipboardShareDestination> aliasMap = new HashMap<>();
|
||||||
|
private static final List<ClipboardShareDestination> registeredDestinations = new ArrayList<>();
|
||||||
|
|
||||||
|
public static void registerClipboardShareDestination(ClipboardShareDestination destination) {
|
||||||
|
checkNotNull(destination);
|
||||||
|
checkState(destination.supportsFormat(destination.getDefaultFormat()), "Destination must accept its default format");
|
||||||
|
|
||||||
|
for (String key : destination.getAliases()) {
|
||||||
|
String lowKey = key.toLowerCase(Locale.ROOT);
|
||||||
|
ClipboardShareDestination old = aliasMap.put(lowKey, destination);
|
||||||
|
if (old != null) {
|
||||||
|
aliasMap.put(lowKey, old);
|
||||||
|
WorldEdit.logger.warn(destination.getClass().getName() + " cannot override existing alias '" + lowKey + "' used by " + old.getClass().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
registeredDestinations.add(destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (BuiltInClipboardShareDestinations destination : BuiltInClipboardShareDestinations.values()) {
|
||||||
|
registerClipboardShareDestination(destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the clipboard format named by the given alias.
|
||||||
|
*
|
||||||
|
* @param alias the alias
|
||||||
|
* @return the format, otherwise null if none is matched
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static ClipboardShareDestination findByAlias(String alias) {
|
||||||
|
checkNotNull(alias);
|
||||||
|
return aliasMap.get(alias.toLowerCase(Locale.ROOT).trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Collection<ClipboardShareDestination> getAll() {
|
||||||
|
return Collections.unmodifiableCollection(registeredDestinations);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClipboardShareDestinations() {
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.extent.clipboard.io.share;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Items of metadata about shared clipboards.
|
||||||
|
*/
|
||||||
|
public class ClipboardShareMetadata {
|
||||||
|
private final ClipboardFormat format;
|
||||||
|
private final String name;
|
||||||
|
private final String author;
|
||||||
|
|
||||||
|
public ClipboardShareMetadata(ClipboardFormat format, String name, String author) {
|
||||||
|
this.format = format;
|
||||||
|
this.name = name;
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClipboardFormat format() {
|
||||||
|
return this.format;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String author() {
|
||||||
|
return this.author;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.extent.clipboard.io.share;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ShareOutputProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the share output to {@code stream}.
|
||||||
|
*
|
||||||
|
* @throws IOException if it failed
|
||||||
|
* @throws WorldEditException if WorldEdit failed to serialize to the stream
|
||||||
|
*/
|
||||||
|
void writeTo(OutputStream stream) throws IOException, WorldEditException;
|
||||||
|
}
|
@ -17,13 +17,16 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.sk89q.worldedit.command;
|
package com.sk89q.worldedit.internal.util;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
import com.sk89q.worldedit.extent.Extent;
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
|
import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
|
||||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||||
import com.sk89q.worldedit.function.operation.Operation;
|
import com.sk89q.worldedit.function.operation.Operation;
|
||||||
|
import com.sk89q.worldedit.function.operation.Operations;
|
||||||
import com.sk89q.worldedit.math.Vector3;
|
import com.sk89q.worldedit.math.Vector3;
|
||||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||||
import com.sk89q.worldedit.math.transform.CombinedTransform;
|
import com.sk89q.worldedit.math.transform.CombinedTransform;
|
||||||
@ -36,12 +39,10 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||||||
/**
|
/**
|
||||||
* Helper class to 'bake' a transform into a clipboard.
|
* Helper class to 'bake' a transform into a clipboard.
|
||||||
*
|
*
|
||||||
* <p>This class needs a better name and may need to be made more generic.</p>
|
|
||||||
*
|
|
||||||
* @see Clipboard
|
* @see Clipboard
|
||||||
* @see Transform
|
* @see Transform
|
||||||
*/
|
*/
|
||||||
public class FlattenedClipboardTransform {
|
public class ClipboardTransformBaker {
|
||||||
|
|
||||||
private final Clipboard original;
|
private final Clipboard original;
|
||||||
private final Transform transform;
|
private final Transform transform;
|
||||||
@ -52,7 +53,7 @@ public class FlattenedClipboardTransform {
|
|||||||
* @param original the original clipboard
|
* @param original the original clipboard
|
||||||
* @param transform the transform
|
* @param transform the transform
|
||||||
*/
|
*/
|
||||||
private FlattenedClipboardTransform(Clipboard original, Transform transform) {
|
private ClipboardTransformBaker(Clipboard original, Transform transform) {
|
||||||
checkNotNull(original);
|
checkNotNull(original);
|
||||||
checkNotNull(transform);
|
checkNotNull(transform);
|
||||||
this.original = original;
|
this.original = original;
|
||||||
@ -64,7 +65,7 @@ public class FlattenedClipboardTransform {
|
|||||||
*
|
*
|
||||||
* @return the transformed region
|
* @return the transformed region
|
||||||
*/
|
*/
|
||||||
public Region getTransformedRegion() {
|
private Region getTransformedRegion() {
|
||||||
Region region = original.getRegion();
|
Region region = original.getRegion();
|
||||||
Vector3 minimum = region.getMinimumPoint().toVector3();
|
Vector3 minimum = region.getMinimumPoint().toVector3();
|
||||||
Vector3 maximum = region.getMaximumPoint().toVector3();
|
Vector3 maximum = region.getMaximumPoint().toVector3();
|
||||||
@ -73,8 +74,7 @@ public class FlattenedClipboardTransform {
|
|||||||
new CombinedTransform(
|
new CombinedTransform(
|
||||||
new AffineTransform().translate(original.getOrigin().multiply(-1)),
|
new AffineTransform().translate(original.getOrigin().multiply(-1)),
|
||||||
transform,
|
transform,
|
||||||
new AffineTransform().translate(original.getOrigin())
|
new AffineTransform().translate(original.getOrigin()));
|
||||||
);
|
|
||||||
|
|
||||||
Vector3[] corners = new Vector3[]{
|
Vector3[] corners = new Vector3[]{
|
||||||
minimum,
|
minimum,
|
||||||
@ -113,7 +113,7 @@ public class FlattenedClipboardTransform {
|
|||||||
* @param target the target
|
* @param target the target
|
||||||
* @return the operation
|
* @return the operation
|
||||||
*/
|
*/
|
||||||
public Operation copyTo(Extent target) {
|
private Operation copyTo(Extent target) {
|
||||||
//FAWE start
|
//FAWE start
|
||||||
Extent extent = original;
|
Extent extent = original;
|
||||||
if (transform != null && !transform.isIdentity()) {
|
if (transform != null && !transform.isIdentity()) {
|
||||||
@ -121,11 +121,7 @@ public class FlattenedClipboardTransform {
|
|||||||
}
|
}
|
||||||
//FAWE end
|
//FAWE end
|
||||||
ForwardExtentCopy copy = new ForwardExtentCopy(
|
ForwardExtentCopy copy = new ForwardExtentCopy(
|
||||||
extent,
|
extent, original.getRegion(), original.getOrigin(), target, original.getOrigin()
|
||||||
original.getRegion(),
|
|
||||||
original.getOrigin(),
|
|
||||||
target,
|
|
||||||
original.getOrigin()
|
|
||||||
);
|
);
|
||||||
copy.setTransform(transform);
|
copy.setTransform(transform);
|
||||||
if (original.hasBiomes()) {
|
if (original.hasBiomes()) {
|
||||||
@ -140,9 +136,18 @@ public class FlattenedClipboardTransform {
|
|||||||
* @param original the original clipboard
|
* @param original the original clipboard
|
||||||
* @param transform the transform
|
* @param transform the transform
|
||||||
* @return a builder
|
* @return a builder
|
||||||
|
* @throws WorldEditException if an error occurred during copy
|
||||||
*/
|
*/
|
||||||
public static FlattenedClipboardTransform transform(Clipboard original, Transform transform) {
|
public static Clipboard bakeTransform(Clipboard original, Transform transform) throws WorldEditException {
|
||||||
return new FlattenedClipboardTransform(original, transform);
|
if (transform.isIdentity()) {
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
ClipboardTransformBaker baker = new ClipboardTransformBaker(original, transform);
|
||||||
|
Clipboard target = new BlockArrayClipboard(baker.getTransformedRegion());
|
||||||
|
target.setOrigin(original.getOrigin());
|
||||||
|
Operations.complete(baker.copyTo(target));
|
||||||
|
|
||||||
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -360,6 +360,11 @@
|
|||||||
"worldedit.schematic.save.already-exists": "That schematic already exists. Use the -f flag to overwrite it.",
|
"worldedit.schematic.save.already-exists": "That schematic already exists. Use the -f flag to overwrite it.",
|
||||||
"worldedit.schematic.save.failed-directory": "Could not create folder for schematics!",
|
"worldedit.schematic.save.failed-directory": "Could not create folder for schematics!",
|
||||||
"worldedit.schematic.save.saving": "(Please wait... saving schematic.)",
|
"worldedit.schematic.save.saving": "(Please wait... saving schematic.)",
|
||||||
|
"worldedit.schematic.save.still-saving": "(Please wait... still saving schematic.)",
|
||||||
|
"worldedit.schematic.share.unsupported-format": "The schematic share destination \"{0}\" does not support the \"{1}\" format.",
|
||||||
|
"worldedit.schematic.share.response.arkitektonika.download" : "Download: {0}",
|
||||||
|
"worldedit.schematic.share.response.arkitektonika.delete" : "Delete: {0}",
|
||||||
|
"worldedit.schematic.share.response.arkitektonika.click-here" : "[Click here]",
|
||||||
"worldedit.schematic.delete.empty": "Schematic {0} not found!",
|
"worldedit.schematic.delete.empty": "Schematic {0} not found!",
|
||||||
"worldedit.schematic.delete.does-not-exist": "Schematic {0} does not exist!",
|
"worldedit.schematic.delete.does-not-exist": "Schematic {0} does not exist!",
|
||||||
"worldedit.schematic.delete.failed": "Deletion of {0} failed! Is it read-only?",
|
"worldedit.schematic.delete.failed": "Deletion of {0} failed! Is it read-only?",
|
||||||
|
Loading…
Reference in New Issue
Block a user