diff --git a/pom.xml b/pom.xml
index 51c6277f..207e05df 100644
--- a/pom.xml
+++ b/pom.xml
@@ -115,7 +115,7 @@
cloud.commandframework
cloud-annotations
- 1.7.1
+ 1.8.2
diff --git a/src/main/java/dev/pgm/community/requests/commands/SponsorCommands.java b/src/main/java/dev/pgm/community/requests/commands/SponsorCommands.java
index c96e0c72..7459ed79 100644
--- a/src/main/java/dev/pgm/community/requests/commands/SponsorCommands.java
+++ b/src/main/java/dev/pgm/community/requests/commands/SponsorCommands.java
@@ -3,10 +3,10 @@
import static net.kyori.adventure.text.Component.empty;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.Component.translatable;
+import static tc.oc.pgm.util.Assert.assertNotNull;
import static tc.oc.pgm.util.player.PlayerComponent.player;
import static tc.oc.pgm.util.text.TemporalComponent.duration;
-import com.google.common.collect.Sets;
import dev.pgm.community.Community;
import dev.pgm.community.CommunityCommand;
import dev.pgm.community.requests.RequestConfig;
@@ -20,9 +20,16 @@
import dev.pgm.community.utils.PGMUtils;
import dev.pgm.community.utils.PaginatedComponentResults;
import dev.pgm.community.utils.VisibilityUtils;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
import java.util.Queue;
import java.util.Set;
+import java.util.TreeSet;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.event.ClickEvent;
@@ -33,12 +40,19 @@
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import tc.oc.pgm.api.PGM;
+import tc.oc.pgm.api.map.Contributor;
import tc.oc.pgm.api.map.MapInfo;
+import tc.oc.pgm.api.map.MapTag;
import tc.oc.pgm.api.map.Phase;
import tc.oc.pgm.lib.cloud.commandframework.annotations.Argument;
import tc.oc.pgm.lib.cloud.commandframework.annotations.CommandDescription;
import tc.oc.pgm.lib.cloud.commandframework.annotations.CommandMethod;
+import tc.oc.pgm.lib.cloud.commandframework.annotations.Flag;
import tc.oc.pgm.lib.cloud.commandframework.annotations.specifier.Greedy;
+import tc.oc.pgm.lib.cloud.commandframework.annotations.suggestions.Suggestions;
+import tc.oc.pgm.lib.cloud.commandframework.context.CommandContext;
+import tc.oc.pgm.util.LiquidMetal;
+import tc.oc.pgm.util.StringUtils;
import tc.oc.pgm.util.named.MapNameStyle;
import tc.oc.pgm.util.named.NameStyle;
import tc.oc.pgm.util.text.TextFormatter;
@@ -216,13 +230,41 @@ public void menu(CommandAudience audience, Player sender) {
@CommandMethod("maps [page]")
@CommandDescription("View a list of maps which can be sponsored")
public void viewMapList(
- CommandAudience audience, @Argument(value = "page", defaultValue = "1") int page) {
- Set maps =
- Sets.newHashSet(PGM.get().getMapLibrary().getMaps()).stream()
+ CommandAudience audience,
+ @Argument(value = "page", defaultValue = "1") int page,
+ @Flag(value = "tags", aliases = "t", repeatable = true, suggestions = "maptags")
+ List tags,
+ @Flag(value = "author", aliases = "a") String author,
+ @Flag(value = "name", aliases = "n") String name) {
+ Stream search =
+ PGM.get()
+ .getMapLibrary()
+ .getMaps(name)
.filter(PGMUtils::isMapSizeAllowed)
.filter(m -> m.getPhase() != Phase.DEVELOPMENT)
- .filter(m -> !requests.hasMapCooldown(m))
- .collect(Collectors.toSet());
+ .filter(m -> !requests.hasMapCooldown(m));
+
+ if (!tags.isEmpty()) {
+ final Map> tagSet =
+ tags.stream()
+ .flatMap(t -> Arrays.stream(t.split(",")))
+ .map(String::toLowerCase)
+ .map(String::trim)
+ .collect(
+ Collectors.partitioningBy(
+ s -> s.startsWith("!"),
+ Collectors.mapping(
+ (String s) -> s.startsWith("!") ? s.substring(1) : s,
+ Collectors.toSet())));
+ search = search.filter(map -> matchesTags(map, tagSet.get(false), tagSet.get(true)));
+ }
+
+ if (author != null) {
+ String query = StringUtils.normalize(author);
+ search = search.filter(map -> matchesAuthor(map, query));
+ }
+
+ Set maps = search.collect(Collectors.toCollection(TreeSet::new));
int resultsPerPage = 8;
int pages = (maps.size() + resultsPerPage - 1) / resultsPerPage;
@@ -300,6 +342,43 @@ public Component formatEmpty() {
}
}
+ @Suggestions("maptags")
+ public List suggestMapTags(CommandContext sender, String input) {
+ int commaIdx = input.lastIndexOf(',');
+
+ final String prefix = input.substring(0, commaIdx == -1 ? 0 : commaIdx + 1);
+ final String toComplete =
+ input.substring(commaIdx + 1).toLowerCase(Locale.ROOT).replace("!", "");
+
+ return MapTag.getAllTagIds().stream()
+ .filter(mt -> LiquidMetal.match(mt, toComplete))
+ .flatMap(tag -> Stream.of(prefix + tag, prefix + "!" + tag))
+ .collect(Collectors.toList());
+ }
+
+ private static boolean matchesTags(
+ MapInfo map, Collection posTags, Collection negTags) {
+ int matches = 0;
+ for (MapTag tag : assertNotNull(map).getTags()) {
+ if (negTags != null && negTags.contains(tag.getId())) {
+ return false;
+ }
+ if (posTags != null && posTags.contains(tag.getId())) {
+ matches++;
+ }
+ }
+ return posTags == null || matches == posTags.size();
+ }
+
+ private static boolean matchesAuthor(MapInfo map, String query) {
+ for (Contributor contributor : map.getAuthors()) {
+ if (StringUtils.normalize(contributor.getNameLegacy()).contains(query)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@CommandMethod("queue [page]")
@CommandDescription("View the sponsored maps queue")
public void viewQueue(
diff --git a/src/main/java/dev/pgm/community/utils/PGMUtils.java b/src/main/java/dev/pgm/community/utils/PGMUtils.java
index a2788070..51fe1c95 100644
--- a/src/main/java/dev/pgm/community/utils/PGMUtils.java
+++ b/src/main/java/dev/pgm/community/utils/PGMUtils.java
@@ -85,7 +85,7 @@ public static boolean isMapSizeAllowed(MapInfo map) {
int max = map.getMaxPlayers().stream().reduce(0, Integer::sum);
int lowerBound = participants;
- int upperBound = total + (int) (total * 0.35);
+ int upperBound = Math.max(5, total + (int) (total * 0.35));
return max >= lowerBound && max <= upperBound;
}