diff --git a/.idea/misc.xml b/.idea/misc.xml
index 03872dd..ecb0c83 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index d949516..c4b14e8 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,12 +5,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -97,15 +144,24 @@
-
+
+
+
+
+
+
+
+
+
+
{
"customColor": "",
"associatedIndex": 0
@@ -124,22 +180,29 @@
"Gradle.core [build].executor": "Run",
"Gradle.core [clean].executor": "Run",
"Gradle.core [publishAllPublicationsToScrowRepository].executor": "Run",
+ "Gradle.core [publishCoreLibPublicationToScrowRepository].executor": "Run",
"Gradle.core:core-bukkit-api [build].executor": "Run",
"Gradle.core:core-bukkit-api [clean].executor": "Run",
+ "Gradle.core:core-lib [publishAllPublicationsToScrowRepository].executor": "Run",
+ "Gradle.core:core-lib [publishCoreLibPublicationToMavenLocal].executor": "Run",
+ "Gradle.core:core-lib [publishCoreLibPublicationToScrowRepository].executor": "Run",
"ModuleVcsDetector.initialDetectionPerformed": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
"RunOnceActivity.git.unshallow": "true",
"git-widget-placeholder": "master",
"kotlin-language-version-configured": "true",
- "last_opened_file_path": "/home/a/src/scrow/core/settings.gradle.kts",
- "project.structure.last.edited": "Modules",
+ "last_opened_file_path": "/home/a/src/scrow",
+ "project.structure.last.edited": "Project",
"project.structure.proportion": "0.15",
"project.structure.side.proportion": "0.6268199",
- "settings.editor.selected.configurable": "editor.preferences.smartKeys"
+ "settings.editor.selected.configurable": "preferences.pluginManager"
}
}]]>
+
+
+
@@ -183,7 +246,7 @@
-
+
@@ -200,10 +263,10 @@
false
-
+
-
+
@@ -222,10 +285,10 @@
false
-
+
-
+
@@ -233,7 +296,7 @@
-
+
@@ -244,10 +307,10 @@
false
-
+
-
+
@@ -255,7 +318,7 @@
-
+
@@ -280,10 +343,10 @@
-
-
-
+
+
+
@@ -311,11 +374,20 @@
1782673270039
-
+
+
+ 1782675674934
+
+
+
+ 1782675674934
+
+
-
+
+
\ No newline at end of file
diff --git a/core-bukkit-api/build.gradle.kts b/core-bukkit-api/build.gradle.kts
index b20cc6b..2c66d03 100644
--- a/core-bukkit-api/build.gradle.kts
+++ b/core-bukkit-api/build.gradle.kts
@@ -4,29 +4,29 @@ plugins {
id("de.kentoj.scrow.scrow-repository")
id("de.kentoj.scrow.base-dependencies")
id("de.kentoj.scrow.java-library")
+ id("de.kentoj.scrow.reactor")
}
group = "de.kentoj.scrow"
repositories {
mavenCentral()
-
- maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") {
- name = "spigotmc-repo"
+ maven("https://repo.papermc.io/repository/maven-public/") {
+ name = "papermc"
}
}
dependencies {
api(project(":core-lib"))
- api("org.spigotmc:spigot-api:1.21.11-R0.1-SNAPSHOT")
+ api("io.papermc.paper:paper-api:1.21.11-rc3-R0.1-SNAPSHOT")
// https://mvnrepository.com/artifact/io.nats/jnats
api("io.nats:jnats:2.25.2")
// http://forge.kentoj.de/scrow/-/packages/maven/de.kentoj.scrow:kencommandapi-core
- api("de.kentoj.scrow:kencommandapi-core:0.9")
+ api("de.kentoj.scrow:kencommandapi-core:0.21")
// http://forge.kentoj.de/scrow/-/packages/maven/de.kentoj.scrow:kencommandapi-bukkit
- api("de.kentoj.scrow:kencommandapi-bukkit:0.9")
+ api("de.kentoj.scrow:kencommandapi-bukkit:0.21")
}
publishing {
diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/PlayerManager.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/PlayerManager.java
new file mode 100644
index 0000000..e19c90c
--- /dev/null
+++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/PlayerManager.java
@@ -0,0 +1,10 @@
+package de.kentoj.scrow.bukkit;
+
+import com.leakyabstractions.result.api.Result;
+
+import java.util.UUID;
+
+public interface PlayerManager {
+
+ Result sendPlayer(UUID uuid, String instanceHandle);
+}
diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/ScrowAPI.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/ScrowAPI.java
index 775f6fd..c1d70b0 100644
--- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/ScrowAPI.java
+++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/ScrowAPI.java
@@ -1,11 +1,11 @@
package de.kentoj.scrow.bukkit;
-import de.kentoj.kencommandapi.BukkitKenCommandApi;
+import de.kentoj.kencommandapi.CommandAPI;
import de.kentoj.scrow.bukkit.friends.FriendRequestService;
import de.kentoj.scrow.bukkit.friends.FriendshipService;
import de.kentoj.scrow.bukkit.region.RegionManager;
import de.kentoj.scrowlib.connection.DatabaseConnectionFactory;
-import de.kentoj.scrowlib.servermanager.ServerManager;
+import de.kentoj.scrowlib.servermanager.InstanceManager;
import io.nats.client.Connection;
import lombok.AccessLevel;
import lombok.Getter;
@@ -30,11 +30,13 @@ public class ScrowAPI {
@Getter
private static Connection nats;
@Getter
- private static ServerManager serverManager;
+ private static InstanceManager instanceManager;
@Getter
private static RegionManager regionManager;
@Getter
- private static final BukkitKenCommandApi commandApi = new BukkitKenCommandApi();
+ private static CommandAPI commandApi;
+ @Getter
+ private static PlayerManager playerManager;
@ApiStatus.Internal
public static void setEconomyService(EconomyService economyService) {
@@ -62,8 +64,8 @@ public class ScrowAPI {
}
@ApiStatus.Internal
- public static void setServerManager(ServerManager serverManager) {
- ScrowAPI.serverManager = serverManager;
+ public static void setInstanceManager(InstanceManager instanceManager) {
+ ScrowAPI.instanceManager = instanceManager;
}
@ApiStatus.Internal
@@ -75,5 +77,15 @@ public class ScrowAPI {
public static void setRegionManager(RegionManager regionManager) {
ScrowAPI.regionManager = regionManager;
}
+
+ @ApiStatus.Internal
+ public static void setCommandApi(CommandAPI commandApi) {
+ ScrowAPI.commandApi = commandApi;
+ }
+
+ @ApiStatus.Internal
+ public static void setPlayerManager(PlayerManager playerManager) {
+ ScrowAPI.playerManager = playerManager;
+ }
}
diff --git a/core-bukkit-impl/build.gradle.kts b/core-bukkit-impl/build.gradle.kts
index a20e7e9..2bbf523 100644
--- a/core-bukkit-impl/build.gradle.kts
+++ b/core-bukkit-impl/build.gradle.kts
@@ -5,6 +5,7 @@ plugins {
id("de.kentoj.scrow.scrow-repository")
id("de.kentoj.scrow.base-dependencies")
id("de.kentoj.scrow.database")
+ id("de.kentoj.scrow.reactor")
}
group = "de.kentoj.scrow"
@@ -12,14 +13,17 @@ group = "de.kentoj.scrow"
repositories {
mavenCentral()
- maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") {
- name = "spigotmc-repo"
+ maven("https://repo.papermc.io/repository/maven-public/") {
+ name = "papermc"
}
}
dependencies {
implementation(project(":core-bukkit-api"))
+ // http://forge.kentoj.de/scrow/-/packages/maven/de.kentoj.scrow:kencommandapi-core
+ implementation("de.kentoj.scrow:kencommandapi-core:0.21")
+
// TODO remove, we use postgres now
// https://www.mongodb.com/docs/languages/java/reactive-streams-driver/current/get-started/download-and-install/
implementation(platform("org.mongodb:mongodb-driver-bom:5.6.1"))
diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/CoreImplPlugin.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/CoreImplPlugin.java
index be88436..f7fd99f 100644
--- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/CoreImplPlugin.java
+++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/CoreImplPlugin.java
@@ -10,6 +10,13 @@ import de.kentoj.scrow.bukkit.server.PlayCommand;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+
public class CoreImplPlugin extends JavaPlugin {
public static boolean ENABLE_DATABASE = false;
@@ -32,8 +39,13 @@ public class CoreImplPlugin extends JavaPlugin {
}
private void registerServer() {
- ScrowAPI.getServerManager().setState(System.getenv("SERVER_HANDLE"), "UP")
- .subscribe(__ -> Bukkit.getLogger().info("registered self"));
+ var opts = new OpenOption[]{StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE, StandardOpenOption.WRITE};
+ try (var file = FileChannel.open(Path.of("/proc/self/fd/3"), opts)) {
+ //noinspection ResultOfMethodCallIgnored
+ file.write(ByteBuffer.wrap(new byte[]{'\n'}));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
@Override
diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/ScrowAPISurface.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/ScrowAPISurface.java
index fc35278..97acb0e 100644
--- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/ScrowAPISurface.java
+++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/ScrowAPISurface.java
@@ -1,6 +1,6 @@
package de.kentoj.scrow.bukkit;
-import de.kentoj.kencommandapi.BukkitKenCommandApi;
+import de.kentoj.kencommandapi.CommandAPI;
import de.kentoj.scrow.bukkit.economy.InMemoryEconomyService;
import de.kentoj.scrow.bukkit.economy.PostgresEconomyService;
import de.kentoj.scrow.bukkit.friends.friendship.InMemoryFriendshipService;
@@ -9,7 +9,8 @@ import de.kentoj.scrow.bukkit.friends.request.InMemoryFriendRequestService;
import de.kentoj.scrow.bukkit.friends.request.PostgresFriendRequestService;
import de.kentoj.scrow.bukkit.region.RegionManagerImpl;
import de.kentoj.scrowlib.connection.DatabaseConnectionFactoryImpl;
-import de.kentoj.scrowlib.servermanager.ServerManagerImpl;
+import de.kentoj.scrowlib.servermanager.InstanceManagerImpl;
+import de.kentoj.scrowlib.utils.EnvUtils;
import io.nats.client.Nats;
import io.nats.client.Options;
import io.r2dbc.spi.ConnectionFactories;
@@ -31,7 +32,7 @@ public class ScrowAPISurface {
}));
try {
- String natsHost = System.getenv("HOST_NATS");
+ String natsHost = EnvUtils.envOrThrow("HOST_NATS");
var options = Options.builder()
.server(natsHost)
.pedantic()
@@ -42,12 +43,13 @@ public class ScrowAPISurface {
}
if (enableDatabase) {
- ConnectionFactory factory = ConnectionFactories.get(System.getenv("HOST_POSTGRES"));
+ ConnectionFactory factory = ConnectionFactories.get(EnvUtils.envOrThrow("HOST_POSTGRES"));
ScrowAPI.setDbConFactory(new DatabaseConnectionFactoryImpl(factory));
}
ScrowAPI.setRegionManager(new RegionManagerImpl());
- ScrowAPI.setServerManager(new ServerManagerImpl(ScrowAPI.getNats()));
+ ScrowAPI.setCommandApi(new CommandAPI(plugin));
+ ScrowAPI.setInstanceManager(new InstanceManagerImpl(ScrowAPI.getNats()));
ScrowAPI.setEconomyService(ScrowAPI.getDbConFactory() != null ?
new PostgresEconomyService(ScrowAPI.getDbConFactory()) : new InMemoryEconomyService());
ScrowAPI.setFriendRequestService(ScrowAPI.getDbConFactory() != null ?
diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownCommand.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownCommand.java
index d958c35..f94001f 100644
--- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownCommand.java
+++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownCommand.java
@@ -1,20 +1,23 @@
package de.kentoj.scrow.bukkit.crown;
-import de.kentoj.kencommandapi.BukkitCommandContext;
-import de.kentoj.kencommandapi.api.nodes.CommandNode;
-import de.kentoj.scrow.bukkit.ScrowAPI;
+import de.kentoj.kencommandapi.api.node.CommandNode;
+import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import lombok.Getter;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.command.CommandSender;
public class CrownCommand {
@Getter
- private final CommandNode rootNode;
+ private final CommandNode rootNode;
public CrownCommand() {
- this.rootNode = ScrowAPI.getCommandApi().createNode("crown", "server-manager");
- this.rootNode.addLiteral(new CrownListServersLiteral().getRootNode());
- this.rootNode.addLiteral(new CrownDeployServerLiteral().getRootNode());
- this.rootNode.addLiteral(new CrownDestroyServerLiteral().getRootNode());
+ this.rootNode = CommandNode.node("crown", "server-manager");
+ var style = new ScrowMessageStyle(Component.text("crown")
+ .color(NamedTextColor.GOLD));
+ this.rootNode.addLiteral(new CrownListServersLiteral(style).getNode());
+ this.rootNode.addLiteral(new CrownDeployServerLiteral(style).getRootNode());
+ this.rootNode.addLiteral(new CrownDestroyServerLiteral(style).getRootNode());
}
}
diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownDeployServerLiteral.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownDeployServerLiteral.java
index 7c3fcb5..d51ea5b 100644
--- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownDeployServerLiteral.java
+++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownDeployServerLiteral.java
@@ -1,35 +1,40 @@
package de.kentoj.scrow.bukkit.crown;
-import de.kentoj.kencommandapi.BukkitCommandContext;
+import de.kentoj.kencommandapi.api.node.CommandNode;
import de.kentoj.kencommandapi.api.argument.CommandArgument;
-import de.kentoj.kencommandapi.api.nodes.CommandNode;
-import de.kentoj.kencommandapi.api.processing.CommandExecutor;
-import de.kentoj.kencommandapi.api.types.StringArgumentType;
+import de.kentoj.kencommandapi.api.argument.types.StringArgumentType;
+import de.kentoj.kencommandapi.api.invocation.CommandContext;
+import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
+import com.leakyabstractions.result.api.Result;
import de.kentoj.scrow.bukkit.ScrowAPI;
import lombok.Getter;
import org.bukkit.command.CommandSender;
-public class CrownDeployServerLiteral implements CommandExecutor {
+import java.util.concurrent.CompletableFuture;
+
+public class CrownDeployServerLiteral implements CommandExecutor {
@Getter
- private final CommandNode rootNode;
- private final CommandArgument templateArg;
+ private final CommandNode rootNode;
+ private final CommandArgument templateArg;
public CrownDeployServerLiteral() {
- this.rootNode = ScrowAPI.getCommandApi().createNode("deploy-server");
+ this.rootNode = CommandNode.node("deploy-server");
this.rootNode.setExecutor(this);
{
- this.templateArg = ScrowAPI.getCommandApi().createArgument("template", new StringArgumentType<>());
+ this.templateArg = CommandArgument.arg("template", new StringArgumentType<>());
this.rootNode.addArgument(templateArg);
}
}
@Override
- public void execute(BukkitCommandContext ctx) {
+ public CompletableFuture> execute(CommandContext ctx) {
var template = ctx.getArg(templateArg);
- ScrowAPI.getServerManager().deployServer(template)
- .subscribe(server ->
- ctx.getSender().sendMessage("Deployed instance of " + template + " with handle " + server.getHandle())
- );
+ return ScrowAPI.getInstanceManager().deployInstance(template)
+ .map(server -> {
+ ctx.getSender().sendMessage("Deployed instance of " + template + " with handle " + server.getHandle());
+ // FIXME handle unknown server
+ return Result.success();
+ }).toFuture();
}
}
diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownDestroyServerLiteral.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownDestroyServerLiteral.java
index f3f520d..3c634da 100644
--- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownDestroyServerLiteral.java
+++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownDestroyServerLiteral.java
@@ -1,31 +1,34 @@
package de.kentoj.scrow.bukkit.crown;
-import de.kentoj.kencommandapi.BukkitCommandContext;
+import de.kentoj.kencommandapi.api.node.CommandNode;
import de.kentoj.kencommandapi.api.argument.CommandArgument;
-import de.kentoj.kencommandapi.api.nodes.CommandNode;
-import de.kentoj.kencommandapi.api.processing.CommandExecutor;
-import de.kentoj.kencommandapi.api.types.StringArgumentType;
+import de.kentoj.kencommandapi.api.argument.types.StringArgumentType;
+import de.kentoj.kencommandapi.api.invocation.CommandContext;
+import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
+import com.leakyabstractions.result.api.Result;
+import com.leakyabstractions.result.api.Results;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrowlib.servermanager.ServerInstance;
import lombok.Getter;
import org.bukkit.command.CommandSender;
+import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
-public class CrownDestroyServerLiteral implements CommandExecutor {
+public class CrownDestroyServerLiteral implements CommandExecutor {
@Getter
- private final CommandNode rootNode;
- private final CommandArgument handleArg;
+ private final CommandNode rootNode;
+ private final CommandArgument handleArg;
public CrownDestroyServerLiteral() {
- this.rootNode = ScrowAPI.getCommandApi().createNode("destroy-server");
+ this.rootNode = CommandNode.node("destroy-server");
this.rootNode.setExecutor(this);
{
- this.handleArg = ScrowAPI.getCommandApi().createArgument("template", new StringArgumentType<>());
+ this.handleArg = CommandArgument.arg("template", new StringArgumentType<>());
this.handleArg.setSuggestionProvider(ctx -> {
//noinspection CodeBlock2Expr
- return ScrowAPI.getServerManager().getRunningServers()
+ return ScrowAPI.getInstanceManager().getInstances()
.map(ServerInstance::getHandle)
.collect(Collectors.toSet())
.toFuture();
@@ -35,11 +38,12 @@ public class CrownDestroyServerLiteral implements CommandExecutor> execute(CommandContext ctx) {
var handle = ctx.getArg(handleArg);
- ScrowAPI.getServerManager().destroyServer(handle)
- .subscribe(__ ->
- ctx.getSender().sendMessage("Destroyed server with handle " + handle)
- );
+ return ScrowAPI.getInstanceManager().destroyInstance(handle)
+ .map(__ -> {
+ ctx.getSender().sendMessage("Destroyed server with handle " + handle);
+ return Result.success();
+ }).toFuture();
}
}
diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownListServersLiteral.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownListServersLiteral.java
index cae17c3..aca4f2b 100644
--- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownListServersLiteral.java
+++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/crown/CrownListServersLiteral.java
@@ -1,35 +1,41 @@
package de.kentoj.scrow.bukkit.crown;
-import de.kentoj.kencommandapi.BukkitCommandContext;
-import de.kentoj.kencommandapi.api.nodes.CommandNode;
-import de.kentoj.kencommandapi.api.processing.CommandExecutor;
+import de.kentoj.kencommandapi.api.invocation.CommandContext;
+import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
+import com.leakyabstractions.result.api.Result;
+import de.kentoj.kencommandapi.api.node.CommandNode;
import de.kentoj.scrow.bukkit.ScrowAPI;
+import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import lombok.Getter;
+import net.kyori.adventure.text.Component;
import org.bukkit.command.CommandSender;
-public class CrownListServersLiteral implements CommandExecutor {
+import java.util.concurrent.CompletableFuture;
+
+public class CrownListServersLiteral implements CommandExecutor {
@Getter
- private final CommandNode rootNode;
+ private final CommandNode node;
+ private final ScrowMessageStyle style;
- public CrownListServersLiteral() {
- this.rootNode = ScrowAPI.getCommandApi().createNode("list-servers");
- this.rootNode.setExecutor(this);
+ public CrownListServersLiteral(ScrowMessageStyle style) {
+ this.style = style;
+ this.node = CommandNode.node("list-servers");
+ this.node.setExecutor(this);
}
@Override
- public void execute(BukkitCommandContext ctx) {
- ScrowAPI.getServerManager().getRunningServers()
- .reduce(new StringBuilder("\n"), (acc, cur) -> acc.append("> ")
- .append(cur.getHandle())
- .append(" on port ")
- .append(cur.getPort())
- .append(": ")
- .append(cur.getState())
- .append('\n')
+ public CompletableFuture> execute(CommandContext ctx) {
+ return ScrowAPI.getInstanceManager().getInstances()
+ .collectList()
+ .map(list -> style.list(Component.text("Running instances:"),
+ list.stream()
+ .map(inst ->
+ Component.text(inst.getHandle() + " on port " + inst.getPort() + ": " + inst.getState())
+ )
+ .toList())
)
- .subscribe(msg ->
- ctx.getPlayerSender().sendMessage(msg.toString())
- );
+ .doOnNext(ctx.getSender()::sendMessage)
+ .thenReturn(Result.success()).toFuture();
}
}
diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/CoinsCommand.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/CoinsCommand.java
index 83e5520..4b3466c 100644
--- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/CoinsCommand.java
+++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/economy/CoinsCommand.java
@@ -1,9 +1,13 @@
package de.kentoj.scrow.bukkit.economy;
-import de.kentoj.kencommandapi.BukkitCommandContext;
+import com.leakyabstractions.result.api.Result;
+import com.leakyabstractions.result.core.Results;
+import de.kentoj.kencommandapi.api.node.CommandNode;
import de.kentoj.kencommandapi.api.argument.CommandArgument;
-import de.kentoj.kencommandapi.api.nodes.CommandNode;
-import de.kentoj.kencommandapi.api.types.IntegerArgumentType;
+import de.kentoj.kencommandapi.api.argument.types.IntegerArgumentType;
+import de.kentoj.kencommandapi.api.invocation.CommandContext;
+import com.leakyabstractions.result.api.Result;
+import com.leakyabstractions.result.api.Results;
import de.kentoj.kencommandapi.type.OfflinePlayerArgumentType;
import de.kentoj.scrow.bukkit.ScrowAPI;
import lombok.Getter;
@@ -12,67 +16,63 @@ import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import reactor.core.scheduler.Schedulers;
+import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
public class CoinsCommand {
@Getter
- private final CommandNode rootNode;
- private final CommandArgument playerArg;
- private final CommandArgument amountArg;
+ private final CommandNode rootNode;
+ private final CommandArgument playerArg;
+ private final CommandArgument amountArg;
public CoinsCommand() {
- this.rootNode = ScrowAPI.getCommandApi().createNode("coins", "eco");
- this.playerArg = ScrowAPI.getCommandApi().createArgument("player", OfflinePlayerArgumentType.getInstance());
- this.amountArg = ScrowAPI.getCommandApi().createArgument("amount", new IntegerArgumentType<>());
+ this.rootNode = CommandNode.node("coins", "eco");
+ this.playerArg = CommandArgument.arg("player", OfflinePlayerArgumentType.getInstance());
+ this.amountArg = CommandArgument.arg("amount", new IntegerArgumentType<>());
{
- var setLiteral = ScrowAPI.getCommandApi().createNode("set");
+ CommandNode setLiteral = CommandNode.node("set");
rootNode.addLiteral(setLiteral);
setLiteral.addArgument(playerArg);
setLiteral.addArgument(amountArg);
setLiteral.setExecutor(this::setCoins);
}
{
- var getLiteral = ScrowAPI.getCommandApi().createNode("get");
+ CommandNode getLiteral = CommandNode.node("get");
rootNode.addLiteral(getLiteral);
getLiteral.addArgument(playerArg);
getLiteral.setExecutor(this::getCoins);
}
}
- private void getCoins(BukkitCommandContext ctx) {
+ private CompletableFuture> getCoins(CommandContext ctx) {
var player = ctx.getArg(playerArg);
-
- ScrowAPI.getEconomyService()
+ return ScrowAPI.getEconomyService()
.getCoins(player.getUniqueId())
.subscribeOn(Schedulers.boundedElastic())
.publishOn(ScrowAPI.getMinecraftScheduler())
- .subscribe(amount -> {
+ .map(amount -> {
if (player == ctx.getSender()) {
ctx.getSender().sendMessage("You have " + amount + "$");
} else {
ctx.getSender().sendMessage(player.getName() + " has " + amount + "$");
}
- }, err -> {
- ctx.getSender().sendMessage("Unable to get coins: " + err.getMessage());
- Bukkit.getLogger().log(Level.SEVERE, "Unable to get coins of " + player.getUniqueId(), err);
- });
+ return Result.success();
+ }).toFuture();
}
- private void setCoins(BukkitCommandContext ctx) {
+ private CompletableFuture> setCoins(CommandContext ctx) {
var player = ctx.getArg(playerArg);
var amount = ctx.getArg(amountArg);
- ScrowAPI.getEconomyService()
+ return ScrowAPI.getEconomyService()
.setCoins(player.getUniqueId(), amount)
.subscribeOn(Schedulers.boundedElastic())
.publishOn(ScrowAPI.getMinecraftScheduler())
- .subscribe(__ -> {
+ .map(__ -> {
ctx.getSender().sendMessage(player.getName() + " now has " + amount + "$");
- }, err -> {
- ctx.getSender().sendMessage("Unable to set coins: " + err.getMessage());
- Bukkit.getLogger().log(Level.SEVERE, "Unable to set coins of " + player.getUniqueId() + " to " + amount, err);
- });
+ return Results.success(null);
+ }).toFuture();
}
}
diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendAddLiteral.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendAddLiteral.java
index d28a752..9036ccb 100644
--- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendAddLiteral.java
+++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendAddLiteral.java
@@ -1,33 +1,107 @@
package de.kentoj.scrow.bukkit.friends.command;
-import de.kentoj.kencommandapi.BukkitCommandContext;
+import de.kentoj.kencommandapi.api.node.CommandNode;
import de.kentoj.kencommandapi.api.argument.CommandArgument;
-import de.kentoj.kencommandapi.api.nodes.CommandNode;
-import de.kentoj.kencommandapi.api.processing.CommandExecutor;
+import de.kentoj.kencommandapi.api.invocation.CommandContext;
+import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
+import com.leakyabstractions.result.api.Result;
+import com.leakyabstractions.result.api.Results;
import de.kentoj.kencommandapi.type.OfflinePlayerArgumentType;
import de.kentoj.scrow.bukkit.ScrowAPI;
-import de.kentoj.scrow.bukkit.friends.handler.FriendAddHandler;
+import de.kentoj.scrow.bukkit.friends.friendship.FriendshipImpl;
+import de.kentoj.scrow.bukkit.friends.request.FriendRequestImpl;
import lombok.Getter;
+import lombok.RequiredArgsConstructor;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import reactor.core.publisher.Mono;
-public class FriendAddLiteral implements CommandExecutor {
+import java.time.Instant;
+import java.util.concurrent.CompletableFuture;
+
+@RequiredArgsConstructor
+public class FriendAddLiteral implements CommandExecutor {
@Getter
- private final CommandNode rootNode;
- private final CommandArgument playerArg;
+ private final CommandNode rootNode;
+ private final CommandArgument playerArg;
public FriendAddLiteral() {
- var cmds = ScrowAPI.getCommandApi();
- playerArg = cmds.createArgument("player", OfflinePlayerArgumentType.getInstance());
- rootNode = cmds.createNode("add");
+ playerArg = CommandArgument.arg("player", OfflinePlayerArgumentType.getInstance());
+ rootNode = CommandNode.node("add");
rootNode.addArgument(playerArg);
rootNode.setExecutor(this);
}
@Override
- public void execute(BukkitCommandContext ctx) {
- var handler = new FriendAddHandler(ctx.getPlayerSender(), ctx.getArg(playerArg));
- handler.handle();
+ public CompletableFuture> execute(CommandContext ctx) {
+ var self = (Player) ctx.getSender();
+ var other = ctx.getArg(playerArg);
+ return findAction(self, other)
+ .flatMap(action -> executeAction(self, other, action))
+ .toFuture();
+ }
+
+ private Mono<@NotNull Result> executeAction(Player self, OfflinePlayer other, AddAction action) {
+ return switch (action) {
+ case ERR_CAN_NOT_ADD_SELF -> Mono.just(Result.error("You can not add yourself"));
+ case ERR_ALREADY_FRIENDS -> Mono.just(Result.error("You are already friends with " + other.getName()));
+ case ERR_ALREADY_REQUESTED ->
+ Mono.just(Result.error("You already requested " + other.getName() + " to be friends with you"));
+ case SEND_REQUEST -> sendRequest(self, other);
+ case ACCEPT_REQUEST -> acceptRequest(self, other);
+ };
+ }
+
+ private Mono<@NotNull Result> sendRequest(Player self, OfflinePlayer other) {
+ return ScrowAPI.getFriendRequestService().saveFriendRequest(new FriendRequestImpl(self.getUniqueId(), other.getUniqueId(), Instant.now()))
+ .map(success -> {
+ if (!success) return Result.error("You already sent " + other.getName() + " a friend request");
+
+ self.sendMessage("Successfully sent " + other.getName() + " a friend request.");
+ var otherPlayer = other.getPlayer();
+ if (otherPlayer != null)
+ otherPlayer.sendMessage(" wants to be friends with you. Use '/f add " + self.getName() + "' to accept.");
+ return Result.success();
+ });
+ }
+
+ private Mono<@NotNull Result> acceptRequest(Player self, OfflinePlayer other) {
+ return Mono.when(
+ ScrowAPI.getFriendRequestService().deleteFriendRequest(self.getUniqueId(), other.getUniqueId()),
+ ScrowAPI.getFriendRequestService().deleteFriendRequest(other.getUniqueId(), self.getUniqueId()),
+ ScrowAPI.getFriendshipService().saveFriendship(new FriendshipImpl(self.getUniqueId(), other.getUniqueId(), Instant.now()))
+ )
+ .doOnNext(__ -> {
+ self.sendMessage("You are now friends with " + other.getName());
+ if (other.getPlayer() != null)
+ other.getPlayer().sendMessage("You are now friends with " + self.getName());
+ })
+ .then(Mono.just(Result.success()));
+ }
+
+ private Mono<@NotNull AddAction> findAction(Player self, OfflinePlayer other) {
+ if (self.getUniqueId() == other.getUniqueId()) return Mono.just(AddAction.ERR_CAN_NOT_ADD_SELF);
+ return ScrowAPI.getFriendshipService().getFriendship(self.getUniqueId(), other.getUniqueId())
+ .map(f -> AddAction.ERR_ALREADY_FRIENDS)
+ .switchIfEmpty(
+ ScrowAPI.getFriendRequestService().getFriendRequest(self.getUniqueId(), other.getUniqueId())
+ .map(r -> AddAction.ERR_ALREADY_REQUESTED)
+ .switchIfEmpty(
+ ScrowAPI.getFriendRequestService().getFriendRequest(other.getUniqueId(), self.getUniqueId())
+ .map(r -> AddAction.ACCEPT_REQUEST)
+ .switchIfEmpty(Mono.just(AddAction.SEND_REQUEST))
+ )
+ );
+ }
+
+ private enum AddAction {
+ ERR_ALREADY_FRIENDS,
+ ERR_ALREADY_REQUESTED,
+ ERR_CAN_NOT_ADD_SELF,
+ SEND_REQUEST,
+ ACCEPT_REQUEST
}
}
diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendCommand.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendCommand.java
index d92378b..a7fcc40 100644
--- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendCommand.java
+++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendCommand.java
@@ -1,21 +1,25 @@
package de.kentoj.scrow.bukkit.friends.command;
-import de.kentoj.kencommandapi.BukkitCommandContext;
-import de.kentoj.kencommandapi.api.nodes.CommandNode;
-import de.kentoj.scrow.bukkit.ScrowAPI;
+import de.kentoj.kencommandapi.api.node.CommandNode;
+import de.kentoj.kencommandapi.api.node.RootCommandNode;
+import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import lombok.Getter;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.command.CommandSender;
public class FriendCommand {
@Getter
- private final CommandNode rootNode;
+ private final RootCommandNode rootNode;
public FriendCommand() {
- this.rootNode = ScrowAPI.getCommandApi().createNode("friends", "f", "friend");
- rootNode.addLiteral(new FriendListLiteral().getRootNode());
- rootNode.addLiteral(new FriendAddLiteral().getRootNode());
- rootNode.addLiteral(new FriendRemoveLiteral().getRootNode());
- rootNode.addLiteral(new FriendRequestsLiteral().getRootNode());
+ var style = new ScrowMessageStyle(Component.text("Friends")
+ .color(NamedTextColor.GREEN));
+ this.rootNode = CommandNode.rootNode(style, "f", "friend");
+ rootNode.addLiteral(new FriendListLiteral(style).getRootNode());
+ rootNode.addLiteral(new FriendAddLiteral(style).getRootNode());
+ rootNode.addLiteral(new FriendRemoveLiteral(style).getRootNode());
+ rootNode.addLiteral(new FriendRequestsLiteral(style).getRootNode());
}
}
diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendListLiteral.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendListLiteral.java
index e487dc8..172b891 100644
--- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendListLiteral.java
+++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendListLiteral.java
@@ -1,36 +1,51 @@
package de.kentoj.scrow.bukkit.friends.command;
-import de.kentoj.kencommandapi.BukkitCommandContext;
-import de.kentoj.kencommandapi.api.nodes.CommandNode;
+import de.kentoj.kencommandapi.api.invocation.CommandContext;
+import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
+import com.leakyabstractions.result.api.Result;
+import com.leakyabstractions.result.api.Results;
+import de.kentoj.kencommandapi.api.node.CommandNode;
import de.kentoj.scrow.bukkit.ScrowAPI;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
-public class FriendListLiteral {
+import java.util.concurrent.CompletableFuture;
+
+public class FriendListLiteral implements CommandExecutor {
@Getter
- private final CommandNode rootNode;
+ private final CommandNode rootNode;
public FriendListLiteral() {
- this.rootNode = ScrowAPI.getCommandApi().createNode("list");
- rootNode.setExecutor(this::friendList);
+ this.rootNode = CommandNode.node("list");
+ rootNode.setExecutor(this);
}
- private void friendList(BukkitCommandContext ctx) {
- var ownUid = ctx.getPlayerSender().getUniqueId();
- ctx.getPlayerSender().sendMessage("friends:");
- ScrowAPI.getFriendshipService().getFriendships(ownUid)
+ @Override
+ public CompletableFuture> execute(CommandContext ctx) {
+ var sender = (Player) ctx.getSender();
+ var ownUid = sender.getUniqueId();
+ return ScrowAPI.getFriendshipService().getFriendships(ownUid)
.map(friendship -> Bukkit.getOfflinePlayer(friendship.getUuids().getOther(ownUid)))
.sort(this::compareByOnlineStatus)
- .map(friendPlayer -> {
- var onlineStatus = friendPlayer.isOnline() ? "§aonline" : "offline";
- return "- " + friendPlayer.getName() + ": " + onlineStatus;
- })
- .doOnNext(line -> ctx.getSender().sendMessage(line))
- .doOnComplete(() -> ctx.getSender().sendMessage("EOF"))
- .subscribe();
+ .collectList()
+ .map(list -> {
+ if (list.isEmpty()) return Result.error("You have no friends. Use /friend add ");
+
+ var msg = "§3§lFriends§r§7 ☆ You have §3" + list.size() + "§7 friend";
+ if (list.size() > 1) msg += "s";
+ msg += ":§r\n";
+ for (var friend : list) {
+ var status = friend.isOnline() ? "(§aonline§7)" : "(offline)";
+ msg += "§c≫ §7" + friend.getName() + " " + status + "\n";
+ }
+
+ sender.sendMessage(msg);
+ return Result.success();
+ }).toFuture();
}
private int compareByOnlineStatus(OfflinePlayer p1, OfflinePlayer p2) {
diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendRemoveLiteral.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendRemoveLiteral.java
index dad9e52..0fa8cbf 100644
--- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendRemoveLiteral.java
+++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendRemoveLiteral.java
@@ -1,34 +1,42 @@
package de.kentoj.scrow.bukkit.friends.command;
-import de.kentoj.kencommandapi.BukkitCommandContext;
+import de.kentoj.kencommandapi.api.node.CommandNode;
import de.kentoj.kencommandapi.api.argument.CommandArgument;
-import de.kentoj.kencommandapi.api.nodes.CommandNode;
+import de.kentoj.kencommandapi.api.invocation.CommandContext;
+import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
+import com.leakyabstractions.result.api.Result;
+import com.leakyabstractions.result.api.Results;
import de.kentoj.kencommandapi.type.OfflinePlayerArgumentType;
import de.kentoj.scrow.bukkit.ScrowAPI;
import lombok.Getter;
import org.bukkit.OfflinePlayer;
-import org.bukkit.command.CommandException;
import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
-public class FriendRemoveLiteral {
+import java.util.concurrent.CompletableFuture;
+
+public class FriendRemoveLiteral implements CommandExecutor {
@Getter
- private final CommandNode rootNode;
- private final CommandArgument playerArg;
+ private final CommandNode rootNode;
+ private final CommandArgument playerArg;
public FriendRemoveLiteral() {
- this.playerArg = ScrowAPI.getCommandApi().createArgument("player", OfflinePlayerArgumentType.getInstance());
- this.rootNode = ScrowAPI.getCommandApi().createNode("remove");
+ this.playerArg = CommandArgument.arg("player", OfflinePlayerArgumentType.getInstance());
+ this.rootNode = CommandNode.node("remove");
this.rootNode.addArgument(playerArg);
- this.rootNode.setExecutor(this::removeFriend);
+ this.rootNode.setExecutor(this);
}
- private void removeFriend(BukkitCommandContext ctx) {
+ @Override
+ public CompletableFuture> execute(CommandContext ctx) {
var friend = ctx.getArg(playerArg);
-
- ScrowAPI.getFriendshipService().deleteFriendship(friend.getUniqueId(), ctx.getPlayerSender().getUniqueId())
- .subscribe(wasDeleted -> {
- if (wasDeleted) throw new CommandException("You were not friends with " + friend.getName() + " in the first place");
- ctx.getSender().sendMessage("You are no longer friends with " + friend.getName());
- });
+ var player = (Player) ctx.getSender();
+ return ScrowAPI.getFriendshipService().deleteFriendship(friend.getUniqueId(), player.getUniqueId())
+ .map(wasAdded -> wasAdded
+ ? Result.success() : Result.error("You are not friends with " + friend.getName())
+ ).doOnNext(success -> {
+ if (success.isSuccess())
+ ctx.getSender().sendMessage("You are no longer friends with " + friend.getName());
+ }).toFuture();
}
}
diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendRequestsLiteral.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendRequestsLiteral.java
index 9d2efe2..769d731 100644
--- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendRequestsLiteral.java
+++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/command/FriendRequestsLiteral.java
@@ -1,32 +1,45 @@
package de.kentoj.scrow.bukkit.friends.command;
-import de.kentoj.kencommandapi.BukkitCommandContext;
-import de.kentoj.kencommandapi.api.nodes.CommandNode;
+import de.kentoj.kencommandapi.api.node.CommandNode;
+import de.kentoj.kencommandapi.api.invocation.CommandContext;
+import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
+import com.leakyabstractions.result.api.Result;
+import com.leakyabstractions.result.api.Results;
import de.kentoj.scrow.bukkit.ScrowAPI;
+import de.kentoj.scrow.bukkit.friends.FriendRequest;
import lombok.Getter;
-import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
-public class FriendRequestsLiteral {
+import java.util.concurrent.CompletableFuture;
+
+public class FriendRequestsLiteral implements CommandExecutor {
@Getter
- private final CommandNode rootNode;
+ private final CommandNode rootNode;
public FriendRequestsLiteral() {
- this.rootNode = ScrowAPI.getCommandApi().createNode("requests", "list-requests");
- rootNode.setExecutor(this::friendRequestsList);
+ this.rootNode = CommandNode.node("requests", "list-requests");
+ rootNode.setExecutor(this);
}
- private void friendRequestsList(BukkitCommandContext ctx) {
- var ownUid = ctx.getPlayerSender().getUniqueId();
- ctx.getPlayerSender().sendMessage("incoming friends requests:");
- ScrowAPI.getFriendRequestService().getFriendRequestsTo(ownUid)
- .map(friendRequest -> {
- var fromUid = friendRequest.getFrom();
- var fromName = Bukkit.getOfflinePlayer(fromUid).getName();
- return "- " + fromName;
- }).doOnNext(line -> ctx.getPlayerSender().sendMessage(line))
- .doOnComplete(() -> ctx.getPlayerSender().sendMessage("EOF"))
- .subscribe();
+ @Override
+ public CompletableFuture> execute(CommandContext ctx) {
+ var sender = (Player) ctx.getSender();
+ return ScrowAPI.getFriendRequestService().getFriendRequestsTo(sender.getUniqueId())
+ .collectList()
+ .map(list -> {
+ if (list.isEmpty()) return Result.error("You have no friend requests");
+
+ var msg = "§3§lFriends§r§7 ☆ You have §3" + list.size() + "§7 open friend request";
+ if (list.size() > 1) msg += "s";
+ msg += ":§r\n";
+ for (FriendRequest friendRequest : list) {
+ msg += "§c≫ §7" + friendRequest.getFrom() + "\n";
+ }
+
+ sender.sendMessage(msg);
+ return Result.success();
+ }).toFuture();
}
}
diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/friendship/InMemoryFriendshipService.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/friendship/InMemoryFriendshipService.java
index 6a260f7..600fd6a 100644
--- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/friendship/InMemoryFriendshipService.java
+++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/friendship/InMemoryFriendshipService.java
@@ -17,7 +17,7 @@ public class InMemoryFriendshipService implements FriendshipService {
@Override
public Mono<@NotNull Friendship> getFriendship(UUID uuid1, UUID uuid2) {
- return Mono.just(friendships.get(new OrderedUUIDPair(uuid1, uuid2)));
+ return Mono.justOrEmpty(friendships.get(new OrderedUUIDPair(uuid1, uuid2)));
}
@Override
diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/handler/FriendAddHandler.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/handler/FriendAddHandler.java
deleted file mode 100644
index ecfcbe1..0000000
--- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/friends/handler/FriendAddHandler.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package de.kentoj.scrow.bukkit.friends.handler;
-
-import de.kentoj.kencommandapi.api.processing.CommandException;
-import de.kentoj.scrow.bukkit.ScrowAPI;
-import de.kentoj.scrow.bukkit.friends.friendship.FriendshipImpl;
-import de.kentoj.scrow.bukkit.friends.request.FriendRequestImpl;
-import lombok.RequiredArgsConstructor;
-import org.bukkit.OfflinePlayer;
-import org.bukkit.entity.Player;
-import org.jetbrains.annotations.NotNull;
-import reactor.core.publisher.Mono;
-
-import java.time.Instant;
-
-@RequiredArgsConstructor
-public class FriendAddHandler {
-
- private final Player self;
- private final OfflinePlayer other;
-
- public void handle() {
- findAction()
- .flatMap(this::executeAction)
- .doOnError(CommandException.class, e -> {
- ScrowAPI.getCommandApi().sendErrorMessage(self, e);
- })
- .onErrorComplete(CommandException.class)
- .subscribe();
- }
-
- private Mono> executeAction(AddAction action) {
- return switch (action) {
- case ERR_CAN_NOT_ADD_SELF -> throw new CommandException("You can not add yourself");
- case ERR_ALREADY_FRIENDS -> throw new CommandException("You are already friends with " + other.getName());
- case ERR_ALREADY_REQUESTED ->
- throw new CommandException("You already requested " + other.getName() + " to be friends with you");
- case SEND_REQUEST -> sendRequest();
- case ACCEPT_REQUEST -> acceptRequest();
- };
- }
-
- private Mono> sendRequest() {
- return ScrowAPI.getFriendRequestService().saveFriendRequest(new FriendRequestImpl(self.getUniqueId(), other.getUniqueId(), Instant.now()))
- .flatMap(success -> {
- if (success) {
- sendMessage(self.getPlayer(), "Successfully sent " + other.getName() + " a friend request.");
- return Mono.just(true);
- } else {
- sendMessage(self.getPlayer(), "You already sent " + other.getName() + " a friend request");
- return Mono.just(Mono.empty());
- }
- })
- .doOnNext(success -> {
- var otherPlayer = other.getPlayer();
- if (otherPlayer != null)
- sendMessage(otherPlayer, self.getName() + " wants to be friends with you. Use '/f add " + self.getName() + "' to accept.").subscribe();
- })
- .doOnError(this::handleError);
-
- }
-
- private Mono> acceptRequest() {
- return Mono.when(
- ScrowAPI.getFriendRequestService().deleteFriendRequest(self.getUniqueId(), other.getUniqueId()),
- ScrowAPI.getFriendRequestService().deleteFriendRequest(other.getUniqueId(), self.getUniqueId()),
- ScrowAPI.getFriendshipService().saveFriendship(new FriendshipImpl(self.getUniqueId(), other.getUniqueId(), Instant.now()))
- )
- .then(sendMessage(self, "You are now friends with " + other.getName()))
- .then(Mono.fromRunnable(() -> {
- var otherPlayer = other.getPlayer();
- if (otherPlayer != null)
- sendMessage(otherPlayer, "You are now friends with " + self.getName()).subscribe();
- }))
- .doOnError(this::handleError);
- }
-
- private Mono<@NotNull AddAction> findAction() {
- if (self.getUniqueId() == other.getUniqueId()) return Mono.just(AddAction.ERR_CAN_NOT_ADD_SELF);
- return ScrowAPI.getFriendshipService().getFriendship(self.getUniqueId(), other.getUniqueId())
- .map(f -> AddAction.ERR_ALREADY_FRIENDS)
- .switchIfEmpty(
- ScrowAPI.getFriendRequestService().getFriendRequest(self.getUniqueId(), other.getUniqueId())
- .map(r -> AddAction.ERR_ALREADY_REQUESTED)
- .switchIfEmpty(
- ScrowAPI.getFriendRequestService().getFriendRequest(other.getUniqueId(), self.getUniqueId())
- .map(r -> AddAction.ACCEPT_REQUEST)
- .switchIfEmpty(Mono.just(AddAction.SEND_REQUEST))
- )
- );
- }
-
- private Mono> sendMessage(Player player, String msg) {
- return Mono.fromRunnable(() -> player.sendMessage(msg))
- .subscribeOn(ScrowAPI.getMinecraftScheduler());
- }
-
- private void handleError(Throwable e) {
- sendMessage(self.getPlayer(), "FAILED SENDING REQUEST. REPORT THIS BUG. " + e.getMessage()).subscribe();
- }
-
- private enum AddAction {
- ERR_ALREADY_FRIENDS,
- ERR_ALREADY_REQUESTED,
- ERR_CAN_NOT_ADD_SELF,
- SEND_REQUEST,
- ACCEPT_REQUEST
- }
-}
diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/playermanager/PlayerManagerImpl.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/playermanager/PlayerManagerImpl.java
new file mode 100644
index 0000000..0238f2f
--- /dev/null
+++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/playermanager/PlayerManagerImpl.java
@@ -0,0 +1,23 @@
+package de.kentoj.scrow.bukkit.playermanager;
+
+import com.leakyabstractions.result.api.Result;
+import de.kentoj.scrow.bukkit.PlayerManager;
+import de.kentoj.scrowlib.messaging.MessageBroker;
+import lombok.RequiredArgsConstructor;
+import org.bson.Document;
+
+import java.util.UUID;
+
+@RequiredArgsConstructor
+public class PlayerManagerImpl implements PlayerManager {
+
+ private final MessageBroker messageBroker;
+
+ @Override
+ public Result sendPlayer(UUID playerId, String instanceHandle) {
+ return messageBroker.request("players.send", new Document()
+ .append("playerId", playerId)
+ .append("handle", instanceHandle))
+ .mapSuccess(__ -> null);
+ }
+}
diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/server/LobbyCommand.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/server/LobbyCommand.java
index 4ddbac2..c3513f9 100644
--- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/server/LobbyCommand.java
+++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/server/LobbyCommand.java
@@ -1,26 +1,29 @@
package de.kentoj.scrow.bukkit.server;
-import de.kentoj.kencommandapi.BukkitCommandContext;
-import de.kentoj.kencommandapi.api.nodes.CommandNode;
-import de.kentoj.kencommandapi.api.processing.CommandExecutor;
-import de.kentoj.scrow.bukkit.ScrowAPI;
+import com.leakyabstractions.result.api.Result;
+import com.leakyabstractions.result.core.Results;
+import de.kentoj.kencommandapi.api.node.CommandNode;
+import de.kentoj.kencommandapi.api.invocation.CommandContext;
+import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
-public class LobbyCommand implements CommandExecutor {
+import java.util.concurrent.CompletableFuture;
+
+public class LobbyCommand implements CommandExecutor {
@Getter
- private final CommandNode rootNode;
+ private final CommandNode rootNode;
public LobbyCommand() {
- var cmds = ScrowAPI.getCommandApi();
- this.rootNode = cmds.createNode("lobby", "l", "hub");
+ this.rootNode = CommandNode.node("lobby", "l", "hub");
this.rootNode.setExecutor(this);
}
@Override
- public void execute(BukkitCommandContext ctx) {
+ public CompletableFuture> execute(CommandContext ctx) {
Bukkit.dispatchCommand(ctx.getSender(), "play lobby");
+ return CompletableFuture.completedFuture(Results.success(null));
}
}
diff --git a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/server/PlayCommand.java b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/server/PlayCommand.java
index 87f4171..ec2482c 100644
--- a/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/server/PlayCommand.java
+++ b/core-bukkit-impl/src/main/java/de/kentoj/scrow/bukkit/server/PlayCommand.java
@@ -1,43 +1,44 @@
package de.kentoj.scrow.bukkit.server;
-import de.kentoj.kencommandapi.BukkitCommandContext;
+import com.leakyabstractions.result.api.Result;
+import com.leakyabstractions.result.core.Results;
import de.kentoj.kencommandapi.api.argument.CommandArgument;
-import de.kentoj.kencommandapi.api.nodes.CommandNode;
-import de.kentoj.kencommandapi.api.processing.CommandExecutor;
-import de.kentoj.kencommandapi.api.types.StringArgumentType;
+import de.kentoj.kencommandapi.api.argument.types.StringArgumentType;
+import de.kentoj.kencommandapi.api.invocation.CommandContext;
+import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
+import de.kentoj.kencommandapi.api.node.CommandNode;
import de.kentoj.scrow.bukkit.ScrowAPI;
-import de.kentoj.scrowlib.servermanager.ServerInstance;
import lombok.Getter;
import org.bukkit.command.CommandSender;
-import reactor.core.publisher.Mono;
+import org.bukkit.entity.Player;
-public class PlayCommand implements CommandExecutor {
+import java.util.concurrent.CompletableFuture;
+
+public class PlayCommand implements CommandExecutor {
@Getter
- private final CommandNode rootNode;
- private final CommandArgument gamemodeArg;
+ private final CommandNode rootNode;
+ private final CommandArgument gamemodeArg;
public PlayCommand() {
- this.rootNode = ScrowAPI.getCommandApi().createNode("play", "queue");
- this.gamemodeArg = ScrowAPI.getCommandApi().createArgument("gamemode", new StringArgumentType<>());
+ this.rootNode = CommandNode.node("play", "queue");
+ this.gamemodeArg = CommandArgument.arg("gamemode", new StringArgumentType<>());
this.rootNode.addArgument(this.gamemodeArg);
this.rootNode.setExecutor(this);
}
@Override
- public void execute(BukkitCommandContext ctx) {
+ public CompletableFuture> execute(CommandContext ctx) {
var gamemode = ctx.getArg(gamemodeArg);
- ScrowAPI.getServerManager().getRunningServers()
- .filter(inst -> inst.getTemplateName().equals(gamemode))
- .filter(inst -> inst.getState().equals("UP"))
- .next()
- .switchIfEmpty(Mono.error(new IllegalStateException("No instance available")))
- .map(ServerInstance::getHandle)
- .flatMap(handle ->
- ScrowAPI.getServerManager().sendPlayer(ctx.getPlayerSender().getUniqueId(), handle)
- )
- .subscribe(null, ex -> {
- ctx.getPlayerSender().sendMessage("failed sending you to an instance of " + gamemode + ": " + ex.getMessage());
- });
+ var player = (Player) ctx.getSender();
+ return CompletableFuture.supplyAsync(() -> ScrowAPI.getInstanceManager().getInstances()
+ .flatMapSuccess(instances -> {
+ var instance = instances.stream()
+ .filter(inst -> inst.getTemplate().equals(gamemode))
+ .findFirst()
+ .orElse(null);
+ if (instance == null) return Results.failure("No instance available");
+ return ScrowAPI.getPlayerManager().sendPlayer(player.getUniqueId(), instance.getHandle());
+ }));
}
}
diff --git a/core-lib/build.gradle.kts b/core-lib/build.gradle.kts
index 2952630..9aed3e7 100644
--- a/core-lib/build.gradle.kts
+++ b/core-lib/build.gradle.kts
@@ -21,6 +21,9 @@ dependencies {
// https://mvnrepository.com/artifact/org.mongodb/bson
implementation("org.mongodb:bson:5.8.0")
api("org.mongodb:bson:5.8.0")
+
+ // http://forge.kentoj.de/scrow/-/packages/maven/de.kentoj.scrow:kencommandapi-core
+ api("de.kentoj.scrow:kencommandapi-core:0.21")
}
publishing {
diff --git a/core-lib/src/main/java/de/kentoj/scrowlib/convention/ScrowMessageStyle.java b/core-lib/src/main/java/de/kentoj/scrowlib/convention/ScrowMessageStyle.java
new file mode 100644
index 0000000..31a5261
--- /dev/null
+++ b/core-lib/src/main/java/de/kentoj/scrowlib/convention/ScrowMessageStyle.java
@@ -0,0 +1,57 @@
+package de.kentoj.scrowlib.convention;
+
+import de.kentoj.kencommandapi.api.platform.MessageStyle;
+import lombok.Getter;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.format.TextColor;
+import net.kyori.adventure.text.format.TextDecoration;
+
+import java.util.List;
+
+public class ScrowMessageStyle implements MessageStyle {
+
+ @Getter
+ private final Component prefix;
+ @Getter
+ private final String prefixText;
+ @Getter
+ private final TextColor prefixColor;
+
+ public ScrowMessageStyle(String prefixText, TextColor prefixColor) {
+ this.prefixText = prefixText;
+ this.prefixColor = prefixColor;
+ this.prefix = Component.text(prefixText)
+ .color(prefixColor)
+ .decorate(TextDecoration.BOLD);
+ }
+
+ @Override
+ public Component ok(Component msg) {
+ return prefix.append(Component.text(" ☆ ").color(NamedTextColor.GRAY))
+ .append(msg.colorIfAbsent(NamedTextColor.GRAY));
+ }
+
+ public Component list(Component header, List extends Component> list) {
+ var res = ok(header);
+ for (Component component : list) {
+ res = res.appendNewline()
+ .append(Component.text(" - ").color(NamedTextColor.GRAY))
+ .append(component.colorIfAbsent(NamedTextColor.GRAY));
+ }
+ return res;
+ }
+
+ @Override
+ public Component err(Component msg) {
+ return ok(msg.color(NamedTextColor.RED));
+ }
+
+ @Override
+ public Component exception(Component msg) {
+ return ok(Component.text("ERROR: ")
+ .color(NamedTextColor.DARK_RED)
+ .append(msg)
+ .decorate(TextDecoration.BOLD));
+ }
+}
diff --git a/core-lib/src/main/java/de/kentoj/scrowlib/messaging/MessageBroker.java b/core-lib/src/main/java/de/kentoj/scrowlib/messaging/MessageBroker.java
new file mode 100644
index 0000000..72a8458
--- /dev/null
+++ b/core-lib/src/main/java/de/kentoj/scrowlib/messaging/MessageBroker.java
@@ -0,0 +1,46 @@
+package de.kentoj.scrowlib.messaging;
+
+import com.leakyabstractions.result.api.Result;
+import io.nats.client.Connection;
+import io.nats.client.Dispatcher;
+import lombok.extern.slf4j.Slf4j;
+import org.bson.Document;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+@Slf4j
+public class MessageBroker {
+
+ private final ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
+ private final Connection nats;
+ protected final Dispatcher dispatcher;
+
+ public MessageBroker(Connection nats) {
+ this.nats = nats;
+ this.dispatcher = nats.createDispatcher();
+
+ }
+
+ public void publish(String subject, Result result) {
+ nats.publish(subject, ResultRepository.toBytes(result));
+ }
+
+ public void handle(String subject, RequestHandler handler) {
+ dispatcher.subscribe(subject, msg -> {
+ if (msg.getReplyTo() == null) {
+ log.warn("request in {} has replyTo unset; ignoring", subject);
+ return;
+ }
+ handler.handle(DocumentRepository.fromMessage(msg))
+ .thenAccept(result ->
+ executor.submit(() -> publish(msg.getReplyTo(), result))
+ );
+ });
+ }
+
+ public Result request(String subject, Document document) {
+ var response = nats.request(subject, DocumentRepository.toBytes(document)).join();
+ return ResultRepository.fromDocument(DocumentRepository.fromMessage(response));
+ }
+}
diff --git a/core-lib/src/main/java/de/kentoj/scrowlib/messaging/NatsRepository.java b/core-lib/src/main/java/de/kentoj/scrowlib/messaging/NatsRepository.java
deleted file mode 100644
index 8e8ba0b..0000000
--- a/core-lib/src/main/java/de/kentoj/scrowlib/messaging/NatsRepository.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package de.kentoj.scrowlib.messaging;
-
-import de.kentoj.scrowlib.messaging.respose.SafeResult;
-import io.nats.client.Connection;
-import io.nats.client.Dispatcher;
-import io.nats.client.Message;
-import org.bson.Document;
-import org.jetbrains.annotations.NotNull;
-import reactor.core.Disposable;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-public class NatsRepository {
-
- private final Connection nats;
-
- private final Dispatcher dispatcher;
-
- public NatsRepository(Connection nats) {
- this.nats = nats;
- this.dispatcher = nats.createDispatcher();
- }
-
- public Mono<@NotNull Void> publishSafeResult(String subject, SafeResult safeResult) {
- return this.publish(subject, safeResult.toDocument());
- }
-
- public Mono<@NotNull Void> publish(String subject, Document document) {
- return publishRaw(subject, DocumentRepository.toBytes(document));
- }
-
- public Mono<@NotNull Void> publishRaw(String subject, byte[] data) {
- return Mono.fromRunnable(() -> nats.publish(subject, data));
- }
-
- public Flux<@NotNull SubscriptionContext> subscribe(String subject) {
- return Flux.create(sink -> {
- dispatcher.subscribe(subject, msg -> {
- try {
- sink.next(new SubscriptionContext(msg));
- } catch (Throwable e) {
- sink.error(e);
- }
- });
- });
- }
-
- public Mono<@NotNull Message> requestRaw(String subject, Document document) {
- return Mono.fromFuture(nats.request(subject, DocumentRepository.toBytes(document)));
- }
-
- public Mono<@NotNull Message> requestRaw(String subject, byte[] data) {
- return Mono.fromFuture(nats.request(subject, data));
- }
-}
diff --git a/core-lib/src/main/java/de/kentoj/scrowlib/messaging/RequestHandler.java b/core-lib/src/main/java/de/kentoj/scrowlib/messaging/RequestHandler.java
new file mode 100644
index 0000000..2efef74
--- /dev/null
+++ b/core-lib/src/main/java/de/kentoj/scrowlib/messaging/RequestHandler.java
@@ -0,0 +1,16 @@
+package de.kentoj.scrowlib.messaging;
+
+import com.leakyabstractions.result.api.Result;
+import org.bson.Document;
+
+import java.util.concurrent.CompletionStage;
+
+@FunctionalInterface
+public interface RequestHandler {
+ /**
+ * Processes a request and replies
+ *
+ * @return result to send back to the requesting client.
+ */
+ CompletionStage> handle(Document request);
+}
diff --git a/core-lib/src/main/java/de/kentoj/scrowlib/messaging/ResultRepository.java b/core-lib/src/main/java/de/kentoj/scrowlib/messaging/ResultRepository.java
new file mode 100644
index 0000000..3faa12f
--- /dev/null
+++ b/core-lib/src/main/java/de/kentoj/scrowlib/messaging/ResultRepository.java
@@ -0,0 +1,26 @@
+package de.kentoj.scrowlib.messaging;
+
+import com.leakyabstractions.result.api.Result;
+import com.leakyabstractions.result.core.Results;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.bson.Document;
+
+
+@NoArgsConstructor(access = AccessLevel.NONE)
+public class ResultRepository {
+
+ public static byte[] toBytes(Result result) {
+ var doc = result.hasSuccess()
+ ? new Document("data", result.getSuccess().orElseThrow())
+ : new Document("error", result.getFailure().orElseThrow());
+ return DocumentRepository.toBytes(doc);
+ }
+
+ public static Result fromDocument(Document doc) {
+ var error = doc.getString("error");
+ return error != null
+ ? Results.failure(error)
+ : Results.success(doc.get("data", Document.class));
+ }
+}
diff --git a/core-lib/src/main/java/de/kentoj/scrowlib/messaging/SubscriptionContext.java b/core-lib/src/main/java/de/kentoj/scrowlib/messaging/SubscriptionContext.java
deleted file mode 100644
index 7d00f05..0000000
--- a/core-lib/src/main/java/de/kentoj/scrowlib/messaging/SubscriptionContext.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package de.kentoj.scrowlib.messaging;
-
-import io.nats.client.Message;
-import lombok.AllArgsConstructor;
-import lombok.Value;
-import org.bson.Document;
-
-@Value
-@AllArgsConstructor
-public class SubscriptionContext {
- Message msg;
- Document document;
-
- public SubscriptionContext(Message msg) {
- this(msg, DocumentRepository.fromMessage(msg));
- }
-}
diff --git a/core-lib/src/main/java/de/kentoj/scrowlib/messaging/respose/SafeErrorResult.java b/core-lib/src/main/java/de/kentoj/scrowlib/messaging/respose/SafeErrorResult.java
deleted file mode 100644
index 2de9027..0000000
--- a/core-lib/src/main/java/de/kentoj/scrowlib/messaging/respose/SafeErrorResult.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package de.kentoj.scrowlib.messaging.respose;
-
-import lombok.AccessLevel;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import org.bson.Document;
-
-@Getter
-@AllArgsConstructor(access = AccessLevel.PACKAGE)
-public final class SafeErrorResult extends SafeResult {
- private final String type;
- private final String message;
-
- public SafeErrorResult(Throwable throwable) {
- this.type = throwable.getClass().getCanonicalName();
- this.message = throwable.getMessage();
- }
-
- @Override
- public Document unwrap() {
- throw this.toException();
- }
-
- public RuntimeException toException() {
- return new RuntimeException(message);
- }
-
- @Override
- public Document toDocument() {
- return new Document("error", new Document()
- .append("type", this.type)
- .append("message", this.getMessage()));
- }
-}
diff --git a/core-lib/src/main/java/de/kentoj/scrowlib/messaging/respose/SafeResult.java b/core-lib/src/main/java/de/kentoj/scrowlib/messaging/respose/SafeResult.java
deleted file mode 100644
index 75a7504..0000000
--- a/core-lib/src/main/java/de/kentoj/scrowlib/messaging/respose/SafeResult.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package de.kentoj.scrowlib.messaging.respose;
-
-import de.kentoj.scrowlib.messaging.DocumentRepository;
-import io.nats.client.Message;
-import org.bson.Document;
-import org.jetbrains.annotations.NotNull;
-import reactor.core.publisher.Mono;
-
-public abstract sealed class SafeResult permits SafeErrorResult, SafeSuccessResult {
-
- /**
- * @return the SafeResult as a Document for transit
- */
- public abstract Document toDocument();
-
- /**
- * @return the data stored in the SafeResult
- * @throws RuntimeException if the SafeResult represents an error
- */
- public abstract Document unwrap();
-
- public boolean isError() {
- return this instanceof SafeErrorResult;
- }
-
- public boolean isSuccess() {
- return this instanceof SafeSuccessResult;
- }
-
- public SafeErrorResult asError() {
- return (SafeErrorResult) this;
- }
-
- public SafeSuccessResult asSuccess() {
- return (SafeSuccessResult) this;
- }
-
- public static Document unwrap(Message message) {
- return fromMessage(message).unwrap();
- }
-
- public static SafeResult wrap(Document document) {
- return new SafeSuccessResult(document);
- }
-
- public static SafeResult wrap(Throwable throwable) {
- return new SafeErrorResult(throwable);
- }
-
- public static SafeResult fromMessage(Message message) {
- return fromDocument(DocumentRepository.fromMessage(message));
- }
-
- public static SafeResult fromDocument(Document document) {
- if (document.containsKey("error")) {
- var doc = document.get("error", Document.class);
- return new SafeErrorResult(
- doc.getString("type"),
- doc.getString("message")
- );
- } else if (document.containsKey("data")) {
- return new SafeSuccessResult(document.get("data", Document.class));
- }
- throw new IllegalArgumentException("document does not conform to SafeDocument format");
- }
-
- public static Mono<@NotNull SafeResult> mono(Mono<@NotNull Document> mono) {
- return mono.map(SafeResult::wrap)
- .onErrorResume(err -> Mono.just(SafeResult.wrap(err)));
- }
-}
diff --git a/core-lib/src/main/java/de/kentoj/scrowlib/messaging/respose/SafeSuccessResult.java b/core-lib/src/main/java/de/kentoj/scrowlib/messaging/respose/SafeSuccessResult.java
deleted file mode 100644
index 69242d1..0000000
--- a/core-lib/src/main/java/de/kentoj/scrowlib/messaging/respose/SafeSuccessResult.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package de.kentoj.scrowlib.messaging.respose;
-
-import lombok.AccessLevel;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import org.bson.Document;
-
-@Getter
-@AllArgsConstructor(access = AccessLevel.PACKAGE)
-public final class SafeSuccessResult extends SafeResult {
- private final Document data;
-
- @Override
- public Document unwrap() {
- return this.getData();
- }
-
- @Override
- public Document toDocument() {
- return new Document("data", this.getData());
- }
-}
diff --git a/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/InstanceManager.java b/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/InstanceManager.java
new file mode 100644
index 0000000..22f930f
--- /dev/null
+++ b/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/InstanceManager.java
@@ -0,0 +1,23 @@
+package de.kentoj.scrowlib.servermanager;
+
+import com.leakyabstractions.result.api.Result;
+import org.jspecify.annotations.Nullable;
+
+import java.util.List;
+
+public interface InstanceManager {
+
+ /**
+ * @return Mono with handle of deployed server
+ */
+ Result deployInstance(String template);
+
+ Result destroyInstance(String handle);
+
+ /**
+ * @return Flux with handles of running servers
+ */
+ Result, String> getInstances();
+
+ Result<@Nullable ServerInstance, String> getInstance(String handle);
+}
diff --git a/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/InstanceManagerImpl.java b/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/InstanceManagerImpl.java
new file mode 100644
index 0000000..9dfc538
--- /dev/null
+++ b/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/InstanceManagerImpl.java
@@ -0,0 +1,45 @@
+package de.kentoj.scrowlib.servermanager;
+
+import com.leakyabstractions.result.api.Result;
+import de.kentoj.scrowlib.messaging.MessageBroker;
+import io.nats.client.Connection;
+import org.bson.Document;
+import org.jspecify.annotations.Nullable;
+
+import java.util.List;
+
+public class InstanceManagerImpl implements InstanceManager {
+
+ private final MessageBroker messageBroker;
+
+ public InstanceManagerImpl(Connection natsCon) {
+ messageBroker = new MessageBroker(natsCon);
+ }
+
+ @Override
+ public Result deployInstance(String template) {
+ var result = messageBroker.request("instance.deploy", new Document("template", template));
+ return result.mapSuccess(ServerInstance::fromDocument);
+ }
+
+ @Override
+ public Result destroyInstance(String handle) {
+ var result = messageBroker.request("instance.destroy", new Document("handle", handle));
+ return result.mapSuccess(__ -> null);
+ }
+
+ @Override
+ public Result, String> getInstances() {
+ var result = messageBroker.request("instance.list", new Document());
+ return result.mapSuccess(doc -> doc.getList("instances", Document.class)
+ .stream()
+ .map(ServerInstance::fromDocument)
+ .toList());
+ }
+
+ @Override
+ public Result<@Nullable ServerInstance, String> getInstance(String handle) {
+ var result = messageBroker.request("instance.get", new Document("handle", handle));
+ return result.mapSuccess(ServerInstance::fromDocument);
+ }
+}
diff --git a/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/ServerInstance.java b/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/ServerInstance.java
index 0750e1b..853226d 100644
--- a/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/ServerInstance.java
+++ b/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/ServerInstance.java
@@ -2,25 +2,27 @@ package de.kentoj.scrowlib.servermanager;
import com.google.common.base.Preconditions;
import lombok.Value;
+import org.bson.Document;
@Value
public class ServerInstance {
- String templateName;
String handle;
+ String template;
int port;
- String state;
- public ServerInstance(String templateName, String handle, int port, String state) {
- Preconditions.checkNotNull(templateName);
+ public ServerInstance(String handle, String template, int port) {
+ Preconditions.checkNotNull(template);
Preconditions.checkNotNull(handle);
- Preconditions.checkNotNull(state);
- this.templateName = templateName;
+ this.template = template;
this.handle = handle;
this.port = port;
- this.state = state;
}
- public ServerInstance(String templateName, String handle, int port) {
- this(templateName, handle, port, "STARTING");
+ static ServerInstance fromDocument(Document document) {
+ return new ServerInstance(
+ document.getString("handle"),
+ document.getString("template"),
+ document.getInteger("port")
+ );
}
}
diff --git a/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/ServerManager.java b/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/ServerManager.java
deleted file mode 100644
index f092bc4..0000000
--- a/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/ServerManager.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package de.kentoj.scrowlib.servermanager;
-
-import org.jetbrains.annotations.NotNull;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-import java.util.UUID;
-
-public interface ServerManager {
-
- /**
- * @return Mono with handle of deployed server
- */
- Mono<@NotNull ServerInstance> deployServer(String template);
-
- /**
- * Attempts a clean shutdown, if that doesn't succeed, kills the server.
- */
- Mono<@NotNull Void> destroyServer(String handle);
-
- /**
- * @return Flux with handles of running servers
- */
- Flux<@NotNull ServerInstance> getRunningServers();
-
- Mono<@NotNull ServerInstance> getInfo(String handle);
-
- Mono<@NotNull Void> setState(String handle, String state);
-
- Mono<@NotNull Void> sendPlayer(UUID playerId, String serverHandle);
-}
diff --git a/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/ServerManagerImpl.java b/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/ServerManagerImpl.java
deleted file mode 100644
index 7d71452..0000000
--- a/core-lib/src/main/java/de/kentoj/scrowlib/servermanager/ServerManagerImpl.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package de.kentoj.scrowlib.servermanager;
-
-import com.google.common.base.Preconditions;
-import de.kentoj.scrowlib.messaging.NatsRepository;
-import de.kentoj.scrowlib.messaging.respose.SafeResult;
-import io.nats.client.Connection;
-import org.bson.Document;
-import org.jetbrains.annotations.NotNull;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-import java.util.UUID;
-
-public class ServerManagerImpl implements ServerManager {
-
- private final NatsRepository natsRepo;
-
- public ServerManagerImpl(Connection nats) {
- this.natsRepo = new NatsRepository(nats);
- }
-
- @Override
- public Mono<@NotNull ServerInstance> deployServer(String template) {
- return natsRepo.requestRaw("crown.deploy-server", new Document("template", template))
- .map(SafeResult::unwrap)
- .map(doc -> new ServerInstance(
- template,
- doc.getString("handle"),
- doc.getInteger("port")
- ));
- }
-
- @Override
- public Flux<@NotNull ServerInstance> getRunningServers() {
- return natsRepo.requestRaw("crown.list-servers", new Document())
- .map(SafeResult::unwrap)
- .map(doc ->
- doc.getList("instances", Document.class)
- )
- .flatMapIterable(l -> l)
- .map(doc -> new ServerInstance(
- doc.getString("templateName"),
- doc.getString("handle"),
- doc.getInteger("port"),
- doc.getString("state")
- ));
- }
-
- @Override
- public Mono<@NotNull Void> destroyServer(String handle) {
- return natsRepo.requestRaw("crown.destroy-server", new Document("handle", handle))
- .map(SafeResult::unwrap)
- .then();
- }
-
- @Override
- public Mono<@NotNull ServerInstance> getInfo(String handle) {
- return natsRepo.requestRaw("crown.get-info", new Document("handle", handle))
- .map(SafeResult::unwrap)
- .map(doc -> new ServerInstance(
- doc.getString("templateName"),
- handle,
- doc.getInteger("port"),
- doc.getString("state")
- ));
- }
-
- @Override
- public Mono<@NotNull Void> setState(String handle, String state) {
- Preconditions.checkArgument(!state.contains(" "), "state may not contain spaces");
- var payload = new Document()
- .append("handle", handle)
- .append("state", state);
- return natsRepo.requestRaw("crown.set-state", payload)
- .map(SafeResult::unwrap)
- .then();
- }
-
- @Override
- public Mono<@NotNull Void> sendPlayer(UUID playerId, String serverHandle) {
- var payload = new Document()
- .append("playerId", playerId.toString())
- .append("handle", serverHandle);
- return natsRepo.requestRaw("proxy.send-player", payload)
- .map(SafeResult::unwrap)
- .then();
- }
-}
diff --git a/core-lib/src/main/java/de/kentoj/scrowlib/utils/EnvUtils.java b/core-lib/src/main/java/de/kentoj/scrowlib/utils/EnvUtils.java
new file mode 100644
index 0000000..2a6570b
--- /dev/null
+++ b/core-lib/src/main/java/de/kentoj/scrowlib/utils/EnvUtils.java
@@ -0,0 +1,13 @@
+package de.kentoj.scrowlib.utils;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor(access = AccessLevel.NONE)
+public class EnvUtils {
+ public static String envOrThrow(String name) {
+ var env = System.getenv(name);
+ if (env == null) throw new IllegalStateException("environment variable " + name + " not set");
+ return env;
+ }
+}
diff --git a/core-velocity-api/build.gradle.kts b/core-velocity-api/build.gradle.kts
index b1c24bb..2911306 100644
--- a/core-velocity-api/build.gradle.kts
+++ b/core-velocity-api/build.gradle.kts
@@ -4,6 +4,7 @@ plugins {
id("de.kentoj.scrow.scrow-repository")
id("de.kentoj.scrow.base-dependencies")
id("de.kentoj.scrow.java-library")
+ id("de.kentoj.scrow.reactor")
}
group = "de.kentoj.scrow"
@@ -23,9 +24,9 @@ dependencies {
api("com.velocitypowered:velocity-api:3.5.0-SNAPSHOT")
// http://forge.kentoj.de/scrow/-/packages/maven/de.kentoj.scrow:kencommandapi-core
- api("de.kentoj.scrow:kencommandapi-core:0.8")
+ api("de.kentoj.scrow:kencommandapi-core:0.21")
// http://forge.kentoj.de/scrow/-/packages/maven/de.kentoj.scrow:kencommandapi-velocity
- api("de.kentoj.scrow:kencommandapi-velocity:0.8")
+ api("de.kentoj.scrow:kencommandapi-velocity:0.21")
}
publishing {
diff --git a/core-velocity-api/src/main/java/de/kentoj/scrow/velocity/ScrowAPI.java b/core-velocity-api/src/main/java/de/kentoj/scrow/velocity/ScrowAPI.java
index b93f81d..f682c83 100644
--- a/core-velocity-api/src/main/java/de/kentoj/scrow/velocity/ScrowAPI.java
+++ b/core-velocity-api/src/main/java/de/kentoj/scrow/velocity/ScrowAPI.java
@@ -1,8 +1,8 @@
package de.kentoj.scrow.velocity;
-import de.kentoj.kencommandapi.VelocityKenCommandApi;
+import de.kentoj.kencommandapi.CommandAPI;
import de.kentoj.scrowlib.connection.DatabaseConnectionFactory;
-import de.kentoj.scrowlib.servermanager.ServerManager;
+import de.kentoj.scrowlib.servermanager.InstanceManager;
import io.nats.client.Connection;
import lombok.AccessLevel;
import lombok.Getter;
@@ -16,14 +16,14 @@ public class ScrowAPI {
@Getter
private static DatabaseConnectionFactory dbConFactory;
@Getter
- private static VelocityKenCommandApi commandApi;
+ private static CommandAPI commandApi;
@Getter
private static Connection nats;
@Getter
- private static ServerManager serverManager;
+ private static InstanceManager instanceManager;
@ApiStatus.Internal
- public static void setCommandApi(VelocityKenCommandApi commandApi) {
+ public static void setCommandApi(CommandAPI commandApi) {
ScrowAPI.commandApi = commandApi;
}
@@ -33,8 +33,8 @@ public class ScrowAPI {
}
@ApiStatus.Internal
- public static void setServerManager(ServerManager serverManager) {
- ScrowAPI.serverManager = serverManager;
+ public static void setInstanceManager(InstanceManager instanceManager) {
+ ScrowAPI.instanceManager = instanceManager;
}
@ApiStatus.Internal
diff --git a/core-velocity-impl/build.gradle.kts b/core-velocity-impl/build.gradle.kts
index 463b32a..1821ec9 100644
--- a/core-velocity-impl/build.gradle.kts
+++ b/core-velocity-impl/build.gradle.kts
@@ -4,6 +4,7 @@ plugins {
id("de.kentoj.scrow.scrow-repository")
id("de.kentoj.scrow.base-dependencies")
id("de.kentoj.scrow.database")
+ id("de.kentoj.scrow.reactor")
}
group = "de.kentoj.scrow"
@@ -23,8 +24,6 @@ dependencies {
// https://mvnrepository.com/artifact/com.github.ben-manes.caffeine/caffeine
implementation("com.github.ben-manes.caffeine:caffeine:3.2.4")
-
- implementation("de.kentoj.scrow:kencommandapi-velocity")
}
val generateBuildInfo by tasks.registering {
diff --git a/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/CoreVelocityPlugin.java b/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/CoreVelocityPlugin.java
index 74c5ec3..5f1c66b 100644
--- a/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/CoreVelocityPlugin.java
+++ b/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/CoreVelocityPlugin.java
@@ -33,7 +33,7 @@ public class CoreVelocityPlugin {
cmds.register(new OnlineCommand(server).getRootNode());
}
- var registerWatchdog = new ServerRegisterWatchdog(ScrowAPI.getNats(), ScrowAPI.getServerManager(), server);
+ var registerWatchdog = new ServerRegisterWatchdog(ScrowAPI.getNats(), ScrowAPI.getInstanceManager(), server);
var sendPlayerWatchdog = new SendPlayerWatchdog(ScrowAPI.getNats(), server);
registerWatchdog.listen();
sendPlayerWatchdog.listen();
diff --git a/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/ScrowAPISurface.java b/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/ScrowAPISurface.java
index a33d453..f0a4934 100644
--- a/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/ScrowAPISurface.java
+++ b/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/ScrowAPISurface.java
@@ -1,10 +1,10 @@
package de.kentoj.scrow.corevelocity;
import com.velocitypowered.api.proxy.ProxyServer;
-import de.kentoj.kencommandapi.VelocityKenCommandApi;
+import de.kentoj.kencommandapi.CommandAPI;
import de.kentoj.scrow.velocity.ScrowAPI;
import de.kentoj.scrowlib.connection.DatabaseConnectionFactoryImpl;
-import de.kentoj.scrowlib.servermanager.ServerManagerImpl;
+import de.kentoj.scrowlib.utils.EnvUtils;
import io.nats.client.Nats;
import io.nats.client.Options;
import io.r2dbc.spi.ConnectionFactories;
@@ -19,7 +19,7 @@ public class ScrowAPISurface {
public static void initScrowAPI(ProxyServer server, boolean enableDatabase) {
try {
- String natsHost = System.getenv("HOST_NATS");
+ String natsHost = EnvUtils.envOrThrow("HOST_NATS");
var options = Options.builder()
.server(natsHost)
.pedantic()
@@ -30,13 +30,13 @@ public class ScrowAPISurface {
}
if (enableDatabase) {
- ConnectionFactory factory = ConnectionFactories.get(System.getenv("HOST_POSTGRES"));
+ ConnectionFactory factory = ConnectionFactories.get(EnvUtils.envOrThrow("HOST_POSTGRES"));
ScrowAPI.setDbConFactory(new DatabaseConnectionFactoryImpl(factory));
}
- ScrowAPI.setServerManager(new ServerManagerImpl(ScrowAPI.getNats()));
+ ScrowAPI.setInstanceManager(new ServerManagerImpl(ScrowAPI.getNats()));
- ScrowAPI.setCommandApi(new VelocityKenCommandApi(server));
+ ScrowAPI.setCommandApi(new CommandAPI(server));
}
public static void destroyScrowAPI() {
diff --git a/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/command/OnlineCommand.java b/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/command/OnlineCommand.java
index 2e3ddba..6a34d18 100644
--- a/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/command/OnlineCommand.java
+++ b/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/command/OnlineCommand.java
@@ -2,34 +2,38 @@ package de.kentoj.scrow.corevelocity.command;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.ProxyServer;
-import de.kentoj.kencommandapi.VelocityCommandContext;
-import de.kentoj.kencommandapi.api.nodes.CommandNode;
-import de.kentoj.kencommandapi.api.processing.CommandExecutor;
-import de.kentoj.scrow.velocity.ScrowAPI;
+import de.kentoj.kencommandapi.api.node.CommandNode;
+import de.kentoj.kencommandapi.api.invocation.CommandContext;
+import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
+import com.leakyabstractions.result.api.Result;
+import com.leakyabstractions.result.api.Results;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.kyori.adventure.text.Component;
+import java.util.concurrent.CompletableFuture;
+
@RequiredArgsConstructor
-public class OnlineCommand implements CommandExecutor {
+public class OnlineCommand implements CommandExecutor {
@Getter
- private final CommandNode rootNode;
+ private final CommandNode rootNode;
private final ProxyServer server;
public OnlineCommand(ProxyServer server) {
this.server = server;
- rootNode = ScrowAPI.getCommandApi().createNode("online");
+ rootNode = CommandNode.node("online");
rootNode.setExecutor(this);
}
@Override
- public void execute(VelocityCommandContext ctx) {
+ public CompletableFuture> execute(CommandContext ctx) {
int cnt = server.getPlayerCount();
var msg = cnt != 1
? "There are currently " + cnt + " players online"
: "There is currently 1 player online";
- ctx.getPlayerSender().sendMessage(Component.text(msg));
+ ctx.getSender().sendMessage(Component.text(msg));
+ return Result.success().toFuture();
}
}
diff --git a/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/privmsg/MsgCommand.java b/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/privmsg/MsgCommand.java
index 35f9ae2..3812ed4 100644
--- a/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/privmsg/MsgCommand.java
+++ b/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/privmsg/MsgCommand.java
@@ -3,46 +3,50 @@ package de.kentoj.scrow.corevelocity.privmsg;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
-import de.kentoj.kencommandapi.VelocityCommandContext;
+import de.kentoj.kencommandapi.api.node.CommandNode;
import de.kentoj.kencommandapi.api.argument.CommandArgument;
-import de.kentoj.kencommandapi.api.nodes.CommandNode;
-import de.kentoj.kencommandapi.api.processing.CommandException;
-import de.kentoj.kencommandapi.api.processing.CommandExecutor;
-import de.kentoj.kencommandapi.api.types.StringArgumentType;
+import de.kentoj.kencommandapi.api.argument.types.StringArgumentType;
+import de.kentoj.kencommandapi.api.invocation.CommandContext;
+import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
+import com.leakyabstractions.result.api.Result;
+import com.leakyabstractions.result.api.Results;
import de.kentoj.kencommandapi.type.PlayerArgumentType;
import de.kentoj.scrow.velocity.ScrowAPI;
import lombok.Getter;
-public class MsgCommand implements CommandExecutor {
+import java.util.concurrent.CompletableFuture;
+
+public class MsgCommand implements CommandExecutor {
@Getter
- private final CommandNode rootNode;
- private final CommandArgument targetArg;
- private final CommandArgument msgArg;
+ private final CommandNode rootNode;
+ private final CommandArgument targetArg;
+ private final CommandArgument msgArg;
private final LastTargetCache cache;
public MsgCommand(ProxyServer server, LastTargetCache cache) {
this.cache = cache;
- var cmds = ScrowAPI.getCommandApi();
- targetArg = cmds.createArgument("target", new PlayerArgumentType(server));
- msgArg = cmds.createArgument("msg", new StringArgumentType<>(true));
- rootNode = cmds.createNode("msg", "w", "privmsg");
+ targetArg = CommandArgument.arg("target", new PlayerArgumentType(server));
+ msgArg = CommandArgument.arg("msg", new StringArgumentType<>(true));
+ rootNode = CommandNode.node("msg", "w", "privmsg");
rootNode.setExecutor(this);
rootNode.addArgument(targetArg);
rootNode.addArgument(msgArg);
}
@Override
- public void execute(VelocityCommandContext ctx) {
+ public CompletableFuture> execute(CommandContext ctx) {
var target = ctx.getArg(targetArg);
var msg = ctx.getArg(msgArg);
+ var sender = (Player)ctx.getSender();
- var isMessagingSelf = target.getUniqueId().equals(ctx.getPlayerSender().getUniqueId());
- if (isMessagingSelf) throw new CommandException("You can't message yourself.");
+ var isMessagingSelf = target.getUniqueId().equals(sender.getUniqueId());
+ if (isMessagingSelf) return Result.error("You can't message yourself").toFuture();
- cache.setLastTarget(ctx.getPlayerSender().getUniqueId(), target.getUniqueId());
- PrivmsgHelper.handle(ctx.getPlayerSender(), target, msg);
+ cache.setLastTarget(sender.getUniqueId(), target.getUniqueId());
+ PrivmsgHelper.handle(sender, target, msg);
+ return Result.success().toFuture();
}
}
diff --git a/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/privmsg/ReplyCommand.java b/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/privmsg/ReplyCommand.java
index a0bd3cd..5aa38a8 100644
--- a/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/privmsg/ReplyCommand.java
+++ b/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/privmsg/ReplyCommand.java
@@ -1,21 +1,24 @@
package de.kentoj.scrow.corevelocity.privmsg;
import com.velocitypowered.api.command.CommandSource;
+import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
-import de.kentoj.kencommandapi.VelocityCommandContext;
+import de.kentoj.kencommandapi.api.node.CommandNode;
import de.kentoj.kencommandapi.api.argument.CommandArgument;
-import de.kentoj.kencommandapi.api.nodes.CommandNode;
-import de.kentoj.kencommandapi.api.processing.CommandException;
-import de.kentoj.kencommandapi.api.processing.CommandExecutor;
-import de.kentoj.kencommandapi.api.types.StringArgumentType;
-import de.kentoj.scrow.velocity.ScrowAPI;
+import de.kentoj.kencommandapi.api.argument.types.StringArgumentType;
+import de.kentoj.kencommandapi.api.invocation.CommandContext;
+import de.kentoj.kencommandapi.api.invocation.CommandExecutor;
+import com.leakyabstractions.result.api.Result;
+import com.leakyabstractions.result.api.Results;
import lombok.Getter;
-public class ReplyCommand implements CommandExecutor {
+import java.util.concurrent.CompletableFuture;
+
+public class ReplyCommand implements CommandExecutor {
@Getter
- private final CommandNode rootNode;
- private final CommandArgument msgArg;
+ private final CommandNode rootNode;
+ private final CommandArgument msgArg;
private final LastTargetCache cache;
private final ProxyServer server;
@@ -24,21 +27,22 @@ public class ReplyCommand implements CommandExecutor(true));
- rootNode = cmds.createNode("reply", "r");
+ msgArg = CommandArgument.arg("msg", new StringArgumentType<>(true));
+ rootNode = CommandNode.node("reply", "r");
rootNode.setExecutor(this);
rootNode.addArgument(msgArg);
}
@Override
- public void execute(VelocityCommandContext ctx) {
- var targetId = cache.getLastTarget(ctx.getPlayerSender().getUniqueId());
+ public CompletableFuture> execute(CommandContext ctx) {
+ var sender = (Player)ctx.getSender();
+ var targetId = cache.getLastTarget(sender.getUniqueId());
var target = server.getPlayer(targetId).orElse(null);
- if (target == null) throw new CommandException("The player you last messaged is no longer online");
+ if (target == null) return Result.error("The player you last messaged is no longer online").toFuture();
var msg = ctx.getArg(msgArg);
- cache.setLastTarget(ctx.getPlayerSender().getUniqueId(), target.getUniqueId());
- PrivmsgHelper.handle(ctx.getPlayerSender(), target, msg);
+ cache.setLastTarget(sender.getUniqueId(), target.getUniqueId());
+ PrivmsgHelper.handle(sender, target, msg);
+ return Result.success().toFuture();
}
}
diff --git a/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/server/SendPlayerWatchdog.java b/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/server/SendPlayerWatchdog.java
index e85601c..0ed69cc 100644
--- a/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/server/SendPlayerWatchdog.java
+++ b/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/server/SendPlayerWatchdog.java
@@ -1,43 +1,47 @@
package de.kentoj.scrow.corevelocity.server;
+import com.leakyabstractions.result.api.Result;
+import com.leakyabstractions.result.core.Results;
import com.velocitypowered.api.proxy.ProxyServer;
-import de.kentoj.scrowlib.messaging.NatsRepository;
-import de.kentoj.scrowlib.messaging.respose.SafeResult;
+import de.kentoj.scrowlib.messaging.MessageBroker;
import io.nats.client.Connection;
+import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
-import org.jetbrains.annotations.NotNull;
-import reactor.core.publisher.Mono;
import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.ExecutionException;
+@Slf4j
public class SendPlayerWatchdog {
- private final NatsRepository natsRepo;
+ private final MessageBroker natsRepo;
private final ProxyServer server;
public SendPlayerWatchdog(Connection nats, ProxyServer server) {
- this.natsRepo = new NatsRepository(nats);
+ this.natsRepo = new MessageBroker(nats);
this.server = server;
}
public void listen() {
- natsRepo.subscribe("proxy.send-player")
- .flatMap(ctx ->
- SafeResult.mono(handleSendPlayer(ctx.getDocument()))
- )
- .subscribe();
+ natsRepo.handle("players.send", doc -> sendPlayer(
+ doc.get("playerId", UUID.class),
+ doc.getString("handle")
+ ));
}
- private Mono<@NotNull Document> handleSendPlayer(Document doc) {
- return Mono.fromCallable(() -> {
- var player = server.getPlayer(UUID.fromString(doc.getString("playerId"))).orElseThrow();
- var targetServer = server.getServer(doc.getString("handle")).orElseThrow();
- return player.createConnectionRequest(targetServer).connect();
- })
- .flatMap(Mono::fromFuture)
- .flatMap(res -> res.isSuccessful()
- ? Mono.just(new Document())
- : Mono.error(new RuntimeException(res.getStatus().name().toLowerCase().replace('_', ' ')))
- );
+ private CompletionStage> sendPlayer(UUID playerId, String handle) {
+ return CompletableFuture.supplyAsync(() -> {
+ var player = server.getPlayer(playerId).orElseThrow();
+ var targetServer = server.getServer(handle).orElseThrow();
+ try {
+ var res = player.createConnectionRequest(targetServer).connect().get();
+ return res.isSuccessful() ? Results.success(new Document()) : Results.failure(res.getStatus().name());
+ } catch (InterruptedException | ExecutionException e) {
+ log.error("failed to send player to {}", handle, e);
+ return Results.failure(e.getMessage());
+ }
+ });
}
}
diff --git a/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/server/ServerRegisterWatchdog.java b/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/server/ServerRegisterWatchdog.java
index 7f5af50..d8f2cda 100644
--- a/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/server/ServerRegisterWatchdog.java
+++ b/core-velocity-impl/src/main/java/de/kentoj/scrow/corevelocity/server/ServerRegisterWatchdog.java
@@ -2,10 +2,9 @@ package de.kentoj.scrow.corevelocity.server;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.server.ServerInfo;
-import de.kentoj.scrowlib.messaging.NatsRepository;
-import de.kentoj.scrowlib.messaging.SubscriptionContext;
+import de.kentoj.scrowlib.messaging.MessageBroker;
import de.kentoj.scrowlib.messaging.respose.SafeResult;
-import de.kentoj.scrowlib.servermanager.ServerManager;
+import de.kentoj.scrowlib.servermanager.InstanceManager;
import io.nats.client.Connection;
import lombok.extern.java.Log;
import org.bson.Document;
@@ -17,13 +16,13 @@ import java.net.InetSocketAddress;
@Log
public class ServerRegisterWatchdog {
- private final NatsRepository natsRepo;
- private final ServerManager serverManager;
+ private final MessageBroker natsRepo;
+ private final InstanceManager instanceManager;
private final ProxyServer server;
- public ServerRegisterWatchdog(Connection nats, ServerManager serverManager, ProxyServer server) {
- this.natsRepo = new NatsRepository(nats);
- this.serverManager = serverManager;
+ public ServerRegisterWatchdog(Connection nats, InstanceManager instanceManager, ProxyServer server) {
+ this.natsRepo = new MessageBroker(nats);
+ this.instanceManager = instanceManager;
this.server = server;
}
@@ -42,11 +41,11 @@ public class ServerRegisterWatchdog {
private @NotNull Mono<@NotNull Void> handleStateChange(SubscriptionContext ctx, String state, String handle) {
return switch (state) {
- case "UP" -> serverManager.getInfo(handle)
+ case "UP" -> instanceManager.getInfo(handle)
.doOnNext(instance ->
server.registerServer(new ServerInfo(handle, new InetSocketAddress(instance.getPort()))))
.then();
- case "DOWN" -> serverManager.getInfo(handle)
+ case "DOWN" -> instanceManager.getInfo(handle)
.doOnNext(instance ->
server.unregisterServer(new ServerInfo(handle, new InetSocketAddress(instance.getPort()))))
.then();