This commit is contained in:
kento2 2026-08-10 21:45:45 +02:00
parent a088d27485
commit 46978ae799
18 changed files with 2233 additions and 112 deletions

View file

@ -24,12 +24,12 @@ public final class CoinsCommand {
.asRootLiteral(ScrowMessageStyle.GENERIC);
}
public CompletableFuture<?> execute(MessageStyle style, CommandContext<Player> ctx) {
public CompletableFuture<?> execute(CommandContext<Player> ctx) {
var player = ctx.sender();
return Tasks.supplyAsync(() ->
ScrowAPI.economyService().getCoins(player.getUniqueId()))
.thenSync(amount ->
player.sendMessage(style.ok("You have " + amount + "$")))
player.sendMessage(ctx.style().ok("You have " + amount + "$")))
.toFuture();
}

View file

@ -28,12 +28,12 @@ public final class CoinsGetLiteral {
.build();
}
private CompletableFuture<?> execute(MessageStyle style, CommandContext<Player> ctx) {
private CompletableFuture<?> execute(CommandContext<Player> ctx) {
var player = ctx.getArg(playerArg);
return Tasks.supplyAsync(() ->
ScrowAPI.economyService().getCoins(player.getUniqueId()))
.thenSync(amount ->
ctx.sender().sendMessage(style.ok(player.getName() + " has " + amount + "$")))
ctx.sender().sendMessage(ctx.style().ok(player.getName() + " has " + amount + "$")))
.toFuture();
}

View file

@ -33,13 +33,13 @@ public final class CoinsSetLiteral {
.build();
}
private CompletableFuture<?> execute(MessageStyle style, CommandContext<Player> ctx) {
private CompletableFuture<?> execute(CommandContext<Player> ctx) {
var player = ctx.getArg(playerArg);
var amount = ctx.getArg(amountArg);
return Tasks.runAsync(() ->
ScrowAPI.economyService().setCoins(player.getUniqueId(), amount))
.runSync(() ->
ctx.sender().sendMessage(style.ok(player.getName() + " now has " + amount + "$")))
ctx.sender().sendMessage(ctx.style().ok(player.getName() + " now has " + amount + "$")))
.toFuture();
}

View file

