/* * Copyright or © or Copr. Amaury Carrade (2014 - 2016) * * http://amaury.carrade.eu * * This software is governed by the CeCILL-B license under French law and * abiding by the rules of distribution of free software. You can use, * modify and/ or redistribute the software under the terms of the CeCILL-B * license as circulated by CEA, CNRS and INRIA at the following URL * "http://www.cecill.info". * * As a counterpart to the access to the source code and rights to copy, * modify and redistribute granted by the license, users are provided only * with a limited warranty and the software's author, the holder of the * economic rights, and the successive licensors have only limited * liability. * * In this respect, the user's attention is drawn to the risks associated * with loading, using, modifying and/or developing or reproducing the * software by the user in light of its specific status of free software, * that may mean that it is complicated to manipulate, and that also * therefore means that it is reserved for developers and experienced * professionals having in-depth computer knowledge. Users are therefore * encouraged to load and test the software's suitability as regards their * requirements in conditions enabling the security of their systems and/or * data to be ensured and, more generally, to use and operate it in the * same conditions as regards security. * * The fact that you are presently reading this means that you have had * knowledge of the CeCILL-B license and that you accept its terms. */ package eu.carrade.amaury.UHCReloaded.teams; import eu.carrade.amaury.UHCReloaded.UHCReloaded; import eu.carrade.amaury.UHCReloaded.UHConfig; import eu.carrade.amaury.UHCReloaded.utils.ColorsUtils; import eu.carrade.amaury.UHCReloaded.utils.TextUtils; import fr.zcraft.zlib.components.i18n.I; import fr.zcraft.zlib.tools.items.ItemStackBuilder; import fr.zcraft.zlib.tools.items.TextualBanners; import fr.zcraft.zlib.tools.text.ActionBar; import org.apache.commons.lang.Validate; import org.bukkit.ChatColor; import org.bukkit.DyeColor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BannerMeta; import org.bukkit.scoreboard.Scoreboard; import org.bukkit.scoreboard.Team; import java.util.Collections; import java.util.HashSet; import java.util.Random; import java.util.Set; import java.util.UUID; public class UHTeam { private static final boolean BANNER_SHAPE_WRITE_LETTER = UHConfig.TEAMS_OPTIONS.BANNER.SHAPE.WRITE_LETTER.get(); private static final boolean BANNER_SHAPE_ADD_BORDER = UHConfig.TEAMS_OPTIONS.BANNER.SHAPE.ADD_BORDER.get(); private UHCReloaded plugin = UHCReloaded.get(); private String name = null; private String internalName = null; private String displayName = null; private TeamColor color = null; private ItemStack defaultBanner = null; private ItemStack banner = null; private HashSet<UUID> players = new HashSet<>(); public UHTeam(String name, TeamColor color) { Validate.notNull(name, "The name cannot be null."); // We use a random internal name because the name of a team, in Minecraft vanilla, is limited // (16 characters max). Random rand = new Random(); this.internalName = String.valueOf(rand.nextInt(99999999)) + String.valueOf(rand.nextInt(99999999)); Scoreboard sb = this.plugin.getScoreboardManager().getScoreboard(); Team t = sb.registerNewTeam(this.internalName); t.setSuffix(ChatColor.RESET.toString()); t.setCanSeeFriendlyInvisibles(UHConfig.TEAMS_OPTIONS.CAN_SEE_FRIENDLY_INVISIBLES.get()); t.setAllowFriendlyFire(UHConfig.TEAMS_OPTIONS.ALLOW_FRIENDLY_FIRE.get()); setName(name, true); setColor(color); updateDefaultBanner(); } /** * @deprecated Use {@link #UHTeam(String, TeamColor)} instead. */ @Deprecated public UHTeam(String name, TeamColor color, UHCReloaded plugin) { this(name, color); } /** * Returns the name of the team. * * Can include spaces. * * @return The name. */ public String getName() { return name; } public void setName(String name) { setName(name, false); } /** * Changes the name of this team. * * @param name The new name. * @param silent if {@code true}, the players will not be notified. */ public void setName(String name, boolean silent) { if (name == null || (this.name != null && this.name.equals(name))) return; this.name = name; updateDisplayName(); updateDefaultBanner(); plugin.getTeamManager().updateGUIs(); for (Player player : getOnlinePlayers()) { if (!silent) player.sendMessage(I.t("{cs}Your team is now called {0}{cs}.", displayName)); if (UHConfig.BEFORE_START.TEAM_IN_ACTION_BAR.get()) plugin.getTeamManager().displayTeamInActionBar(player, this); } } /** * Returns the display name of the team. * * This name is: * - if the team is uncolored, the name of the team; * - else, the name of the team with: * - before, the color of the team; * - after, the "reset" formatting mark (§r). * * @return The display name. */ public String getDisplayName() { return displayName; } private void updateDisplayName() { displayName = (color != null) ? color.toChatColor() + name + ChatColor.RESET : name; Team t = plugin.getScoreboardManager().getScoreboard().getTeam(internalName); if (t != null) t.setDisplayName(displayName.substring(0, Math.min(displayName.length(), 32))); } /** * Returns the players inside this team. * * @return The players. */ public Set<OfflinePlayer> getPlayers() { HashSet<OfflinePlayer> playersList = new HashSet<>(); for (UUID id : players) { Player player = plugin.getServer().getPlayer(id); if (player != null) { playersList.add(player); } else { playersList.add(plugin.getServer().getOfflinePlayer(id)); } } return playersList; } /** * Returns the online players inside this team. * * @return The online players. */ public Set<Player> getOnlinePlayers() { HashSet<Player> playersList = new HashSet<>(); for (UUID id : players) { Player player = plugin.getServer().getPlayer(id); if (player != null && player.isOnline()) { playersList.add(player); } } return playersList; } /** * Returns the UUIDs of the players inside this team. * * @return The UUIDs of the players. */ @SuppressWarnings ("unchecked") public Set<UUID> getPlayersUUID() { return Collections.unmodifiableSet(players); } /** * Returns the UUIDs of the online players inside this team. * * @return The UUID of the online players. */ public Set<UUID> getOnlinePlayersUUID() { HashSet<UUID> playersList = new HashSet<>(); for (UUID id : players) { Player player = plugin.getServer().getPlayer(id); if (player != null && player.isOnline()) { playersList.add(id); } } return playersList; } /** * Returns the size of this team. * * @return The size. */ public int getSize() { return players.size(); } /** * Returns true if the team is empty. * * @return The emptiness. */ public boolean isEmpty() { return getSize() == 0; } public boolean isFull() { return plugin.getTeamManager().getMaxPlayersPerTeam() != 0 && getSize() >= plugin.getTeamManager().getMaxPlayersPerTeam(); } /** * Adds a player inside this team. * * @param player The player to add. */ public void addPlayer(OfflinePlayer player) { addPlayer(player, false); } /** * Adds a player inside this team. * * @param player The player to add. * @param silent If true, the player will not be notified about this. */ public void addPlayer(OfflinePlayer player, boolean silent) { Validate.notNull(player, "The player cannot be null."); if (plugin.getTeamManager().getMaxPlayersPerTeam() != 0 && this.players.size() >= plugin.getTeamManager().getMaxPlayersPerTeam()) { throw new RuntimeException("The team " + getName() + " is full"); } plugin.getTeamManager().removePlayerFromTeam(player, true); players.add(player.getUniqueId()); plugin.getScoreboardManager().getScoreboard().getTeam(this.internalName).addPlayer(player); plugin.getTeamManager().colorizePlayer(player); plugin.getTeamManager().updateGUIs(); if (player.isOnline()) { if (!silent) ((Player) player).sendMessage(I.t("{aqua}You are now in the {0}{aqua} team.", getDisplayName())); if (UHConfig.BEFORE_START.TEAM_IN_ACTION_BAR.get()) plugin.getTeamManager().displayTeamInActionBar((Player) player, this); } } /** * Removes a player from this team. * * Nothing is done if the player wasn't in this team. * * @param player The player to remove. */ public void removePlayer(OfflinePlayer player) { removePlayer(player, false); } /** * Removes a player from this team. * * Nothing is done if the player wasn't in this team. * * @param player The player to remove. * @param silent If true, the player will not be notified. */ public void removePlayer(OfflinePlayer player, boolean silent) { Validate.notNull(player, "The player cannot be null."); players.remove(player.getUniqueId()); unregisterPlayer(player, silent); plugin.getTeamManager().updateGUIs(); } /** * Unregisters a player from the scoreboard and uncolorizes the pseudo. * * Internal use, avoids a ConcurrentModificationException in this.deleteTeam() * (this.players is listed and emptied simultaneously, else). */ private void unregisterPlayer(OfflinePlayer player, boolean silent) { if (player == null) return; plugin.getScoreboardManager().getScoreboard().getTeam(this.internalName).removePlayer(player); plugin.getTeamManager().colorizePlayer(player); if (player.isOnline()) { if (!silent) ((Player) player).sendMessage(I.t("{darkaqua}You are no longer part of the {0}{darkaqua} team.", getDisplayName())); if (UHConfig.BEFORE_START.TEAM_IN_ACTION_BAR.get()) ActionBar.removeMessage((Player) player, true); } } /** * Deletes this team. * * The players inside the team are left without any team. */ public void deleteTeam() { // We removes the players from the team (scoreboard team too) for (UUID id : players) unregisterPlayer(plugin.getServer().getOfflinePlayer(id), false); players.clear(); // Then the scoreboard team is deleted. plugin.getScoreboardManager().getScoreboard().getTeam(this.internalName).unregister(); } /** * Returns true if the given player is in this team. * * @param player The player to check. * @return true if the given player is in this team. */ public boolean containsPlayer(Player player) { Validate.notNull(player, "The player cannot be null."); return players.contains(player.getUniqueId()); } /** * Returns true if the player with the given UUID is in this team. * * @param id The UUID of the player to check. * @return true if the given player is in this team. */ public boolean containsPlayer(UUID id) { Validate.notNull(id, "The player cannot be null."); return players.contains(id); } /** * Teleports the entire team to the given location. * * @param location The location. */ public void teleportTo(Location location) { Validate.notNull(location, "The location cannot be null."); for (UUID id : players) { Player player = plugin.getServer().getPlayer(id); if (player != null && player.isOnline()) { player.teleport(location, TeleportCause.PLUGIN); } } } /** * @return the color of the team. */ public TeamColor getColor() { return color; } /** * @return the color of the team, or white if the color is set to null. Never returns {@code null}. */ public TeamColor getColorOrWhite() { return color != null ? color : TeamColor.WHITE; } /** * Updates the team color. * * @param color The new color. */ public void setColor(TeamColor color) { // We don't use generateColor directly because we want to keep the "null" color. if (color == TeamColor.RANDOM) this.color = plugin.getTeamManager().generateColor(color); else this.color = color; updateDisplayName(); // The team color needs to be updated if (this.color != null) { Team t = plugin.getScoreboardManager().getScoreboard().getTeam(internalName); if (t != null) t.setPrefix(this.color.toChatColor().toString()); } // The players names too for (Player player : getOnlinePlayers()) { plugin.getTeamManager().colorizePlayer(player); // Also we update the action bar if needed if (UHConfig.BEFORE_START.TEAM_IN_ACTION_BAR.get()) plugin.getTeamManager().displayTeamInActionBar(player, this); } // The default banner too updateDefaultBanner(); plugin.getTeamManager().updateGUIs(); } /** * Generates and return the default banner for this team, following the * banners options in the configuration file. * * @return the generated banner. */ public ItemStack getDefaultBanner() { final ItemStack banner; final DyeColor dye = ColorsUtils.chat2Dye(getColorOrWhite().toChatColor()); if (BANNER_SHAPE_WRITE_LETTER) { banner = TextualBanners.getCharBanner(Character.toUpperCase(TextUtils.getInitialLetter(name)), dye, BANNER_SHAPE_ADD_BORDER); } else { banner = new ItemStack(Material.BANNER); BannerMeta meta = (BannerMeta) banner.getItemMeta(); meta.setBaseColor(dye); banner.setItemMeta(meta); } return banner; } /** * Regenerates the default banner. */ private void updateDefaultBanner() { // Avoid updating in the constructor before all the object is populated. if (name != null) defaultBanner = getDefaultBanner(); else defaultBanner = new ItemStack(Material.BANNER); } /** * Updates this team's banner. * * @param banner The new banner. {@code null} to use the default banner. */ public void setBanner(ItemStack banner) { if (banner == null) { this.banner = null; return; } if (banner.getType() != Material.BANNER) throw new IllegalArgumentException("A banner is required"); this.banner = new ItemStackBuilder(banner.clone()) .title(displayName) .amount(1) .hideAttributes() .item(); if (banner.hasItemMeta()) { BannerMeta meta = (BannerMeta) this.banner.getItemMeta(); meta.setBaseColor(((BannerMeta) banner.getItemMeta()).getBaseColor()); this.banner.setItemMeta(meta); } plugin.getTeamManager().updateGUIs(); } /** * Updates this team's banner. * * @param banner The new banner. {@code null} to use the default banner. */ public void setBanner(BannerMeta banner) { if (banner == null) { this.banner = null; return; } this.banner = new ItemStackBuilder(Material.BANNER) .title(displayName) .amount(1) .hideAttributes() .item(); this.banner.setItemMeta(banner.clone()); plugin.getTeamManager().updateGUIs(); } /** * Returns this team's banner. * * @return the banner. */ public ItemStack getBanner() { return banner == null ? defaultBanner : banner; } @Override public int hashCode() { return ((name == null) ? 0 : name.hashCode()); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof UHTeam)) return false; UHTeam other = (UHTeam) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } }