private boolean validateFolder(File file, PluginType pluginType, String version) {
    if (!file.exists()) {
      getLogger().info(file.getPath() + " does not exist! Cannot load " + pluginType.name());
      return true;
    }

    if (!(file.isDirectory()) || file.listFiles() == null || file.listFiles().length < 1) {
      getLogger()
          .info(pluginType.name() + " " + version + " has either no files or has an invalid setup");
      return true;
    }

    return false;
  }
  @Override
  public void onEnable() {
    MineCloud.environmentSetup();

    mongo = MineCloud.instance().mongo();
    redis = MineCloud.instance().redis();

    redis.addChannel(
        SimpleRedisChannel.create("server-start-notif", redis)
            .addCallback(
                (message) ->
                    getProxy()
                        .getScheduler()
                        .schedule(
                            this,
                            () -> {
                              if (message.type() != MessageType.BINARY) {
                                return;
                              }

                              try {
                                MessageInputStream stream = message.contents();

                                Server server =
                                    mongo.repositoryBy(Server.class).findFirst(stream.readString());

                                addServer(server);
                              } catch (IOException ignored) {
                              }
                            },
                            1,
                            TimeUnit.SECONDS)));

    redis.addChannel(
        SimpleRedisChannel.create("server-shutdown-notif", redis)
            .addCallback(
                (message) -> {
                  if (message.type() != MessageType.BINARY) {
                    return;
                  }

                  MessageInputStream stream = message.contents();

                  removeServer(stream.readString());
                }));

    redis.addChannel(
        SimpleRedisChannel.create("teleport", redis)
            .addCallback(
                (message) -> {
                  if (message.type() != MessageType.BINARY) {
                    return;
                  }

                  MessageInputStream stream = message.contents();
                  ProxiedPlayer player = getProxy().getPlayer(stream.readString());

                  if (player == null) {
                    return;
                  }

                  String name = stream.readString();
                  ServerInfo info = getProxy().getServerInfo(name);

                  if (info == null) {
                    ServerRepository repository = mongo.repositoryBy(Server.class);
                    Server server = repository.findOne("_id", name);

                    if (server != null) {
                      addServer(server);
                      info = getProxy().getServerInfo(name);
                    }
                  }

                  player.connect(info);
                }));

    redis.addChannel(
        SimpleRedisChannel.create("teleport-type", redis)
            .addCallback(
                (message) -> {
                  if (message.type() != MessageType.BINARY) {
                    return;
                  }

                  MessageInputStream stream = message.contents();
                  ProxiedPlayer player = getProxy().getPlayer(stream.readString());

                  if (player == null) {
                    return;
                  }

                  ServerType type =
                      mongo.repositoryBy(ServerType.class).findFirst(stream.readString());

                  if (type == null) {
                    getLogger()
                        .log(Level.SEVERE, "Received teleport message with invalid server type");
                    return;
                  }

                  ServerRepository repository = mongo.repositoryBy(Server.class);
                  List<Server> servers =
                      repository
                          .find(
                              repository
                                  .createQuery()
                                  .field("network")
                                  .equal(bungee().network())
                                  .field("type")
                                  .equal(type)
                                  .field("port")
                                  .notEqual(-1)
                                  .field("ramUsage")
                                  .notEqual(-1))
                          .asList();

                  Collections.sort(
                      servers, (a, b) -> a.onlinePlayers().size() - b.onlinePlayers().size());

                  Server server = servers.get(0);
                  ServerInfo info = getProxy().getServerInfo(server.name());

                  if (info == null) {
                    getLogger()
                        .warning("Cannot find " + server.name() + " in ServerInfo store, adding.");
                    addServer(server);
                    info = getProxy().getServerInfo(server.name());
                  }

                  player.connect(info);
                }));

    getProxy()
        .getScheduler()
        .schedule(
            this,
            () ->
                getProxy()
                    .getScheduler()
                    .runAsync(
                        this,
                        () -> {
                          Bungee bungee = bungee();

                          if (bungee != null) {
                            return;
                          }

                          getLogger().info("Bungee removed from database, going down...");
                          getProxy().stop(); // bye bye
                        }),
            2,
            2,
            TimeUnit.SECONDS);

    BungeeType type = bungee().type();

    File nContainer = new File("nplugins/");
    nContainer.mkdirs();

    type.plugins()
        .forEach(
            (plugin) -> {
              String version = plugin.version();
              PluginType pluginType = plugin.type();
              File pluginsContainer =
                  new File("/mnt/minecloud/plugins/", pluginType.name() + "/" + version);
              List<File> plugins = new ArrayList<>();

              getLogger().info("Loading " + pluginType.name() + "...");

              if (validateFolder(pluginsContainer, pluginType, version)) return;

              for (File f : pluginsContainer.listFiles()) {
                if (f.isDirectory()) continue; // ignore directories
                File pl = new File(nContainer, f.getName());

                try {
                  Files.copy(f, pl);
                } catch (IOException ex) {
                  getLogger()
                      .log(
                          Level.SEVERE,
                          "Could not load " + pluginType.name() + ", printing stacktrace...");
                  ex.printStackTrace();
                  return;
                }

                plugins.add(pl);
              }

              File configs =
                  new File(
                      "/mnt/minecloud/configs/",
                      pluginType.name()
                          + "/"
                          + (plugin.config() == null ? version : plugin.config()));
              File configContainer = new File(nContainer, pluginType.name());

              if (!validateFolder(configs, pluginType, version))
                copyFolder(configs, configContainer);
            });

    getProxy()
        .getScheduler()
        .schedule(
            this,
            () -> {
              ServerRepository repository = mongo.repositoryBy(Server.class);
              List<Server> servers =
                  repository
                      .find(repository.createQuery().field("network").equal(bungee().network()))
                      .asList();

              servers.removeIf((s) -> s.port() == -1);
              servers.forEach(this::addServer);

              getProxy().setReconnectHandler(new ReconnectHandler(this));
              getProxy().getPluginManager().registerListener(this, new MineCloudListener(this));

              // release plugin manager lock
              try {
                Field f = PluginManager.class.getDeclaredField("toLoad");

                f.setAccessible(true);
                f.set(getProxy().getPluginManager(), new HashMap<>());
              } catch (NoSuchFieldException | IllegalAccessException ignored) {
              }

              getProxy().getPluginManager().detectPlugins(nContainer);
              getProxy().getPluginManager().loadPlugins();
              getProxy()
                  .getPluginManager()
                  .getPlugins()
                  .stream()
                  .filter((p) -> !p.getDescription().getName().equals("MineCloud-Bungee"))
                  .forEach(Plugin::onEnable);
            },
            0,
            TimeUnit.SECONDS);
  }