@Override
  public void onDisable() {
    disable = true;
    tmetrics.stop();

    ttt.disableItemThread.interrupt();
    ttt.entityRemoveThread.interrupt();
    ttt.gemArmorThread.interrupt();
    ttt.worldScrubThread.interrupt();
    ttt.saveThread.interrupt();
    // ttt.limitFlyThread.interrupt();

    try {
      Thread.sleep(1500);
    } catch (InterruptedException e) {
    } // Sleep for 1.5 seconds to allow the savethread to save.

    TRLogger.saveLogs();
    TRLogFilter.disable();
    Log.deinit();
    FileLog.closeAll();

    log.info("TekkitRestrict v " + version.fullVer + " disabled!");
  }
  @Override
  public void onLoad() {
    instance = this; // Set the instance
    log = getLogger(); // Set the logger

    version =
        new TRVersion(
            getDescription().getVersion().equals("1.2") ? "1.20" : getDescription().getVersion());
    Log.init();

    // #################### load Config ####################
    saveDefaultConfig(false); // Copy config files

    config = this.getConfigx(); // Load the configuration files
    double configVer = config.getDouble(ConfigFile.General, "ConfigVersion", 0.9);
    if (configVer < 1.1) UpdateConfigFiles.v09(); // 0 --> newest
    else if (configVer < 1.5) { // Upgrade to 1.8
      AdvancedConfig.upgradeFile();
      DatabaseConfig.upgradeFile();
      GeneralConfig.upgradeFile();
      HackDupeConfig.upgradeOldHackFile();
      ModModificationsConfig.upgradeFile();
      SafeZonesConfig.upgradeFile();
      TPerformanceConfig.upgradeFile();
      LoggingConfig.upgradeFile();
      if (linkEEPatch()) EEPatchConfig.upgradeFile();
      reloadConfig();
    } else if (configVer < 1.6) { // Upgrade to 1.8
      GeneralConfig.upgradeFile();
      DatabaseConfig.upgradeFile();
      LoggingConfig.upgradeFile();
      if (linkEEPatch()) EEPatchConfig.upgradeFile();
      reloadConfig();
    } else if (configVer < 1.7) { // upgrade to 1.8
      GeneralConfig.upgradeFile();
      DatabaseConfig.upgradeFile();
      LoggingConfig.upgradeFile();
      if (linkEEPatch()) EEPatchConfig.upgradeFile();
      reloadConfig();
    } else if (configVer < 1.8) { // upgrade to 1.8
      GeneralConfig.upgradeFile();
      DatabaseConfig.upgradeFile();
      reloadConfig();
    }

    try { // Load all settings
      load(); // TODO loading eepatch
    } catch (Exception ex) {
      Warning.load("An error occurred: Unable to load settings!", true);
      Log.Exception(ex, true);
    }
    // #####################################################

    // ##################### load SQL ######################

    log.info("[DB] Loading Database...");
    if (!TRDB.loadDB()) {
      Warning.dbAndLoad("[DB] Failed to load Database!", true);
    } else {
      if (dbtype == DBType.SQLite) {
        if (TRDB.initSQLite()) log.info("[SQLite] SQLite Database loaded!");
        else {
          Warning.dbAndLoad("[SQLite] Failed to load SQLite Database!", true);
        }
      } else if (dbtype == DBType.MySQL) {
        if (TRDB.initMySQL()) {
          log.info("[MySQL] Database connection established!");
        } else {
          Warning.dbAndLoad("[MySQL] Failed to connect to MySQL Database!", true);
        }
      } else {
        Warning.dbAndLoad("[DB] Unknown Database type set!", true);
      }
    }
    // #####################################################

    // ###################### RPTimer ######################
    if (config.getBoolean2(ConfigFile.General, "UseAutoRPTimer", false)) {
      try {
        double value = config.getDouble(ConfigFile.ModModifications, "RPTimerMin", 0.2d);
        int ticks = (int) Math.round((value - 0.1d) * 20d);
        RedPowerLogic.minInterval = ticks; // set minimum interval for logic timers...
        log.info("Set the RedPower Timer Min interval to " + value + " seconds.");
      } catch (Exception e) {
        Warning.load("Setting the RedPower Timer failed!", false);
      }
    }
    // #####################################################

    // ###################### Patch CC #####################
    if (config.getBoolean2(ConfigFile.General, "PatchComputerCraft", true)) {
      PatchCC.start();
    }
    // #####################################################

    // BlockBreaker anti-dupe
    try {
      ArrayList<Block> miningLaser = new ArrayList<Block>();

      for (Block block : EntityMiningLaser.unmineableBlocks) {
        miningLaser.add(block);
      }
      miningLaser.add(Block.byId[194]);
      EntityMiningLaser.unmineableBlocks = miningLaser.toArray(new Block[miningLaser.size()]);
      log.fine("Patched Mining Laser + Auto Crafting Table MK II dupe.");
    } catch (Exception ex) {
      Warning.load("Unable to patch Mining Laser + Auto Crafting Table MK II dupe!", false);
    }

    try {
      RedPowerMachine.breakerBlacklist.add(Integer.valueOf(-1 << 15 | 194));

      RedPowerMachine.deployerBlacklist.add(Integer.valueOf(0 << 15 | 6362)); // REP
      RedPowerMachine.deployerBlacklist.add(Integer.valueOf(0 << 15 | 6359)); // Wireless sniffer
      RedPowerMachine.deployerBlacklist.add(Integer.valueOf(0 << 15 | 6363)); // Private sniffer
      RedPowerMachine.deployerBlacklist.add(Integer.valueOf(0 << 15 | 27562)); // Alcbag
      RedPowerMachine.deployerBlacklist.add(Integer.valueOf(0 << 15 | 27585)); // Divining ROd
      RedPowerMachine.deployerBlacklist.add(Integer.valueOf(0 << 15 | 30122)); // Cropnalyser
      RedPowerMachine.deployerBlacklist.add(Integer.valueOf(0 << 15 | 30104)); // Debug item

      RedPowerMachine.deployerBlacklist.add(Integer.valueOf(0 << 15 | 27592)); // transtablet
      RedPowerMachine.deployerBlacklist.add(Integer.valueOf(0 << 15 | 7493)); // Ender pouch
      log.fine("Patched BlockBreaker + Auto Crafting Table MK II dupe.");
      log.fine("Patched most Deployer Crash Bugs.");
    } catch (Exception ex) {
      Warning.load("Unable to patch BlockBreaker + Auto Crafting Table MK II dupe!", false);
      Warning.load("Unable to patch Deployer Crash Bugs!", false);
    }

    try {
      Ic2Recipes.addMaceratorRecipe(new ItemStack(135, 1, 2), new ItemStack(30254, 4, 0));
      Ic2Recipes.addMaceratorRecipe(new ItemStack(135, 1, 3), new ItemStack(30255, 4, 0));
      log.fine("Added Missing Nether Ores recipes.");
    } catch (Exception ex) {
      Warning.load("Unable to add missing Nether Ore recipes.", false);
    }
  }
  @Override
  public void onEnable() {
    ttt = new TRThread();
    try {
      Assigner.assign(); // Register the required listeners
    } catch (Exception ex) {
      Warning.load("A severe error occurred: Unable to start listeners!", true);
      Log.Exception(ex, true);
    }

    TRSafeZone.init();

    TRLimiter.init();

    getCommand("tekkitrestrict").setExecutor(new TRCommandTR());
    getCommand("openalc").setExecutor(new TRCommandAlc());
    getCommand("tpic").setExecutor(new TRCommandTPIC());
    getCommand("checklimits").setExecutor(new TRCommandCheck());

    // determine if EE2 is enabled by using pluginmanager
    PluginManager pm = this.getServer().getPluginManager();

    tekkitrestrict.EEEnabled = pm.isPluginEnabled("mod_EE");

    try {
      if (pm.isPluginEnabled("PermissionsEx")) {
        TRPermHandler.permEx = ru.tehkode.permissions.bukkit.PermissionsEx.getPermissionManager();
        log.info("PEX is enabled!");
      }
    } catch (Exception ex) {
      log.info("Linking with Pex Failed!");
      // Was not able to load permissionsEx
    }

    try {
      ttt.init();
    } catch (Exception ex) {
      Warning.loadWarnings.add("An error occurred: Unable to start threads!");
      Log.Exception(ex, true);
    }

    try {
      initHeartBeat();
    } catch (Exception ex) {
      Warning.load("An error occurred: Unable to initiate Limiter Manager correctly!", false);
      Log.Exception(ex, false);
    }

    if (linkEEPatch()) {
      boolean success = true;
      try {
        Assigner.assignEEPatch();
      } catch (Exception ex) {
        success = false;
      }

      if (success) log.info("Linked with EEPatch for extended functionality!");
      else Warning.other("Linking with EEPatch Failed!", true);

    } else {
      log.info("EEPatch is not available. Extended EE integration disabled.");
    }

    Bukkit.getScheduler()
        .scheduleAsyncDelayedTask(
            this,
            new Runnable() {
              public void run() {
                if (config.getBoolean2(ConfigFile.General, "Auto-Update", true)) {
                  // updater = new Updater_Old(this, "tekkit-restrict", this.getFile(),
                  // Updater_Old.UpdateType.DEFAULT, true);
                  updater2 =
                      new Updater(
                          tekkitrestrict.this,
                          44061,
                          tekkitrestrict.this.getFile(),
                          Updater.UpdateType.DEFAULT,
                          true);
                } else if (config.getBoolean2(
                    ConfigFile.General, "CheckForUpdateOnStartup", true)) {
                  // updater = new Updater_Old(this, "tekkit-restrict", this.getFile(),
                  // Updater_Old.UpdateType.NO_DOWNLOAD, true);
                  updater2 =
                      new Updater(
                          tekkitrestrict.this,
                          44061,
                          tekkitrestrict.this.getFile(),
                          Updater.UpdateType.NO_DOWNLOAD,
                          true);
                  // if (updater.getResult() == UpdateResult.UPDATE_AVAILABLE)
                  // log.info(ChatColor.GREEN + "There is an update available: " +
                  // updater.getLatestVersionString() + ". Use /tr admin update ingame to update.");
                  if (updater2.getResult() == Updater.UpdateResult.UPDATE_AVAILABLE)
                    log.info(
                        ChatColor.GREEN
                            + "There is an update available: "
                            + updater2.getLatestName()
                            + ". Use /tr admin update ingame to update.");
                }
              }
            });

    // ##################### Log Filter ####################
    if (config.getBoolean2(ConfigFile.Logging, "FilterLogs", true)
        || config.getBoolean2(ConfigFile.Logging, "SplitLogs", true)) {
      Enumeration<String> cc = LogManager.getLogManager().getLoggerNames();
      filter = new TRLogFilter();
      while (cc.hasMoreElements()) {
        Logger.getLogger(cc.nextElement()).setFilter(filter);
      }
    }
    // #####################################################

    initMetrics();
    tmetrics =
        new TMetrics(this, config.getBoolean2(ConfigFile.General, "ShowTMetricsWarnings", true));

    if (config.getBoolean2(ConfigFile.General, "UseTMetrics", true)) {
      tmetrics.start();
    }

    Bukkit.getScheduler()
        .scheduleSyncDelayedTask(
            this,
            new Runnable() {
              @Override
              public void run() {
                if (!Warning.loadWarnings.isEmpty()) {
                  log.warning("There were some warnings while loading TekkitRestrict!");
                  log.warning(
                      "Use /tr warnings load to view them again (in case you missed them).");
                } else if (!Warning.dbWarnings.isEmpty()) {
                  log.warning("There were some database warnings while loading TekkitRestrict!");
                  log.warning("Use /tr warnings db to view them again (in case you missed them).");
                }
              }
            });

    log.info("TekkitRestrict v" + version.fullVer + " Enabled!");
  }