/* * This file is part of Libelula Minecraft Edition Project. * * Libelula Minecraft Edition is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Libelula Minecraft Edition is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Libelula Minecraft Edition. * If not, see <http://www.gnu.org/licenses/>. * */ package me.libelula.networkmanager; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.net.InetSocketAddress; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.TreeMap; import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import java.util.logging.Logger; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; /** * * @author Diego D'Onofrio <ddonofrio@member.fsf.org> */ public class ServerManager { private final Main plugin; private final TreeMap<String, Server> servers; private final TreeMap<String, String> aliasServerName; private final List<InetSocketAddress> addresses; private final ReentrantLock _servers_mutex; public class Server { private final InetSocketAddress address; private final String networkName; private final String name; private final String alias; public Server(InetSocketAddress address, String network, String name, String alias) { this.address = address; this.networkName = network; this.name = name; this.alias = alias; } public String getName() { return name; } public String getNetwork() { return networkName; } public InetSocketAddress getAddress() { return address; } public String getServerId() { return networkName + "." + name; } public void sendMessage(String message) { plugin.cm.sendMessage(message, address); } } public ServerManager(Main plugin) { this.plugin = plugin; this.servers = new TreeMap<>(); this.aliasServerName = new TreeMap<>(); this._servers_mutex = new ReentrantLock(true); addresses = new ArrayList<>(); } public String getServerId() { return plugin.getConfig().getString("network-name") + "." + plugin.getConfig().getString("server-name"); } public InetSocketAddress getInetSocketAddress() { return new InetSocketAddress("localhost", plugin.getServer().getPort()); } public void load() { _servers_mutex.lock(); try { addresses.clear(); servers.clear(); aliasServerName.clear(); YamlConfiguration serversConfig = new YamlConfiguration(); File configCache = new File(plugin.getDataFolder(), "netcache.yml"); try { serversConfig.loadFromString(plugin.cm.getSting(new URL(plugin.getConfig().getString("source-uri")))); try { serversConfig.save(configCache); } catch (IOException ex) { Logger.getLogger(ServerManager.class.getName()).log(Level.SEVERE, null, ex); } } catch (Exception ex) { try { if (configCache.exists()) { serversConfig.load(configCache); plugin.getLogger().warning("Unable to read remote file. Using cache."); } else { plugin.getLogger().severe(ex.getMessage()); plugin.getLogger().severe("There is no local cache and network global file is unreachable."); } } catch (IOException | InvalidConfigurationException ex1) { Logger.getLogger(ServerManager.class.getName()).log(Level.SEVERE, null, ex1); } } boolean foundMySelf = false; for (String remoteNetworkName : serversConfig.getKeys(false)) { plugin.getLogger().info("Debug: " + remoteNetworkName); ConfigurationSection netSection = serversConfig.getConfigurationSection(remoteNetworkName); for (String remoteServerName : netSection.getKeys(false)) { String remoteServerID = remoteNetworkName + "." + remoteServerName; String addressString[] = serversConfig.getString(remoteServerID + "." + "address").split(":"); String alias = serversConfig.getString(remoteServerID + "." + "alias"); InetSocketAddress address = new InetSocketAddress(addressString[0], Integer.parseInt(addressString[1])); if (remoteServerID.equals(getServerId())) { foundMySelf = true; if (address.getPort() == getInetSocketAddress().getPort()) { address = getInetSocketAddress(); } else { plugin.getLogger().warning("Invalid port configuration on global configuration file!"); } } else { addresses.add(address); } Server remoteServer = new Server(address, remoteNetworkName, remoteServerName, alias); servers.put(remoteServerID, remoteServer); if (alias != null) { aliasServerName.put(alias, remoteServerName); } } } if (!foundMySelf) { plugin.getLogger().warning("Local server is not configured on global configuration."); } plugin.getLogger().log(Level.INFO, "{0} servers loaded.", servers.size()); } finally { _servers_mutex.unlock(); } } public Server getServer(String serverId) { return servers.get(serverId); } public Server getThisServer() { return getServer(getServerId()); } public List<InetSocketAddress> getAddresses() { return addresses; } public void showServerListTo(final CommandSender cs) { Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { @Override public void run() { plugin.pm.sendSyncMessage(cs, ChatColor.GOLD + "Para saltar a los distintos universos escribe: /universo y el nombre de un universo. Los posibles universos son:"); for (String serverName : aliasServerName.keySet()) { plugin.pm.sendSyncMessage(cs, ChatColor.GOLD + " * " + serverName); } } }); } public void tryToJump(final CommandSender cs, final String givenServerName) { Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { @Override public void run() { Player player; if (cs instanceof Player) { player = (Player) cs; } else { return; } String resolvedServer = null; for (String serverName : aliasServerName.keySet()) { if (serverName.equalsIgnoreCase(givenServerName)) { resolvedServer = serverName; break; } } if (resolvedServer != null) { plugin.pm.sendSyncMessage(player, ChatColor.translateAlternateColorCodes('&', "&1[&6Libelula &eNetwork&1] &eLlevándote a " + resolvedServer + "...")); plugin.teleportToServer(player, resolvedServer); } else { if (player.hasPermission("lnm.jump-to-hide")) { plugin.pm.sendSyncMessage(player, ChatColor.RED + "Ese universo no está en la lista."); player.sendMessage(ChatColor.GOLD + "Tienes permisos para saltar a universos no listados, tratando de llevarte..."); plugin.teleportToServer(player, givenServerName); } else { plugin.pm.sendSyncMessage(player, ChatColor.RED + "Ese universo no existe, escribe /universo para ver la lista."); } } } }); } public void runCommandOnNetwork(final CommandSender cs, final String command) { Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { @Override public void run() { String ownNetwork = getThisServer().networkName; for (Server server : servers.values()) { if (server.networkName.equals(ownNetwork)) { if (server.getName().equals(getThisServer().getName())) { continue; } runRemoteCommand(server.getName(), cs, command); } } Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), command); } }); } public void runRemoteCommand(String serverName, CommandSender cs, String command) { String[] args = {serverName, cs.getName(), command}; Server server = servers.get(serverName); if (server != null) { server.sendMessage(plugin.cm.formatMessage(CommunicationManager.MessageType.RUN_COMMAND, args)); } } }