diff --git a/build.gradle.kts b/build.gradle.kts index 7ef251b..dae6e1c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,78 +5,78 @@ import java.util.zip.ZipEntry import java.util.zip.ZipOutputStream plugins { - id("org.jetbrains.kotlin.jvm") version "1.9.23" - id("com.github.johnrengelman.shadow") version "8.1.1" - id("eclipse") + id("java") // Tell gradle this is a java project. + id("java-library") // Import helper for source-based libraries. + id("com.diffplug.spotless") version "7.0.4" + id("com.gradleup.shadow") version "8.3.6" // Import shadow API. + eclipse // Import eclipse plugin for IDE integration. +} + +java { + // Declare java version. + sourceCompatibility = JavaVersion.VERSION_17 } group = "net.trueog.wets-og" // Declare bundle identifier. -version = "1.2" - +version = "1.2" // Declare plugin version (will be in .jar). val apiVersion = "1.19" tasks.named("processResources") { val props = mapOf( "version" to version, - "apiVersion" to apiVersion, + "apiVersion" to apiVersion ) + inputs.properties(props) // Indicates to rerun if version changes. + filesMatching("plugin.yml") { expand(props) } + from("LICENSE") { // Bundle license into .jars. + into("/") + } } repositories { - mavenCentral() - + gradlePluginPortal() maven { url = uri("https://repo.purpurmc.org/snapshots") } - maven { - url = uri("https://maven.enginehub.org/repo") // Get WorldEdit API from EngineHub Repository. - } - + maven { + url = uri("https://maven.enginehub.org/repo") // Get WorldEdit API from EngineHub Repository. + } } dependencies { - compileOnly("org.purpurmc.purpur:purpur-api:1.19.4-R0.1-SNAPSHOT") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0") - compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.2.14") + compileOnly("org.purpurmc.purpur:purpur-api:1.19.4-R0.1-SNAPSHOT") // Declare purpur API version to be packaged. + compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.3.0-SNAPSHOT") // Import WorldEdit API. } -tasks.withType().configureEach { +tasks.withType().configureEach { // Ensure reproducible .jars isPreserveFileTimestamps = false isReproducibleFileOrder = true } tasks.shadowJar { + archiveClassifier.set("") // Use empty string instead of null. minimize() } -tasks.shadowJar.configure { - archiveClassifier.set("") - from("LICENSE") { - into("/") - } +tasks.build { + dependsOn(tasks.spotlessApply) + dependsOn(tasks.shadowJar) } tasks.jar { - dependsOn("shadowJar") -} - -tasks.jar.configure { archiveClassifier.set("part") } tasks.withType().configureEach { options.compilerArgs.add("-parameters") - options.encoding = "UTF-8" - options.forkOptions.executable = File(options.forkOptions.javaHome, "bin/javac").path -} - -kotlin { - jvmToolchain(17) + options.compilerArgs.add("-Xlint:deprecation") // Triggers deprecation warning messages. + options.encoding = "UTF-8" + options.isFork = true } java { @@ -85,3 +85,10 @@ java { vendor = JvmVendorSpec.GRAAL_VM } } + +spotless { + java { + removeUnusedImports() + palantirJavaFormat() + } +} diff --git a/gradle.properties b/gradle.properties index 0d43b6b..1bc8cb9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,4 +2,4 @@ org.gradle.jvmargs=-Xmx1G org.gradle.parallel=false org.gradle.caching=false group=ar.emily -version=0.0.4 +version=0.0.5 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e644113..1b33c55 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23..002b867 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a4..23d15a9 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -112,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -203,7 +205,7 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. @@ -211,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 25da30d..db3a6ac 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -68,11 +70,11 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/src/main/java/ar/emily/wets/bukkit/AbstractScheduler.java b/src/main/java/ar/emily/wets/bukkit/AbstractScheduler.java index baff43c..71bc8f8 100644 --- a/src/main/java/ar/emily/wets/bukkit/AbstractScheduler.java +++ b/src/main/java/ar/emily/wets/bukkit/AbstractScheduler.java @@ -8,78 +8,77 @@ import java.util.function.IntSupplier; public final class AbstractScheduler implements Scheduler { - private final IntSupplier currentTickGetter; - private final Queue pendingTasks = new ArrayDeque<>(); - private final Queue tasks = new ArrayDeque<>(); - private final Consumer underlyingScheduler; + private final IntSupplier currentTickGetter; + private final Queue pendingTasks = new ArrayDeque<>(); + private final Queue tasks = new ArrayDeque<>(); + private final Consumer underlyingScheduler; - public AbstractScheduler(final IntSupplier currentTickGetter, final Consumer underlyingScheduler) { - this.currentTickGetter = currentTickGetter; - this.underlyingScheduler = underlyingScheduler; - } + public AbstractScheduler(final IntSupplier currentTickGetter, final Consumer underlyingScheduler) { + this.currentTickGetter = currentTickGetter; + this.underlyingScheduler = underlyingScheduler; + } - public void setup() { - this.underlyingScheduler.accept(() -> { - processPendingTasks(); - processTasks(); - }); - } + public void setup() { + this.underlyingScheduler.accept(() -> { + processPendingTasks(); + processTasks(); + }); + } - @Override - public void runPeriodically(final Consumer action, final long initialDelay, final long period) { - this.pendingTasks.add(new AbstractTask(action, this.currentTickGetter.getAsInt(), initialDelay, period)); - } + @Override + public void runPeriodically(final Consumer action, final long initialDelay, final long period) { + this.pendingTasks.add(new AbstractTask(action, this.currentTickGetter.getAsInt(), initialDelay, period)); + } - public void flush() { - this.tasks.addAll(this.pendingTasks); - this.pendingTasks.clear(); + public void flush() { + this.tasks.addAll(this.pendingTasks); + this.pendingTasks.clear(); - final Iterator it = this.tasks.iterator(); - while (it.hasNext()) { - final AbstractTask task = it.next(); - task.task.accept(it::remove); - } + final Iterator it = this.tasks.iterator(); + while (it.hasNext()) { + final AbstractTask task = it.next(); + task.task.accept(it::remove); + } - this.tasks.clear(); - } + this.tasks.clear(); + } - private void processPendingTasks() { - final int currentTick = this.currentTickGetter.getAsInt(); - final Iterator it = this.pendingTasks.iterator(); - while (it.hasNext()) { - final AbstractTask task = it.next(); - if (task.registerTick + task.initialDelay >= currentTick) { - this.tasks.add(task); - task.registerTick = currentTick; - it.remove(); - } - } - } + private void processPendingTasks() { + final int currentTick = this.currentTickGetter.getAsInt(); + final Iterator it = this.pendingTasks.iterator(); + while (it.hasNext()) { + final AbstractTask task = it.next(); + if (task.registerTick + task.initialDelay >= currentTick) { + this.tasks.add(task); + task.registerTick = currentTick; + it.remove(); + } + } + } - private void processTasks() { - final int currentTick = this.currentTickGetter.getAsInt(); - final Iterator it = this.tasks.iterator(); - while (it.hasNext()) { - final AbstractTask task = it.next(); - if ((currentTick - task.registerTick) % task.period == 0) { - task.task.accept(it::remove); - } - } - } + private void processTasks() { + final int currentTick = this.currentTickGetter.getAsInt(); + final Iterator it = this.tasks.iterator(); + while (it.hasNext()) { + final AbstractTask task = it.next(); + if ((currentTick - task.registerTick) % task.period == 0) { + task.task.accept(it::remove); + } + } + } - private static final class AbstractTask { + private static final class AbstractTask { - final Consumer task; - final long initialDelay; - final long period; - long registerTick; + final Consumer task; + final long initialDelay; + final long period; + long registerTick; - AbstractTask(final Consumer task, final long registerTick, final long initialDelay, final long period) { - this.task = task; - this.registerTick = registerTick; - this.initialDelay = Math.min(initialDelay, 1); - this.period = Math.min(period, 1); - } - } - -} \ No newline at end of file + AbstractTask(final Consumer task, final long registerTick, final long initialDelay, final long period) { + this.task = task; + this.registerTick = registerTick; + this.initialDelay = Math.min(initialDelay, 1); + this.period = Math.min(period, 1); + } + } +} diff --git a/src/main/java/ar/emily/wets/bukkit/Scheduler.java b/src/main/java/ar/emily/wets/bukkit/Scheduler.java index d193c4c..616abcd 100644 --- a/src/main/java/ar/emily/wets/bukkit/Scheduler.java +++ b/src/main/java/ar/emily/wets/bukkit/Scheduler.java @@ -4,13 +4,13 @@ import java.util.function.Consumer; public interface Scheduler { - void flush(); - void runPeriodically(Consumer action, long initialDelay, long period); + void flush(); - @FunctionalInterface - interface Task { + void runPeriodically(Consumer action, long initialDelay, long period); - void cancel(); - } + @FunctionalInterface + interface Task { -} \ No newline at end of file + void cancel(); + } +} diff --git a/src/main/java/ar/emily/wets/bukkit/Utils.java b/src/main/java/ar/emily/wets/bukkit/Utils.java index d386901..080225c 100644 --- a/src/main/java/ar/emily/wets/bukkit/Utils.java +++ b/src/main/java/ar/emily/wets/bukkit/Utils.java @@ -4,79 +4,68 @@ import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; public class Utils { - public static String legacySerializerAnyCase(String subject) { + public static String legacySerializerAnyCase(String subject) { - int count = 0; - // Count the number of '&' characters to determine the size of the array - for (char c : subject.toCharArray()) { + int count = 0; + // Count the number of '&' characters to determine the size of the array + for (char c : subject.toCharArray()) { - if (c == '&') { + if (c == '&') { - count++; + count++; + } + } - } + // Create an array to store the positions of '&' characters + int[] positions = new int[count]; + int index = 0; + // Find the positions of '&' characters and store in the array + for (int i = 0; i < subject.length(); i++) { - } + if (subject.charAt(i) == '&') { - // Create an array to store the positions of '&' characters - int[] positions = new int[count]; - int index = 0; - // Find the positions of '&' characters and store in the array - for (int i = 0; i < subject.length(); i++) { + if (isUpperBukkitCode(subject.charAt(i + 1))) { - if (subject.charAt(i) == '&') { + subject = replaceCharAtIndex(subject, (i + 1), Character.toLowerCase(subject.charAt(i + 1))); + } - if (isUpperBukkitCode(subject.charAt(i + 1))) { + positions[index++] = i; + } + } - subject = replaceCharAtIndex(subject, (i + 1), Character.toLowerCase(subject.charAt(i + 1))); + String serializedText = LegacyComponentSerializer.legacySection() + .serialize(LegacyComponentSerializer.legacyAmpersand().deserialize(subject)); - } + return serializedText; + } - positions[index++] = i; + private static boolean isUpperBukkitCode(char input) { - } + char[] bukkitColorCodes = {'A', 'B', 'C', 'D', 'E', 'F', 'K', 'L', 'M', 'N', 'O', 'R'}; + boolean match = false; - } + // Loop through each character in the array. + for (char c : bukkitColorCodes) { + // Check if the current character in the array is equal to the input character. + if (c == input) { - String serializedText = LegacyComponentSerializer.legacySection().serialize(LegacyComponentSerializer.legacyAmpersand().deserialize(subject)); + match = true; + } + } - return serializedText; + return match; + } - } + private static String replaceCharAtIndex(String original, int index, char newChar) { - private static boolean isUpperBukkitCode(char input) { + // Check if the index is valid + if (index >= 0 && index < original.length()) { - char[] bukkitColorCodes = {'A', 'B', 'C', 'D', 'E', 'F', 'K', 'L', 'M', 'N', 'O', 'R'}; - boolean match = false; + // Create a new string with the replaced character + return original.substring(0, index) + newChar + original.substring(index + 1); + } - // Loop through each character in the array. - for (char c : bukkitColorCodes) { - // Check if the current character in the array is equal to the input character. - if (c == input) { - - match = true; - - } - - } - - return match; - - } - - private static String replaceCharAtIndex(String original, int index, char newChar) { - - // Check if the index is valid - if (index >= 0 && index < original.length()) { - - // Create a new string with the replaced character - return original.substring(0, index) + newChar + original.substring(index + 1); - - } - - // If the index is invalid, return the original string - return original; - - } - -} \ No newline at end of file + // If the index is invalid, return the original string + return original; + } +} diff --git a/src/main/java/ar/emily/wets/bukkit/V5UUID.java b/src/main/java/ar/emily/wets/bukkit/V5UUID.java index 0a36be1..d2c38a9 100644 --- a/src/main/java/ar/emily/wets/bukkit/V5UUID.java +++ b/src/main/java/ar/emily/wets/bukkit/V5UUID.java @@ -11,45 +11,40 @@ import java.util.UUID; // why am I overcomplicating this? final class V5UUID { - private static final VarHandle AS_LONG_ARRAY = byteArrayViewVarHandle(long[].class, ByteOrder.BIG_ENDIAN); - private static final MessageDigest MD; + private static final VarHandle AS_LONG_ARRAY = byteArrayViewVarHandle(long[].class, ByteOrder.BIG_ENDIAN); + private static final MessageDigest MD; - static { - try { - MD = MessageDigest.getInstance("SHA-1"); - } catch (final NoSuchAlgorithmException ex) { - // shouldn't throw, SHA-1 is a standard algorithm that is required by Java SE - // https://docs.oracle.com/en/java/javase/17/docs/specs/security/standard-names.html - throw new ExceptionInInitializerError(ex); - } - } + static { + try { + MD = MessageDigest.getInstance("SHA-1"); + } catch (final NoSuchAlgorithmException ex) { + // shouldn't throw, SHA-1 is a standard algorithm that is required by Java SE + // https://docs.oracle.com/en/java/javase/17/docs/specs/security/standard-names.html + throw new ExceptionInInitializerError(ex); + } + } - // MessageDigest isn't thread safe, that's why it's being cloned - private static MessageDigest md() { - try { - return (MessageDigest) MD.clone(); - } catch (final CloneNotSupportedException ex) { - // shouldn't throw - throw new RuntimeException(ex); - } - } + // MessageDigest isn't thread safe, that's why it's being cloned + private static MessageDigest md() { + try { + return (MessageDigest) MD.clone(); + } catch (final CloneNotSupportedException ex) { + // shouldn't throw + throw new RuntimeException(ex); + } + } - // use V5 UUID as to not collide with V3 or V4 UUIDs, which are used by the game - static UUID create(final byte[] bs) { - final var md = md(); - md.update(bs); - final byte[] digest = md.digest(); - digest[6] &= 0x0f; // clear version - digest[6] |= 0x50; // set version 5 - digest[8] &= 0x3f; // clear variant - digest[8] |= (byte) 0x80; // set variant 1 - return new UUID( - (long) AS_LONG_ARRAY.get(digest, 0), - (long) AS_LONG_ARRAY.get(digest, 8) - ); - } - - private V5UUID() { - } + // use V5 UUID as to not collide with V3 or V4 UUIDs, which are used by the game + static UUID create(final byte[] bs) { + final var md = md(); + md.update(bs); + final byte[] digest = md.digest(); + digest[6] &= 0x0f; // clear version + digest[6] |= 0x50; // set version 5 + digest[8] &= 0x3f; // clear variant + digest[8] |= (byte) 0x80; // set variant 1 + return new UUID((long) AS_LONG_ARRAY.get(digest, 0), (long) AS_LONG_ARRAY.get(digest, 8)); + } + private V5UUID() {} } diff --git a/src/main/java/ar/emily/wets/bukkit/WESpread.java b/src/main/java/ar/emily/wets/bukkit/WESpread.java index b5d9d6d..e5f4637 100644 --- a/src/main/java/ar/emily/wets/bukkit/WESpread.java +++ b/src/main/java/ar/emily/wets/bukkit/WESpread.java @@ -1,23 +1,5 @@ package ar.emily.wets.bukkit; -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; -import java.util.function.LongSupplier; -import java.util.stream.Stream; - -import org.bukkit.configuration.InvalidConfigurationException; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.jetbrains.annotations.Nullable; - import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; @@ -37,21 +19,36 @@ import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; - import it.unimi.dsi.fastutil.objects.Object2LongMap; import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.function.LongSupplier; +import java.util.stream.Stream; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.jetbrains.annotations.Nullable; public final class WESpread { - public static final UUID NON_PLAYER_ACTOR_ID = - V5UUID.create(WESpread.class.descriptorString().getBytes(StandardCharsets.UTF_8)); + public static final UUID NON_PLAYER_ACTOR_ID = + V5UUID.create(WESpread.class.descriptorString().getBytes(StandardCharsets.UTF_8)); - private AbstractScheduler scheduler; + private AbstractScheduler scheduler; - File configFile = new File("plugins/WETS-OG/config.yml"); + File configFile = new File("plugins/WETS-OG/config.yml"); public static FileConfiguration convertFileToConfig(File file) { - FileConfiguration config = YamlConfiguration.loadConfiguration(file); + FileConfiguration config = YamlConfiguration.loadConfiguration(file); try { config.load(file); @@ -62,154 +59,165 @@ public final class WESpread { return config; } - FileConfiguration configFileYAML = convertFileToConfig(configFile); + FileConfiguration configFileYAML = convertFileToConfig(configFile); - public WESpread(AbstractScheduler scheduler) { - this.scheduler = scheduler; - } + public WESpread(AbstractScheduler scheduler) { + this.scheduler = scheduler; + } - private final Component INVALID_ARGUMENT = TextComponent.of(Utils.legacySerializerAnyCase(Utils.legacySerializerAnyCase(configFileYAML.getString("ChatPrefix") + "&cERROR: Blocks per tick must be a valid positive number!"))); - private final Component COMMAND_USAGE = TextComponent.of(Utils.legacySerializerAnyCase(configFileYAML.getString("ChatPrefix") + "&6Usage: &e/wets ( | sorted | not-sorted)")); - private final Component COMMAND_SORTED = TextComponent.of(Utils.legacySerializerAnyCase(configFileYAML.getString("ChatPrefix") + "&6Block placement of new operations will now be &esorted&6.")); - private final Component COMMAND_NOT_SORTED = TextComponent.of(Utils.legacySerializerAnyCase(configFileYAML.getString("ChatPrefix") + "&6Block placement of new operations will now be &eunsorted&6.")); - private final Component COMMAND_BPT_UPDATED = TextComponent.of(Utils.legacySerializerAnyCase(configFileYAML.getString("ChatPrefix") + "&aBlocks per tick placement set to: ")); + private final Component INVALID_ARGUMENT = TextComponent.of( + Utils.legacySerializerAnyCase(Utils.legacySerializerAnyCase(configFileYAML.getString("ChatPrefix") + + "&cERROR: Blocks per tick must be a valid positive number!"))); + private final Component COMMAND_USAGE = TextComponent.of(Utils.legacySerializerAnyCase( + configFileYAML.getString("ChatPrefix") + "&6Usage: &e/wets ( | sorted | not-sorted)")); + private final Component COMMAND_SORTED = TextComponent.of(Utils.legacySerializerAnyCase( + configFileYAML.getString("ChatPrefix") + "&6Block placement of new operations will now be &esorted&6.")); + private final Component COMMAND_NOT_SORTED = TextComponent.of(Utils.legacySerializerAnyCase( + configFileYAML.getString("ChatPrefix") + "&6Block placement of new operations will now be &eunsorted&6.")); + private final Component COMMAND_BPT_UPDATED = TextComponent.of(Utils.legacySerializerAnyCase( + configFileYAML.getString("ChatPrefix") + "&aBlocks per tick placement set to: ")); - private final Object2LongMap blocksPerTickMap = new Object2LongOpenHashMap<>(); - private final Set actorsWhosePlacementIsNotSorted = new HashSet<>(); - private long defaultBlocksPerTick = configFileYAML.getInt("DefaultBlocksPerTick"); + private final Object2LongMap blocksPerTickMap = new Object2LongOpenHashMap<>(); + private final Set actorsWhosePlacementIsNotSorted = new HashSet<>(); + private long defaultBlocksPerTick = configFileYAML.getInt("DefaultBlocksPerTick"); - public void playerLogout(final UUID id) { - this.blocksPerTickMap.removeLong(id); - this.actorsWhosePlacementIsNotSorted.remove(id); - } + public void playerLogout(final UUID id) { + this.blocksPerTickMap.removeLong(id); + this.actorsWhosePlacementIsNotSorted.remove(id); + } - public void load() { - WorldEdit.getInstance().getEventBus().register(this); - } + public void load() { + WorldEdit.getInstance().getEventBus().register(this); + } - // We really really really want to flush the queue before WorldEdit itself unloads. - @Subscribe(priority = EventHandler.Priority.VERY_EARLY) - public void on(final PlatformUnreadyEvent event) { - WorldEdit.getInstance().getEventBus().unregister(this); - this.defaultBlocksPerTick = Long.MAX_VALUE; - this.blocksPerTickMap.clear(); - this.actorsWhosePlacementIsNotSorted.clear(); - this.scheduler.flush(); - } + // We really really really want to flush the queue before WorldEdit itself unloads. + @Subscribe(priority = EventHandler.Priority.VERY_EARLY) + public void on(final PlatformUnreadyEvent event) { + WorldEdit.getInstance().getEventBus().unregister(this); + this.defaultBlocksPerTick = Long.MAX_VALUE; + this.blocksPerTickMap.clear(); + this.actorsWhosePlacementIsNotSorted.clear(); + this.scheduler.flush(); + } - @Subscribe - public void on(final EditSessionEvent event) { - if (event.getStage() == EditSession.Stage.BEFORE_CHANGE) { - final UUID actorId = - Optional.ofNullable(event.getActor()) - // use a set ID for non-player actors, such as console or potentially API users - .filter(Actor::isPlayer) - .map(Identifiable::getUniqueId) - .orElse(NON_PLAYER_ACTOR_ID); - event.setExtent(new SchedulingExtent(event.getExtent(), actorId)); - } - } + @Subscribe + public void on(final EditSessionEvent event) { + if (event.getStage() == EditSession.Stage.BEFORE_CHANGE) { + final UUID actorId = Optional.ofNullable(event.getActor()) + // use a set ID for non-player actors, such as console or potentially API users + .filter(Actor::isPlayer) + .map(Identifiable::getUniqueId) + .orElse(NON_PLAYER_ACTOR_ID); + event.setExtent(new SchedulingExtent(event.getExtent(), actorId)); + } + } - public void command(final Actor source, final List args) { - if (args.size() != 1) { - source.print(COMMAND_USAGE); - return; - } + public void command(final Actor source, final List args) { + if (args.size() != 1) { + source.print(COMMAND_USAGE); + return; + } - final UUID id = source.isPlayer() ? source.getUniqueId() : NON_PLAYER_ACTOR_ID; - final String arg = args.iterator().next(); - if ("sorted".equals(arg)) { - this.actorsWhosePlacementIsNotSorted.remove(id); - source.print(COMMAND_SORTED); - return; - } else if ("not-sorted".equals(arg)) { - this.actorsWhosePlacementIsNotSorted.add(id); - source.print(COMMAND_NOT_SORTED); - return; - } + final UUID id = source.isPlayer() ? source.getUniqueId() : NON_PLAYER_ACTOR_ID; + final String arg = args.iterator().next(); + if ("sorted".equals(arg)) { + this.actorsWhosePlacementIsNotSorted.remove(id); + source.print(COMMAND_SORTED); + return; + } else if ("not-sorted".equals(arg)) { + this.actorsWhosePlacementIsNotSorted.add(id); + source.print(COMMAND_NOT_SORTED); + return; + } - try { - long blocksPerTick = Long.parseLong(arg); - if (blocksPerTick < 0) { blocksPerTick = Long.MAX_VALUE; } - this.blocksPerTickMap.put(id, blocksPerTick); - configFileYAML.set("DefaultBlocksPerTick", blocksPerTick); - try { - configFileYAML.save(configFile); - } - catch (IOException error) { - error.printStackTrace(); - } - source.print(COMMAND_BPT_UPDATED.append(TextComponent.of(Utils.legacySerializerAnyCase("&e" + String.valueOf(blocksPerTick))))); - } - catch (final NumberFormatException exception) { - source.printError(INVALID_ARGUMENT); - source.print(COMMAND_USAGE); - } - } + try { + long blocksPerTick = Long.parseLong(arg); + if (blocksPerTick < 0) { + blocksPerTick = Long.MAX_VALUE; + } + this.blocksPerTickMap.put(id, blocksPerTick); + configFileYAML.set("DefaultBlocksPerTick", blocksPerTick); + try { + configFileYAML.save(configFile); + } catch (IOException error) { + error.printStackTrace(); + } + source.print(COMMAND_BPT_UPDATED.append( + TextComponent.of(Utils.legacySerializerAnyCase("&e" + String.valueOf(blocksPerTick))))); + } catch (final NumberFormatException exception) { + source.printError(INVALID_ARGUMENT); + source.print(COMMAND_USAGE); + } + } - private final class SchedulingExtent extends AbstractBufferingExtent { + private final class SchedulingExtent extends AbstractBufferingExtent { - private final BlockMap buffer = BlockMap.createForBaseBlock(); - private final LongSupplier blocksPerTick; - private final boolean sorted; + private final BlockMap buffer = BlockMap.createForBaseBlock(); + private final LongSupplier blocksPerTick; + private final boolean sorted; - private SchedulingExtent(final Extent delegate, final UUID actor) { - super(delegate); - this.sorted = ! WESpread.this.actorsWhosePlacementIsNotSorted.contains(actor); - this.blocksPerTick = () -> WESpread.this.blocksPerTickMap.getOrDefault(actor, WESpread.this.defaultBlocksPerTick); - } + private SchedulingExtent(final Extent delegate, final UUID actor) { + super(delegate); + this.sorted = !WESpread.this.actorsWhosePlacementIsNotSorted.contains(actor); + this.blocksPerTick = + () -> WESpread.this.blocksPerTickMap.getOrDefault(actor, WESpread.this.defaultBlocksPerTick); + } - @Override - protected @Nullable BaseBlock getBufferedFullBlock(final BlockVector3 position) { - return this.buffer.computeIfAbsent(position, getExtent()::getFullBlock); - } + @Override + protected @Nullable BaseBlock getBufferedFullBlock(final BlockVector3 position) { + return this.buffer.computeIfAbsent(position, getExtent()::getFullBlock); + } - @Override - public > boolean setBlock(final BlockVector3 position, final T block) { - this.buffer.remove(position); // workaround silly WorldEdit bug, see https://github.com/emilyy-dev/wets/issues/1 - this.buffer.put(position, block.toBaseBlock()); - return true; - } + @Override + public > boolean setBlock(final BlockVector3 position, final T block) { + this.buffer.remove( + position); // workaround silly WorldEdit bug, see https://github.com/emilyy-dev/wets/issues/1 + this.buffer.put(position, block.toBaseBlock()); + return true; + } - @Override - protected Operation commitBefore() { - final Iterator> it; - { - Stream> stream = this.buffer.entrySet().stream(); - if (this.sorted) { stream = stream.sorted(Map.Entry.comparingByKey(BlockVector3.sortByCoordsYzx())); } - it = stream.iterator(); - } + @Override + protected Operation commitBefore() { + final Iterator> it; + { + Stream> stream = this.buffer.entrySet().stream(); + if (this.sorted) { + stream = stream.sorted(Map.Entry.comparingByKey(BlockVector3.sortByCoordsYzx())); + } + it = stream.iterator(); + } - return new Operation() { - boolean started = false; + return new Operation() { + boolean started = false; - @Override - public Operation resume(final RunContext run) { - if (! this.started && it.hasNext()) { - this.started = true; - WESpread.this.scheduler.runPeriodically(this::putBlock, 1L, 1L); - } + @Override + public Operation resume(final RunContext run) { + if (!this.started && it.hasNext()) { + this.started = true; + WESpread.this.scheduler.runPeriodically(this::putBlock, 1L, 1L); + } - return null; - } + return null; + } - private void putBlock(final Scheduler.Task task) { - try { - for (long i = 0; it.hasNext() && i < SchedulingExtent.this.blocksPerTick.getAsLong(); ++i) { - final var entry = it.next(); - setDelegateBlock(entry.getKey(), entry.getValue()); - } - } catch (final WorldEditException exception) { - throw new RuntimeException(exception); - } finally { - if (! it.hasNext()) { task.cancel(); } - } - } + private void putBlock(final Scheduler.Task task) { + try { + for (long i = 0; it.hasNext() && i < SchedulingExtent.this.blocksPerTick.getAsLong(); ++i) { + final var entry = it.next(); + setDelegateBlock(entry.getKey(), entry.getValue()); + } + } catch (final WorldEditException exception) { + throw new RuntimeException(exception); + } finally { + if (!it.hasNext()) { + task.cancel(); + } + } + } - @Override - public void cancel() { - } - }; - } - } -} \ No newline at end of file + @Override + public void cancel() {} + }; + } + } +} diff --git a/src/main/java/ar/emily/wets/bukkit/WESpreadPlugin.java b/src/main/java/ar/emily/wets/bukkit/WESpreadPlugin.java index 5f0d052..3cd8f3a 100644 --- a/src/main/java/ar/emily/wets/bukkit/WESpreadPlugin.java +++ b/src/main/java/ar/emily/wets/bukkit/WESpreadPlugin.java @@ -1,9 +1,9 @@ package ar.emily.wets.bukkit; +import com.sk89q.worldedit.bukkit.BukkitAdapter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; - import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.event.EventHandler; @@ -13,55 +13,47 @@ import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; -import com.sk89q.worldedit.bukkit.BukkitAdapter; - public final class WESpreadPlugin extends JavaPlugin implements Listener { - private static final List COMPLETIONS = List.of("sorted", "not-sorted"); + private static final List COMPLETIONS = List.of("sorted", "not-sorted"); - private final AbstractScheduler scheduler = - new AbstractScheduler( - getServer()::getCurrentTick, - task -> getServer().getScheduler().runTaskTimer(this, task, 1L, 1L) - ); - private final WESpread wetsSpread = new WESpread(this.scheduler); + private final AbstractScheduler scheduler = new AbstractScheduler( + getServer()::getCurrentTick, task -> getServer().getScheduler().runTaskTimer(this, task, 1L, 1L)); + private final WESpread wetsSpread = new WESpread(this.scheduler); - @EventHandler - public void on(final PlayerQuitEvent event) { - this.wetsSpread.playerLogout(event.getPlayer().getUniqueId()); - } + @EventHandler + public void on(final PlayerQuitEvent event) { + this.wetsSpread.playerLogout(event.getPlayer().getUniqueId()); + } - @Override - public void onLoad() { - this.wetsSpread.load(); - } + @Override + public void onLoad() { + this.wetsSpread.load(); + } - @Override - public void onEnable() { - saveDefaultConfig(); - this.scheduler.setup(); - getServer().getPluginManager().registerEvents(this, this); - } + @Override + public void onEnable() { + saveDefaultConfig(); + this.scheduler.setup(); + getServer().getPluginManager().registerEvents(this, this); + } - @Override - public boolean onCommand( - final @NotNull CommandSender sender, - final @NotNull Command command, - final @NotNull String label, - final String @NotNull [] args - ) { - this.wetsSpread.command(BukkitAdapter.adapt(sender), Arrays.asList(args)); - return true; - } + @Override + public boolean onCommand( + final @NotNull CommandSender sender, + final @NotNull Command command, + final @NotNull String label, + final String @NotNull [] args) { + this.wetsSpread.command(BukkitAdapter.adapt(sender), Arrays.asList(args)); + return true; + } - @Override - public @NotNull List onTabComplete( - final @NotNull CommandSender sender, - final @NotNull Command command, - final @NotNull String alias, - final String @NotNull [] args - ) { - return args.length == 1 ? StringUtil.copyPartialMatches(args[0], COMPLETIONS, new ArrayList<>(1)) : List.of(); - } - -} \ No newline at end of file + @Override + public @NotNull List onTabComplete( + final @NotNull CommandSender sender, + final @NotNull Command command, + final @NotNull String alias, + final String @NotNull [] args) { + return args.length == 1 ? StringUtil.copyPartialMatches(args[0], COMPLETIONS, new ArrayList<>(1)) : List.of(); + } +}