From 7635eec2e47f8caf1454f3744c3949990c9cf41e Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 2 Jun 2024 17:11:53 +0200 Subject: [PATCH 01/15] fix: improve how we determine if using FAWE from jenkins (#2754) - SNAPSHOT will usually only be removed if it's a release version - If others remove SNAPSHOT, then they're probably doing their own stuff, just use this as the "release" check - fixes #2744 --- .../com/fastasyncworldedit/core/util/UpdateNotification.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/UpdateNotification.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/UpdateNotification.java index 73ad01361..fdfe7c56c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/UpdateNotification.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/UpdateNotification.java @@ -59,12 +59,12 @@ public class UpdateNotification { Document doc = db.parse(body); faweVersion = doc.getElementsByTagName("lastSuccessfulBuild").item(0).getFirstChild().getTextContent(); FaweVersion faweVersion = Fawe.instance().getVersion(); - if (faweVersion.build == 0 && !faweVersion.snapshot) { + if (faweVersion.build == 0 && faweVersion.snapshot) { LOGGER.warn("You are using a snapshot or a custom version of FAWE. This is not an official build distributed " + "via https://www.spigotmc.org/resources/13932/"); return; } - if (faweVersion.build < Integer.parseInt(UpdateNotification.faweVersion)) { + if (faweVersion.snapshot && faweVersion.build < Integer.parseInt(UpdateNotification.faweVersion)) { hasUpdate = true; int versionDifference = Integer.parseInt(UpdateNotification.faweVersion) - faweVersion.build; LOGGER.warn( From 261ebfa754c1a2e4ffd4e44aa6952e0a5e73b0b1 Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Sun, 2 Jun 2024 18:21:56 +0200 Subject: [PATCH 02/15] 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 * 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 * Update worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestination.java Co-authored-by: Octavia Togami * Update worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ShareOutputConsumer.java Co-authored-by: Octavia Togami * Update worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ShareOutputConsumer.java Co-authored-by: Octavia Togami * 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 (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 --- .../core/configuration/Settings.java | 7 + .../arkitektonika/ArkitektonikaResponse.java | 4 + .../ArkitektonikaSchematicUploader.java | 58 +++++ .../worldedit/command/ClipboardCommands.java | 7 +- .../worldedit/command/SchematicCommands.java | 224 ++++++++---------- .../argument/ClipboardFormatConverter.java | 76 ++++++ .../ClipboardShareDestinationConverter.java | 72 ++++++ .../platform/PlatformCommandManager.java | 6 +- .../worldedit/extent/clipboard/Clipboard.java | 24 +- .../extent/clipboard/io/ClipboardFormats.java | 6 +- .../BuiltInClipboardShareDestinations.java | 149 ++++++++++++ .../io/share/ClipboardShareDestination.java | 72 ++++++ .../io/share/ClipboardShareDestinations.java | 80 +++++++ .../io/share/ClipboardShareMetadata.java | 49 ++++ .../io/share/ShareOutputProvider.java | 37 +++ .../util/ClipboardTransformBaker.java} | 37 +-- .../src/main/resources/lang/strings.json | 5 + 17 files changed, 764 insertions(+), 149 deletions(-) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/util/arkitektonika/ArkitektonikaResponse.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/util/arkitektonika/ArkitektonikaSchematicUploader.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ClipboardFormatConverter.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ClipboardShareDestinationConverter.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/BuiltInClipboardShareDestinations.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestination.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestinations.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareMetadata.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ShareOutputProvider.java rename worldedit-core/src/main/java/com/sk89q/worldedit/{command/FlattenedClipboardTransform.java => internal/util/ClipboardTransformBaker.java} (79%) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index 33c8c94f0..cf0ba6f35 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -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",}) 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.") public int MAX_IMAGE_LOAD_TIME = 5; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/arkitektonika/ArkitektonikaResponse.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/arkitektonika/ArkitektonikaResponse.java new file mode 100644 index 000000000..821751c2a --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/arkitektonika/ArkitektonikaResponse.java @@ -0,0 +1,4 @@ +package com.fastasyncworldedit.core.util.arkitektonika; + +public record ArkitektonikaResponse(String downloadKey, String deletionKey) { +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/arkitektonika/ArkitektonikaSchematicUploader.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/arkitektonika/ArkitektonikaSchematicUploader.java new file mode 100644 index 000000000..152bca058 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/arkitektonika/ArkitektonikaSchematicUploader.java @@ -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 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() + ); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index b4037ba15..8c0b69ec9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -340,7 +340,7 @@ public class ClipboardCommands { aliases = {"/download"}, desc = "Downloads your clipboard through the configured web interface" ) - @Deprecated + @Deprecated(forRemoval = true, since = "TODO") @CommandPermissions({"worldedit.clipboard.download"}) public void download( final Actor actor, @@ -402,10 +402,7 @@ public class ClipboardCommands { final Clipboard target; // If we have a transform, bake it into the copy if (!transform.isIdentity()) { - final FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform); - target = new BlockArrayClipboard(result.getTransformedRegion(), actor.getUniqueId()); - target.setOrigin(clipboard.getOrigin()); - Operations.completeLegacy(result.copyTo(target)); + target = clipboard.transform(transform); } else { target = clipboard; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index e711e61ee..920a24901 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -26,7 +26,6 @@ import com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder; import com.fastasyncworldedit.core.extent.clipboard.URIClipboardHolder; import com.fastasyncworldedit.core.extent.clipboard.io.schematic.MinecraftStructure; import com.fastasyncworldedit.core.util.MainUtil; -import com.google.common.collect.ImmutableList; import com.google.common.collect.Multimap; import com.sk89q.worldedit.LocalConfiguration; 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.extension.platform.Actor; 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.io.ClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; 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.math.transform.AffineTransform; 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.file.FilenameException; 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.CommandContainer; import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.Switch; -import org.enginehub.piston.exception.CommandException; import org.enginehub.piston.exception.StopExecutionException; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -85,11 +80,9 @@ import java.net.URL; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.io.OutputStream; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Base64; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -98,6 +91,7 @@ import java.util.Map; import java.util.Objects; import java.util.UUID; import java.util.concurrent.Callable; +import java.util.function.Consumer; import java.util.concurrent.ThreadLocalRandom; import java.util.function.Function; import java.util.regex.Pattern; @@ -321,7 +315,7 @@ public class SchematicCommands { Actor actor, LocalSession session, @Arg(desc = "File name.") String filename, - //FAWE start - random rotation + //FAWE start - use format-name, random rotation @Arg(desc = "Format name.", def = "") String formatName, @Switch(name = 'r', desc = "Apply random rotation to the clipboard") @@ -445,8 +439,8 @@ public class SchematicCommands { Actor actor, LocalSession session, @Arg(desc = "File name.") String filename, - @Arg(desc = "Format name.", def = "fast") - String formatName, + @Arg(desc = "Format name.", def = "fast") //FAWE: def: sponge -> fast + ClipboardFormat format, @Switch(name = 'f', desc = "Overwrite an existing file.") boolean allowOverwrite, //FAWE start @@ -474,12 +468,6 @@ public class SchematicCommands { 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; if (filename.contains("../")) { other = true; @@ -551,35 +539,98 @@ public class SchematicCommands { @CommandPermissions({ "worldedit.clipboard.share", "worldedit.schematic.share" }) public void share(Actor actor, LocalSession session, @Arg(desc = "Schematic name. Defaults to name-millis", def = "") - String schematicName, - @Arg(desc = "Format name.", def = "sponge") - String formatName) throws WorldEditException { - if (true) { - throw new UnsupportedOperationException("This feature is currently not implemented"); - } + String schematicName, + @Arg(desc = "Share location", def = "arkitektonika") //FAWE: def: ehpaste -> arkitektonika + ClipboardShareDestination destination, + @Arg(desc = "Format name", def = "fast") //FAWE: def: sponge -> fast + ClipboardFormat format) throws WorldEditException { if (worldEdit.getPlatformManager().queryCapability(Capability.GAME_HOOKS).getDataVersion() == -1) { actor.printError(TranslatableComponent.of("worldedit.schematic.unsupported-minecraft-version")); return; } - ClipboardFormat format = ClipboardFormats.findByAlias(formatName); 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; } 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) .registerWithSupervisor(worldEdit.getSupervisor(), "Sharing schematic") .setDelayMessage(TranslatableComponent.of("worldedit.schematic.save.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()) .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 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( name = "formats", 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 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 { private final Actor actor; - private final ClipboardFormat format; private final File file; + private final ClipboardFormat format; SchematicLoadTask(Actor actor, File file, ClipboardFormat format) { this.actor = actor; @@ -863,19 +857,10 @@ public class SchematicCommands { this.holder = holder; } - protected void writeToOutputStream(OutputStream outputStream) throws Exception { + protected void writeToOutputStream(OutputStream outputStream) throws IOException, WorldEditException { 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)); - } + Clipboard target = clipboard.transform(transform); try (Closer closer = Closer.create()) { OutputStream stream = closer.register(outputStream); @@ -887,9 +872,10 @@ public class SchematicCommands { } private static class SchematicSaveTask extends SchematicOutputTask { - private File file; + private final Actor actor; + private File file; //FAWE: un-finalize private final boolean overwrite; - private final File rootDir; + private final File rootDir; //FAWE: add root-dir SchematicSaveTask( Actor actor, @@ -900,9 +886,10 @@ public class SchematicCommands { boolean overwrite ) { super(actor, format, holder); + this.actor = actor; this.file = file; - this.rootDir = rootDir; this.overwrite = overwrite; + this.rootDir = rootDir; //FAWE: add root-dir } @Override @@ -975,10 +962,7 @@ public class SchematicCommands { 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)); + target = clipboard.transform(transform); } try (Closer closer = Closer.create()) { @@ -1062,29 +1046,31 @@ public class SchematicCommands { } } - private static class SchematicShareTask extends SchematicOutputTask { + private static class SchematicShareTask extends SchematicOutputTask> { + private final Actor actor; 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); + this.actor = actor; this.name = name; + this.destination = destination; } @Override - public URL call() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try { - writeToOutputStream(baos); - } catch (Exception e) { - throw new CommandException(TextComponent.of(e.getMessage()), e, ImmutableList.of()); - } + public Consumer call() throws Exception { + ClipboardShareMetadata metadata = new ClipboardShareMetadata( + format, + this.actor.getName(), + name == null ? actor.getName() + "-" + System.currentTimeMillis() : name + ); - EngineHubPaste pasteService = new EngineHubPaste(); - 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(); + return destination.share(metadata, this::writeToOutputStream); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ClipboardFormatConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ClipboardFormatConverter.java new file mode 100644 index 000000000..cfa0a1ed4 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ClipboardFormatConverter.java @@ -0,0 +1,76 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * 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 . + */ + +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 { + + 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 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 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); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ClipboardShareDestinationConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ClipboardShareDestinationConverter.java new file mode 100644 index 000000000..5af81bb1d --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ClipboardShareDestinationConverter.java @@ -0,0 +1,72 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * 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 . + */ + +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 { + + 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 getSuggestions(String input, InjectedValueAccess context) { + return limitByPrefix(ClipboardShareDestinations.getAll().stream() + .map(ClipboardShareDestination::getAliases) + .flatMap(Set::stream), input); + } + + @Override + public ConversionResult 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); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 7b493cf98..b03e4ce54 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -86,6 +86,8 @@ import com.sk89q.worldedit.command.WorldEditCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.command.argument.BooleanConverter; 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.DirectionConverter; import com.sk89q.worldedit.command.argument.DirectionVectorConverter; @@ -174,7 +176,6 @@ import java.util.stream.Stream; import static com.google.common.base.Preconditions.checkNotNull; - /** * Handles the registration and invocation of commands. * @@ -272,6 +273,8 @@ public final class PlatformCommandManager { SideEffectConverter.register(commandManager); HeightConverter.register(commandManager); OffsetConverter.register(worldEdit, commandManager); + ClipboardFormatConverter.register(commandManager); + ClipboardShareDestinationConverter.register(commandManager); //FAWE start commandManager.registerConverter( Key.of(com.sk89q.worldedit.function.pattern.Pattern.class, Annotations.patternList()), @@ -604,7 +607,6 @@ public final class PlatformCommandManager { void registerCommandsWith(Platform platform) { LOGGER.info("Registering commands with " + platform.getClass().getCanonicalName()); - LocalConfiguration config = platform.getConfiguration(); boolean logging = config.logCommands; String path = config.logFile; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java index d52fd1056..4cd2ead97 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java @@ -31,6 +31,7 @@ import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSessionBuilder; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; 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.Operations; import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.internal.util.ClipboardTransformBaker; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.Region; @@ -98,7 +100,7 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl * - {@link DiskOptimizedClipboard} * - {@link CPUOptimizedClipboard} * - {@link MemoryOptimizedClipboard} - * + * * @deprecated Internal use only. Use {@link BlockArrayClipboard#BlockArrayClipboard(Region, UUID)} */ @Deprecated @@ -144,10 +146,9 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl 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} - * if biomes aren't present. However, it might not be desired to set areas to ocean if the clipboard is defaulting - * to ocean, instead of having biomes explicitly set. + * if biomes aren't present. * * @return true if the clipboard has biome data set */ @@ -155,6 +156,21 @@ public interface Clipboard extends Extent, Iterable, Closeable, Fl return false; } + /** + * Returns a clipboard with a given transform baked in. + * + *

+ * 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. + *

+ * + * @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 /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java index 03cce5d80..b69a7a0cc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java @@ -73,7 +73,7 @@ public class ClipboardFormats { checkNotNull(format); for (String key : format.getAliases()) { - String lowKey = key.toLowerCase(Locale.ENGLISH); + String lowKey = key.toLowerCase(Locale.ROOT); ClipboardFormat old = aliasMap.put(lowKey, format); if (old != null) { aliasMap.put(lowKey, old); @@ -83,7 +83,7 @@ public class ClipboardFormats { } } for (String ext : format.getFileExtensions()) { - String lowExt = ext.toLowerCase(Locale.ENGLISH); + String lowExt = ext.toLowerCase(Locale.ROOT); fileExtensionMap.put(lowExt, format); } registeredFormats.add(format); @@ -104,7 +104,7 @@ public class ClipboardFormats { @Nullable public static ClipboardFormat findByAlias(String alias) { checkNotNull(alias); - return aliasMap.get(alias.toLowerCase(Locale.ENGLISH).trim()); + return aliasMap.get(alias.toLowerCase(Locale.ROOT).trim()); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/BuiltInClipboardShareDestinations.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/BuiltInClipboardShareDestinations.java new file mode 100644 index 000000000..981debe4b --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/BuiltInClipboardShareDestinations.java @@ -0,0 +1,149 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * 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 . + */ + +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 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 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 aliases; + + BuiltInClipboardShareDestinations(String... aliases) { + this.aliases = ImmutableSet.copyOf(aliases); + } + + @Override + public ImmutableSet getAliases() { + return this.aliases; + } + + @Override + public String getName() { + return name(); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestination.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestination.java new file mode 100644 index 000000000..1b0cb9e21 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestination.java @@ -0,0 +1,72 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * 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 . + */ + +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 getAliases(); + + /** + * Share a clipboard output stream and return a URL. + * + *

+ * The serialized schematic can be retrieved by providing an {@link java.io.OutputStream} to {@code serializer}. + *

+ * + * @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 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); +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestinations.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestinations.java new file mode 100644 index 000000000..cf9b408f1 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareDestinations.java @@ -0,0 +1,80 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * 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 . + */ + +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 aliasMap = new HashMap<>(); + private static final List 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 getAll() { + return Collections.unmodifiableCollection(registeredDestinations); + } + + private ClipboardShareDestinations() { + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareMetadata.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareMetadata.java new file mode 100644 index 000000000..2e5f6c042 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareMetadata.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * 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 . + */ + +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; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ShareOutputProvider.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ShareOutputProvider.java new file mode 100644 index 000000000..6d7587925 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ShareOutputProvider.java @@ -0,0 +1,37 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * 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 . + */ + +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; +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/ClipboardTransformBaker.java similarity index 79% rename from worldedit-core/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/ClipboardTransformBaker.java index d32504ad4..daa969080 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/ClipboardTransformBaker.java @@ -17,13 +17,16 @@ * along with this program. If not, see . */ -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.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.transform.BlockTransformExtent; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; 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.transform.AffineTransform; 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. * - *

This class needs a better name and may need to be made more generic.

- * * @see Clipboard * @see Transform */ -public class FlattenedClipboardTransform { +public class ClipboardTransformBaker { private final Clipboard original; private final Transform transform; @@ -52,7 +53,7 @@ public class FlattenedClipboardTransform { * @param original the original clipboard * @param transform the transform */ - private FlattenedClipboardTransform(Clipboard original, Transform transform) { + private ClipboardTransformBaker(Clipboard original, Transform transform) { checkNotNull(original); checkNotNull(transform); this.original = original; @@ -64,7 +65,7 @@ public class FlattenedClipboardTransform { * * @return the transformed region */ - public Region getTransformedRegion() { + private Region getTransformedRegion() { Region region = original.getRegion(); Vector3 minimum = region.getMinimumPoint().toVector3(); Vector3 maximum = region.getMaximumPoint().toVector3(); @@ -73,8 +74,7 @@ public class FlattenedClipboardTransform { new CombinedTransform( new AffineTransform().translate(original.getOrigin().multiply(-1)), transform, - new AffineTransform().translate(original.getOrigin()) - ); + new AffineTransform().translate(original.getOrigin())); Vector3[] corners = new Vector3[]{ minimum, @@ -113,7 +113,7 @@ public class FlattenedClipboardTransform { * @param target the target * @return the operation */ - public Operation copyTo(Extent target) { + private Operation copyTo(Extent target) { //FAWE start Extent extent = original; if (transform != null && !transform.isIdentity()) { @@ -121,11 +121,7 @@ public class FlattenedClipboardTransform { } //FAWE end ForwardExtentCopy copy = new ForwardExtentCopy( - extent, - original.getRegion(), - original.getOrigin(), - target, - original.getOrigin() + extent, original.getRegion(), original.getOrigin(), target, original.getOrigin() ); copy.setTransform(transform); if (original.hasBiomes()) { @@ -140,9 +136,18 @@ public class FlattenedClipboardTransform { * @param original the original clipboard * @param transform the transform * @return a builder + * @throws WorldEditException if an error occurred during copy */ - public static FlattenedClipboardTransform transform(Clipboard original, Transform transform) { - return new FlattenedClipboardTransform(original, transform); + public static Clipboard bakeTransform(Clipboard original, Transform transform) throws WorldEditException { + 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; } } diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index c343dd623..c67da38d7 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -360,6 +360,11 @@ "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.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.does-not-exist": "Schematic {0} does not exist!", "worldedit.schematic.delete.failed": "Deletion of {0} failed! Is it read-only?", From c41e38202c959f6f89c56e945800f16866c0081e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 00:48:40 +0000 Subject: [PATCH 03/15] Update dependency com.palmergames.bukkit.towny:towny to v0.100.2.12 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 38f8f3f32..d6bf97dcb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.2.11" +towny = "0.100.2.12" plotsquared = "7.3.8" # Third party From da81530f869e0f3269eeabad89b2a8ed93396c4d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 00:48:46 +0000 Subject: [PATCH 04/15] Update dependency net.kyori:adventure-platform-bukkit to v4.3.3 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d6bf97dcb..12c34eeca 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -22,7 +22,7 @@ bstats = "3.0.2" sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.17.0" -adventure-bukkit = "4.3.2" +adventure-bukkit = "4.3.3" checkerqual = "3.43.0" truezip = "6.8.4" auto-value = "1.10.4" From e044b92d45bad2536b881418cf52b1eab8b2b9ae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 03:30:53 +0000 Subject: [PATCH 05/15] Update dependency paperweight-userdev --- worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts | 2 +- worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts index 821b6c52d..c82a5bd55 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_4/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.4-R0.1-SNAPSHOT - the().paperDevBundle("1.20.4-R0.1-20240424.165410-174") + the().paperDevBundle("1.20.4-R0.1-20240528.102248-175") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts index 8f97a8454..43bc53f15 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/ - the().paperDevBundle("1.20.6-R0.1-20240526.222003-87") + the().paperDevBundle("1.20.6-R0.1-20240602.222958-106") compileOnly(libs.paperlib) } From 393ed005245bd51f1251a5e62664a237af87d37b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 03:30:58 +0000 Subject: [PATCH 06/15] Update eps1lon/actions-label-merge-conflict action to v3.0.2 --- .github/workflows/label-merge-conflicts.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-merge-conflicts.yaml b/.github/workflows/label-merge-conflicts.yaml index 551b39417..8a2c30125 100644 --- a/.github/workflows/label-merge-conflicts.yaml +++ b/.github/workflows/label-merge-conflicts.yaml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Label conflicting PRs - uses: eps1lon/actions-label-merge-conflict@v3.0.1 + uses: eps1lon/actions-label-merge-conflict@v3.0.2 with: dirtyLabel: "unresolved-merge-conflict" repoToken: "${{ secrets.GITHUB_TOKEN }}" From a82ba31185e9142c8ce0b12d83d2a9d0ad573df6 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sun, 2 Jun 2024 09:23:31 +0100 Subject: [PATCH 07/15] feat: allow NBT on wand items - closes #2383 --- .../core/util/gson/BaseItemAdapter.java | 61 +++++++++++++ .../com/sk89q/worldedit/LocalSession.java | 87 ++++++++++++++----- .../com/sk89q/worldedit/blocks/BaseItem.java | 1 + .../worldedit/command/SelectionCommands.java | 32 ++++--- .../sk89q/worldedit/command/ToolCommands.java | 4 +- .../util/PropertiesConfiguration.java | 4 +- .../worldedit/util/YAMLConfiguration.java | 4 +- .../sk89q/worldedit/util/gson/GsonUtil.java | 3 + 8 files changed, 156 insertions(+), 40 deletions(-) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/BaseItemAdapter.java diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/BaseItemAdapter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/BaseItemAdapter.java new file mode 100644 index 000000000..859ed9194 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/BaseItemAdapter.java @@ -0,0 +1,61 @@ +package com.fastasyncworldedit.core.util.gson; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.util.nbt.TagStringIO; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.item.ItemTypes; + +import java.io.IOException; +import java.lang.reflect.Type; + +public final class BaseItemAdapter implements JsonDeserializer, JsonSerializer { + + @Override + public BaseItem deserialize(JsonElement json, Type type, JsonDeserializationContext cont) throws JsonParseException { + JsonObject jsonObject = json.getAsJsonObject(); + JsonElement id = jsonObject.get("id"); + if (id != null) { + ItemType itemType = ItemTypes.get(id.getAsString()); + if (itemType == null) { + throw new JsonParseException("Could not parse item type `" + id + "`"); + } + return new BaseItem(itemType); + } + ItemType itemType = cont.deserialize(jsonObject.get("itemType").getAsJsonObject(), ItemType.class); + JsonElement nbt = jsonObject.get("nbt"); + if (nbt == null) { + return new BaseItem(itemType); + } + try { + return new BaseItem(itemType, LazyReference.computed(TagStringIO.get().asCompound(nbt.getAsString()))); + } catch (IOException e) { + throw new JsonParseException("Could not deserialize BaseItem", e); + } + } + + @Override + public JsonElement serialize( + final BaseItem baseItem, + final Type type, + final JsonSerializationContext jsonSerializationContext + ) { + JsonObject obj = new JsonObject(); + obj.add("itemType", jsonSerializationContext.serialize(baseItem.getType())); + try { + obj.add("nbt", baseItem.getNbt() == null ? null : new JsonPrimitive(TagStringIO.get().asString(baseItem.getNbt()))); + return obj; + } catch (IOException e) { + throw new JsonParseException("Could not deserialize BaseItem", e); + } + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index 5a5fa654e..8bf84ab8b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -52,6 +52,7 @@ import com.sk89q.worldedit.command.tool.SelectionWand; import com.sk89q.worldedit.command.tool.SinglePickaxe; import com.sk89q.worldedit.command.tool.Tool; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Locatable; import com.sk89q.worldedit.extent.NullExtent; @@ -80,7 +81,6 @@ import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.item.ItemType; -import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.snapshot.experimental.Snapshot; import com.zaxxer.sparsebits.SparseBitSet; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -182,8 +182,10 @@ public class LocalSession implements TextureHolder { private String lastScript; private RegionSelectorType defaultSelector; private boolean useServerCUI = false; // Save this to not annoy players. - private ItemType wandItem; - private ItemType navWandItem; + //FAWE start - allow NBT + private BaseItem wandItem; + private BaseItem navWandItem; + //FAWE end /** * Construct the object. @@ -1199,7 +1201,7 @@ public class LocalSession implements TextureHolder { tool = tools.get(item.getInternalId()); } if (tool == SelectionWand.INSTANCE && !SelectionWand.INSTANCE.canUse(player)) { - tools.remove(wandItem.getInternalId()); + tools.remove(wandItem.getType().getInternalId()); loadDefaults(player, true); // Permissions have changed so redo the player's current tools. return null; } @@ -1253,18 +1255,20 @@ public class LocalSession implements TextureHolder { if (loadDefaults || force) { loadDefaults = false; LocalConfiguration config = WorldEdit.getInstance().getConfiguration(); + ParserContext context = new ParserContext(); + context.setActor(actor); if (wandItem == null) { - wandItem = ItemTypes.parse(config.wandItem); + wandItem = WorldEdit.getInstance().getItemFactory().parseFromInput(config.wandItem, context); } if (navWandItem == null) { - navWandItem = ItemTypes.parse(config.navigationWand); + navWandItem = WorldEdit.getInstance().getItemFactory().parseFromInput(config.navigationWand, context); } synchronized (this.tools) { - if (tools.get(navWandItem.getInternalId()) == null && NavigationWand.INSTANCE.canUse(actor)) { - tools.put(navWandItem.getInternalId(), NavigationWand.INSTANCE); + if (tools.get(navWandItem.getType().getInternalId()) == null && NavigationWand.INSTANCE.canUse(actor)) { + tools.put(navWandItem.getType().getInternalId(), NavigationWand.INSTANCE); } - if (tools.get(wandItem.getInternalId()) == null && SelectionWand.INSTANCE.canUse(actor)) { - tools.put(wandItem.getInternalId(), SelectionWand.INSTANCE); + if (tools.get(wandItem.getType().getInternalId()) == null && SelectionWand.INSTANCE.canUse(actor)) { + tools.put(wandItem.getType().getInternalId(), SelectionWand.INSTANCE); } } } @@ -1334,10 +1338,23 @@ public class LocalSession implements TextureHolder { * @param item the item type * @param tool the tool to set, which can be {@code null} * @throws InvalidToolBindException if the item can't be bound to that item + * @deprecated use {@link #setTool(BaseItem, Tool)} */ + @Deprecated public void setTool(ItemType item, @Nullable Tool tool) throws InvalidToolBindException { - if (item.hasBlockType()) { - throw new InvalidToolBindException(item, Caption.of("worldedit.error.blocks-cant-be-used")); + setTool(new BaseItem(item), tool); + } + + /** + * Set the tool. + * + * @param item the item type + * @param tool the tool to set, which can be {@code null} + * @throws InvalidToolBindException if the item can't be bound to that item + */ + public void setTool(BaseItem item, @Nullable Tool tool) throws InvalidToolBindException { + if (item.getType().hasBlockType()) { + throw new InvalidToolBindException(item.getType(), Caption.of("worldedit.error.blocks-cant-be-used")); } if (tool instanceof SelectionWand) { changeTool(this.wandItem, this.wandItem = item, tool); @@ -1348,7 +1365,7 @@ public class LocalSession implements TextureHolder { setDirty(); return; } - setTool(item.getDefaultState(), tool, null); + setTool(item, tool, null); } public void setTool(Player player, @Nullable Tool tool) throws InvalidToolBindException { @@ -1356,17 +1373,17 @@ public class LocalSession implements TextureHolder { setTool(item, tool, player); } - private void changeTool(ItemType oldType, ItemType newType, Tool newTool) { - if (oldType != null) { + private void changeTool(BaseItem oldItem, BaseItem newItem, Tool newTool) { + if (oldItem != null) { synchronized (this.tools) { - this.tools.remove(oldType.getInternalId()); + this.tools.remove(oldItem.getType().getInternalId()); } } synchronized (this.tools) { if (newTool == null) { - this.tools.remove(newType.getInternalId()); + this.tools.remove(newItem.getType().getInternalId()); } else { - this.tools.put(newType.getInternalId(), newTool); + this.tools.put(newItem.getType().getInternalId(), newTool); } } } @@ -1376,11 +1393,11 @@ public class LocalSession implements TextureHolder { if (type.hasBlockType() && type.getBlockType().getMaterial().isAir()) { throw new InvalidToolBindException(type, Caption.of("worldedit.error.blocks-cant-be-used")); } else if (tool instanceof SelectionWand) { - changeTool(this.wandItem, this.wandItem = item.getType(), tool); + changeTool(this.wandItem, this.wandItem = item, tool); setDirty(); return; } else if (tool instanceof NavigationWand) { - changeTool(this.navWandItem, this.navWandItem = item.getType(), tool); + changeTool(this.navWandItem, this.navWandItem = item, tool); setDirty(); return; } @@ -1877,9 +1894,32 @@ public class LocalSession implements TextureHolder { * Get the preferred wand item for this user, or {@code null} to use the default * * @return item id of wand item, or {@code null} + * @deprecated use {@link #getWandBaseItem()} */ + @Deprecated public String getWandItem() { - return wandItem.getId(); + return wandItem.getType().getId(); + } + + /** + * Get the preferred navigation wand item for this user, or {@code null} to use the default + * + * @return item id of nav wand item, or {@code null} + * @deprecated use {@link #getNavWandBaseItem()} + */ + @Deprecated + public String getNavWandItem() { + return navWandItem.getType().getId(); + } + + //FAWE start + /** + * Get the preferred wand item for this user, or {@code null} to use the default + * + * @return item id of wand item, or {@code null} + */ + public BaseItem getWandBaseItem() { + return wandItem == null ? null : new BaseItem(wandItem.getType(), wandItem.getNbtReference()); } /** @@ -1887,9 +1927,10 @@ public class LocalSession implements TextureHolder { * * @return item id of nav wand item, or {@code null} */ - public String getNavWandItem() { - return navWandItem.getId(); + public BaseItem getNavWandBaseItem() { + return navWandItem == null ? null : new BaseItem(navWandItem.getType(), navWandItem.getNbtReference()); } + //FAWE end /** * Get the last block distribution stored in this session. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java index 1dab627c7..ac8236297 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java @@ -71,6 +71,7 @@ public class BaseItem implements NbtValued { * @param itemType The type to set */ public void setType(ItemType itemType) { + checkNotNull(itemType); this.itemType = itemType; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index d8e0943dc..ac13defc3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -30,6 +30,7 @@ import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.command.argument.SelectorChoice; import com.sk89q.worldedit.command.tool.NavigationWand; @@ -38,6 +39,8 @@ import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Locatable; import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits; @@ -325,22 +328,29 @@ public class SelectionCommands { //FAWE start session.loadDefaults(player, true); //FAWE end - String wandId = navWand ? session.getNavWandItem() : session.getWandItem(); - if (wandId == null) { - wandId = navWand ? we.getConfiguration().navigationWand : we.getConfiguration().wandItem; + BaseItem wand = navWand ? session.getNavWandBaseItem() : session.getWandBaseItem(); + if (wand == null) { + String wandId = navWand ? we.getConfiguration().navigationWand : we.getConfiguration().wandItem; + //FAWE start - allow item NBT + ParserContext parserContext = new ParserContext(); + parserContext.setActor(player); + parserContext.setSession(session); + try { + wand = WorldEdit.getInstance().getItemFactory().parseFromInput(wandId, parserContext); + } catch (InputParseException e) { + player.print(Caption.of("worldedit.wand.invalid")); + return; + } } - ItemType itemType = ItemTypes.parse(wandId); - if (itemType == null) { - player.print(Caption.of("worldedit.wand.invalid")); - return; - } - player.giveItem(new BaseItemStack(itemType, 1)); + System.out.println("a "+ wand); + player.giveItem(new BaseItemStack(wand.getType(), wand.getNbtReference(), 1)); + //FAWE end //FAWE start - instance-iate session if (navWand) { - session.setTool(itemType, NavigationWand.INSTANCE); + session.setTool(wand, NavigationWand.INSTANCE); player.print(Caption.of("worldedit.wand.navwand.info")); } else { - session.setTool(itemType, SelectionWand.INSTANCE); + session.setTool(wand, SelectionWand.INSTANCE); player.print(Caption.of("worldedit.wand.selwand.info")); //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java index 95499372c..f3be41469 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -149,7 +149,7 @@ public class ToolCommands { throws InvalidToolBindException { //FAWE start isBrush = session.getTool(player) instanceof BrushTool; - session.setTool(player.getItemInHand(HandSide.MAIN_HAND).getType(), null); + session.setTool(player.getItemInHand(HandSide.MAIN_HAND), null); //FAWE end player.print(Caption.of(isBrush ? "worldedit.brush.none.equip" : "worldedit.tool.none.equip")); } @@ -163,7 +163,7 @@ public class ToolCommands { String translationKey ) throws InvalidToolBindException { BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND); - session.setTool(itemStack.getType(), tool); + session.setTool(itemStack, tool); player.print(Caption.of(translationKey, itemStack.getRichName())); sendUnbindInstruction(player, UNBIND_COMMAND_COMPONENT); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java index 3804be8d3..7bec7c2f5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java @@ -112,7 +112,7 @@ public class PropertiesConfiguration extends LocalConfiguration { logFile = getString("log-file", logFile); logFormat = getString("log-format", logFormat); registerHelp = getBool("register-help", registerHelp); - wandItem = getString("wand-item", wandItem).toLowerCase(Locale.ROOT); + wandItem = getString("wand-item", wandItem); try { wandItem = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(wandItem)).getId(); } catch (Throwable ignored) { @@ -122,7 +122,7 @@ public class PropertiesConfiguration extends LocalConfiguration { useInventory = getBool("use-inventory", useInventory); useInventoryOverride = getBool("use-inventory-override", useInventoryOverride); useInventoryCreativeOverride = getBool("use-inventory-creative-override", useInventoryCreativeOverride); - navigationWand = getString("nav-wand-item", navigationWand).toLowerCase(Locale.ROOT); + navigationWand = getString("nav-wand-item", navigationWand); try { navigationWand = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(navigationWand)).getId(); } catch (Throwable ignored) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java index 7b0cbf4b8..4a5e45713 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java @@ -58,7 +58,7 @@ public class YAMLConfiguration extends LocalConfiguration { profile = config.getBoolean("debug", profile); traceUnflushedSessions = config.getBoolean("debugging.trace-unflushed-sessions", traceUnflushedSessions); - wandItem = convertLegacyItem(config.getString("wand-item", wandItem)).toLowerCase(Locale.ROOT); + wandItem = convertLegacyItem(config.getString("wand-item", wandItem)); defaultChangeLimit = Math.max(-1, config.getInt( "limits.max-blocks-changed.default", defaultChangeLimit)); @@ -130,7 +130,7 @@ public class YAMLConfiguration extends LocalConfiguration { useInventoryCreativeOverride ); - navigationWand = convertLegacyItem(config.getString("navigation-wand.item", navigationWand)).toLowerCase(Locale.ROOT); + navigationWand = convertLegacyItem(config.getString("navigation-wand.item", navigationWand)); navigationWandMaxDistance = config.getInt("navigation-wand.max-distance", navigationWandMaxDistance); navigationUseGlass = config.getBoolean("navigation.use-glass", navigationUseGlass); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java index e5d05ee6d..416fbeaae 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/gson/GsonUtil.java @@ -19,10 +19,12 @@ package com.sk89q.worldedit.util.gson; +import com.fastasyncworldedit.core.util.gson.BaseItemAdapter; import com.fastasyncworldedit.core.util.gson.ItemTypeAdapter; import com.fastasyncworldedit.core.util.gson.RegionSelectorAdapter; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.RegionSelector; @@ -48,6 +50,7 @@ public final class GsonUtil { //FAWE start gsonBuilder.registerTypeAdapter(RegionSelector.class, new RegionSelectorAdapter()); gsonBuilder.registerTypeAdapter(ItemType.class, new ItemTypeAdapter()); + gsonBuilder.registerTypeAdapter(BaseItem.class, new BaseItemAdapter()); //FAWE end return gsonBuilder; } From 47b0ece3777ae13564575cc6569ed2c34cac40d4 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sun, 2 Jun 2024 09:27:56 +0100 Subject: [PATCH 08/15] Add since tags to new methods --- .../src/main/java/com/sk89q/worldedit/LocalSession.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index 8bf84ab8b..5df95414b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -1351,6 +1351,7 @@ public class LocalSession implements TextureHolder { * @param item the item type * @param tool the tool to set, which can be {@code null} * @throws InvalidToolBindException if the item can't be bound to that item + * @since TODO */ public void setTool(BaseItem item, @Nullable Tool tool) throws InvalidToolBindException { if (item.getType().hasBlockType()) { @@ -1917,6 +1918,7 @@ public class LocalSession implements TextureHolder { * Get the preferred wand item for this user, or {@code null} to use the default * * @return item id of wand item, or {@code null} + * @since TODO */ public BaseItem getWandBaseItem() { return wandItem == null ? null : new BaseItem(wandItem.getType(), wandItem.getNbtReference()); @@ -1926,6 +1928,7 @@ public class LocalSession implements TextureHolder { * Get the preferred navigation wand item for this user, or {@code null} to use the default * * @return item id of nav wand item, or {@code null} + * @since TODO */ public BaseItem getNavWandBaseItem() { return navWandItem == null ? null : new BaseItem(navWandItem.getType(), navWandItem.getNbtReference()); From a7e4d19605484b7eb3f2619ea270114be8fa56cf Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sun, 2 Jun 2024 17:25:32 +0100 Subject: [PATCH 09/15] Remove debug --- .../main/java/com/sk89q/worldedit/command/SelectionCommands.java | 1 - 1 file changed, 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index ac13defc3..d000fcef7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -342,7 +342,6 @@ public class SelectionCommands { return; } } - System.out.println("a "+ wand); player.giveItem(new BaseItemStack(wand.getType(), wand.getNbtReference(), 1)); //FAWE end //FAWE start - instance-iate session From 5714a526756e1819b1598f31211e26b48cdd217d Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 5 Jun 2024 21:23:12 +0200 Subject: [PATCH 10/15] fix: correctly trim the max chunk section (#2753) - fixes #2727 - fixes IntellectualSites/Plotsquared#4436 --- .../regions/plotsquared/PlotSquaredFeature.java | 14 ++++++-------- .../core/queue/IBatchProcessor.java | 12 ++++-------- .../com/sk89q/worldedit/regions/CuboidRegion.java | 4 ++-- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java index 9f0916a4b..49955a4fa 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/PlotSquaredFeature.java @@ -1,6 +1,5 @@ package com.fastasyncworldedit.bukkit.regions.plotsquared; -import com.fastasyncworldedit.core.FaweAPI; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.regions.FaweMask; import com.fastasyncworldedit.core.regions.FaweMaskManager; @@ -174,22 +173,21 @@ public class PlotSquaredFeature extends FaweMaskManager { return null; } + final World world = player.getWorld(); + int min = area != null ? area.getMinBuildHeight() : world.getMinY(); + // PlotSquared uses exclusive max height, WorldEdit uses inclusive max height -> subtract 1 + int max = area != null ? Math.min(world.getMaxY(), area.getMaxBuildHeight() - 1) : world.getMaxY(); Region maskedRegion; if (regions.size() == 1) { - final World world = player.getWorld(); - int min = area != null ? area.getMinBuildHeight() : world.getMinY(); - // PlotSquared uses exclusive max height, WorldEdit uses inclusive max height -> subtract 1 - int max = area != null ? Math.min(world.getMaxY(), area.getMaxBuildHeight() - 1) : world.getMaxY(); final CuboidRegion region = regions.iterator().next(); final BlockVector3 pos1 = BlockVector3.at(region.getMinimumX(), min, region.getMinimumZ()); final BlockVector3 pos2 = BlockVector3.at(region.getMaximumX(), max, region.getMaximumZ()); maskedRegion = new CuboidRegion(pos1, pos2); } else { - World world = FaweAPI.getWorld(area.getWorldName()); List weRegions = regions.stream().map( - r -> new CuboidRegion(world, BlockVector3.at(r.getMinimumX(), r.getMinimumY(), r.getMinimumZ()), - BlockVector3.at(r.getMaximumX(), r.getMaximumY(), r.getMaximumZ()) + r -> new CuboidRegion(world, BlockVector3.at(r.getMinimumX(), min, r.getMinimumZ()), + BlockVector3.at(r.getMaximumX(), max, r.getMaximumZ()) )).collect(Collectors.toList()); maskedRegion = new RegionIntersection(world, weRegions); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java index 778f85ce4..4ba91a4f3 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java @@ -58,7 +58,7 @@ public interface IBatchProcessor { /** * Utility method to trim a chunk based on min and max Y (inclusive). * - * @param keepInsideRange if all blocks inside the range (inclusive) should be kept (default) + * @param keepInsideRange if all blocks inside the range (inclusive) should be kept (default), or removed * @return false if chunk is empty of blocks */ default boolean trimY(IChunkSet set, int minY, int maxY, final boolean keepInsideRange) { @@ -74,16 +74,14 @@ public interface IBatchProcessor { for (int i = 0; i < index; i++) { arr[i] = BlockTypesCache.ReservedIDs.__RESERVED__; } - } else { - arr = new char[4096]; + set.setBlocks(layer, arr); } - set.setBlocks(layer, arr); } else { set.setBlocks(layer, null); } } } - for (int layer = maxLayer; layer < set.getMaxSectionPosition(); layer++) { + for (int layer = maxLayer; layer <= set.getMaxSectionPosition(); layer++) { if (set.hasSection(layer)) { if (layer == maxLayer) { char[] arr = set.loadIfPresent(layer); @@ -92,10 +90,8 @@ public interface IBatchProcessor { for (int i = index; i < arr.length; i++) { arr[i] = BlockTypesCache.ReservedIDs.__RESERVED__; } - } else { - arr = new char[4096]; + set.setBlocks(layer, arr); } - set.setBlocks(layer, arr); } else { set.setBlocks(layer, null); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index 8616cbb2b..8e4da9214 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -828,7 +828,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { return set; } - for (int layer = get.getMinSectionPosition(); layer < get.getMaxSectionPosition(); layer++) { + for (int layer = get.getMinSectionPosition(); layer <= get.getMaxSectionPosition(); layer++) { if (!set.hasSection(layer)) { continue; } @@ -912,7 +912,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { boolean trimX = lowerX != 0 || upperX != 15; boolean trimZ = lowerZ != 0 || upperZ != 15; - for (int layer = get.getMinSectionPosition(); layer < get.getMaxSectionPosition(); layer++) { + for (int layer = get.getMinSectionPosition(); layer <= get.getMaxSectionPosition(); layer++) { if (!set.hasSection(layer)) { continue; } From c095c492e0264fc19a9d6f453183adf0f9f3f2e7 Mon Sep 17 00:00:00 2001 From: EpicPlayerA10 <62206933+EpicPlayerA10@users.noreply.github.com> Date: Fri, 7 Jun 2024 12:30:31 +0200 Subject: [PATCH 11/15] fix: normalize layer when setting ordinal to ThreadUnsafeCharBlocks (#2764) - fixes #2763 --- .../queue/implementation/blocks/ThreadUnsafeCharBlocks.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java index 54331279f..90ae6b32e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java @@ -222,7 +222,7 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks { } public void set(int x, int y, int z, char value) { - final int layer = y >> 4; + final int layer = (y >> 4) - minSectionPosition; final int index = (y & 15) << 8 | z << 4 | x; try { blocks[layer][index] = value; From ee5d1caa2c568ee40eecc9523453bb132265cfab Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Sat, 8 Jun 2024 10:07:05 +0200 Subject: [PATCH 12/15] Fix more upstream incompatibilities (#2767) * Move more public types to records (cherry picked from commit 35e58895f5379e78b856e8997a593701c6d9db21) * chore: pull in PlacementType * fix: mask reference in NegatedMask * Use records in expression impl (cherry picked from commit 453537c5b4783412aa1b4e982d7b72c637d0db8e) * fix: variable record getter access * chore: add since to Deprecated annotation * chore: revert weird merge in ClientProxy * chore: cleanup remaining deprecations * chore: code-style --------- Co-authored-by: Octavia Togami --- .../java/com/sk89q/worldedit/EditSession.java | 10 +- .../io/share/ClipboardShareMetadata.java | 27 +--- .../worldedit/function/factory/Deform.java | 26 ++-- .../sk89q/worldedit/function/mask/Mask.java | 2 +- .../sk89q/worldedit/function/mask/Masks.java | 18 +-- .../history/change/BiomeChange3D.java | 24 ++-- .../worldedit/history/change/BlockChange.java | 30 +++-- .../exception/ExceptionConverterHelper.java | 14 +-- .../internal/event/InteractionDebouncer.java | 9 +- .../internal/expression/ExecutionData.java | 27 ++-- .../internal/expression/ExpressionHelper.java | 26 ++-- .../internal/expression/Functions.java | 12 +- .../internal/expression/LocalSlot.java | 19 +-- .../internal/expression/SlotTable.java | 2 +- .../expression/invoke/CompilingVisitor.java | 22 ++-- .../internal/expression/invoke/ExecNode.java | 13 +- .../expression/invoke/ExpressionHandles.java | 26 ++-- .../com/sk89q/worldedit/registry/Keyed.java | 22 +++- .../sk89q/worldedit/session/Placement.java | 52 ++++++++ .../worldedit/session/PlacementType.java | 119 ++++++++++++++++++ .../sk89q/worldedit/util/LocatedBlock.java | 48 +++---- .../worldedit/util/report/DataReport.java | 11 +- .../worldedit/world/biome/BiomeType.java | 25 ++-- .../worldedit/world/entity/EntityType.java | 30 ++++- .../worldedit/world/fluid/FluidType.java | 20 ++- .../worldedit/world/gamemode/GameMode.java | 28 +---- .../world/registry/ItemMaterial.java | 37 +++++- .../registry/PassthroughItemMaterial.java | 8 +- .../world/registry/SimpleItemMaterial.java | 20 +-- .../worldedit/world/weather/WeatherType.java | 29 +---- 30 files changed, 435 insertions(+), 321 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/session/Placement.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/session/PlacementType.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 2e5e3c2ef..1469ffb96 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -3082,8 +3082,8 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { ) <= 0) { return null; } - int newType = (int) typeVariable.getValue(); - int newData = (int) dataVariable.getValue(); + int newType = (int) typeVariable.value(); + int newData = (int) dataVariable.value(); if (newType != typeVar || newData != dataVar) { BlockState state = LegacyMapper.getInstance().getBlockFromLegacy(newType, newData); return state == null ? defaultMaterial : state.toBaseBlock(); @@ -3181,9 +3181,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { // transform expression.evaluate(new double[]{scaled.x(), scaled.y(), scaled.z()}, timeout); - int xv = (int) Math.floor(x.getValue() * unit.x() + zero2.x()); - int yv = (int) Math.floor(y.getValue() * unit.y() + zero2.y()); - int zv = (int) Math.floor(z.getValue() * unit.z() + zero2.z()); + int xv = (int) Math.floor(x.value() * unit.x() + zero2.x()); + int yv = (int) Math.floor(y.value() * unit.y() + zero2.y()); + int zv = (int) Math.floor(z.value() * unit.z() + zero2.z()); BlockState get; if (yv >= minY && yv <= maxY) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareMetadata.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareMetadata.java index 2e5f6c042..a670ea7cc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareMetadata.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/ClipboardShareMetadata.java @@ -23,27 +23,10 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; /** * Items of metadata about shared clipboards. + * + * @param format the format of the clipboard + * @param name the name of the clipboard + * @param author the author of the clipboard */ -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; - } +public record ClipboardShareMetadata(ClipboardFormat format, String name, String author) { } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java index b4ccd0a55..6dea78892 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/factory/Deform.java @@ -167,24 +167,14 @@ public class Deform implements Contextual { ); } - private static final class DeformOperation implements Operation { - - private final Extent destination; - private final Region region; - private final Vector3 zero; - private final Vector3 unit; - private final String expression; - private final int timeout; - - private DeformOperation(Extent destination, Region region, Vector3 zero, Vector3 unit, String expression, int timeout) { - this.destination = destination; - this.region = region; - this.zero = zero; - this.unit = unit; - this.expression = expression; - this.timeout = timeout; - } - + private record DeformOperation( + Extent destination, + Region region, + Vector3 zero, + Vector3 unit, + String expression, //FAWE: Expression -> String + int timeout + ) implements Operation { @Override public Operation resume(RunContext run) throws WorldEditException { try { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java index 3c4cb1378..94141278d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java @@ -87,7 +87,7 @@ public interface Mask { } else if (this instanceof Masks.AlwaysFalse) { return Masks.ALWAYS_TRUE; } else if (this instanceof Masks.NegatedMask) { - return ((Masks.NegatedMask) this).mask; + return ((Masks.NegatedMask) this).mask(); } return new InverseMask(this); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java index d3cb4cad7..478d2732a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Masks.java @@ -211,15 +211,7 @@ public final class Masks { } - //FAWE start - protected > private - protected static class NegatedMask implements Mask { - - //FAWE end - protected final Mask mask; - - private NegatedMask(Mask mask) { - this.mask = mask; - } + protected record NegatedMask(Mask mask) implements Mask { @Override public boolean test(BlockVector3 vector) { @@ -245,13 +237,7 @@ public final class Masks { } - private static class NegatedMask2D implements Mask2D { - - private final Mask2D mask; - - private NegatedMask2D(Mask2D mask) { - this.mask = mask; - } + private record NegatedMask2D(Mask2D mask) implements Mask2D { @Override public boolean test(BlockVector2 vector) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java index 74a16e90e..1106899f8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java @@ -33,34 +33,30 @@ import static com.google.common.base.Preconditions.checkNotNull; *

This biome change does not have an {@link Extent} assigned to it because * one will be taken from the passed {@link UndoContext}. If the context * does not have an extent (it is null), cryptic errors may occur.

+ * + * @param position the position + * @param previous the previous biome + * @param current the current biome */ -public class BiomeChange3D implements Change { - - private final BlockVector3 position; - private final BiomeType previous; - private final BiomeType current; +public record BiomeChange3D(BlockVector3 position, BiomeType previous, BiomeType current) implements Change { /** * Create a new biome change. * - * @param position the position - * @param previous the previous biome - * @param current the current biome */ - public BiomeChange3D(BlockVector3 position, BiomeType previous, BiomeType current) { + public BiomeChange3D { checkNotNull(position); checkNotNull(previous); checkNotNull(current); - this.position = position; - this.previous = previous; - this.current = current; } /** * Get the position. * * @return the position + * @deprecated Use {@link #position()}. */ + @Deprecated(forRemoval = true, since = "TODO") public BlockVector3 getPosition() { return position; } @@ -69,7 +65,9 @@ public class BiomeChange3D implements Change { * Get the previous biome. * * @return the previous biome + * @deprecated Use {@link #previous()}. */ + @Deprecated(forRemoval = true, since = "TODO") public BiomeType getPrevious() { return previous; } @@ -78,7 +76,9 @@ public class BiomeChange3D implements Change { * Get the current biome. * * @return the current biome + * @deprecated Use {@link #current()}. */ + @Deprecated(forRemoval = true, since = "TODO") public BiomeType getCurrent() { return current; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java index ec9bb104d..16fc50e0d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java @@ -34,12 +34,21 @@ import static com.google.common.base.Preconditions.checkNotNull; *

This block change does not have an {@link Extent} assigned to it because * one will be taken from the passed {@link UndoContext}. If the context * does not have an extent (it is null), cryptic errors may occur.

+ * + * @param position the position + * @param previous the previous block + * @param current the current block */ -public class BlockChange implements Change { +public record BlockChange(BlockVector3 position, BaseBlock previous, BaseBlock current) implements Change { - private final BlockVector3 position; - private final BaseBlock previous; - private final BaseBlock current; + /** + * Create a new block change. + */ + public BlockChange { + checkNotNull(position); + checkNotNull(previous); + checkNotNull(current); + } /** * Create a new block change. @@ -53,19 +62,16 @@ public class BlockChange implements Change { BP previous, BC current ) { - checkNotNull(position); - checkNotNull(previous); - checkNotNull(current); - this.position = position; - this.previous = previous.toBaseBlock(); - this.current = current.toBaseBlock(); + this(position, previous.toBaseBlock(), current.toBaseBlock()); } /** * Get the position. * * @return the position + * @deprecated use {@link #position()} */ + @Deprecated(forRemoval = true, since = "TODO") public BlockVector3 getPosition() { return position; } @@ -74,7 +80,9 @@ public class BlockChange implements Change { * Get the previous block. * * @return the previous block + * @deprecated use {@link #previous()} */ + @Deprecated(forRemoval = true, since = "TODO") public BaseBlock getPrevious() { return previous; } @@ -83,7 +91,9 @@ public class BlockChange implements Change { * Get the current block. * * @return the current block + * @deprecated use {@link #current()} */ + @Deprecated(forRemoval = true, since = "TODO") public BaseBlock getCurrent() { return current; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java index 73f76280e..64e78250a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java @@ -87,16 +87,10 @@ public abstract class ExceptionConverterHelper implements ExceptionConverter { } } - private static class ExceptionHandler implements Comparable { - - final Class cls; - final Method method; - - private ExceptionHandler(Class cls, Method method) { - this.cls = cls; - this.method = method; - } - + private record ExceptionHandler( + Class cls, + Method method + ) implements Comparable { @Override public int compareTo(ExceptionHandler o) { if (cls.equals(o.cls)) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/event/InteractionDebouncer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/event/InteractionDebouncer.java index b33570cd9..37e9442b7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/event/InteractionDebouncer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/event/InteractionDebouncer.java @@ -57,13 +57,6 @@ public class InteractionDebouncer { return Optional.empty(); } - private static class Interaction { - public final long tick; - public final boolean result; - - public Interaction(long tick, boolean result) { - this.tick = tick; - this.result = result; - } + private record Interaction(long tick, boolean result) { } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExecutionData.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExecutionData.java index 1fef5aa81..bcf04b907 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExecutionData.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExecutionData.java @@ -23,36 +23,23 @@ import java.time.Instant; import static java.util.Objects.requireNonNull; -public class ExecutionData { - +public record ExecutionData(SlotTable slots, Functions functions, Instant deadline) { /** - * Special execution context for evaluating constant values. As long as no variables are used, - * it can be considered constant. + * Special execution context for evaluating constant values. As long as no variables are used, it can be considered + * constant. */ public static final ExecutionData CONSTANT_EVALUATOR = new ExecutionData(null, null, Instant.MAX); - private final SlotTable slots; - private final Functions functions; - private final Instant deadline; - - public ExecutionData(SlotTable slots, Functions functions, Instant deadline) { - this.slots = slots; - this.functions = functions; - this.deadline = deadline; - } - - public SlotTable getSlots() { + @Override + public SlotTable slots() { return requireNonNull(slots, "Cannot use variables in a constant"); } - public Functions getFunctions() { + @Override + public Functions functions() { return requireNonNull(functions, "Cannot use functions in a constant"); } - public Instant getDeadline() { - return deadline; - } - public void checkDeadline() { if (Instant.now().isAfter(deadline)) { throw new ExpressionTimeoutException("Calculations exceeded time limit."); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionHelper.java index 0afeb6dd3..0521c0a50 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionHelper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionHelper.java @@ -40,6 +40,12 @@ public class ExpressionHelper { } } + public static void check(boolean condition, int positionInLine, String message) { + if (!condition) { + throw evalException(positionInLine, message); + } + } + public static int getErrorPosition(Token token) { return token.getCharPositionInLine(); } @@ -49,14 +55,18 @@ public class ExpressionHelper { } public static EvaluationException evalException(Token token, String message) { + return evalException(getErrorPosition(token), message); + } + + public static EvaluationException evalException(int positionInLine, String message) { return new EvaluationException( - getErrorPosition(token), - message + positionInLine, + message ); } - public static void checkIterations(int iterations, ParserRuleContext ctx) { - check(iterations <= 256, ctx, "Loop exceeded 256 iterations"); + public static void checkIterations(int iterations, int positionInLine) { + check(iterations <= 256, positionInLine, "Loop exceeded 256 iterations"); } public static MethodHandle resolveFunction( @@ -72,10 +82,10 @@ public class ExpressionHelper { // last param is the array, turn that varargs int keptParams = nParams - 1; function = function.asCollector( - // collect into the last array - function.type().parameterType(nParams - 1), - // collect the variable args (args over kept) - ctx.args.size() - keptParams + // collect into the last array + function.type().parameterType(nParams - 1), + // collect the variable args (args over kept) + ctx.args.size() - keptParams ); // re-wrap it for the inner arguments function = function.asType(function.type().wrap()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Functions.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Functions.java index 6f3a63787..ef219e3f8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Functions.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Functions.java @@ -211,8 +211,8 @@ public final class Functions { final double cosF = Math.cos(angle); final double sinF = Math.sin(angle); - final double xOld = x.getValue(); - final double yOld = y.getValue(); + final double xOld = x.value(); + final double yOld = y.value(); x.setValue(xOld * cosF - yOld * sinF); y.setValue(xOld * sinF + yOld * cosF); @@ -221,9 +221,9 @@ public final class Functions { } private static double swap(Variable x, Variable y) { - final double tmp = x.getValue(); + final double tmp = x.value(); - x.setValue(y.getValue()); + x.setValue(y.value()); y.setValue(tmp); return 0.0; @@ -391,8 +391,8 @@ public final class Functions { private static double queryInternal(LocalSlot type, LocalSlot data, double typeId, double dataValue) { // Compare to input values and determine return value // -1 is a wildcard, always true - double ret = ((type.getValue() == -1 || typeId == type.getValue()) - && (data.getValue() == -1 || dataValue == data.getValue())) ? 1.0 : 0.0; + double ret = ((type.value() == -1 || typeId == type.value()) + && (data.value() == -1 || dataValue == data.value())) ? 1.0 : 0.0; if (type instanceof Variable) { ((Variable) type).setValue(typeId); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/LocalSlot.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/LocalSlot.java index 2b02fa036..0b2a5bc48 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/LocalSlot.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/LocalSlot.java @@ -24,19 +24,7 @@ package com.sk89q.worldedit.internal.expression; */ public interface LocalSlot { - final class Constant implements LocalSlot { - - private final double value; - - public Constant(double value) { - this.value = value; - } - - @Override - public double getValue() { - return value; - } - + record Constant(double value) implements LocalSlot { @Override public String toString() { return String.valueOf(value); @@ -57,7 +45,7 @@ public interface LocalSlot { } @Override - public double getValue() { + public double value() { return value; } @@ -65,9 +53,8 @@ public interface LocalSlot { public String toString() { return String.valueOf(value); } - } - double getValue(); + double value(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/SlotTable.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/SlotTable.java index a94c9dc62..e7090f461 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/SlotTable.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/SlotTable.java @@ -58,7 +58,7 @@ public class SlotTable { public OptionalDouble getSlotValue(String name) { LocalSlot slot = slots.get(name); - return slot == null ? OptionalDouble.empty() : OptionalDouble.of(slot.getValue()); + return slot == null ? OptionalDouble.empty() : OptionalDouble.of(slot.value()); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java index 7645c8413..0c6e87810 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java @@ -106,7 +106,7 @@ class CompilingVisitor extends ExpressionBaseVisitor { if (ctx.parent instanceof ParserRuleContext) { checkHandle(mh, (ParserRuleContext) ctx.parent); } - return new ExecNode(ctx, mh); + return new ExecNode(ctx.start.getCharPositionInLine(), mh); } private void checkHandle(MethodHandle mh, ParserRuleContext ctx) { @@ -127,7 +127,7 @@ class CompilingVisitor extends ExpressionBaseVisitor { MethodHandles.identity(Double.class) ); // now pass `result` into `guard` - MethodHandle result = evaluate(ctx).handle; + MethodHandle result = evaluate(ctx).handle(); return MethodHandles.collectArguments(guard, 0, result); } @@ -151,8 +151,8 @@ class CompilingVisitor extends ExpressionBaseVisitor { // easiest one of the bunch return MethodHandles.guardWithTest( evaluateBoolean(condition), - trueBranch == null ? NULL_DOUBLE : evaluate(trueBranch).handle, - falseBranch == null ? NULL_DOUBLE : evaluate(falseBranch).handle + trueBranch == null ? NULL_DOUBLE : evaluate(trueBranch).handle(), + falseBranch == null ? NULL_DOUBLE : evaluate(falseBranch).handle() ); } @@ -185,10 +185,10 @@ class CompilingVisitor extends ExpressionBaseVisitor { @Override public MethodHandle visitForStatement(ExpressionParser.ForStatementContext ctx) { return ExpressionHandles.forLoop( - evaluate(ctx.init).handle, + evaluate(ctx.init).handle(), evaluateBoolean(ctx.condition), evaluate(ctx.body), - evaluate(ctx.update).handle + evaluate(ctx.update).handle() ); } @@ -235,7 +235,7 @@ class CompilingVisitor extends ExpressionBaseVisitor { RETURN_STATEMENT_BASE, 0, // map the Double back to ExecutionData via the returnValue - evaluate(ctx.value).handle + evaluate(ctx.value).handle() ); } @@ -262,7 +262,7 @@ class CompilingVisitor extends ExpressionBaseVisitor { @Override public MethodHandle visitExpressionStatement(ExpressionParser.ExpressionStatementContext ctx) { - return evaluate(ctx.expression()).handle; + return evaluate(ctx.expression()).handle(); } @Override @@ -271,7 +271,7 @@ class CompilingVisitor extends ExpressionBaseVisitor { int opType = ctx.op.getType(); return ExpressionHandles.call(data -> { LocalSlot.Variable variable = ExpressionHandles.getVariable(data, target); - double value = variable.getValue(); + double value = variable.value(); double result = value; if (opType == INCREMENT) { value++; @@ -289,7 +289,7 @@ class CompilingVisitor extends ExpressionBaseVisitor { int opType = ctx.op.getType(); return ExpressionHandles.call(data -> { LocalSlot.Variable variable = ExpressionHandles.getVariable(data, target); - double value = variable.getValue(); + double value = variable.value(); if (opType == INCREMENT) { value++; } else { @@ -547,7 +547,7 @@ class CompilingVisitor extends ExpressionBaseVisitor { value = arg; } else { variable = ExpressionHandles.getVariable(data, target); - value = variable.getValue(); + value = variable.value(); switch (type) { case POWER_ASSIGN: value = Math.pow(value, arg); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExecNode.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExecNode.java index 6c53a13e5..86a944f03 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExecNode.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExecNode.java @@ -19,18 +19,7 @@ package com.sk89q.worldedit.internal.expression.invoke; -import org.antlr.v4.runtime.ParserRuleContext; - import java.lang.invoke.MethodHandle; -class ExecNode { - - final ParserRuleContext ctx; - final MethodHandle handle; - - ExecNode(ParserRuleContext ctx, MethodHandle handle) { - this.ctx = ctx; - this.handle = handle; - } - +record ExecNode(int positionInLine, MethodHandle handle) { } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExpressionHandles.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExpressionHandles.java index a2d0ad483..dab0be01b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExpressionHandles.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/ExpressionHandles.java @@ -200,7 +200,7 @@ class ExpressionHandles { static LocalSlot.Variable initVariable(ExecutionData data, Token nameToken) { String name = nameToken.getText(); - return data.getSlots().initVariable(name) + return data.slots().initVariable(name) .orElseThrow(() -> ExpressionHelper.evalException( nameToken, "Cannot overwrite non-variable '" + name + "'" )); @@ -218,7 +218,7 @@ class ExpressionHandles { static LocalSlot.Variable getVariable(ExecutionData data, Token nameToken) { String name = nameToken.getText(); - LocalSlot slot = data.getSlots().getSlot(name) + LocalSlot slot = data.slots().getSlot(name) .orElseThrow(varNotInitException(nameToken)); if (!(slot instanceof LocalSlot.Variable)) { throw ExpressionHelper.evalException( @@ -230,7 +230,7 @@ class ExpressionHandles { static double getSlotValue(ExecutionData data, Token nameToken) { String name = nameToken.getText(); - return data.getSlots().getSlotValue(name) + return data.slots().getSlotValue(name) .orElseThrow(varNotInitException(nameToken)); } @@ -302,11 +302,11 @@ class ExpressionHandles { standardInvoke(init, data); } while ((boolean) standardInvoke(condition, data)) { - checkIterations(iterations, body.ctx); + checkIterations(iterations, body.positionInLine()); data.checkDeadline(); iterations++; try { - result = (Double) standardInvoke(body.handle, data); + result = (Double) standardInvoke(body.handle(), data); } catch (BreakException ex) { if (!ex.doContinue) { break; @@ -331,11 +331,11 @@ class ExpressionHandles { Double result = null; int iterations = 0; do { - checkIterations(iterations, body.ctx); + checkIterations(iterations, body.positionInLine()); data.checkDeadline(); iterations++; try { - result = (Double) standardInvoke(body.handle, data); + result = (Double) standardInvoke(body.handle(), data); } catch (BreakException ex) { if (!ex.doContinue) { break; @@ -369,12 +369,12 @@ class ExpressionHandles { double last = (double) standardInvoke(getLast, data); LocalSlot.Variable variable = initVariable(data, counterToken); for (double i = first; i <= last; i++) { - checkIterations(iterations, body.ctx); + checkIterations(iterations, body.positionInLine()); data.checkDeadline(); iterations++; variable.setValue(i); try { - result = (Double) standardInvoke(body.handle, data); + result = (Double) standardInvoke(body.handle(), data); } catch (BreakException ex) { if (!ex.doContinue) { break; @@ -406,10 +406,10 @@ class ExpressionHandles { if (falling || entry.getDoubleKey() == value) { matched = true; try { - evaluated = (Double) standardInvoke(entry.getValue().handle, data); + evaluated = (Double) standardInvoke(entry.getValue().handle(), data); falling = true; } catch (BreakException brk) { - check(!brk.doContinue, entry.getValue().ctx, "Cannot continue in a switch"); + check(!brk.doContinue, entry.getValue().positionInLine(), "Cannot continue in a switch"); falling = false; break; } @@ -418,9 +418,9 @@ class ExpressionHandles { // This if is like the one in the loop, default's "case" is `!matched` & present if ((falling || !matched) && defaultCase != null) { try { - evaluated = (Double) standardInvoke(defaultCase.handle, data); + evaluated = (Double) standardInvoke(defaultCase.handle(), data); } catch (BreakException brk) { - check(!brk.doContinue, defaultCase.ctx, "Cannot continue in a switch"); + check(!brk.doContinue, defaultCase.positionInLine(), "Cannot continue in a switch"); } } return evaluated; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java index e892ba1f1..b31e62d7f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java @@ -19,6 +19,9 @@ package com.sk89q.worldedit.registry; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; + /** * Represents an objects that can be added to a registry and referenced by an id which is unique within its registry. */ @@ -28,7 +31,24 @@ public interface Keyed { * The id of this object in the registry. Must be unique, and lowercase. Certain registries (e.g Namespaced ones) may have additional restrictions. * * @return an id + * @deprecated Use {@link #id()} instead. */ - String getId(); + @Deprecated(forRemoval = true, since = "TODO") + default String getId() { + return id(); + } + + /** + * The id of this object in the registry. Must be unique and lowercase. Certain registries (e.g namespaced ones) + * may have additional restrictions. + * + * @return an id + * @since TODO + */ + @NonAbstractForCompatibility(delegateName = "getId", delegateParams = {}) + default String id() { + DeprecationUtil.checkDelegatingOverride(getClass()); + return getId(); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/Placement.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/Placement.java new file mode 100644 index 000000000..3171bc66e --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/Placement.java @@ -0,0 +1,52 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * 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 . + */ + +package com.sk89q.worldedit.session; + +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; + +//FAWE: not in use (yet) +public record Placement(PlacementType placementType, BlockVector3 offset) { + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + return placementType.getPlacementPosition(selector, actor).add(offset); + } + + public boolean canBeUsedBy(Actor actor) { + return placementType.canBeUsedBy(actor); + } + + public Component getInfo() { + if (offset.equals(BlockVector3.ZERO)) { + return TranslatableComponent.of(placementType.getTranslationKey()); + } else { + return TranslatableComponent.of( + placementType.getTranslationKeyWithOffset(), + TextComponent.of(offset.getX()), + TextComponent.of(offset.getY()), + TextComponent.of(offset.getZ()) + ); + } + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/PlacementType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/PlacementType.java new file mode 100644 index 000000000..90b6ff01e --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/PlacementType.java @@ -0,0 +1,119 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * 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 . + */ + +package com.sk89q.worldedit.session; + +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Locatable; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.RegionSelector; + +import static com.google.common.base.Preconditions.checkNotNull; + +//FAWE: not in use (yet) +public enum PlacementType { + WORLD("worldedit.toggleplace.world", "worldedit.toggleplace.world-offset") { + @Override + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + return BlockVector3.ZERO; + } + }, + + PLAYER("worldedit.toggleplace.player", "worldedit.toggleplace.player-offset") { + @Override + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + if (!canBeUsedBy(actor)) { + throw new IncompleteRegionException(); + } + return ((Locatable) actor).getBlockLocation().toVector().toBlockPoint(); + } + + @Override + public boolean canBeUsedBy(Actor actor) { + checkNotNull(actor); + return actor instanceof Locatable; + } + }, + + HERE(null, null) { + @Override + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + throw new IllegalStateException("PlacementType.HERE cannot be used. Use PLAYER or WORLD instead."); + } + + @Override + public boolean canBeUsedBy(Actor actor) { + return PLAYER.canBeUsedBy(actor); + } + + @Override + public String getTranslationKey() { + throw new IllegalStateException("PlacementType.HERE cannot be used. Use PLAYER or WORLD instead."); + } + + @Override + public String getTranslationKeyWithOffset() { + throw new IllegalStateException("PlacementType.HERE cannot be used. Use PLAYER or WORLD instead."); + } + }, + + POS1("worldedit.toggleplace.pos1", "worldedit.toggleplace.pos1-offset") { + @Override + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + return selector.getPrimaryPosition(); + } + }, + + MIN("worldedit.toggleplace.min", "worldedit.toggleplace.min-offset") { + @Override + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + return selector.getRegion().getMinimumPoint(); + } + }, + + MAX("worldedit.toggleplace.max", "worldedit.toggleplace.max-offset") { + @Override + public BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException { + return selector.getRegion().getMaximumPoint(); + } + }; + + private final String translationKey; + private final String translationKeyWithOffset; + + PlacementType(String translationKey, String translationKeyWithOffset) { + this.translationKey = translationKey; + this.translationKeyWithOffset = translationKeyWithOffset; + } + + public abstract BlockVector3 getPlacementPosition(RegionSelector selector, Actor actor) throws IncompleteRegionException; + + public boolean canBeUsedBy(Actor actor) { + return true; + } + + public String getTranslationKey() { + return translationKey; + } + + public String getTranslationKeyWithOffset() { + return translationKeyWithOffset; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java index 2ea1d1d59..ff946e458 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java @@ -22,46 +22,38 @@ package com.sk89q.worldedit.util; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; -import java.util.Objects; - import static com.google.common.base.Preconditions.checkNotNull; /** * Represents a block located at some position. */ -public final class LocatedBlock { +public record LocatedBlock(BlockVector3 location, BaseBlock block) { - private final BlockVector3 location; - private final BaseBlock block; - - public LocatedBlock(BlockVector3 location, BaseBlock block) { - this.location = checkNotNull(location); - this.block = checkNotNull(block); + public LocatedBlock { + checkNotNull(location); + checkNotNull(block); } + /** + * Gets the location. + * + * @return The location + * @deprecated This class is now a record. Use {@link #location()} instead. + */ + @Deprecated(forRemoval = true, since = "TODO") public BlockVector3 getLocation() { - return location; + return this.location; } + /** + * Gets the block. + * + * @return The block + * @deprecated This class is now a record. Use {@link #block()} instead. + */ + @Deprecated(forRemoval = true, since = "TODO") public BaseBlock getBlock() { - return block; - } - - @Override - public int hashCode() { - return Objects.hash(location, block); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (this.getClass() != obj.getClass()) { - return false; - } - LocatedBlock lb = (LocatedBlock) obj; - return Objects.equals(location, lb.location) && Objects.equals(block, lb.block); + return this.block; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/DataReport.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/DataReport.java index 8a18f07b3..62e83a7b0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/DataReport.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/report/DataReport.java @@ -168,16 +168,7 @@ public class DataReport implements Report { } } - private static class Line { - - private final String key; - private final String value; - - public Line(String key, String value) { - this.key = key; - this.value = value; - } - + private record Line(String key, String value) { } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java index e8501da69..e7ec152a9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java @@ -28,21 +28,32 @@ import com.sk89q.worldedit.registry.NamespacedRegistry; /** * All the types of biomes in the game. */ -//FAWE start - RegistryItem +//FAWE start - RegistryItem + not a record (legacyId + internalId need mutability) public class BiomeType implements RegistryItem, Keyed, BiomePattern { //FAWE end public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("biome type", true); + //FAWE start private final String id; private int legacyId = -1; private int internalId; - //FAWE start public BiomeType(String id) { this.id = id; } + /** + * Gets the ID of this biome. + * + * @return The id + * @since TODO + */ + @Override + public String id() { + return this.id; + } + public int getLegacyId() { return legacyId; } @@ -60,13 +71,14 @@ public class BiomeType implements RegistryItem, Keyed, BiomePattern { public int getInternalId() { return internalId; } - //FAWE end /** * Gets the ID of this biome. * * @return The id + * @deprecated use {@link #id()} */ + @Deprecated(forRemoval = true, since = "TODO") @Override public String getId() { return this.id; @@ -74,20 +86,19 @@ public class BiomeType implements RegistryItem, Keyed, BiomePattern { @Override public String toString() { - return getId(); + return id(); } @Override public int hashCode() { - //FAWE start - internalId > hashCode - return this.internalId; // stop changing this - //FAWE end + return this.internalId; // stop changing this (ok) } @Override public boolean equals(Object obj) { return obj instanceof BiomeType && this.id.equals(((BiomeType) obj).id); } + //FAWE end @Override public BiomeType applyBiome(BlockVector3 position) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java index 5a530c8a6..1faf3bc4c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java @@ -23,13 +23,15 @@ import com.fastasyncworldedit.core.registry.RegistryItem; import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; -//FAWE start - implements RegistryItem +//FAWE start - implements RegistryItem, not a record (internalId needs mutability) public class EntityType implements RegistryItem, Keyed { //FAWE end public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("entity type", true); + //FAWE start private final String id; + private int internalId; public EntityType(String id) { // If it has no namespace, assume minecraft. @@ -39,14 +41,28 @@ public class EntityType implements RegistryItem, Keyed { this.id = id; } + /** + * Gets the id of this entity type. + * + * @return the id + * @since TODO + */ + public String id() { + return this.id; + } + + /** + * Gets the id of this entity type. + * + * @return the id + * @deprecated use {@link #id()} + */ + @Deprecated(forRemoval = true, since = "TODO") @Override public String getId() { return this.id; } - //FAWE start - private int internalId; - @Override public void setInternalId(int internalId) { this.internalId = internalId; @@ -64,14 +80,15 @@ public class EntityType implements RegistryItem, Keyed { * @return The name, or ID */ public String getName() { - return getId(); + return id(); } @Override public String toString() { - return getId(); + return id(); } + //FAWE start @Override public int hashCode() { return this.id.hashCode(); @@ -81,5 +98,6 @@ public class EntityType implements RegistryItem, Keyed { public boolean equals(Object obj) { return obj instanceof EntityType && this.id.equals(((EntityType) obj).id); } + //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java index d62d13b51..1642ed4e9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java @@ -24,15 +24,15 @@ import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; /** - * Minecraft now has a 'fluid' system. This is a - * stub class to represent what it may be in the future. + * Minecraft now has a 'fluid' system. This is a stub class to represent what it may be in the future. */ -//FAWE start - implements RegistryItem +//FAWE start - implements RegistryItem, not a record (internalId needs mutability) public class FluidType implements RegistryItem, Keyed { //FAWE end public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("fluid type"); + //FAWE start private final String id; public FluidType(String id) { @@ -43,7 +43,19 @@ public class FluidType implements RegistryItem, Keyed { * Gets the ID of this block. * * @return The id + * @since TODO */ + public String id() { + return this.id; + } + + /** + * Gets the ID of this block. + * + * @return The id + * @deprecated use {@link #id()} + */ + @Deprecated(forRemoval = true, since = "TODO") @Override public String getId() { return this.id; @@ -67,7 +79,7 @@ public class FluidType implements RegistryItem, Keyed { @Override public String toString() { - return getId(); + return id(); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameMode.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameMode.java index 312caa3b5..94b7b7cfe 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameMode.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameMode.java @@ -22,43 +22,21 @@ package com.sk89q.worldedit.world.gamemode; import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.Registry; -public class GameMode implements Keyed { +public record GameMode(String id) implements Keyed { public static final Registry REGISTRY = new Registry<>("game mode"); - private final String id; - - public GameMode(String id) { - this.id = id; - } - - @Override - public String getId() { - return this.id; - } - /** * Gets the name of this game mode, or the ID if the name cannot be found. * * @return The name, or ID */ public String getName() { - return getId(); + return id(); } @Override public String toString() { - return getId(); + return id(); } - - @Override - public int hashCode() { - return this.id.hashCode(); - } - - @Override - public boolean equals(Object obj) { - return obj instanceof GameMode && this.id.equals(((GameMode) obj).id); - } - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java index 19fe653fc..db63b53a4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java @@ -19,20 +19,53 @@ package com.sk89q.worldedit.world.registry; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; + public interface ItemMaterial { + /** + * Gets the the maximum quantity of this item that can be in a single stack. + * + * @return the maximum quantity + * @deprecated Use {@link #maxStackSize()} instead. + */ + @Deprecated(forRemoval = true, since = "TODO") + default int getMaxStackSize() { + return maxStackSize(); + } /** * Gets the the maximum quantity of this item that can be in a single stack. * * @return the maximum quantity + * @since TODO */ - int getMaxStackSize(); + @NonAbstractForCompatibility(delegateName = "getMaxStackSize", delegateParams = {}) + default int maxStackSize() { + DeprecationUtil.checkDelegatingOverride(getClass()); + return getMaxStackSize(); + } /** * Gets the the maximum damage this item can take before being broken. * * @return the maximum damage, or 0 if not applicable + * @deprecated Use {@link #maxDamage()} instead. */ - int getMaxDamage(); + @Deprecated(forRemoval = true, since = "TODO") + default int getMaxDamage() { + return maxDamage(); + } + /** + * Gets the the maximum damage this item can take before being broken. + * + * @return the maximum damage, or 0 if not applicable + * @since TODO + */ + @NonAbstractForCompatibility(delegateName = "getMaxDamage", delegateParams = {}) + default int maxDamage() { + DeprecationUtil.checkDelegatingOverride(getClass()); + return getMaxDamage(); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughItemMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughItemMaterial.java index 681add8cc..e5dac8a7f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughItemMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughItemMaterial.java @@ -34,13 +34,13 @@ public class PassthroughItemMaterial implements ItemMaterial { } @Override - public int getMaxStackSize() { - return itemMaterial.getMaxStackSize(); + public int maxStackSize() { + return itemMaterial.maxStackSize(); } @Override - public int getMaxDamage() { - return itemMaterial.getMaxDamage(); + public int maxDamage() { + return itemMaterial.maxDamage(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleItemMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleItemMaterial.java index 40ed03515..9e552e18a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleItemMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/SimpleItemMaterial.java @@ -19,24 +19,6 @@ package com.sk89q.worldedit.world.registry; -public class SimpleItemMaterial implements ItemMaterial { - - private final int maxStackSize; - private final int maxDamage; - - public SimpleItemMaterial(int maxStackSize, int maxDamage) { - this.maxStackSize = maxStackSize; - this.maxDamage = maxDamage; - } - - @Override - public int getMaxStackSize() { - return maxStackSize; - } - - @Override - public int getMaxDamage() { - return maxDamage; - } +public record SimpleItemMaterial(int maxStackSize, int maxDamage) implements ItemMaterial { } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherType.java index ea78ee112..4a7b3cd0c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherType.java @@ -22,43 +22,20 @@ package com.sk89q.worldedit.world.weather; import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.Registry; -public class WeatherType implements Keyed { - +public record WeatherType(String id) implements Keyed { public static final Registry REGISTRY = new Registry<>("weather type"); - private final String id; - - public WeatherType(String id) { - this.id = id; - } - - @Override - public String getId() { - return this.id; - } - /** * Gets the name of this weather, or the ID if the name cannot be found. * * @return The name, or ID */ public String getName() { - return getId(); + return id(); } @Override public String toString() { - return getId(); + return id(); } - - @Override - public int hashCode() { - return this.id.hashCode(); - } - - @Override - public boolean equals(Object obj) { - return obj instanceof WeatherType && this.id.equals(((WeatherType) obj).id); - } - } From a87124821f3922e6f13c809f3291d37197bcf989 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 01:53:35 +0000 Subject: [PATCH 13/15] Update dependency com.palmergames.bukkit.towny:towny to v0.100.2.14 (#2774) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 12c34eeca..bb46a654c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.2.12" +towny = "0.100.2.14" plotsquared = "7.3.8" # Third party From c6e297942f60709cd4ec57e75b26e3bc80bccf3f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 01:54:22 +0000 Subject: [PATCH 14/15] Update dependency paperweight-userdev to v1.20.6-R0.1-20240604.210637-112 (#2775) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts index 43bc53f15..a2b5aa66d 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/ - the().paperDevBundle("1.20.6-R0.1-20240602.222958-106") + the().paperDevBundle("1.20.6-R0.1-20240604.210637-112") compileOnly(libs.paperlib) } From 62297f9479db21ba62a71e31e14f3c29ca28c478 Mon Sep 17 00:00:00 2001 From: Jordan Date: Mon, 10 Jun 2024 20:11:04 +0200 Subject: [PATCH 15/15] refactor: adjust chunk sending (#2770) - synchronise on the chunk GET object (when available) - kick it off to be run at some point on the main server thread --- .../PaperweightFaweWorldNativeAccess.java | 4 +- .../fawe/v1_19_R3/PaperweightGetBlocks.java | 6 +-- .../v1_19_R3/PaperweightPlatformAdapter.java | 41 +++++++++++-------- .../PaperweightStarlightRelighter.java | 2 +- .../PaperweightFaweWorldNativeAccess.java | 4 +- .../fawe/v1_20_R1/PaperweightGetBlocks.java | 6 +-- .../v1_20_R1/PaperweightPlatformAdapter.java | 37 +++++++++-------- .../PaperweightStarlightRelighter.java | 2 +- .../PaperweightFaweWorldNativeAccess.java | 4 +- .../fawe/v1_20_R2/PaperweightGetBlocks.java | 6 +-- .../v1_20_R2/PaperweightPlatformAdapter.java | 37 +++++++++-------- .../PaperweightStarlightRelighter.java | 2 +- .../PaperweightFaweWorldNativeAccess.java | 4 +- .../fawe/v1_20_R3/PaperweightGetBlocks.java | 9 ++-- .../v1_20_R3/PaperweightPlatformAdapter.java | 37 +++++++++-------- .../PaperweightStarlightRelighter.java | 2 +- .../PaperweightFaweWorldNativeAccess.java | 4 +- .../fawe/v1_20_R4/PaperweightGetBlocks.java | 6 +-- .../v1_20_R4/PaperweightPlatformAdapter.java | 37 +++++++++-------- .../PaperweightStarlightRelighter.java | 2 +- .../bukkit/adapter/BukkitGetBlocks.java | 2 +- .../bukkit/adapter/NMSAdapter.java | 2 +- 22 files changed, 139 insertions(+), 117 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweWorldNativeAccess.java index dbe0150a9..91fa70546 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweWorldNativeAccess.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweWorldNativeAccess.java @@ -246,7 +246,7 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess { + MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - true, - false // last false is to not bother with x-ray - ); + synchronized (chunk) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + true, + false // last false is to not bother with x-ray + ); + } } else { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - true - ); + synchronized (chunk) { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + true + ); + } } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java index 580bbf5a6..b1e0c5772 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java @@ -67,7 +67,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter { + MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - // last false is to not bother with x-ray - ); + synchronized (chunk) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); + } } else { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); + synchronized (chunk) { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); + } } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java index 30df91459..7de83af21 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java @@ -67,7 +67,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter { + MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - // last false is to not bother with x-ray - ); + synchronized (chunk) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); + } } else { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); + synchronized (chunk) { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); + } } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java index e869046da..addf03867 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightStarlightRelighter.java @@ -67,7 +67,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter biomeRegistry; private final IdMap> biomeHolderIdMap; private final ConcurrentHashMap copies = new ConcurrentHashMap<>(); - private final Object sendLock = new Object(); private LevelChunkSection[] sections; private LevelChunk levelChunk; private DataLayer[] blockLight; @@ -808,7 +807,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc nmsChunk.setUnsaved(true); // send to player if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING) { - this.send(finalMask, finalLightUpdate); + this.send(); } if (finalizer != null) { finalizer.run(); @@ -904,10 +903,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } @Override - public void send(int mask, boolean lighting) { - synchronized (sendLock) { - PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); - } + public void send() { + PaperweightPlatformAdapter.sendChunk(this, serverLevel, chunkX, chunkZ); } /** diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java index 23de00ade..2f25bc6f1 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java @@ -26,6 +26,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.IdMap; import net.minecraft.core.Registry; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; @@ -332,7 +333,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } @SuppressWarnings("deprecation") - public static void sendChunk(ServerLevel nmsWorld, int chunkX, int chunkZ, boolean lighting) { + public static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int chunkZ) { ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ); if (chunkHolder == null) { return; @@ -353,24 +354,28 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { if (levelChunk == null) { return; } - TaskManager.taskManager().task(() -> { + MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - // last false is to not bother with x-ray - ); + synchronized (chunk) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); + } } else { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); + synchronized (chunk) { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); + } } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java index 49f02bf8d..d9109b4df 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightStarlightRelighter.java @@ -67,7 +67,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter { + MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - // last false is to not bother with x-ray - ); + synchronized (chunk) { + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); + } } else { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); + synchronized (chunk) { + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); + } } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighter.java index 476978b57..ae09dcc58 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightStarlightRelighter.java @@ -67,7 +67,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter