diff --git a/.idea/EnhancedBungeeList.iml b/.idea/EnhancedBungeeList.iml index a276d847..5a366a81 100644 --- a/.idea/EnhancedBungeeList.iml +++ b/.idea/EnhancedBungeeList.iml @@ -26,5 +26,23 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/Config.yml b/resources/Config.yml index 3c6f98eb..dd6b37f3 100644 --- a/resources/Config.yml +++ b/resources/Config.yml @@ -9,10 +9,16 @@ command: # Aliases of the List Command, for example, if you set "blist" and "bls" as aliases of # the List Command then you can use /blist and /bls to display the enhanced Bungee List. aliases: - - "blist" - - "bls" + - "blist" + - "bls" formats: global-list: + # Format for the -sp option + server-sp-option: + # The main format of the -sp option, this is displayed below of the server row + # when uses /glist -sp + main-format: '&a{SERVER_NAME}: &8[{PLAYERS_FORMAT}&8]' + players-format: '&f{PLAYER_NAME}&7, ' # Available Formats: # {SERVER_NAME} = Replaced by the server name configured in the Config.yml of your BungeeCord Server. # {PLAYER_AMOUNT} = Amount of players connected to the server. @@ -30,16 +36,16 @@ formats: # {LABEL} = Label or alias used to display the Enhanced List. # {TOTAL_PLAYER_AMOUNT} = Amount of total players in the Network. full-message-format: - - "&8&m&l----------------------------------&r" - - " &eList of all servers on the Network:" - - "" - - "{SERVERS_ROWS}" - - "" - - " &7&oAnd &f&o{NOT_DISPLAYED_AMOUNT} &7&oservers not displayed.&r" - - " &6Total Players: &f{TOTAL_PLAYER_AMOUNT}" - - "" - - " &fTIP: &7Use &e/{LABEL} &7to display a list of all players in the specified server." - - "&8&m&l----------------------------------" + - "&8&m&l----------------------------------&r" + - " &eList of all servers on the Network:" + - "" + - "{SERVERS_ROWS}" + - "" + - " &7&oAnd &f&o{NOT_DISPLAYED_AMOUNT} &7&oservers not displayed.&r" + - " &6Total Players: &f{TOTAL_PLAYER_AMOUNT}" + - "" + - " &fTIP: &7Use &e/{LABEL} &7to display a list of all players in the specified server." + - "&8&m&l----------------------------------" # Message when no rows are available to display in the {SERVERS_ROW} format (configured previously). no-servers-format: " &cNo servers to display." server-list: @@ -52,26 +58,26 @@ formats: # {PLAYERS_ROWS} = Rows that displays the players names that are in the server. # {PAGINATION_CONTROLLER} = Pagination controller (for previous and next page). full-message-format: - - "&8&m--------------------------------------&r" - - " &6Server Name: &f{SERVER_NAME}" - - " &6Players: &f{PLAYERS_COUNT}" - - " &eDisplaying page &f{PAGE} &6of &f{TOTAL_PAGES}" - - "" - - "{PLAYERS_ROWS}" - - "{PAGINATION_CONTROLLER}" - - "&8&m--------------------------------------" + - "&8&m--------------------------------------&r" + - " &6Server Name: &f{SERVER_NAME}" + - " &6Players: &f{PLAYERS_COUNT}" + - " &eDisplaying page &f{PAGE} &6of &f{TOTAL_PAGES}" + - "" + - "{PLAYERS_ROWS}" + - "{PAGINATION_CONTROLLER}" + - "&8&m--------------------------------------" # Message displayed when the executor tries to retrieve a page that are out of the index bounds. # Available Formats: # {TOTAL_PAGES} = Total number of pages. no-page-data-message: - - "&8&m--------------------------------------&r" - - " &cNo data to show in this page! Please try with a another page between &f1 &cand &f{TOTAL_PAGES}&c." - - "&8&m--------------------------------------" + - "&8&m--------------------------------------&r" + - " &cNo data to show in this page! Please try with a another page between &f1 &cand &f{TOTAL_PAGES}&c." + - "&8&m--------------------------------------" # Message displayed when the executor tries to list a server that not have players. no-players-message: - - "&8&m--------------------------------------&r" - - " &cThis server not have players at this moment." - - "&8&m--------------------------------------" + - "&8&m--------------------------------------&r" + - " &cThis server not have players at this moment." + - "&8&m--------------------------------------" behaviour: global-list: # Hide servers that not have players in the Enhanced List. @@ -94,15 +100,72 @@ behaviour: players-per-page: 16 # A list of servers names that you want to ignore/hide. blacklisted-servers: - - "Login" + - "Login" + # Set as true to show server names in upper case global-list-uppercase-server-names: false + # Set as true to show the server name in upper case (/glist ) server-list-uppercase-server-name: false + # Configurations related to the Group System + # If enabled, plugin will show the respective prefix of each player + # using LuckPerms (if available), or the internal Group System (GroupsPrefix.yml) + groups-prefix: + # Set as true to enable prefixes + enable: true + use: + # Set as true if you want to use LuckPerms to get the prefix of a player + # Only applicable if LuckPerms is present in your BungeeCord server + luckperms: true + # Set as true to use the internal Group System of the plugin + # Configurable though the GroupsPrefix.yml configuration + internal-group-system: true + # Set the priority to use, for example, if you enable LuckPerms and internal Group System + # and you have set LuckPerms with a priority of 20 and the internal Group System with a + # priority of 1, if a certain player has a prefix through LuckPerms but also is applicable + # for a prefix through the internal Group System, then the LuckPerms prefix will be + # preferred and displayed as the current prefix of the player discarding the prefix of the + # internal Group System + priority: + luckperms: 20 + internal-group-system: 1 messages: - server-players: "{SERVER_NAME} players:" cannot-found-server: "&cThe specified server name {NAME} &ccannot be found in the Network." previous-page-hover-message: "&eClick here to go to the page &f#{PAGE_NUMBER}" next-page-hover-message: "&eClick here to go to the page &f#{PAGE_NUMBER}" previous-page: "Previous Page" next-page: "Next Page" no-previous-page: "&cNo previous page available." - no-next-page: "&cNo next page available." \ No newline at end of file + no-next-page: "&cNo next page available." + all-pages: "Todas las Páginas" +updates: + # Set as true to check updates periodically + check-updates: true + # Notify configurations only have effect if you have set "check-updates" as true + notify: + # Set as true to receive notifications in-game when a new update is available + enable: true + # Delay in milliseconds before the update message will be send to the player that have the correct permission + delay-ms: 2500 + # Permission required to show the notification + permission: "ebcl.update.notify" + # Message to use as notification + message: + - "&8&m-------------[&r &aEnhancedBungeeList &8&m]-------------" + - "&eA new update is available! Download:" + - "&bhttps://www.spigotmc.org/resources/enhancedbungeelist.53295/" + - "&8&m----------------------------------------------" +# Configure server groups. +# If you define a group with multiples servers, then all servers will be threaded as one server +# when you use the /glist command +servers: + groups: + - group-id: "bedwars" + servers: + - "bedwars1" + - "bedwars2" + - "bedwars3" + - "bedwars4" + - group-id: "lobby" + servers: + - "lobby1" + - "lobby2" + - "lobby3" diff --git a/resources/Groups.yml b/resources/GroupsPrefix.yml similarity index 98% rename from resources/Groups.yml rename to resources/GroupsPrefix.yml index c283107a..288230c5 100644 --- a/resources/Groups.yml +++ b/resources/GroupsPrefix.yml @@ -56,4 +56,4 @@ groups: # IF DEFAULT GROUP IS TRUE, THIS SETTING IS IGNORED. # prefix-visible-to-users: true name-color: "&7" - default-group: true \ No newline at end of file + default-group: true diff --git a/resources/bungee.yml b/resources/bungee.yml index ec516349..378b0d0b 100644 --- a/resources/bungee.yml +++ b/resources/bungee.yml @@ -1,4 +1,4 @@ name: EnhancedBungeeList author: Wirlie -version: 1.0.7 -main: dev.wirlie.bungeecord.glist.EnhancedBCL \ No newline at end of file +version: 1.0.8 +main: dev.wirlie.bungeecord.glist.EnhancedBCL diff --git a/src/dev/wirlie/bungeecord/glist/ConfigurationValidator.java b/src/dev/wirlie/bungeecord/glist/ConfigurationValidator.java deleted file mode 100644 index 8bca56ae..00000000 --- a/src/dev/wirlie/bungeecord/glist/ConfigurationValidator.java +++ /dev/null @@ -1,164 +0,0 @@ -package dev.wirlie.bungeecord.glist; - -import net.md_5.bungee.config.Configuration; - -import java.util.Arrays; -import java.util.Collections; - -public class ConfigurationValidator { - public static void validate(EnhancedBCL plugin) { - Configuration configuration = plugin.getConfig(); - - boolean needCommentsFix = false; - - if(!configuration.contains("formats.global-list.server-sp-option.main-format")) { - needCommentsFix = true; - configuration.set("formats.global-list.server-sp-option.main-format", "&a{SERVER_NAME}: &8[{PLAYERS_FORMAT}&8]"); - } - - if(!configuration.contains("formats.global-list.server-sp-option.players-format")) { - needCommentsFix = true; - configuration.set("formats.global-list.server-sp-option.players-format", "&f{PLAYER_NAME}&7, "); - } - - if(!configuration.contains("command.global-list.label")) { - needCommentsFix = true; - configuration.set("command.global-list.label", "glist"); - } - - if(!configuration.contains("command.global-list.permission")) { - needCommentsFix = true; - configuration.set("command.global-list.permission", "bungeecord.command.list"); - } - - if(!configuration.contains("command.global-list.aliases")) { - needCommentsFix = true; - configuration.set("command.global-list.aliases", Arrays.asList("blist", "bls")); - } - - if(!configuration.contains("formats.global-list.server-row-format")) { - needCommentsFix = true; - configuration.set("formats.global-list.server-row-format", " &b{SERVER_NAME} &6{PLAYER_AMOUNT} &8{GRAPHIC_BAR} &8[&6{PERCENT}&8]"); - } - - if(!configuration.contains("formats.global-list.graphic-background-color")) { - needCommentsFix = true; - configuration.set("formats.global-list.graphic-background-color", "&8&l"); - } - - if(!configuration.contains("formats.global-list.graphic-bar-color")) { - needCommentsFix = true; - configuration.set("formats.global-list.graphic-bar-color", "&7&l"); - } - - if(!configuration.contains("formats.global-list.full-message-format")) { - needCommentsFix = true; - configuration.set("formats.global-list.full-message-format", Arrays.asList("&8&m&l----------------------------------&r", " &eList of all servers on the Network:", "", "{SERVERS_ROWS}", "", " &7&oAnd &f&o{NOT_DISPLAYED_AMOUNT} &7&oservers not displayed.&r", " &6Total Players: &f{TOTAL_PLAYER_AMOUNT}", "", " &fTIP: &7Use &e/{LABEL} &7to display a list of all players in the specified server.", "&8&m&l----------------------------------")); - } - - if(!configuration.contains("formats.global-list.no-servers-format")) { - needCommentsFix = true; - configuration.set("formats.global-list.no-servers-format", " &cNo servers to display."); - } - - if(!configuration.contains("formats.server-list.full-message-format")) { - needCommentsFix = true; - configuration.set("formats.server-list.full-message-format", Arrays.asList("&8&m--------------------------------------&r", " &6Server Name: &f{SERVER_NAME}", " &6Players: &f{PLAYERS_COUNT}", " &eDisplaying page &f{PAGE} &6of &f{TOTAL_PAGES}", "", "{PLAYERS_ROWS}", "{PAGINATION_CONTROLLER}", "&8&m--------------------------------------")); - } - - if(!configuration.contains("formats.server-list.no-page-data-message")) { - needCommentsFix = true; - configuration.set("formats.server-list.no-page-data-message", Arrays.asList("&8&m--------------------------------------&r", " &cNo data to show in this page! Please try with a another page between &f1 &cand &f{TOTAL_PAGES}&c.", "&8&m--------------------------------------")); - } - - if(!configuration.contains("formats.server-list.no-players-message")) { - needCommentsFix = true; - configuration.set("formats.server-list.no-players-message", Arrays.asList("&8&m--------------------------------------&r", " &cThis server not have players at this moment.", "&8&m--------------------------------------")); - } - - if(!configuration.contains("behaviour.global-list.hide-empty-servers")) { - needCommentsFix = true; - configuration.set("behaviour.global-list.hide-empty-servers", true); - } - - if(!configuration.contains("behaviour.global-list.max-servers-rows")) { - needCommentsFix = true; - configuration.set("behaviour.global-list.max-servers-rows", 20); - } - - if(!configuration.contains("behaviour.global-list.min-player-count-to-display-server")) { - needCommentsFix = true; - configuration.set("behaviour.global-list.min-player-count-to-display-server", 3); - } - - if(!configuration.contains("behaviour.server-list.players-per-page")) { - needCommentsFix = true; - configuration.set("behaviour.server-list.players-per-page", 16); - } - - if(!configuration.contains("behaviour.blacklisted-servers")) { - needCommentsFix = true; - configuration.set("behaviour.blacklisted-servers", Collections.singletonList("Login")); - } - - if(!configuration.contains("messages.server-players")) { - needCommentsFix = true; - configuration.set("messages.server-players", "{SERVER_NAME} players:"); - } - - if(!configuration.contains("messages.cannot-found-server")) { - needCommentsFix = true; - configuration.set("messages.cannot-found-server", "&cThe specified server name {NAME} &ccannot be found in the Network."); - } - - if(!configuration.contains("messages.previous-page-hover-message")) { - needCommentsFix = true; - configuration.set("messages.previous-page-hover-message", "&eClick here to go to the page &f#{PAGE_NUMBER}"); - } - - if(!configuration.contains("messages.next-page-hover-message")) { - needCommentsFix = true; - configuration.set("messages.next-page-hover-message", "&eClick here to go to the page &f#{PAGE_NUMBER}"); - } - - if(!configuration.contains("messages.previous-page")) { - needCommentsFix = true; - configuration.set("messages.previous-page", "Previous Page"); - } - - if(!configuration.contains("messages.next-page")) { - needCommentsFix = true; - configuration.set("messages.next-page", "Next Page"); - } - - if(!configuration.contains("messages.no-previous-page")) { - needCommentsFix = true; - configuration.set("messages.no-previous-page", "&cNo previous page available."); - } - - if(!configuration.contains("messages.no-next-page")) { - needCommentsFix = true; - configuration.set("messages.no-next-page", "&cNo next page available."); - } - - if(!configuration.contains("behaviour.global-list-uppercase-server-names")) { - needCommentsFix = true; - configuration.set("behaviour.global-list-uppercase-server-names", false); - } - - if(!configuration.contains("behaviour.server-list-uppercase-server-name")) { - needCommentsFix = true; - configuration.set("behaviour.server-list-uppercase-server-name", false); - } - - plugin.saveConfig(); - - if(needCommentsFix) { - fixComments(plugin); - } - } - - private static void fixComments(EnhancedBCL plugin) { - //TODO - } -} diff --git a/src/dev/wirlie/bungeecord/glist/DefaultValues.java b/src/dev/wirlie/bungeecord/glist/DefaultValues.java deleted file mode 100644 index c8b12ddc..00000000 --- a/src/dev/wirlie/bungeecord/glist/DefaultValues.java +++ /dev/null @@ -1,57 +0,0 @@ -package dev.wirlie.bungeecord.glist; - -import java.util.*; - -public class DefaultValues { - private static Map defaults = new HashMap<>(); - - public DefaultValues() { - super(); - } - - public static String getDefaultString(final String path) { - return (String) DefaultValues.defaults.get(path); - } - - public static int getDefaultInt(final String path) { - return (int) DefaultValues.defaults.get(path); - } - - public static List getDefaultStringList(final String path) { - //noinspection unchecked - return (List) DefaultValues.defaults.get(path); - } - - public static boolean getDefaultBoolean(final String path) { - return (boolean) DefaultValues.defaults.get(path); - } - - static { - DefaultValues.defaults.put("command.global-list.label", "glist"); - DefaultValues.defaults.put("command.global-list.permission", "ebl.command.list"); - DefaultValues.defaults.put("command.global-list.aliases", Arrays.asList("blist", "bls")); - DefaultValues.defaults.put("formats.global-list.server-row-format", " &b{SERVER_NAME} &6{PLAYER_AMOUNT} &8{GRAPHIC_BAR} &8[&6{PERCENT}&8]"); - DefaultValues.defaults.put("formats.global-list.graphic-background-color", "&8&l"); - DefaultValues.defaults.put("formats.global-list.graphic-bar-color", "&7&l"); - DefaultValues.defaults.put("formats.global-list.full-message-format", "&8&m&l----------------------------------&r\n &eList of all servers on the Network:\n\n{SERVERS_ROWS}\n\n &7&oAnd &f&o{NOT_DISPLAYED_AMOUNT} &7&oservers not displayed.&r\n &6Total Players: &f{TOTAL_PLAYER_AMOUNT}\n\n &fTIP: &7Use &e/{LABEL} &7to display a list of all players in the specified server.\n&8&m&l----------------------------------"); - DefaultValues.defaults.put("formats.global-list.no-servers-format", " &cNo servers to display."); - DefaultValues.defaults.put("formats.server-list.full-message-format", "&8&m--------------------------------------&r\n &6Server Name: &f{SERVER_NAME}\n &6Players: &f{PLAYERS_COUNT}\n &eDisplaying page &f{PAGE} &6of &f{TOTAL_PAGES}\n\n{PLAYERS_ROWS}\n{PAGINATION_CONTROLLER}\n&8&m--------------------------------------"); - DefaultValues.defaults.put("formats.server-list.no-page-data-message", "&8&m--------------------------------------&r\n &cNo data to show in this page! Please try with a another page between &f1 &cand &f{TOTAL_PAGES}&c.\n&8&m--------------------------------------"); - DefaultValues.defaults.put("formats.server-list.no-players-message", "&8&m--------------------------------------&r\n &cThis server not have players at this moment.\n&8&m--------------------------------------"); - DefaultValues.defaults.put("behaviour.global-list.hide-empty-servers", true); - DefaultValues.defaults.put("behaviour.global-list.max-servers-rows", 20); - DefaultValues.defaults.put("behaviour.global-list.min-player-count-to-display-server", 3); - DefaultValues.defaults.put("behaviour.server-list.players-per-page", 16); - DefaultValues.defaults.put("behaviour.blacklisted-servers", new ArrayList()); - DefaultValues.defaults.put("messages.server-players", "{SERVER_NAME} players"); - DefaultValues.defaults.put("messages.cannot-found-server", "&cThe specified server name {NAME} &ccannot be found in the Network."); - DefaultValues.defaults.put("messages.previous-page-hover-message", "&eClick here to go to the page &f#{PAGE_NUMBER}"); - DefaultValues.defaults.put("messages.next-page-hover-message", "&eClick here to go to the page &f#{PAGE_NUMBER}"); - DefaultValues.defaults.put("messages.previous-page", "Previous Page"); - DefaultValues.defaults.put("messages.next-page", "Next Page"); - DefaultValues.defaults.put("messages.no-previous-page", "&cNo previous page available."); - DefaultValues.defaults.put("messages.no-next-page", "&cNo next page available."); - DefaultValues.defaults.put("formats.global-list.server-sp-option.main-format", "&a{SERVER_NAME}: &8[{PLAYERS_FORMAT}&8]"); - DefaultValues.defaults.put("formats.global-list.server-sp-option.players-format", "&f{PLAYER_NAME}&7, "); - } -} \ No newline at end of file diff --git a/src/dev/wirlie/bungeecord/glist/EnhancedBCL.java b/src/dev/wirlie/bungeecord/glist/EnhancedBCL.java index 7b98bd5c..b19cb316 100644 --- a/src/dev/wirlie/bungeecord/glist/EnhancedBCL.java +++ b/src/dev/wirlie/bungeecord/glist/EnhancedBCL.java @@ -3,24 +3,46 @@ import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import java.util.stream.Collectors; +import dev.wirlie.bungeecord.glist.config.Config; +import dev.wirlie.bungeecord.glist.config.ConfigEntry; +import dev.wirlie.bungeecord.glist.executor.GlistCommand; +import dev.wirlie.bungeecord.glist.executor.EBLCommand; import dev.wirlie.bungeecord.glist.groups.GroupManager; +import dev.wirlie.bungeecord.glist.hooks.GroupHook; +import dev.wirlie.bungeecord.glist.hooks.InternalGroupSystemHook; +import dev.wirlie.bungeecord.glist.hooks.LuckPermsHook; +import dev.wirlie.bungeecord.glist.servers.ServerGroup; +import dev.wirlie.bungeecord.glist.updater.UpdateNotifyListener; +import dev.wirlie.bungeecord.glist.updater.UpdateChecker; import net.md_5.bungee.BungeeCord; +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.config.ServerInfo; +import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.PluginManager; import net.md_5.bungee.config.Configuration; import net.md_5.bungee.config.ConfigurationProvider; import net.md_5.bungee.config.YamlConfiguration; +import org.jetbrains.annotations.Nullable; public class EnhancedBCL extends Plugin { + + public static final List> CONFIGURATIONS_REGISTRY = new ArrayList<>(); + private Configuration config = null; private ConfigurationProvider yamlProvider = null; private File configFile = null; - private ListExecutor commandExecutor = null; - private GroupManager groupManager; + private GlistCommand commandExecutor = null; + + private final List groupHooks = new ArrayList<>(); + private final List serverGroups = new ArrayList<>(); public void onEnable() { //declaration of commons variables @@ -31,69 +53,172 @@ public void onEnable() { logger.info("Enabling plugin ..."); configFile = new File(this.getDataFolder() + File.separator + "Config.yml"); - getLogger().info("Validating Config.yml ..."); - ConfigurationValidator.validate(this); + logger.info("Preparing and validating configuration ..."); + try { + //make initialization of static variables... + //noinspection InstantiationOfUtilityClass + new Config(); + + prepareConfig(); + } catch (IOException e) { + e.printStackTrace(); + return; + } logger.info("Registering /ebl command ..."); - pm.registerCommand(this, new PluginExecutor(this)); + + logger.info("Registering /ebl command ..."); + pm.registerCommand(this, new EBLCommand(this)); registerListExecutor(true); - groupManager = new GroupManager(this); + + if(Config.UPDATES__CHECK_UPDATES.get()) { + UpdateChecker updateChecker = new UpdateChecker(this); + updateChecker.getSpigotVersion(v -> {}, Throwable::printStackTrace); + + pm.registerListener(this, new UpdateNotifyListener(this)); + } } - public GroupManager getGroupManager() { - return groupManager; + public List getGroupHooks() { + return groupHooks; } - public Configuration getConfig() { - if (config == null) { - loadConfig(); + public ConfigurationProvider getYamlProvider() { + return yamlProvider; + } + + private void prepareConfig() throws IOException { + getLogger().info("Starting verification of " + CONFIGURATIONS_REGISTRY.size() + " configurations..."); + + if(!configFile.exists()) { + File parent = configFile.getParentFile(); + + if(!parent.exists()) { + parent.mkdirs(); + } + + Files.copy(getClass().getResourceAsStream("/Config.yml"), configFile.toPath()); } - return this.config; - } + config = yamlProvider.load(new InputStreamReader(new FileInputStream(configFile), StandardCharsets.UTF_8)); - public void reloadConfig() { - config = null; + Configuration defaultConfiguration = yamlProvider.load(new InputStreamReader(getClass().getResourceAsStream("/Config.yml"), StandardCharsets.UTF_8)); - registerListExecutor(false); - getGroupManager().loadGroups(); - } + boolean shouldSave = false; + for(ConfigEntry pendingResolution : CONFIGURATIONS_REGISTRY) { + if(!config.contains(pendingResolution.getKey()) || config.get(pendingResolution.getKey()) == null) { + getLogger().warning("Missing configuration [" + pendingResolution.getKey() + "], trying to get fallback value..."); - @SuppressWarnings("unused") - public void saveConfig() { - if (config != null) { - try { - yamlProvider.save(config, new OutputStreamWriter(new FileOutputStream(configFile), StandardCharsets.UTF_8)); - } catch (IOException e) { - e.printStackTrace(); + //get fallback value + Object fallbackValue = defaultConfiguration.get(pendingResolution.getKey()); + + if(fallbackValue == null) { + throw new IOException("Cannot get default value of [" + pendingResolution.getKey() + "] from default Configuration..."); + } + + config.set(pendingResolution.getKey(), fallbackValue); + pendingResolution.setValue(fallbackValue); + shouldSave = true; + } else { + pendingResolution.setValue(config.get(pendingResolution.getKey())); } } - } + if(shouldSave) { + saveConfig(); + } + + //hooks + groupHooks.clear(); - private void loadConfig() { - if (!configFile.exists()) { - if (!configFile.getParentFile().mkdirs()) { - getLogger().warning("Cannot make parent dir: " + configFile.getParentFile().getAbsolutePath()); + if(Config.BEHAVIOUR__GROUPS_PREFIX__ENABLE.get()) { + if (Config.BEHAVIOUR__GROUPS_PREFIX__USE__LUCKPERMS.get() && BungeeCord.getInstance().getPluginManager().getPlugin("LuckPerms") != null) { + getLogger().info("LuckPerms Hooked!"); + groupHooks.add(new LuckPermsHook()); } - try (InputStream in = getResourceAsStream("Config.yml")) { - Files.copy(in, configFile.toPath()); - } catch (IOException e) { - e.printStackTrace(); + if (Config.BEHAVIOUR__GROUPS_PREFIX__USE__INTERNAL_GROUP_SYSTEM.get()) { + getLogger().info("Enabling internal Group System"); + groupHooks.add(new InternalGroupSystemHook(this)); + } + + //sort group hooks by priority + groupHooks.sort((v1, v2) -> Integer.compare(v2.getPriority(), v1.getPriority())); + + if (groupHooks.isEmpty()) { + getLogger().warning("Player prefixes are enabled but LuckPerms and the internal Group System are disabled, so... player prefixes will be disabled."); } } - try { - config = yamlProvider.load(new InputStreamReader(new FileInputStream(configFile), StandardCharsets.UTF_8)); - } catch (FileNotFoundException e) { - e.printStackTrace(); + //server groups + serverGroups.clear(); + + for(Map configuration : Config.SERVERS__GROUPS.get()) { + String id = null; + List serversIds = null; + + for(Map.Entry entry : configuration.entrySet()) { + if(entry.getKey().equalsIgnoreCase("group-id")) { + id = (String) entry.getValue(); + } else if(entry.getKey().equalsIgnoreCase("servers")) { + //noinspection unchecked + serversIds = (List) entry.getValue(); + } + } + + if(id == null || serversIds == null) { + getLogger().warning("Not valid server group found! Missing id or server list..."); + getLogger().warning("Full map: {" + (configuration.entrySet().stream().map((e) -> "[k=" + e.getKey() + ",v=" + e.getValue() + "]").collect(Collectors.joining(","))) + "}"); + continue; + } + + BungeeCord bc = BungeeCord.getInstance(); + List matchedServers = new ArrayList<>(); + + for(String sid : serversIds) { + ServerInfo server = bc.getServerInfo(sid); + + if(server == null) { + continue; + } + + matchedServers.add(server); + } + + if(matchedServers.isEmpty()) { + continue; + } + + String finalId = id; + if(serverGroups.stream().anyMatch(s -> s.getId().equalsIgnoreCase(finalId))) { + getLogger().warning("Duplicated server group [id=" + finalId + "], skipping duplicated definition..."); + continue; + } + + getLogger().info("New server group found, id=" + id + " with " + matchedServers.size() + " servers"); + ServerGroup group = new ServerGroup(id); + group.setServers(matchedServers); + serverGroups.add(group); } } - public Configuration loadConfiguration(File file) throws IOException { - return yamlProvider.load(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)); + public void reloadConfig() throws IOException { + prepareConfig(); + groupHooks.forEach(GroupHook::reload); + registerListExecutor(false); + commandExecutor.reload(); + } + + private void saveConfig() { + if (config != null) { + try { + yamlProvider.save(config, new OutputStreamWriter(new FileOutputStream(configFile), StandardCharsets.UTF_8)); + } catch (IOException e) { + e.printStackTrace(); + } + } + } private void registerListExecutor(boolean firstRegister) { @@ -102,14 +227,14 @@ private void registerListExecutor(boolean firstRegister) { } //read configuration - String label = this.getConfig().getString("command.global-list.label", "glist"); + String label = Config.COMMAND__GLIST__LABEL.get(); getLogger().info("Loading /" + label + " command ..."); - String permission = this.getConfig().getString("command.global-list.permission", null); - List aliasesList = this.getConfig().getStringList("command.global-list.aliases"); + String permission = Config.COMMAND__GLIST__PERMISSION.get(); + List aliasesList = Config.COMMAND__GLIST__ALIASES.get(); String[] aliases = aliasesList.toArray(new String[0]); //prepare enhanced list executor - commandExecutor = new ListExecutor(this, label, permission, aliases); + commandExecutor = new GlistCommand(this, label, permission, aliases); if (firstRegister && label.equalsIgnoreCase("glist")) { //TODO: Probably this can be removed if we declare the cmd_glist plugin as soft dependency, so cmd_glist should be loaded before EnhancedBungeeList... @@ -125,4 +250,37 @@ private void registerListExecutor(boolean firstRegister) { } } -} \ No newline at end of file + @Nullable + public String getPrefix(ProxiedPlayer player) { + for(GroupHook hook : groupHooks) { + String tryPrefix = hook.getPrefix(player); + + if(tryPrefix != null) { + String sanitizedPrefix = ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', tryPrefix)); + + if(sanitizedPrefix.endsWith(" ")) { + int lastSpace = tryPrefix.lastIndexOf(' '); + if(lastSpace == tryPrefix.length() - 1) { + tryPrefix = tryPrefix.substring(0, tryPrefix.length() - 1); + } else { + tryPrefix = tryPrefix.substring(0, lastSpace) + tryPrefix.substring(lastSpace + 1, tryPrefix.length()); + } + } else if(tryPrefix.isEmpty()) { + continue; + } + + return ChatColor.translateAlternateColorCodes('&', tryPrefix); + } + } + + return null; + } + + public List getServerGroups() { + return serverGroups; + } + + public boolean isInGroup(ServerInfo server) { + return serverGroups.stream().flatMap(sg -> sg.getServers().stream()).anyMatch(s -> s.getName().equalsIgnoreCase(server.getName())); + } +} diff --git a/src/dev/wirlie/bungeecord/glist/ListExecutor.java b/src/dev/wirlie/bungeecord/glist/ListExecutor.java deleted file mode 100644 index dfc1ca37..00000000 --- a/src/dev/wirlie/bungeecord/glist/ListExecutor.java +++ /dev/null @@ -1,519 +0,0 @@ -package dev.wirlie.bungeecord.glist; - -import com.google.common.collect.Iterators; -import net.md_5.bungee.BungeeCord; -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.CommandSender; -import net.md_5.bungee.api.chat.*; -import net.md_5.bungee.api.chat.ClickEvent.Action; -import net.md_5.bungee.api.chat.ComponentBuilder.FormatRetention; -import net.md_5.bungee.api.config.ServerInfo; -import net.md_5.bungee.api.connection.ProxiedPlayer; -import net.md_5.bungee.api.plugin.Command; -import net.md_5.bungee.api.plugin.TabExecutor; - -import java.text.NumberFormat; -import java.util.*; -import java.util.stream.Collectors; - -public class ListExecutor extends Command implements TabExecutor { - - private String globalListSpOptionMainFormat = DefaultValues.getDefaultString("formats.global-list.server-sp-option.main-format"); - private String globalListSpOptionPlayersFormat = DefaultValues.getDefaultString("formats.global-list.server-sp-option.players-format"); - private String globalListFullFormat = DefaultValues.getDefaultString("formats.global-list.full-message-format"); - private String globalListServerRowFormat = DefaultValues.getDefaultString("formats.global-list.server-row-format"); - private String globalListNoServersFormat = DefaultValues.getDefaultString("formats.global-list.no-servers-format"); - private String globalListBackgroundGraphicColor = DefaultValues.getDefaultString("formats.global-list.graphic-background-color"); - private String globalListGraphicBarColor = DefaultValues.getDefaultString("formats.global-list.graphic-bar-color"); - private boolean globalListBehaviourHideEmptyServer = DefaultValues.getDefaultBoolean("behaviour.global-list.hide-empty-servers"); - private int globalListBehaviourMaxRows = DefaultValues.getDefaultInt("behaviour.global-list.max-servers-rows"); - private int globalListBehaviourMinPlayerToDisplay = DefaultValues.getDefaultInt("behaviour.global-list.min-player-count-to-display-server"); - private String serverListFullFormat = DefaultValues.getDefaultString("formats.server-list.full-message-format"); - private String serverListNoPageDataFormat = DefaultValues.getDefaultString("formats.server-list.no-page-data-message"); - private String serverListNoPlayersFormat = DefaultValues.getDefaultString("formats.server-list.no-players-message"); - private int serverListBehaviourPlayerPerPage = DefaultValues.getDefaultInt("behaviour.server-list.players-per-page"); - private List blacklistedServers = DefaultValues.getDefaultStringList("behaviour.blacklisted-servers"); - private boolean globalListUpperCaseServerNames = false; - private boolean serverListUpperCaseServerName = false; - - //Messages - private String messagesServerPlayers = DefaultValues.getDefaultString("messages.server-players"); - private String messagesCannotFoundServer = DefaultValues.getDefaultString("messages.cannot-found-server"); - private String messagesPreviousPageHover = DefaultValues.getDefaultString("messages.previous-page-hover-message"); - private String messagesNextPageHover = DefaultValues.getDefaultString("messages.next-page-hover-message"); - private String messagesPreviousPage = DefaultValues.getDefaultString("messages.previous-page"); - private String messagesNextPage = DefaultValues.getDefaultString("messages.next-page"); - private String messagesNoPreviousPage = DefaultValues.getDefaultString("messages.no-previous-page"); - private String messagesNoNextPage = DefaultValues.getDefaultString("messages.no-next-page"); - - private NumberFormat format = NumberFormat.getNumberInstance(); - private EnhancedBCL plugin; - private Map> serversPaginators = new HashMap<>(); - - ListExecutor(EnhancedBCL plugin, String name, String permission, String... aliases) { - super(name, permission, aliases); - this.plugin = plugin; - this.format.setMaximumFractionDigits(2); - this.loadFromConfig(); - } - - private void loadFromConfig() { - this.globalListServerRowFormat = this.plugin.getConfig().getString("formats.global-list.server-row-format", DefaultValues.getDefaultString("formats.global-list.server-row-format")); - List fullMessageLines = this.plugin.getConfig().getStringList("formats.global-list.full-message-format"); - if (!fullMessageLines.isEmpty()) { - StringBuilder messageBuilder = new StringBuilder(); - - for (int i = 0; i < fullMessageLines.size(); i++) { - String line = fullMessageLines.get(i); - messageBuilder.append(line); - if(i < (fullMessageLines.size() - 1)){ - messageBuilder.append("\n"); - } - } - - this.globalListFullFormat = messageBuilder.toString(); - } else { - this.globalListFullFormat = DefaultValues.getDefaultString("formats.global-list.full-message-format"); - } - - this.globalListSpOptionMainFormat = this.plugin.getConfig().getString("formats.global-list.server-sp-option.main-format", DefaultValues.getDefaultString("formats.global-list.server-sp-option.main-format")); - this.globalListSpOptionPlayersFormat = this.plugin.getConfig().getString("formats.global-list.server-sp-option.players-format", DefaultValues.getDefaultString("formats.global-list.server-sp-option.players-format")); - this.globalListNoServersFormat = this.plugin.getConfig().getString("formats.global-list.no-servers-format", DefaultValues.getDefaultString("formats.global-list.no-servers-format")); - this.globalListBackgroundGraphicColor = this.plugin.getConfig().getString("formats.global-list.graphic-background-color", DefaultValues.getDefaultString("formats.global-list.graphic-background-color")); - this.globalListGraphicBarColor = this.plugin.getConfig().getString("formats.global-list.graphic-bar-color", DefaultValues.getDefaultString("formats.global-list.graphic-bar-color")); - this.globalListBehaviourHideEmptyServer = this.plugin.getConfig().getBoolean("behaviour.global-list.hide-empty-servers", DefaultValues.getDefaultBoolean("behaviour.global-list.hide-empty-servers")); - this.globalListBehaviourMaxRows = this.plugin.getConfig().getInt("behaviour.global-list.max-servers-rows", DefaultValues.getDefaultInt("behaviour.global-list.max-servers-rows")); - this.globalListBehaviourMinPlayerToDisplay = this.plugin.getConfig().getInt("behaviour.global-list.min-player-count-to-display-server", DefaultValues.getDefaultInt("behaviour.global-list.min-player-count-to-display-server")); - this.blacklistedServers = this.plugin.getConfig().getStringList("behaviour.blacklisted-servers"); - - List serverListFullMessage = this.plugin.getConfig().getStringList("formats.server-list.full-message-format"); - if (!serverListFullMessage.isEmpty()) { - StringBuilder messageBuilder = new StringBuilder(); - - for (int i = 0; i < serverListFullMessage.size(); i++) { - String line = serverListFullMessage.get(i); - messageBuilder.append(line); - if(i < (serverListFullMessage.size() - 1)){ - messageBuilder.append("\n"); - } - } - - this.serverListFullFormat = messageBuilder.toString(); - } else { - this.serverListFullFormat = DefaultValues.getDefaultString("formats.server-list.full-message-format"); - } - - List noPageDataMessage = this.plugin.getConfig().getStringList("formats.server-list.no-page-data-message"); - if (!noPageDataMessage.isEmpty()) { - StringBuilder messageBuilder = new StringBuilder(); - - for (int i = 0; i < noPageDataMessage.size(); i++) { - String line = noPageDataMessage.get(i); - messageBuilder.append(line); - if(i < (noPageDataMessage.size() - 1)){ - messageBuilder.append("\n"); - } - } - - this.serverListNoPageDataFormat = messageBuilder.toString(); - if(serverListNoPageDataFormat.endsWith("\n")) { - serverListNoPageDataFormat = serverListNoPageDataFormat.substring(0, serverListNoPageDataFormat.length() - 2); - } - } else { - this.serverListNoPageDataFormat = DefaultValues.getDefaultString("formats.server-list.no-page-data-message"); - } - - List noPlayersMessage = this.plugin.getConfig().getStringList("formats.server-list.no-players-message"); - if (!noPlayersMessage.isEmpty()) { - StringBuilder messageBuilder = new StringBuilder(); - - for (int i = 0; i < noPlayersMessage.size(); i++) { - String line = noPlayersMessage.get(i); - messageBuilder.append(line); - if(i < (noPlayersMessage.size() - 1)){ - messageBuilder.append("\n"); - } - } - - this.serverListNoPlayersFormat = messageBuilder.toString(); - if(serverListNoPlayersFormat.endsWith("\n")) { - serverListNoPlayersFormat = serverListNoPlayersFormat.substring(0, serverListNoPlayersFormat.length() - 2); - } - } else { - this.serverListNoPlayersFormat = DefaultValues.getDefaultString("formats.server-list.no-players-message"); - } - - this.serverListBehaviourPlayerPerPage = this.plugin.getConfig().getInt("behaviour.server-list.players-per-page", DefaultValues.getDefaultInt("behaviour.server-list.players-per-page")); - - this.globalListUpperCaseServerNames = plugin.getConfig().getBoolean("behaviour.global-list-uppercase-server-names"); - this.serverListUpperCaseServerName = plugin.getConfig().getBoolean("behaviour.server-list-uppercase-server-name"); - - this.messagesServerPlayers = plugin.getConfig().getString("messages.server-players", DefaultValues.getDefaultString("messages.server-players")); - this.messagesCannotFoundServer = plugin.getConfig().getString("messages.cannot-found-server", DefaultValues.getDefaultString("messages.cannot-found-server")); - this.messagesPreviousPageHover = plugin.getConfig().getString("messages.previous-page-hover-message", DefaultValues.getDefaultString("messages.previous-page-hover-message")); - this.messagesNextPageHover = plugin.getConfig().getString("messages.next-page-hover-message", DefaultValues.getDefaultString("messages.next-page-hover-message")); - this.messagesPreviousPage = plugin.getConfig().getString("messages.previous-page" ,DefaultValues.getDefaultString("messages.previous-page")); - this.messagesNextPage = plugin.getConfig().getString("messages.next-page", DefaultValues.getDefaultString("messages.next-page")); - this.messagesNoPreviousPage = plugin.getConfig().getString("messages.no-previous-page", DefaultValues.getDefaultString("messages.no-previous-page")); - this.messagesNoNextPage = plugin.getConfig().getString("messages.no-next-page", DefaultValues.getDefaultString("messages.no-next-page")); - } - - public void execute(CommandSender sender, String[] args) { - boolean isPlayerExecutor = sender instanceof ProxiedPlayer; - Set options = new HashSet<>(); - - for(String arg : args) { - String[] backup; - boolean alreadySkipped; - int i; - String b; - if (arg.equalsIgnoreCase("-g")) { - options.add("-g"); - backup = args; - args = new String[args.length - 1]; - alreadySkipped = false; - i = 0; - - for(int j = 0; i < args.length; ++j) { - b = backup[i]; - if (b.equalsIgnoreCase("-g") && !alreadySkipped) { - alreadySkipped = true; - --j; - } else { - args[j] = b; - } - - ++i; - } - } else if (arg.equalsIgnoreCase("-sp")) { - options.add("-sp"); - backup = args; - args = new String[args.length - 1]; - alreadySkipped = false; - i = 0; - - for(int j = 0; i < args.length; ++j) { - b = backup[i]; - if (b.equalsIgnoreCase("-sp") && !alreadySkipped) { - alreadySkipped = true; - --j; - } else { - args[j] = b; - } - - ++i; - } - } else if (arg.equalsIgnoreCase("-a")) { - options.add("-a"); - backup = args; - args = new String[args.length - 1]; - alreadySkipped = false; - i = 0; - - for(int j = 0; i < args.length; ++j) { - b = backup[i]; - if (b.equalsIgnoreCase("-a") && !alreadySkipped) { - alreadySkipped = true; - --j; - } else { - args[j] = b; - } - - ++i; - } - } - } - - int page; - String[] partsController; - if (args.length == 0) { - List servers = BungeeCord.getInstance() - .getServers() - .values() - .stream() - .sorted((o, o1) -> Integer.compare(o1.getPlayers().size(), o.getPlayers().size())) - .filter((o) -> { - if(blacklistedServers.contains(o.getName())) { - return false; - } - - if(options.contains("-a")) { - if(o.getPlayers().size() > 0) { - return true; - } - } - - if (options.contains("-g")) { - return true; - } else if (this.globalListBehaviourMinPlayerToDisplay >= 1) { - return o.getPlayers().size() >= this.globalListBehaviourMinPlayerToDisplay; - } else { - return !o.getPlayers().isEmpty() || o.getPlayers().isEmpty() && !this.globalListBehaviourHideEmptyServer; - } - }) - .limit(this.globalListBehaviourMaxRows < 1 ? Integer.MAX_VALUE : options.contains("-g") ? Integer.MAX_VALUE : this.globalListBehaviourMaxRows).collect(Collectors.toList()); - StringBuilder rowsBuilder = new StringBuilder(); - int totalPlayers = BungeeCord.getInstance().getPlayers().size(); - if (servers.isEmpty()) { - rowsBuilder.append(this.globalListNoServersFormat); - } else { - page = (servers.get(0)).getPlayers().size(); - Iterator serversIterator = servers.iterator(); - - mainWhile: - while(true) { - ServerInfo serverInfo; - do { - do { - if (!serversIterator.hasNext()) { - break mainWhile; - } - - serverInfo = serversIterator.next(); - float percent = totalPlayers == 0 ? 0.0F : (serverInfo.getPlayers().size() * 100.0F / totalPlayers); - float percentGraphic = page == 0 ? 0.0F : (serverInfo.getPlayers().size() * 100F / page); - StringBuilder graphicBarBuilder = new StringBuilder(); - float barPercent = 5.0F; - int totalBars = (int)(percentGraphic / barPercent); - - for(int i = 0; i < 20; ++i) { - if (i < totalBars) { - graphicBarBuilder.append(this.globalListGraphicBarColor).append("|"); - } else { - graphicBarBuilder.append(this.globalListBackgroundGraphicColor).append("|"); - } - } - - rowsBuilder.append(this.globalListServerRowFormat.replace("{SERVER_NAME}", globalListUpperCaseServerNames ? serverInfo.getName().toUpperCase() : serverInfo.getName()).replace("{PLAYER_AMOUNT}", String.valueOf(serverInfo.getPlayers().size())).replace("{GRAPHIC_BAR}", graphicBarBuilder.toString()).replace("{PERCENT}", this.format.format(percent) + "%")).append("\n"); - } while(!options.contains("-sp")); - } while(serverInfo.getPlayers().isEmpty()); - - String mainFormat = globalListSpOptionMainFormat; - String playersFormat = globalListSpOptionPlayersFormat; - - StringBuilder playersString = new StringBuilder(); - List players = new ArrayList<>(serverInfo.getPlayers()); - for(int i = 0; i < players.size(); i++) { - ProxiedPlayer player = players.get(i); - - if(i == players.size() - 1) { - //eliminar formato - int indexOf = playersFormat.indexOf("{PLAYER_NAME}"); - if(indexOf != -1) { - playersString.append(playersFormat.substring(0, indexOf + "{PLAYER_NAME}".length()).replace("{PLAYER_NAME}", player.getName())); - } else { - playersString.append(playersFormat.replace("{PLAYER_NAME}", player.getName())); - } - } else { - playersString.append(playersFormat.replace("{PLAYER_NAME}", player.getName())); - } - } - - rowsBuilder.append(mainFormat.replace("{SERVER_NAME}", globalListUpperCaseServerNames ? serverInfo.getName().toUpperCase() : serverInfo.getName()).replace("{PLAYERS_FORMAT}", playersString.toString())).append("\n"); - - /*rowsBuilder.append(" &e").append(messagesServerPlayers.replace("{SERVER_NAME}", globalListUpperCaseServerNames ? serverInfo.getName().toUpperCase() : serverInfo.getName())).append(": &8[&7"); - - for (ProxiedPlayer player : serverInfo.getPlayers()) { - rowsBuilder.append(player.getName()).append("&8,&7 "); - } - - rowsBuilder.append("&8]\n");*/ - } - } - - page = BungeeCord.getInstance().getServers().size() - servers.size(); - String fullMessageCopy = this.globalListFullFormat; - String message = ChatColor.translateAlternateColorCodes('&', fullMessageCopy.replace("{SERVERS_ROWS}", rowsBuilder.toString()).replace("{NOT_DISPLAYED_AMOUNT}", String.valueOf(page)).replace("{TOTAL_PLAYER_AMOUNT}", String.valueOf(totalPlayers)).replace("{LABEL}", this.getName())); - - if(message.endsWith("\n")) { - message = message.substring(message.length() - 2); - } - - String[] lines = message.split("\\n"); - partsController = lines; - - for(int totalBars = 0; totalBars < lines.length; ++totalBars) { - String line = partsController[totalBars]; - sender.sendMessage(TextUtil.fromLegacy(line)); - } - } else { - String serverName = args[0]; - ServerInfo serverInfo = BungeeCord.getInstance().getServerInfo(serverName); - if (serverInfo == null) { - sender.sendMessage(TextUtil.fromLegacy(messagesCannotFoundServer.replace("{NAME}", serverName))); - } else { - TemporalPaginator temporalPaginator = this.serversPaginators.computeIfAbsent(serverInfo.getName(), (k) -> new TemporalPaginator<>(serverInfo.getPlayers().stream().map(CommandSender::getName).collect(Collectors.toList()), this.serverListBehaviourPlayerPerPage)); - - if (temporalPaginator.shouldUpdate(60000L)) { - temporalPaginator.update(serverInfo.getPlayers().stream().map(CommandSender::getName).collect(Collectors.toList())); - } - - page = 1; - if (args.length > 1) { - try { - page = Integer.parseInt(args[1]); - } catch (NumberFormatException ignored) { - - } - } - - List pageData = options.contains("-g") ? temporalPaginator.getFullData() : temporalPaginator.getPage(page); - if (pageData.isEmpty()) { - if (temporalPaginator.getTotalPages() > 0) { - sender.sendMessage(TextUtil.fromLegacy(this.serverListNoPageDataFormat.replace("{TOTAL_PAGES}", String.valueOf(temporalPaginator.getTotalPages())))); - } else { - sender.sendMessage(TextUtil.fromLegacy(this.serverListNoPlayersFormat)); - } - } else { - String[] namesData = pageData.toArray(new String[0]); - String message = this.serverListFullFormat.replace("{PLAYERS_ROWS}", TextUtil.makeRows(2, 25, (page - 1) * this.serverListBehaviourPlayerPerPage + 1, ChatColor.GRAY, namesData)).replace("{SERVER_NAME}", serverListUpperCaseServerName ? serverInfo.getName().toUpperCase() : serverInfo.getName()).replace("{PLAYERS_COUNT}", String.valueOf(temporalPaginator.dataSize())).replace("{PAGE}", options.contains("-g") ? "All Pages" : String.valueOf(page)).replace("{TOTAL_PAGES}", String.valueOf(temporalPaginator.getTotalPages())); - if (options.contains("-g")) { - partsController = message.split("\\n"); - - for (String line : partsController) { - if (!line.contains("{PAGINATION_CONTROLLER}")) { - sender.sendMessage(TextUtil.fromLegacy(line)); - } - } - } else if (message.contains("{PAGINATION_CONTROLLER}")) { - partsController = message.split("\\{PAGINATION_CONTROLLER}"); - BaseComponent mainComponent = new TextComponent(); - - for (BaseComponent bc : TextUtil.fromLegacy(partsController[0])) { - mainComponent.addExtra(bc); - } - - ComponentBuilder cb = null; - if (page > 1 && page < temporalPaginator.getTotalPages()) { - cb = new ComponentBuilder(""); - - if (isPlayerExecutor) { - cb.append("<<") - .color(ChatColor.WHITE) - .event(new ClickEvent(Action.RUN_COMMAND, "/" + this.getName() + " " + serverInfo.getName() + " " + (page - 1))) - .event(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, TextUtil.fromLegacy(messagesPreviousPageHover.replace("{PAGE_NUMBER}", String.valueOf(page - 1)) ))) - .append(" " + messagesPreviousPage + " ") - .color(ChatColor.GOLD) - .append("|", FormatRetention.NONE) - .color(ChatColor.DARK_GRAY) - .append(" " + messagesNextPage + " ") - .color(ChatColor.GOLD) - .event(new ClickEvent(Action.RUN_COMMAND, "/" + this.getName() + " " + serverInfo.getName() + " " + (page + 1))) - .event(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, TextUtil.fromLegacy(messagesNextPageHover.replace("{PAGE_NUMBER}", String.valueOf(page + 1))))) - .append(">>").color(ChatColor.WHITE); - } else { - cb.append("Use ").color(ChatColor.GOLD).append("/" + this.getName() + " " + serverInfo.getName() + " " + (page - 1)).color(ChatColor.WHITE).append(" to go to the previous page.\n").color(ChatColor.GOLD).append("Use ").color(ChatColor.GOLD).append("/" + this.getName() + " " + serverInfo.getName() + " " + (page + 1)).color(ChatColor.WHITE).append(" to go to the next page.").color(ChatColor.GOLD); - } - } else if (page <= 1) { - if (page + 1 <= temporalPaginator.getTotalPages()) { - cb = new ComponentBuilder(""); - if (isPlayerExecutor) { - cb.append("<<") - .color(ChatColor.DARK_RED) - .event(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, TextUtil.fromLegacy(messagesNoPreviousPage))) - .append(" " + messagesPreviousPage + " ") - .color(ChatColor.RED) - .append("|", FormatRetention.NONE) - .color(ChatColor.DARK_GRAY) - .append(" " + messagesNextPage + " ") - .color(ChatColor.GOLD) - .event(new ClickEvent(Action.RUN_COMMAND, "/" + this.getName() + " " + serverInfo.getName() + " " + (page + 1))) - .event(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, TextUtil.fromLegacy(messagesNextPageHover.replace("{PAGE_NUMBER}", String.valueOf(page + 1))))) - .append(">>").color(ChatColor.WHITE); - } else { - cb.append("Use ").color(ChatColor.GOLD) - .append("/" + this.getName() + " " + serverInfo.getName() + " " + (page + 1)) - .color(ChatColor.WHITE) - .append(" to go to the next page.") - .color(ChatColor.GOLD); - } - } else if (isPlayerExecutor) { - cb = new ComponentBuilder("<<") - .color(ChatColor.DARK_RED) - .event(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, TextUtil.fromLegacy(messagesNoPreviousPage))) - .append(" " + messagesPreviousPage + " ") - .color(ChatColor.RED) - .append("|", FormatRetention.NONE) - .color(ChatColor.DARK_GRAY) - .append(" " + messagesNextPage + " ") - .color(ChatColor.RED) - .event(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, TextUtil.fromLegacy(messagesNoNextPage))) - .append(">>") - .color(ChatColor.DARK_RED); - } - } else if (page >= temporalPaginator.getTotalPages()) { - if (isPlayerExecutor) { - cb = new ComponentBuilder("<<") - .color(ChatColor.WHITE) - .event(new ClickEvent(Action.RUN_COMMAND, "/" + this.getName() + " " + serverInfo.getName() + " " + (page - 1))) - .event(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, TextUtil.fromLegacy(messagesPreviousPageHover.replace("{PAGE_NUMBER}", String.valueOf(page - 1))))) - .append(" " + messagesPreviousPage + " ") - .color(ChatColor.GOLD) - .append("|", FormatRetention.NONE) - .color(ChatColor.DARK_GRAY) - .append(" " + messagesNextPage + " ") - .color(ChatColor.RED) - .event(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, TextUtil.fromLegacy(messagesNoNextPage))) - .append(">>") - .color(ChatColor.DARK_RED); - } else { - cb = new ComponentBuilder("Use ") - .color(ChatColor.GOLD) - .append("/" + this.getName() + " " + serverInfo.getName() + " " + (page - 1)) - .color(ChatColor.WHITE) - .append(" to go to the previous page.") - .color(ChatColor.GOLD); - } - } - - BaseComponent bc; - BaseComponent[] bcObject; - int j; - if (cb != null) { - bcObject = cb.create(); - - for(j = 0; j < bcObject.length; ++j) { - bc = bcObject[j]; - mainComponent.addExtra(bc); - } - } - - if (partsController.length > 1) { - bcObject = TextUtil.fromLegacy(partsController[1]); - - for(j = 0; j < bcObject.length; ++j) { - bc = bcObject[j]; - mainComponent.addExtra(bc); - } - } - - sender.sendMessage(mainComponent); - } else { - if(message.endsWith("\n")) { - message = message.substring(0, message.length() - 2); - } - - sender.sendMessage(TextUtil.fromLegacy(message)); - } - } - } - } - } - - @Override - public Iterable onTabComplete(CommandSender sender, String[] args) { - - if(args.length == 1) { - List suggestions = BungeeCord.getInstance().getServers().values().stream().filter(s -> s.getName().toLowerCase().contains(args[0].toLowerCase())).map(ServerInfo::getName).collect(Collectors.toList()); - if(args[0].isEmpty() || args[0].startsWith("-")) { - suggestions.add("-g"); - suggestions.add("-sp"); - suggestions.add("-a"); - } - return suggestions; - } - - return Collections.emptyList(); - } - -} \ No newline at end of file diff --git a/src/dev/wirlie/bungeecord/glist/TemporalPaginator.java b/src/dev/wirlie/bungeecord/glist/TemporalPaginator.java index 4fb797ff..f2320d78 100644 --- a/src/dev/wirlie/bungeecord/glist/TemporalPaginator.java +++ b/src/dev/wirlie/bungeecord/glist/TemporalPaginator.java @@ -9,11 +9,11 @@ public class TemporalPaginator { private List data; private int totalPages; - private int pageSize; - private long createdAt = System.currentTimeMillis(); + private final int pageSize; + private final long createdAt = System.currentTimeMillis(); private boolean testedData = false; - TemporalPaginator(Collection data, int pageSize) { + public TemporalPaginator(Collection data, int pageSize) { if (pageSize < 1) { pageSize = 1; } @@ -66,4 +66,4 @@ public int getTotalPages() { public int dataSize() { return this.data.size(); } -} \ No newline at end of file +} diff --git a/src/dev/wirlie/bungeecord/glist/config/Config.java b/src/dev/wirlie/bungeecord/glist/config/Config.java new file mode 100644 index 00000000..fe9c8a6a --- /dev/null +++ b/src/dev/wirlie/bungeecord/glist/config/Config.java @@ -0,0 +1,53 @@ +package dev.wirlie.bungeecord.glist.config; + +import java.util.List; +import java.util.Map; + +public class Config { + + public static final ConfigEntry COMMAND__GLIST__LABEL = new ConfigEntry<>("command.global-list.label"); + public static final ConfigEntry COMMAND__GLIST__PERMISSION = new ConfigEntry<>("command.global-list.permission"); + public static final ConfigEntry> COMMAND__GLIST__ALIASES = new ConfigEntry<>("command.global-list.aliases"); + + public static final ConfigEntry FORMATS__GLOBAL_LIST__SERVER_ROW_FORMAT = new ConfigEntry<>("formats.global-list.server-row-format"); + public static final ConfigEntry FORMATS__GLOBAL_LIST__GRAPHIC_BACKGROUND_COLOR = new ConfigEntry<>("formats.global-list.graphic-background-color"); + public static final ConfigEntry FORMATS__GLOBAL_LIST__GRAPHIC_BAR_COLOR = new ConfigEntry<>("formats.global-list.graphic-bar-color"); + public static final ConfigEntry> FORMATS__GLOBAL_LIST__FULL_MESSAGE_FORMAT = new ConfigEntry<>("formats.global-list.full-message-format"); + public static final ConfigEntry FORMATS__GLOBAL_LIST__NO_SERVERS_FORMAT = new ConfigEntry<>("formats.global-list.no-servers-format"); + public static final ConfigEntry> FORMATS__SERVER_LIST__FULL_MESSAGE_FORMAT = new ConfigEntry<>("formats.server-list.full-message-format"); + public static final ConfigEntry> FORMATS__SERVER_LIST__NO_PAGE_DATA_MESSAGE = new ConfigEntry<>("formats.server-list.no-page-data-message"); + public static final ConfigEntry> FORMATS__SERVER_LIST__NO_PLAYERS_MESSAGE = new ConfigEntry<>("formats.server-list.no-players-message"); + public static final ConfigEntry FORMATS__GLOBAL_LIST__SERVER_SP_OPTION__MAIN_FORMAT = new ConfigEntry<>("formats.global-list.server-sp-option.main-format"); + public static final ConfigEntry FORMATS__GLOBAL_LIST__SERVER_SP_OPTION__PLAYERS_FORMAT = new ConfigEntry<>("formats.global-list.server-sp-option.players-format"); + + public static final ConfigEntry BEHAVIOUR__GLOBAL_LIST__HIDE_EMPTY_SERVERS = new ConfigEntry<>("behaviour.global-list.hide-empty-servers"); + public static final ConfigEntry BEHAVIOUR__GLOBAL_LIST__MAX_SERVERS_ROWS = new ConfigEntry<>("behaviour.global-list.max-servers-rows"); + public static final ConfigEntry BEHAVIOUR__GLOBAL_LIST__MIN_PLAYER_COUNT_TO_DISPLAY_SERVER = new ConfigEntry<>("behaviour.global-list.min-player-count-to-display-server"); + public static final ConfigEntry BEHAVIOUR__SERVER_LIST__PLAYERS_PER_PAGE = new ConfigEntry<>("behaviour.server-list.players-per-page"); + public static final ConfigEntry> BEHAVIOUR__SERVER_LIST__BLACKLISTED_SERVERS = new ConfigEntry<>("behaviour.blacklisted-servers"); + public static final ConfigEntry BEHAVIOUR__GLOBAL_LIST__UPPER_CASE_NAMES = new ConfigEntry<>("behaviour.global-list-uppercase-server-names"); + public static final ConfigEntry BEHAVIOUR__SERVER_LIST__UPPER_CASE_NAME = new ConfigEntry<>("behaviour.server-list-uppercase-server-name"); + public static final ConfigEntry BEHAVIOUR__GROUPS_PREFIX__ENABLE = new ConfigEntry<>("behaviour.groups-prefix.enable"); + public static final ConfigEntry BEHAVIOUR__GROUPS_PREFIX__USE__LUCKPERMS = new ConfigEntry<>("behaviour.groups-prefix.use.luckperms"); + public static final ConfigEntry BEHAVIOUR__GROUPS_PREFIX__USE__INTERNAL_GROUP_SYSTEM = new ConfigEntry<>("behaviour.groups-prefix.use.internal-group-system"); + public static final ConfigEntry BEHAVIOUR__GROUPS_PREFIX__PRIORITY__LUCKPERMS = new ConfigEntry<>("behaviour.groups-prefix.priority.luckperms"); + public static final ConfigEntry BEHAVIOUR__GROUPS_PREFIX__PRIORITY__INTERNAL_GROUP_SYSTEM = new ConfigEntry<>("behaviour.groups-prefix.priority.internal-group-system"); + + public static final ConfigEntry MESSAGES__CANNOT_FOUND_SERVER = new ConfigEntry<>("messages.cannot-found-server"); + public static final ConfigEntry MESSAGES__PREVIOUS_PAGE_HOVER_MESSAGE = new ConfigEntry<>("messages.previous-page-hover-message"); + public static final ConfigEntry MESSAGES__NEXT_PAGE_HOVER_MESSAGE = new ConfigEntry<>("messages.next-page-hover-message"); + public static final ConfigEntry MESSAGES__PREVIOUS_PAGE = new ConfigEntry<>("messages.previous-page"); + public static final ConfigEntry MESSAGES__NEXT_PAGE = new ConfigEntry<>("messages.next-page"); + public static final ConfigEntry MESSAGES__NO_PREVIOUS_PAGE = new ConfigEntry<>("messages.no-previous-page"); + public static final ConfigEntry MESSAGES__NO_NEXT_PAGE = new ConfigEntry<>("messages.no-next-page"); + public static final ConfigEntry MESSAGES__ALL_PAGES = new ConfigEntry<>("messages.all-pages"); + + public static final ConfigEntry UPDATES__CHECK_UPDATES = new ConfigEntry<>("updates.check-updates"); + public static final ConfigEntry UPDATES__NOTIFY__ENABLE = new ConfigEntry<>("updates.notify.enable"); + public static final ConfigEntry UPDATES__NOTIFY__PERMISSION = new ConfigEntry<>("updates.notify.permission"); + public static final ConfigEntry> UPDATES__NOTIFY__MESSAGE = new ConfigEntry<>("updates.notify.message"); + public static final ConfigEntry UPDATES__NOTIFY__DELAY_MS = new ConfigEntry<>("updates.notify.delay-ms"); + + public static final ConfigEntry>> SERVERS__GROUPS = new ConfigEntry<>("servers.groups"); + +} diff --git a/src/dev/wirlie/bungeecord/glist/config/ConfigEntry.java b/src/dev/wirlie/bungeecord/glist/config/ConfigEntry.java new file mode 100644 index 00000000..d411f07d --- /dev/null +++ b/src/dev/wirlie/bungeecord/glist/config/ConfigEntry.java @@ -0,0 +1,31 @@ +package dev.wirlie.bungeecord.glist.config; + +import dev.wirlie.bungeecord.glist.EnhancedBCL; +import org.jetbrains.annotations.NotNull; + +public class ConfigEntry { + + private final String key; + + private T value = null; + + public ConfigEntry(String key) { + this.key = key; + EnhancedBCL.CONFIGURATIONS_REGISTRY.add(this); + } + + @SuppressWarnings("unchecked") + public void setValue(@NotNull Object value) { + this.value = (T) value; + } + + @NotNull + public T get() { + return value; + } + + public String getKey() { + return key; + } + +} diff --git a/src/dev/wirlie/bungeecord/glist/PluginExecutor.java b/src/dev/wirlie/bungeecord/glist/executor/EBLCommand.java similarity index 55% rename from src/dev/wirlie/bungeecord/glist/PluginExecutor.java rename to src/dev/wirlie/bungeecord/glist/executor/EBLCommand.java index b4eeb4a8..3591ddb4 100644 --- a/src/dev/wirlie/bungeecord/glist/PluginExecutor.java +++ b/src/dev/wirlie/bungeecord/glist/executor/EBLCommand.java @@ -1,12 +1,16 @@ -package dev.wirlie.bungeecord.glist; +package dev.wirlie.bungeecord.glist.executor; +import dev.wirlie.bungeecord.glist.EnhancedBCL; +import dev.wirlie.bungeecord.glist.util.TextUtil; import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.plugin.Command; -public class PluginExecutor extends Command { - private EnhancedBCL plugin; +import java.io.IOException; - PluginExecutor(EnhancedBCL plugin) { +public class EBLCommand extends Command { + private final EnhancedBCL plugin; + + public EBLCommand(EnhancedBCL plugin) { super("enhancedbungeelist", "ebl.command.reload","enhancedbl", "ebl", "ebcl"); this.plugin = plugin; } @@ -15,11 +19,16 @@ public void execute(CommandSender sender, String[] args) { if (args.length == 0) { sender.sendMessage(TextUtil.fromLegacy(" \n&7&m&l----------------------------&r\n &6Enhanced Bunge List &bv" + this.plugin.getDescription().getVersion() + "\n \n &fUsage:\n &e/ebl reload &7| &aReload Configuration.\n &e/glist &7| &aList all servers.\n&7&m&l----------------------------&r\n ")); } else if (args[0].equalsIgnoreCase("reload")) { - this.plugin.reloadConfig(); - sender.sendMessage(TextUtil.fromLegacy(" \n&7&m&l----------------------------&r\n &6Enhanced Bunge List &bv" + this.plugin.getDescription().getVersion() + "\n \n &aConfiguration reloaded!\n&7&m&l----------------------------&r\n ")); + try { + this.plugin.reloadConfig(); + sender.sendMessage(TextUtil.fromLegacy(" \n&7&m&l----------------------------&r\n &6Enhanced Bunge List &bv" + this.plugin.getDescription().getVersion() + "\n \n &aConfiguration reloaded!\n&7&m&l----------------------------&r\n ")); + } catch (IOException e) { + e.printStackTrace(); + sender.sendMessage(TextUtil.fromLegacy("&cAn internal error has occurred, check the console")); + } } else { sender.sendMessage(TextUtil.fromLegacy(" \n&7&m&l----------------------------&r\n &6Enhanced Bunge List &bv" + this.plugin.getDescription().getVersion() + "\n \n &cUnknown argument &f" + args[0] + " &c. Use &b/ebl &cfor help.\n&7&m&l----------------------------&r\n ")); } } -} \ No newline at end of file +} diff --git a/src/dev/wirlie/bungeecord/glist/executor/GlistCommand.java b/src/dev/wirlie/bungeecord/glist/executor/GlistCommand.java new file mode 100644 index 00000000..1d24edf0 --- /dev/null +++ b/src/dev/wirlie/bungeecord/glist/executor/GlistCommand.java @@ -0,0 +1,470 @@ +package dev.wirlie.bungeecord.glist.executor; + +import dev.wirlie.bungeecord.glist.EnhancedBCL; +import dev.wirlie.bungeecord.glist.TemporalPaginator; +import dev.wirlie.bungeecord.glist.config.Config; +import dev.wirlie.bungeecord.glist.servers.BungeecordInfoProvider; +import dev.wirlie.bungeecord.glist.servers.ServerGroup; +import dev.wirlie.bungeecord.glist.servers.ServerInfoProvider; +import dev.wirlie.bungeecord.glist.util.TextUtil; +import net.md_5.bungee.BungeeCord; +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.chat.*; +import net.md_5.bungee.api.chat.ClickEvent.Action; +import net.md_5.bungee.api.chat.ComponentBuilder.FormatRetention; +import net.md_5.bungee.api.config.ServerInfo; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.plugin.Command; +import net.md_5.bungee.api.plugin.TabExecutor; + +import java.text.Collator; +import java.text.NumberFormat; +import java.util.*; +import java.util.stream.Collectors; + +public class GlistCommand extends Command implements TabExecutor { + + private final NumberFormat format = NumberFormat.getNumberInstance(); + private final Map> serversPaginators = new HashMap<>(); + private final EnhancedBCL plugin; + + public GlistCommand(EnhancedBCL plugin, String name, String permission, String... aliases) { + super(name, permission, aliases); + this.plugin = plugin; + this.format.setMaximumFractionDigits(2); + } + + public void reload() { + serversPaginators.clear(); + } + + public void execute(CommandSender sender, String[] args) { + boolean isPlayerExecutor = sender instanceof ProxiedPlayer; + Set options = new HashSet<>(); + + for(String arg : args) { + String[] backup; + boolean alreadySkipped; + int i; + String b; + if (arg.equalsIgnoreCase("-g")) { + options.add("-g"); + backup = args; + args = new String[args.length - 1]; + alreadySkipped = false; + i = 0; + + for(int j = 0; i < args.length; ++j) { + b = backup[i]; + if (b.equalsIgnoreCase("-g") && !alreadySkipped) { + alreadySkipped = true; + --j; + } else { + args[j] = b; + } + + ++i; + } + } else if (arg.equalsIgnoreCase("-sp")) { + options.add("-sp"); + backup = args; + args = new String[args.length - 1]; + alreadySkipped = false; + i = 0; + + for(int j = 0; i < args.length; ++j) { + b = backup[i]; + if (b.equalsIgnoreCase("-sp") && !alreadySkipped) { + alreadySkipped = true; + --j; + } else { + args[j] = b; + } + + ++i; + } + } else if (arg.equalsIgnoreCase("-a")) { + options.add("-a"); + backup = args; + args = new String[args.length - 1]; + alreadySkipped = false; + i = 0; + + for(int j = 0; i < args.length; ++j) { + b = backup[i]; + if (b.equalsIgnoreCase("-a") && !alreadySkipped) { + alreadySkipped = true; + --j; + } else { + args[j] = b; + } + + ++i; + } + } + } + + int page; + String[] partsController; + if (args.length == 0) { + List allServers = new ArrayList<>(); + + //bungeecord servers + for(ServerInfo sv : BungeeCord.getInstance().getServers().values()) { + if(!plugin.isInGroup(sv)) { + allServers.add(new BungeecordInfoProvider(sv)); + } + } + + //groups servers + allServers.addAll(plugin.getServerGroups()); + + List servers = allServers.stream() + .sorted((o,o1) -> Integer.compare(o1.getPlayerCount(), o.getPlayerCount())) + .filter((o) -> { + if(Config.BEHAVIOUR__SERVER_LIST__BLACKLISTED_SERVERS.get().contains(o.getId())) { + return false; + } + + if(options.contains("-a")) { + if(o.getPlayerCount() > 0) { + return true; + } + } + + if (options.contains("-g")) { + return true; + } else if (Config.BEHAVIOUR__GLOBAL_LIST__MIN_PLAYER_COUNT_TO_DISPLAY_SERVER.get() >= 1) { + return o.getPlayerCount() >= Config.BEHAVIOUR__GLOBAL_LIST__MIN_PLAYER_COUNT_TO_DISPLAY_SERVER.get(); + } else { + return o.getPlayerCount() > 0 || o.getPlayerCount() == 0 && !Config.BEHAVIOUR__GLOBAL_LIST__HIDE_EMPTY_SERVERS.get(); + } + }) + .limit(Config.BEHAVIOUR__GLOBAL_LIST__MAX_SERVERS_ROWS.get() < 1 ? Integer.MAX_VALUE : options.contains("-g") ? Integer.MAX_VALUE : Config.BEHAVIOUR__GLOBAL_LIST__MAX_SERVERS_ROWS.get()).collect(Collectors.toList()); + + StringBuilder rowsBuilder = new StringBuilder(); + int totalPlayers = BungeeCord.getInstance().getPlayers().size(); + if (servers.isEmpty()) { + rowsBuilder.append(Config.FORMATS__GLOBAL_LIST__NO_SERVERS_FORMAT.get()); + } else { + page = (servers.get(0)).getPlayerCount(); + Iterator serversIterator = servers.iterator(); + + mainWhile: + while(true) { + ServerInfoProvider serverInfo; + do { + do { + if (!serversIterator.hasNext()) { + break mainWhile; + } + + serverInfo = serversIterator.next(); + float percent = totalPlayers == 0 ? 0.0F : (serverInfo.getPlayerCount() * 100.0F / totalPlayers); + float percentGraphic = page == 0 ? 0.0F : (serverInfo.getPlayerCount() * 100F / page); + StringBuilder graphicBarBuilder = new StringBuilder(); + float barPercent = 5.0F; + int totalBars = (int)(percentGraphic / barPercent); + + for(int i = 0; i < 20; ++i) { + if (i < totalBars) { + graphicBarBuilder.append(Config.FORMATS__GLOBAL_LIST__GRAPHIC_BAR_COLOR.get()).append("|"); + } else { + graphicBarBuilder.append(Config.FORMATS__GLOBAL_LIST__GRAPHIC_BACKGROUND_COLOR.get()).append("|"); + } + } + + rowsBuilder.append(Config.FORMATS__GLOBAL_LIST__SERVER_ROW_FORMAT.get().replace("{SERVER_NAME}", Config.BEHAVIOUR__GLOBAL_LIST__UPPER_CASE_NAMES.get() ? serverInfo.getId().toUpperCase() : serverInfo.getId()).replace("{PLAYER_AMOUNT}", String.valueOf(serverInfo.getPlayers().size())).replace("{GRAPHIC_BAR}", graphicBarBuilder.toString()).replace("{PERCENT}", this.format.format(percent) + "%")).append("\n"); + } while(!options.contains("-sp")); + } while(serverInfo.getPlayerCount() == 0); + + String mainFormat = Config.FORMATS__GLOBAL_LIST__SERVER_SP_OPTION__MAIN_FORMAT.get(); + String playersFormat = Config.FORMATS__GLOBAL_LIST__SERVER_SP_OPTION__PLAYERS_FORMAT.get(); + + StringBuilder playersString = new StringBuilder(); + List players = new ArrayList<>(serverInfo.getPlayers()); + for(int i = 0; i < players.size(); i++) { + ProxiedPlayer player = players.get(i); + + if(i == players.size() - 1) { + //eliminar formato + int indexOf = playersFormat.indexOf("{PLAYER_NAME}"); + if(indexOf != -1) { + String prefix = plugin.getPrefix(player); + boolean isEmptyPrefix = prefix != null && ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', prefix)).isEmpty(); + String playerName = (prefix == null ? "" : prefix + (isEmptyPrefix ? "" : " ")) + player.getName(); + playersString.append(playersFormat.substring(0, indexOf + "{PLAYER_NAME}".length()).replace("{PLAYER_NAME}", playerName)); + } else { + String prefix = plugin.getPrefix(player); + boolean isEmptyPrefix = prefix != null && ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', prefix)).isEmpty(); + String playerName = (prefix == null ? "" : prefix + (isEmptyPrefix ? "" : " ")) + player.getName(); + playersString.append(playersFormat.replace("{PLAYER_NAME}", playerName)); + } + } else { + String prefix = plugin.getPrefix(player); + boolean isEmptyPrefix = prefix != null && ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', prefix)).isEmpty(); + String playerName = (prefix == null ? "" : prefix + (isEmptyPrefix ? "" : " ")) + player.getName(); + playersString.append(playersFormat.replace("{PLAYER_NAME}", playerName)); + } + } + + rowsBuilder.append(mainFormat.replace("{SERVER_NAME}", Config.BEHAVIOUR__GLOBAL_LIST__UPPER_CASE_NAMES.get() ? serverInfo.getId().toUpperCase() : serverInfo.getId()).replace("{PLAYERS_FORMAT}", playersString.toString())).append("\n"); + } + } + + page = BungeeCord.getInstance().getServers().size() - servers.size(); + List fullMessageCopy = new ArrayList<>(Config.FORMATS__GLOBAL_LIST__FULL_MESSAGE_FORMAT.get()); + + for(String line : fullMessageCopy) { + sender.sendMessage(TextUtil.fromLegacy(ChatColor.translateAlternateColorCodes('&', line.replace("{SERVERS_ROWS}", rowsBuilder.toString()).replace("{NOT_DISPLAYED_AMOUNT}", String.valueOf(page)).replace("{TOTAL_PLAYER_AMOUNT}", String.valueOf(totalPlayers)).replace("{LABEL}", this.getName())))); + } + } else { + String serverName = args[0]; + + //is blacklisted? + if(Config.BEHAVIOUR__SERVER_LIST__BLACKLISTED_SERVERS.get().stream().anyMatch(s -> s.equalsIgnoreCase(serverName))) { + sender.sendMessage(TextUtil.fromLegacy(Config.MESSAGES__CANNOT_FOUND_SERVER.get().replace("{NAME}", serverName))); + return; + } + + ServerInfoProvider serverInfoPre = null; + + //try with group first + serverInfoPre = plugin.getServerGroups().stream().filter(g -> g.getId().equalsIgnoreCase(serverName)).findFirst().orElse(null); + + if(serverInfoPre == null) { + //try with bungeecord + ServerInfo bungeeServer = BungeeCord.getInstance().getServerInfo(serverName); + if(bungeeServer != null) { + serverInfoPre = new BungeecordInfoProvider(bungeeServer); + } + } + + ServerInfoProvider serverInfo = serverInfoPre; + + if (serverInfo == null) { + sender.sendMessage(TextUtil.fromLegacy(Config.MESSAGES__CANNOT_FOUND_SERVER.get().replace("{NAME}", serverName))); + } else { + TemporalPaginator temporalPaginator = this.serversPaginators.computeIfAbsent(serverInfo.getId(), (k) -> new TemporalPaginator<>(serverInfo.getPlayers().stream().map(cs -> { + String prefix = plugin.getPrefix(cs); + if(prefix != null) { + if(ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', prefix)).isEmpty()) { + return prefix + cs.getName(); + } else { + return prefix + " " + cs.getName(); + } + } else { + return cs.getName(); + } + }).collect(Collectors.toList()), Config.BEHAVIOUR__SERVER_LIST__PLAYERS_PER_PAGE.get())); + + if (temporalPaginator.shouldUpdate(60000L)) { + temporalPaginator.update(serverInfo.getPlayers().stream().map(cs -> { + String prefix = plugin.getPrefix(cs); + if(prefix != null) { + if(ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', prefix)).isEmpty()) { + return prefix + cs.getName(); + } else { + return prefix + " " + cs.getName(); + } + } else { + return cs.getName(); + } + }).collect(Collectors.toList())); + } + + page = 1; + if (args.length > 1) { + try { + page = Integer.parseInt(args[1]); + } catch (NumberFormatException ignored) { + + } + } + + List pageData = options.contains("-g") ? temporalPaginator.getFullData() : temporalPaginator.getPage(page); + if (pageData.isEmpty()) { + if (temporalPaginator.getTotalPages() > 0) { + for (String line : Config.FORMATS__SERVER_LIST__NO_PAGE_DATA_MESSAGE.get()) { + sender.sendMessage(TextUtil.fromLegacy(line.replace("{TOTAL_PAGES}", String.valueOf(temporalPaginator.getTotalPages())))); + } + }else { + for(String line : Config.FORMATS__SERVER_LIST__NO_PLAYERS_MESSAGE.get()) { + sender.sendMessage(TextUtil.fromLegacy(line)); + } + } + } else { + String[] namesData = pageData.toArray(new String[0]); + String message = String.join("\n", new ArrayList<>(Config.FORMATS__SERVER_LIST__FULL_MESSAGE_FORMAT.get())).replace("{PLAYERS_ROWS}", TextUtil.makeRows(2, 25, (page - 1) * Config.BEHAVIOUR__SERVER_LIST__PLAYERS_PER_PAGE.get() + 1, ChatColor.GRAY, namesData)).replace("{SERVER_NAME}", Config.BEHAVIOUR__SERVER_LIST__UPPER_CASE_NAME.get() ? serverInfo.getDisplayName().toUpperCase() : serverInfo.getDisplayName()).replace("{PLAYERS_COUNT}", String.valueOf(temporalPaginator.dataSize())).replace("{PAGE}", options.contains("-g") ? Config.MESSAGES__ALL_PAGES.get() : String.valueOf(page)).replace("{TOTAL_PAGES}", String.valueOf(temporalPaginator.getTotalPages())); + + if (options.contains("-g")) { + partsController = message.split("\\n"); + + for (String line : partsController) { + if (!line.contains("{PAGINATION_CONTROLLER}")) { + sender.sendMessage(TextUtil.fromLegacy(line)); + } + } + } else if (message.contains("{PAGINATION_CONTROLLER}")) { + partsController = message.split("\\{PAGINATION_CONTROLLER}"); + BaseComponent mainComponent = new TextComponent(); + + for (BaseComponent bc : TextUtil.fromLegacy(partsController[0])) { + mainComponent.addExtra(bc); + } + + ComponentBuilder cb = null; + if (page > 1 && page < temporalPaginator.getTotalPages()) { + cb = new ComponentBuilder(""); + + if (isPlayerExecutor) { + cb.append("<<") + .color(ChatColor.WHITE) + .event(new ClickEvent(Action.RUN_COMMAND, "/" + this.getName() + " " + serverInfo.getId() + " " + (page - 1))) + .event(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, TextUtil.fromLegacy(Config.MESSAGES__PREVIOUS_PAGE_HOVER_MESSAGE.get().replace("{PAGE_NUMBER}", String.valueOf(page - 1)) ))) + .append(" " + Config.MESSAGES__PREVIOUS_PAGE.get() + " ") + .color(ChatColor.GOLD) + .append("|", FormatRetention.NONE) + .color(ChatColor.DARK_GRAY) + .append(" " + Config.MESSAGES__NEXT_PAGE.get() + " ") + .color(ChatColor.GOLD) + .event(new ClickEvent(Action.RUN_COMMAND, "/" + this.getName() + " " + serverInfo.getId() + " " + (page + 1))) + .event(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, TextUtil.fromLegacy(Config.MESSAGES__NEXT_PAGE_HOVER_MESSAGE.get().replace("{PAGE_NUMBER}", String.valueOf(page + 1))))) + .append(">>").color(ChatColor.WHITE); + } else { + cb.append("Use ").color(ChatColor.GOLD).append("/" + this.getName() + " " + serverInfo.getId() + " " + (page - 1)).color(ChatColor.WHITE).append(" to go to the previous page.\n").color(ChatColor.GOLD).append("Use ").color(ChatColor.GOLD).append("/" + this.getName() + " " + serverInfo.getId() + " " + (page + 1)).color(ChatColor.WHITE).append(" to go to the next page.").color(ChatColor.GOLD); + } + } else if (page <= 1) { + if (page + 1 <= temporalPaginator.getTotalPages()) { + cb = new ComponentBuilder(""); + if (isPlayerExecutor) { + cb.append("<<") + .color(ChatColor.DARK_RED) + .event(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, TextUtil.fromLegacy(Config.MESSAGES__NO_PREVIOUS_PAGE.get()))) + .append(" " + Config.MESSAGES__PREVIOUS_PAGE.get() + " ") + .color(ChatColor.RED) + .append("|", FormatRetention.NONE) + .color(ChatColor.DARK_GRAY) + .append(" " + Config.MESSAGES__NEXT_PAGE.get() + " ") + .color(ChatColor.GOLD) + .event(new ClickEvent(Action.RUN_COMMAND, "/" + this.getName() + " " + serverInfo.getId() + " " + (page + 1))) + .event(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, TextUtil.fromLegacy(Config.MESSAGES__NEXT_PAGE_HOVER_MESSAGE.get().replace("{PAGE_NUMBER}", String.valueOf(page + 1))))) + .append(">>").color(ChatColor.WHITE); + } else { + cb.append("Use ").color(ChatColor.GOLD) + .append("/" + this.getName() + " " + serverInfo.getId() + " " + (page + 1)) + .color(ChatColor.WHITE) + .append(" to go to the next page.") + .color(ChatColor.GOLD); + } + } else if (isPlayerExecutor) { + cb = new ComponentBuilder("<<") + .color(ChatColor.DARK_RED) + .event(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, TextUtil.fromLegacy(Config.MESSAGES__NO_PREVIOUS_PAGE.get()))) + .append(" " + Config.MESSAGES__PREVIOUS_PAGE.get() + " ") + .color(ChatColor.RED) + .append("|", FormatRetention.NONE) + .color(ChatColor.DARK_GRAY) + .append(" " + Config.MESSAGES__NEXT_PAGE.get() + " ") + .color(ChatColor.RED) + .event(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, TextUtil.fromLegacy(Config.MESSAGES__NO_NEXT_PAGE.get()))) + .append(">>") + .color(ChatColor.DARK_RED); + } + } else if (page >= temporalPaginator.getTotalPages()) { + if (isPlayerExecutor) { + cb = new ComponentBuilder("<<") + .color(ChatColor.WHITE) + .event(new ClickEvent(Action.RUN_COMMAND, "/" + this.getName() + " " + serverInfo.getId() + " " + (page - 1))) + .event(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, TextUtil.fromLegacy(Config.MESSAGES__PREVIOUS_PAGE_HOVER_MESSAGE.get().replace("{PAGE_NUMBER}", String.valueOf(page - 1))))) + .append(" " + Config.MESSAGES__PREVIOUS_PAGE.get() + " ") + .color(ChatColor.GOLD) + .append("|", FormatRetention.NONE) + .color(ChatColor.DARK_GRAY) + .append(" " + Config.MESSAGES__NEXT_PAGE.get() + " ") + .color(ChatColor.RED) + .event(new HoverEvent(net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT, TextUtil.fromLegacy(Config.MESSAGES__NO_NEXT_PAGE.get()))) + .append(">>") + .color(ChatColor.DARK_RED); + } else { + cb = new ComponentBuilder("Use ") + .color(ChatColor.GOLD) + .append("/" + this.getName() + " " + serverInfo.getId() + " " + (page - 1)) + .color(ChatColor.WHITE) + .append(" to go to the previous page.") + .color(ChatColor.GOLD); + } + } + + BaseComponent bc; + BaseComponent[] bcObject; + int j; + if (cb != null) { + bcObject = cb.create(); + + for(j = 0; j < bcObject.length; ++j) { + bc = bcObject[j]; + mainComponent.addExtra(bc); + } + } + + if (partsController.length > 1) { + bcObject = TextUtil.fromLegacy(partsController[1]); + + for(j = 0; j < bcObject.length; ++j) { + bc = bcObject[j]; + mainComponent.addExtra(bc); + } + } + + sender.sendMessage(mainComponent); + } else { + if(message.endsWith("\n")) { + message = message.substring(0, message.length() - 2); + } + + sender.sendMessage(TextUtil.fromLegacy(message)); + } + } + } + } + } + + @Override + public Iterable onTabComplete(CommandSender sender, String[] args) { + + if(args.length == 1) { + List blackListedServers = Config.BEHAVIOUR__SERVER_LIST__BLACKLISTED_SERVERS.get(); + Set suggestions = BungeeCord.getInstance().getServers().values().stream().filter(s -> { + //hide blacklisted + if(blackListedServers.stream().anyMatch(ss -> ss.equalsIgnoreCase(s.getName()))) { + return false; + } + + return s.getName().toLowerCase().contains(args[0].toLowerCase()); + }).map(s -> s.getName().toLowerCase()).collect(Collectors.toSet()); + + //add groups as suggestions + List groupSuggestions = plugin.getServerGroups().stream().map(s -> s.getId().toLowerCase()).collect(Collectors.toList()); + //remove blacklisted + groupSuggestions.removeIf(g -> blackListedServers.stream().anyMatch(ss -> ss.equalsIgnoreCase(g))); + + suggestions.addAll(groupSuggestions); + + List sortedSuggestions = new ArrayList<>(suggestions); + sortedSuggestions.sort(Collator.getInstance(Locale.US)); + + if(args[0].isEmpty() || args[0].startsWith("-")) { + sortedSuggestions.add(0, "-g"); + sortedSuggestions.add(0, "-sp"); + sortedSuggestions.add(0, "-a"); + } + + return sortedSuggestions; + } + + return Collections.emptyList(); + } + +} diff --git a/src/dev/wirlie/bungeecord/glist/groups/GroupManager.java b/src/dev/wirlie/bungeecord/glist/groups/GroupManager.java index 8f9045b7..3c9e9361 100644 --- a/src/dev/wirlie/bungeecord/glist/groups/GroupManager.java +++ b/src/dev/wirlie/bungeecord/glist/groups/GroupManager.java @@ -5,125 +5,150 @@ import net.md_5.bungee.config.Configuration; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.*; import java.util.logging.Level; import java.util.stream.Collectors; public class GroupManager { - private List groups = new ArrayList<>(); - private String staffGroupPermission = null; + private final List groups = new ArrayList<>(); - private File groupFile; - private EnhancedBCL plugin; + private final File groupFile; + private final EnhancedBCL plugin; public GroupManager(EnhancedBCL plugin) { - this.groupFile = new File(plugin.getDataFolder(), "Groups.yml"); + this.groupFile = new File(plugin.getDataFolder(), "GroupsPrefix.yml"); this.plugin = plugin; } public void loadGroups() { if(!groupFile.exists()) { - plugin.getLogger().warning("File not found: Groups.yml | 0 groups loaded for enhanced list."); - } else { - plugin.getLogger().info("Groups.yml found, reading configuration ..."); - + plugin.getLogger().info("File not found: GroupsPrefix.yml | Generating file..."); + File parentFolder = groupFile.getParentFile(); + if(!parentFolder.exists()) { + parentFolder.mkdirs(); + } try { - groups.clear(); + Files.copy(getClass().getResourceAsStream("/GroupsPrefix.yml"), groupFile.toPath()); + } catch (IOException e) { + e.printStackTrace(); + } + } - Configuration config = plugin.loadConfiguration(groupFile); - staffGroupPermission = config.getString("staff-group.permission", null); + if(!groupFile.exists()) { + plugin.getLogger().warning("File: GroupsPrefix.yml not found, check folder permissions, plugin cannot create default file..."); + return; + } - if(staffGroupPermission == null) { - plugin.getLogger().warning("No permission defined for staff members. Using default permission: 'ebl.groups.staff'"); - staffGroupPermission = "ebl.groups.staff"; - } + plugin.getLogger().info("GroupsPrefix.yml found, reading configuration ..."); - if(!config.contains("groups")) { - plugin.getLogger().warning("No groups defined. Adding default group for users."); - Group group = new Group("default"); - group.setDefaultGroup(true); - group.setNameColor("&7"); - groups.add(group); - return; - } + try { + groups.clear(); - try { - @SuppressWarnings("unchecked") - List> allData = (List>) config.get("groups"); - for(Map groupData : allData) { - try { - String id = null; - int weight = 0; - String prefix = null; - String prefixPermission = null; - boolean prefixVisibleToUsers = true; - String nameColor = null; - - for (Map.Entry entry : groupData.entrySet()) { - String key = entry.getKey().toString(); - String value = entry.getValue().toString(); - - if (key.equalsIgnoreCase("id")) { - id = value; - } else if (key.equalsIgnoreCase("weight")) { - try { - weight = Integer.parseInt(value); - } catch (NumberFormatException e) { - plugin.getLogger().warning("Unexpected weight value: " + value); - } - } else if (key.equalsIgnoreCase("prefix")) { - prefix = value; - } else if (key.equalsIgnoreCase("prefix-permission")) { - prefixPermission = value; - } else if(key.equalsIgnoreCase("prefix-visible-to-users")) { - prefixVisibleToUsers = Boolean.parseBoolean(value); - } else if(key.equalsIgnoreCase("name-color")) { - nameColor = value; - } - } + Configuration config = plugin.getYamlProvider().load(new InputStreamReader(new FileInputStream(groupFile), StandardCharsets.UTF_8)); + String staffGroupPermission = config.getString("staff-group.permission", null); - if(id == null) { - plugin.getLogger().warning("Group not loaded: id must be defined"); - } else { - Group group = new Group(id); - group.setWeight(weight); - group.setPrefix(prefix); - group.setPrefixPermission(prefixPermission); - group.setVisibleToUsers(prefixVisibleToUsers); - group.setNameColor(nameColor); - - if(groups.contains(group)) { - plugin.getLogger().warning("Group '" + group.getId() + "' already loaded! Fixing id to: '" + group.getId() + "~1'"); - group.setId(id + "~1"); - } + if(staffGroupPermission == null) { + plugin.getLogger().warning("No permission defined for staff members. Using default permission: 'ebl.groups.staff'"); + staffGroupPermission = "ebl.groups.staff"; + } - int fixedId = 1; - while(groups.contains(group)) { - fixedId++; - plugin.getLogger().warning("Group '" + group.getId() + "' already loaded! Fixing id to: '" + id + "~" + fixedId + "'"); - group.setId(id + "~" + fixedId); + if(!config.contains("groups")) { + plugin.getLogger().warning("No groups defined. Adding default group for users."); + Group group = new Group("default"); + group.setDefaultGroup(true); + group.setNameColor("&7"); + groups.add(group); + return; + } + + try { + @SuppressWarnings("unchecked") + List> allData = (List>) config.get("groups"); + for(Map groupData : allData) { + try { + String id = null; + int weight = 0; + String prefix = null; + String prefixPermission = null; + boolean prefixVisibleToUsers = true; + String nameColor = ""; + boolean defaultGroup = false; + + for (Map.Entry entry : groupData.entrySet()) { + String key = entry.getKey().toString(); + String value = entry.getValue().toString(); + + if (key.equalsIgnoreCase("id")) { + id = value; + } else if (key.equalsIgnoreCase("weight")) { + try { + weight = Integer.parseInt(value); + } catch (NumberFormatException e) { + plugin.getLogger().warning("Unexpected weight value: " + value); } + } else if (key.equalsIgnoreCase("prefix")) { + prefix = value; + } else if (key.equalsIgnoreCase("prefix-permission")) { + prefixPermission = value; + } else if(key.equalsIgnoreCase("prefix-visible-to-users")) { + prefixVisibleToUsers = Boolean.parseBoolean(value); + } else if(key.equalsIgnoreCase("name-color")) { + nameColor = value; + } else if(key.equalsIgnoreCase("default-group")) { + try { + defaultGroup = Boolean.parseBoolean(value); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } - plugin.getLogger().info("Group '" + group.getId() + "' loaded. Weight: " + group.getWeight() + ", permission: " + group.getPrefixPermission()); + if(id == null) { + plugin.getLogger().warning("Group not loaded: id must be defined"); + } else { + Group group = new Group(id); + group.setDefaultGroup(defaultGroup); + group.setWeight(weight); + group.setPrefix(prefix); + group.setPrefixPermission(prefixPermission); + group.setVisibleToUsers(prefixVisibleToUsers); + group.setNameColor(nameColor); + + if(groups.contains(group)) { + plugin.getLogger().warning("Group '" + group.getId() + "' already loaded! Fixing id to: '" + group.getId() + "~1'"); + group.setId(id + "~1"); + } - groups.add(group); + int fixedId = 1; + while(groups.contains(group)) { + fixedId++; + plugin.getLogger().warning("Group '" + group.getId() + "' already loaded! Fixing id to: '" + id + "~" + fixedId + "'"); + group.setId(id + "~" + fixedId); } - } catch (Exception e) { - e.printStackTrace(); + + plugin.getLogger().info("Group '" + group.getId() + "' loaded. Weight: " + group.getWeight() + ", permission: " + group.getPrefixPermission()); + + groups.add(group); } + } catch (Exception e) { + e.printStackTrace(); } - } catch (ClassCastException e) { - plugin.getLogger().log(Level.SEVERE, "Cannot read Groups.yml (ClassCastException)", e); } - - groups.sort(Comparator.naturalOrder()); - plugin.getLogger().info(groups.size() + " groups loaded."); - plugin.getLogger().info(groups.stream().map(Group::getId).collect(Collectors.joining(", ", "[", "]"))); - } catch (IOException e) { - plugin.getLogger().log(Level.SEVERE, "Cannot read Groups.yml (IOException)", e); + } catch (ClassCastException e) { + plugin.getLogger().log(Level.SEVERE, "Cannot read GroupsPrefix.yml (ClassCastException)", e); } + + groups.sort(Comparator.naturalOrder()); + plugin.getLogger().info(groups.size() + " groups loaded."); + plugin.getLogger().info(groups.stream().map(Group::getId).collect(Collectors.joining(", ", "[", "]"))); + } catch (IOException e) { + plugin.getLogger().log(Level.SEVERE, "Cannot read GroupsPrefix.yml (IOException)", e); } } diff --git a/src/dev/wirlie/bungeecord/glist/hooks/GroupHook.java b/src/dev/wirlie/bungeecord/glist/hooks/GroupHook.java new file mode 100644 index 00000000..8c2744d6 --- /dev/null +++ b/src/dev/wirlie/bungeecord/glist/hooks/GroupHook.java @@ -0,0 +1,23 @@ +package dev.wirlie.bungeecord.glist.hooks; + +import net.md_5.bungee.api.connection.ProxiedPlayer; +import org.jetbrains.annotations.Nullable; + +public abstract class GroupHook { + + private int priority; + + public GroupHook(int priority) { + this.priority = priority; + } + + public int getPriority() { + return priority; + } + + @Nullable + public abstract String getPrefix(ProxiedPlayer player); + + public abstract void reload(); + +} diff --git a/src/dev/wirlie/bungeecord/glist/hooks/InternalGroupSystemHook.java b/src/dev/wirlie/bungeecord/glist/hooks/InternalGroupSystemHook.java new file mode 100644 index 00000000..d493b033 --- /dev/null +++ b/src/dev/wirlie/bungeecord/glist/hooks/InternalGroupSystemHook.java @@ -0,0 +1,32 @@ +package dev.wirlie.bungeecord.glist.hooks; + +import dev.wirlie.bungeecord.glist.EnhancedBCL; +import dev.wirlie.bungeecord.glist.config.Config; +import dev.wirlie.bungeecord.glist.groups.Group; +import dev.wirlie.bungeecord.glist.groups.GroupManager; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +public class InternalGroupSystemHook extends GroupHook { + + private final GroupManager manager; + + public InternalGroupSystemHook(EnhancedBCL plugin) { + super(Config.BEHAVIOUR__GROUPS_PREFIX__PRIORITY__INTERNAL_GROUP_SYSTEM.get()); + this.manager = new GroupManager(plugin); + manager.loadGroups(); + } + + @Override + public @Nullable String getPrefix(ProxiedPlayer player) { + return manager.getGroup(player).map(g -> g.getPrefix() + g.getNameColor()).orElse(null); + } + + @Override + public void reload() { + manager.loadGroups(); + } + +} diff --git a/src/dev/wirlie/bungeecord/glist/hooks/LuckPermsHook.java b/src/dev/wirlie/bungeecord/glist/hooks/LuckPermsHook.java new file mode 100644 index 00000000..e4fedb4c --- /dev/null +++ b/src/dev/wirlie/bungeecord/glist/hooks/LuckPermsHook.java @@ -0,0 +1,37 @@ +package dev.wirlie.bungeecord.glist.hooks; + +import dev.wirlie.bungeecord.glist.config.Config; +import net.luckperms.api.LuckPerms; +import net.luckperms.api.LuckPermsProvider; +import net.luckperms.api.model.user.User; +import net.luckperms.api.query.QueryOptions; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import org.jetbrains.annotations.Nullable; + +public class LuckPermsHook extends GroupHook { + + public LuckPermsHook() { + super(Config.BEHAVIOUR__GROUPS_PREFIX__PRIORITY__LUCKPERMS.get()); + } + + @Override + public @Nullable String getPrefix(ProxiedPlayer player) { + String prefix = null; + + LuckPerms luckPerms = LuckPermsProvider.get(); + User user = luckPerms.getUserManager().getUser(player.getUniqueId()); + + if (user != null) { + prefix = user + .getCachedData() + .getMetaData(QueryOptions.defaultContextualOptions()) + .getPrefix(); + } + + return prefix; + } + + @Override + public void reload() {} + +} diff --git a/src/dev/wirlie/bungeecord/glist/servers/BungeecordInfoProvider.java b/src/dev/wirlie/bungeecord/glist/servers/BungeecordInfoProvider.java new file mode 100644 index 00000000..7693d2f7 --- /dev/null +++ b/src/dev/wirlie/bungeecord/glist/servers/BungeecordInfoProvider.java @@ -0,0 +1,36 @@ +package dev.wirlie.bungeecord.glist.servers; + +import net.md_5.bungee.api.config.ServerInfo; +import net.md_5.bungee.api.connection.ProxiedPlayer; + +import java.util.ArrayList; +import java.util.List; + +public class BungeecordInfoProvider implements ServerInfoProvider { + + private final ServerInfo info; + + public BungeecordInfoProvider(ServerInfo info) { + this.info = info; + } + + @Override + public String getId() { + return info.getName(); + } + + @Override + public int getPlayerCount() { + return info.getPlayers().size(); + } + + @Override + public List getPlayers() { + return new ArrayList<>(info.getPlayers()); + } + + @Override + public String getDisplayName() { + return info.getName(); + } +} diff --git a/src/dev/wirlie/bungeecord/glist/servers/ServerGroup.java b/src/dev/wirlie/bungeecord/glist/servers/ServerGroup.java new file mode 100644 index 00000000..699a63c1 --- /dev/null +++ b/src/dev/wirlie/bungeecord/glist/servers/ServerGroup.java @@ -0,0 +1,46 @@ +package dev.wirlie.bungeecord.glist.servers; + +import net.md_5.bungee.api.config.ServerInfo; +import net.md_5.bungee.api.connection.ProxiedPlayer; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class ServerGroup implements ServerInfoProvider { + + private final String id; + private List servers = new ArrayList<>(); + + public ServerGroup(String id) { + this.id = id; + } + + public void setServers(List servers) { + this.servers = servers; + } + + public List getServers() { + return servers; + } + + @Override + public String getId() { + return id; + } + + @Override + public int getPlayerCount() { + return servers.stream().mapToInt(s -> s.getPlayers().size()).sum(); + } + + @Override + public List getPlayers() { + return servers.stream().flatMap(s -> s.getPlayers().stream()).collect(Collectors.toList()); + } + + @Override + public String getDisplayName() { + return id + " (" + servers.stream().map(ServerInfo::getName).collect(Collectors.joining(", ")) + ")"; + } +} diff --git a/src/dev/wirlie/bungeecord/glist/servers/ServerInfoProvider.java b/src/dev/wirlie/bungeecord/glist/servers/ServerInfoProvider.java new file mode 100644 index 00000000..ffeb31ef --- /dev/null +++ b/src/dev/wirlie/bungeecord/glist/servers/ServerInfoProvider.java @@ -0,0 +1,17 @@ +package dev.wirlie.bungeecord.glist.servers; + +import net.md_5.bungee.api.connection.ProxiedPlayer; + +import java.util.List; + +public interface ServerInfoProvider { + + String getId(); + + String getDisplayName(); + + int getPlayerCount(); + + List getPlayers(); + +} diff --git a/src/dev/wirlie/bungeecord/glist/updater/UpdateChecker.java b/src/dev/wirlie/bungeecord/glist/updater/UpdateChecker.java new file mode 100644 index 00000000..64cf6193 --- /dev/null +++ b/src/dev/wirlie/bungeecord/glist/updater/UpdateChecker.java @@ -0,0 +1,131 @@ +package dev.wirlie.bungeecord.glist.updater; + +import dev.wirlie.bungeecord.glist.EnhancedBCL; +import net.md_5.bungee.BungeeCord; + +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; +import java.util.function.Consumer; +import java.util.logging.Level; + +public class UpdateChecker { + + private final EnhancedBCL plugin; + private String lastKnowVersion = null; + private boolean hasUpdate = false; + + public UpdateChecker(EnhancedBCL plugin) { + this.plugin = plugin; + } + + public void hasUpdate(Consumer updateConsumer, Consumer exceptionConsumer) { + if(lastKnowVersion != null) { + updateConsumer.accept(hasUpdate); + } else { + //obtener + getSpigotVersion(version -> updateConsumer.accept(hasUpdate), ex -> { + if(ex != null) { + exceptionConsumer.accept(ex); + } + }); + } + } + + public void getLastKnowVersion(Consumer versionConsumer, Consumer exceptionConsumer) { + if(lastKnowVersion != null) { + versionConsumer.accept(lastKnowVersion); + } else { + //obtener + getSpigotVersion(versionConsumer, ex -> { + if(ex != null) { + exceptionConsumer.accept(ex); + } + }); + } + } + + public void getSpigotVersion(Consumer versionConsumer, Consumer exceptionConsumer) { + plugin.getLogger().info("Checking for updates..."); + BungeeCord.getInstance().getScheduler().runAsync(plugin, () -> { + try (InputStream inputStream = new URL("https://api.spigotmc.org/legacy/update.php?resource=53295").openStream(); Scanner scanner = new Scanner(inputStream)) { + if (scanner.hasNext()) { + String version = scanner.next(); + lastKnowVersion = version; + hasUpdate = determineIfUpdateAvailable(); + + plugin.getLogger().info("-------------------------------------------"); + plugin.getLogger().info("Remote version (SpigotMC): " + version); + plugin.getLogger().info("Current version (Plugin): " + plugin.getDescription().getVersion()); + plugin.getLogger().info("-------------------------------------------"); + + if(hasUpdate) { + plugin.getLogger().warning("New update found!! Download the latest update from: "); + plugin.getLogger().warning("https://www.spigotmc.org/resources/enhancedbungeelist.53295/"); + } else { + plugin.getLogger().info("Plugin is up to date."); + } + + plugin.getLogger().info("-------------------------------------------"); + + versionConsumer.accept(version); + } + } catch (Throwable exception) { + exceptionConsumer.accept(exception); + } + }); + } + + private boolean determineIfUpdateAvailable() { + try { + String currentVersion = plugin.getDescription().getVersion(); + String remoteVersion = lastKnowVersion; + + if(currentVersion.equals(remoteVersion)) { + return false; + } + + List currentVersionParts = new ArrayList<>(Arrays.asList(currentVersion.split("\\."))); + List remoteVersionParts = new ArrayList<>(Arrays.asList(remoteVersion.split("\\."))); + + int maxParts = Math.max(currentVersionParts.size(), remoteVersionParts.size()); + + for(int i = currentVersionParts.size(); i < maxParts; i++) { + currentVersionParts.add("0"); + } + + for(int i = remoteVersionParts.size(); i < maxParts; i++) { + remoteVersionParts.add("0"); + } + + if(currentVersionParts.size() != remoteVersionParts.size()) { + throw new IllegalStateException("Unexpected size mismatch, remote parts: [" + String.join(".", remoteVersionParts) + "] vs plugin parts: [" + String.join(".", currentVersionParts) + "]"); + } + + for(int i = 0; i < maxParts; i++) { + String remotePart = remoteVersionParts.get(i); + String currentPart = currentVersionParts.get(i); + + int remotePartNumber = Integer.parseInt(remotePart); + int currentPartNumber = Integer.parseInt(currentPart); + + if(remotePartNumber > currentPartNumber) { + return true; + } + + if(remotePartNumber < currentPartNumber) { + return false; + } + } + + return false; + } catch (Exception ex) { + plugin.getLogger().log(Level.SEVERE, "Failed to determine if there is a new update! Remote[" + lastKnowVersion + "], Plugin[" + plugin.getDescription().getVersion() + "]", ex); + return false; + } + } + +} diff --git a/src/dev/wirlie/bungeecord/glist/updater/UpdateNotifyListener.java b/src/dev/wirlie/bungeecord/glist/updater/UpdateNotifyListener.java new file mode 100644 index 00000000..0bf6c790 --- /dev/null +++ b/src/dev/wirlie/bungeecord/glist/updater/UpdateNotifyListener.java @@ -0,0 +1,48 @@ +package dev.wirlie.bungeecord.glist.updater; + +import dev.wirlie.bungeecord.glist.EnhancedBCL; +import dev.wirlie.bungeecord.glist.config.Config; +import dev.wirlie.bungeecord.glist.util.TextUtil; +import net.md_5.bungee.BungeeCord; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.event.PostLoginEvent; +import net.md_5.bungee.api.plugin.Listener; +import net.md_5.bungee.event.EventHandler; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class UpdateNotifyListener implements Listener { + + private final EnhancedBCL plugin; + + public UpdateNotifyListener(EnhancedBCL plugin) { + this.plugin = plugin; + } + + @EventHandler + public void event(PostLoginEvent e) { + ProxiedPlayer pp = e.getPlayer(); + if(pp.isConnected()) { + if(Config.UPDATES__NOTIFY__ENABLE.get()) { + if(pp.hasPermission(Config.UPDATES__NOTIFY__PERMISSION.get())) { + int delay = Config.UPDATES__NOTIFY__DELAY_MS.get(); + + if(delay < 1) { + delay = 1; + } + + BungeeCord.getInstance().getScheduler().schedule(plugin, () -> { + //notify + List rawMessages = Config.UPDATES__NOTIFY__MESSAGE.get(); + + for(String line : rawMessages) { + pp.sendMessage(TextUtil.fromLegacy(line)); + } + }, delay, TimeUnit.MILLISECONDS); + } + } + } + } + +} diff --git a/src/dev/wirlie/bungeecord/glist/TextUtil.java b/src/dev/wirlie/bungeecord/glist/util/TextUtil.java similarity index 52% rename from src/dev/wirlie/bungeecord/glist/TextUtil.java rename to src/dev/wirlie/bungeecord/glist/util/TextUtil.java index b8ed4f16..a43f1adf 100644 --- a/src/dev/wirlie/bungeecord/glist/TextUtil.java +++ b/src/dev/wirlie/bungeecord/glist/util/TextUtil.java @@ -1,4 +1,4 @@ -package dev.wirlie.bungeecord.glist; +package dev.wirlie.bungeecord.glist.util; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.BaseComponent; @@ -16,11 +16,49 @@ private static String makeRow(int columnSize, int startIndex, ChatColor columnCo for (String aData : data) { String str = aData; if (str != null) { - if (str.length() > columnSize - 2) { - str = str.substring(0, columnSize - 2); + String sanitized = ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', str)); + + int realIndex = sanitized.length(); + + if (sanitized.length() > columnSize - 2) { + char[] chars = str.toCharArray(); + + int absoluteIndex = 0; + int strippedIndex = 0; + boolean colorToken = false; + + for(char ch : chars) { + absoluteIndex++; + + if(ch == '&' || ch == '§') { + if(colorToken) { + //subsequents & will not be parsed + strippedIndex++; + } + + colorToken = true; + } else if(colorToken) { + if(ch != '1' && ch != '2' && ch != '3' && ch != '4' && ch != '5' && ch != '6' && ch != '7' && ch != '8' && ch != '9' + && ch != 'a' && ch != 'b' && ch != 'c' && ch != 'd' && ch != 'e' && ch != 'f' + && ch != 'k' && ch != 'l' && ch != 'm' && ch != 'n' && ch != 'o' && ch != 'r') { + strippedIndex++; + } + + colorToken = false; + } else { + strippedIndex++; + } + + if(strippedIndex >= columnSize - 2) { + break; + } + } + + str = str.substring(0, absoluteIndex); + realIndex = strippedIndex; } - int fillSpaces = columnSize - str.length(); + int fillSpaces = columnSize - realIndex; stringBuilder.append(ChatColor.DARK_AQUA.toString()).append("#").append(j).append(" ").append(columnColor.toString()).append(str); for (int i = 0; i < fillSpaces; ++i) { @@ -58,4 +96,4 @@ public static String makeRows(int columns, int columnSize, int startIndex, ChatC return stringBuilder.toString(); } -} \ No newline at end of file +}