diff --git a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/ArcCaptionKeys.java b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/ArcCaptionKeys.java index c3cdc438..70a9897f 100644 --- a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/ArcCaptionKeys.java +++ b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/ArcCaptionKeys.java @@ -31,7 +31,7 @@ */ public final class ArcCaptionKeys { - private static final Collection RECOGNIZED_CAPTIONS = new ArrayList<>(7); + private static final Collection RECOGNIZED_CAPTIONS = new ArrayList<>(3); /** * Variables: {@code {input}}. @@ -48,26 +48,6 @@ public final class ArcCaptionKeys { */ public static final Caption ARGUMENT_PARSE_FAILURE_TEAM = of("argument.parse.failure.team"); - /** - * Variables: {@code {syntax}}. - */ - public static final Caption COMMAND_INVALID_SYNTAX = of("command.invalid.syntax"); - - /** - * Variables: {@code {permission}}. - */ - public static final Caption COMMAND_INVALID_PERMISSION = of("command.invalid.permission"); - - /** - * Variables: {@code {command}}. - */ - public static final Caption COMMAND_FAILURE_NO_SUCH_COMMAND = of("command.failure.no_such_command"); - - /** - * Variables: {@code {message}}. - */ - public static final Caption COMMAND_FAILURE_EXECUTION = of("command.failure.execution"); - private ArcCaptionKeys() {} private static Caption of(final String key) { diff --git a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/PermissionChecker.java b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/ArcCommandContextKeys.java similarity index 72% rename from distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/PermissionChecker.java rename to distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/ArcCommandContextKeys.java index 9d6df2f5..69061457 100644 --- a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/PermissionChecker.java +++ b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/ArcCommandContextKeys.java @@ -18,4 +18,13 @@ */ package com.xpdustry.distributor.command.cloud; -public interface PermissionChecker {} +import io.leangen.geantyref.TypeToken; +import org.incendo.cloud.key.CloudKey; + +public final class ArcCommandContextKeys { + + public static final CloudKey MINDUSTRY_ADMIN = + CloudKey.of("mindustry:admin", TypeToken.get(Boolean.class)); + + private ArcCommandContextKeys() {} +} diff --git a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/ArcCommandManager.java b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/ArcCommandManager.java index 5b4425da..323b5bcd 100644 --- a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/ArcCommandManager.java +++ b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/ArcCommandManager.java @@ -92,6 +92,15 @@ public ArcCommandManager( TypeToken.get(Team.class), params -> new TeamParser<>(params.get(ArcParserParameters.TEAM_MODE, TeamParser.TeamMode.BASE))); + + this.registerCommandPreProcessor(ctx -> { + final var reversed = + this.senderMapper().reverse(ctx.commandContext().sender()); + ctx.commandContext() + .store( + ArcCommandContextKeys.MINDUSTRY_ADMIN, + reversed.isServer() || reversed.getPlayer().admin()); + }); } @Override diff --git a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/parser/PlayerInfoParser.java b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/parser/PlayerInfoParser.java index 11a1636e..43f6812e 100644 --- a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/parser/PlayerInfoParser.java +++ b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/parser/PlayerInfoParser.java @@ -18,13 +18,7 @@ */ package com.xpdustry.distributor.command.cloud.parser; -import arc.Core; -import com.xpdustry.distributor.core.DistributorProvider; -import com.xpdustry.distributor.core.collection.ArcCollections; -import com.xpdustry.distributor.core.player.PlayerLookup; -import java.util.concurrent.CompletableFuture; -import mindustry.gen.Groups; -import mindustry.gen.Player; +import com.xpdustry.distributor.command.cloud.ArcCommandContextKeys; import mindustry.net.Administration; import org.checkerframework.checker.nullness.qual.NonNull; import org.incendo.cloud.component.CommandComponent; @@ -33,10 +27,9 @@ import org.incendo.cloud.parser.ArgumentParseResult; import org.incendo.cloud.parser.ArgumentParser; import org.incendo.cloud.parser.ParserDescriptor; -import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.SuggestionProvider; -public final class PlayerInfoParser implements ArgumentParser.FutureArgumentParser { +public final class PlayerInfoParser implements ArgumentParser { public static ParserDescriptor playerInfoParser() { return ParserDescriptor.of(new PlayerInfoParser<>(), Administration.PlayerInfo.class); @@ -47,33 +40,24 @@ public static CommandComponent.Builder playerI } @Override - public CompletableFuture> parseFuture( - final CommandContext ctx, final CommandInput input) { + public ArgumentParseResult parse(final CommandContext ctx, final CommandInput input) { final var query = input.readString(); - return DistributorProvider.get() - .getService(PlayerLookup.class) - .orElseThrow() - .findOfflinePlayers(query, true) - .thenApply(result -> { - if (result.isEmpty()) { - return ArgumentParseResult.failure( - new PlayerParseException.PlayerNotFound(PlayerInfoParser.class, query, ctx)); - } else if (result.size() > 1) { - return ArgumentParseResult.failure( - new PlayerParseException.TooManyPlayers(PlayerInfoParser.class, query, ctx)); - } else { - return ArgumentParseResult.success(result.get(0)); - } - }); + final var result = + PlayerLookup.findOfflinePlayers(query, ctx.getOrDefault(ArcCommandContextKeys.MINDUSTRY_ADMIN, false)); + if (result.isEmpty()) { + return ArgumentParseResult.failure( + new PlayerParseException.PlayerNotFound(PlayerInfoParser.class, query, ctx)); + } else if (result.size() > 1) { + return ArgumentParseResult.failure( + new PlayerParseException.TooManyPlayers(PlayerInfoParser.class, query, ctx)); + } else { + return ArgumentParseResult.success(result.iterator().next()); + } } + @SuppressWarnings("unchecked") @Override public @NonNull SuggestionProvider suggestionProvider() { - return (ctx, input) -> CompletableFuture.supplyAsync( - () -> ArcCollections.immutableList(Groups.player).stream() - .map(Player::plainName) - .map(Suggestion::simple) - .toList(), - Core.app::post); + return (SuggestionProvider) PlayerParser.SUGGESTION_PROVIDER; } } diff --git a/distributor-common/src/main/java/com/xpdustry/distributor/core/player/SimplePlayerLookup.java b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/parser/PlayerLookup.java similarity index 65% rename from distributor-common/src/main/java/com/xpdustry/distributor/core/player/SimplePlayerLookup.java rename to distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/parser/PlayerLookup.java index e7b711d8..00335d21 100644 --- a/distributor-common/src/main/java/com/xpdustry/distributor/core/player/SimplePlayerLookup.java +++ b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/parser/PlayerLookup.java @@ -16,37 +16,27 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.xpdustry.distributor.core.player; +package com.xpdustry.distributor.command.cloud.parser; -import arc.Core; import arc.util.Strings; import com.xpdustry.distributor.core.collection.ArcCollections; +import com.xpdustry.distributor.core.player.MUUID; import java.text.Normalizer; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Set; -import java.util.concurrent.CompletableFuture; import mindustry.Vars; import mindustry.gen.Groups; import mindustry.gen.Player; import mindustry.net.Administration; -final class SimplePlayerLookup implements PlayerLookup { +final class PlayerLookup { - static final SimplePlayerLookup INSTANCE = new SimplePlayerLookup(); - - /** - * Finds online players their its name, UUID or entity ID. - * - * @param query the query - * @param admin whether the query should also search by sensitive IDs such as MUUID - * @return the list player of matching players - */ - @Override - public List findOnlinePlayers(final String query, final boolean admin) { + public static Collection findOnlinePlayers(final String query, final boolean admin) { if (query.startsWith("#")) { final var id = Strings.parseInt(query.substring(1), -1); final var players = ArcCollections.immutableList(Groups.player).stream() @@ -83,24 +73,18 @@ public List findOnlinePlayers(final String query, final boolean admin) { return matches == 1 ? Collections.singletonList(match) : Collections.unmodifiableList(result); } - @Override - public CompletableFuture> findOfflinePlayers( - final String query, final boolean admin) { - return CompletableFuture.supplyAsync( - () -> { - final Set result = new LinkedHashSet<>(); - for (final var online : findOnlinePlayers(query, admin)) { - result.add(online.getInfo()); - } - if (admin && MUUID.isUuid(query)) { - final var info = Vars.netServer.admins.getInfoOptional(query); - if (info != null) { - result.add(info); - } - } - return List.copyOf(result); - }, - Core.app::post); + static Collection findOfflinePlayers(final String query, final boolean admin) { + final Set result = new LinkedHashSet<>(); + for (final var online : findOnlinePlayers(query, admin)) { + result.add(online.getInfo()); + } + if (admin && MUUID.isUuid(query)) { + final var info = Vars.netServer.admins.getInfoOptional(query); + if (info != null) { + result.add(info); + } + } + return Collections.unmodifiableSet(result); } // https://stackoverflow.com/a/4122207 diff --git a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/parser/PlayerParser.java b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/parser/PlayerParser.java index c3431b03..260bc3ef 100644 --- a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/parser/PlayerParser.java +++ b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/command/cloud/parser/PlayerParser.java @@ -19,9 +19,8 @@ package com.xpdustry.distributor.command.cloud.parser; import arc.Core; -import com.xpdustry.distributor.core.DistributorProvider; +import com.xpdustry.distributor.command.cloud.ArcCommandContextKeys; import com.xpdustry.distributor.core.collection.ArcCollections; -import com.xpdustry.distributor.core.player.PlayerLookup; import java.util.concurrent.CompletableFuture; import mindustry.gen.Groups; import mindustry.gen.Player; @@ -37,6 +36,13 @@ public final class PlayerParser implements ArgumentParser { + static SuggestionProvider SUGGESTION_PROVIDER = (ctx, input) -> CompletableFuture.supplyAsync( + () -> ArcCollections.immutableList(Groups.player).stream() + .map(Player::plainName) + .map(Suggestion::simple) + .toList(), + Core.app::post); + public static ParserDescriptor playerParser() { return ParserDescriptor.of(new PlayerParser<>(), Player.class); } @@ -48,16 +54,14 @@ public static CommandComponent.Builder playerComponent() { @Override public ArgumentParseResult parse(final CommandContext ctx, final CommandInput input) { final var query = input.readString(); - final var result = DistributorProvider.get() - .getService(PlayerLookup.class) - .orElseThrow() - .findOnlinePlayers(query, true); - if (result.isEmpty()) { + final var players = + PlayerLookup.findOnlinePlayers(query, ctx.getOrDefault(ArcCommandContextKeys.MINDUSTRY_ADMIN, false)); + if (players.isEmpty()) { return ArgumentParseResult.failure(new PlayerParseException.PlayerNotFound(PlayerParser.class, query, ctx)); - } else if (result.size() > 1) { + } else if (players.size() > 1) { return ArgumentParseResult.failure(new PlayerParseException.TooManyPlayers(PlayerParser.class, query, ctx)); } else { - return ArgumentParseResult.success(result.get(0)); + return ArgumentParseResult.success(players.iterator().next()); } } @@ -67,13 +71,9 @@ public ArgumentParseResult parse(final CommandContext ctx, final Comm return CompletableFuture.supplyAsync(() -> this.parse(ctx, input), Core.app::post); } + @SuppressWarnings("unchecked") @Override public @NonNull SuggestionProvider suggestionProvider() { - return (ctx, input) -> CompletableFuture.supplyAsync( - () -> ArcCollections.immutableList(Groups.player).stream() - .map(Player::plainName) - .map(Suggestion::simple) - .toList(), - Core.app::post); + return (SuggestionProvider) SUGGESTION_PROVIDER; } } diff --git a/distributor-common/src/main/java/com/xpdustry/distributor/core/command/CommandSender.java b/distributor-common/src/main/java/com/xpdustry/distributor/core/command/CommandSender.java index 651dcfd0..142880ac 100644 --- a/distributor-common/src/main/java/com/xpdustry/distributor/core/command/CommandSender.java +++ b/distributor-common/src/main/java/com/xpdustry/distributor/core/command/CommandSender.java @@ -37,6 +37,11 @@ public boolean isPlayer() { public boolean isServer() { return false; } + + @Override + public Player getPlayer() { + throw new UnsupportedOperationException(); + } }; } @@ -51,10 +56,17 @@ public boolean isPlayer() { public boolean isServer() { return true; } + + @Override + public Player getPlayer() { + throw new UnsupportedOperationException(); + } }; } boolean isPlayer(); boolean isServer(); + + Player getPlayer(); } diff --git a/distributor-common/src/main/java/com/xpdustry/distributor/core/player/PlayerLookup.java b/distributor-common/src/main/java/com/xpdustry/distributor/core/player/PlayerLookup.java deleted file mode 100644 index 6425f5ee..00000000 --- a/distributor-common/src/main/java/com/xpdustry/distributor/core/player/PlayerLookup.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Distributor, a feature-rich framework for Mindustry plugins. - * - * Copyright (C) 2024 Xpdustry - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.xpdustry.distributor.core.player; - -import java.util.List; -import java.util.concurrent.CompletableFuture; -import mindustry.gen.Player; -import mindustry.net.Administration; - -public interface PlayerLookup { - - static PlayerLookup simple() { - return SimplePlayerLookup.INSTANCE; - } - - List findOnlinePlayers(final String query, final boolean admin); - - CompletableFuture> findOfflinePlayers(final String query, final boolean admin); -}