/******************************************************************************* * This file is part of ASkyBlock. * * ASkyBlock is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ASkyBlock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ASkyBlock. If not, see <http://www.gnu.org/licenses/>. *******************************************************************************/ package com.wasteofplastic.askyblock; import java.io.File; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; import org.bukkit.Location; import org.bukkit.entity.Player; import com.google.common.collect.Lists; import com.wasteofplastic.askyblock.util.VaultHelper; /** * Provides a memory cache of online player information * This is the one-stop-shop of player info * If the player is not cached, then a request is made to Players to obtain it * * @author tastybento */ public class PlayerCache { private HashMap<UUID, Players> playerCache = new HashMap<UUID, Players>(); private final ASkyBlock plugin; private Set<UUID> inTeleport = new HashSet<UUID>(); public PlayerCache(ASkyBlock plugin) { this.plugin = plugin; // final Collection<? extends Player> serverPlayers = // Bukkit.getServer().getOnlinePlayers(); for (Player p : plugin.getServer().getOnlinePlayers()) { if (p.getUniqueId() != null) { try { final Players playerInf = new Players(plugin, p.getUniqueId()); // Make sure parties are working correctly if (playerInf.inTeam() && playerInf.getTeamIslandLocation() == null) { if (playerInf.getTeamLeader() == null) { // Player cannot be in a team - try to clean up playerInf.setLeaveTeam(); } else { final Players leaderInf = new Players(plugin, playerInf.getTeamLeader()); playerInf.setTeamIslandLocation(leaderInf.getIslandLocation()); } playerInf.save(); } // Add this player to the online cache //plugin.getLogger().info("DEBUG: added player " + p.getUniqueId()); playerCache.put(p.getUniqueId(), playerInf); } catch (Exception e) { plugin.getLogger().severe("Player add tried for a player with null UUID"); } } } } /** * @return list of all online cached players */ public List<UUID> getOnlineCachedPlayers() { List<UUID> list = Lists.newArrayList(); for (Player p: plugin.getServer().getOnlinePlayers()) { if (playerCache.containsKey(p.getUniqueId())) { list.add(p.getUniqueId()); } } return Collections.unmodifiableList(list); } /* * Cache control methods */ public void addPlayer(final UUID playerUUID) { //plugin.getLogger().info("DEBUG: added player " + playerUUID); if (!playerCache.containsKey(playerUUID)) { try { final Players player = new Players(plugin, playerUUID); playerCache.put(playerUUID, player); } catch (Exception e) { plugin.getLogger().severe("Player add request for a null UUID"); } } } /** * Stores the player's info to a file and removes the player from the list * of currently online players * * @param player * - name of player */ public void removeOnlinePlayer(final UUID player) { if (playerCache.containsKey(player)) { playerCache.get(player).save(); playerCache.remove(player); // plugin.getLogger().info("Removing player from cache: " + player); } } /** * Removes all players on the server now from cache and saves their info */ public void removeAllPlayers() { for (UUID pl : playerCache.keySet()) { playerCache.get(pl).save(); } playerCache.clear(); } /* * Player info query methods */ /** * Returns location of player's island from cache if available * * @param playerUUID * @return Location of player's island */ /* * public Location getPlayerIsland(final UUID playerUUID) { * if (playerCache.containsKey(playerUUID)) { * return playerCache.get(playerUUID).getIslandLocation(); * } * final Players player = new Players(plugin, playerUUID); * return player.getIslandLocation(); * } */ /** * Checks if the player is known or not by looking through the filesystem * * @param uniqueID * @return true if player is know, otherwise false */ public boolean isAKnownPlayer(final UUID uniqueID) { if (uniqueID == null) { return false; } if (playerCache.containsKey(uniqueID)) { return true; } else { // Get the file system try { final File file = new File(plugin.getPlayersFolder(), uniqueID.toString() + ".yml"); return file.exists(); } catch (Exception e) { return false; } } } /** * Returns the player object for the named player * * @param playerUUID * - String name of player * @return - player object */ public Players get(UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID); } /** * Checks if player has island from cache if available * * @param playerUUID * - string name of player * @return true if player has island */ public boolean hasIsland(final UUID playerUUID) { addPlayer(playerUUID); // plugin.getLogger().info("DEBUG: hasIsland = " + playerUUID.toString() // + " = " + playerCache.get(playerUUID).hasIsland()); return playerCache.get(playerUUID).hasIsland(); } /** * Checks if player is in a Team from cache if available * * @param playerUUID * @return true if player in a team */ public boolean inTeam(final UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID).inTeam(); } /** * Removes any island associated with this player and generally cleans up * the player * * @param playerUUID */ public void zeroPlayerData(UUID playerUUID) { addPlayer(playerUUID); // Remove and clean up any team players (if the asadmin delete command // was called this is needed) if (playerCache.get(playerUUID).inTeam()) { UUID leader = playerCache.get(playerUUID).getTeamLeader(); // If they are the leader, dissolve the team if (leader != null) { if (leader.equals(playerUUID)) { for (UUID member : playerCache.get(leader).getMembers()) { addPlayer(member); playerCache.get(member).setLeaveTeam(); } } else { // Just remove them from the team addPlayer(leader); playerCache.get(leader).removeMember(playerUUID); playerCache.get(leader).save(); } } } playerCache.get(playerUUID).setLeaveTeam(); playerCache.get(playerUUID).setHasIsland(false); playerCache.get(playerUUID).clearHomeLocations(); playerCache.get(playerUUID).setIslandLocation(null); playerCache.get(playerUUID).setIslandLevel(0); playerCache.get(playerUUID).save(); // Needed? TopTen.topTenRemoveEntry(playerUUID); } /** * Sets the home location for the player * @param playerUUID * @param location * @param number - 1 is default. Can be any number. */ public void setHomeLocation(UUID playerUUID, Location location, int number) { addPlayer(playerUUID); playerCache.get(playerUUID).setHomeLocation(location,number); } /** * Set the default home location for player * @param playerUUID * @param location */ public void setHomeLocation(UUID playerUUID, Location location) { addPlayer(playerUUID); playerCache.get(playerUUID).setHomeLocation(location,1); } /** * Clears any home locations for player * @param playerUUID */ public void clearHomeLocations(UUID playerUUID) { addPlayer(playerUUID); playerCache.get(playerUUID).clearHomeLocations(); } /** * Returns the home location, or null if none * * @param playerUUID * @param number * @return Home location or null if none */ public Location getHomeLocation(UUID playerUUID, int number) { addPlayer(playerUUID); return playerCache.get(playerUUID).getHomeLocation(number); } /** * Gets the default home location for player * @param playerUUID * @return Home location or null if none */ public Location getHomeLocation(UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID).getHomeLocation(1); } /** * Provides all home locations for player * @param playerUUID * @return List of home locations */ public HashMap<Integer, Location> getHomeLocations(UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID).getHomeLocations(); } /** * Returns the player's island location. * Returns an island location OR a team island location * * @param playerUUID * @return Location of player's island */ public Location getIslandLocation(UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID).getIslandLocation(); } public void setHasIsland(UUID playerUUID, boolean b) { // plugin.getLogger().info("DEBUG: setHasIsland " + // playerUUID.toString() + " " + b); addPlayer(playerUUID); playerCache.get(playerUUID).setHasIsland(b); } public void setIslandLocation(UUID playerUUID, Location islandLocation) { addPlayer(playerUUID); playerCache.get(playerUUID).setIslandLocation(islandLocation); } public Integer getIslandLevel(UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID).getIslandLevel(); } public void setIslandLevel(UUID playerUUID, int islandLevel) { addPlayer(playerUUID); playerCache.get(playerUUID).setIslandLevel(islandLevel); plugin.getChatListener().setPlayerLevel(playerUUID, islandLevel); } public void setTeamIslandLocation(UUID playerUUID, Location islandLocation) { addPlayer(playerUUID); playerCache.get(playerUUID).setTeamIslandLocation(islandLocation); } /** * Checks if a challenge has been completed or not * * @param playerUUID * @param challenge * @return true if complete */ public boolean checkChallenge(UUID playerUUID, String challenge) { addPlayer(playerUUID); return playerCache.get(playerUUID).checkChallenge(challenge); } /** * Checks how often a challenge has been completed * * @param playerUUID * @param challenge * @return number of times */ public int checkChallengeTimes(UUID playerUUID, String challenge) { addPlayer(playerUUID); return playerCache.get(playerUUID).checkChallengeTimes(challenge); } /** * Provides the status of all challenges for this player * * @param playerUUID * @return Hashmap of challenges as key, boolean as state */ public HashMap<String, Boolean> getChallengeStatus(UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID).getChallengeStatus(); } /** * How many times a challenge has been completed * * @param playerUUID * @return map of completion times */ public HashMap<String, Integer> getChallengeTimes(UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID).getChallengeCompleteTimes(); } public void resetChallenge(UUID playerUUID, String challenge) { addPlayer(playerUUID); playerCache.get(playerUUID).resetChallenge(challenge); } /** * Resets all the player's challenges. If the boolean is true, then everything will be reset, if false * challenges that have the "resetallowed: false" flag in challenges.yml will not be reset * @param playerUUID * @param resetAll */ public void resetAllChallenges(UUID playerUUID, boolean resetAll) { addPlayer(playerUUID); if (resetAll) { playerCache.get(playerUUID).resetAllChallenges(); } else { // Look through challenges and check them for (String challenge: plugin.getChallenges().getAllChallenges()) { // Check for the flag if (plugin.getChallenges().resetable(challenge)) { playerCache.get(playerUUID).resetChallenge(challenge); } } } } /** * Puts a player in a team * @param playerUUID * @param teamLeader * @param islandLocation * @return true if successful, false if not */ public boolean setJoinTeam(UUID playerUUID, UUID teamLeader, Location islandLocation) { addPlayer(playerUUID); addPlayer(teamLeader); return playerCache.get(playerUUID).setJoinTeam(teamLeader, islandLocation); } /** * Called when a player leaves a team Resets inTeam, teamLeader, * islandLevel, teamIslandLocation, islandLocation and members array */ public boolean setLeaveTeam(UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID).setLeaveTeam(); } /** * Returns a list of team member UUID's. If the player is not the leader, * then the leader's list is used * * @param playerUUID * @return List of team UUIDs */ public List<UUID> getMembers(UUID playerUUID) { addPlayer(playerUUID); UUID leader = getTeamLeader(playerUUID); if (leader != null && !leader.equals(playerUUID)) { addPlayer(leader); return playerCache.get(leader).getMembers(); } // I am not the leader, so return the leader's list return playerCache.get(playerUUID).getMembers(); } public void addTeamMember(UUID teamLeader, UUID playerUUID) { addPlayer(teamLeader); addPlayer(playerUUID); playerCache.get(teamLeader).addTeamMember(playerUUID); } public void removeMember(UUID teamLeader, UUID playerUUID) { if (teamLeader != null) { addPlayer(teamLeader); } addPlayer(playerUUID); if (teamLeader != null) { playerCache.get(teamLeader).removeMember(playerUUID); } // Remove from team chat too plugin.getChatListener().unSetPlayer(playerUUID); } /** * Provides UUID of this player's team leader or null if it does not exist * @param playerUUID * @return UUID of leader */ public UUID getTeamLeader(UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID).getTeamLeader(); } /** * Saves the player's info to the file system * * @param playerUUID */ public void save(UUID playerUUID) { playerCache.get(playerUUID).save(); // Save the name + UUID in the database if it ready if (plugin.getTinyDB() != null && plugin.getTinyDB().isDbReady()) { plugin.getTinyDB().savePlayerName(playerCache.get(playerUUID).getPlayerName(), playerUUID); } } public void completeChallenge(UUID playerUUID, String challenge) { addPlayer(playerUUID); playerCache.get(playerUUID).completeChallenge(challenge); } public boolean challengeExists(UUID playerUUID, String challenge) { addPlayer(playerUUID); return playerCache.get(playerUUID).challengeExists(challenge); } /** * Attempts to return a UUID for a given player's name. Only uses online or cached information. * @param string * @return UUID of player or null if unknown */ public UUID getUUID(String string) { return getUUID(string, false); } /** * Attempts to return a UUID for a given player's name * @param string * @param adminCheck - if made via an admin call, this will go out to the 'net and grab - may cause lag * @return UUID of player or null if unknown */ @SuppressWarnings("deprecation") public UUID getUUID(String string, boolean adminCheck) { // Look in the database if it ready if (plugin.getTinyDB() != null && plugin.getTinyDB().isDbReady()) { UUID result = plugin.getTinyDB().getPlayerUUID(string); if (result != null) { return result; } } // This goes after the database because it is possible for islands that have a duplicate name to be in // the cache. For example, Bill had an island but left. Bill changes his name to Bob. Then Alice changes // her name to Bill and logs into the game. There are now two islands with owner names called "Bill" // The name database will ensure the names are updated. for (UUID id : playerCache.keySet()) { String name = playerCache.get(id).getPlayerName(); //plugin.getLogger().info("DEBUG: Testing name " + name); if (name != null && name.equalsIgnoreCase(string)) { //plugin.getLogger().info("DEBUG: found it! " + id); return id; } } // Try the server if (adminCheck && plugin.getServer().getOfflinePlayer(string) != null) { return plugin.getServer().getOfflinePlayer(string).getUniqueId(); } return null; } /** * Sets the player's name and updates the name>UUID database is up to date * @param uniqueId * @param name */ public void setPlayerName(UUID uniqueId, String name) { addPlayer(uniqueId); playerCache.get(uniqueId).setPlayerN(name); // Save the name in the name database. Note that the old name will still work until someone takes it // This feature enables admins to locate 'fugitive' players even if they change their name if (plugin.getTinyDB() != null && plugin.getTinyDB().isDbReady()) { plugin.getTinyDB().savePlayerName(name, uniqueId); } } /** * Obtains the name of the player from their UUID * Player must have logged into the game before * * @param playerUUID * @return String - playerName */ public String getName(UUID playerUUID) { if (playerUUID == null) { return ""; } addPlayer(playerUUID); return playerCache.get(playerUUID).getPlayerName(); } public Location getTeamIslandLocation(UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID).getTeamIslandLocation(); } /** * Reverse lookup - returns the owner of an island from the location * * @param loc * @return UUID of owner of island */ public UUID getPlayerFromIslandLocation(Location loc) { if (loc == null) return null; // Look in the grid Island island = plugin.getGrid().getIslandAt(loc); if (island != null) { return island.getOwner(); } return null; } /** * Gets how many island resets the player has left * * @param playerUUID * @return number of resets */ public int getResetsLeft(UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID).getResetsLeft(); } /** * Sets how many resets the player has left * * @param playerUUID * @param resets */ public void setResetsLeft(UUID playerUUID, int resets) { addPlayer(playerUUID); playerCache.get(playerUUID).setResetsLeft(resets); } /** * Returns how long the player must wait before they can be invited to an * island with the location * * @param playerUUID * @param location * @return time to wait in minutes/hours */ public long getInviteCoolDownTime(UUID playerUUID, Location location) { addPlayer(playerUUID); return playerCache.get(playerUUID).getInviteCoolDownTime(location); } /** * Starts the timer for the player for this location before which they can * be invited * Called when they are kicked from an island or leave. * * @param playerUUID * @param location */ public void startInviteCoolDownTimer(UUID playerUUID, Location location) { addPlayer(playerUUID); playerCache.get(playerUUID).startInviteCoolDownTimer(location); } /** * Returns the locale for this player. If missing, will return nothing * @param playerUUID * @return name of the locale this player uses */ public String getLocale(UUID playerUUID) { addPlayer(playerUUID); if (playerUUID == null) { return ""; } return playerCache.get(playerUUID).getLocale(); } /** * Sets the locale this player wants to use * @param playerUUID * @param localeName */ public void setLocale(UUID playerUUID, String localeName) { addPlayer(playerUUID); playerCache.get(playerUUID).setLocale(localeName); } /** * The rating of the initial starter island out of 100. Default is 50 * @param playerUUID * @return rating */ public int getStartIslandRating(UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID).getStartIslandRating(); } /** * Record the island rating that the player started with * @param playerUUID * @param rating */ public void setStartIslandRating(UUID playerUUID, int rating) { addPlayer(playerUUID); playerCache.get(playerUUID).setStartIslandRating(rating); } /** * Clear the starter island rating from the player's record * @param playerUUID */ public void clearStartIslandRating(UUID playerUUID) { setStartIslandRating(playerUUID, 0); } /** * Ban target from a player's island * @param playerUUID * @param targetUUID */ public void ban(UUID playerUUID, UUID targetUUID) { addPlayer(playerUUID); addPlayer(targetUUID); if (playerCache.get(playerUUID).hasIsland()) { // Player has island playerCache.get(playerUUID).addToBanList(targetUUID); } else if (playerCache.get(playerUUID).inTeam()) { // Try to get the leader's UUID leader = playerCache.get(playerUUID).getTeamLeader(); if (leader != null) { addPlayer(leader); playerCache.get(leader).addToBanList(targetUUID); playerCache.get(leader).save(); } } } /** * Unban target from player's island * @param playerUUID * @param targetUUID */ public void unBan(UUID playerUUID, UUID targetUUID) { addPlayer(playerUUID); addPlayer(targetUUID); if (playerCache.get(playerUUID).hasIsland()) { // Player has island playerCache.get(playerUUID).unBan(targetUUID); } else if (playerCache.get(playerUUID).inTeam()) { // Try to get the leader's UUID leader = playerCache.get(playerUUID).getTeamLeader(); if (leader != null) { addPlayer(leader); playerCache.get(leader).unBan(targetUUID); playerCache.get(leader).save(); } } } /** * @param playerUUID * @param targetUUID * @return true if target is banned from player's island */ public boolean isBanned(UUID playerUUID, UUID targetUUID) { if (playerUUID == null || targetUUID == null) { // If the island is unowned, then playerUUID could be null return false; } addPlayer(playerUUID); addPlayer(targetUUID); // Check if the target player has a permission bypass (admin.noban) Player target = plugin.getServer().getPlayer(targetUUID); if (target != null && VaultHelper.checkPerm(target, Settings.PERMPREFIX + "admin.noban")) { return false; } if (playerCache.get(playerUUID).hasIsland()) { // Player has island return playerCache.get(playerUUID).isBanned(targetUUID); } else if (playerCache.get(playerUUID).inTeam()) { // Try to get the leader's UUID leader = playerCache.get(playerUUID).getTeamLeader(); if (leader != null) { addPlayer(leader); return playerCache.get(leader).isBanned(targetUUID); } } return false; } /** * @param playerUUID * @return ban list for player */ public List<UUID> getBanList(UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID).getBanList(); } /** * Clears resets for online players or players in the cache * @param resetLimit */ public void clearResets(int resetLimit) { for (Players player : playerCache.values()) { player.setResetsLeft(resetLimit); } } /** * Sets whether the player uses the control panel or not when doing /island * @param b */ public void setControlPanel(UUID playerUUID, boolean b) { addPlayer(playerUUID); playerCache.get(playerUUID).setControlPanel(b); } /** * Gets whether the player uses the control panel or not when doing /island * @param playerUUID * @return true if they use the control panel */ public boolean getControlPanel(UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID).getControlPanel(); } /** * Map storing whether a player is officially teleporting or not * @param uniqueId * @param b */ public void setInTeleport(UUID uniqueId, boolean b) { if (b) { inTeleport.add(uniqueId); } else { inTeleport.remove(uniqueId); } } /** * Checks whether player with UUID uniqueId is in an official teleport or not * @param uniqueId * @return true if in teleport */ public boolean isInTeleport(UUID uniqueId) { return inTeleport.contains(uniqueId); } /** * Add death to player * @param playerUUID */ public void addDeath(UUID playerUUID) { addPlayer(playerUUID); playerCache.get(playerUUID).addDeath(); } /** * Set death number for player * @param playerUUID * @param deaths */ public void setDeaths(UUID playerUUID, int deaths) { addPlayer(playerUUID); playerCache.get(playerUUID).setDeaths(deaths); } /** * Get number of times player has died in ASkyBlock worlds since counting began * @param playerUUID * @return */ public int getDeaths(UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID).getDeaths(); } /** * @param playerUUID * @return List of challenges or levels done */ public List<String> getChallengesDone(UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID).getChallengesDone(); } /** * @param playerUUID * @return List of challenges or levels not done */ public List<String> getChallengesNotDone(UUID playerUUID) { addPlayer(playerUUID); return playerCache.get(playerUUID).getChallengesNotDone(); } }