/** Creates a new server. */
  public GlowServer(ServerConfig config) {
    this.config = config;
    // stuff based on selected config directory
    opsList = new UuidListFile(config.getFile("ops.json"));
    whitelist = new UuidListFile(config.getFile("whitelist.json"));
    nameBans = new GlowBanList(this, BanList.Type.NAME);
    ipBans = new GlowBanList(this, BanList.Type.IP);

    Bukkit.setServer(this);
    loadConfig();
  }
  /** Binds the query server to the address specified in the configuration. */
  private void bindQuery() {
    if (!config.getBoolean(ServerConfig.Key.QUERY_ENABLED)) {
      return;
    }

    SocketAddress address = getBindAddress(ServerConfig.Key.QUERY_PORT);
    queryServer = new QueryServer(this, config.getBoolean(ServerConfig.Key.QUERY_PLUGINS));

    logger.info("Binding query to address: " + address + "...");
    ChannelFuture future = queryServer.bind(address);
    Channel channel = future.awaitUninterruptibly().channel();
    if (!channel.isActive()) {
      logger.warning("Failed to bind query. Address already in use?");
    }
  }
  /** Binds the rcon server to the address specified in the configuration. */
  private void bindRcon() {
    if (!config.getBoolean(ServerConfig.Key.RCON_ENABLED)) {
      return;
    }

    SocketAddress address = getBindAddress(ServerConfig.Key.RCON_PORT);
    rconServer = new RconServer(this, config.getString(ServerConfig.Key.RCON_PASSWORD));

    logger.info("Binding rcon to address: " + address + "...");
    ChannelFuture future = rconServer.bind(address);
    Channel channel = future.awaitUninterruptibly().channel();
    if (!channel.isActive()) {
      logger.warning("Failed to bind rcon. Address already in use?");
    }
  }
  /**
   * Creates a new Server object.
   *
   * @param sqlDriver JDBC driver
   * @param dbURL JDBC connection url
   * @param dbLogin database login
   * @param dbPasswd database password
   */
  private Server(ServerConfig config) {
    Server.instance = this;
    this.connections = new ArrayList();
    this.services = new ArrayList();
    this.port = config.getPort();
    this.socket = null;
    this.dbLayer = null;

    try {
      dbLayer = DatabaseAbstractionLayer.createLayer(config);
      Logging.getLogger().finer("dbLayer   : " + dbLayer);

      this.store = new Store(config);
    } catch (Exception ex) {
      Logging.getLogger().severe("#Err > Unable to connect to the database : " + ex.getMessage());
      ex.printStackTrace();
      System.exit(1);
    }

    try {
      this.serverIp = InetAddress.getLocalHost().getHostAddress();
      this.socket = new ServerSocket(this.port);
    } catch (IOException e) {
      Logging.getLogger().severe("#Err > Unable to listen on the port " + port + ".");
      e.printStackTrace();
      System.exit(1);
    }

    loadInternalServices();
  }
  /** Loads all plugins, calling onLoad, &c. */
  private void loadPlugins() {
    // clear the map
    commandMap.clearCommands();
    commandMap.register("glowstone", new ColorCommand("colors"));
    commandMap.register("glowstone", new TellrawCommand());

    File folder = new File(config.getString(ServerConfig.Key.PLUGIN_FOLDER));
    if (!folder.isDirectory() && !folder.mkdirs()) {
      logger.log(Level.SEVERE, "Could not create plugins directory: " + folder);
    }

    // clear plugins and prepare to load
    pluginManager.clearPlugins();
    pluginManager.registerInterface(JavaPluginLoader.class);
    Plugin[] plugins = pluginManager.loadPlugins(folder);

    // call onLoad methods
    for (Plugin plugin : plugins) {
      try {
        plugin.onLoad();
      } catch (Exception ex) {
        logger.log(Level.SEVERE, "Error loading " + plugin.getDescription().getFullName(), ex);
      }
    }
  }
 /**
  * Get the default game difficulty defined in the config.
  *
  * @return The default difficulty.
  */
 public Difficulty getDifficulty() {
   try {
     return Difficulty.valueOf(config.getString(ServerConfig.Key.DIFFICULTY));
   } catch (IllegalArgumentException | NullPointerException e) {
     return Difficulty.NORMAL;
   }
 }
  /** Load the server configuration. */
  private void loadConfig() {
    config.load();

    // modifiable values
    spawnRadius = config.getInt(ServerConfig.Key.SPAWN_RADIUS);
    whitelistEnabled = config.getBoolean(ServerConfig.Key.WHITELIST);
    idleTimeout = config.getInt(ServerConfig.Key.PLAYER_IDLE_TIMEOUT);
    craftingManager.initialize();

    // special handling
    warnState = Warning.WarningState.value(config.getString(ServerConfig.Key.WARNING_STATE));
    try {
      defaultGameMode = GameMode.valueOf(config.getString(ServerConfig.Key.GAMEMODE));
    } catch (IllegalArgumentException | NullPointerException e) {
      defaultGameMode = GameMode.SURVIVAL;
    }

    // server icon
    defaultIcon = new GlowServerIcon();
    try {
      File file = config.getFile("server-icon.png");
      if (file.isFile()) {
        defaultIcon = new GlowServerIcon(file);
      }
    } catch (Exception e) {
      logger.log(Level.WARNING, "Failed to load server-icon.png", e);
    }
  }
 /**
  * Get the SocketAddress to bind to for a specified service.
  *
  * @param portKey The configuration key for the port to use.
  * @return The SocketAddress
  */
 private SocketAddress getBindAddress(ServerConfig.Key portKey) {
   String ip = getIp();
   int port = config.getInt(portKey);
   if (ip.length() == 0) {
     return new InetSocketAddress(port);
   } else {
     return new InetSocketAddress(ip, port);
   }
 }
  @Override
  public void configureDbConfig(com.avaje.ebean.config.ServerConfig dbConfig) {
    com.avaje.ebean.config.DataSourceConfig ds = new com.avaje.ebean.config.DataSourceConfig();
    ds.setDriver(config.getString(ServerConfig.Key.DB_DRIVER));
    ds.setUrl(config.getString(ServerConfig.Key.DB_URL));
    ds.setUsername(config.getString(ServerConfig.Key.DB_USERNAME));
    ds.setPassword(config.getString(ServerConfig.Key.DB_PASSWORD));
    ds.setIsolationLevel(
        com.avaje.ebeaninternal.server.lib.sql.TransactionIsolation.getLevel(
            config.getString(ServerConfig.Key.DB_ISOLATION)));

    if (ds.getDriver().contains("sqlite")) {
      dbConfig.setDatabasePlatform(new com.avaje.ebean.config.dbplatform.SQLitePlatform());
      dbConfig.getDatabasePlatform().getDbDdlSyntax().setIdentity("");
    }

    dbConfig.setDataSourceConfig(ds);
  }
 @Override
 public Map<String, String[]> getCommandAliases() {
   Map<String, String[]> aliases = new HashMap<>();
   ConfigurationSection section =
       config.getConfigFile(ServerConfig.Key.COMMANDS_FILE).getConfigurationSection("aliases");
   if (section == null) {
     return aliases;
   }
   for (String key : section.getKeys(false)) {
     List<String> list = section.getStringList(key);
     aliases.put(key, list.toArray(new String[list.size()]));
   }
   return aliases;
 }
  /**
   * Gets the default ChunkGenerator for the given environment and type.
   *
   * @return The ChunkGenerator.
   */
  private ChunkGenerator getGenerator(String name, Environment environment, WorldType type) {
    // find generator based on configuration
    ConfigurationSection worlds = config.getWorlds();
    if (worlds != null) {
      String genName = worlds.getString(name + ".generator", null);
      ChunkGenerator generator =
          WorldCreator.getGeneratorForName(name, genName, getConsoleSender());
      if (generator != null) {
        return generator;
      }
    }

    // find generator based on environment and world type
    if (environment == Environment.NETHER) {
      return new net.glowstone.generator.UndergroundGenerator();
    } else if (environment == Environment.THE_END) {
      return new net.glowstone.generator.CakeTownGenerator();
    } else {
      return new net.glowstone.generator.SurfaceGenerator();
    }
  }
 /**
  * Get whether to use color codes in Rcon responses.
  *
  * @return True if color codes will be present in Rcon responses
  */
 public boolean useRconColors() {
   return config.getBoolean(ServerConfig.Key.RCON_COLORS);
 }
 /**
  * Get whether parsing of data provided by a proxy is enabled.
  *
  * @return True if a proxy is providing data to use.
  */
 public boolean getProxySupport() {
   return config.getBoolean(ServerConfig.Key.PROXY_SUPPORT);
 }
 /**
  * Get whether worlds should keep their spawns loaded by default.
  *
  * @return Whether to keep spawns loaded by default.
  */
 public boolean keepSpawnLoaded() {
   return config.getBoolean(ServerConfig.Key.PERSIST_SPAWN);
 }
 @Override
 public boolean useExactLoginLocation() {
   return config.getBoolean(ServerConfig.Key.EXACT_LOGIN_LOCATION);
 }
 /**
  * Get the threshold to use for network compression defined in the config.
  *
  * @return The compression threshold, or -1 for no compression.
  */
 public int getCompressionThreshold() {
   return config.getInt(ServerConfig.Key.COMPRESSION_THRESHOLD);
 }
 @Override
 public boolean getAllowFlight() {
   return config.getBoolean(ServerConfig.Key.ALLOW_FLIGHT);
 }
 /**
  * Get whether achievements should be announced.
  *
  * @return True if achievements should be announced in chat.
  */
 public boolean getAnnounceAchievements() {
   return config.getBoolean(ServerConfig.Key.ANNOUNCE_ACHIEVEMENTS);
 }
 @Override
 public int getMonsterSpawnLimit() {
   return config.getInt(ServerConfig.Key.MONSTER_LIMIT);
 }
 @Override
 public boolean isHardcore() {
   return config.getBoolean(ServerConfig.Key.HARDCORE);
 }
 @Override
 public int getWaterAnimalSpawnLimit() {
   return config.getInt(ServerConfig.Key.WATER_ANIMAL_LIMIT);
 }
 @Override
 public int getAmbientSpawnLimit() {
   return config.getInt(ServerConfig.Key.AMBIENT_LIMIT);
 }
  /** Starts this server. */
  public void start() {
    // Determine console mode and start reading input
    consoleManager.startConsole(config.getBoolean(ServerConfig.Key.USE_JLINE));
    consoleManager.startFile(config.getString(ServerConfig.Key.LOG_FILE));

    if (getProxySupport()) {
      if (getOnlineMode()) {
        logger.warning("Proxy support is enabled, but online mode is enabled.");
      } else {
        logger.info("Proxy support is enabled.");
      }
    } else if (!getOnlineMode()) {
      logger.warning(
          "The server is running in offline mode! Only do this if you know what you're doing.");
    }

    // Load player lists
    opsList.load();
    whitelist.load();
    nameBans.load();
    ipBans.load();

    // DRAGONET-Start
    this.dragonetServer = new DragonetServer(this);
    this.dragonetServer.initialize();
    // DRAGONET-End

    // Start loading plugins
    loadPlugins();
    enablePlugins(PluginLoadOrder.STARTUP);

    // Create worlds
    String name = config.getString(ServerConfig.Key.LEVEL_NAME);
    String seedString = config.getString(ServerConfig.Key.LEVEL_SEED);
    boolean structs = getGenerateStructures();
    WorldType type = WorldType.getByName(getWorldType());
    if (type == null) {
      type = WorldType.NORMAL;
    }

    long seed = new Random().nextLong();
    if (!seedString.isEmpty()) {
      try {
        long parsed = Long.parseLong(seedString);
        if (parsed != 0) {
          seed = parsed;
        }
      } catch (NumberFormatException ex) {
        seed = seedString.hashCode();
      }
    }

    createWorld(
        WorldCreator.name(name)
            .environment(Environment.NORMAL)
            .seed(seed)
            .type(type)
            .generateStructures(structs));
    if (getAllowNether()) {
      createWorld(
          WorldCreator.name(name + "_nether")
              .environment(Environment.NETHER)
              .seed(seed)
              .type(type)
              .generateStructures(structs));
    }
    if (getAllowEnd()) {
      createWorld(
          WorldCreator.name(name + "_the_end")
              .environment(Environment.THE_END)
              .seed(seed)
              .type(type)
              .generateStructures(structs));
    }

    // Finish loading plugins
    enablePlugins(PluginLoadOrder.POSTWORLD);
    commandMap.registerServerAliases();
    scheduler.start();
  }
 @Override
 public int getTicksPerAnimalSpawns() {
   return config.getInt(ServerConfig.Key.ANIMAL_TICKS);
 }
 /**
  * Get the resource pack url for this server, or {@code null} if not set.
  *
  * @return The url of the resource pack to use, or {@code null}
  */
 public String getResourcePackURL() {
   return config.getString(ServerConfig.Key.RESOURCE_PACK);
 }
  /**
   * Enable all plugins of the given load order type.
   *
   * @param type The type of plugin to enable.
   */
  private void enablePlugins(PluginLoadOrder type) {
    if (type == PluginLoadOrder.STARTUP) {
      helpMap.clear();
      helpMap.initializeGeneralTopics();
    }

    // load all the plugins
    Plugin[] plugins = pluginManager.getPlugins();
    for (Plugin plugin : plugins) {
      if (!plugin.isEnabled() && plugin.getDescription().getLoad() == type) {
        List<Permission> perms = plugin.getDescription().getPermissions();
        for (Permission perm : perms) {
          try {
            pluginManager.addPermission(perm);
          } catch (IllegalArgumentException ex) {
            getLogger()
                .log(
                    Level.WARNING,
                    "Plugin "
                        + plugin.getDescription().getFullName()
                        + " tried to register permission '"
                        + perm.getName()
                        + "' but it's already registered",
                    ex);
          }
        }

        try {
          pluginManager.enablePlugin(plugin);
        } catch (Throwable ex) {
          logger.log(Level.SEVERE, "Error loading " + plugin.getDescription().getFullName(), ex);
        }
      }
    }

    if (type == PluginLoadOrder.POSTWORLD) {
      commandMap.setFallbackCommands();
      commandMap.registerServerAliases();
      DefaultPermissions.registerCorePermissions();
      helpMap.initializeCommands();

      // load permissions.yml
      ConfigurationSection permConfig = config.getConfigFile(ServerConfig.Key.PERMISSIONS_FILE);
      List<Permission> perms =
          Permission.loadPermissions(
              permConfig.getValues(false),
              "Permission node '%s' in permissions config is invalid",
              PermissionDefault.OP);
      for (Permission perm : perms) {
        try {
          pluginManager.addPermission(perm);
        } catch (IllegalArgumentException ex) {
          getLogger()
              .log(
                  Level.WARNING,
                  "Permission config tried to register '"
                      + perm.getName()
                      + "' but it's already registered",
                  ex);
        }
      }
    }
  }
 /**
  * Get the resource pack hash for this server, or the empty string if not set.
  *
  * @return The hash of the resource pack, or the empty string
  */
 public String getResourcePackHash() {
   return config.getString(ServerConfig.Key.RESOURCE_PACK_HASH);
 }
 /** Returns the folder where configuration files are stored */
 public File getConfigDir() {
   return config.getDirectory();
 }
 @Override
 public int getTicksPerMonsterSpawns() {
   return config.getInt(ServerConfig.Key.MONSTER_TICKS);
 }
 @Override
 public String getShutdownMessage() {
   return config.getString(ServerConfig.Key.SHUTDOWN_MESSAGE);
 }