diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 3437112b3..6888903e3 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -16,7 +16,7 @@ jobs:
- uses: actions/setup-java@v2
with:
distribution: temurin
- java-version: 17
+ java-version: 21
- uses: actions/setup-node@v3
with:
node-version: 16
diff --git a/.github/workflows/build_pr.yml b/.github/workflows/build_pr.yml
index e8af231e7..2f2b7be1f 100644
--- a/.github/workflows/build_pr.yml
+++ b/.github/workflows/build_pr.yml
@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- java: [17]
+ java: [21]
fail-fast: true
steps:
- uses: actions/checkout@v4
diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml
index 8794b0ec8..c2600239a 100644
--- a/.github/workflows/pullrequest.yml
+++ b/.github/workflows/pullrequest.yml
@@ -10,7 +10,7 @@ jobs:
- uses: actions/setup-java@v2
with:
distribution: temurin
- java-version: 17
+ java-version: 21
- uses: actions/setup-node@v3
with:
node-version: 16
diff --git a/README.md b/README.md
index 2bfc743e4..ae471f209 100644
--- a/README.md
+++ b/README.md
@@ -85,7 +85,7 @@ Maven
maven.modrinthpl3xmap
- 1.20.4-476
+ 1.20.6-493provided
```
@@ -101,7 +101,7 @@ repositories {
}
dependencies {
- compileOnly 'maven.modrinth:pl3xmap:1.20.4-476'
+ compileOnly 'maven.modrinth:pl3xmap:1.20.6-493'
}
```
diff --git a/build.gradle b/build.gradle
index d3e4bd5c8..e95efab14 100644
--- a/build.gradle
+++ b/build.gradle
@@ -44,7 +44,7 @@ def combineJars = tasks.register('combineJars', Jar) {
def copyWebmap = tasks.register('copyWebmap', Copy) {
dependsOn ':webmap:buildWebmap'
- duplicatesStrategy = DuplicatesStrategy.INHERIT
+ duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from "$rootDir/webmap/public", "$rootDir/webmap/dist"
include '**/*'
exclude 'tiles*/'
@@ -70,21 +70,39 @@ allprojects {
java {
toolchain {
- languageVersion = JavaLanguageVersion.of(17)
+ languageVersion = JavaLanguageVersion.of(21)
}
}
repositories {
mavenCentral()
- mavenLocal()
- maven { url = 'https://jitpack.io' }
+ maven {
+ url = 'https://repo.granny.dev/snapshots/'
+ }
+ maven {
+ name = 'sonatype-snapshots'
+ url = 'https://oss.sonatype.org/content/repositories/snapshots/'
+ mavenContent {
+ snapshotsOnly()
+ }
+ }
+ maven {
+ url = 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
+ mavenContent {
+ snapshotsOnly()
+ }
+ }
+ maven {
+ url = 'https://jitpack.io'
+ }
}
dependencies {
- implementation "cloud.commandframework:cloud-core:$cloudVersion"
- implementation "cloud.commandframework:cloud-brigadier:$cloudVersion"
- implementation "cloud.commandframework:cloud-paper:$cloudVersion"
- implementation("cloud.commandframework:cloud-minecraft-extras:$cloudVersion") {
+ implementation "org.incendo:cloud-core:$cloudVersion"
+ implementation "org.incendo:cloud-brigadier:$cloudVersion"
+ implementation "org.incendo:cloud-paper:$cloudVersion"
+ implementation "org.incendo:cloud-processors-confirmation:1.0.0-SNAPSHOT"
+ implementation("org.incendo:cloud-minecraft-extras:$cloudVersion") {
exclude group: 'net.kyori', module: '*'
}
@@ -120,7 +138,7 @@ allprojects {
compileJava {
options.encoding = 'UTF-8'
- options.release.set(17)
+ options.release.set(21)
}
processResources {
diff --git a/bukkit/src/main/java/net/pl3x/map/bukkit/BukkitNetwork.java b/bukkit/src/main/java/net/pl3x/map/bukkit/BukkitNetwork.java
index 6a04f2da3..2867f6631 100644
--- a/bukkit/src/main/java/net/pl3x/map/bukkit/BukkitNetwork.java
+++ b/bukkit/src/main/java/net/pl3x/map/bukkit/BukkitNetwork.java
@@ -23,16 +23,22 @@
*/
package net.pl3x.map.bukkit;
-import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
+import io.netty.buffer.Unpooled;
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
+import net.pl3x.map.bukkit.network.ClientboundMapPayload;
+import net.pl3x.map.bukkit.network.ClientboundServerPayload;
+import net.pl3x.map.bukkit.network.ServerboundMapPayload;
+import net.pl3x.map.bukkit.network.ServerboundServerPayload;
+import net.pl3x.map.core.configuration.Config;
import net.pl3x.map.core.network.Constants;
import net.pl3x.map.core.network.Network;
import org.bukkit.Bukkit;
import org.bukkit.World;
-import org.bukkit.craftbukkit.v1_20_R3.map.CraftMapRenderer;
import org.bukkit.entity.Player;
-import org.bukkit.map.MapRenderer;
import org.bukkit.map.MapView;
+import org.jetbrains.annotations.NotNull;
public class BukkitNetwork extends Network {
private final Pl3xMapBukkit plugin;
@@ -42,69 +48,77 @@ public BukkitNetwork(Pl3xMapBukkit plugin) {
}
public void register() {
- Bukkit.getMessenger().registerOutgoingPluginChannel(this.plugin, Network.CHANNEL);
- Bukkit.getMessenger().registerIncomingPluginChannel(this.plugin, Network.CHANNEL,
+ Bukkit.getMessenger().registerOutgoingPluginChannel(this.plugin, ClientboundServerPayload.TYPE.id().toString());
+ Bukkit.getMessenger().registerOutgoingPluginChannel(this.plugin, ClientboundMapPayload.TYPE.id().toString());
+ Bukkit.getMessenger().registerIncomingPluginChannel(this.plugin, ServerboundServerPayload.TYPE.id().toString(),
(channel, player, bytes) -> {
- ByteArrayDataInput in = in(bytes);
- int protocol = in.readInt();
- if (protocol != Constants.PROTOCOL) {
+ ClientboundServerPayload payload = new ClientboundServerPayload(Constants.PROTOCOL, Constants.RESPONSE_SUCCESS, Config.WEB_ADDRESS);
+ FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer());
+ ClientboundServerPayload.STREAM_CODEC.encode(friendlyByteBuf, payload);
+ sendCustomPayloadPacket(player, payload, friendlyByteBuf);
+ }
+ );
+ Bukkit.getMessenger().registerIncomingPluginChannel(this.plugin, ServerboundMapPayload.TYPE.id().toString(),
+ (channel, player, bytes) -> {
+ FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.copiedBuffer(bytes));
+ ServerboundMapPayload payload = ServerboundMapPayload.STREAM_CODEC.decode(byteBuf);
+
+ MapView map = Bukkit.getMap(payload.mapId());
+ if (map == null) {
+ ClientboundMapPayload customPacketPayload = new ClientboundMapPayload(Constants.PROTOCOL, Constants.ERROR_NO_SUCH_MAP, payload.mapId());
+ FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer(bytes.length));
+ ClientboundMapPayload.STREAM_CODEC.encode(friendlyByteBuf, customPacketPayload);
+ sendCustomPayloadPacket(player, customPacketPayload, friendlyByteBuf);
return;
}
- int action = in.readInt();
- switch (action) {
- case Constants.SERVER_DATA -> sendServerData(player);
- case Constants.MAP_DATA -> sendMapData(player, in.readInt());
+
+ World world = map.getWorld();
+ if (world == null) {
+ ClientboundMapPayload customPacketPayload = new ClientboundMapPayload(Constants.PROTOCOL, Constants.ERROR_NO_SUCH_WORLD, payload.mapId());
+ FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer());
+ ClientboundMapPayload.STREAM_CODEC.encode(friendlyByteBuf, customPacketPayload);
+ sendCustomPayloadPacket(player, customPacketPayload, friendlyByteBuf);
+ return;
}
+
+ ClientboundMapPayload customPacketPayload = new ClientboundMapPayload(
+ Constants.PROTOCOL, Constants.RESPONSE_SUCCESS, payload.mapId(),
+ getScale(map), map.getCenterX(), map.getCenterZ(), world.getName()
+ );
+ FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer());
+ ClientboundMapPayload.STREAM_CODEC.encode(friendlyByteBuf, customPacketPayload);
+ sendCustomPayloadPacket(player, customPacketPayload, friendlyByteBuf);
}
);
}
+ @NotNull
+ private void sendCustomPayloadPacket(Player player, CustomPacketPayload customPacketPayload, FriendlyByteBuf friendlyByteBuf) {
+ byte[] byteArray = new byte[friendlyByteBuf.readableBytes()];
+ friendlyByteBuf.readBytes(byteArray);
+ player.sendPluginMessage(this.plugin, customPacketPayload.type().id().toString(), byteArray);
+ }
+
public void unregister() {
- Bukkit.getMessenger().unregisterOutgoingPluginChannel(this.plugin, Network.CHANNEL);
- Bukkit.getMessenger().unregisterIncomingPluginChannel(this.plugin, Network.CHANNEL);
+ Bukkit.getMessenger().unregisterOutgoingPluginChannel(this.plugin, ClientboundServerPayload.TYPE.id().toString());
+ Bukkit.getMessenger().unregisterOutgoingPluginChannel(this.plugin, ClientboundMapPayload.TYPE.id().toString());
+ Bukkit.getMessenger().unregisterIncomingPluginChannel(this.plugin, ServerboundServerPayload.TYPE.id().toString());
+ Bukkit.getMessenger().unregisterIncomingPluginChannel(this.plugin, ServerboundMapPayload.TYPE.id().toString());
+ }
+
+ @Override
+ protected void sendServerData(T player) {
+
}
+ @Override
protected void sendMapData(T player, int id) {
- ByteArrayDataOutput out = out();
-
- out.writeInt(Constants.PROTOCOL);
- out.writeInt(Constants.MAP_DATA);
- out.writeInt(Constants.RESPONSE_SUCCESS);
-
- MapView map = Bukkit.getMap(id);
- if (map == null) {
- out.writeInt(Constants.ERROR_NO_SUCH_MAP);
- out.writeInt(id);
- return;
- }
-
- World world = map.getWorld();
- if (world == null) {
- out.writeInt(Constants.ERROR_NO_SUCH_WORLD);
- out.writeInt(id);
- return;
- }
-
- for (MapRenderer renderer : map.getRenderers()) {
- if (!renderer.getClass().getName().equals(CraftMapRenderer.class.getName())) {
- out.writeInt(Constants.ERROR_NOT_VANILLA_MAP);
- out.writeInt(id);
- return;
- }
- }
-
- out.writeInt(id);
- out.writeByte(getScale(map));
- out.writeInt(map.getCenterX());
- out.writeInt(map.getCenterZ());
- out.writeUTF(world.getName());
-
- send(player, out);
+
}
@Override
protected void send(T player, ByteArrayDataOutput out) {
- ((Player) player).sendPluginMessage(this.plugin, Network.CHANNEL, out.toByteArray());
+
}
@SuppressWarnings("deprecation")
diff --git a/bukkit/src/main/java/net/pl3x/map/bukkit/BukkitPlayer.java b/bukkit/src/main/java/net/pl3x/map/bukkit/BukkitPlayer.java
index c1af9ed22..190251e28 100644
--- a/bukkit/src/main/java/net/pl3x/map/bukkit/BukkitPlayer.java
+++ b/bukkit/src/main/java/net/pl3x/map/bukkit/BukkitPlayer.java
@@ -42,8 +42,8 @@
import org.bukkit.NamespacedKey;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeInstance;
-import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
-import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
diff --git a/bukkit/src/main/java/net/pl3x/map/bukkit/BukkitWorld.java b/bukkit/src/main/java/net/pl3x/map/bukkit/BukkitWorld.java
index f09a27da4..49faae157 100644
--- a/bukkit/src/main/java/net/pl3x/map/bukkit/BukkitWorld.java
+++ b/bukkit/src/main/java/net/pl3x/map/bukkit/BukkitWorld.java
@@ -52,7 +52,7 @@ public BukkitWorld(@NotNull ServerLevel level, @NotNull String name) {
super(
name,
level.getSeed(),
- Point.of(level.getLevelData().getXSpawn(), level.getLevelData().getZSpawn()),
+ Point.of(level.getLevelData().getSpawnPos().getX(), level.getLevelData().getSpawnPos().getZ()),
Type.get(level.dimension().location().toString()),
level.convertable.getDimensionPath(level.dimension()).resolve("region")
);
diff --git a/bukkit/src/main/java/net/pl3x/map/bukkit/Pl3xMapBukkit.java b/bukkit/src/main/java/net/pl3x/map/bukkit/Pl3xMapBukkit.java
index cd91e7dc0..1837efa5d 100644
--- a/bukkit/src/main/java/net/pl3x/map/bukkit/Pl3xMapBukkit.java
+++ b/bukkit/src/main/java/net/pl3x/map/bukkit/Pl3xMapBukkit.java
@@ -32,7 +32,7 @@
import net.pl3x.map.core.player.PlayerListener;
import net.pl3x.map.core.player.PlayerRegistry;
import org.bukkit.World;
-import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
+import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@@ -81,7 +81,7 @@ public void onEnable() {
}
getServer().getScheduler().runTaskTimer(this, () ->
- this.pl3xmap.getScheduler().tick(), 20, 20);
+ this.pl3xmap.getScheduler().tick(), 20, 1);
}
@Override
diff --git a/bukkit/src/main/java/net/pl3x/map/bukkit/Pl3xMapImpl.java b/bukkit/src/main/java/net/pl3x/map/bukkit/Pl3xMapImpl.java
index 3fc957178..7fda1684b 100644
--- a/bukkit/src/main/java/net/pl3x/map/bukkit/Pl3xMapImpl.java
+++ b/bukkit/src/main/java/net/pl3x/map/bukkit/Pl3xMapImpl.java
@@ -52,7 +52,7 @@
import net.pl3x.map.core.registry.BlockRegistry;
import net.pl3x.map.core.world.World;
import org.bukkit.Bukkit;
-import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
+import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
diff --git a/bukkit/src/main/java/net/pl3x/map/bukkit/command/BukkitCommandManager.java b/bukkit/src/main/java/net/pl3x/map/bukkit/command/BukkitCommandManager.java
index 3432bc471..d69582688 100644
--- a/bukkit/src/main/java/net/pl3x/map/bukkit/command/BukkitCommandManager.java
+++ b/bukkit/src/main/java/net/pl3x/map/bukkit/command/BukkitCommandManager.java
@@ -23,14 +23,16 @@
*/
package net.pl3x.map.bukkit.command;
-import cloud.commandframework.Command;
-import cloud.commandframework.brigadier.CloudBrigadierManager;
-import cloud.commandframework.bukkit.CloudBukkitCapabilities;
-import cloud.commandframework.execution.CommandExecutionCoordinator;
-import cloud.commandframework.paper.PaperCommandManager;
import net.pl3x.map.core.command.CommandHandler;
import net.pl3x.map.core.command.Sender;
+import net.pl3x.map.core.command.parser.PlatformParsers;
import org.bukkit.plugin.Plugin;
+import org.incendo.cloud.Command;
+import org.incendo.cloud.SenderMapper;
+import org.incendo.cloud.brigadier.CloudBrigadierManager;
+import org.incendo.cloud.bukkit.CloudBukkitCapabilities;
+import org.incendo.cloud.execution.ExecutionCoordinator;
+import org.incendo.cloud.paper.PaperCommandManager;
import org.jetbrains.annotations.NotNull;
public class BukkitCommandManager implements CommandHandler {
@@ -38,7 +40,9 @@ public class BukkitCommandManager implements CommandHandler {
private final Command.Builder<@NotNull Sender> root;
public BukkitCommandManager(@NotNull Plugin plugin) throws Exception {
- this.manager = new PaperCommandManager<>(plugin, CommandExecutionCoordinator.simpleCoordinator(), BukkitSender::create, Sender::getSender);
+ this.manager = new PaperCommandManager(plugin,
+ ExecutionCoordinator.simpleCoordinator(),
+ SenderMapper.create(BukkitSender::create, Sender::getSender));
if (getManager().hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) {
getManager().registerBrigadier();
@@ -64,6 +68,11 @@ public BukkitCommandManager(@NotNull Plugin plugin) throws Exception {
return this.manager;
}
+ @Override
+ public @NotNull PlatformParsers getPlatformParsers() {
+ return new BukkitParsers();
+ }
+
@Override
public Command.@NotNull Builder<@NotNull Sender> getRoot() {
return this.root;
diff --git a/bukkit/src/main/java/net/pl3x/map/bukkit/command/BukkitParsers.java b/bukkit/src/main/java/net/pl3x/map/bukkit/command/BukkitParsers.java
new file mode 100644
index 000000000..772506fa3
--- /dev/null
+++ b/bukkit/src/main/java/net/pl3x/map/bukkit/command/BukkitParsers.java
@@ -0,0 +1,52 @@
+package net.pl3x.map.bukkit.command;
+
+import net.minecraft.world.phys.Vec3;
+import net.pl3x.map.bukkit.BukkitPlayer;
+import net.pl3x.map.core.Pl3xMap;
+import net.pl3x.map.core.command.Sender;
+import net.pl3x.map.core.command.parser.PlatformParsers;
+import net.pl3x.map.core.markers.Point;
+import net.pl3x.map.core.player.Player;
+import org.incendo.cloud.bukkit.data.SinglePlayerSelector;
+import org.incendo.cloud.bukkit.parser.location.Location2D;
+import org.incendo.cloud.bukkit.parser.location.Location2DParser;
+import org.incendo.cloud.bukkit.parser.selector.SinglePlayerSelectorParser;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.parser.ParserDescriptor;
+
+public class BukkitParsers implements PlatformParsers {
+ @Override
+ public ParserDescriptor columnPosParser() {
+ return Location2DParser.location2DParser();
+ }
+
+ @Override
+ public Point resolvePointFromColumnPos(String name, CommandContext context) {
+ Location2D location2D = context.getOrDefault(name, null);
+ if (location2D == null) {
+ return Point.ZERO;
+ }
+ return Point.of(location2D.blockX(), location2D.blockZ());
+ }
+
+ @Override
+ public ParserDescriptor playerSelectorParser() {
+ return SinglePlayerSelectorParser.singlePlayerSelectorParser();
+ }
+
+ @Override
+ public Player resolvePlayerFromPlayerSelector(String name, CommandContext context) {
+ Sender sender = context.sender();
+ SinglePlayerSelector playerSelector = context.getOrDefault(name, null);
+ if (playerSelector == null) {
+ if (sender instanceof Sender.Player> senderPlayer) {
+ Player player = Pl3xMap.api().getPlayerRegistry().get(senderPlayer.getUUID());
+ if (player != null) {
+ return player;
+ }
+ }
+ return null;
+ }
+ return new BukkitPlayer(playerSelector.single());
+ }
+}
diff --git a/bukkit/src/main/java/net/pl3x/map/bukkit/network/ClientboundMapPayload.java b/bukkit/src/main/java/net/pl3x/map/bukkit/network/ClientboundMapPayload.java
new file mode 100644
index 000000000..cd72c754c
--- /dev/null
+++ b/bukkit/src/main/java/net/pl3x/map/bukkit/network/ClientboundMapPayload.java
@@ -0,0 +1,35 @@
+package net.pl3x.map.bukkit.network;
+
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.codec.StreamCodec;
+import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
+import net.minecraft.resources.ResourceLocation;
+import net.pl3x.map.core.network.Constants;
+
+public record ClientboundMapPayload(int protocol, int response, int mapId, byte scale, int centerX, int centerZ, String worldName) implements CustomPacketPayload {
+ public static final StreamCodec STREAM_CODEC = CustomPacketPayload.codec(ClientboundMapPayload::write, ClientboundMapPayload::new);
+ public static final Type TYPE = new Type<>(new ResourceLocation(Constants.MODID, "client_map_data"));
+
+ public ClientboundMapPayload(int protocol, int response, int mapId) {
+ this(protocol, response, mapId, (byte) 0, 0, 0, null);
+ }
+
+ public ClientboundMapPayload(FriendlyByteBuf friendlyByteBuf) {
+ this(friendlyByteBuf.readInt(), friendlyByteBuf.readInt(), friendlyByteBuf.readInt(), friendlyByteBuf.readByte(), friendlyByteBuf.readInt(), friendlyByteBuf.readInt(), friendlyByteBuf.readUtf());
+ }
+
+ private void write(FriendlyByteBuf friendlyByteBuf) {
+ friendlyByteBuf.writeInt(protocol);
+ friendlyByteBuf.writeInt(response);
+ friendlyByteBuf.writeInt(mapId);
+ friendlyByteBuf.writeByte(scale);
+ friendlyByteBuf.writeInt(centerX);
+ friendlyByteBuf.writeInt(centerZ);
+ friendlyByteBuf.writeUtf(worldName);
+ }
+
+ @Override
+ public Type extends CustomPacketPayload> type() {
+ return TYPE;
+ }
+}
diff --git a/bukkit/src/main/java/net/pl3x/map/bukkit/network/ClientboundServerPayload.java b/bukkit/src/main/java/net/pl3x/map/bukkit/network/ClientboundServerPayload.java
new file mode 100644
index 000000000..bcc4df553
--- /dev/null
+++ b/bukkit/src/main/java/net/pl3x/map/bukkit/network/ClientboundServerPayload.java
@@ -0,0 +1,31 @@
+package net.pl3x.map.bukkit.network;
+
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.codec.StreamCodec;
+import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
+import net.minecraft.resources.ResourceLocation;
+import net.pl3x.map.core.network.Constants;
+
+public record ClientboundServerPayload(int protocol, int response, String webAddress) implements CustomPacketPayload {
+ public static final StreamCodec STREAM_CODEC = CustomPacketPayload.codec(ClientboundServerPayload::write, ClientboundServerPayload::new);
+ public static final Type TYPE = new Type<>(new ResourceLocation(Constants.MODID, "client_server_data"));
+
+ public ClientboundServerPayload(int protocol, int response) {
+ this(protocol, response, null);
+ }
+
+ public ClientboundServerPayload(FriendlyByteBuf friendlyByteBuf) {
+ this(friendlyByteBuf.readInt(), friendlyByteBuf.readInt(), friendlyByteBuf.readUtf());
+ }
+
+ private void write(FriendlyByteBuf friendlyByteBuf) {
+ friendlyByteBuf.writeInt(protocol);
+ friendlyByteBuf.writeInt(response);
+ friendlyByteBuf.writeUtf(webAddress);
+ }
+
+ @Override
+ public Type extends CustomPacketPayload> type() {
+ return TYPE;
+ }
+}
diff --git a/bukkit/src/main/java/net/pl3x/map/bukkit/network/ServerboundMapPayload.java b/bukkit/src/main/java/net/pl3x/map/bukkit/network/ServerboundMapPayload.java
new file mode 100644
index 000000000..1b5d87511
--- /dev/null
+++ b/bukkit/src/main/java/net/pl3x/map/bukkit/network/ServerboundMapPayload.java
@@ -0,0 +1,30 @@
+package net.pl3x.map.bukkit.network;
+
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.codec.StreamCodec;
+import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
+import net.minecraft.resources.ResourceLocation;
+import net.pl3x.map.core.network.Constants;
+
+public record ServerboundMapPayload(int protocol, int mapId) implements CustomPacketPayload {
+ public static final StreamCodec STREAM_CODEC = CustomPacketPayload.codec(ServerboundMapPayload::write, ServerboundMapPayload::new);
+ public static final Type TYPE = new Type<>(new ResourceLocation(Constants.MODID, "server_map_data"));
+
+ public ServerboundMapPayload(int mapId) {
+ this(Constants.PROTOCOL, mapId);
+ }
+
+ public ServerboundMapPayload(FriendlyByteBuf friendlyByteBuf) {
+ this(friendlyByteBuf.readInt(), friendlyByteBuf.readInt());
+ }
+
+ private void write(FriendlyByteBuf friendlyByteBuf) {
+ friendlyByteBuf.writeInt(protocol);
+ friendlyByteBuf.writeInt(mapId);
+ }
+
+ @Override
+ public Type extends CustomPacketPayload> type() {
+ return TYPE;
+ }
+}
diff --git a/bukkit/src/main/java/net/pl3x/map/bukkit/network/ServerboundServerPayload.java b/bukkit/src/main/java/net/pl3x/map/bukkit/network/ServerboundServerPayload.java
new file mode 100644
index 000000000..0601dd640
--- /dev/null
+++ b/bukkit/src/main/java/net/pl3x/map/bukkit/network/ServerboundServerPayload.java
@@ -0,0 +1,25 @@
+package net.pl3x.map.bukkit.network;
+
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.codec.StreamCodec;
+import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
+import net.minecraft.resources.ResourceLocation;
+import net.pl3x.map.core.network.Constants;
+
+public record ServerboundServerPayload(int protocol) implements CustomPacketPayload {
+ public static final StreamCodec STREAM_CODEC = CustomPacketPayload.codec(ServerboundServerPayload::write, ServerboundServerPayload::new);
+ public static final Type TYPE = new Type<>(new ResourceLocation(Constants.MODID, "server_server_data"));
+
+ public ServerboundServerPayload(FriendlyByteBuf friendlyByteBuf) {
+ this(friendlyByteBuf.readInt());
+ }
+
+ private void write(FriendlyByteBuf friendlyByteBuf) {
+ friendlyByteBuf.writeInt(protocol);
+ }
+
+ @Override
+ public Type extends CustomPacketPayload> type() {
+ return TYPE;
+ }
+}
diff --git a/core/src/main/java/net/pl3x/map/core/command/CommandHandler.java b/core/src/main/java/net/pl3x/map/core/command/CommandHandler.java
index bab0efe0b..ef38bfdb8 100644
--- a/core/src/main/java/net/pl3x/map/core/command/CommandHandler.java
+++ b/core/src/main/java/net/pl3x/map/core/command/CommandHandler.java
@@ -23,15 +23,11 @@
*/
package net.pl3x.map.core.command;
-import cloud.commandframework.Command;
-import cloud.commandframework.CommandManager;
-import cloud.commandframework.meta.CommandMeta;
-import cloud.commandframework.minecraft.extras.AudienceProvider;
-import cloud.commandframework.minecraft.extras.MinecraftExceptionHandler;
import java.util.List;
import java.util.function.UnaryOperator;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
+import net.pl3x.map.core.Pl3xMap;
import net.pl3x.map.core.command.commands.ConfirmCommand;
import net.pl3x.map.core.command.commands.FullRenderCommand;
import net.pl3x.map.core.command.commands.HelpCommand;
@@ -45,8 +41,15 @@
import net.pl3x.map.core.command.commands.StatusCommand;
import net.pl3x.map.core.command.commands.StitchCommand;
import net.pl3x.map.core.command.commands.VersionCommand;
+import net.pl3x.map.core.command.parser.PlatformParsers;
import net.pl3x.map.core.configuration.Config;
import net.pl3x.map.core.configuration.Lang;
+import org.incendo.cloud.Command;
+import org.incendo.cloud.CommandManager;
+import org.incendo.cloud.description.CommandDescription;
+import org.incendo.cloud.description.Description;
+import org.incendo.cloud.minecraft.extras.AudienceProvider;
+import org.incendo.cloud.minecraft.extras.MinecraftExceptionHandler;
import org.jetbrains.annotations.NotNull;
/**
@@ -60,6 +63,13 @@ public interface CommandHandler {
*/
@NotNull CommandManager<@NotNull Sender> getManager();
+ /**
+ * Get the platform parsers.
+ *
+ * @return platform parsers
+ */
+ @NotNull PlatformParsers getPlatformParsers();
+
/**
* Get the root command.
*
@@ -68,15 +78,15 @@ public interface CommandHandler {
Command.@NotNull Builder<@NotNull Sender> getRoot();
default void setupExceptionHandlers() {
- new MinecraftExceptionHandler()
- .withDefaultHandlers()
- .withDecorator(component -> Component.text()
+ MinecraftExceptionHandler.createNative()
+ .defaultHandlers()
+ .decorator(component -> Component.text()
.append(Lang.parse(Lang.PREFIX_COMMAND)
.hoverEvent(Lang.parse(Lang.CLICK_FOR_HELP))
.clickEvent(ClickEvent.runCommand("/map help")))
.append(component)
.build())
- .apply(getManager(), AudienceProvider.nativeAudience());
+ .registerTo(getManager());
}
/**
@@ -91,9 +101,9 @@ default void registerSubcommand(@NotNull UnaryOperator buildRoot() {
return getManager().commandBuilder("map", "pl3xmap")
.permission("pl3xmap.command.map")
- .meta(CommandMeta.DESCRIPTION, "Pl3xMap command. '/map help'")
+ .commandDescription(CommandDescription.commandDescription("Pl3xMap command. '/map help'"))
.handler(context -> {
- context.getSender().sendMessage(Lang.COMMAND_BASE
+ context.sender().sendMessage(Lang.COMMAND_BASE
// minimessage doesn't seem to handle placeholders inside
// placeholders, so we have to replace this one manually
.replace("", Config.WEB_ADDRESS));
diff --git a/core/src/main/java/net/pl3x/map/core/command/Pl3xMapCommand.java b/core/src/main/java/net/pl3x/map/core/command/Pl3xMapCommand.java
index 8eadf82cd..0ceba395c 100644
--- a/core/src/main/java/net/pl3x/map/core/command/Pl3xMapCommand.java
+++ b/core/src/main/java/net/pl3x/map/core/command/Pl3xMapCommand.java
@@ -23,9 +23,9 @@
*/
package net.pl3x.map.core.command;
-import cloud.commandframework.minecraft.extras.RichDescription;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import net.pl3x.map.core.configuration.Lang;
+import org.incendo.cloud.minecraft.extras.RichDescription;
import org.jetbrains.annotations.NotNull;
/**
diff --git a/core/src/main/java/net/pl3x/map/core/command/argument/PlayerArgument.java b/core/src/main/java/net/pl3x/map/core/command/argument/PlayerArgument.java
deleted file mode 100644
index 49881dd1d..000000000
--- a/core/src/main/java/net/pl3x/map/core/command/argument/PlayerArgument.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2020-2023 William Blake Galbreath
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package net.pl3x.map.core.command.argument;
-
-import cloud.commandframework.ArgumentDescription;
-import cloud.commandframework.arguments.CommandArgument;
-import cloud.commandframework.context.CommandContext;
-import java.util.List;
-import java.util.function.BiFunction;
-import net.pl3x.map.core.Pl3xMap;
-import net.pl3x.map.core.command.Sender;
-import net.pl3x.map.core.command.argument.parser.PlayerParser;
-import net.pl3x.map.core.command.exception.PlayerParseException;
-import net.pl3x.map.core.configuration.Lang;
-import net.pl3x.map.core.player.Player;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * A {@link Player} argument that belongs to a command.
- *
- * @param command sender type
- */
-public class PlayerArgument extends CommandArgument<@NotNull C, @NotNull Player> {
- protected PlayerArgument(boolean required, @NotNull String name, @NotNull String defaultValue, @NotNull BiFunction<@NotNull CommandContext<@NotNull C>, @NotNull String, @NotNull List<@NotNull String>> suggestionsProvider, @NotNull ArgumentDescription defaultDescription) {
- super(required, name, new PlayerParser<>(), defaultValue, Player.class, suggestionsProvider, defaultDescription);
- }
-
- /**
- * Create a new {@link PlayerArgument} builder.
- *
- * @param name argument name
- * @return new player argument builder
- */
- public static CommandArgument.@NotNull Builder<@NotNull C, @NotNull Player> newBuilder(@NotNull String name) {
- return new Builder<>(name);
- }
-
- /**
- * Create a required {@link PlayerArgument}.
- *
- * @param name argument name
- * @return constructed player argument
- */
- public static @NotNull CommandArgument<@NotNull C, @NotNull Player> of(@NotNull String name) {
- return PlayerArgument.<@NotNull C>newBuilder(name).asRequired().build();
- }
-
- /**
- * Create an optional {@link PlayerArgument}.
- *
- * All arguments prior to any other required argument must also be required.
- *
- * @param name argument name
- * @return constructed player argument
- */
- public static @NotNull CommandArgument<@NotNull C, @NotNull Player> optional(@NotNull String name) {
- return PlayerArgument.<@NotNull C>newBuilder(name).asOptional().build();
- }
-
- /**
- * Create an optional {@link PlayerArgument} with a default value.
- *
- * All arguments prior to any other required argument must also be required.
- *
- * @param name argument name
- * @param defaultValue default value that will be used if none was supplied
- * @return constructed player argument
- */
- public static @NotNull CommandArgument<@NotNull C, @NotNull Player> optional(@NotNull String name, @NotNull String defaultValue) {
- return PlayerArgument.<@NotNull C>newBuilder(name).asOptionalWithDefault(defaultValue).build();
- }
-
- /**
- * Resolve {@link Player} from command context.
- *
- * If context does not contain a {@link Player} and the sender is a {@link net.pl3x.map.core.command.Sender.Player} then the sender will be used.
- *
- * @param context command context
- * @param name argument name
- * @return player
- * @throws PlayerParseException if context did not contain a {@link Player} and the sender is not a {@link net.pl3x.map.core.command.Sender.Player}
- */
- public static @NotNull Player resolve(@NotNull CommandContext<@NotNull Sender> context, @NotNull String name) {
- Sender sender = context.getSender();
- Player player = context.getOrDefault(name, null);
- if (player != null) {
- return player;
- }
- if (sender instanceof Sender.Player> senderPlayer) {
- player = Pl3xMap.api().getPlayerRegistry().get(senderPlayer.getUUID());
- if (player != null) {
- return player;
- }
- }
- sender.sendMessage(Lang.ERROR_MUST_SPECIFY_PLAYER);
- throw new PlayerParseException(null, PlayerParseException.MUST_SPECIFY_PLAYER);
- }
-
- /**
- * Mutable builder for {@link PlayerArgument} instances.
- *
- * @param command sender type
- */
- public static class Builder extends CommandArgument.Builder<@NotNull C, @NotNull Player> {
- private Builder(@NotNull String name) {
- super(Player.class, name);
- }
-
- @Override
- public @NotNull CommandArgument<@NotNull C, @NotNull Player> build() {
- return new PlayerArgument<>(isRequired(), getName(), getDefaultValue(), getSuggestionsProvider(), getDefaultDescription());
- }
- }
-}
diff --git a/core/src/main/java/net/pl3x/map/core/command/argument/PointArgument.java b/core/src/main/java/net/pl3x/map/core/command/argument/PointArgument.java
deleted file mode 100644
index 7de2ffca1..000000000
--- a/core/src/main/java/net/pl3x/map/core/command/argument/PointArgument.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2020-2023 William Blake Galbreath
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package net.pl3x.map.core.command.argument;
-
-import cloud.commandframework.ArgumentDescription;
-import cloud.commandframework.arguments.CommandArgument;
-import cloud.commandframework.context.CommandContext;
-import java.util.List;
-import java.util.function.BiFunction;
-import net.pl3x.map.core.Pl3xMap;
-import net.pl3x.map.core.command.Sender;
-import net.pl3x.map.core.command.argument.parser.PointParser;
-import net.pl3x.map.core.markers.Point;
-import net.pl3x.map.core.player.Player;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * A {@link Point} argument that belongs to a command.
- *
- * @param command sender type
- */
-@SuppressWarnings("unused")
-public class PointArgument extends CommandArgument<@NotNull C, @NotNull Point> {
- protected PointArgument(boolean required, @NotNull String name, @NotNull String defaultValue, @NotNull BiFunction<@NotNull CommandContext<@NotNull C>, @NotNull String, @NotNull List<@NotNull String>> suggestionsProvider, @NotNull ArgumentDescription defaultDescription) {
- super(required, name, new PointParser<>(), defaultValue, Point.class, suggestionsProvider, defaultDescription);
- }
-
- /**
- * Create a new {@link PointArgument} builder.
- *
- * @param name argument name
- * @return new point argument builder
- */
- public static CommandArgument.@NotNull Builder<@NotNull C, @NotNull Point> builder(@NotNull String name) {
- return new PointArgument.Builder<>(name);
- }
-
- /**
- * Create a required {@link PointArgument}.
- *
- * @param name argument name
- * @return constructed point argument
- */
- public static @NotNull CommandArgument<@NotNull C, @NotNull Point> of(@NotNull String name) {
- return PointArgument.<@NotNull C>builder(name).asRequired().build();
- }
-
- /**
- * Create an optional {@link PointArgument}.
- *
- * All arguments prior to any other required argument must also be required.
- *
- * @param name argument name
- * @return constructed point argument
- */
- public static @NotNull CommandArgument<@NotNull C, @NotNull Point> optional(@NotNull String name) {
- return PointArgument.<@NotNull C>builder(name).asOptional().build();
- }
-
- /**
- * Create an optional {@link PointArgument} with a default value.
- *
- * All arguments prior to any other required argument must also be required.
- *
- * @param name argument name
- * @param defaultValue default value that will be used if none was supplied
- * @return constructed point argument
- */
- public static @NotNull CommandArgument<@NotNull C, @NotNull Point> optional(@NotNull String name, @NotNull String defaultValue) {
- return PointArgument.<@NotNull C>builder(name).asOptionalWithDefault(defaultValue).build();
- }
-
- /**
- * Resolve {@link Point} from command context.
- *
- * If context does not contain a {@link Point} and the sender is a {@link net.pl3x.map.core.command.Sender.Player} then the sender's location will be used, otherwise [0, 0] will be used
- *
- * @param context command context
- * @param name argument name
- * @return player
- */
- public static @NotNull Point resolve(@NotNull CommandContext<@NotNull Sender> context, @NotNull String name) {
- Sender sender = context.getSender();
- Point point = context.getOrDefault(name, null);
- if (point != null) {
- return point;
- }
- if (sender instanceof Sender.Player) {
- Player player = Pl3xMap.api().getPlayerRegistry().get(((Sender.Player>) sender).getUUID());
- point = player == null ? Point.ZERO : player.getPosition();
- } else {
- point = Point.ZERO;
- }
- return point;
- }
-
- /**
- * Mutable builder for {@link PointArgument} instances.
- *
- * @param command sender type
- */
- public static class Builder extends CommandArgument.Builder<@NotNull C, @NotNull Point> {
- private Builder(@NotNull String name) {
- super(Point.class, name);
- }
-
- @Override
- public @NotNull CommandArgument<@NotNull C, @NotNull Point> build() {
- return new PointArgument<>(isRequired(), getName(), getDefaultValue(), getSuggestionsProvider(), getDefaultDescription());
- }
- }
-}
diff --git a/core/src/main/java/net/pl3x/map/core/command/argument/RendererArgument.java b/core/src/main/java/net/pl3x/map/core/command/argument/RendererArgument.java
deleted file mode 100644
index 575b3e203..000000000
--- a/core/src/main/java/net/pl3x/map/core/command/argument/RendererArgument.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2020-2023 William Blake Galbreath
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package net.pl3x.map.core.command.argument;
-
-import cloud.commandframework.ArgumentDescription;
-import cloud.commandframework.arguments.CommandArgument;
-import cloud.commandframework.context.CommandContext;
-import java.util.List;
-import java.util.function.BiFunction;
-import net.pl3x.map.core.command.argument.parser.RendererParser;
-import net.pl3x.map.core.renderer.Renderer;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * A {@link Renderer} argument that belongs to a command.
- *
- * @param command sender type
- */
-@SuppressWarnings("unused")
-public class RendererArgument extends CommandArgument<@NotNull C, Renderer.@NotNull Builder> {
- protected RendererArgument(boolean required, @NotNull String name, @NotNull String defaultValue, @NotNull BiFunction<@NotNull CommandContext<@NotNull C>, @NotNull String, @NotNull List<@NotNull String>> suggestionsProvider, @NotNull ArgumentDescription defaultDescription) {
- super(required, name, new RendererParser<>(), defaultValue, Renderer.Builder.class, suggestionsProvider, defaultDescription);
- }
-
- /**
- * Create a new {@link RendererArgument} builder.
- *
- * @param name argument name
- * @return new renderer argument builder
- */
- public static CommandArgument.@NotNull Builder<@NotNull C, Renderer.@NotNull Builder> builder(@NotNull String name) {
- return new RendererArgument.Builder<>(name);
- }
-
- /**
- * Create a required {@link RendererArgument}.
- *
- * @param name argument name
- * @return constructed renderer argument
- */
- public static @NotNull CommandArgument<@NotNull C, Renderer.@NotNull Builder> of(@NotNull String name) {
- return RendererArgument.<@NotNull C>builder(name).asRequired().build();
- }
-
- /**
- * Create an optional {@link RendererArgument}.
- *
- * All arguments prior to any other required argument must also be required.
- *
- * @param name argument name
- * @return constructed renderer argument
- */
- public static @NotNull CommandArgument<@NotNull C, Renderer.@NotNull Builder> optional(@NotNull String name) {
- return RendererArgument.<@NotNull C>builder(name).asOptional().build();
- }
-
- /**
- * Create an optional {@link RendererArgument} with a default value.
- *
- * All arguments prior to any other required argument must also be required.
- *
- * @param name argument name
- * @param defaultValue default value that will be used if none was supplied
- * @return constructed renderer argument
- */
- public static @NotNull CommandArgument<@NotNull C, Renderer.@NotNull Builder> optional(@NotNull String name, @NotNull String defaultValue) {
- return RendererArgument.<@NotNull C>builder(name).asOptionalWithDefault(defaultValue).build();
- }
-
- /**
- * Mutable builder for {@link RendererArgument} instances.
- *
- * @param command sender type
- */
- public static class Builder extends CommandArgument.Builder<@NotNull C, Renderer.@NotNull Builder> {
- private Builder(@NotNull String name) {
- super(Renderer.Builder.class, name);
- }
-
- @Override
- public @NotNull CommandArgument<@NotNull C, Renderer.@NotNull Builder> build() {
- return new RendererArgument<>(isRequired(), getName(), getDefaultValue(), getSuggestionsProvider(), getDefaultDescription());
- }
- }
-}
diff --git a/core/src/main/java/net/pl3x/map/core/command/argument/WorldArgument.java b/core/src/main/java/net/pl3x/map/core/command/argument/WorldArgument.java
deleted file mode 100644
index 58adec0ce..000000000
--- a/core/src/main/java/net/pl3x/map/core/command/argument/WorldArgument.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2020-2023 William Blake Galbreath
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package net.pl3x.map.core.command.argument;
-
-import cloud.commandframework.ArgumentDescription;
-import cloud.commandframework.arguments.CommandArgument;
-import cloud.commandframework.context.CommandContext;
-import java.util.List;
-import java.util.function.BiFunction;
-import net.pl3x.map.core.command.Sender;
-import net.pl3x.map.core.command.argument.parser.WorldParser;
-import net.pl3x.map.core.command.exception.WorldParseException;
-import net.pl3x.map.core.player.Player;
-import net.pl3x.map.core.world.World;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * A {@link World} argument that belongs to a command.
- *
- * @param command sender type
- */
-@SuppressWarnings("unused")
-public class WorldArgument extends CommandArgument<@NotNull C, @NotNull World> {
- protected WorldArgument(boolean required, @NotNull String name, @NotNull String defaultValue, @NotNull BiFunction<@NotNull CommandContext<@NotNull C>, @NotNull String, @NotNull List<@NotNull String>> suggestionsProvider, @NotNull ArgumentDescription defaultDescription) {
- super(required, name, new WorldParser<>(), defaultValue, World.class, suggestionsProvider, defaultDescription);
- }
-
- /**
- * Create a new {@link WorldArgument} builder.
- *
- * @param name argument name
- * @return new world argument builder
- */
- public static CommandArgument.@NotNull Builder<@NotNull C, @NotNull World> builder(@NotNull String name) {
- return new WorldArgument.Builder<>(name);
- }
-
- /**
- * Create a required {@link WorldArgument}.
- *
- * @param name argument name
- * @return constructed world argument
- */
- public static @NotNull CommandArgument<@NotNull C, @NotNull World> of(@NotNull String name) {
- return WorldArgument.<@NotNull C>builder(name).asRequired().build();
- }
-
- /**
- * Create an optional {@link WorldArgument}.
- *
- * All arguments prior to any other required argument must also be required.
- *
- * @param name argument name
- * @return constructed world argument
- */
- public static @NotNull CommandArgument<@NotNull C, @NotNull World> optional(@NotNull String name) {
- return WorldArgument.<@NotNull C>builder(name).asOptional().build();
- }
-
- /**
- * Create an optional {@link WorldArgument} with a default value.
- *
- * All arguments prior to any other required argument must also be required.
- *
- * @param name argument name
- * @param defaultValue default value that will be used if none was supplied
- * @return constructed world argument
- */
- public static @NotNull CommandArgument<@NotNull C, @NotNull World> optional(@NotNull String name, @NotNull String defaultValue) {
- return WorldArgument.<@NotNull C>builder(name).asOptionalWithDefault(defaultValue).build();
- }
-
- /**
- * Resolve {@link World} from command context.
- *
- * If context does not contain a {@link World} and the sender is a {@link Player} then the player's world will be used.
- *
- * @param context command context
- * @param name argument name
- * @return world
- * @throws WorldParseException if context did not contain a {@link World}
- * and the sender is not a {@link Player}, or
- * the world is not enabled
- */
- public static @NotNull World resolve(@NotNull CommandContext<@NotNull Sender> context, @NotNull String name) {
- Sender sender = context.getSender();
- World world = context.getOrDefault(name, null);
- if (world != null) {
- return world;
- }
- if (sender instanceof Sender.Player> player) {
- world = player.getWorld();
- if (world == null) {
- throw new WorldParseException("unknown", WorldParseException.NO_SUCH_WORLD);
- }
- if (!world.isEnabled()) {
- throw new WorldParseException(world.getName(), WorldParseException.MAP_NOT_ENABLED);
- } else {
- return world;
- }
- }
- throw new WorldParseException(null, WorldParseException.MUST_SPECIFY_WORLD);
- }
-
- /**
- * Mutable builder for {@link WorldArgument} instances.
- *
- * @param command sender type
- */
- public static class Builder extends CommandArgument.Builder<@NotNull C, @NotNull World> {
- private Builder(@NotNull String name) {
- super(World.class, name);
- }
-
- @Override
- public @NotNull CommandArgument<@NotNull C, @NotNull World> build() {
- return new WorldArgument<>(isRequired(), getName(), getDefaultValue(), getSuggestionsProvider(), getDefaultDescription());
- }
- }
-}
diff --git a/core/src/main/java/net/pl3x/map/core/command/argument/ZoomArgument.java b/core/src/main/java/net/pl3x/map/core/command/argument/ZoomArgument.java
deleted file mode 100644
index cecf6db8c..000000000
--- a/core/src/main/java/net/pl3x/map/core/command/argument/ZoomArgument.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2020-2023 William Blake Galbreath
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package net.pl3x.map.core.command.argument;
-
-import cloud.commandframework.ArgumentDescription;
-import cloud.commandframework.arguments.CommandArgument;
-import cloud.commandframework.context.CommandContext;
-import java.util.List;
-import java.util.function.BiFunction;
-import net.pl3x.map.core.command.argument.parser.ZoomParser;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * A {@link Integer} argument that belongs to a command.
- *
- * @param command sender type
- */
-public class ZoomArgument extends CommandArgument<@NotNull C, @NotNull Integer> {
- protected ZoomArgument(boolean required, @NotNull String name, @NotNull String defaultValue, @NotNull BiFunction<@NotNull CommandContext<@NotNull C>, @NotNull String, @NotNull List<@NotNull String>> suggestionsProvider, @NotNull ArgumentDescription defaultDescription) {
- super(required, name, new ZoomParser<>(), defaultValue, Integer.class, suggestionsProvider, defaultDescription);
- }
-
- /**
- * Create a new {@link ZoomArgument} builder.
- *
- * @param name argument name
- * @return new player argument builder
- */
- public static CommandArgument.@NotNull Builder<@NotNull C, @NotNull Integer> newBuilder(@NotNull String name) {
- return new Builder<>(name);
- }
-
- /**
- * Create a required {@link ZoomArgument}.
- *
- * @param name argument name
- * @return constructed player argument
- */
- public static @NotNull CommandArgument<@NotNull C, @NotNull Integer> of(@NotNull String name) {
- return ZoomArgument.<@NotNull C>newBuilder(name).asRequired().build();
- }
-
- /**
- * Create an optional {@link ZoomArgument}.
- *
- * All arguments prior to any other required argument must also be required.
- *
- * @param name argument name
- * @return constructed player argument
- */
- public static @NotNull CommandArgument<@NotNull C, @NotNull Integer> optional(@NotNull String name) {
- return ZoomArgument.<@NotNull C>newBuilder(name).asOptional().build();
- }
-
- /**
- * Create an optional {@link ZoomArgument} with a default value.
- *
- * All arguments prior to any other required argument must also be required.
- *
- * @param name argument name
- * @param defaultValue default value that will be used if none was supplied
- * @return constructed player argument
- */
- public static @NotNull CommandArgument<@NotNull C, @NotNull Integer> optional(@NotNull String name, @NotNull String defaultValue) {
- return ZoomArgument.<@NotNull C>newBuilder(name).asOptionalWithDefault(defaultValue).build();
- }
-
- /**
- * Mutable builder for {@link ZoomArgument} instances.
- *
- * @param command sender type
- */
- public static class Builder extends CommandArgument.Builder<@NotNull C, @NotNull Integer> {
- private Builder(@NotNull String name) {
- super(Integer.class, name);
- }
-
- @Override
- public @NotNull CommandArgument<@NotNull C, @NotNull Integer> build() {
- return new ZoomArgument<>(isRequired(), getName(), getDefaultValue(), getSuggestionsProvider(), getDefaultDescription());
- }
- }
-}
diff --git a/core/src/main/java/net/pl3x/map/core/command/argument/parser/PlayerParser.java b/core/src/main/java/net/pl3x/map/core/command/argument/parser/PlayerParser.java
deleted file mode 100644
index 793beff2a..000000000
--- a/core/src/main/java/net/pl3x/map/core/command/argument/parser/PlayerParser.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2020-2023 William Blake Galbreath
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package net.pl3x.map.core.command.argument.parser;
-
-import cloud.commandframework.arguments.parser.ArgumentParseResult;
-import cloud.commandframework.arguments.parser.ArgumentParser;
-import cloud.commandframework.context.CommandContext;
-import java.util.List;
-import java.util.Queue;
-import java.util.stream.Collectors;
-import net.pl3x.map.core.Pl3xMap;
-import net.pl3x.map.core.command.exception.PlayerParseException;
-import net.pl3x.map.core.player.Player;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Parser that parses strings into {@link Player}s.
- *
- * @param command sender type
- */
-public class PlayerParser implements ArgumentParser<@NotNull C, @NotNull Player> {
- @Override
- public @NotNull ArgumentParseResult<@NotNull Player> parse(@NotNull CommandContext<@NotNull C> context, @NotNull Queue<@NotNull String> queue) {
- String input = queue.peek();
- if (input == null) {
- return ArgumentParseResult.failure(new PlayerParseException(null, PlayerParseException.MUST_SPECIFY_PLAYER));
- }
-
- Player player = Pl3xMap.api().getPlayerRegistry().get(input);
- if (player == null) {
- return ArgumentParseResult.failure(new PlayerParseException(input, PlayerParseException.NO_SUCH_PLAYER));
- }
-
- queue.remove();
- return ArgumentParseResult.success(player);
- }
-
- @Override
- public @NotNull List<@NotNull String> suggestions(@NotNull CommandContext<@NotNull C> commandContext, @NotNull String input) {
- return Pl3xMap.api().getPlayerRegistry()
- .values().stream()
- .map(Player::getName)
- .collect(Collectors.toList());
- }
-}
diff --git a/core/src/main/java/net/pl3x/map/core/command/argument/parser/PointParser.java b/core/src/main/java/net/pl3x/map/core/command/argument/parser/PointParser.java
deleted file mode 100644
index 99c9e31b8..000000000
--- a/core/src/main/java/net/pl3x/map/core/command/argument/parser/PointParser.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2020-2023 William Blake Galbreath
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package net.pl3x.map.core.command.argument.parser;
-
-import cloud.commandframework.arguments.parser.ArgumentParseResult;
-import cloud.commandframework.arguments.parser.ArgumentParser;
-import cloud.commandframework.arguments.standard.IntegerArgument;
-import cloud.commandframework.context.CommandContext;
-import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Queue;
-import net.pl3x.map.core.command.exception.PointParseException;
-import net.pl3x.map.core.log.Logger;
-import net.pl3x.map.core.markers.Point;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Parser that parses strings into {@link Point}s.
- *
- * @param command sender type
- */
-public class PointParser implements ArgumentParser<@NotNull C, @NotNull Point> {
- @Override
- public @NotNull ArgumentParseResult<@NotNull Point> parse(@NotNull CommandContext<@NotNull C> context, @NotNull Queue<@NotNull String> queue) {
- if (queue.size() < 2) {
- StringBuilder input = new StringBuilder();
- for (int i = 0; i < queue.size(); i++) {
- input.append(((LinkedList) queue).get(i));
- }
- return ArgumentParseResult.failure(new PointParseException(input.toString(), PointParseException.INVALID_FORMAT));
- }
- Integer[] coordinates = new Integer[2];
- for (int i = 0; i < 2; i++) {
- ArgumentParseResult coordinate = parseCoord(context, queue);
- if (coordinate.getFailure().isPresent()) {
- return ArgumentParseResult.failure(coordinate.getFailure().get());
- }
- coordinates[i] = coordinate.getParsedValue().orElseThrow(NullPointerException::new);
- }
-
- return ArgumentParseResult.success(new Point(coordinates[0], coordinates[1]));
- }
-
- @Override
- public @NotNull List<@NotNull String> suggestions(@NotNull CommandContext<@NotNull C> commandContext, @NotNull String input) {
- return IntegerArgument.IntegerParser.getSuggestions(Integer.MIN_VALUE, Integer.MAX_VALUE, input);
- }
-
- public @NotNull ArgumentParseResult<@NotNull Integer> parseCoord(@NotNull CommandContext<@NotNull C> context, @NotNull Queue<@NotNull String> queue) {
- String input = queue.peek();
- if (input == null) {
- return ArgumentParseResult.failure(new NoInputProvidedException(PointParser.class, context));
- }
-
- int coordinate;
- try {
- coordinate = input.isEmpty() ? 0 : Integer.parseInt(input);
- } catch (Exception e) {
- Logger.severe("Failed to get integer from coordinate input", e);
- return ArgumentParseResult.failure(new IntegerArgument.IntegerParseException(
- input,
- new IntegerArgument.IntegerParser<>(
- IntegerArgument.IntegerParser.DEFAULT_MINIMUM,
- IntegerArgument.IntegerParser.DEFAULT_MAXIMUM
- ),
- context
- ));
- }
-
- queue.remove();
- return ArgumentParseResult.success(coordinate);
- }
-}
diff --git a/core/src/main/java/net/pl3x/map/core/command/commands/ConfirmCommand.java b/core/src/main/java/net/pl3x/map/core/command/commands/ConfirmCommand.java
index 16443316f..0983d5f77 100644
--- a/core/src/main/java/net/pl3x/map/core/command/commands/ConfirmCommand.java
+++ b/core/src/main/java/net/pl3x/map/core/command/commands/ConfirmCommand.java
@@ -23,8 +23,8 @@
*/
package net.pl3x.map.core.command.commands;
-import cloud.commandframework.extra.confirmation.CommandConfirmationManager;
-import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys;
+import com.google.common.cache.CacheBuilder;
+import java.time.Duration;
import java.util.concurrent.TimeUnit;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
@@ -32,17 +32,27 @@
import net.pl3x.map.core.command.Pl3xMapCommand;
import net.pl3x.map.core.command.Sender;
import net.pl3x.map.core.configuration.Lang;
+import org.incendo.cloud.description.CommandDescription;
+import org.incendo.cloud.description.Description;
+import org.incendo.cloud.minecraft.extras.RichDescription;
+import org.incendo.cloud.processors.cache.CloudCache;
+import org.incendo.cloud.processors.cache.GuavaCache;
+import org.incendo.cloud.processors.confirmation.ConfirmationConfiguration;
+import org.incendo.cloud.processors.confirmation.ConfirmationManager;
import org.jetbrains.annotations.NotNull;
public class ConfirmCommand extends Pl3xMapCommand {
- private final CommandConfirmationManager<@NotNull Sender> confirmationManager = new CommandConfirmationManager<>(
- 15L, TimeUnit.SECONDS,
- context -> context.getCommandContext().getSender().sendMessage(
- Component.text().append(Lang.parse(Lang.COMMAND_CONFIRM_CONFIRMATION_REQUIRED_MESSAGE))
- .hoverEvent(Lang.parse(Lang.CLICK_TO_CONFIRM))
- .clickEvent(ClickEvent.runCommand("/map confirm"))
- ),
- sender -> sender.sendMessage(Lang.COMMAND_CONFIRM_NO_PENDING_MESSAGE)
+ private final ConfirmationManager<@NotNull Sender> confirmationManager = ConfirmationManager.confirmationManager(
+ ConfirmationConfiguration.builder()
+ .cache(GuavaCache.of(CacheBuilder.newBuilder().build()))
+ .noPendingCommandNotifier(sender -> sender.sendMessage(Lang.COMMAND_CONFIRM_NO_PENDING_MESSAGE))
+ .confirmationRequiredNotifier((sender, senderConfirmationContext) -> sender.sendMessage(
+ Component.text().append(Lang.parse(Lang.COMMAND_CONFIRM_CONFIRMATION_REQUIRED_MESSAGE))
+ .hoverEvent(Lang.parse(Lang.CLICK_TO_CONFIRM))
+ .clickEvent(ClickEvent.runCommand("/map confirm"))
+ ))
+ .expiration(Duration.ofSeconds(15L))
+ .build()
);
public ConfirmCommand(@NotNull CommandHandler handler) {
@@ -51,11 +61,11 @@ public ConfirmCommand(@NotNull CommandHandler handler) {
@Override
public void register() {
- this.confirmationManager.registerConfirmationProcessor(getHandler().getManager());
+ getHandler().getManager().registerCommandPostProcessor(this.confirmationManager.createPostprocessor());
getHandler().registerSubcommand(builder -> builder.literal("confirm")
- .meta(MinecraftExtrasMetaKeys.DESCRIPTION, Lang.parse(Lang.COMMAND_CONFIRM_DESCRIPTION))
+ .commandDescription(RichDescription.of(Lang.parse(Lang.COMMAND_CONFIRM_DESCRIPTION)))
.permission("pl3xmap.command.confirm")
- .handler(this.confirmationManager.createConfirmationExecutionHandler()));
+ .handler(this.confirmationManager.createExecutionHandler()));
}
}
diff --git a/core/src/main/java/net/pl3x/map/core/command/commands/FullRenderCommand.java b/core/src/main/java/net/pl3x/map/core/command/commands/FullRenderCommand.java
index b5c02f944..380b84077 100644
--- a/core/src/main/java/net/pl3x/map/core/command/commands/FullRenderCommand.java
+++ b/core/src/main/java/net/pl3x/map/core/command/commands/FullRenderCommand.java
@@ -23,20 +23,20 @@
*/
package net.pl3x.map.core.command.commands;
-import cloud.commandframework.context.CommandContext;
-import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import net.pl3x.map.core.Pl3xMap;
import net.pl3x.map.core.command.CommandHandler;
import net.pl3x.map.core.command.Pl3xMapCommand;
import net.pl3x.map.core.command.Sender;
-import net.pl3x.map.core.command.argument.WorldArgument;
+import net.pl3x.map.core.command.parser.WorldParser;
import net.pl3x.map.core.configuration.Config;
import net.pl3x.map.core.configuration.Lang;
import net.pl3x.map.core.log.Logger;
import net.pl3x.map.core.markers.Point;
import net.pl3x.map.core.world.World;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.minecraft.extras.RichDescription;
import org.jetbrains.annotations.NotNull;
public class FullRenderCommand extends Pl3xMapCommand {
@@ -47,8 +47,8 @@ public FullRenderCommand(@NotNull CommandHandler handler) {
@Override
public void register() {
getHandler().registerSubcommand(builder -> builder.literal("fullrender")
- .argument(WorldArgument.of("world"), description(Lang.COMMAND_ARGUMENT_REQUIRED_WORLD_DESCRIPTION))
- .meta(MinecraftExtrasMetaKeys.DESCRIPTION, Lang.parse(Lang.COMMAND_FULLRENDER_DESCRIPTION))
+ .required("world", WorldParser.parser(), description(Lang.COMMAND_ARGUMENT_REQUIRED_WORLD_DESCRIPTION))
+ .commandDescription(RichDescription.of(Lang.parse(Lang.COMMAND_FULLRENDER_DESCRIPTION)))
.permission("pl3xmap.command.fullrender")
.handler(this::execute));
}
@@ -58,7 +58,7 @@ public void execute(@NotNull CommandContext<@NotNull Sender> context) {
}
private void executeAsync(@NotNull CommandContext<@NotNull Sender> context) {
- Sender sender = context.getSender();
+ Sender sender = context.sender();
World world = context.get("world");
Collection regions = world.listRegions(true);
diff --git a/core/src/main/java/net/pl3x/map/core/command/commands/HelpCommand.java b/core/src/main/java/net/pl3x/map/core/command/commands/HelpCommand.java
index 1ed6074bb..372791e0d 100644
--- a/core/src/main/java/net/pl3x/map/core/command/commands/HelpCommand.java
+++ b/core/src/main/java/net/pl3x/map/core/command/commands/HelpCommand.java
@@ -23,16 +23,19 @@
*/
package net.pl3x.map.core.command.commands;
-import cloud.commandframework.CommandHelpHandler.VerboseHelpEntry;
-import cloud.commandframework.arguments.standard.StringArgument;
-import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys;
-import cloud.commandframework.minecraft.extras.MinecraftHelp;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.pl3x.map.core.command.CommandHandler;
import net.pl3x.map.core.command.Pl3xMapCommand;
import net.pl3x.map.core.command.Sender;
import net.pl3x.map.core.configuration.Lang;
+import org.incendo.cloud.component.CommandComponent;
+import org.incendo.cloud.help.result.CommandEntry;
+import org.incendo.cloud.minecraft.extras.AudienceProvider;
+import org.incendo.cloud.minecraft.extras.MinecraftHelp;
+import org.incendo.cloud.minecraft.extras.RichDescription;
+import org.incendo.cloud.parser.standard.StringParser;
+import org.incendo.cloud.suggestion.SuggestionProvider;
import org.jetbrains.annotations.NotNull;
public class HelpCommand extends Pl3xMapCommand {
@@ -40,30 +43,34 @@ public class HelpCommand extends Pl3xMapCommand {
public HelpCommand(@NotNull CommandHandler handler) {
super(handler);
- this.minecraftHelp = MinecraftHelp.createNative("/map help", handler.getManager());
- this.minecraftHelp.setHelpColors(MinecraftHelp.HelpColors.of(
- TextColor.color(0x5B00FF),
- NamedTextColor.WHITE,
- TextColor.color(0xC028FF),
- NamedTextColor.GRAY,
- NamedTextColor.DARK_GRAY
- ));
- this.minecraftHelp.setMessage(MinecraftHelp.MESSAGE_HELP_TITLE, "Pl3xMap Help");
+ this.minecraftHelp = MinecraftHelp.builder()
+ .commandManager(handler.getManager())
+ .audienceProvider(AudienceProvider.nativeAudience())
+ .commandPrefix("/map help")
+ .colors(MinecraftHelp.helpColors(
+ TextColor.color(0x5B00FF),
+ NamedTextColor.WHITE,
+ TextColor.color(0xC028FF),
+ NamedTextColor.GRAY,
+ NamedTextColor.DARK_GRAY
+ ))
+ .messages(MinecraftHelp.MESSAGE_HELP_TITLE, "Pl3xMap Help")
+ .build();
}
@Override
public void register() {
getHandler().registerSubcommand(builder -> builder.literal("help")
- .meta(MinecraftExtrasMetaKeys.DESCRIPTION, Lang.parse(Lang.COMMAND_HELP_DESCRIPTION))
- .argument(StringArgument.builder("query").greedy().asOptional()
- .withSuggestionsProvider((context, input) -> getHandler().getManager()
- .createCommandHelpHandler().queryRootIndex(context.getSender())
- .getEntries().stream().map(VerboseHelpEntry::getSyntaxString).toList())
- .build(), description(Lang.COMMAND_HELP_ARGUMENT_QUERY_DESCRIPTION))
+ .commandDescription(RichDescription.of(Lang.parse(Lang.COMMAND_HELP_DESCRIPTION)))
+ .optional(CommandComponent.ofType(String.class, "query")
+ .parser(StringParser.greedyStringParser())
+ .suggestionProvider(SuggestionProvider.blockingStrings((context, input) -> getHandler().getManager()
+ .createHelpHandler().queryRootIndex(context.sender())
+ .entries().stream().map(CommandEntry::syntax).toList())))
.permission("pl3xmap.command.help")
.handler(ctx -> {
- String query = ctx.getOptional("query").orElse("");
- this.minecraftHelp.queryCommands(query, ctx.getSender());
+ String query = ctx.optional("query").orElse("");
+ this.minecraftHelp.queryCommands(query, ctx.sender());
}));
}
}
diff --git a/core/src/main/java/net/pl3x/map/core/command/commands/HideCommand.java b/core/src/main/java/net/pl3x/map/core/command/commands/HideCommand.java
index 7c3565a49..fb24fb474 100644
--- a/core/src/main/java/net/pl3x/map/core/command/commands/HideCommand.java
+++ b/core/src/main/java/net/pl3x/map/core/command/commands/HideCommand.java
@@ -23,15 +23,14 @@
*/
package net.pl3x.map.core.command.commands;
-import cloud.commandframework.context.CommandContext;
-import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.pl3x.map.core.command.CommandHandler;
import net.pl3x.map.core.command.Pl3xMapCommand;
import net.pl3x.map.core.command.Sender;
-import net.pl3x.map.core.command.argument.PlayerArgument;
import net.pl3x.map.core.configuration.Lang;
import net.pl3x.map.core.player.Player;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.minecraft.extras.RichDescription;
import org.jetbrains.annotations.NotNull;
public class HideCommand extends Pl3xMapCommand {
@@ -42,19 +41,25 @@ public HideCommand(@NotNull CommandHandler handler) {
@Override
public void register() {
getHandler().registerSubcommand(builder -> builder.literal("hide")
- .meta(MinecraftExtrasMetaKeys.DESCRIPTION, Lang.parse(Lang.COMMAND_HIDE_DESCRIPTION))
+ .commandDescription(RichDescription.of(Lang.parse(Lang.COMMAND_HIDE_DESCRIPTION)))
.permission("pl3xmap.command.hide")
.handler(this::execute));
getHandler().registerSubcommand(builder -> builder.literal("hide")
- .argument(PlayerArgument.optional("player"), description(Lang.COMMAND_ARGUMENT_OPTIONAL_PLAYER_DESCRIPTION))
- .meta(MinecraftExtrasMetaKeys.DESCRIPTION, Lang.parse(Lang.COMMAND_HIDE_DESCRIPTION))
+ .optional("player", getHandler().getPlatformParsers().playerSelectorParser(),
+ description(Lang.COMMAND_ARGUMENT_OPTIONAL_PLAYER_DESCRIPTION))
+ .commandDescription(RichDescription.of(Lang.parse(Lang.COMMAND_HIDE_DESCRIPTION)))
.permission("pl3xmap.command.hide.others")
.handler(this::execute));
}
private void execute(@NotNull CommandContext<@NotNull Sender> context) {
- Sender sender = context.getSender();
- Player player = PlayerArgument.resolve(context, "player");
+ Sender sender = context.sender();
+ Player player = getHandler().getPlatformParsers().resolvePlayerFromPlayerSelector("player", context);
+
+ if (player == null) {
+ sender.sendMessage(Lang.ERROR_MUST_SPECIFY_PLAYER);
+ return;
+ }
if (player.isHidden()) {
sender.sendMessage(Lang.COMMAND_HIDE_ALREADY_HIDDEN,
@@ -67,4 +72,6 @@ private void execute(@NotNull CommandContext<@NotNull Sender> context) {
sender.sendMessage(Lang.COMMAND_HIDE_SUCCESS,
Placeholder.unparsed("player", player.getName()));
}
+
+
}
diff --git a/core/src/main/java/net/pl3x/map/core/command/commands/PauseCommand.java b/core/src/main/java/net/pl3x/map/core/command/commands/PauseCommand.java
index 241f5a783..ddaede302 100644
--- a/core/src/main/java/net/pl3x/map/core/command/commands/PauseCommand.java
+++ b/core/src/main/java/net/pl3x/map/core/command/commands/PauseCommand.java
@@ -23,14 +23,14 @@
*/
package net.pl3x.map.core.command.commands;
-import cloud.commandframework.context.CommandContext;
-import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys;
import net.pl3x.map.core.Pl3xMap;
import net.pl3x.map.core.command.CommandHandler;
import net.pl3x.map.core.command.Pl3xMapCommand;
import net.pl3x.map.core.command.Sender;
import net.pl3x.map.core.configuration.Lang;
import net.pl3x.map.core.renderer.task.RegionProcessor;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.minecraft.extras.RichDescription;
import org.jetbrains.annotations.NotNull;
public class PauseCommand extends Pl3xMapCommand {
@@ -41,13 +41,13 @@ public PauseCommand(@NotNull CommandHandler handler) {
@Override
public void register() {
getHandler().registerSubcommand(builder -> builder.literal("pause")
- .meta(MinecraftExtrasMetaKeys.DESCRIPTION, Lang.parse(Lang.COMMAND_PAUSE_DESCRIPTION))
+ .commandDescription(RichDescription.of(Lang.parse(Lang.COMMAND_PAUSE_DESCRIPTION)))
.permission("pl3xmap.command.pause")
.handler(this::execute));
}
private void execute(@NotNull CommandContext<@NotNull Sender> context) {
- Sender sender = context.getSender();
+ Sender sender = context.sender();
RegionProcessor processor = Pl3xMap.api().getRegionProcessor();
diff --git a/core/src/main/java/net/pl3x/map/core/command/commands/RadiusRenderCommand.java b/core/src/main/java/net/pl3x/map/core/command/commands/RadiusRenderCommand.java
index 59da5fd8e..2f6e56d82 100644
--- a/core/src/main/java/net/pl3x/map/core/command/commands/RadiusRenderCommand.java
+++ b/core/src/main/java/net/pl3x/map/core/command/commands/RadiusRenderCommand.java
@@ -23,22 +23,21 @@
*/
package net.pl3x.map.core.command.commands;
-import cloud.commandframework.arguments.standard.IntegerArgument;
-import cloud.commandframework.context.CommandContext;
-import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import net.pl3x.map.core.Pl3xMap;
import net.pl3x.map.core.command.CommandHandler;
import net.pl3x.map.core.command.Pl3xMapCommand;
import net.pl3x.map.core.command.Sender;
-import net.pl3x.map.core.command.argument.PointArgument;
-import net.pl3x.map.core.command.argument.WorldArgument;
+import net.pl3x.map.core.command.parser.WorldParser;
import net.pl3x.map.core.configuration.Config;
import net.pl3x.map.core.configuration.Lang;
import net.pl3x.map.core.log.Logger;
import net.pl3x.map.core.markers.Point;
import net.pl3x.map.core.world.World;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.minecraft.extras.RichDescription;
+import org.incendo.cloud.parser.standard.IntegerParser;
import org.jetbrains.annotations.NotNull;
public class RadiusRenderCommand extends Pl3xMapCommand {
@@ -49,10 +48,10 @@ public RadiusRenderCommand(@NotNull CommandHandler handler) {
@Override
public void register() {
getHandler().registerSubcommand(builder -> builder.literal("radiusrender")
- .argument(WorldArgument.of("world"), description(Lang.COMMAND_ARGUMENT_REQUIRED_WORLD_DESCRIPTION))
- .argument(IntegerArgument.builder("radius").withMin(1).withMax(1000000).build())
- .argument(PointArgument.optional("center"), description(Lang.COMMAND_ARGUMENT_OPTIONAL_CENTER_DESCRIPTION))
- .meta(MinecraftExtrasMetaKeys.DESCRIPTION, Lang.parse(Lang.COMMAND_RADIUSRENDER_DESCRIPTION))
+ .required("world", WorldParser.parser(), description(Lang.COMMAND_ARGUMENT_REQUIRED_WORLD_DESCRIPTION))
+ .required("radius", IntegerParser.integerParser(1, 1000000))
+ .optional("center", getHandler().getPlatformParsers().columnPosParser(), description(Lang.COMMAND_ARGUMENT_OPTIONAL_CENTER_DESCRIPTION))
+ .commandDescription(RichDescription.of(Lang.parse(Lang.COMMAND_RADIUSRENDER_DESCRIPTION)))
.permission("pl3xmap.command.radiusrender")
.handler(this::execute));
}
@@ -62,10 +61,10 @@ public void execute(@NotNull CommandContext<@NotNull Sender> context) {
}
private void executeAsync(@NotNull CommandContext<@NotNull Sender> context) {
- Sender sender = context.getSender();
+ Sender sender = context.sender();
World world = context.get("world");
int radius = context.get("radius");
- Point center = PointArgument.resolve(context, "center");
+ Point center = getHandler().getPlatformParsers().resolvePointFromColumnPos("center", context);
int rX = center.x() >> 9;
int rZ = center.z() >> 9;
diff --git a/core/src/main/java/net/pl3x/map/core/command/commands/ReloadCommand.java b/core/src/main/java/net/pl3x/map/core/command/commands/ReloadCommand.java
index ec7a7a69e..d0f105b59 100644
--- a/core/src/main/java/net/pl3x/map/core/command/commands/ReloadCommand.java
+++ b/core/src/main/java/net/pl3x/map/core/command/commands/ReloadCommand.java
@@ -23,14 +23,14 @@
*/
package net.pl3x.map.core.command.commands;
-import cloud.commandframework.context.CommandContext;
-import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.pl3x.map.core.Pl3xMap;
import net.pl3x.map.core.command.CommandHandler;
import net.pl3x.map.core.command.Pl3xMapCommand;
import net.pl3x.map.core.command.Sender;
import net.pl3x.map.core.configuration.Lang;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.minecraft.extras.RichDescription;
import org.jetbrains.annotations.NotNull;
public class ReloadCommand extends Pl3xMapCommand {
@@ -41,7 +41,7 @@ public ReloadCommand(@NotNull CommandHandler handler) {
@Override
public void register() {
getHandler().registerSubcommand(builder -> builder.literal("reload")
- .meta(MinecraftExtrasMetaKeys.DESCRIPTION, Lang.parse(Lang.COMMAND_RELOAD_DESCRIPTION))
+ .commandDescription(RichDescription.of(Lang.parse(Lang.COMMAND_RELOAD_DESCRIPTION)))
.permission("pl3xmap.command.reload")
.handler(this::execute));
}
@@ -51,7 +51,7 @@ public void execute(@NotNull CommandContext<@NotNull Sender> context) {
Pl3xMap.api().enable();
- context.getSender().sendMessage(Lang.COMMAND_RELOAD_SUCCESS,
+ context.sender().sendMessage(Lang.COMMAND_RELOAD_SUCCESS,
Placeholder.unparsed("version", Pl3xMap.api().getVersion()));
}
}
diff --git a/core/src/main/java/net/pl3x/map/core/command/commands/ResetMapCommand.java b/core/src/main/java/net/pl3x/map/core/command/commands/ResetMapCommand.java
index f82e79295..2b8ac1341 100644
--- a/core/src/main/java/net/pl3x/map/core/command/commands/ResetMapCommand.java
+++ b/core/src/main/java/net/pl3x/map/core/command/commands/ResetMapCommand.java
@@ -23,9 +23,6 @@
*/
package net.pl3x.map.core.command.commands;
-import cloud.commandframework.context.CommandContext;
-import cloud.commandframework.extra.confirmation.CommandConfirmationManager;
-import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
@@ -34,10 +31,13 @@
import net.pl3x.map.core.command.CommandHandler;
import net.pl3x.map.core.command.Pl3xMapCommand;
import net.pl3x.map.core.command.Sender;
-import net.pl3x.map.core.command.argument.WorldArgument;
+import net.pl3x.map.core.command.parser.WorldParser;
import net.pl3x.map.core.configuration.Lang;
import net.pl3x.map.core.util.FileUtil;
import net.pl3x.map.core.world.World;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.minecraft.extras.RichDescription;
+import org.incendo.cloud.processors.confirmation.ConfirmationManager;
import org.jetbrains.annotations.NotNull;
public class ResetMapCommand extends Pl3xMapCommand {
@@ -48,9 +48,9 @@ public ResetMapCommand(@NotNull CommandHandler handler) {
@Override
public void register() {
getHandler().registerSubcommand(builder -> builder.literal("resetmap")
- .argument(WorldArgument.of("world"), description(Lang.COMMAND_ARGUMENT_REQUIRED_WORLD_DESCRIPTION))
- .meta(MinecraftExtrasMetaKeys.DESCRIPTION, Lang.parse(Lang.COMMAND_RESETMAP_DESCRIPTION))
- .meta(CommandConfirmationManager.META_CONFIRMATION_REQUIRED, true)
+ .required("world", WorldParser.parser(), description(Lang.COMMAND_ARGUMENT_REQUIRED_WORLD_DESCRIPTION))
+ .commandDescription(RichDescription.of(Lang.parse(Lang.COMMAND_RESETMAP_DESCRIPTION)))
+ .meta(ConfirmationManager.META_CONFIRMATION_REQUIRED, true)
.permission("pl3xmap.command.resetmap")
.handler(this::execute));
}
@@ -60,7 +60,7 @@ private void execute(@NotNull CommandContext<@NotNull Sender> context) {
}
private void executeAsync(@NotNull CommandContext<@NotNull Sender> context) {
- Sender sender = context.getSender();
+ Sender sender = context.sender();
World world = context.get("world");
TagResolver.Single worldPlaceholder = Placeholder.unparsed("world", world.getName());
diff --git a/core/src/main/java/net/pl3x/map/core/command/commands/ResumeCommand.java b/core/src/main/java/net/pl3x/map/core/command/commands/ResumeCommand.java
index 430b0aba4..3dd6e46c1 100644
--- a/core/src/main/java/net/pl3x/map/core/command/commands/ResumeCommand.java
+++ b/core/src/main/java/net/pl3x/map/core/command/commands/ResumeCommand.java
@@ -23,14 +23,14 @@
*/
package net.pl3x.map.core.command.commands;
-import cloud.commandframework.context.CommandContext;
-import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys;
import net.pl3x.map.core.Pl3xMap;
import net.pl3x.map.core.command.CommandHandler;
import net.pl3x.map.core.command.Pl3xMapCommand;
import net.pl3x.map.core.command.Sender;
import net.pl3x.map.core.configuration.Lang;
import net.pl3x.map.core.renderer.task.RegionProcessor;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.minecraft.extras.RichDescription;
import org.jetbrains.annotations.NotNull;
public class ResumeCommand extends Pl3xMapCommand {
@@ -41,13 +41,13 @@ public ResumeCommand(@NotNull CommandHandler handler) {
@Override
public void register() {
getHandler().registerSubcommand(builder -> builder.literal("resume")
- .meta(MinecraftExtrasMetaKeys.DESCRIPTION, Lang.parse(Lang.COMMAND_RESUME_DESCRIPTION))
+ .commandDescription(RichDescription.of(Lang.parse(Lang.COMMAND_RESUME_DESCRIPTION)))
.permission("pl3xmap.command.resume")
.handler(this::execute));
}
private void execute(@NotNull CommandContext<@NotNull Sender> context) {
- Sender sender = context.getSender();
+ Sender sender = context.sender();
RegionProcessor processor = Pl3xMap.api().getRegionProcessor();
diff --git a/core/src/main/java/net/pl3x/map/core/command/commands/ShowCommand.java b/core/src/main/java/net/pl3x/map/core/command/commands/ShowCommand.java
index fb46a3d36..9851061fd 100644
--- a/core/src/main/java/net/pl3x/map/core/command/commands/ShowCommand.java
+++ b/core/src/main/java/net/pl3x/map/core/command/commands/ShowCommand.java
@@ -23,15 +23,14 @@
*/
package net.pl3x.map.core.command.commands;
-import cloud.commandframework.context.CommandContext;
-import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.pl3x.map.core.command.CommandHandler;
import net.pl3x.map.core.command.Pl3xMapCommand;
import net.pl3x.map.core.command.Sender;
-import net.pl3x.map.core.command.argument.PlayerArgument;
import net.pl3x.map.core.configuration.Lang;
import net.pl3x.map.core.player.Player;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.minecraft.extras.RichDescription;
import org.jetbrains.annotations.NotNull;
public class ShowCommand extends Pl3xMapCommand {
@@ -42,19 +41,24 @@ public ShowCommand(@NotNull CommandHandler handler) {
@Override
public void register() {
getHandler().registerSubcommand(builder -> builder.literal("show")
- .meta(MinecraftExtrasMetaKeys.DESCRIPTION, Lang.parse(Lang.COMMAND_SHOW_DESCRIPTION))
+ .commandDescription(RichDescription.of(Lang.parse(Lang.COMMAND_SHOW_DESCRIPTION)))
.permission("pl3xmap.command.show")
.handler(this::execute));
getHandler().registerSubcommand(builder -> builder.literal("show")
- .argument(PlayerArgument.optional("player"), description(Lang.COMMAND_ARGUMENT_OPTIONAL_PLAYER_DESCRIPTION))
- .meta(MinecraftExtrasMetaKeys.DESCRIPTION, Lang.parse(Lang.COMMAND_SHOW_DESCRIPTION))
+ .optional("player", getHandler().getPlatformParsers().playerSelectorParser(), description(Lang.COMMAND_ARGUMENT_OPTIONAL_PLAYER_DESCRIPTION))
+ .commandDescription(RichDescription.of(Lang.parse(Lang.COMMAND_SHOW_DESCRIPTION)))
.permission("pl3xmap.command.show.others")
.handler(this::execute));
}
private void execute(@NotNull CommandContext<@NotNull Sender> context) {
- Sender sender = context.getSender();
- Player target = PlayerArgument.resolve(context, "player");
+ Sender sender = context.sender();
+ Player target = getHandler().getPlatformParsers().resolvePlayerFromPlayerSelector("player", context);
+
+ if (target == null) {
+ sender.sendMessage(Lang.ERROR_MUST_SPECIFY_PLAYER);
+ return;
+ }
if (!target.isHidden()) {
sender.sendMessage(Lang.COMMAND_SHOW_NOT_HIDDEN,
diff --git a/core/src/main/java/net/pl3x/map/core/command/commands/StatusCommand.java b/core/src/main/java/net/pl3x/map/core/command/commands/StatusCommand.java
index 8e44b1d88..d30654bc8 100644
--- a/core/src/main/java/net/pl3x/map/core/command/commands/StatusCommand.java
+++ b/core/src/main/java/net/pl3x/map/core/command/commands/StatusCommand.java
@@ -23,8 +23,6 @@
*/
package net.pl3x.map.core.command.commands;
-import cloud.commandframework.context.CommandContext;
-import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys;
import java.util.Set;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.pl3x.map.core.Pl3xMap;
@@ -35,6 +33,8 @@
import net.pl3x.map.core.renderer.progress.Progress;
import net.pl3x.map.core.renderer.task.RegionProcessor;
import net.pl3x.map.core.world.World;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.minecraft.extras.RichDescription;
import org.jetbrains.annotations.NotNull;
public class StatusCommand extends Pl3xMapCommand {
@@ -45,13 +45,13 @@ public StatusCommand(@NotNull CommandHandler handler) {
@Override
public void register() {
getHandler().registerSubcommand(builder -> builder.literal("status")
- .meta(MinecraftExtrasMetaKeys.DESCRIPTION, Lang.parse(Lang.COMMAND_STATUS_DESCRIPTION))
+ .commandDescription(RichDescription.of(Lang.parse(Lang.COMMAND_STATUS_DESCRIPTION)))
.permission("pl3xmap.command.status")
.handler(this::execute));
}
public void execute(@NotNull CommandContext<@NotNull Sender> context) {
- Sender sender = context.getSender();
+ Sender sender = context.sender();
String lineNext = "├─";
String lineLast = "└─";
diff --git a/core/src/main/java/net/pl3x/map/core/command/commands/StitchCommand.java b/core/src/main/java/net/pl3x/map/core/command/commands/StitchCommand.java
index 6fe584cab..1b2cb1386 100644
--- a/core/src/main/java/net/pl3x/map/core/command/commands/StitchCommand.java
+++ b/core/src/main/java/net/pl3x/map/core/command/commands/StitchCommand.java
@@ -23,8 +23,6 @@
*/
package net.pl3x.map.core.command.commands;
-import cloud.commandframework.context.CommandContext;
-import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
@@ -38,9 +36,9 @@
import net.pl3x.map.core.command.CommandHandler;
import net.pl3x.map.core.command.Pl3xMapCommand;
import net.pl3x.map.core.command.Sender;
-import net.pl3x.map.core.command.argument.RendererArgument;
-import net.pl3x.map.core.command.argument.WorldArgument;
-import net.pl3x.map.core.command.argument.ZoomArgument;
+import net.pl3x.map.core.command.parser.RendererParser;
+import net.pl3x.map.core.command.parser.WorldParser;
+import net.pl3x.map.core.command.parser.ZoomParser;
import net.pl3x.map.core.configuration.Config;
import net.pl3x.map.core.configuration.Lang;
import net.pl3x.map.core.image.io.IO;
@@ -48,6 +46,8 @@
import net.pl3x.map.core.markers.Point;
import net.pl3x.map.core.renderer.Renderer;
import net.pl3x.map.core.world.World;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.minecraft.extras.RichDescription;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -59,10 +59,10 @@ public StitchCommand(@NotNull CommandHandler handler) {
@Override
public void register() {
getHandler().registerSubcommand(builder -> builder.literal("stitch")
- .argument(WorldArgument.of("world"), description(Lang.COMMAND_ARGUMENT_REQUIRED_WORLD_DESCRIPTION))
- .argument(RendererArgument.of("renderer"), description(Lang.COMMAND_ARGUMENT_REQUIRED_RENDERER_DESCRIPTION))
- .argument(ZoomArgument.optional("zoom"), description(Lang.COMMAND_ARGUMENT_OPTIONAL_ZOOM_DESCRIPTION))
- .meta(MinecraftExtrasMetaKeys.DESCRIPTION, Lang.parse(Lang.COMMAND_STITCH_DESCRIPTION))
+ .required("world", WorldParser.parser(), description(Lang.COMMAND_ARGUMENT_REQUIRED_WORLD_DESCRIPTION))
+ .required("renderer", RendererParser.parser(), description(Lang.COMMAND_ARGUMENT_REQUIRED_RENDERER_DESCRIPTION))
+ .optional("zoom", ZoomParser.parser(), description(Lang.COMMAND_ARGUMENT_OPTIONAL_ZOOM_DESCRIPTION))
+ .commandDescription(RichDescription.of(Lang.parse(Lang.COMMAND_STITCH_DESCRIPTION)))
.permission("pl3xmap.command.stitch")
.handler(this::execute));
}
@@ -72,7 +72,7 @@ private void execute(@NotNull CommandContext<@NotNull Sender> context) {
}
private void executeAsync(@NotNull CommandContext<@NotNull Sender> context) {
- Sender sender = context.getSender();
+ Sender sender = context.sender();
World world = context.get("world");
Renderer.Builder renderer = context.get("renderer");
int zoom = context.getOrDefault("zoom", 0);
diff --git a/core/src/main/java/net/pl3x/map/core/command/commands/VersionCommand.java b/core/src/main/java/net/pl3x/map/core/command/commands/VersionCommand.java
index c3db31aa3..75ecc8558 100644
--- a/core/src/main/java/net/pl3x/map/core/command/commands/VersionCommand.java
+++ b/core/src/main/java/net/pl3x/map/core/command/commands/VersionCommand.java
@@ -23,8 +23,6 @@
*/
package net.pl3x.map.core.command.commands;
-import cloud.commandframework.context.CommandContext;
-import cloud.commandframework.minecraft.extras.MinecraftExtrasMetaKeys;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -40,6 +38,8 @@
import net.pl3x.map.core.command.Pl3xMapCommand;
import net.pl3x.map.core.command.Sender;
import net.pl3x.map.core.configuration.Lang;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.minecraft.extras.RichDescription;
import org.jetbrains.annotations.NotNull;
public class VersionCommand extends Pl3xMapCommand {
@@ -56,13 +56,13 @@ public VersionCommand(@NotNull CommandHandler handler) {
@Override
public void register() {
getHandler().registerSubcommand(builder -> builder.literal("version")
- .meta(MinecraftExtrasMetaKeys.DESCRIPTION, Lang.parse(Lang.COMMAND_VERSION_DESCRIPTION))
+ .commandDescription(RichDescription.of(Lang.parse(Lang.COMMAND_VERSION_DESCRIPTION)))
.permission("pl3xmap.command.version")
.handler(this::execute));
}
public void execute(@NotNull CommandContext<@NotNull Sender> context) {
- Sender sender = context.getSender();
+ Sender sender = context.sender();
long now = System.currentTimeMillis();
if (this.lastChecked + TimeUnit.SECONDS.toMillis(15) > now) {
@@ -89,7 +89,7 @@ public void execute(@NotNull CommandContext<@NotNull Sender> context) {
JsonElement elem = JsonParser.parseString(json);
if (elem.isJsonArray()) {
JsonArray arr = elem.getAsJsonArray();
- if (arr.size() > 0) {
+ if (!arr.isEmpty()) {
JsonElement elem1 = arr.get(0);
if (elem1.isJsonObject()) {
JsonObject obj = elem1.getAsJsonObject();
@@ -117,6 +117,12 @@ public void execute(@NotNull CommandContext<@NotNull Sender> context) {
}
private void showVersion(Sender sender) {
+ sender.sendMessage(Lang.COMMAND_VERSION_SUCCESS,
+ Placeholder.unparsed("version", Pl3xMap.api().getVersion()),
+ Placeholder.unparsed("platform", Pl3xMap.api().getPlatform()),
+ Placeholder.unparsed("commit", Pl3xMap.api().getVersionCommit())
+ );
+
if (this.version.startsWith("-")) {
sender.sendMessage(switch (this.version) {
case "-1" -> Lang.COMMAND_VERSION_STILL_CHECKING;
@@ -127,12 +133,6 @@ private void showVersion(Sender sender) {
return;
}
- sender.sendMessage(Lang.COMMAND_VERSION_SUCCESS,
- Placeholder.unparsed("version", Pl3xMap.api().getVersion()),
- Placeholder.unparsed("platform", Pl3xMap.api().getPlatform()),
- Placeholder.unparsed("commit", Pl3xMap.api().getVersionCommit())
- );
-
int cur_build;
int new_build;
diff --git a/core/src/main/java/net/pl3x/map/core/command/parser/PlatformParsers.java b/core/src/main/java/net/pl3x/map/core/command/parser/PlatformParsers.java
new file mode 100644
index 000000000..41d1a4c16
--- /dev/null
+++ b/core/src/main/java/net/pl3x/map/core/command/parser/PlatformParsers.java
@@ -0,0 +1,17 @@
+package net.pl3x.map.core.command.parser;
+
+import net.pl3x.map.core.command.Sender;
+import net.pl3x.map.core.markers.Point;
+import net.pl3x.map.core.player.Player;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.parser.ParserDescriptor;
+
+public interface PlatformParsers {
+ ParserDescriptor columnPosParser();
+
+ Point resolvePointFromColumnPos(String name, CommandContext context);
+
+ ParserDescriptor playerSelectorParser();
+
+ Player resolvePlayerFromPlayerSelector(String name, CommandContext context);
+}
diff --git a/core/src/main/java/net/pl3x/map/core/command/argument/parser/RendererParser.java b/core/src/main/java/net/pl3x/map/core/command/parser/RendererParser.java
similarity index 71%
rename from core/src/main/java/net/pl3x/map/core/command/argument/parser/RendererParser.java
rename to core/src/main/java/net/pl3x/map/core/command/parser/RendererParser.java
index 13f2d5ae6..d2961bda8 100644
--- a/core/src/main/java/net/pl3x/map/core/command/argument/parser/RendererParser.java
+++ b/core/src/main/java/net/pl3x/map/core/command/parser/RendererParser.java
@@ -21,18 +21,20 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-package net.pl3x.map.core.command.argument.parser;
+package net.pl3x.map.core.command.parser;
-import cloud.commandframework.arguments.parser.ArgumentParseResult;
-import cloud.commandframework.arguments.parser.ArgumentParser;
-import cloud.commandframework.context.CommandContext;
-import java.util.List;
-import java.util.Queue;
import java.util.stream.Collectors;
import net.pl3x.map.core.Pl3xMap;
import net.pl3x.map.core.command.exception.RendererParseException;
import net.pl3x.map.core.registry.RendererRegistry;
import net.pl3x.map.core.renderer.Renderer;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.context.CommandInput;
+import org.incendo.cloud.parser.ArgumentParseResult;
+import org.incendo.cloud.parser.ArgumentParser;
+import org.incendo.cloud.parser.ParserDescriptor;
+import org.incendo.cloud.suggestion.BlockingSuggestionProvider;
import org.jetbrains.annotations.NotNull;
/**
@@ -40,10 +42,14 @@
*
* @param command sender type
*/
-public class RendererParser implements ArgumentParser<@NotNull C, Renderer.@NotNull Builder> {
+public class RendererParser implements ArgumentParser<@NotNull C, Renderer.@NotNull Builder>, BlockingSuggestionProvider.Strings {
+ public static ParserDescriptor parser() {
+ return ParserDescriptor.of(new RendererParser<>(), Renderer.Builder.class);
+ }
+
@Override
- public @NotNull ArgumentParseResult parse(@NotNull CommandContext<@NotNull C> context, @NotNull Queue<@NotNull String> queue) {
- String input = queue.peek();
+ public @NotNull ArgumentParseResult parse(@NotNull CommandContext<@NotNull C> commandContext, @NotNull CommandInput commandInput) {
+ String input = commandInput.peekString();
if (input == null) {
return ArgumentParseResult.failure(new RendererParseException(null, RendererParseException.MUST_SPECIFY_RENDERER));
}
@@ -53,12 +59,12 @@ public class RendererParser implements ArgumentParser<@NotNull C, Renderer.@N
return ArgumentParseResult.failure(new RendererParseException(input, RendererParseException.NO_SUCH_RENDERER));
}
- queue.remove();
+ commandInput.readString();
return ArgumentParseResult.success(builder);
}
@Override
- public @NotNull List<@NotNull String> suggestions(@NotNull CommandContext<@NotNull C> commandContext, @NotNull String input) {
+ public @NonNull Iterable<@NonNull String> stringSuggestions(@NonNull CommandContext commandContext, @NonNull CommandInput input) {
return Pl3xMap.api().getRendererRegistry()
.values().stream()
.map(Renderer.Builder::getKey)
diff --git a/core/src/main/java/net/pl3x/map/core/command/argument/parser/WorldParser.java b/core/src/main/java/net/pl3x/map/core/command/parser/WorldParser.java
similarity index 56%
rename from core/src/main/java/net/pl3x/map/core/command/argument/parser/WorldParser.java
rename to core/src/main/java/net/pl3x/map/core/command/parser/WorldParser.java
index 7a2213e3d..2fb97b492 100644
--- a/core/src/main/java/net/pl3x/map/core/command/argument/parser/WorldParser.java
+++ b/core/src/main/java/net/pl3x/map/core/command/parser/WorldParser.java
@@ -21,17 +21,20 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-package net.pl3x.map.core.command.argument.parser;
+package net.pl3x.map.core.command.parser;
-import cloud.commandframework.arguments.parser.ArgumentParseResult;
-import cloud.commandframework.arguments.parser.ArgumentParser;
-import cloud.commandframework.context.CommandContext;
-import java.util.List;
-import java.util.Queue;
import java.util.stream.Collectors;
import net.pl3x.map.core.Pl3xMap;
+import net.pl3x.map.core.command.Sender;
import net.pl3x.map.core.command.exception.WorldParseException;
import net.pl3x.map.core.world.World;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.context.CommandInput;
+import org.incendo.cloud.parser.ArgumentParseResult;
+import org.incendo.cloud.parser.ArgumentParser;
+import org.incendo.cloud.parser.ParserDescriptor;
+import org.incendo.cloud.suggestion.BlockingSuggestionProvider;
import org.jetbrains.annotations.NotNull;
/**
@@ -39,10 +42,14 @@
*
* @param command sender type
*/
-public class WorldParser implements ArgumentParser<@NotNull C, @NotNull World> {
+public class WorldParser implements ArgumentParser<@NotNull C, @NotNull World>, BlockingSuggestionProvider.Strings {
+ public static ParserDescriptor parser() {
+ return ParserDescriptor.of(new WorldParser<>(), World.class);
+ }
+
@Override
- public @NotNull ArgumentParseResult<@NotNull World> parse(@NotNull CommandContext<@NotNull C> context, @NotNull Queue<@NotNull String> queue) {
- String input = queue.peek();
+ public @NonNull ArgumentParseResult<@NonNull @NotNull World> parse(@NonNull CommandContext<@NonNull @NotNull C> commandContext, @NonNull CommandInput commandInput) {
+ String input = commandInput.peekString();
if (input == null) {
return ArgumentParseResult.failure(new WorldParseException(null, WorldParseException.MUST_SPECIFY_WORLD));
}
@@ -61,12 +68,32 @@ public class WorldParser implements ArgumentParser<@NotNull C, @NotNull World
return ArgumentParseResult.failure(new WorldParseException(input, WorldParseException.MAP_NOT_ENABLED));
}
- queue.remove();
+ commandInput.readString();
return ArgumentParseResult.success(world);
}
+ public static @NotNull World resolveWorld(@NotNull CommandContext<@NotNull Sender> context, @NotNull String name) {
+ Sender sender = context.sender();
+ World world = context.getOrDefault(name, null);
+ if (world != null) {
+ return world;
+ }
+ if (sender instanceof Sender.Player> player) {
+ world = player.getWorld();
+ if (world == null) {
+ throw new WorldParseException("unknown", WorldParseException.NO_SUCH_WORLD);
+ }
+ if (!world.isEnabled()) {
+ throw new WorldParseException(world.getName(), WorldParseException.MAP_NOT_ENABLED);
+ } else {
+ return world;
+ }
+ }
+ throw new WorldParseException(null, WorldParseException.MUST_SPECIFY_WORLD);
+ }
+
@Override
- public @NotNull List<@NotNull String> suggestions(@NotNull CommandContext<@NotNull C> commandContext, @NotNull String input) {
+ public @NonNull Iterable<@NonNull String> stringSuggestions(@NonNull CommandContext commandContext, @NonNull CommandInput input) {
return Pl3xMap.api().getWorldRegistry()
.values().stream()
.filter(World::isEnabled)
diff --git a/core/src/main/java/net/pl3x/map/core/command/argument/parser/ZoomParser.java b/core/src/main/java/net/pl3x/map/core/command/parser/ZoomParser.java
similarity index 67%
rename from core/src/main/java/net/pl3x/map/core/command/argument/parser/ZoomParser.java
rename to core/src/main/java/net/pl3x/map/core/command/parser/ZoomParser.java
index 46b500489..53ea651b5 100644
--- a/core/src/main/java/net/pl3x/map/core/command/argument/parser/ZoomParser.java
+++ b/core/src/main/java/net/pl3x/map/core/command/parser/ZoomParser.java
@@ -21,21 +21,22 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-package net.pl3x.map.core.command.argument.parser;
+package net.pl3x.map.core.command.parser;
-import cloud.commandframework.arguments.parser.ArgumentParseResult;
-import cloud.commandframework.arguments.parser.ArgumentParser;
-import cloud.commandframework.arguments.standard.IntegerArgument;
-import cloud.commandframework.context.CommandContext;
-import cloud.commandframework.exceptions.parsing.NoInputProvidedException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
-import java.util.Queue;
import java.util.Set;
import java.util.TreeSet;
import net.pl3x.map.core.command.exception.ZoomParseException;
import net.pl3x.map.core.world.World;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.context.CommandInput;
+import org.incendo.cloud.parser.ArgumentParseResult;
+import org.incendo.cloud.parser.ArgumentParser;
+import org.incendo.cloud.parser.ParserDescriptor;
+import org.incendo.cloud.suggestion.BlockingSuggestionProvider;
import org.jetbrains.annotations.NotNull;
/**
@@ -43,39 +44,43 @@
*
* @param command sender type
*/
-public class ZoomParser implements ArgumentParser {
+public class ZoomParser implements ArgumentParser, BlockingSuggestionProvider.Strings {
+ public static ParserDescriptor parser() {
+ return ParserDescriptor.of(new ZoomParser<>(), Integer.class);
+ }
+
@Override
- public @NotNull ArgumentParseResult parse(@NotNull CommandContext context, @NotNull Queue<@NotNull String> inputQueue) {
- String input = inputQueue.peek();
- if (input == null) {
- return ArgumentParseResult.failure(new NoInputProvidedException(IntegerArgument.IntegerParser.class, context));
- }
+ public @NonNull ArgumentParseResult<@NonNull Integer> parse(@NonNull CommandContext<@NonNull C> commandContext, @NonNull CommandInput commandInput) {
+ String input = commandInput.peekString();
try {
int zoom = Integer.parseInt(input);
- if (zoom < 0 || zoom > getMax(context)) {
+ if (zoom < 0 || zoom > getMax(commandContext)) {
return ArgumentParseResult.failure(new ZoomParseException(input, ZoomParseException.NOT_VALID_ZOOM_LEVEL));
}
- inputQueue.remove();
+ commandInput.readString();
return ArgumentParseResult.success(zoom);
} catch (Exception e) {
return ArgumentParseResult.failure(new ZoomParseException(input, ZoomParseException.NOT_VALID_ZOOM_LEVEL));
}
}
+
@Override
- public @NotNull List<@NotNull String> suggestions(@NotNull CommandContext context, @NotNull String input) {
- Set numbers = new TreeSet<>();
+ public @NonNull Iterable<@NonNull String> stringSuggestions(@NonNull CommandContext commandContext, @NonNull CommandInput input) {
+ final Set numbers = new TreeSet<>();
+ final String token = input.peekString();
+
try {
- long inputNum = Long.parseLong(input.equals("-") ? "-0" : input.isEmpty() ? "0" : input);
- long inputNumAbsolute = Math.abs(inputNum);
+ final long inputNum = Long.parseLong(token.equals("-") ? "-0" : token.isEmpty() ? "0" : token);
+ final long inputNumAbsolute = Math.abs(inputNum);
numbers.add(inputNumAbsolute); /* It's a valid number, so we suggest it */
- int max = getMax(context);
+ int max = getMax(commandContext);
for (int i = 0; i < 10 && (inputNum * 10) + i <= max; i++) {
numbers.add((inputNumAbsolute * 10) + i);
}
List suggestions = new LinkedList<>();
for (long number : numbers) {
- if (input.startsWith("-")) {
+ if (token.startsWith("-")) {
number = -number; /* Preserve sign */
}
if (number < 0 || number > max) {
diff --git a/core/src/main/java/net/pl3x/map/core/configuration/Config.java b/core/src/main/java/net/pl3x/map/core/configuration/Config.java
index a0c4a2cae..348b200ff 100644
--- a/core/src/main/java/net/pl3x/map/core/configuration/Config.java
+++ b/core/src/main/java/net/pl3x/map/core/configuration/Config.java
@@ -118,6 +118,17 @@ How many scroll pixels (as reported by L.DomEvent.getWheelDelta) mean
for security reasons. But you do you, boo boo.""")
public static boolean HTTPD_FOLLOW_SYMLINKS = false;
+ @Key("settings.performance.live-update.enabled")
+ @Comment("""
+ Whether or not the real-time marker system should run.""")
+ public static boolean LIVE_UPDATE_ENABLED = true;
+
+ @Key("settings.performance.live-update.threads")
+ @Comment("""
+ The number of process-threads to use for real-time marker updates on the map.
+ Value of -1 will use 50% of the available cpu-threads. (recommended)""")
+ public static int LIVE_UPDATE_THREADS = -1;
+
@Key("settings.performance.render-threads")
@Comment("""
The number of process-threads to use for loading and scanning chunks.
diff --git a/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java b/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java
index 7ccbdd848..81380d5d9 100644
--- a/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java
+++ b/core/src/main/java/net/pl3x/map/core/configuration/PlayersLayerConfig.java
@@ -44,9 +44,12 @@ public final class PlayersLayerConfig extends AbstractConfig {
@Key("settings.layer.update-interval")
@Comment("""
- How often (in seconds) to update the marker.
- Setting to 0 is the same as setting it to 1.""")
+ How often (in seconds) to update the marker.""")
public static int UPDATE_INTERVAL = 0;
+ @Key("settings.layer.live-update")
+ @Comment("""
+ Whether to push this layer through SSE or not.""")
+ public static boolean LIVE_UPDATE = true;
@Key("settings.layer.show-controls")
@Comment("""
Whether the players layer control shows up in the layers list or not.""")
diff --git a/core/src/main/java/net/pl3x/map/core/configuration/SpawnLayerConfig.java b/core/src/main/java/net/pl3x/map/core/configuration/SpawnLayerConfig.java
index 86c6f7a44..edc56b5b4 100644
--- a/core/src/main/java/net/pl3x/map/core/configuration/SpawnLayerConfig.java
+++ b/core/src/main/java/net/pl3x/map/core/configuration/SpawnLayerConfig.java
@@ -34,9 +34,12 @@ public final class SpawnLayerConfig extends AbstractConfig {
@Key("settings.layer.update-interval")
@Comment("""
- How often (in seconds) to update the marker.
- Setting to 0 is the same as setting it to 1.""")
+ How often (in seconds) to update the marker.""")
public static int UPDATE_INTERVAL = 30;
+ @Key("settings.layer.live-update")
+ @Comment("""
+ Whether to push this layer through SSE or not.""")
+ public static boolean LIVE_UPDATE = true;
@Key("settings.layer.show-controls")
@Comment("""
Whether the spawn layer control shows up in the layers list or not.""")
diff --git a/core/src/main/java/net/pl3x/map/core/configuration/WorldBorderLayerConfig.java b/core/src/main/java/net/pl3x/map/core/configuration/WorldBorderLayerConfig.java
index b7f5c78f0..9fa92e96e 100644
--- a/core/src/main/java/net/pl3x/map/core/configuration/WorldBorderLayerConfig.java
+++ b/core/src/main/java/net/pl3x/map/core/configuration/WorldBorderLayerConfig.java
@@ -35,9 +35,12 @@ public final class WorldBorderLayerConfig extends AbstractConfig {
@Key("settings.layer.update-interval")
@Comment("""
- How often (in seconds) to update the marker.
- Setting to 0 is the same as setting it to 1.""")
+ How often (in seconds) to update the marker.""")
public static int UPDATE_INTERVAL = 30;
+ @Key("settings.layer.live-update")
+ @Comment("""
+ Whether to push this layer through SSE or not.""")
+ public static boolean LIVE_UPDATE = true;
@Key("settings.layer.show-controls")
@Comment("""
Whether the vanilla world border layer control shows up in the layers list or not.""")
diff --git a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java
index 46f022a58..1423a3409 100644
--- a/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java
+++ b/core/src/main/java/net/pl3x/map/core/httpd/HttpdServer.java
@@ -23,26 +23,40 @@
*/
package net.pl3x.map.core.httpd;
+import io.undertow.Handlers;
import io.undertow.Undertow;
import io.undertow.UndertowLogger;
import io.undertow.UndertowOptions;
+import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.resource.PathResourceManager;
import io.undertow.server.handlers.resource.ResourceHandler;
import io.undertow.server.handlers.resource.ResourceManager;
import io.undertow.util.ETag;
import io.undertow.util.Headers;
+import io.undertow.util.HttpString;
+import io.undertow.util.StatusCodes;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
+import java.util.stream.Collectors;
+import net.pl3x.map.core.Pl3xMap;
import net.pl3x.map.core.configuration.Config;
import net.pl3x.map.core.configuration.Lang;
import net.pl3x.map.core.log.LogFilter;
import net.pl3x.map.core.log.Logger;
+import net.pl3x.map.core.registry.WorldRegistry;
import net.pl3x.map.core.util.FileUtil;
+import net.pl3x.map.core.world.World;
public class HttpdServer {
+ private HttpString X_ACCEL_BUFFERING = new HttpString("X-Accel-Buffering");
private Undertow server;
+ private LiveDataHandler liveDataHandler = new LiveDataHandler();
+
+ public LiveDataHandler getLiveDataHandler() {
+ return liveDataHandler;
+ }
public void startServer() {
if (!Config.HTTPD_ENABLED) {
@@ -81,16 +95,48 @@ public void startServer() {
this.server = Undertow.builder()
.setServerOption(UndertowOptions.ENABLE_HTTP2, true)
.addHttpListener(Config.HTTPD_PORT, Config.HTTPD_BIND)
- .setHandler(exchange -> {
- if (exchange.getRelativePath().startsWith("/tiles")) {
- exchange.getResponseHeaders().put(Headers.CACHE_CONTROL, "max-age=0, must-revalidate, no-cache");
- }
- if (exchange.getRelativePath().endsWith(".gz")) {
- exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json");
- exchange.getResponseHeaders().put(Headers.CONTENT_ENCODING, "gzip");
- }
- resourceHandler.handleRequest(exchange);
- })
+ .setHandler(
+ Handlers.path(exchange -> {
+ if (exchange.getRelativePath().startsWith("/tiles")) {
+ exchange.getResponseHeaders().put(Headers.CACHE_CONTROL, "max-age=0, must-revalidate, no-cache");
+ }
+ if (exchange.getRelativePath().endsWith(".gz")) {
+ exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json");
+ exchange.getResponseHeaders().put(Headers.CONTENT_ENCODING, "gzip");
+ }
+ resourceHandler.handleRequest(exchange);
+ })
+ .addPrefixPath("/sse",
+ Handlers.pathTemplate()
+ .add("{world}", exchange -> {
+ String worldName = exchange.getQueryParameters().get("world").peek();
+ if (worldName == null || worldName.isEmpty()) {
+ exchange.getResponseHeaders().put(X_ACCEL_BUFFERING, "no");
+ liveDataHandler.handle(exchange);
+ return;
+ }
+
+ WorldRegistry worldRegistry = Pl3xMap.api().getWorldRegistry();
+ World world = worldRegistry.get(worldName);
+ if (world == null || !world.isEnabled()) {
+ String listOfValidWorlds = worldRegistry.values().stream()
+ .filter(World::isEnabled)
+ .map(World::getName).collect(Collectors.joining(", "));
+ handleError(exchange, "Could not find world named '%s'. Available worlds: %s"
+ .formatted(worldName, listOfValidWorlds));
+ exchange.endExchange();
+ return;
+ }
+
+ if (exchange.isInIoThread()) {
+ exchange.dispatch(world.getServerSentEventHandler().get());
+ } else {
+ exchange.getResponseHeaders().put(X_ACCEL_BUFFERING, "no");
+ world.getServerSentEventHandler().handle(exchange);
+ }
+ })
+ )
+ )
.build();
this.server.start();
LogFilter.HIDE_UNDERTOW_LOGS = false;
@@ -105,6 +151,12 @@ public void startServer() {
}
}
+ private void handleError(HttpServerExchange exchange, String errorMessage) {
+ exchange.setStatusCode(StatusCodes.NOT_FOUND);
+ exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json");
+ exchange.getResponseSender().send("{\"error\": \"" + errorMessage + "\"}");
+ }
+
public void stopServer() {
if (!Config.HTTPD_ENABLED) {
return;
@@ -116,6 +168,10 @@ public void stopServer() {
}
LogFilter.HIDE_UNDERTOW_LOGS = true;
+ this.liveDataHandler.closeConnections();
+ Pl3xMap.api().getWorldRegistry().forEach(world -> {
+ world.getServerSentEventHandler().closeConnections();
+ });
this.server.stop();
LogFilter.HIDE_UNDERTOW_LOGS = false;
diff --git a/core/src/main/java/net/pl3x/map/core/httpd/LiveDataHandler.java b/core/src/main/java/net/pl3x/map/core/httpd/LiveDataHandler.java
new file mode 100644
index 000000000..9130ad52b
--- /dev/null
+++ b/core/src/main/java/net/pl3x/map/core/httpd/LiveDataHandler.java
@@ -0,0 +1,152 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2020-2023 William Blake Galbreath
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package net.pl3x.map.core.httpd;
+
+import io.undertow.Handlers;
+import io.undertow.server.HttpServerExchange;
+import io.undertow.server.handlers.sse.ServerSentEventConnection;
+import io.undertow.server.handlers.sse.ServerSentEventHandler;
+import java.io.IOException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class LiveDataHandler {
+ private ServerSentEventHandler serverSentEventHandler;
+
+ public LiveDataHandler() {
+ this.serverSentEventHandler = Handlers.serverSentEvents();
+ }
+
+ /**
+ *
+ * @param event The message event
+ * @param data The message data
+ * @param success The callback that is called when a message is sucessfully sent.
+ * @param failure The callback that is called when a message send fails.
+ */
+ public void send(String event, String data, SuccessCallback success, FailureCallback failure) {
+ if (serverSentEventHandler == null) {
+ return;
+ }
+
+ Callback callback = new Callback(success, failure);
+ for (ServerSentEventConnection connection : this.serverSentEventHandler.getConnections()) {
+ connection.send(data, event, null, callback);
+ }
+ }
+
+ /**
+ *
+ * @param event The message event
+ * @param data The message data
+ * @param success The callback that is called when a message is sucessfully sent.
+ */
+ public void send(String event, String data, SuccessCallback success) {
+ this.send(event, data, success, null);
+ }
+
+ /**
+ *
+ * @param event The message event
+ * @param data The message data
+ */
+ public void send(String event, String data) {
+ this.send(event, data, null, null);
+ }
+
+ /**
+ *
+ * @param data The message data
+ */
+ public void send(String data) {
+ this.send(null, data);
+ }
+
+ public void closeConnections() {
+ for (ServerSentEventConnection connection : serverSentEventHandler.getConnections()) {
+ connection.shutdown();
+ }
+ }
+
+ public void handle(HttpServerExchange exchange) throws Exception {
+ this.serverSentEventHandler.handleRequest(exchange);
+ }
+
+ public ServerSentEventHandler get() {
+ return this.serverSentEventHandler;
+ }
+
+ /**
+ * Notification that is called when a message is sucessfully sent
+ */
+ @FunctionalInterface
+ public interface SuccessCallback {
+ /**
+ * @param connection The connection
+ * @param data The message data
+ * @param event The message event
+ * @param id The message id
+ */
+ void apply(@NotNull ServerSentEventConnection connection, @Nullable String data, @Nullable String event, @Nullable String id);
+ }
+
+ /**
+ * Notification that is called when a message send fails.
+ */
+ @FunctionalInterface
+ public interface FailureCallback {
+ /**
+ * @param connection The connection
+ * @param data The message data
+ * @param event The message event
+ * @param id The message id
+ * @param exception The exception
+ */
+ void apply(@NotNull ServerSentEventConnection connection, @Nullable String data, @Nullable String event, @Nullable String id, @NotNull IOException exception);
+ }
+
+ private class Callback implements ServerSentEventConnection.EventCallback {
+ private SuccessCallback success;
+ private FailureCallback failure;
+
+ public Callback(SuccessCallback success, FailureCallback failure) {
+ this.success = success;
+ this.failure = failure;
+ }
+
+ @Override
+ public void done(ServerSentEventConnection connection, String data, String event, String id) {
+ if (success != null) {
+ success.apply(connection, data, event, id);
+ }
+ }
+
+ @Override
+ public void failed(ServerSentEventConnection connection, String data, String event, String id, IOException e) {
+ if (failure != null) {
+ failure.apply(connection, data, event, id, e);
+ }
+ }
+ }
+}
diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java
index b5f07c09b..3925fe1c4 100644
--- a/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java
+++ b/core/src/main/java/net/pl3x/map/core/markers/layer/Layer.java
@@ -32,6 +32,7 @@
import net.pl3x.map.core.markers.JsonSerializable;
import net.pl3x.map.core.markers.marker.Marker;
import net.pl3x.map.core.util.Preconditions;
+import net.pl3x.map.core.util.TickUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -41,13 +42,14 @@
@SuppressWarnings("UnusedReturnValue")
public abstract class Layer extends Keyed implements JsonSerializable {
private Supplier<@NotNull String> labelSupplier;
- private int updateInterval = 15;
+ private int updateInterval = TickUtil.toTicks(15);
private boolean showControls = true;
private boolean defaultHidden = false;
private int priority = 99;
private Integer zIndex = 99;
private String pane;
private String css;
+ private boolean liveUpdate = false;
/**
* Create a layer.
@@ -98,7 +100,17 @@ public Layer(@NotNull String key, @NotNull Supplier<@NotNull String> labelSuppli
* @return update interval
*/
public int getUpdateInterval() {
- return this.updateInterval;
+ return this.getUpdateInterval(false);
+ }
+
+ /**
+ * Get this layer's update interval (in seconds or in ticks).
+ *
+ * @param ticks set to true to get update interval as ticks instead of seconds
+ * @return update interval
+ */
+ public int getUpdateInterval(boolean ticks) {
+ return ticks ? this.updateInterval : (int) TickUtil.toSeconds(this.updateInterval);
}
/**
@@ -108,7 +120,19 @@ public int getUpdateInterval() {
* @return this layer
*/
public @NotNull Layer setUpdateInterval(int updateInterval) {
- this.updateInterval = updateInterval;
+ this.setUpdateInterval(updateInterval, false);
+ return this;
+ }
+
+ /**
+ * Set this layer's update interval (in seconds or in ticks).
+ *
+ * @param updateInterval new update interval
+ * @param ticks set to true to treat the interval value as ticks instead of seconds
+ * @return this layer
+ */
+ public @NotNull Layer setUpdateInterval(int updateInterval, boolean ticks) {
+ this.updateInterval = ticks ? updateInterval : TickUtil.toTicks(updateInterval);
return this;
}
@@ -246,6 +270,26 @@ public int getPriority() {
return this;
}
+ /**
+ * Get if this layer gets pushed through sse.
+ *
+ * @return true if being sent through sse
+ */
+ public @Nullable boolean isLiveUpdate() {
+ return this.liveUpdate;
+ }
+
+ /**
+ * Set whether to push this layer through sse.
+ *
+ * @param liveUpdate true to push this layer through sse.
+ * @return this layer
+ */
+ public @NotNull Layer setLiveUpdate(@Nullable boolean liveUpdate) {
+ this.liveUpdate = liveUpdate;
+ return this;
+ }
+
/**
* Get the markers to display in this Layer.
*
diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java
index bf01e7e30..c4ca32573 100644
--- a/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java
+++ b/core/src/main/java/net/pl3x/map/core/markers/layer/PlayersLayer.java
@@ -60,6 +60,7 @@ public class PlayersLayer extends WorldLayer {
public PlayersLayer(@NotNull World world) {
this(KEY, world, () -> Lang.UI_LAYER_PLAYERS);
setUpdateInterval(PlayersLayerConfig.UPDATE_INTERVAL);
+ setLiveUpdate(PlayersLayerConfig.LIVE_UPDATE);
setShowControls(PlayersLayerConfig.SHOW_CONTROLS);
setDefaultHidden(PlayersLayerConfig.DEFAULT_HIDDEN);
setPriority(PlayersLayerConfig.PRIORITY);
diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java
index 2114e589a..e27635a0c 100644
--- a/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java
+++ b/core/src/main/java/net/pl3x/map/core/markers/layer/SpawnLayer.java
@@ -66,6 +66,7 @@ public SpawnLayer(@NotNull World world) {
}
setUpdateInterval(SpawnLayerConfig.UPDATE_INTERVAL);
+ setLiveUpdate(SpawnLayerConfig.LIVE_UPDATE);
setShowControls(SpawnLayerConfig.SHOW_CONTROLS);
setDefaultHidden(SpawnLayerConfig.DEFAULT_HIDDEN);
setPriority(SpawnLayerConfig.PRIORITY);
diff --git a/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java b/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java
index 33d8e97bd..753d27818 100644
--- a/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java
+++ b/core/src/main/java/net/pl3x/map/core/markers/layer/WorldBorderLayer.java
@@ -53,6 +53,7 @@ public class WorldBorderLayer extends WorldLayer {
public WorldBorderLayer(@NotNull World world) {
this(KEY, world, () -> Lang.UI_LAYER_WORLDBORDER);
setUpdateInterval(WorldBorderLayerConfig.UPDATE_INTERVAL);
+ setLiveUpdate(WorldBorderLayerConfig.LIVE_UPDATE);
setShowControls(WorldBorderLayerConfig.SHOW_CONTROLS);
setDefaultHidden(WorldBorderLayerConfig.DEFAULT_HIDDEN);
setPriority(WorldBorderLayerConfig.PRIORITY);
diff --git a/core/src/main/java/net/pl3x/map/core/network/Network.java b/core/src/main/java/net/pl3x/map/core/network/Network.java
index 5f943de4c..c6bb92eea 100644
--- a/core/src/main/java/net/pl3x/map/core/network/Network.java
+++ b/core/src/main/java/net/pl3x/map/core/network/Network.java
@@ -35,17 +35,7 @@ public abstract class Network {
public abstract void unregister();
- public void sendServerData(T player) {
- ByteArrayDataOutput out = out();
-
- out.writeInt(Constants.PROTOCOL);
- out.writeInt(Constants.SERVER_DATA);
- out.writeInt(Constants.RESPONSE_SUCCESS);
-
- out.writeUTF(Config.WEB_ADDRESS);
-
- send(player, out);
- }
+ protected abstract void sendServerData(T player);
protected abstract void sendMapData(T player, int id);
diff --git a/core/src/main/java/net/pl3x/map/core/player/PlayerRegistry.java b/core/src/main/java/net/pl3x/map/core/player/PlayerRegistry.java
index 820ec23a1..7a8b032ca 100644
--- a/core/src/main/java/net/pl3x/map/core/player/PlayerRegistry.java
+++ b/core/src/main/java/net/pl3x/map/core/player/PlayerRegistry.java
@@ -23,10 +23,17 @@
*/
package net.pl3x.map.core.player;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Supplier;
+import net.pl3x.map.core.Pl3xMap;
+import net.pl3x.map.core.configuration.PlayersLayerConfig;
import net.pl3x.map.core.registry.Registry;
import net.pl3x.map.core.util.Preconditions;
import org.jetbrains.annotations.NotNull;
@@ -89,4 +96,34 @@ public class PlayerRegistry extends Registry<@NotNull Player> {
Player player = get(uuid);
return player == null ? Optional.empty() : Optional.of(player);
}
+
+ public @NotNull List<@NotNull Object> parsePlayers() {
+ if (!PlayersLayerConfig.ENABLED) {
+ return Collections.emptyList();
+ }
+ List