Parameter for section commands and improvements to the ping manager

This commit is contained in:
Jaime Martinez Rincon 2017-03-28 19:54:44 +02:00
parent 5df10a5ab5
commit 24953e5ff3
19 changed files with 265 additions and 94 deletions

View File

@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<list size="1">
<item index="0" class="java.lang.String" itemvalue="net.md_5.bungee.event.EventHandler" />
</list>
</component>
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>

View File

@ -6,7 +6,7 @@
<groupId>me.jaimemartz</groupId>
<artifactId>lobbybalancer</artifactId>
<version>2.0.9.4</version>
<version>2.0.9.5</version>
<name>LobbyBalancer</name>
<properties>

View File

@ -79,7 +79,7 @@ public class FallbackCommand extends Command {
try {
ServerSection section = callable.call();
if (section != null) {
ConnectionIntent.connect(plugin, player, section);
ConnectionIntent.simple(plugin, player, section);
}
} catch (Exception e) {
//Nothing to do

View File

@ -32,7 +32,6 @@ public class MainCommand extends Command {
switch (args[0]) {
case "paste": {
if (sender.hasPermission("lobbybalancer.admin")) {
PasteHelper.LOGS.send(plugin, sender, "Last log file paste link: {link}");
PasteHelper.PLUGIN.send(plugin, sender, "Plugin config paste link: {link}");
PasteHelper.BUNGEE.send(plugin, sender, "Bungee config paste link (sensitive): {link}");
} else {

View File

@ -6,7 +6,7 @@ import me.jaimemartz.faucet.StringCombiner;
import me.jaimemartz.lobbybalancer.LobbyBalancer;
import me.jaimemartz.lobbybalancer.configuration.ConfigEntries;
import me.jaimemartz.lobbybalancer.connection.ConnectionIntent;
import me.jaimemartz.lobbybalancer.ping.ServerStatus;
import me.jaimemartz.lobbybalancer.ping.PingStatus;
import me.jaimemartz.lobbybalancer.section.ServerSection;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
@ -35,7 +35,7 @@ public class ManageCommand extends Command {
if (sender.hasPermission("lobbybalancer.admin")) {
if (args.length != 0) {
switch (args[0].toLowerCase()) {
case "connect": {
case "simple": {
if (args.length >= 2) {
String input = args[1];
ServerSection section = plugin.getSectionManager().getByName(input);
@ -43,13 +43,13 @@ public class ManageCommand extends Command {
if (args.length == 3) {
ProxiedPlayer player = plugin.getProxy().getPlayer(args[2]);
if (player != null) {
ConnectionIntent.connect(plugin, player, section);
ConnectionIntent.simple(plugin, player, section);
} else {
msgr.send("&cThere is no player with that name connected to this proxy");
}
} else {
if (sender instanceof ProxiedPlayer) {
ConnectionIntent.connect(plugin, (ProxiedPlayer) sender, section);
ConnectionIntent.simple(plugin, (ProxiedPlayer) sender, section);
} else {
msgr.send("&cThis command can only be executed by a player");
}
@ -117,7 +117,7 @@ public class ManageCommand extends Command {
if (!section.getServers().isEmpty()) {
msgr.send("&7Section Servers: ");
section.getServers().forEach(server -> {
ServerStatus status = plugin.getPingManager().getStatus(server);
PingStatus status = plugin.getPingManager().getStatus(server);
msgr.send("&7> Server &b{name} &c({connected}/{maximum}) &7({status}&7)",
new Replacement("{name}", server.getName()),
new Replacement("{connected}", String.valueOf(status.getOnlinePlayers())),
@ -191,7 +191,7 @@ public class ManageCommand extends Command {
"&7Available commands:",
"&3/section list &7- &cTells you which sections are configured in the plugin",
"&3/section info <section> &7- &cTells you info about the section",
"&3/section connect <section> [player] &7- &cConnects you or the specified player to that section",
"&3/section simple <section> [player] &7- &cConnects you or the specified player to that section",
"&7&m-----------------------------------------------------"
);
}

View File

@ -47,8 +47,9 @@ public class ConfigEntries implements ConfigEntryHolder {
public static final ConfigEntry<String> CONNECTING_MESSAGE = new ConfigEntry<>(0, "settings.messages.connecting", null);
public static final ConfigEntry<String> FAILURE_MESSAGE = new ConfigEntry<>(0, "settings.messages.failure", null);
public static final ConfigEntry<String> UNAVAILABLE_MESSAGE = new ConfigEntry<>(0, "settings.messages.unavailable", null);
public static final ConfigEntry<String> UNKNOWN_SECTION_MESSAGE = new ConfigEntry<>(0, "settings.messages.unknown", null);
public static final ConfigEntry<String> UNKNOWN_SECTION_MESSAGE = new ConfigEntry<>(0, "settings.messages.unknown-section", null);
public static final ConfigEntry<String> INVALID_INPUT_MESSAGE = new ConfigEntry<>(0, "settings.messages.invalid-input", null);
public static final ConfigEntry<String> UNAVAILABLE_MESSAGE = new ConfigEntry<>(0, "settings.messages.unavailable-server", null);
public static final ConfigEntry<String> KICK_MESSAGE = new ConfigEntry<>(0, "settings.messages.kick", null);
public static final ConfigEntry<String> CONFIG_VERSION = new ConfigEntry<>(0, "version", null);

View File

@ -5,7 +5,7 @@ import me.jaimemartz.faucet.Replacement;
import me.jaimemartz.lobbybalancer.LobbyBalancer;
import me.jaimemartz.lobbybalancer.configuration.ConfigEntries;
import me.jaimemartz.lobbybalancer.manager.PlayerLocker;
import me.jaimemartz.lobbybalancer.ping.ServerStatus;
import me.jaimemartz.lobbybalancer.ping.PingStatus;
import me.jaimemartz.lobbybalancer.section.ServerSection;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
@ -32,7 +32,7 @@ public abstract class ConnectionIntent {
ServerInfo target = this.fetchServer(plugin, player, section, provider, servers);
if (target != null) {
new Messager(player).send(ConfigEntries.CONNECTING_MESSAGE.get(), new Replacement("{server}", target.getName()));
this.connect(target);
this.simple(target);
} else {
new Messager(player).send(ConfigEntries.FAILURE_MESSAGE.get());
this.failure();
@ -56,7 +56,7 @@ public abstract class ConnectionIntent {
if (ConfigEntries.ASSIGN_TARGETS_ENABLED.get()) {
if (ServerAssignRegistry.hasAssignedServer(player, section)) {
ServerInfo target = ServerAssignRegistry.getAssignedServer(player, section);
ServerStatus status = plugin.getPingManager().getStatus(target);
PingStatus status = plugin.getPingManager().getStatus(target);
if (status.isAccessible()) {
return target;
} else {
@ -73,7 +73,7 @@ public abstract class ConnectionIntent {
ServerInfo target = provider.requestTarget(plugin, section, servers, player);
if (target == null) continue;
ServerStatus status = plugin.getPingManager().getStatus(target);
PingStatus status = plugin.getPingManager().getStatus(target);
if (status.isAccessible()) {
return target;
} else {
@ -84,22 +84,26 @@ public abstract class ConnectionIntent {
return null;
}
public abstract void connect(ServerInfo server);
public abstract void simple(ServerInfo server);
public void failure() {
//Nothing to do
}
public static void connect(LobbyBalancer plugin, ProxiedPlayer player, ServerSection section) {
public static void simple(LobbyBalancer plugin, ProxiedPlayer player, ServerSection section) {
new ConnectionIntent(plugin, player, section) {
@Override
public void connect(ServerInfo server) {
public void simple(ServerInfo server) {
direct(plugin, player, server);
}
};
}
public static void direct(LobbyBalancer plugin, ProxiedPlayer player, ServerInfo server) {
PlayerLocker.lock(player);
player.connect(server);
plugin.getProxy().getScheduler().schedule(plugin, () -> {
PlayerLocker.unlock(player);
}, 5, TimeUnit.SECONDS);
}
};
}
}

View File

@ -7,7 +7,7 @@ import com.maxmind.geoip2.record.Country;
import me.jaimemartz.lobbybalancer.LobbyBalancer;
import me.jaimemartz.lobbybalancer.configuration.ConfigEntries;
import me.jaimemartz.lobbybalancer.manager.NetworkManager;
import me.jaimemartz.lobbybalancer.ping.ServerStatus;
import me.jaimemartz.lobbybalancer.ping.PingStatus;
import me.jaimemartz.lobbybalancer.section.ServerSection;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
@ -95,7 +95,7 @@ public enum ProviderType {
@Override
public ServerInfo requestTarget(LobbyBalancer plugin, ServerSection section, List<ServerInfo> list, ProxiedPlayer player) {
for (ServerInfo server : list) {
ServerStatus status = plugin.getPingManager().getStatus(server);
PingStatus status = plugin.getPingManager().getStatus(server);
if (NetworkManager.getPlayers(server).size() < status.getMaximumPlayers()) {
return server;
}
@ -111,7 +111,7 @@ public enum ProviderType {
ServerInfo target = null;
for (ServerInfo server : list) {
ServerStatus status = plugin.getPingManager().getStatus(server);
PingStatus status = plugin.getPingManager().getStatus(server);
int count = NetworkManager.getPlayers(server).size();
if (count > max && count <= status.getMaximumPlayers()) {

View File

@ -46,7 +46,7 @@ public class PluginMessageListener implements Listener {
return;
}
ConnectionIntent.connect(plugin, player, section);
ConnectionIntent.simple(plugin, player, section);
}
break;
}
@ -62,7 +62,7 @@ public class PluginMessageListener implements Listener {
return;
}
ConnectionIntent.connect(plugin, player, section);
ConnectionIntent.simple(plugin, player, section);
break;
}

View File

@ -65,7 +65,7 @@ public class ServerConnectListener implements Listener {
if (section != null) {
new ConnectionIntent(plugin, player, section) {
@Override
public void connect(ServerInfo server) {
public void simple(ServerInfo server) {
if (ConfigEntries.ASSIGN_TARGETS_ENABLED.get()) {
ServerAssignRegistry.assignTarget(player, section, server);
}

View File

@ -115,7 +115,7 @@ public class ServerKickListener implements Listener {
new ConnectionIntent(plugin, player, section, servers) {
@Override
public void connect(ServerInfo server) {
public void simple(ServerInfo server) {
PlayerLocker.lock(player);
msgr.send(ConfigEntries.KICK_MESSAGE.get(),
new Replacement("{from}", from.getName()),

View File

@ -1,10 +1,10 @@
package me.jaimemartz.lobbybalancer.manager;
import com.google.common.io.CharStreams;
import me.jaimemartz.lobbybalancer.LobbyBalancer;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.api.scheduler.ScheduledTask;
import org.jpaste.exceptions.PasteException;
import org.jpaste.pastebin.PasteExpireDate;
@ -19,7 +19,7 @@ import java.util.concurrent.TimeUnit;
public enum PasteHelper {
PLUGIN {
@Override
public String paste(Plugin plugin) throws Exception {
public String paste(LobbyBalancer plugin) throws Exception {
File file = new File(plugin.getDataFolder(), "config.yml");
if (!file.exists()) {
return "File does not exist";
@ -44,8 +44,8 @@ public enum PasteHelper {
},
BUNGEE {
@Override
public String paste(Plugin plugin) throws Exception {
File file = new File(plugin.getDataFolder().getParentFile().getParentFile(), "config.yml");
public String paste(LobbyBalancer plugin) throws Exception {
File file = new File("config.yml");
if (!file.exists()) {
return "File does not exist";
}
@ -65,38 +65,13 @@ public enum PasteHelper {
PastebinLink link = paste.paste();
return link.getLink().toString();
}
},
LOGS {
@Override
public String paste(Plugin plugin) throws Exception {
//TODO Do not assume location and name of the latest log file
File file = new File(plugin.getDataFolder().getParentFile().getParentFile(), "proxy.log.0");
if (!file.exists()) {
return "File does not exist";
}
PastebinPaste paste = new PastebinPaste();
paste.setPasteTitle("{name} ({version}) Last Logs"
.replace("{name}", plugin.getProxy().getName())
.replace("{version}", plugin.getProxy().getVersion())
);
paste.setDeveloperKey(DEVELOPER_KEY);
paste.setPasteExpireDate(PasteExpireDate.ONE_MONTH);
paste.setVisibility(PastebinPaste.VISIBILITY_UNLISTED);
paste.setPasteFormat("text");
try (FileInputStream stream = new FileInputStream(file)) {
paste.setContents(CharStreams.toString(new InputStreamReader(stream, "UTF-8")));
}
PastebinLink link = paste.paste();
return link.getLink().toString();
}
};
public static final String DEVELOPER_KEY = "e3ff18d8fb001a3ece08ae0d7d4a87bd";
private String link;
private ScheduledTask task = null;
public void send(Plugin plugin, CommandSender sender, String message) {
public void send(LobbyBalancer plugin, CommandSender sender, String message) {
try {
sender.sendMessage(new ComponentBuilder(message.replace("{link}", link == null ? link = paste(plugin) : link)
).color(ChatColor.GREEN).create());
@ -117,5 +92,5 @@ public enum PasteHelper {
}
}
public abstract String paste(Plugin plugin) throws Exception;
public abstract String paste(LobbyBalancer plugin) throws Exception;
}

View File

@ -2,7 +2,7 @@ package me.jaimemartz.lobbybalancer.ping;
import me.jaimemartz.lobbybalancer.LobbyBalancer;
import me.jaimemartz.lobbybalancer.configuration.ConfigEntries;
import me.jaimemartz.lobbybalancer.utils.FixedAdapter;
import me.jaimemartz.lobbybalancer.section.ServerSection;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.scheduler.ScheduledTask;
@ -14,7 +14,7 @@ public class PingManager {
private boolean stopped = true;
private PingTactic tactic;
private ScheduledTask task;
private final Map<ServerInfo, ServerStatus> storage = new HashMap<>();
private final Map<ServerInfo, PingStatus> storage = new HashMap<>();
public PingManager(LobbyBalancer plugin) {
if (task != null) {
@ -26,18 +26,17 @@ public class PingManager {
plugin.getLogger().info(String.format("Starting the ping task, the interval is %s", ConfigEntries.SERVER_CHECK_INTERVAL.get()));
task = plugin.getProxy().getScheduler().schedule(plugin, () -> {
for (ServerInfo server : plugin.getProxy().getServers().values()) {
if (stopped) {
storage.forEach((k, v) -> v.setOutdated(true));
for (ServerSection section : plugin.getSectionManager().getSections().values()) {
if (stopped)
break;
}
if (server != null) {
if (FixedAdapter.getFakeServers().containsKey(server.getName())) {
continue;
}
section.getServers().forEach(server -> {
if (getStatus(server).isOutdated()) {
track(plugin, server);
}
});
}
}, 0L, ConfigEntries.SERVER_CHECK_INTERVAL.get(), TimeUnit.MILLISECONDS);
}
@ -53,7 +52,7 @@ public class PingManager {
private void track(LobbyBalancer plugin, ServerInfo server) {
tactic.ping(server, (status, throwable) -> {
if (status == null) {
status = new ServerStatus("Server Unreachable", 0, 0);
status = new PingStatus("Server Unreachable", 0, 0);
}
if (ConfigEntries.SERVER_CHECK_PRINT_INFO.get()) {
@ -61,15 +60,16 @@ public class PingManager {
server.getName(), status.getDescription(), status.getOnlinePlayers(), status.getMaximumPlayers(), status.isAccessible()));
}
status.setOutdated(false);
storage.put(server, status);
}, plugin);
}
public ServerStatus getStatus(ServerInfo server) {
ServerStatus status = storage.get(server);
public PingStatus getStatus(ServerInfo server) {
PingStatus status = storage.get(server);
if (status == null) {
status = new ServerStatus(server.getMotd(), server.getPlayers().size(), Integer.MAX_VALUE);
status = new PingStatus(server.getMotd(), server.getPlayers().size(), Integer.MAX_VALUE);
}
return status;

View File

@ -2,11 +2,12 @@ package me.jaimemartz.lobbybalancer.ping;
import me.jaimemartz.lobbybalancer.configuration.ConfigEntries;
public final class ServerStatus {
public final class PingStatus {
private final String description;
private final int online, maximum;
private boolean outdated = true;
public ServerStatus(String description, int online, int maximum) {
public PingStatus(String description, int online, int maximum) {
this.description = description;
this.online = online;
this.maximum = maximum;
@ -24,6 +25,14 @@ public final class ServerStatus {
return maximum;
}
public void setOutdated(boolean outdated) {
this.outdated = outdated;
}
public boolean isOutdated() {
return outdated;
}
public boolean isAccessible() {
if (maximum == 0) {
return false;

View File

@ -14,12 +14,12 @@ public enum PingTactic {
ServerListPing utility = new ServerListPing();
@Override
public void ping(ServerInfo server, Callback<ServerStatus> callback, LobbyBalancer plugin) {
public void ping(ServerInfo server, Callback<PingStatus> callback, LobbyBalancer plugin) {
utility.setTimeout(ConfigEntries.SERVER_CHECK_TIMEOUT.get());
plugin.getProxy().getScheduler().runAsync(plugin, () -> {
try {
StatusResponse response = utility.ping(server.getAddress());
callback.done(new ServerStatus(
callback.done(new PingStatus(
response.getDescription().toLegacyText(),
response.getPlayers().getOnline(),
response.getPlayers().getMax()),
@ -33,11 +33,11 @@ public enum PingTactic {
GENERIC {
@Override
public void ping(ServerInfo server, Callback<ServerStatus> callback, LobbyBalancer plugin) {
public void ping(ServerInfo server, Callback<PingStatus> callback, LobbyBalancer plugin) {
try {
server.ping((ping, throwable) -> {
if (ping != null) {
callback.done(new ServerStatus(
callback.done(new PingStatus(
ping.getDescription(),
ping.getPlayers().getOnline(),
ping.getPlayers().getMax()
@ -52,5 +52,5 @@ public enum PingTactic {
}
};
public abstract void ping(ServerInfo server, Callback<ServerStatus> callback, LobbyBalancer plugin);
public abstract void ping(ServerInfo server, Callback<PingStatus> callback, LobbyBalancer plugin);
}

View File

@ -2,17 +2,19 @@ package me.jaimemartz.lobbybalancer.section;
import me.jaimemartz.faucet.Messager;
import me.jaimemartz.lobbybalancer.LobbyBalancer;
import me.jaimemartz.lobbybalancer.configuration.ConfigEntries;
import me.jaimemartz.lobbybalancer.connection.ConnectionIntent;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
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 java.util.List;
public class SectionCommand extends Command {
private transient final LobbyBalancer plugin;
private transient final ServerSection section;
private final LobbyBalancer plugin;
private final ServerSection section;
public SectionCommand(LobbyBalancer plugin, String name, String permission, List<String> aliases, ServerSection section) {
super(name, permission, aliases.stream().toArray(String[]::new));
@ -26,7 +28,25 @@ public class SectionCommand extends Command {
Messager msgr = new Messager(sender);
if (sender instanceof ProxiedPlayer) {
ProxiedPlayer player = (ProxiedPlayer) sender;
ConnectionIntent.connect(plugin, player, section);
if (args.length == 1) {
try {
int number = Integer.parseInt(args[0]);
if (number <= 0) {
msgr.send(ConfigEntries.INVALID_INPUT_MESSAGE.get());
} else if (number > section.getServers().size()) {
msgr.send(ConfigEntries.FAILURE_MESSAGE.get());
} else {
ServerInfo server = section.getSortedServers().get(number);
ConnectionIntent.direct(plugin, player, server);
}
} catch (NumberFormatException e) {
msgr.send(ConfigEntries.INVALID_INPUT_MESSAGE.get());
}
} else {
ConnectionIntent.simple(plugin, player, section);
}
} else {
msgr.send(ChatColor.RED + "This command can only be executed by a player");
}

View File

@ -3,13 +3,13 @@ package me.jaimemartz.lobbybalancer.section;
import com.google.gson.annotations.Expose;
import me.jaimemartz.lobbybalancer.LobbyBalancer;
import me.jaimemartz.lobbybalancer.connection.ProviderType;
import me.jaimemartz.lobbybalancer.utils.AlphanumComparator;
import me.jaimemartz.lobbybalancer.utils.FixedAdapter;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.config.Configuration;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher;
@ -18,6 +18,8 @@ import java.util.regex.Pattern;
public class ServerSection {
private final LobbyBalancer plugin;
private Configuration configuration;
private List<ServerInfo> sortedServers;
@Expose private final String name;
@Expose private boolean principal;
@Expose private int position;
@ -54,6 +56,8 @@ public class ServerSection {
}
public void preInit() {
checkInit();
if (configuration == null) {
throw new IllegalStateException("Tried to call an init method with null configuration section");
}
@ -106,6 +110,8 @@ public class ServerSection {
}
public void load() {
checkInit();
if (configuration == null) {
throw new IllegalStateException("Tried to call an init method with null configuration section");
}
@ -134,6 +140,8 @@ public class ServerSection {
}
public void postInit() {
checkInit();
if (configuration == null) {
throw new IllegalStateException("Tried to call an init method with null configuration section");
}
@ -211,7 +219,16 @@ public class ServerSection {
plugin.getProxy().getPluginManager().registerCommand(plugin, command);
}
this.setValid(true);
sortedServers = new ArrayList<>();
sortedServers.addAll(servers);
sortedServers.sort(new AlphanumComparator());
valid = true;
}
private void checkInit() {
if (!valid) return;
throw new IllegalStateException("Tried to init a section that is already valid");
}
public String getName() {
@ -246,6 +263,10 @@ public class ServerSection {
return servers;
}
public List<ServerInfo> getSortedServers() {
return sortedServers;
}
public ProviderType getProvider() {
return provider;
}
@ -302,6 +323,10 @@ public class ServerSection {
this.servers = servers;
}
public void setSortedServers(List<ServerInfo> sortedServers) {
this.sortedServers = sortedServers;
}
public void setProvider(ProviderType provider) {
this.provider = provider;
}

View File

@ -0,0 +1,132 @@
package me.jaimemartz.lobbybalancer.utils;
/*
* The Alphanum Algorithm is an improved sorting algorithm for strings
* containing numbers. Instead of sorting numbers in ASCII order like
* a standard sort, this algorithm sorts numbers in numeric order.
*
* The Alphanum Algorithm is discussed at http://www.DaveKoelle.com
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
import java.util.Comparator;
/**
* This is an updated version with enhancements made by Daniel Migowski,
* Andre Bogus, and David Koelle
*
* To convert to use Templates (Java 1.5+):
* - Change "implements Comparator" to "implements Comparator<String>"
* - Change "compare(Object o1, Object o2)" to "compare(String s1, String s2)"
* - Remove the type checking and casting in compare().
*
* To use this class:
* Use the static "sort" method from the java.util.Collections class:
* Collections.sort(your list, new AlphanumComparator());
*/
public class AlphanumComparator implements Comparator
{
private final boolean isDigit(char ch)
{
return ch >= 48 && ch <= 57;
}
/** Length of string is passed in for improved efficiency (only need to calculate it once) **/
private final String getChunk(String s, int slength, int marker)
{
StringBuilder chunk = new StringBuilder();
char c = s.charAt(marker);
chunk.append(c);
marker++;
if (isDigit(c))
{
while (marker < slength)
{
c = s.charAt(marker);
if (!isDigit(c))
break;
chunk.append(c);
marker++;
}
} else
{
while (marker < slength)
{
c = s.charAt(marker);
if (isDigit(c))
break;
chunk.append(c);
marker++;
}
}
return chunk.toString();
}
public int compare(Object o1, Object o2)
{
if (!(o1 instanceof String) || !(o2 instanceof String))
{
return 0;
}
String s1 = (String)o1;
String s2 = (String)o2;
int thisMarker = 0;
int thatMarker = 0;
int s1Length = s1.length();
int s2Length = s2.length();
while (thisMarker < s1Length && thatMarker < s2Length)
{
String thisChunk = getChunk(s1, s1Length, thisMarker);
thisMarker += thisChunk.length();
String thatChunk = getChunk(s2, s2Length, thatMarker);
thatMarker += thatChunk.length();
// If both chunks contain numeric characters, sort them numerically
int result = 0;
if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0)))
{
// Simple chunk comparison by length.
int thisChunkLength = thisChunk.length();
result = thisChunkLength - thatChunk.length();
// If equal, the first different number counts
if (result == 0)
{
for (int i = 0; i < thisChunkLength; i++)
{
result = thisChunk.charAt(i) - thatChunk.charAt(i);
if (result != 0)
{
return result;
}
}
}
} else
{
result = thisChunk.compareTo(thatChunk);
}
if (result != 0)
return result;
}
return s1Length - s2Length;
}
}

View File

@ -13,7 +13,7 @@ settings:
# Pings to the servers to see if they can be accessed or not
server-check:
# If this is disabled the players will connect to the first server available
# If this is disabled the players will simple to the first server available
enabled: true
# Use either CUSTOM or GENERIC, the first one generally works the best
@ -34,7 +34,7 @@ settings:
# The descriptions that mark a server as non accessible
marker-descs: ["Server is not accessible", "Gamemode has already started"]
# This will connect the player to a server of the parent of the section the player is kicked from
# This will simple the player to a server of the parent of the section the player is kicked from
reconnect-kick:
# If this is enabled the kick reasons must still match for this to work
enabled: true
@ -66,7 +66,7 @@ settings:
rules:
'section-from': 'section-to'
# This will connect the player to a server of the parent of the section the player is currently on
# This will simple the player to a server of the parent of the section the player is currently on
fallback-command:
# If this is disabled the command will not be registered
enabled: true
@ -132,8 +132,9 @@ settings:
messages:
connecting: '&aConnecting to {server}'
failure: '&cCould not find a server to get connected'
unavailable: '&cThis command cannot be executed on this server'
unknown: '&cCould not find a section with that name'
unknown-section: '&cCould not find a section with that name'
invalid-input: '&cThis is an invalid input type for this command'
unavailable-server: '&cThis command cannot be executed on this server'
kick: '&cYou have been kicked from &a{from} &cand you are being moved to &a{to}&c, reason: &a{reason}'
# Here you have an example of what you can do with the sections