package net.anxuiz.tourney.command; import java.util.Arrays; import javax.inject.Inject; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.google.common.util.concurrent.ListenableFuture; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.minecraft.util.commands.Console; import com.sk89q.minecraft.util.commands.SuggestException; import net.anxuiz.tourney.TeamManager; import net.anxuiz.tourney.Tourney; import net.anxuiz.tourney.TourneyState; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.TranslatableComponent; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import tc.oc.api.bukkit.users.BukkitUserStore; import tc.oc.api.docs.Entrant; import tc.oc.api.docs.PlayerId; import tc.oc.api.docs.Tournament; import tc.oc.api.docs.team; import tc.oc.api.exceptions.NotFound; import tc.oc.api.tourney.TeamUtils; import tc.oc.api.tourney.TournamentService; import tc.oc.commons.bukkit.chat.Audiences; import tc.oc.commons.bukkit.chat.Paginator; import tc.oc.commons.bukkit.chat.PlayerComponent; import tc.oc.commons.bukkit.chat.WarningComponent; import tc.oc.commons.bukkit.nick.IdentityProvider; import tc.oc.minecraft.scheduler.MainThreadExecutor; import tc.oc.commons.core.chat.Audience; import tc.oc.commons.core.chat.Component; import tc.oc.commons.core.commands.CommandFutureCallback; import tc.oc.commons.core.commands.NestedCommands; import tc.oc.commons.core.commands.TranslatableCommandException; import tc.oc.commons.core.formatting.StringUtils; import tc.oc.pgm.match.inject.MatchScoped; import tc.oc.pgm.teams.Team; import tc.oc.pgm.teams.TeamCommandUtils; @MatchScoped public class TeamCommands implements NestedCommands { private final BukkitUserStore userStore; private final Tournament tournament; private final BaseComponent tournamentName; private final TournamentService tournamentService; private final Audiences audiences; private final Tourney tourney; private final TeamManager teamManager; private final TeamCommandUtils teamCommandUtils; private final IdentityProvider identityProvider; private final MainThreadExecutor mainThread; @Inject TeamCommands(Tournament tournament, BukkitUserStore userStore, TournamentService tournamentService, Audiences audiences, Tourney tourney, TeamManager teamManager, TeamCommandUtils teamCommandUtils, IdentityProvider identityProvider, MainThreadExecutor mainThread) { this.tournament = tournament; this.tournamentName = new Component(tournament.name(), ChatColor.GREEN); this.userStore = userStore; this.tournamentService = tournamentService; this.audiences = audiences; this.tourney = tourney; this.teamManager = teamManager; this.teamCommandUtils = teamCommandUtils; this.identityProvider = identityProvider; this.mainThread = mainThread; } private BaseComponent teamName(team.Id team) { return new Component(team.name(), ChatColor.YELLOW); } private BaseComponent teamName(Entrant entrant) { return teamName(entrant.team()); } private team.Id findTeam(String name) throws CommandException { return StringUtils.fuzzyMatch(TeamUtils.normalizeName(name), Maps.uniqueIndex(tournament.accepted_teams(), team.Id::name_normalized), 0.9) .orElseThrow(() -> new TranslatableCommandException("tourney.team.notFound", tournamentName, name)); } private team.Id teamArgument(CommandContext args, int index) throws SuggestException, CommandException { return findTeam(args.joinedStrings(index, tournament.acceptedTeamNames())); } @Command( aliases = {"roster", "players"}, usage = "[team]", desc = "Lists the players on a specified team.", flags = "p:", min = 0, max = -1 ) @Console @CommandPermissions("tourney.roster") public void roster(final CommandContext args, final CommandSender sender) throws CommandException, SuggestException { final int page = args.getFlagInteger('p', 1); final ListenableFuture<Entrant> futureEntrant; if(args.argsLength() > 0) { futureEntrant = tournamentService.entrant(tournament, teamArgument(args, 0)); } else if(sender instanceof Player) { futureEntrant = tournamentService.entrantByMember(tournament, userStore.playerId((Player) sender)); } else { throw new TranslatableCommandException("tourney.team.notSpecified"); } final Audience audience = audiences.get(sender); mainThread.callback( futureEntrant, CommandFutureCallback.<Entrant>onSuccess(sender, args, entrant -> { new Paginator<PlayerId>() .title(new TranslatableComponent("tourney.team.roster.title", tournamentName, teamName(entrant))) .entries((playerId, index) -> new Component(new PlayerComponent(identityProvider.createIdentity(playerId))) .bold(index == 0)) // Team leader is always first .display(audience, entrant.members(), page); }).onFailure(NotFound.class, notFound -> { audience.sendMessage(new WarningComponent("tourney.team.notOnAnyTeam")); }) ); } @Command( aliases = {"teams", "listteams"}, desc = "Lists the teams registered for competition on this server.", min = 0, max = 1, usage = "[page]" ) @Console @CommandPermissions("tourney.listteams") public void listTeams(final CommandContext args, final CommandSender sender) throws CommandException { new Paginator<team.Id>() .title(new TranslatableComponent("tourney.teams.title", tournamentName)) .entries((team, index) -> teamName(team)) .display(audiences.get(sender), tournament.accepted_teams(), args.getInteger(0, 1)); } @Command( aliases = {"register", "whitelist", "add"}, desc = "Registers a team for competition.", help = "Registers the specified team, entering them into the competition.", max = -1, min = 1, flags = "t:", usage = "[-t <map team>] <tournament team>" ) @Console @CommandPermissions("tourney.addteam") public void register(final CommandContext args, final CommandSender sender) throws CommandException, SuggestException { if(!Arrays.asList(TourneyState.DISABLED, TourneyState.ENABLED_WAITING_FOR_TEAMS).contains(tourney.getState())) { throw new TranslatableCommandException("tourney.team.cannotRegister"); } final Audience audience = audiences.get(sender); final Team matchTeam = teamCommandUtils.teamFlag(args, 't').orElse(null); final team.Id team = teamArgument(args, 0); mainThread.callback( tournamentService.entrant(tournament, team), CommandFutureCallback.onSuccess(sender, args, entrant -> { Team assignedTeam = teamManager.entrantToTeam(entrant); if(assignedTeam != null) { throw new TranslatableCommandException( "tourney.team.alreadyRegistered", tournamentName, teamName(entrant), assignedTeam.getComponentName() ); } assignedTeam = teamManager.assignEntrant(entrant, matchTeam); if(assignedTeam == null) { throw new TranslatableCommandException("tourney.team.cannotRegister"); } audience.sendMessage(new TranslatableComponent( "tourney.team.registered", tournamentName, new Component(entrant.team().name(), ChatColor.YELLOW), assignedTeam.getDefinition().getComponentName() )); }) ); } @Command( aliases = {"unregister", "remove"}, desc = "Un-registers a team from competition.", help = "Un-registers the specified team, ejecting them from the competition.", max = -1, min = 1, usage = "<team>" ) @Console @CommandPermissions("tourney.removeteam") public void unregister(final CommandContext args, final CommandSender sender) throws CommandException, SuggestException { if(!Arrays.asList(TourneyState.DISABLED, TourneyState.ENABLED_WAITING_FOR_TEAMS).contains(tourney.getState())) { throw new TranslatableCommandException("tourney.team.cannotUnregister"); } final Audience audience = audiences.get(sender); final String teamName = args.joinedStrings(0, Iterables.transform(teamManager.mappedTeams().values(), entrant -> entrant.team().name())); final Entrant entrant = teamManager.getEntrant(teamName); if(entrant == null) { throw new TranslatableCommandException("tourney.team.notFound", tournamentName, teamName); } if(teamManager.unmap(entrant)) { audience.sendMessage(new TranslatableComponent("tourney.team.unregistered", tournamentName, teamName(entrant))); } else { throw new TranslatableCommandException("tourney.team.cannotUnregister"); } } }