Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tweak flags & gamemodes, add gamemode to votebook #1210

Merged
merged 1 commit into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 31 additions & 36 deletions core/src/main/java/tc/oc/pgm/api/map/MapTag.java
Original file line number Diff line number Diff line change
@@ -1,53 +1,51 @@
package tc.oc.pgm.api.map;

import static net.kyori.adventure.text.Component.empty;
import static net.kyori.adventure.text.Component.text;
import static tc.oc.pgm.util.Assert.assertNotNull;
import static tc.oc.pgm.util.Assert.assertTrue;

import java.util.Collections;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.regex.Pattern;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;

/** A "#hashtag" that describes a {@link MapInfo} feature. */
public final class MapTag implements Comparable<MapTag> {
private static final SortedSet<String> TAG_IDS = new TreeSet<>();

private static final Pattern PATTERN = Pattern.compile("^[a-z0-9_-]+$");
private static final String SYMBOL = "#";

private final String id;
private final Component name;
private final Component acronym;
private final boolean gamemode;
private final @Nullable Gamemode gamemode;
private final boolean auxiliary;

public MapTag(
final String id, final String name, final boolean gamemode, final boolean auxiliary) {
this(id, id, name, gamemode, auxiliary);
public MapTag(String id, String name) {
this(id, name, null, true);
}

public MapTag(String id, Gamemode gm, boolean auxiliary) {
this(id, gm.getFullName(), gm, auxiliary);
}

public MapTag(
final String internalId,
final String id,
final String name,
final boolean gamemode,
final boolean auxiliary) {
assertTrue(
PATTERN.matcher(assertNotNull(id)).matches(), name + " must match " + PATTERN.pattern());
private MapTag(String id, String name, @Nullable Gamemode gamemode, boolean auxiliary) {
assertNotNull(id);
assertTrue(PATTERN.matcher(id).matches(), id + " must match " + PATTERN.pattern());
TAG_IDS.add(id);
this.id = id;
if (gamemode) {
Gamemode gm = Gamemode.byId(internalId);
if (gm == null) {
throw new IllegalArgumentException("Gamemode id " + internalId + " not recognized");
}
this.name = text(gm.getFullName());
this.acronym = text(gm.getAcronym());
} else {
this.name = text(name);
this.acronym = empty();
}
this.name = text(name);
this.gamemode = gamemode;
this.auxiliary = auxiliary;
}

public static Set<String> getAllTagIds() {
return Collections.unmodifiableSortedSet(TAG_IDS);
}

/**
* Get a short id for the tag.
*
Expand All @@ -66,26 +64,23 @@ public Component getName() {
return this.name;
}

/**
* Gets an acronym for the tag.
*
* @return An acronym.
*/
public Component getAcronym() {
return this.acronym;
}

/**
* Get whether this tag represents a "gamemode."
*
* @return If a gamemode.
* @return If the tag is for a gamemode.
*/
public boolean isGamemode() {
return this.gamemode != null;
}

/** @return the gamemode if this tag represents one, null otherwise. */
public @Nullable Gamemode getGamemode() {
return this.gamemode;
}

/**
* Get whether this tag is an auxiliary feature.
* Get whether this tag is an auxiliary gamemode, that works as a 2nd level gamemode. Eg: blitz or
* rage are auxiliary due to wool "and blitz", or deathmatch "and rage".
*
* @return If an auxiliary feature.
*/
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/tc/oc/pgm/blitz/BlitzModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.jdom2.Document;
import org.jdom2.Element;
import tc.oc.pgm.api.filter.Filter;
import tc.oc.pgm.api.map.Gamemode;
import tc.oc.pgm.api.map.MapModule;
import tc.oc.pgm.api.map.MapTag;
import tc.oc.pgm.api.map.factory.MapFactory;
Expand All @@ -26,7 +27,7 @@
public class BlitzModule implements MapModule<BlitzMatchModule> {

private static final Collection<MapTag> TAGS =
ImmutableList.of(new MapTag("blitz", "Blitz", true, true));
ImmutableList.of(new MapTag("blitz", Gamemode.BLITZ, true));
private final BlitzConfig config;

public BlitzModule(BlitzConfig config) {
Expand Down
3 changes: 1 addition & 2 deletions core/src/main/java/tc/oc/pgm/classes/ClassModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@

public class ClassModule implements MapModule<ClassMatchModule> {

private static final Collection<MapTag> TAGS =
ImmutableList.of(new MapTag("classes", "Classes", false, true));
private static final Collection<MapTag> TAGS = ImmutableList.of(new MapTag("classes", "Classes"));
final String family;
final Map<String, PlayerClass> classes;
final PlayerClass defaultClass;
Expand Down
20 changes: 19 additions & 1 deletion core/src/main/java/tc/oc/pgm/command/MapCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import cloud.commandframework.annotations.Flag;
import cloud.commandframework.annotations.specifier.Greedy;
import cloud.commandframework.annotations.specifier.Range;
import cloud.commandframework.annotations.suggestions.Suggestions;
import cloud.commandframework.context.CommandContext;
import com.google.common.collect.ImmutableList;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
Expand All @@ -36,6 +38,7 @@
import tc.oc.pgm.rotation.MapPoolManager;
import tc.oc.pgm.rotation.pools.MapPool;
import tc.oc.pgm.util.Audience;
import tc.oc.pgm.util.LiquidMetal;
import tc.oc.pgm.util.PrettyPaginatedComponentResults;
import tc.oc.pgm.util.StringUtils;
import tc.oc.pgm.util.named.MapNameStyle;
Expand All @@ -52,7 +55,8 @@ public void maps(
CommandSender sender,
MapLibrary library,
@Argument(value = "page", defaultValue = "1") @Range(min = "1") int page,
@Flag(value = "tags", aliases = "t", repeatable = true) List<String> tags,
@Flag(value = "tags", aliases = "t", repeatable = true, suggestions = "maptags")
List<String> tags,
@Flag(value = "author", aliases = "a") String author,
@Flag(value = "name", aliases = "n") String name,
@Flag(value = "phase", aliases = "p") Phase phase) {
Expand Down Expand Up @@ -115,6 +119,20 @@ public Component format(MapInfo map, int index) {
}.display(audience, ImmutableList.copyOf(maps), page);
}

@Suggestions("maptags")
public List<String> suggestMapTags(CommandContext<CommandSender> 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<String> posTags, Collection<String> negTags) {
int matches = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.jdom2.Document;
import org.jdom2.Element;
import tc.oc.pgm.api.PGM;
import tc.oc.pgm.api.map.Gamemode;
import tc.oc.pgm.api.map.MapModule;
import tc.oc.pgm.api.map.MapTag;
import tc.oc.pgm.api.map.factory.MapFactory;
Expand All @@ -27,11 +28,9 @@

public class ControlPointModule implements MapModule<ControlPointMatchModule> {

private static final MapTag CP =
new MapTag("cp", "controlpoint", "Control the Point", true, false);
private static final MapTag KOTH =
new MapTag("koth", "controlpoint", "King of the Hill", true, false);
private static final MapTag PAYLOAD = new MapTag("payload", "Payload", true, false);
private static final MapTag CP = new MapTag("controlpoint", Gamemode.CONTROL_THE_POINT, false);
private static final MapTag KOTH = new MapTag("controlpoint", Gamemode.KING_OF_THE_HILL, false);
private static final MapTag PAYLOAD = new MapTag("payload", Gamemode.PAYLOAD, false);

private final List<ControlPointDefinition> definitions;
private final Collection<MapTag> tags;
Expand Down Expand Up @@ -94,7 +93,8 @@ public ControlPointModule parse(MapFactory factory, Logger logger, Document doc)

for (Element kingEl : doc.getRootElement().getChildren("king")) {
for (Element hillEl : XMLUtils.flattenElements(kingEl, "hills", "hill")) {
tags.add(KOTH);
// CP and KOTH are mutually exclusive, they're the same ID.
if (tags.isEmpty()) tags.add(KOTH);
ControlPointDefinition definition =
ControlPointParser.parseControlPoint(factory, hillEl, Type.HILL, serialNumber);
factory.getFeatures().addFeature(kingEl, definition);
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/tc/oc/pgm/core/CoreModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.jdom2.Attribute;
import org.jdom2.Document;
import org.jdom2.Element;
import tc.oc.pgm.api.map.Gamemode;
import tc.oc.pgm.api.map.MapModule;
import tc.oc.pgm.api.map.MapProtos;
import tc.oc.pgm.api.map.MapTag;
Expand All @@ -38,7 +39,7 @@
public class CoreModule implements MapModule<CoreMatchModule> {

private static final Collection<MapTag> TAGS =
ImmutableList.of(new MapTag("dtc", "core", "Destroy the Core", true, false));
ImmutableList.of(new MapTag("core", Gamemode.DESTROY_THE_CORE, false));
protected final List<CoreFactory> coreFactories;

public CoreModule(List<CoreFactory> coreFactories) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.logging.Logger;
import org.jdom2.Document;
import org.jdom2.Element;
import tc.oc.pgm.api.map.Gamemode;
import tc.oc.pgm.api.map.MapModule;
import tc.oc.pgm.api.map.MapProtos;
import tc.oc.pgm.api.map.MapTag;
Expand Down Expand Up @@ -37,7 +38,7 @@
public class DestroyableModule implements MapModule<DestroyableMatchModule> {

private static final Collection<MapTag> TAGS =
ImmutableList.of(new MapTag("dtm", "monument", "Destroy the Monument", true, false));
ImmutableList.of(new MapTag("monument", Gamemode.DESTROY_THE_MONUMENT, false));
protected final List<DestroyableFactory> destroyableFactories;

public DestroyableModule(List<DestroyableFactory> destroyableFactories) {
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/tc/oc/pgm/ffa/FreeForAllModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.jdom2.Document;
import org.jdom2.Element;
import tc.oc.pgm.api.PGM;
import tc.oc.pgm.api.map.Gamemode;
import tc.oc.pgm.api.map.MapModule;
import tc.oc.pgm.api.map.MapTag;
import tc.oc.pgm.api.map.factory.MapFactory;
Expand All @@ -24,7 +25,7 @@
public class FreeForAllModule implements MapModule<FreeForAllMatchModule> {

private static final Collection<MapTag> TAGS =
ImmutableList.of(new MapTag("ffa", "Free for All", false, false));
ImmutableList.of(new MapTag("ffa", Gamemode.FREE_FOR_ALL, true));
private final FreeForAllOptions options;

public FreeForAllModule(FreeForAllOptions options) {
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/tc/oc/pgm/flag/FlagModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.List;
import java.util.logging.Logger;
import org.jdom2.Document;
import tc.oc.pgm.api.map.Gamemode;
import tc.oc.pgm.api.map.MapModule;
import tc.oc.pgm.api.map.MapTag;
import tc.oc.pgm.api.map.factory.MapFactory;
Expand All @@ -22,7 +23,7 @@
public class FlagModule implements MapModule<FlagMatchModule> {

private static final Collection<MapTag> TAGS =
ImmutableList.of(new MapTag("ctf", "flag", "Capture the Flag", true, false));
ImmutableList.of(new MapTag("flag", Gamemode.CAPTURE_THE_FLAG, false));
private final ImmutableList<PostDefinition> posts;
private final ImmutableList<NetDefinition> nets;
private final ImmutableList<FlagDefinition> flags;
Expand Down
28 changes: 2 additions & 26 deletions core/src/main/java/tc/oc/pgm/map/MapContextImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,24 @@

import static tc.oc.pgm.util.Assert.assertNotNull;

import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import java.lang.ref.SoftReference;
import java.util.Collection;
import java.util.List;
import tc.oc.pgm.api.map.MapContext;
import tc.oc.pgm.api.map.MapInfo;
import tc.oc.pgm.api.map.MapModule;
import tc.oc.pgm.api.map.MapTag;
import tc.oc.pgm.ffa.FreeForAllModule;
import tc.oc.pgm.teams.TeamFactory;
import tc.oc.pgm.teams.TeamModule;

public class MapContextImpl implements MapContext {
private static final MapTag TERRAIN = new MapTag("terrain", "Terrain", false, true);

private final MapInfo info;
private final List<MapModule> modules;

public MapContextImpl(MapInfoImpl info, Collection<MapModule<?>> modules) {
info.context = new SoftReference<>(this);
this.info = info;
this.modules = ImmutableList.copyOf(assertNotNull(modules));

for (MapModule<?> module : this.modules) {
info.tags.addAll(module.getTags());

if (module instanceof TeamModule) {
info.players.clear();
info.players.addAll(
Collections2.transform(((TeamModule) module).getTeams(), TeamFactory::getMaxPlayers));
}

if (module instanceof FreeForAllModule) {
info.players.clear();
info.players.add(((FreeForAllModule) module).getOptions().maxPlayers);
}
}

if (info.getWorld().hasTerrain()) {
info.tags.add(TERRAIN);
}
// Update the map info with stuff derived from modules, like team sizes or tags.
info.setContext(this);
}

public MapInfo getInfo() {
Expand Down
Loading