From 3c0ec809595193c68c3e3d47813ebe2f2f83ecb3 Mon Sep 17 00:00:00 2001 From: Yomamaeatstoes <114538961+Yomamaeatstoes@users.noreply.github.com> Date: Thu, 10 Sep 2026 10:22:03 -0400 Subject: [PATCH 1/3] fix: avoid private LevelChunk level access on 26.1 --- .../impl/fawe/v26_1/PaperweightGetBlocks_Copy.java | 2 +- .../impl/fawe/v26_1/PaperweightPlatformAdapter.java | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v26_1/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v26_1/PaperweightGetBlocks_Copy.java index e3effd6b66..360fbf0598 100644 --- a/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v26_1/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v26_1/PaperweightGetBlocks_Copy.java @@ -54,7 +54,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { this.levelChunk = levelChunk; - this.serverLevel = levelChunk.level; + this.serverLevel = (ServerLevel) levelChunk.getLevel(); this.minHeight = serverLevel.getMinY(); this.maxHeight = serverLevel.getMaxY() - 1; // Minecraft max limit is exclusive. this.blocks = new char[getSectionCount()][]; diff --git a/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v26_1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v26_1/PaperweightPlatformAdapter.java index 057f730ff7..830b0b7bf2 100644 --- a/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v26_1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v26_1/PaperweightPlatformAdapter.java @@ -653,11 +653,11 @@ public static BiomeType adapt(Holder biome, LevelAccessor levelAccessor) static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { try { - if (levelChunk.loaded || levelChunk.level.isClientSide()) { + if (levelChunk.loaded || levelChunk.getLevel().isClientSide()) { BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos()); if (blockEntity != null) { - if (!levelChunk.level.isClientSide()) { - methodRemoveGameEventListener.invoke(levelChunk, beacon, levelChunk.level); + if (!levelChunk.getLevel().isClientSide()) { + methodRemoveGameEventListener.invoke(levelChunk, beacon, levelChunk.getLevel()); } fieldRemove.set(beacon, true); } @@ -670,13 +670,13 @@ static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { static List getEntities(LevelChunk chunk) { if (PaperSupport.isPaper()) { - return Optional.ofNullable(chunk.level + return Optional.ofNullable(chunk.getLevel() .moonrise$getEntityLookup() .getChunk(chunk.locX, chunk.locZ)).map(ChunkEntitySlices::getAllEntities).orElse(Collections.emptyList()); } try { //noinspection unchecked - return getEntitySectionManager(chunk.level).getEntities(chunk.getPos()); + return getEntitySectionManager((ServerLevel) chunk.getLevel()).getEntities(chunk.getPos()); } catch (IllegalAccessException e) { throw new RuntimeException("Failed to lookup entities [PAPER=false]", e); } From ca82241c2cf2a9bf0c487ab82c8f75841b05999b Mon Sep 17 00:00:00 2001 From: Yomamaeatstoes <114538961+Yomamaeatstoes@users.noreply.github.com> Date: Sat, 17 Oct 2026 20:56:38 -0400 Subject: [PATCH 2/3] Fix command help when the FAWE platform is unavailable --- worldedit-bukkit/build.gradle.kts | 2 + .../bukkit/BukkitCommandInspector.java | 15 ++- .../bukkit/BukkitCommandInspectorTest.java | 117 ++++++++++++++++++ 3 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/BukkitCommandInspectorTest.java diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index 4fa170b7f5..be2518e14e 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -155,6 +155,8 @@ dependencies { testImplementation(libs.mockito.core) testImplementation(libs.adventureApi) testImplementation(libs.checkerqual) + // JavaPlugin exposes SLF4J in its API; it is normally supplied by the server. + testRuntimeOnly("org.slf4j:slf4j-api:2.0.17") } tasks.named("processResources") { diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java index de0c2c254f..c3b3fc3035 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java @@ -22,6 +22,7 @@ import com.sk89q.bukkit.util.CommandInspector; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.NoCapablePlatformException; import com.sk89q.worldedit.internal.util.LogManagerCompat; import org.apache.logging.log4j.Logger; import org.bukkit.command.Command; @@ -53,7 +54,13 @@ class BukkitCommandInspector implements CommandInspector { public String getShortText(Command command) { Optional mapping = dispatcher.getCommand(command.getName()); if (mapping.isPresent()) { - return reduceToText(mapping.get().getDescription(), WorldEdit.getInstance().getConfiguration().defaultLocale); + try { + return reduceToText(mapping.get().getDescription(), WorldEdit.getInstance().getConfiguration().defaultLocale); + } catch (NoCapablePlatformException e) { + // Bukkit can build help topics while the platform is unavailable (including after a failed enable). + // Use the text stored at command registration without consulting configuration or translations. + return command.getDescription(); + } } else { LOGGER.warn("BukkitCommandInspector doesn't know how about the command '" + command + "'"); return "Help text not available"; @@ -64,7 +71,11 @@ public String getShortText(Command command) { public String getFullText(Command command) { Optional mapping = dispatcher.getCommand(command.getName()); if (mapping.isPresent()) { - return reduceToText(mapping.get().getFullHelp(), WorldEdit.getInstance().getConfiguration().defaultLocale); + try { + return reduceToText(mapping.get().getFullHelp(), WorldEdit.getInstance().getConfiguration().defaultLocale); + } catch (NoCapablePlatformException e) { + return command.getUsage(); + } } else { LOGGER.warn("BukkitCommandInspector doesn't know how about the command '" + command + "'"); return "Help text not available"; diff --git a/worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/BukkitCommandInspectorTest.java b/worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/BukkitCommandInspectorTest.java new file mode 100644 index 0000000000..2cb60bf750 --- /dev/null +++ b/worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/BukkitCommandInspectorTest.java @@ -0,0 +1,117 @@ +/* + * 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.bukkit; + +import com.sk89q.bukkit.util.DynamicPluginCommand; +import com.sk89q.bukkit.util.DynamicPluginCommandHelpTopic; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.NoCapablePlatformException; +import com.sk89q.worldedit.util.formatting.WorldEditText; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import org.enginehub.piston.CommandManager; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +import java.util.Locale; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +class BukkitCommandInspectorTest { + + @Test + void helpTopicCanBeCreatedWithoutACapablePlatform() { + WorldEdit worldEdit = mock(WorldEdit.class); + when(worldEdit.getConfiguration()).thenThrow(new NoCapablePlatformException()); + try (MockedStatic singleton = mockStatic(WorldEdit.class)) { + singleton.when(WorldEdit::getInstance).thenReturn(worldEdit); + DynamicPluginCommand command = command(); + DynamicPluginCommandHelpTopic topic = new DynamicPluginCommandHelpTopic(command); + assertEquals("Stored description", topic.getShortText()); + assertEquals("/test ", topic.getFullText(null)); + } + } + + @Test + void helpUsesConfiguredLocaleWhenPlatformIsAvailable() { + WorldEdit worldEdit = mock(WorldEdit.class); + LocalConfiguration configuration = mock(LocalConfiguration.class); + configuration.defaultLocale = Locale.GERMAN; + when(worldEdit.getConfiguration()).thenReturn(configuration); + try (MockedStatic singleton = mockStatic(WorldEdit.class); + MockedStatic text = mockStatic(WorldEditText.class)) { + singleton.when(WorldEdit::getInstance).thenReturn(worldEdit); + text.when(() -> WorldEditText.reduceToText(TextComponent.of("description"), Locale.GERMAN)) + .thenReturn("Translated description"); + text.when(() -> WorldEditText.reduceToText(TextComponent.of("full help"), Locale.GERMAN)) + .thenReturn("Translated full help"); + DynamicPluginCommandHelpTopic topic = new DynamicPluginCommandHelpTopic(command()); + assertEquals("Translated description", topic.getShortText()); + assertEquals("Translated full help", topic.getFullText(null)); + } + } + + @Test + void helpAlsoFallsBackWhenTranslationPlatformIsUnavailable() { + WorldEdit worldEdit = mock(WorldEdit.class); + LocalConfiguration configuration = mock(LocalConfiguration.class); + configuration.defaultLocale = Locale.ENGLISH; + when(worldEdit.getConfiguration()).thenReturn(configuration); + try (MockedStatic singleton = mockStatic(WorldEdit.class); + MockedStatic text = mockStatic(WorldEditText.class)) { + singleton.when(WorldEdit::getInstance).thenReturn(worldEdit); + text.when(() -> WorldEditText.reduceToText(TextComponent.of("description"), Locale.ENGLISH)) + .thenThrow(new NoCapablePlatformException()); + text.when(() -> WorldEditText.reduceToText(TextComponent.of("full help"), Locale.ENGLISH)) + .thenThrow(new NoCapablePlatformException()); + DynamicPluginCommandHelpTopic topic = new DynamicPluginCommandHelpTopic(command()); + assertEquals("Stored description", topic.getShortText()); + assertEquals("/test ", topic.getFullText(null)); + } + } + + @Test + void unrelatedFailuresAreNotSuppressed() { + WorldEdit worldEdit = mock(WorldEdit.class); + when(worldEdit.getConfiguration()).thenThrow(new IllegalStateException("unrelated")); + try (MockedStatic singleton = mockStatic(WorldEdit.class)) { + singleton.when(WorldEdit::getInstance).thenReturn(worldEdit); + assertThrows(IllegalStateException.class, () -> new DynamicPluginCommandHelpTopic(command())); + } + } + + private DynamicPluginCommand command() { + WorldEditPlugin plugin = mock(WorldEditPlugin.class); + CommandManager dispatcher = mock(CommandManager.class); + org.enginehub.piston.Command mapping = mock(org.enginehub.piston.Command.class); + when(mapping.getDescription()).thenReturn(TextComponent.of("description")); + when(mapping.getFullHelp()).thenReturn(TextComponent.of("full help")); + when(dispatcher.getCommand("test")).thenReturn(Optional.of(mapping)); + BukkitCommandInspector inspector = new BukkitCommandInspector(plugin, dispatcher); + return new DynamicPluginCommand( + new String[]{"test"}, "Stored description", "/test ", plugin, inspector, plugin + ); + } +} From f11392e836666e670a3621bfabba23c7bc5bc908 Mon Sep 17 00:00:00 2001 From: Yomamaeatstoes <114538961+Yomamaeatstoes@users.noreply.github.com> Date: Mon, 19 Oct 2026 12:58:16 -0400 Subject: [PATCH 3/3] Remove oversized command help test --- worldedit-bukkit/build.gradle.kts | 2 - .../bukkit/BukkitCommandInspectorTest.java | 117 ------------------ 2 files changed, 119 deletions(-) delete mode 100644 worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/BukkitCommandInspectorTest.java diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index be2518e14e..4fa170b7f5 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -155,8 +155,6 @@ dependencies { testImplementation(libs.mockito.core) testImplementation(libs.adventureApi) testImplementation(libs.checkerqual) - // JavaPlugin exposes SLF4J in its API; it is normally supplied by the server. - testRuntimeOnly("org.slf4j:slf4j-api:2.0.17") } tasks.named("processResources") { diff --git a/worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/BukkitCommandInspectorTest.java b/worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/BukkitCommandInspectorTest.java deleted file mode 100644 index 2cb60bf750..0000000000 --- a/worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/BukkitCommandInspectorTest.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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.bukkit; - -import com.sk89q.bukkit.util.DynamicPluginCommand; -import com.sk89q.bukkit.util.DynamicPluginCommandHelpTopic; -import com.sk89q.worldedit.LocalConfiguration; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.extension.platform.NoCapablePlatformException; -import com.sk89q.worldedit.util.formatting.WorldEditText; -import com.sk89q.worldedit.util.formatting.text.TextComponent; -import org.enginehub.piston.CommandManager; -import org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; - -import java.util.Locale; -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.when; - -class BukkitCommandInspectorTest { - - @Test - void helpTopicCanBeCreatedWithoutACapablePlatform() { - WorldEdit worldEdit = mock(WorldEdit.class); - when(worldEdit.getConfiguration()).thenThrow(new NoCapablePlatformException()); - try (MockedStatic singleton = mockStatic(WorldEdit.class)) { - singleton.when(WorldEdit::getInstance).thenReturn(worldEdit); - DynamicPluginCommand command = command(); - DynamicPluginCommandHelpTopic topic = new DynamicPluginCommandHelpTopic(command); - assertEquals("Stored description", topic.getShortText()); - assertEquals("/test ", topic.getFullText(null)); - } - } - - @Test - void helpUsesConfiguredLocaleWhenPlatformIsAvailable() { - WorldEdit worldEdit = mock(WorldEdit.class); - LocalConfiguration configuration = mock(LocalConfiguration.class); - configuration.defaultLocale = Locale.GERMAN; - when(worldEdit.getConfiguration()).thenReturn(configuration); - try (MockedStatic singleton = mockStatic(WorldEdit.class); - MockedStatic text = mockStatic(WorldEditText.class)) { - singleton.when(WorldEdit::getInstance).thenReturn(worldEdit); - text.when(() -> WorldEditText.reduceToText(TextComponent.of("description"), Locale.GERMAN)) - .thenReturn("Translated description"); - text.when(() -> WorldEditText.reduceToText(TextComponent.of("full help"), Locale.GERMAN)) - .thenReturn("Translated full help"); - DynamicPluginCommandHelpTopic topic = new DynamicPluginCommandHelpTopic(command()); - assertEquals("Translated description", topic.getShortText()); - assertEquals("Translated full help", topic.getFullText(null)); - } - } - - @Test - void helpAlsoFallsBackWhenTranslationPlatformIsUnavailable() { - WorldEdit worldEdit = mock(WorldEdit.class); - LocalConfiguration configuration = mock(LocalConfiguration.class); - configuration.defaultLocale = Locale.ENGLISH; - when(worldEdit.getConfiguration()).thenReturn(configuration); - try (MockedStatic singleton = mockStatic(WorldEdit.class); - MockedStatic text = mockStatic(WorldEditText.class)) { - singleton.when(WorldEdit::getInstance).thenReturn(worldEdit); - text.when(() -> WorldEditText.reduceToText(TextComponent.of("description"), Locale.ENGLISH)) - .thenThrow(new NoCapablePlatformException()); - text.when(() -> WorldEditText.reduceToText(TextComponent.of("full help"), Locale.ENGLISH)) - .thenThrow(new NoCapablePlatformException()); - DynamicPluginCommandHelpTopic topic = new DynamicPluginCommandHelpTopic(command()); - assertEquals("Stored description", topic.getShortText()); - assertEquals("/test ", topic.getFullText(null)); - } - } - - @Test - void unrelatedFailuresAreNotSuppressed() { - WorldEdit worldEdit = mock(WorldEdit.class); - when(worldEdit.getConfiguration()).thenThrow(new IllegalStateException("unrelated")); - try (MockedStatic singleton = mockStatic(WorldEdit.class)) { - singleton.when(WorldEdit::getInstance).thenReturn(worldEdit); - assertThrows(IllegalStateException.class, () -> new DynamicPluginCommandHelpTopic(command())); - } - } - - private DynamicPluginCommand command() { - WorldEditPlugin plugin = mock(WorldEditPlugin.class); - CommandManager dispatcher = mock(CommandManager.class); - org.enginehub.piston.Command mapping = mock(org.enginehub.piston.Command.class); - when(mapping.getDescription()).thenReturn(TextComponent.of("description")); - when(mapping.getFullHelp()).thenReturn(TextComponent.of("full help")); - when(dispatcher.getCommand("test")).thenReturn(Optional.of(mapping)); - BukkitCommandInspector inspector = new BukkitCommandInspector(plugin, dispatcher); - return new DynamicPluginCommand( - new String[]{"test"}, "Stored description", "/test ", plugin, inspector, plugin - ); - } -}