mirror of
https://github.com/itHotL/PlayerStats.git
synced 2025-01-19 21:11:36 +01:00
The exclude function now works completely, the only thing left is give fancier feedback (#88)
This commit is contained in:
parent
da49c46539
commit
f69367cb31
@ -127,7 +127,7 @@ public final class Main extends JavaPlugin implements PlayerStats {
|
||||
}
|
||||
PluginCommand excludecmd = this.getCommand("statisticexclude");
|
||||
if (excludecmd != null) {
|
||||
excludecmd.setExecutor(new ExcludeCommand());
|
||||
excludecmd.setExecutor(new ExcludeCommand(outputManager));
|
||||
excludecmd.setTabCompleter(tabCompleter);
|
||||
}
|
||||
|
||||
|
@ -1,44 +1,55 @@
|
||||
package com.artemis.the.gr8.playerstats.commands;
|
||||
|
||||
|
||||
import com.artemis.the.gr8.playerstats.utils.MyLogger;
|
||||
import com.artemis.the.gr8.playerstats.msg.OutputManager;
|
||||
import com.artemis.the.gr8.playerstats.utils.OfflinePlayerHandler;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public final class ExcludeCommand implements CommandExecutor {
|
||||
|
||||
private static OutputManager outputManager;
|
||||
private final OfflinePlayerHandler offlinePlayerHandler;
|
||||
|
||||
public ExcludeCommand() {
|
||||
public ExcludeCommand(OutputManager outputManager) {
|
||||
ExcludeCommand.outputManager = outputManager;
|
||||
this.offlinePlayerHandler = OfflinePlayerHandler.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
if (args.length == 1 && args[0].equalsIgnoreCase("list")) {
|
||||
List<String> excludedPlayers = offlinePlayerHandler.getListOfExcludedPlayerNames();
|
||||
|
||||
for (String player : excludedPlayers) {
|
||||
MyLogger.logLowLevelMsg(player);
|
||||
}
|
||||
ArrayList<String> excludedPlayers = offlinePlayerHandler.getExcludedPlayerNames();
|
||||
sender.sendMessage(String.valueOf(excludedPlayers));
|
||||
return true;
|
||||
}
|
||||
//this is going to return false for all UUIDs in file at boot-up - that's an issue
|
||||
else if (args.length >= 2 && offlinePlayerHandler.isLoadedPlayer(args[1])) {
|
||||
String playerName = args[1];
|
||||
OfflinePlayer player = offlinePlayerHandler.getOfflinePlayer(playerName);
|
||||
else if (args.length >= 2) {
|
||||
|
||||
String playerName = args[1];
|
||||
switch (args[0]) {
|
||||
case "add" -> offlinePlayerHandler.addPlayerToExcludeList(player.getUniqueId());
|
||||
case "remove" -> offlinePlayerHandler.removePlayerFromExcludeList(player.getUniqueId());
|
||||
case "add" -> {
|
||||
if (offlinePlayerHandler.isLoadedPlayer(playerName)) {
|
||||
offlinePlayerHandler.addLoadedPlayerToExcludeList(playerName);
|
||||
sender.sendMessage("Excluded " + playerName + "!");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
case "remove" -> {
|
||||
if (offlinePlayerHandler.isExcludedPlayer(playerName)) {
|
||||
offlinePlayerHandler.addExcludedPlayerToLoadedList(playerName);
|
||||
sender.sendMessage("Removed " + playerName + " from the exclude list again!");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
case "info" -> {
|
||||
boolean isExcluded = offlinePlayerHandler.isExcluded(player.getUniqueId());
|
||||
MyLogger.logLowLevelMsg(player.getName() + " is excluded: " + isExcluded);
|
||||
boolean isExcluded = offlinePlayerHandler.isExcludedPlayer(playerName);
|
||||
sender.sendMessage(playerName+ " is excluded: " + isExcluded);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,11 +45,13 @@ public final class StatCommand implements CommandExecutor {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
if (args.length == 0 || args[0].equalsIgnoreCase("help")) { //in case of less than 1 argument or "help", display the help message
|
||||
if (args.length == 0 ||
|
||||
args[0].equalsIgnoreCase("help") ||
|
||||
args[0].equalsIgnoreCase("info")) {
|
||||
outputManager.sendHelp(sender);
|
||||
}
|
||||
else if (args[0].equalsIgnoreCase("examples") ||
|
||||
args[0].equalsIgnoreCase("example")) { //in case of "statistic examples", show examples
|
||||
args[0].equalsIgnoreCase("example")) {
|
||||
outputManager.sendExamples(sender);
|
||||
}
|
||||
else {
|
||||
|
@ -7,7 +7,6 @@ import org.bukkit.Statistic;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ -29,14 +28,9 @@ public final class TabCompleter implements org.bukkit.command.TabCompleter {
|
||||
public TabCompleter() {
|
||||
offlinePlayerHandler = OfflinePlayerHandler.getInstance();
|
||||
enumHandler = EnumHandler.getInstance();
|
||||
|
||||
prepareLists();
|
||||
}
|
||||
|
||||
//args[0] = statistic (length = 1)
|
||||
//args[1] = target (player/server/top) OR sub-stat (block/item/entity) (length = 2)
|
||||
//args[2] = playerName OR target (player/server/top) (length = 3)
|
||||
//args[3] = playerName (length = 4)
|
||||
@Override
|
||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
if (command.getName().equalsIgnoreCase("statistic")) {
|
||||
@ -59,8 +53,13 @@ public final class TabCompleter implements org.bukkit.command.TabCompleter {
|
||||
}
|
||||
else if (args.length == 2) {
|
||||
tabSuggestions = switch (args[0]) {
|
||||
case "add" -> offlinePlayerHandler.getOfflinePlayerNames();
|
||||
case "remove" -> removablePlayerNames();
|
||||
case "add" -> offlinePlayerHandler.getLoadedOfflinePlayerNames();
|
||||
case "remove" -> offlinePlayerHandler.getExcludedPlayerNames();
|
||||
case "info" -> {
|
||||
ArrayList<String> loadedPlayers = offlinePlayerHandler.getLoadedOfflinePlayerNames();
|
||||
loadedPlayers.addAll(offlinePlayerHandler.getExcludedPlayerNames());
|
||||
yield loadedPlayers;
|
||||
}
|
||||
default -> tabSuggestions;
|
||||
};
|
||||
}
|
||||
@ -91,7 +90,7 @@ public final class TabCompleter implements org.bukkit.command.TabCompleter {
|
||||
tabSuggestions = statCommandTargets; //if arg before "player" was entity-sub-stat, suggest targets
|
||||
}
|
||||
else { //otherwise "player" is the target: suggest playerNames
|
||||
tabSuggestions = offlinePlayerHandler.getOfflinePlayerNames();
|
||||
tabSuggestions = offlinePlayerHandler.getLoadedOfflinePlayerNames();
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,6 +116,7 @@ public final class TabCompleter implements org.bukkit.command.TabCompleter {
|
||||
private @NotNull List<String> firstStatCommandArgSuggestions() {
|
||||
List<String> suggestions = enumHandler.getAllStatNames();
|
||||
suggestions.add("examples");
|
||||
suggestions.add("info");
|
||||
suggestions.add("help");
|
||||
return suggestions;
|
||||
}
|
||||
@ -142,11 +142,6 @@ public final class TabCompleter implements org.bukkit.command.TabCompleter {
|
||||
}
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
private @Nullable List<String> removablePlayerNames() {
|
||||
return statCommandTargets;
|
||||
}
|
||||
|
||||
private void prepareLists() {
|
||||
statCommandTargets = new ArrayList<>();
|
||||
statCommandTargets.add("top");
|
||||
@ -158,6 +153,7 @@ public final class TabCompleter implements org.bukkit.command.TabCompleter {
|
||||
excludeCommandOptions.add("add");
|
||||
excludeCommandOptions.add("list");
|
||||
excludeCommandOptions.add("remove");
|
||||
excludeCommandOptions.add("info");
|
||||
|
||||
//breaking an item means running its durability negative
|
||||
itemsThatCanBreak = Arrays.stream(Material.values())
|
||||
|
@ -63,7 +63,7 @@ public final class ConfigHandler extends FileHandler {
|
||||
Map<String, Object> defaultValues = defaultValueGetter.getValuesToAdjust();
|
||||
defaultValues.put("config-version", configVersion);
|
||||
|
||||
super.addValuesToFile(defaultValues);
|
||||
super.addValues(defaultValues);
|
||||
reload();
|
||||
|
||||
MyLogger.logLowLevelMsg("Your config has been updated to version " + configVersion +
|
||||
|
@ -6,6 +6,8 @@ import com.artemis.the.gr8.playerstats.enums.PluginColor;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@ -85,7 +87,8 @@ public class PrideComponentFactory extends ComponentFactory {
|
||||
.build();
|
||||
}
|
||||
|
||||
private TextComponent backwardsPluginPrefixComponent() {
|
||||
@Contract(" -> new")
|
||||
private @NotNull TextComponent backwardsPluginPrefixComponent() {
|
||||
return text()
|
||||
.append(MiniMessage.miniMessage()
|
||||
.deserialize("<#631ae6>[</#631ae6>" +
|
||||
|
@ -73,7 +73,7 @@ final class PlayerLoadAction extends RecursiveAction {
|
||||
String playerName = player.getName();
|
||||
MyLogger.actionRunning(Thread.currentThread().getName());
|
||||
if (playerName != null &&
|
||||
!offlinePlayerHandler.isExcluded(player.getUniqueId()) &&
|
||||
!offlinePlayerHandler.isExcludedPlayer(player.getUniqueId()) &&
|
||||
UnixTimeHandler.hasPlayedSince(lastPlayedLimit, player.getLastPlayed())) {
|
||||
offlinePlayerUUIDs.put(playerName, player.getUniqueId());
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ public final class ThreadManager {
|
||||
public static @NotNull StatAction getStatAction(StatRequest.Settings requestSettings) {
|
||||
OfflinePlayerHandler offlinePlayerHandler = OfflinePlayerHandler.getInstance();
|
||||
|
||||
ImmutableList<String> relevantPlayerNames = ImmutableList.copyOf(offlinePlayerHandler.getOfflinePlayerNames());
|
||||
ImmutableList<String> relevantPlayerNames = ImmutableList.copyOf(offlinePlayerHandler.getLoadedOfflinePlayerNames());
|
||||
ConcurrentHashMap<String, Integer> resultingStatNumbers = new ConcurrentHashMap<>(relevantPlayerNames.size());
|
||||
StatAction task = new StatAction(relevantPlayerNames, requestSettings, resultingStatNumbers);
|
||||
|
||||
|
@ -25,7 +25,7 @@ public abstract class FileHandler {
|
||||
loadFile();
|
||||
}
|
||||
|
||||
public void loadFile() {
|
||||
private void loadFile() {
|
||||
JavaPlugin plugin = Main.getPluginInstance();
|
||||
|
||||
file = new File(plugin.getDataFolder(), fileName);
|
||||
@ -48,7 +48,7 @@ public abstract class FileHandler {
|
||||
return fileConfiguration;
|
||||
}
|
||||
|
||||
public void addValuesToFile(@NotNull Map<String, Object> keyValuePairs) {
|
||||
public void addValues(@NotNull Map<String, Object> keyValuePairs) {
|
||||
keyValuePairs.forEach(this::setValue);
|
||||
save();
|
||||
updateFile();
|
||||
@ -59,7 +59,7 @@ public abstract class FileHandler {
|
||||
* (or expanded if it already exists)
|
||||
* @param value the value(s) to expand the List with
|
||||
*/
|
||||
public void addEntryToListInFile(@NotNull String key, @NotNull String value) {
|
||||
public void writeEntryToList(@NotNull String key, @NotNull String value) {
|
||||
List<String> existingList = fileConfiguration.getStringList(key);
|
||||
|
||||
List<String> updatedList = existingList.stream()
|
||||
@ -72,7 +72,7 @@ public abstract class FileHandler {
|
||||
updateFile();
|
||||
}
|
||||
|
||||
public void removeEntryFromListInFile(@NotNull String key, @NotNull String value) {
|
||||
public void removeEntryFromList(@NotNull String key, @NotNull String value) {
|
||||
List<String> currentValues = fileConfiguration.getStringList(key);
|
||||
|
||||
if (currentValues.remove(value)) {
|
||||
|
@ -4,7 +4,6 @@ import com.artemis.the.gr8.playerstats.config.ConfigHandler;
|
||||
import com.artemis.the.gr8.playerstats.multithreading.ThreadManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ -13,7 +12,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A utility class that deals with OfflinePlayers. It stores a list
|
||||
@ -25,14 +23,13 @@ public final class OfflinePlayerHandler extends FileHandler {
|
||||
|
||||
private static volatile OfflinePlayerHandler instance;
|
||||
private final ConfigHandler config;
|
||||
private static FileConfiguration excludedPlayers;
|
||||
private static ConcurrentHashMap<String, UUID> offlinePlayerUUIDs;
|
||||
private static ConcurrentHashMap<String, UUID> includedPlayerUUIDs;
|
||||
private static ConcurrentHashMap<String, UUID> excludedPlayerUUIDs;
|
||||
|
||||
private OfflinePlayerHandler() {
|
||||
super("excluded_players.yml");
|
||||
config = ConfigHandler.getInstance();
|
||||
|
||||
excludedPlayers = super.getFileConfiguration();
|
||||
loadOfflinePlayers();
|
||||
}
|
||||
|
||||
@ -53,8 +50,6 @@ public final class OfflinePlayerHandler extends FileHandler {
|
||||
@Override
|
||||
public void reload() {
|
||||
super.reload();
|
||||
excludedPlayers = super.getFileConfiguration();
|
||||
|
||||
loadOfflinePlayers();
|
||||
}
|
||||
|
||||
@ -66,43 +61,40 @@ public final class OfflinePlayerHandler extends FileHandler {
|
||||
* @return true if this player is included
|
||||
*/
|
||||
public boolean isLoadedPlayer(String playerName) {
|
||||
return offlinePlayerUUIDs.containsKey(playerName);
|
||||
return includedPlayerUUIDs.containsKey(playerName);
|
||||
}
|
||||
|
||||
public void addPlayerToExcludeList(UUID uniqueID) {
|
||||
super.addEntryToListInFile("excluded", uniqueID.toString());
|
||||
public boolean isExcludedPlayer(String playerName) {
|
||||
return excludedPlayerUUIDs.containsKey(playerName);
|
||||
}
|
||||
|
||||
public void removePlayerFromExcludeList(UUID uniqueID) {
|
||||
super.removeEntryFromListInFile("excluded", uniqueID.toString());
|
||||
public boolean isExcludedPlayer(UUID uniqueID) {
|
||||
return excludedPlayerUUIDs.containsValue(uniqueID);
|
||||
}
|
||||
|
||||
public List<String> getListOfExcludedPlayerNames() {
|
||||
List<String> excludedUUIDs = excludedPlayers.getStringList("excluded");
|
||||
return excludedUUIDs.stream()
|
||||
.map(UUID::fromString)
|
||||
.map(Bukkit::getOfflinePlayer)
|
||||
.map(OfflinePlayer::getName)
|
||||
.collect(Collectors.toList());
|
||||
public void addLoadedPlayerToExcludeList(String playerName) throws IllegalArgumentException {
|
||||
UUID uuid = includedPlayerUUIDs.get(playerName);
|
||||
if (uuid == null) {
|
||||
throw new IllegalArgumentException("This player is not loaded, and therefore cannot be excluded!");
|
||||
}
|
||||
super.writeEntryToList("excluded", uuid.toString());
|
||||
includedPlayerUUIDs.remove(playerName);
|
||||
excludedPlayerUUIDs.put(playerName, uuid);
|
||||
}
|
||||
|
||||
public boolean isExcluded(UUID uniqueID) {
|
||||
List<String> excluded = excludedPlayers.getStringList("excluded");
|
||||
|
||||
return excluded.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(UUID::fromString)
|
||||
.anyMatch(uuid -> uuid.equals(uniqueID));
|
||||
public void addExcludedPlayerToLoadedList(String playerName) {
|
||||
UUID uuid = excludedPlayerUUIDs.get(playerName);
|
||||
if (uuid == null) {
|
||||
throw new IllegalArgumentException("This player is not excluded, and therefore cannot be un-excluded!");
|
||||
}
|
||||
super.removeEntryFromList("excluded", uuid.toString());
|
||||
excludedPlayerUUIDs.remove(playerName);
|
||||
includedPlayerUUIDs.put(playerName, uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of OfflinePlayers that are
|
||||
* currently included in statistic calculations.
|
||||
*
|
||||
* @return the number of included OfflinePlayers
|
||||
*/
|
||||
public int getOfflinePlayerCount() {
|
||||
return offlinePlayerUUIDs.size();
|
||||
@Contract(" -> new")
|
||||
public @NotNull ArrayList<String> getExcludedPlayerNames() {
|
||||
return Collections.list(excludedPlayerUUIDs.keys());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -112,8 +104,18 @@ public final class OfflinePlayerHandler extends FileHandler {
|
||||
* @return the ArrayList
|
||||
*/
|
||||
@Contract(" -> new")
|
||||
public @NotNull ArrayList<String> getOfflinePlayerNames() {
|
||||
return Collections.list(offlinePlayerUUIDs.keys());
|
||||
public @NotNull ArrayList<String> getLoadedOfflinePlayerNames() {
|
||||
return Collections.list(includedPlayerUUIDs.keys());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of OfflinePlayers that are
|
||||
* currently included in statistic calculations.
|
||||
*
|
||||
* @return the number of included OfflinePlayers
|
||||
*/
|
||||
public int getOfflinePlayerCount() {
|
||||
return includedPlayerUUIDs.size();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -126,8 +128,8 @@ public final class OfflinePlayerHandler extends FileHandler {
|
||||
* of players that should be included in statistic calculations
|
||||
*/
|
||||
public @NotNull OfflinePlayer getOfflinePlayer(String playerName) throws IllegalArgumentException {
|
||||
if (offlinePlayerUUIDs.get(playerName) != null) {
|
||||
return Bukkit.getOfflinePlayer(offlinePlayerUUIDs.get(playerName));
|
||||
if (includedPlayerUUIDs.get(playerName) != null) {
|
||||
return Bukkit.getOfflinePlayer(includedPlayerUUIDs.get(playerName));
|
||||
}
|
||||
else {
|
||||
MyLogger.logWarning("Cannot calculate statistics for player-name: " + playerName +
|
||||
@ -139,29 +141,51 @@ public final class OfflinePlayerHandler extends FileHandler {
|
||||
|
||||
private void loadOfflinePlayers() {
|
||||
Executors.newSingleThreadExecutor().execute(() -> {
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
OfflinePlayer[] offlinePlayers;
|
||||
if (config.whitelistOnly()) {
|
||||
offlinePlayers = getWhitelistedPlayers();
|
||||
}
|
||||
else if (config.excludeBanned()) {
|
||||
offlinePlayers = getNonBannedPlayers();
|
||||
}
|
||||
else {
|
||||
offlinePlayers = Bukkit.getOfflinePlayers();
|
||||
}
|
||||
|
||||
int size = offlinePlayerUUIDs != null ? offlinePlayerUUIDs.size() : 16;
|
||||
offlinePlayerUUIDs = new ConcurrentHashMap<>(size);
|
||||
|
||||
ForkJoinPool.commonPool().invoke(ThreadManager.getPlayerLoadAction(offlinePlayers, offlinePlayerUUIDs));
|
||||
|
||||
MyLogger.actionFinished();
|
||||
MyLogger.logLowLevelTask(("Loaded " + offlinePlayerUUIDs.size() + " offline players"), time);
|
||||
loadExcludedPlayerNames();
|
||||
loadIncludedOfflinePlayers();
|
||||
});
|
||||
}
|
||||
|
||||
private void loadIncludedOfflinePlayers() {
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
OfflinePlayer[] offlinePlayers;
|
||||
if (config.whitelistOnly()) {
|
||||
offlinePlayers = getWhitelistedPlayers();
|
||||
} else if (config.excludeBanned()) {
|
||||
offlinePlayers = getNonBannedPlayers();
|
||||
} else {
|
||||
offlinePlayers = Bukkit.getOfflinePlayers();
|
||||
}
|
||||
|
||||
int size = includedPlayerUUIDs != null ? includedPlayerUUIDs.size() : 16;
|
||||
includedPlayerUUIDs = new ConcurrentHashMap<>(size);
|
||||
|
||||
ForkJoinPool.commonPool().invoke(ThreadManager.getPlayerLoadAction(offlinePlayers, includedPlayerUUIDs));
|
||||
|
||||
MyLogger.actionFinished();
|
||||
MyLogger.logLowLevelTask(("Loaded " + includedPlayerUUIDs.size() + " offline players"), time);
|
||||
}
|
||||
|
||||
private void loadExcludedPlayerNames() {
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
excludedPlayerUUIDs = new ConcurrentHashMap<>();
|
||||
List<String> excluded = super.getFileConfiguration().getStringList("excluded");
|
||||
excluded.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(UUID::fromString)
|
||||
.forEach(uuid -> {
|
||||
OfflinePlayer player = Bukkit.getOfflinePlayer(uuid);
|
||||
String playerName = player.getName();
|
||||
if (playerName != null) {
|
||||
excludedPlayerUUIDs.put(playerName, uuid);
|
||||
}
|
||||
});
|
||||
|
||||
MyLogger.logLowLevelTask("Loaded " + excludedPlayerUUIDs.size() + " excluded players from file", time);
|
||||
}
|
||||
|
||||
private OfflinePlayer[] getWhitelistedPlayers() {
|
||||
return Bukkit.getWhitelistedPlayers().toArray(OfflinePlayer[]::new);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user