diff --git a/src/dev/w1zzrd/spigot/wizcompat/OfflinePlayers.java b/src/dev/w1zzrd/spigot/wizcompat/OfflinePlayers.java new file mode 100644 index 0000000..ef600e6 --- /dev/null +++ b/src/dev/w1zzrd/spigot/wizcompat/OfflinePlayers.java @@ -0,0 +1,108 @@ +package dev.w1zzrd.spigot.wizcompat; + +import org.bukkit.Bukkit; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +import java.io.File; +import java.util.Arrays; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public final class OfflinePlayers { + private OfflinePlayers(){ throw new UnsupportedOperationException("Functional class"); } + + private static int totalFiles = -1; + private static Set fileUUIDs = null; + + private static Set getFileUUIDsAggressive(final Server server) { + return server.getWorlds().stream().flatMap(world -> { + File[] playerDataFiles = new File(world.getWorldFolder(), "playerdata").listFiles(); + + if (playerDataFiles == null) + return Stream.empty(); + + return Arrays.stream(playerDataFiles) + .filter(file -> file.getName().endsWith(".dat")) + .map(file -> { + try { + return UUID.fromString(file.getName().substring(0, file.getName().indexOf('.'))); + } catch (IllegalArgumentException badName) { + return null; + } + }) + .filter(Objects::nonNull); + }).collect(Collectors.toSet()); + } + + private static Set getFileUUIDsLazy(final Server server) { + int totalFiles = 0; + for (final World world : server.getWorlds()) { + final File worldFolder = new File(world.getWorldFolder(), "playerdata"); + final String[] fileNames = worldFolder.list(); + + if (fileNames != null) + totalFiles += fileNames.length; + } + + // Assume no data files have been deleted + // I.e. if there is not change in the dat file count, we assume no new players have been seen + if (OfflinePlayers.totalFiles != totalFiles || fileUUIDs == null) { + final Set found = getFileUUIDsAggressive(server); + OfflinePlayers.totalFiles = totalFiles; + + fileUUIDs = found; + return found; + } + + return fileUUIDs; + } + + /** + * Get UUIDs of all players known to this server + * @param server Server to get player UUIDs for + * @return Array of all UUIDs of players on the server + */ + public static UUID[] getAllKnownPlayers(final Server server, final boolean lazyFileLoading) { + final Set fileUUIDS = lazyFileLoading ? getFileUUIDsLazy(server) : getFileUUIDsAggressive(server); + + // Add online players, in case (for some reason idk) the online player data hasn't yet been saved to a file + // This is probably unnecessary + fileUUIDS.addAll(server.getOnlinePlayers().stream().map(Entity::getUniqueId).collect(Collectors.toSet())); + + return fileUUIDS.toArray(new UUID[0]); + } + + /** + * Find a player on the server by name + * @param server Server to find player for + * @param playerName Name of player to find + * @param ignoreCase Whether or not to respect case-sensitivity + * @return Matching player instance, or null if server does not know of a player with the given name + */ + public static Player getKnownPlayer(final Server server, final String playerName, final boolean ignoreCase, final boolean lazyFileLoading) { + for (final UUID uuid : getAllKnownPlayers(server, lazyFileLoading)) { + final Player player = Bukkit.getPlayer(uuid); + + if (player != null && ((ignoreCase && player.getName().equalsIgnoreCase(playerName)) || (!ignoreCase && player.getName().equals(playerName)))) + return player; + } + + return null; + } + + /** + * Find a player on the server by name + * @param server Server to find player for + * @param playerName Name of player to find + * @return Matching player instance, or null if server does not know of a player with the given name + */ + public static Player getKnownPlayer(final Server server, final String playerName) { + return getKnownPlayer(server, playerName, true, true); + } +} \ No newline at end of file