From 3474ce6d48d4c74b88430a60f6b539797ee5b07d Mon Sep 17 00:00:00 2001 From: Zoriot Date: Tue, 13 Oct 2026 11:47:11 +0200 Subject: [PATCH 1/2] feat(map): add WorldEdit claim creation command Add a dedicated map module and /map create command that converts cuboid WorldEdit selections to geographic claim boundaries and submits them through the web API client. Configure a dedicated Bearer token and map-create permission, and add command registration coverage. Register like other commands and configure map labels Drop the one-off registerParent helper in favor of the shared register + subcommand pattern, and read map standalone labels from MainConfig like the other feature commands. Harden claim creation against API and init-order bugs Use polygonal selections with lng/lat strings, pass owner by Minecraft name, optional claim name, clickable map link, configurable API base path, and lazy config access so registration during Module.super() does not NPE. Register parent aliases without a standalone handler Add registerParent so /map create works without a misleading no-op /map command, move web-api-client into the version catalog, and cover the parent-only registration path in tests. Use module config and updated claim API Move the map API credential and independent build team ID into modules/map/config.yml. Update claim creation for the republished client, which accepts a string team ID and derives the claim name when omitted. --- build.gradle.kts | 1 + gradle/libs.versions.toml | 5 +- .../buildteamtools/BuildTeamTools.java | 8 + .../common/commands/BttCommandManager.java | 4 +- .../buildteamtools/modules/map/MapModule.java | 27 ++ .../map/commands/MapCreateCommand.java | 241 ++++++++++++++++++ .../modules/network/model/Permissions.java | 2 + .../buildteamtools/utils/io/MainConfig.java | 1 + .../buildteamtools/utils/io/MapConfig.java | 26 ++ src/main/resources/plugin.yml | 5 + .../commands/BttCommandManagerTest.java | 20 +- 11 files changed, 337 insertions(+), 3 deletions(-) create mode 100644 src/main/java/net/buildtheearth/buildteamtools/modules/map/MapModule.java create mode 100644 src/main/java/net/buildtheearth/buildteamtools/modules/map/commands/MapCreateCommand.java create mode 100644 src/main/java/net/buildtheearth/buildteamtools/utils/io/MapConfig.java diff --git a/build.gradle.kts b/build.gradle.kts index 082b3e3a..1599013b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -43,6 +43,7 @@ dependencies { exclude(group = "com.github.cryptomorin", module = "XSeries") } implementation(libs.alpslib.geo) + implementation(libs.alpslib.web.api) implementation(libs.alpsbte.canvas) implementation(libs.xseries) implementation(libs.anvilgui) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f6309f4f..f9bf23df 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,9 +9,11 @@ alpslib-io = "1.2.5" # https://mvn.alps-bte.com/service/rest/repository/browse/alps-bte/com/alpsbte/alpslib/alpslib-libpsterra/ alpslib-libpsterra = "1.1.4" # https://mvn.alps-bte.com/service/rest/repository/browse/alps-bte/com/alpsbte/alpslib/alpslib-utils/ -alpslib-utils = "1.5.2" +alpslib-utils = "1.6.0" # https://mvn.alps-bte.com/service/rest/repository/browse/alps-bte/com/alpsbte/alpslib/alpslib-geo/ alpslib-geo = "1.0.0-SNAPSHOT" +# https://mvn.alps-bte.com/service/rest/repository/browse/alps-bte/com/alpsbte/alpslib/alpslib-web-api/ +alpslib-web-api = "1.0.0-SNAPSHOT" # https://github.com/WesJD/AnvilGUI https://mvn.wesjd.net/ anvilgui = "1.10.14-SNAPSHOT" # @pin Ref: https://github.com/BlueMap-Minecraft/BlueMapAPI - Newer Versions require Java 25 @@ -60,6 +62,7 @@ alpsbte-canvas = { module = "com.alpsbte:canvas", version.ref = "alpsbte-canvas" alpslib-io = { module = "com.alpsbte.alpslib:alpslib-io", version.ref = "alpslib-io" } alpslib-utils = { module = "com.alpsbte.alpslib:alpslib-utils", version.ref = "alpslib-utils" } alpslib-geo = { module = "com.alpsbte.alpslib:alpslib-geo", version.ref = "alpslib-geo" } +alpslib-web-api = { module = "com.alpsbte.alpslib:web-api-client", version.ref = "alpslib-web-api" } anvilgui = { module = "net.wesjd:anvilgui", version.ref = "anvilgui" } bluemap-api = { module = "de.bluecolored:bluemap-api", version.ref = "bluemap-api" } bstats-bukkit = { module = "org.bstats:bstats-bukkit", version.ref = "bstats" } diff --git a/src/main/java/net/buildtheearth/buildteamtools/BuildTeamTools.java b/src/main/java/net/buildtheearth/buildteamtools/BuildTeamTools.java index 153f7435..848131e6 100644 --- a/src/main/java/net/buildtheearth/buildteamtools/BuildTeamTools.java +++ b/src/main/java/net/buildtheearth/buildteamtools/BuildTeamTools.java @@ -6,6 +6,7 @@ import net.buildtheearth.buildteamtools.modules.common.CommonModule; import net.buildtheearth.buildteamtools.modules.common.commands.BttCommandManager; import net.buildtheearth.buildteamtools.modules.generator.GeneratorModule; +import net.buildtheearth.buildteamtools.modules.map.MapModule; import net.buildtheearth.buildteamtools.modules.miscellaneous.MiscModule; import net.buildtheearth.buildteamtools.modules.navigation.NavigationModule; import net.buildtheearth.buildteamtools.modules.network.NetworkModule; @@ -13,6 +14,7 @@ import net.buildtheearth.buildteamtools.modules.stats.StatsModule; import net.buildtheearth.buildteamtools.utils.io.ConfigurationLoader; import net.buildtheearth.buildteamtools.utils.io.GeneratorConfig; +import net.buildtheearth.buildteamtools.utils.io.MapConfig; import net.buildtheearth.buildteamtools.utils.io.MainConfig; import net.buildtheearth.buildteamtools.utils.io.NavigationConfig; import net.buildtheearth.buildteamtools.utils.io.PlotSystemConfig; @@ -38,6 +40,7 @@ public class BuildTeamTools extends JavaPlugin { private ConfigurationLoader mainConfigLoader; private ConfigurationLoader navigationConfigLoader; private ConfigurationLoader generatorConfigLoader; + private ConfigurationLoader mapConfigLoader; private ConfigurationLoader plotSystemConfigLoader; @Getter private BttCommandManager commandManager; @@ -50,11 +53,14 @@ public void onEnable() { getDataFolder().toPath().resolve("modules/navigation"), getSLF4JLogger()); generatorConfigLoader = new ConfigurationLoader<>(GeneratorConfig.class, getDataFolder().toPath().resolve("modules/generator"), getSLF4JLogger()); + mapConfigLoader = new ConfigurationLoader<>(MapConfig.class, + getDataFolder().toPath().resolve("modules/map"), getSLF4JLogger()); plotSystemConfigLoader = new ConfigurationLoader<>(PlotSystemConfig.class, getDataFolder().toPath().resolve("modules/plotsystem"), getSLF4JLogger()); MainConfig mainConfig = mainConfigLoader.load(); NavigationConfig navigationConfig = navigationConfigLoader.load(); GeneratorConfig generatorConfig = generatorConfigLoader.load(); + MapConfig mapConfig = mapConfigLoader.load(); plotSystemConfigLoader.load(); commandManager = new BttCommandManager(this); @@ -63,6 +69,7 @@ public void onEnable() { new CommonModule(mainConfig), new NetworkModule(mainConfig), new GeneratorModule(generatorConfig), + new MapModule(mapConfig), new NavigationModule(navigationConfig), MiscModule.getInstance(), StatsModule.getInstance(), @@ -83,6 +90,7 @@ public void reloadConfig() { mainConfigLoader.reload(); navigationConfigLoader.reload(); generatorConfigLoader.reload(); + mapConfigLoader.reload(); plotSystemConfigLoader.reload(); } diff --git a/src/main/java/net/buildtheearth/buildteamtools/modules/common/commands/BttCommandManager.java b/src/main/java/net/buildtheearth/buildteamtools/modules/common/commands/BttCommandManager.java index ac91d2a3..72c11283 100644 --- a/src/main/java/net/buildtheearth/buildteamtools/modules/common/commands/BttCommandManager.java +++ b/src/main/java/net/buildtheearth/buildteamtools/modules/common/commands/BttCommandManager.java @@ -38,7 +38,7 @@ public final class BttCommandManager { private static final Set COMMAND_NAMES = Set.of( "btt", "generate", "kml", "geopoints", "geopath", "georing", "geosurface", - "navigator", "buildteam", "btwarps", "address", "warp", "blockpalette", + "navigator", "buildteam", "btwarps", "address", "warp", "map", "blockpalette", "help", "communicators", "cache", "debug", "checkforupdates", "reload-config", "update" ); private static final ParserDescriptor ARGUMENT_PARSER = @@ -425,6 +425,7 @@ private List configuredAliases(String name) { case "btwarps" -> labels.btwarps(); case "address" -> labels.address(); case "warp" -> labels.warp(); + case "map" -> labels.map(); case "blockpalette" -> labels.blockpalette(); default -> List.of(); }; @@ -476,6 +477,7 @@ private static RichDescription descriptionFor(String name) { case "btwarps" -> "Open the warp menu for a build team."; case "address" -> "Look up the address at your current location."; case "warp" -> "Warp to a saved location."; + case "map" -> "Create map claims from polygonal WorldEdit selections."; case "blockpalette" -> "Open the block palette menu."; default -> "BuildTeamTools command."; }; diff --git a/src/main/java/net/buildtheearth/buildteamtools/modules/map/MapModule.java b/src/main/java/net/buildtheearth/buildteamtools/modules/map/MapModule.java new file mode 100644 index 00000000..511e6b28 --- /dev/null +++ b/src/main/java/net/buildtheearth/buildteamtools/modules/map/MapModule.java @@ -0,0 +1,27 @@ +package net.buildtheearth.buildteamtools.modules.map; + +import lombok.Getter; +import net.buildtheearth.buildteamtools.modules.Module; +import net.buildtheearth.buildteamtools.modules.map.commands.MapCreateCommand; +import net.buildtheearth.buildteamtools.utils.WikiLinks; +import net.buildtheearth.buildteamtools.utils.io.MapConfig; + +public class MapModule extends Module { + + @Getter + private final MapConfig config; + + public MapModule(MapConfig config) { + super("Map", WikiLinks.ENTRY); + this.config = config; + } + + @Override + public void registerCommands() { + new MapCreateCommand(this).register(this); + } + + @Override + public void registerListeners() { + } +} diff --git a/src/main/java/net/buildtheearth/buildteamtools/modules/map/commands/MapCreateCommand.java b/src/main/java/net/buildtheearth/buildteamtools/modules/map/commands/MapCreateCommand.java new file mode 100644 index 00000000..4896aaff --- /dev/null +++ b/src/main/java/net/buildtheearth/buildteamtools/modules/map/commands/MapCreateCommand.java @@ -0,0 +1,241 @@ +package net.buildtheearth.buildteamtools.modules.map.commands; + +import com.alpsbte.alpslib.utils.ChatHelper; +import com.alpsbte.alpslib.web.api.ClaimApi; +import com.alpsbte.alpslib.web.invoker.ApiClient; +import com.alpsbte.alpslib.web.invoker.ApiException; +import com.alpsbte.alpslib.web.model.Claim; +import com.alpsbte.alpslib.web.model.PublicBuildteamsTeamClaimsPostRequest; +import com.alpsbte.alpslib.web.model.PublicBuildteamsTeamClaimsPostRequestAreaInner; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.regions.Polygonal2DRegion; +import com.sk89q.worldedit.regions.Region; +import net.buildtheearth.OutOfProjectionBoundsException; +import net.buildtheearth.Projection; +import net.buildtheearth.buildteamtools.BuildTeamTools; +import net.buildtheearth.buildteamtools.modules.Module; +import net.buildtheearth.buildteamtools.modules.common.commands.BttCommandManager; +import net.buildtheearth.buildteamtools.modules.map.MapModule; +import net.buildtheearth.buildteamtools.modules.network.model.Permissions; +import net.buildtheearth.buildteamtools.utils.io.MapConfig; +import net.buildtheearth.model.GeographicalCoordinate; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.incendo.cloud.minecraft.extras.RichDescription; +import org.incendo.cloud.parser.standard.StringParser; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class MapCreateCommand { + + private static final String COMMAND_NAME = "map"; + private static final int MIN_POLYGON_VERTICES = 3; + /** Claim creation may wait on Overpass (retries); OkHttp's default 10s read timeout is too short. */ + private static final int API_READ_TIMEOUT_MS = 120_000; + private static final String CLAIM_MAP_URL = "https://buildtheearth.net/map?claim="; + + private final MapModule module; + + public MapCreateCommand(MapModule module) { + this.module = module; + } + + private MapConfig config() { + // Config is assigned after Module.super() finishes; registerCommands() runs during super(). + return module.getConfig(); + } + + public void register(Module owner) { + var commandManager = BuildTeamTools.getInstance().getCommandManager(); + commandManager.register(owner, COMMAND_NAME, Permissions.MAP_CREATE, + (sender, args) -> sender.sendMessage(ChatHelper.getErrorComponent("Usage: /map create [name]")), + (sender, input) -> BttCommandManager.matchingSuggestions(List.of("create"), input)); + commandManager.registerSubcommand( + owner, + COMMAND_NAME, + "create", + "Create a map claim from your polygonal WorldEdit selection.", + builder -> builder + .permission(Permissions.MAP_CREATE) + .optional("name", StringParser.greedyStringParser(), + RichDescription.of(Component.text("Optional claim name"))), + context -> { + CommandSender sender = context.sender().getSender(); + if (!(sender instanceof Player player)) { + sender.sendMessage(ChatHelper.getErrorComponent("This command can only be used by a player!")); + return; + } + create(player, context.optional("name").orElse("").trim()); + } + ); + } + + private void create(Player player, String claimName) { + if (!hasApiConfig(player) || !hasWorldEdit(player)) return; + + Polygonal2DRegion selection = requirePolygonalSelection(player); + if (selection == null) return; + + List area = buildArea(player, selection); + if (area == null) return; + + PublicBuildteamsTeamClaimsPostRequest request = new PublicBuildteamsTeamClaimsPostRequest() + .owner(Map.of("minecraft", player.getName())) + .area(area) + .active(true) + .finished(false); + if (!claimName.isEmpty()) { + request.name(claimName); + } + + player.sendMessage(ChatHelper.getStandardComponent(false, "Creating map claim from your selection...")); + Bukkit.getScheduler().runTaskAsynchronously(BuildTeamTools.getInstance(), + () -> submitClaim(player, request)); + } + + private boolean hasApiConfig(Player player) { + MapConfig config = config(); + if (config.webApiToken() == null || config.webApiToken().isBlank()) { + player.sendMessage(ChatHelper.getErrorComponent( + "Map claim creation is unavailable. Configure webApiToken in modules/map/config.yml.")); + return false; + } + if (config.buildTeamId() == null || config.buildTeamId().isBlank()) { + player.sendMessage(ChatHelper.getErrorComponent( + "Map claim creation is unavailable. Configure buildTeamId in modules/map/config.yml.")); + return false; + } + if (config.webApiBasePath() == null || config.webApiBasePath().isBlank()) { + player.sendMessage(ChatHelper.getErrorComponent( + "Map claim creation is unavailable. Configure webApiBasePath in modules/map/config.yml.")); + return false; + } + return true; + } + + private boolean hasWorldEdit(Player player) { + if (Bukkit.getPluginManager().isPluginEnabled("WorldEdit") + || Bukkit.getPluginManager().isPluginEnabled("FastAsyncWorldEdit")) { + return true; + } + player.sendMessage(ChatHelper.getErrorComponent("WorldEdit or FastAsyncWorldEdit must be enabled.")); + return false; + } + + private Polygonal2DRegion requirePolygonalSelection(Player player) { + World earthWorld = BuildTeamTools.getInstance().getEarthWorld(); + if (earthWorld == null) { + player.sendMessage(ChatHelper.getErrorComponent("The configured Earth world is not loaded.")); + return null; + } + if (!player.getWorld().equals(earthWorld)) { + player.sendMessage(ChatHelper.getErrorComponent("Select an area in the configured Earth world.")); + return null; + } + + Region selection; + try { + Actor actor = BukkitAdapter.adapt(player); + LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor); + selection = session.getSelection(BukkitAdapter.adapt(earthWorld)); + } catch (IncompleteRegionException exception) { + player.sendMessage(ChatHelper.getErrorComponent( + "Make a polygonal WorldEdit selection (//sel poly) before creating a map claim.")); + return null; + } + if (!(selection instanceof Polygonal2DRegion polygonalSelection)) { + player.sendMessage(ChatHelper.getErrorComponent( + "Map claims require a polygonal WorldEdit selection. Use //sel poly.")); + return null; + } + if (polygonalSelection.getPoints().size() < MIN_POLYGON_VERTICES) { + player.sendMessage(ChatHelper.getErrorComponent( + "A map claim needs at least %s distinct polygon points.", MIN_POLYGON_VERTICES)); + return null; + } + return polygonalSelection; + } + + private List buildArea( + Player player, Polygonal2DRegion selection) { + try { + return createArea(selection); + } catch (OutOfProjectionBoundsException exception) { + player.sendMessage(ChatHelper.getErrorComponent( + "The selection is outside the supported map projection: %s", exception.getMessage())); + return null; + } + } + + private void submitClaim(Player player, PublicBuildteamsTeamClaimsPostRequest request) { + try { + MapConfig config = config(); + ApiClient apiClient = new ApiClient(); + apiClient.setBearerToken(config.webApiToken()); + apiClient.setBasePath(config.webApiBasePath()); + apiClient.setReadTimeout(API_READ_TIMEOUT_MS); + // null, not false: Express treats ?slug=false as truthy and looks up the UUID as a slug. + Claim claim = new ClaimApi(apiClient) + .publicBuildteamsTeamClaimsPost(config.buildTeamId(), request, null, null); + if (claim == null || claim.getId() == null) { + throw new IllegalStateException("The map API did not return the created claim ID."); + } + sendSuccess(player, claim); + } catch (ApiException | RuntimeException exception) { + BuildTeamTools.getInstance().getComponentLogger().error( + "Failed to create map claim for player {}.", player.getUniqueId(), exception); + sendFailure(player, exception); + } + } + + private void sendSuccess(Player player, Claim claim) { + String claimName = claim.getName() == null || claim.getName().isBlank() + ? "Unnamed Claim" + : claim.getName(); + String claimUrl = CLAIM_MAP_URL + claim.getId(); + Component idLink = Component.text(Objects.requireNonNull(claim.getId()).toString(), NamedTextColor.AQUA) + .clickEvent(ClickEvent.openUrl(claimUrl)) + .hoverEvent(HoverEvent.showText(Component.text("Open claim on the map", NamedTextColor.GRAY))); + player.sendMessage(ChatHelper.getSuccessComponent("Created map claim %s (ID: ", claimName) + .append(idLink) + .append(Component.text(")."))); + } + + private void sendFailure(Player player, Exception exception) { + if (exception instanceof ApiException apiException && apiException.getCode() == 404) { + player.sendMessage(ChatHelper.getErrorComponent( + "Your Minecraft account is not registered on buildtheearth.net. Link it on the website first.")); + return; + } + String reason = exception.getMessage() == null + ? exception.getClass().getSimpleName() + : exception.getMessage(); + player.sendMessage(ChatHelper.getErrorComponent("Failed to create map claim: %s", reason)); + } + + /** API default coordType expects {@code "lng, lat"} strings; the API closes the ring. */ + private List createArea(Polygonal2DRegion selection) + throws OutOfProjectionBoundsException { + List area = new ArrayList<>(); + for (BlockVector2 point : selection.getPoints()) { + GeographicalCoordinate coordinate = Projection.toGeo(point.x(), point.z()); + area.add(new PublicBuildteamsTeamClaimsPostRequestAreaInner( + coordinate.longitude() + ", " + coordinate.latitude())); + } + return area; + } +} diff --git a/src/main/java/net/buildtheearth/buildteamtools/modules/network/model/Permissions.java b/src/main/java/net/buildtheearth/buildteamtools/modules/network/model/Permissions.java index 5ec17f99..282370e3 100644 --- a/src/main/java/net/buildtheearth/buildteamtools/modules/network/model/Permissions.java +++ b/src/main/java/net/buildtheearth/buildteamtools/modules/network/model/Permissions.java @@ -43,6 +43,8 @@ public class Permissions { public static final String WARP_GROUP_EDIT = "btt.warp.group.edit"; public static final String WARP_GROUP_DELETE = "btt.warp.group.delete"; + public static final String MAP_CREATE = "btt.map.create"; + public static final String NOTIFY_UPDATE = "btt.notify.update"; public static final String AUTO_TPLL = "btt.global.autotpll"; diff --git a/src/main/java/net/buildtheearth/buildteamtools/utils/io/MainConfig.java b/src/main/java/net/buildtheearth/buildteamtools/utils/io/MainConfig.java index 88f798fc..d9b0617b 100644 --- a/src/main/java/net/buildtheearth/buildteamtools/utils/io/MainConfig.java +++ b/src/main/java/net/buildtheearth/buildteamtools/utils/io/MainConfig.java @@ -74,6 +74,7 @@ interface Labels { default List btwarps() { return List.of("btwarps", "btwarp", "wbt", "wpt", "buildteamwarps"); } default List address() { return List.of("address"); } default List warp() { return List.of("warp", "warps", "wp"); } + default List map() { return List.of("map"); } default List blockpalette() { return List.of("blockpalette", "bp", "blocks"); } } } diff --git a/src/main/java/net/buildtheearth/buildteamtools/utils/io/MapConfig.java b/src/main/java/net/buildtheearth/buildteamtools/utils/io/MapConfig.java new file mode 100644 index 00000000..acdf759d --- /dev/null +++ b/src/main/java/net/buildtheearth/buildteamtools/utils/io/MapConfig.java @@ -0,0 +1,26 @@ +package net.buildtheearth.buildteamtools.utils.io; + +import space.arim.dazzleconf.engine.Comments; + +@Comments("BuildTeamTools Map Module Configuration") +@Comments("[Github Repo] https://github.com/BuildTheEarth/BuildTeamTools") +@Comments("[Contacts - Discord] BTE Development Hub, @Zoriot") +public interface MapConfig { + + @Comments("Build Team ID used by the web API to create map claims.") + @Comments("This is independent of the Build Team ID configured for NWAPI.") + default String buildTeamId() { + return ""; + } + + @Comments("Authentication secret used by the web API client to create map claims.") + @Comments("Keep this private; claim creation is unavailable when this is empty.") + default String webApiToken() { + return ""; + } + + @Comments("Base URL of the BuildTheEarth web API (no trailing slash), e.g. https://api.buildtheearth.net/api/v1") + default String webApiBasePath() { + return "https://api.buildtheearth.net/api/v1"; + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 05429c39..422e3a3a 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -43,6 +43,7 @@ permissions: btt.warp.group.create: true btt.warp.group.edit: true btt.warp.group.delete: true + btt.map.create: true btt.notify.update: true btt.bp.edit: true btt.generator.rail.create: true @@ -75,4 +76,8 @@ permissions: description: Allows players to create and edit custom block palettes default: op + btt.map.create: + description: Allows players to create map claims from WorldEdit selections + default: op + github-repo: "BuildTheEarth/BuildTeamTools" diff --git a/src/test/java/net/buildtheearth/buildteamtools/modules/common/commands/BttCommandManagerTest.java b/src/test/java/net/buildtheearth/buildteamtools/modules/common/commands/BttCommandManagerTest.java index 9daedffa..e7055f3e 100644 --- a/src/test/java/net/buildtheearth/buildteamtools/modules/common/commands/BttCommandManagerTest.java +++ b/src/test/java/net/buildtheearth/buildteamtools/modules/common/commands/BttCommandManagerTest.java @@ -128,7 +128,7 @@ void commandsAreRegisteredWhenDisabledModuleIsEnabledLater() { @Test void allDefaultFeatureAliasesRegisterWithoutAmbiguity() { for (String name : List.of("generate", "kml", "geopoints", "geopath", "georing", "geosurface", - "warp", "address", "blockpalette")) { + "warp", "address", "map", "blockpalette")) { commands.register(null, name, (sender, args) -> {}); } commands.registerNoArguments(null, "navigator", Permissions.NAVIGATOR_USE, ignored -> {}); @@ -139,6 +139,9 @@ void allDefaultFeatureAliasesRegisterWithoutAmbiguity() { } assertSame(parse("navigator").command(), parse("nav").command()); + assertNotNull(parse("map").command()); + assertNotNull(parse("btt map").command()); + assertNotNull(parse("buildteamtools map").command()); assertSame(parse("btt navigator").command(), parse("buildteamtools navigate").command()); assertSame(parse("buildteam New York").command(), parse("bt New York").command()); assertEquals("New York", parse("buildteamtools bt New York").get("team")); @@ -150,12 +153,18 @@ void allDefaultFeatureAliasesRegisterWithoutAmbiguity() { @Test void subcommandsRetainArgumentsPermissionsAndHandlersForEveryAlias() throws Exception { AtomicInteger invocations = new AtomicInteger(); + AtomicInteger mapInvocations = new AtomicInteger(); Module owner = new EnabledModule(); commands.register(null, "warp", (sender, args) -> {}); + commands.register(null, "map", (sender, args) -> {}); commands.registerSubcommand(owner, "warp", "migrate", "Migrate warps", builder -> builder.permission(Permissions.WARP_MIGRATE) .required("source", EnumParser.enumParser(WarpMigrationSource.class)), ignored -> invocations.incrementAndGet()); + commands.registerSubcommand(owner, "map", "create", "Create a map claim", + builder -> builder.permission(Permissions.MAP_CREATE) + .optional("name", StringParser.greedyStringParser()), + context -> mapInvocations.incrementAndGet()); for (String input : List.of("warp migrate essentials", "wp migrate essentials", "btt warp migrate essentials", "buildteamtools wp migrate essentials")) { @@ -167,6 +176,15 @@ void subcommandsRetainArgumentsPermissionsAndHandlersForEveryAlias() throws Exce assertEquals(4, invocations.get()); assertParseFailure(InvalidSyntaxException.class, "wp migrate"); assertParseFailure(ArgumentParseException.class, "btt warp migrate invalid"); + for (String input : List.of("map create", "btt map create", "buildteamtools map create")) { + var context = parse(input); + assertEquals(Permissions.MAP_CREATE, context.command().commandPermission().permissionString()); + context.command().commandExecutionHandler().execute(context); + } + assertEquals(3, mapInvocations.get()); + assertEquals("Old Town", parse("map create Old Town").get("name")); + assertNotNull(parse("map").command()); + assertNotNull(parse("btt map").command()); manager.deniedPermissions = Set.of(Permissions.WARP_MIGRATE); assertParseFailure(NoPermissionException.class, "wp migrate essentials"); assertParseFailure(NoPermissionException.class, "buildteamtools wp migrate essentials"); From b8432ab1c94ce5b9b9ccf30ba13de09cf69aae05 Mon Sep 17 00:00:00 2001 From: Zoriot Date: Tue, 27 Oct 2026 20:01:27 +0100 Subject: [PATCH 2/2] build: Switch to release version of AlpsLib and Anvilgui --- build.gradle.kts | 9 +-------- gradle/libs.versions.toml | 6 +++--- .../modules/map/commands/MapCreateCommand.java | 4 ++-- .../modules/network/api/OpenStreetMapAPI.java | 2 +- 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 1599013b..29482069 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,17 +10,10 @@ plugins { repositories { mavenCentral() - // Anvilgui + Alps Lib Geo (for geo it can be removed once https://github.com/AlpsBTE/Alps-Lib/pull/17 is merged & version is set to 1.0.0) - maven("https://mvn.alps-bte.com/repository/alps-bte-snapshots/") { - content { - includeGroup("com.alpsbte.alpslib") - includeGroup("net.wesjd") - } - } maven("https://maven.buildtheearth.net/releases") // BuildTheEarth Projection maven("https://mvn.alps-bte.com/repository/alps-bte/") // AlpsLib maven("https://maven.enginehub.org/repo/") // WorldEdit - //maven("https://mvn.wesjd.net/") // Anvilgui - includes 26.1 module which is build with Java 25, what breaks the Plugin Remapper on Paper 1.21.4 see https://github.com/WesJD/AnvilGUI/issues/408 + maven("https://mvn.wesjd.net/") // https://github.com/WesJD/AnvilGUI/issues/408 maven("https://repo.bluecolored.de/releases") // BlueMap maven("https://repo.essentialsx.net/releases/") maven("https://repo.lushplugins.org/releases") // PluginUpdater diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f9bf23df..a12f8000 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,11 +11,11 @@ alpslib-libpsterra = "1.1.4" # https://mvn.alps-bte.com/service/rest/repository/browse/alps-bte/com/alpsbte/alpslib/alpslib-utils/ alpslib-utils = "1.6.0" # https://mvn.alps-bte.com/service/rest/repository/browse/alps-bte/com/alpsbte/alpslib/alpslib-geo/ -alpslib-geo = "1.0.0-SNAPSHOT" +alpslib-geo = "1.0.0" # https://mvn.alps-bte.com/service/rest/repository/browse/alps-bte/com/alpsbte/alpslib/alpslib-web-api/ -alpslib-web-api = "1.0.0-SNAPSHOT" +alpslib-web-api = "1.0.0" # https://github.com/WesJD/AnvilGUI https://mvn.wesjd.net/ -anvilgui = "1.10.14-SNAPSHOT" +anvilgui = "1.10.13-SNAPSHOT" # @pin Ref: https://github.com/BlueMap-Minecraft/BlueMapAPI - Newer Versions require Java 25 bluemap-api = "2.7.8" # https://central.sonatype.com/artifact/org.bstats/bstats-bukkit diff --git a/src/main/java/net/buildtheearth/buildteamtools/modules/map/commands/MapCreateCommand.java b/src/main/java/net/buildtheearth/buildteamtools/modules/map/commands/MapCreateCommand.java index 4896aaff..388cc364 100644 --- a/src/main/java/net/buildtheearth/buildteamtools/modules/map/commands/MapCreateCommand.java +++ b/src/main/java/net/buildtheearth/buildteamtools/modules/map/commands/MapCreateCommand.java @@ -7,6 +7,7 @@ import com.alpsbte.alpslib.web.model.Claim; import com.alpsbte.alpslib.web.model.PublicBuildteamsTeamClaimsPostRequest; import com.alpsbte.alpslib.web.model.PublicBuildteamsTeamClaimsPostRequestAreaInner; +import com.alpsbte.alpslib.web.model.PublicBuildteamsTeamClaimsPostRequestOwner; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -37,7 +38,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.Objects; public class MapCreateCommand { @@ -94,7 +94,7 @@ private void create(Player player, String claimName) { if (area == null) return; PublicBuildteamsTeamClaimsPostRequest request = new PublicBuildteamsTeamClaimsPostRequest() - .owner(Map.of("minecraft", player.getName())) + .owner(new PublicBuildteamsTeamClaimsPostRequestOwner().minecraft(player.getName())) .area(area) .active(true) .finished(false); diff --git a/src/main/java/net/buildtheearth/buildteamtools/modules/network/api/OpenStreetMapAPI.java b/src/main/java/net/buildtheearth/buildteamtools/modules/network/api/OpenStreetMapAPI.java index 1a2fe96e..93c1cc8e 100644 --- a/src/main/java/net/buildtheearth/buildteamtools/modules/network/api/OpenStreetMapAPI.java +++ b/src/main/java/net/buildtheearth/buildteamtools/modules/network/api/OpenStreetMapAPI.java @@ -56,7 +56,7 @@ private static void completeRgcLookup(@NotNull GeographicalCoordinate coordinate var location = NavigationModule.getInstance().getRgcHandler() .locationFromCoordinates((float) coordinates.latitude(), (float) coordinates.longitude()); ChatHelper.logDebug("RGC lookup successful: %s", location); - future.complete(new RegionLookupResult(location.get(AdminLevel.COUNTRY), null)); + future.complete(new RegionLookupResult(location.get().get(AdminLevel.COUNTRY), null)); } catch (Exception ex) { future.completeExceptionally(ex); }