@ -5,6 +5,7 @@ import com.leakyabstractions.result.core.Results;
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.kencommandapi.api.platform.MessageStyle;
import de.kentoj.kencommandapi.type.OfflinePlayerArgumentType;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.scheduler.Task;
@ -27,12 +28,10 @@ public final class FriendAddLiteral {
private final Literal<Player> literal;
private final CommandArgumentSpec<Player, OfflinePlayer> playerArg;
private final ScrowMessageStyle style;
private final FriendRequestService requestService = ScrowAPI.friendRequestService();
private final FriendshipService friendsService = ScrowAPI.friendshipService();
FriendAddLiteral(ScrowMessageStyle style) {
this.style = style;
FriendAddLiteral() {
playerArg = CommandArgumentSpec.builder("player", new OfflinePlayerArgumentType<Player>())
.build();
literal = Literal.<Player>builder("add")
@ -41,19 +40,19 @@ public final class FriendAddLiteral {
.build();
}
private CompletableFuture<Result<Object, String>> execute(CommandContext<Player> ctx) {
private CompletableFuture<?> execute(CommandContext<Player> ctx) {
var self = ctx.sender();
var other = ctx.getArg(playerArg);
return Tasks.supplyAsync(() -> findAction(self, other)
.mapSuccess(action -> {
if (action == AddAction.SEND_REQUEST) sendRequest(self, other);
else if (action == AddAction.ACCEPT_REQUEST) acceptRequest(self, other);
if (action == AddAction.SEND_REQUEST) sendRequest(ctx.style(), self, other);
else if (action == AddAction.ACCEPT_REQUEST) acceptRequest(ctx.style(), self, other);
return new Object();
}))
.toFuture();
}
private void sendRequest(Player self, OfflinePlayer other) {
private void sendRequest(MessageStyle style, Player self, OfflinePlayer other) {
Tasks.runAsync(() ->
requestService.saveFriendRequest(new FriendRequestImpl(self.getUniqueId(), other.getUniqueId())))
.runSync(() -> {
@ -65,7 +64,7 @@ public final class FriendAddLiteral {
.await();
}
private void acceptRequest(Player self, OfflinePlayer other) {
private void acceptRequest(MessageStyle style, Player self, OfflinePlayer other) {
Tasks.runAsync(() -> Tasks.awaitAll(
Tasks.runAsync(() -> requestService.deleteFriendRequest(self.getUniqueId(), other.getUniqueId())),
Tasks.runAsync(() -> requestService.deleteFriendRequest(other.getUniqueId(), self.getUniqueId())),

View file

@ -1,12 +1,11 @@
package de.kentoj.scrow.bukkit.command.friends;
import com.leakyabstractions.result.api.Result;
import com.leakyabstractions.result.core.Results;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.kencommandapi.api.platform.MessageStyle;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.scheduler.Tasks;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.minimessage.MiniMessage;
@ -29,7 +28,7 @@ public final class FriendListLiteral {
.build();
}
private CompletableFuture<?> displayFriendList(MessageStyle style, CommandContext<Player> ctx) {
private CompletableFuture<?> displayFriendList(CommandContext<Player> ctx) {
var sender = ctx.sender();
return Tasks.supplyAsync(() ->
ScrowAPI.friendshipService().getFriendships(sender.getUniqueId()))
@ -39,11 +38,11 @@ public final class FriendListLiteral {
.sorted(this::compareByOnlineStatus)
.toList();
if (friends.isEmpty()) {
ctx.sender().sendMessage(style.err("You have no friends. Use /friend add <player>"));
ctx.sender().sendMessage(ctx.style().err("You have no friends. Use /friend add <player>"));
return;
}
sender.sendMessage(formatList(style, friends));
sender.sendMessage(formatList(ctx.style(), friends));
}).toFuture();
}
@ -53,7 +52,7 @@ public final class FriendListLiteral {
return 0;
}
private Component formatList(MessageStyle style, List<OfflinePlayer> friends) {
private Component formatList(ScrowMessageStyle style, List<OfflinePlayer> friends) {
var message = style.ok(MiniMessage.miniMessage().deserialize("Your friends:"));
for (var friend : friends) {
var status = MiniMessage.miniMessage().deserialize(friend.isOnline()

View file

@ -8,7 +8,6 @@ import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.kencommandapi.type.OfflinePlayerArgumentType;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.scheduler.Tasks;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
@ -18,10 +17,8 @@ public final class FriendRemoveLiteral {
private final Literal<Player> literal;
private final CommandArgumentSpec<Player, OfflinePlayer> playerArg;
private final ScrowMessageStyle style;
FriendRemoveLiteral(ScrowMessageStyle style) {
this.style = style;
FriendRemoveLiteral() {
playerArg = CommandArgumentSpec.<Player, OfflinePlayer>builder("player", new OfflinePlayerArgumentType<>())
.build();
literal = Literal.<Player>builder("remove")
@ -30,15 +27,16 @@ public final class FriendRemoveLiteral {
.build();
}
private CompletableFuture<Result<Object, String>> removeFriend(CommandContext<Player> ctx) {
private CompletableFuture<?> removeFriend(CommandContext<Player> ctx) {
var friend = ctx.getArg(playerArg);
return Tasks.supplyAsync(() ->
ScrowAPI.friendshipService().deleteFriendship(friend.getUniqueId(), ctx.sender().getUniqueId()))
.<Result<Object, String>>mapSync(deleted -> {
if (!deleted)
return Results.failure("You are not friends with " + friend.getName() + ".");
ctx.sender().sendMessage(style.ok("You have ended the friendship with " + friend.getName() + "."));
return Results.success(new Object());
.thenSync(deleted -> {
if (!deleted) {
ctx.sender().sendMessage(ctx.style().err("You are not friends with " + friend.getName() + "."));
return;
}
ctx.sender().sendMessage(ctx.style().ok("You have ended the friendship with " + friend.getName() + "."));
}).toFuture();
}

View file

@ -19,11 +19,9 @@ public final class FriendRequestDeclineLiteral {
private final Literal<Player> literal;
private final CommandArgumentSpec<Player, OfflinePlayer> playerArg;
private final ScrowMessageStyle style;
private final FriendRequestService requestService = ScrowAPI.friendRequestService();
FriendRequestDeclineLiteral(ScrowMessageStyle style) {
this.style = style;
FriendRequestDeclineLiteral() {
playerArg = CommandArgumentSpec.builder("player", new OfflinePlayerArgumentType<Player>())
.build();
literal = Literal.<Player>builder("reject", "decline")
@ -32,16 +30,17 @@ public final class FriendRequestDeclineLiteral {
.build();
}
private CompletableFuture<Result<Object, String>> declineFriendRequest(CommandContext<Player> ctx) {
private CompletableFuture<?> declineFriendRequest(CommandContext<Player> ctx) {
var other = ctx.getArg(playerArg);
return Tasks.supplyAsync(() ->
requestService.deleteFriendRequest(other.getUniqueId(), ctx.sender().getUniqueId()))
.<Result<Object, String>>mapSync(deleted -> {
if (!deleted)
return Results.failure("There's no incoming friend request from " + other.getName() + ".");
ctx.sender().sendMessage(style.ok("Friend request declined."));
ScrowAPI.getPlayer(other).sendMessage(style.ok(ctx.sender().getName() + " has declined your friend request."));
return Results.success(new Object());
.thenSync(deleted -> {
if (!deleted) {
ctx.sender().sendMessage(ctx.style().err("There's no incoming friend request from " + other.getName() + "."));
return;
}
ctx.sender().sendMessage(ctx.style().ok("Friend request declined."));
ScrowAPI.getPlayer(other).sendMessage(ctx.style().ok(ctx.sender().getName() + " has declined your friend request."));
}).toFuture();
}

View file

@ -1,9 +1,8 @@
package de.kentoj.scrow.bukkit.command.friends;
import com.leakyabstractions.result.api.Result;
import com.leakyabstractions.result.core.Results;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.kencommandapi.api.platform.MessageStyle;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.scheduler.Tasks;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
@ -22,25 +21,25 @@ import static net.kyori.adventure.text.Component.text;
public final class FriendRequestsLiteral {
private final Literal<Player> literal;
private final ScrowMessageStyle style;
FriendRequestsLiteral(ScrowMessageStyle style) {
this.style = style;
FriendRequestsLiteral() {
literal = Literal.<Player>builder("requests")
.withExecutor(this::displayFriendRequests)
.build();
}
private CompletableFuture<Result<Object, String>> displayFriendRequests(CommandContext<Player> ctx) {
private CompletableFuture<?> displayFriendRequests(CommandContext<Player> ctx) {
return Tasks.supplyAsync(() ->
ScrowAPI.friendRequestService().getFriendRequestsTo(ctx.sender().getUniqueId()))
.<Result<Object, String>>mapAsync(list -> {
if (list.isEmpty()) return Results.failure("You have no friend requests.");
.thenSync(list -> {
if (list.isEmpty()) {
ctx.sender().sendMessage(ctx.style().err("You have no friend requests."));
return;
}
var requesters = list.stream()
.sorted(this::compareByAge)
.map(fr -> Bukkit.getOfflinePlayer(fr.from()).getName());
ctx.sender().sendMessage(formatList(requesters.toList()));
return Results.success(new Object());
ctx.sender().sendMessage(formatList(ctx.style(), requesters.toList()));
}).toFuture();
}
@ -48,7 +47,7 @@ public final class FriendRequestsLiteral {
return a.createdAt().isAfter(b.createdAt()) ? 1 : -1;
}
private Component formatList(List<String> requesters) {
private Component formatList(ScrowMessageStyle style, List<String> requesters) {
var message = style.ok(MiniMessage.miniMessage().deserialize("Open friend requests:"));
for (String requester : requesters) {
message = message

View file

@ -11,12 +11,11 @@ public final class InstanceCommand {
private final RootLiteral<CommandSender> rootLiteral;
public InstanceCommand(InstanceCache instanceCache) {
var style = new ScrowMessageStyle("server-manager", NamedTextColor.RED);
rootLiteral = Literal.<CommandSender>builder("instance", "server-manager")
.withLiteral(new InstanceListLiteral(style).literal())
.withLiteral(new InstanceDeployLiteral(style).literal())
.withLiteral(new InstanceDestroyLiteral(instanceCache, style).literal())
.asRootLiteral(style);
.withLiteral(new InstanceListLiteral().literal())
.withLiteral(new InstanceDeployLiteral().literal())
.withLiteral(new InstanceDestroyLiteral(instanceCache).literal())
.asRootLiteral(new ScrowMessageStyle("server-manager", NamedTextColor.RED));
}
public RootLiteral<CommandSender> rootLiteral() {

View file

@ -1,14 +1,11 @@
package de.kentoj.scrow.bukkit.command.instance;
import com.leakyabstractions.result.api.Result;
import com.leakyabstractions.result.core.Results;
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
import de.kentoj.kencommandapi.api.argument.types.StringArgumentType;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.scheduler.Tasks;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import org.bukkit.command.CommandSender;
import java.util.concurrent.CompletableFuture;
@ -17,11 +14,8 @@ public final class InstanceDeployLiteral {
private final Literal<CommandSender> literal;
private final CommandArgumentSpec<CommandSender, String> templateArg;
private final ScrowMessageStyle style;
InstanceDeployLiteral(ScrowMessageStyle style) {
this.style = style;
InstanceDeployLiteral() {
templateArg = CommandArgumentSpec.builder("template", new StringArgumentType<CommandSender>())
.build();
literal = Literal.<CommandSender>builder("deploy")
@ -30,15 +24,14 @@ public final class InstanceDeployLiteral {
.build();
}
private CompletableFuture<Result<Object, String>> deployInstance(CommandContext<CommandSender> ctx) {
private CompletableFuture<?> deployInstance(CommandContext<CommandSender> ctx) {
var template = ctx.getArg(templateArg);
ctx.sender().sendMessage(style.ok("Deploying instance... this may take a while."));
ctx.sender().sendMessage(ctx.style().ok("Deploying instance... this may take a while."));
return Tasks.supplyAsync(() ->
ScrowAPI.instanceManager().deployInstance(template))
.<Result<Object, String>>mapSync(instance -> {
ctx.sender().sendMessage(style.ok("Deployed instance of " + template + " with handle " + instance.handle() + "."));
.thenSync(instance -> {
ctx.sender().sendMessage(ctx.style().ok("Deployed instance of " + template + " with handle " + instance.handle() + "."));
// FIXME handle unknown server
return Results.success(new Object());
}).toFuture();
}

View file

@ -1,7 +1,5 @@
package de.kentoj.scrow.bukkit.command.instance;
import com.leakyabstractions.result.api.Result;
import com.leakyabstractions.result.core.Results;
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
import de.kentoj.kencommandapi.api.argument.types.StringArgumentType;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
@ -18,11 +16,8 @@ public final class InstanceDestroyLiteral {
private final Literal<CommandSender> literal;
private final CommandArgumentSpec<CommandSender, String> handleArg;
private final ScrowMessageStyle style;
InstanceDestroyLiteral(InstanceCache cache, ScrowMessageStyle style) {
this.style = style;
InstanceDestroyLiteral(InstanceCache cache) {
handleArg = CommandArgumentSpec.builder("handle", new StringArgumentType<CommandSender>())
.withSuggestionProvider((_, _) ->
cache.getInstances().stream()
@ -35,14 +30,15 @@ public final class InstanceDestroyLiteral {
.build();
}
private CompletableFuture<Result<Object, String>> destroyInstance(CommandContext<CommandSender> ctx) {
private CompletableFuture<?> destroyInstance(CommandContext<CommandSender> ctx) {
var handle = ctx.getArg(handleArg);
return Tasks.supplyAsync(() -> ScrowAPI.instanceManager().destroyInstance(handle))
.<Result<Object, String>>mapSync(found -> {
if (!found)
return Results.failure("No instance with that handle found.");
ctx.sender().sendMessage(style.ok("Destroyed server with handle " + handle + "."));
return Results.success(new Object());
.thenSync(found -> {
if (!found) {
ctx.sender().sendMessage(ctx.style().err("No instance with that handle found."));
return;
}
ctx.sender().sendMessage(ctx.style().ok("Destroyed server with handle " + handle + "."));
}).toFuture();
}

View file

@ -1,12 +1,9 @@
package de.kentoj.scrow.bukkit.command.instance;
import com.leakyabstractions.result.api.Result;
import com.leakyabstractions.result.core.Results;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
import de.kentoj.kencommandapi.api.literal.Literal;
import de.kentoj.scrow.bukkit.ScrowAPI;
import de.kentoj.scrow.bukkit.scheduler.Tasks;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import net.kyori.adventure.text.Component;
import org.bukkit.command.CommandSender;
@ -15,26 +12,23 @@ import java.util.concurrent.CompletableFuture;
public final class InstanceListLiteral {
private final Literal<CommandSender> literal;
private final ScrowMessageStyle style;
InstanceListLiteral(ScrowMessageStyle style) {
this.style = style;
InstanceListLiteral() {
this.literal = Literal.<CommandSender>builder("list")
.withExecutor(this::displayInstanceList)
.build();
}
private CompletableFuture<Result<Object, String>> displayInstanceList(CommandContext<CommandSender> ctx) {
private CompletableFuture<?> displayInstanceList(CommandContext<CommandSender> ctx) {
return Tasks.supplyAsync(() ->
ScrowAPI.instanceManager().instances())
.<Result<Object, String>>mapSync(instances -> {
.thenSync(instances -> {
var msg = Component.text("Running instances:");
for (var inst : instances) {
msg = msg.appendNewline()
.append(Component.text(" - " + inst.handle() + " on port " + inst.port()));
}
ctx.sender().sendMessage(style.ok(msg));
return Results.success(new Object());
ctx.sender().sendMessage(ctx.style().ok(msg));
}).toFuture();
}

View file

@ -19,9 +19,8 @@ public final class LobbyCommand {
.asRootLiteral(ScrowMessageStyle.GENERIC);
}
private Result<Object, String> sendToLobby(CommandContext<Player> ctx) {
private void sendToLobby(CommandContext<Player> ctx) {
Bukkit.dispatchCommand(ctx.sender(), "play lobby");
return Results.success(new Object());
}
public RootLiteral<Player> rootLiteral() {

View file

@ -1,7 +1,5 @@
package de.kentoj.scrow.bukkit.command.instance;
import com.leakyabstractions.result.api.Result;
import com.leakyabstractions.result.core.Results;
import de.kentoj.kencommandapi.api.argument.CommandArgumentSpec;
import de.kentoj.kencommandapi.api.argument.types.StringArgumentType;
import de.kentoj.kencommandapi.api.invocation.CommandContext;
@ -12,6 +10,7 @@ import de.kentoj.scrow.bukkit.scheduler.Tasks;
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
import org.bukkit.entity.Player;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
public final class PlayCommand {
@ -28,22 +27,25 @@ public final class PlayCommand {
.asRootLiteral(style);
}
private CompletableFuture<Result<Object, String>> execute(CommandContext<Player> ctx) {
private CompletableFuture<?> execute(CommandContext<Player> ctx) {
var gamemode = ctx.getArg(gamemodeArg);
return Tasks.supplyAsync(() -> ScrowAPI.instanceManager().instances())
.mapAsync(instances -> {
.mapSync(instances -> {
var instance = instances.stream()
.filter(inst -> inst.template().equals(gamemode))
.findFirst()
.orElse(null);
if (instance == null)
return Results.failure("No instance for " + gamemode + " found.");
if (instance == null) {
ctx.sender().sendMessage(ctx.style().err("No instance for " + gamemode + " found."));
return null;
}
return Results.ofCallable(() -> {
ScrowAPI.getPlayer(ctx.sender()).sendToInstance(instance.handle());
return new Object();
}).mapFailure(Exception::getMessage);
}).toFuture();
return instance.handle();
})
.yieldIf(Objects::isNull)
.thenAsync(handle ->
ScrowAPI.getPlayer(ctx.sender()).sendToInstance(handle)
).toFuture();
}
public RootLiteral<Player> rootLiteral() {