diff --git a/core/src/main/java/tc/oc/pgm/api/map/Gamemode.java b/core/src/main/java/tc/oc/pgm/api/map/Gamemode.java new file mode 100644 index 0000000000..dc23b8a5a3 --- /dev/null +++ b/core/src/main/java/tc/oc/pgm/api/map/Gamemode.java @@ -0,0 +1,41 @@ +package tc.oc.pgm.api.map; + +public enum Gamemode { + ATTACK_DEFEND("ad"), + ARCADE("arcade"), + BLITZ("blitz"), + BLITZ_RAGE("br"), + CAPTURE_THE_FLAG("ctf"), + CONTROL_THE_POINT("cp"), + CAPTURE_THE_WOOL("ctw"), + DESTROY_THE_CORE("dtc"), + DESTROY_THE_MONUMENT("dtm"), + FREE_FOR_ALL("ffa"), + FLAG_FOOTBALL("ffb"), + KING_OF_THE_HILL("koth"), + KING_OF_THE_FLAG("kotf"), + MIXED("mixed"), + RAGE("rage"), + RACE_FOR_WOOL("rfw"), + SCOREBOX("scorebox"), + DEATHMATCH("tdm"); + + private final String id; + + Gamemode(String id) { + this.id = id; + } + + public static Gamemode byId(String gamemodeId) { + for (Gamemode gamemode : Gamemode.values()) { + if (gamemode.getId().equals(gamemodeId)) { + return gamemode; + } + } + return null; + } + + public String getId() { + return id; + } +} diff --git a/core/src/main/java/tc/oc/pgm/api/map/MapInfo.java b/core/src/main/java/tc/oc/pgm/api/map/MapInfo.java index 4af5210698..3af82a1437 100644 --- a/core/src/main/java/tc/oc/pgm/api/map/MapInfo.java +++ b/core/src/main/java/tc/oc/pgm/api/map/MapInfo.java @@ -109,12 +109,19 @@ default String getStyledNameLegacy(MapNameStyle style, @Nullable CommandSender s Collection getTags(); /** - * Get a {@link Component} that represents this map's gamemode name. + * Get a {@link Component} that represents this map's custom game title. * - * @return A component of the gamemode name if defined or null. + * @return Returns the defined gamemode title, empty if not defined. */ Component getGamemode(); + /** + * Get a {@link Collection} that represents this map's gamemodes. + * + * @return A Collection of gamemodes if defined or null. + */ + Collection getGamemodes(); + /** * Get the maximum number of players that can participate on each team. * diff --git a/core/src/main/java/tc/oc/pgm/map/MapInfoImpl.java b/core/src/main/java/tc/oc/pgm/map/MapInfoImpl.java index 70e6b5afb7..f88fe9a7c3 100644 --- a/core/src/main/java/tc/oc/pgm/map/MapInfoImpl.java +++ b/core/src/main/java/tc/oc/pgm/map/MapInfoImpl.java @@ -16,6 +16,7 @@ import org.bukkit.Difficulty; import org.jdom2.Element; import tc.oc.pgm.api.map.Contributor; +import tc.oc.pgm.api.map.Gamemode; import tc.oc.pgm.api.map.MapInfo; import tc.oc.pgm.api.map.MapTag; import tc.oc.pgm.api.map.Phase; @@ -47,6 +48,7 @@ public class MapInfoImpl implements MapInfo { protected final Collection tags; protected final Collection players; + protected final Collection gamemodes; public MapInfoImpl( @Nullable String id, @@ -63,6 +65,7 @@ public MapInfoImpl( @Nullable Collection players, @Nullable WorldInfo world, @Nullable Component gamemode, + @Nullable Collection gamemodes, Phase phase) { this.name = checkNotNull(name); this.id = checkNotNull(MapInfo.normalizeName(id == null ? name : id)); @@ -78,6 +81,7 @@ public MapInfoImpl( this.players = players == null ? new LinkedList<>() : players; this.world = world == null ? new WorldInfoImpl() : world; this.gamemode = gamemode; + this.gamemodes = gamemodes; this.phase = phase; } @@ -97,6 +101,7 @@ public MapInfoImpl(MapInfo info) { info.getMaxPlayers(), info.getWorld(), info.getGamemode(), + info.getGamemodes(), info.getPhase()); } @@ -121,6 +126,7 @@ public MapInfoImpl(Element root) throws InvalidXMLException { null, parseWorld(root), XMLUtils.parseFormattedText(root, "game"), + parseGamemodes(root), XMLUtils.parseEnum( Node.fromLastChildOrAttr(root, "phase"), Phase.class, "phase", Phase.PRODUCTION)); } @@ -190,6 +196,11 @@ public Component getGamemode() { return gamemode; } + @Override + public Collection getGamemodes() { + return gamemodes; + } + @Override public WorldInfo getWorld() { return world; @@ -255,6 +266,16 @@ private static List parseRules(Element root) { return rules; } + private static List parseGamemodes(Element root) throws InvalidXMLException { + List gamemodes = new ArrayList<>(); + for (Element gamemodeEl : root.getChildren("gamemode")) { + Gamemode gm = Gamemode.byId(gamemodeEl.getText()); + if (gm == null) throw new InvalidXMLException("Unknown gamemode", gamemodeEl); + gamemodes.add(gm); + } + return gamemodes; + } + private static List parseContributors(Element root, String tag) throws InvalidXMLException { List contributors = null; diff --git a/core/src/main/java/tc/oc/pgm/scoreboard/SidebarMatchModule.java b/core/src/main/java/tc/oc/pgm/scoreboard/SidebarMatchModule.java index 94373e494e..12ad246d06 100644 --- a/core/src/main/java/tc/oc/pgm/scoreboard/SidebarMatchModule.java +++ b/core/src/main/java/tc/oc/pgm/scoreboard/SidebarMatchModule.java @@ -1,5 +1,6 @@ package tc.oc.pgm.scoreboard; +import static net.kyori.adventure.text.Component.text; import static net.kyori.adventure.text.Component.translatable; import com.google.common.collect.ImmutableList; @@ -18,6 +19,7 @@ import java.util.UUID; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import javax.annotation.Nullable; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -30,6 +32,7 @@ import org.bukkit.event.Listener; import tc.oc.pgm.api.Config; import tc.oc.pgm.api.PGM; +import tc.oc.pgm.api.map.Gamemode; import tc.oc.pgm.api.map.MapInfo; import tc.oc.pgm.api.map.MapTag; import tc.oc.pgm.api.match.Match; @@ -258,9 +261,19 @@ private Component renderTitle(final Config config, final MapInfo map) { return header.colorIfAbsent(NamedTextColor.AQUA); } - final Component game = map.getGamemode(); - if (game != null) { - return game.colorIfAbsent(NamedTextColor.AQUA); + final Component gamemode = map.getGamemode(); + if (gamemode != null) { + return gamemode.colorIfAbsent(NamedTextColor.AQUA); + } + + final Collection gamemodes = map.getGamemodes(); + if (!gamemodes.isEmpty()) { + String suffix = gamemodes.size() <= 1 ? ".name" : ".acronym"; + List gmComponents = + gamemodes.stream() + .map(gm -> translatable("gamemode." + gm.getId() + suffix)) + .collect(Collectors.toList()); + return TextFormatter.list(gmComponents, NamedTextColor.AQUA); } final List games = new LinkedList<>(); diff --git a/util/src/main/i18n/templates/gamemode.properties b/util/src/main/i18n/templates/gamemode.properties index 6c0a6e7aff..a560521510 100644 --- a/util/src/main/i18n/templates/gamemode.properties +++ b/util/src/main/i18n/templates/gamemode.properties @@ -8,6 +8,10 @@ gamemode.ctw.name = Capture the Wool gamemode.ctf.name = Capture the Flag +gamemode.ffb.name = Flag Football + +gamemode.kotf.name = King of the Flag + gamemode.tdm.name = Deathmatch gamemode.ad.name = Attack/Defend @@ -20,6 +24,10 @@ gamemode.blitz.name = Blitz gamemode.rage.name = Rage +gamemode.br.name = Blitz: Rage + +gamemode.rfw.name = Race for Wool + gamemode.scorebox.name = Scorebox gamemode.arcade.name = Arcade @@ -36,18 +44,26 @@ gamemode.ctw.acronym = CTW gamemode.ctf.acronym = CTF +gamemode.ffb.acronym = FFB + +gamemode.kotf.acronym = KotF + gamemode.tdm.acronym = TDM gamemode.ad.acronym = A/D gamemode.cp.acronym = CP -gamemode.koth.acronym = KoTH +gamemode.koth.acronym = KotH gamemode.blitz.acronym = Blitz gamemode.rage.acronym = Rage +gamemode.br.acronym = Blitz: Rage + +gamemode.rfw.acronym = RFW + gamemode.scorebox.acronym = Scorebox gamemode.arcade.acronym = Arcade