/* * This file is part of NucleusFramework for Bukkit, licensed under the MIT License (MIT). * * Copyright (c) JCThePants (www.jcwhatever.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.jcwhatever.nucleus.utils.player; import com.jcwhatever.nucleus.Nucleus; import com.jcwhatever.nucleus.internal.InternalPlayerTracker; import com.jcwhatever.nucleus.mixins.IPlayerReference; import com.jcwhatever.nucleus.providers.npc.Npcs; import com.jcwhatever.nucleus.utils.PreCon; import com.jcwhatever.nucleus.utils.inventory.InventoryUtils; import com.jcwhatever.nucleus.utils.observer.future.IFutureResult; import com.jcwhatever.nucleus.utils.text.TextUtils; import com.jcwhatever.nucleus.utils.validate.IValidator; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.util.BlockIterator; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.UUID; /** * Provides {@link org.bukkit.entity.Player} related utilities. */ public final class PlayerUtils { private PlayerUtils() {} private static final Location PLAYER_LOCATION = new Location(null, 0, 0, 0); /** * A validator that always specifies a player entity as valid. */ public static final IValidator<Player> ALL_VALID = new IValidator<Player>() { @Override public boolean isValid(Player element) { return true; } }; /** * Get the time the {@link Player} logged in for the current session. * * @param player The {@link Player} to check. * * @return The {@link Date} or null if the player is not logged in. */ @Nullable public static Date getLoginDate(Player player) { return InternalPlayerTracker.get().getLoginDate(player); } /** * Get the time the {@link Player} last changed worlds in the current session. * * @param player The {@link Player} to check. * * @return The {@link Date} or null if the player is not logged in. */ @Nullable public static Date getLastWorldChangeDate(Player player) { return InternalPlayerTracker.get().getLastWorldChangeDate(player); } /** * Get the number of milliseconds the {@link Player} has been on * the server during the current login session. * * @param player The {@link Player} to check. * * @return 0 if the {@link Player} is not online. */ public static long getSessionTime(Player player) { return InternalPlayerTracker.get().getSessionTime(player); } /** * Get the number of milliseconds the {@link Player} has been in * the world they are currently in. * * @param player The {@link Player} to check. * * @return 0 if the {@link Player} is not online. */ public static long getWorldSessionTime(Player player) { return InternalPlayerTracker.get().getWorldSessionTime(player); } /** * Get an online {@link Player} by name. * * @param playerName The name of the {@link Player}. * * @return The {@link Player} or null if not online. */ @Nullable public static Player getPlayer(String playerName) { PreCon.notNullOrEmpty(playerName); UUID playerId = getPlayerId(playerName); if (playerId == null) return null; return Bukkit.getServer().getPlayer(playerId); } /** * Get an online {@link Player} by ID. * * @param playerId The ID of the {@link Player}. * * @return The {@link Player} or null if not online. */ @Nullable public static Player getPlayer(UUID playerId) { PreCon.notNull(playerId); return Bukkit.getServer().getPlayer(playerId); } /** * Get {@link Player} instance from provided object. * * <p>Attempts to retrieve the {@link Player} object from one of the following * types of objects:</p> * * <ul> * <li>{@link org.bukkit.entity.Player}</li> * <li>{@link IPlayerReference}</li> * <li>{@link java.util.UUID} (player ID)</li> * <li>{@link java.lang.String} (player name)</li> * </ul> * * @param player The object that represents a {@link Player}. * * @return The {@link Player} or null if not found. */ @Nullable public static Player getPlayer(Object player) { if (player instanceof Player) return (Player)player; if (player instanceof IPlayerReference) return ((IPlayerReference)player).getPlayer(); if (player instanceof UUID) return getPlayer((UUID)player); if (player instanceof String) return getPlayer((String)player); return null; } /** * Gets player ID from provided object. * * <p>Attempts to retrieve the {@link Player} object from one of the following * types of objects:</p> * * <ul> * <li>{@link org.bukkit.entity.Player}</li> * <li>{@link IPlayerReference}</li> * <li>{@link java.util.UUID} (player ID)</li> * <li>{@link java.lang.String} (player name)</li> * </ul> * * @param player The object to get the player ID from. * * @return The players ID or null if not found. */ @Nullable public static UUID getPlayerId(Object player) { if (player instanceof UUID) return (UUID)player; if (player instanceof Player) return ((Player)player).getUniqueId(); if (player instanceof IPlayerReference) return ((IPlayerReference)player).getPlayer().getUniqueId(); if (player instanceof String) { UUID playerId = TextUtils.parseUUID((String)player); if (playerId != null) return playerId; return getPlayerId((String)player); } return null; } /** * Gets player ID from name using stored ID to name map if * the player is not online. * * <p>Uses the player lookup provider.</p> * * @param playerName The name of the player. * * @return The player ID or null if not found. */ @Nullable public static UUID getPlayerId(String playerName) { return Nucleus.getProviders().getPlayerLookup().getPlayerId(playerName); } /** * Get the name of a player from the player ID. * * <p>Uses the player lookup provider.</p> * * @param playerId The ID of the player. * * @return The players name or null if a record was not found. */ @Nullable public static String getPlayerName(UUID playerId) { return Nucleus.getProviders().getPlayerLookup().getPlayerName(playerId); } /** * Get the Date the player first logged in successfully. * * @param playerId The ID of the player. * * @return The date or null if the player was not found. */ @Nullable public static Date getFirstLogin(UUID playerId) { return Nucleus.getProviders().getPlayerLookup().getFirstLogin(playerId); } /** * Get the last Date the player logged in successfully. * * @param playerId The ID of the player. * * @return The date or null if the player was not found. */ @Nullable public static Date getLastLogin(UUID playerId) { return Nucleus.getProviders().getPlayerLookup().getLastLogin(playerId); } /** * Get the number of times a player has successfully logged into the server. * * @param playerId The ID of the player. * * @return The number of times or 0 if a player with the specified ID * was not found. */ public static int getLoginCount(UUID playerId) { return Nucleus.getProviders().getPlayerLookup().getLoginCount(playerId); } /** * Search stored players for players whose name contains the specified search * text. * * @param searchText The search text. * @param maxResults The max number of results to return. * * @return A collection of IDs of matched players. */ public static IFutureResult<Collection<UUID>> searchNames(String searchText, int maxResults) { return Nucleus.getProviders().getPlayerLookup().searchNames(searchText, maxResults); } /** * Reset player state. * * <ul> * <li>Inventory cleared, including armor.</li> * <li>GameMode set to SURVIVAL</li> * <li>Potion effects cleared</li> * <li>Food level restored</li> * <li>Exp set to 0</li> * <li>Flying turned off</li> * <li>Fire ticks set to 0</li> * <li>Fall distance set to 0</li> * </ul> * * @param player The {@link Player}. */ public static void resetPlayer(Player player) { PreCon.notNull(player); InventoryUtils.clearAll(player.getInventory()); player.setGameMode(GameMode.SURVIVAL); player.getActivePotionEffects().clear(); player.setHealth(player.getMaxHealth()); player.setFoodLevel(20); player.setLevel(0); player.setExp(0); player.setFlying(false); player.setAllowFlight(false); player.setFireTicks(0); player.setFallDistance(0); } /** * Get a collection of {@link Player}'s that are near the specified {@link Location}. * * <p>Does not include NPC players in result if a validator is not specified.</p> * * @param loc The {@link Location} to check. * @param maxDistance The radius that players must be within to be included in results. */ public static Collection<Player> getNearbyPlayers(Location loc, double maxDistance) { return getNearbyPlayers(loc, maxDistance, null, new ArrayList<Player>(0)); } /** * Get a collection of {@link Player}'s that are near the specified {@link Location}. * * <p>Does not include NPC players in result if a validator is not specified.</p> * * @param loc The {@link Location} to check. * @param maxDistance The radius that players must be within to be included in results. * @param validator A validator used to validate if a player is a candidate to return. */ public static Collection<Player> getNearbyPlayers(Location loc, double maxDistance, @Nullable IValidator<Player> validator) { return getNearbyPlayers(loc, maxDistance, validator, new ArrayList<Player>(0)); } /** * Get {@link Player}'s that are near the specified {@link Location} and add them * to the specified output collection. * * <p>Does not include NPC players in result if a validator is not specified.</p> * * @param loc The {@link Location} to check. * @param maxDistance The radius that players must be within to be included in results. * @param validator A validator used to validate if a player is a candidate to return. * @param output The output collection. * * @return The output collection. */ public static <T extends Collection<Player>> T getNearbyPlayers(Location loc, double maxDistance, @Nullable IValidator<Player> validator, T output) { PreCon.notNull(loc, "loc"); PreCon.notNull(loc.getWorld(), "loc world"); PreCon.notNull(output); World world = loc.getWorld(); List<Player> players = world.getPlayers(); if (players.isEmpty()) return output; maxDistance *= maxDistance; if (output instanceof ArrayList) ((ArrayList) output).ensureCapacity((int)(players.size() * 0.5D) + output.size()); for (Player player : players) { if (validator == null && Npcs.isNpc(player)) continue; Location playerLoc = player.getLocation(PLAYER_LOCATION); if (loc.distanceSquared(playerLoc) > maxDistance) continue; if (validator != null && !validator.isValid(player)) continue; output.add(player); } return output; } /** * Determine if there is at least 1 {@link Player}'s near the specified {@link Location}. * * <p>Does not include NPC players in result.</p> * * @param loc The {@link Location} to check. * @param maxDistance The radius that players must be within from the location. */ public static boolean hasNearbyPlayers(Location loc, double maxDistance) { return hasNearbyPlayers(loc, maxDistance, null); } /** * Determine if there is at least 1 {@link Player}'s near the specified {@link Location}. * * <p>Does not include NPC players in result if a validator is not specified..</p> * * @param loc The {@link Location} to check. * @param maxDistance The radius that players must be within from the location. * @param validator A validator used to validate if a player is a candidate to return. */ public static boolean hasNearbyPlayers(Location loc, double maxDistance, @Nullable IValidator<Player> validator) { PreCon.notNull(loc, "loc"); PreCon.notNull(loc.getWorld(), "loc world"); World world = loc.getWorld(); List<Player> players = world.getPlayers(); if (players.isEmpty()) return false; maxDistance *= maxDistance; for (Player player : players) { if (validator == null && Npcs.isNpc(player)) continue; Location playerLoc = player.getLocation(PLAYER_LOCATION); if (loc.distanceSquared(playerLoc) > maxDistance) continue; if (validator != null && !validator.isValid(player)) continue; return true; } return false; } /** * Get the closest {@link Player} to the specified {@link Location} within the * specified radius. * * <p>Does not include NPC players in result if a validator is not specified.</p> * * @param loc The {@link Location} to check. * @param radius The radius that players must be within to be considered. * @param validator A validator used to validate if a player is a candidate to return. * * @return The closest player or null if not found. */ @Nullable public static Player getClosestPlayer(Location loc, double radius, @Nullable IValidator<Player> validator) { PreCon.notNull(loc, "loc"); PreCon.notNull(loc.getWorld(), "loc world"); World world = loc.getWorld(); List<Player> players = world.getPlayers(); if (players.isEmpty()) return null; radius *= radius; Player closest = null; double closestDistSq = 0; for (Player player : players) { if (validator == null && Npcs.isNpc(player)) continue; Location playerLoc = player.getLocation(PLAYER_LOCATION); double distanceSq = loc.distanceSquared(playerLoc); if (distanceSq > radius) continue; if (validator != null && !validator.isValid(player)) continue; if (closest == null || distanceSq < closestDistSq) { closest = player; closestDistSq = distanceSq; } } return closest; } /** * Iterates over blocks in the direction the player is looking until the * max distance is reached or a block that isn't {@link org.bukkit.Material#AIR} * is found. * * @param player The {@link Player}. * @param maxDistance The max distance to search. * * @return The {@link Block} that was found or null if the max distance was reached. */ @Nullable public static Block getTargetBlock(Player player, int maxDistance) { PreCon.notNull(player); PreCon.positiveNumber(maxDistance); BlockIterator bit = new BlockIterator(player, maxDistance); Block next; while(bit.hasNext()) { next = bit.next(); if (next != null && next.getType() != Material.AIR) return next; } return null; } }