AuraBanBase.java

package team.aura_dev.auraban.platform.common;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import lombok.Getter;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import team.aura_dev.auraban.api.AuraBanApi;
import team.aura_dev.auraban.platform.common.config.ConfigLoader;
import team.aura_dev.auraban.platform.common.dependency.RuntimeDependencies;
import team.aura_dev.auraban.platform.common.player.PlayerManagerCommon;
import team.aura_dev.auraban.platform.common.punishment.PunishmentManagerCommon;
import team.aura_dev.auraban.platform.common.storage.StorageEngine;
import team.aura_dev.auraban.platform.common.storage.StorageEngineData;
import team.aura_dev.lib.multiplatformcore.DependencyClassLoader;
import team.aura_dev.lib.multiplatformcore.dependency.RuntimeDependency;
import team.aura_dev.lib.multiplatformcore.download.DependencyDownloader;

@SuppressFBWarnings(
    value = {"JLM_JSR166_UTILCONCURRENT_MONITORENTER", "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"},
    justification = "Code is generated by lombok which means I don't have any influence on it.")
public abstract class AuraBanBase implements AuraBanApi, AuraBanBaseBootstrap {
  public static final Logger logger = LoggerFactory.getLogger(NAME);

  @Getter private static AuraBanBase instance = null;

  @Getter protected PlayerManagerCommon playerManager;
  @Getter protected PunishmentManagerCommon punishmentManager;

  @Getter protected final DependencyClassLoader classLoader;
  @Getter protected final Path configDir;
  @Getter protected final Path libsDir;
  @Getter protected final DependencyDownloader dependencyDownloader;

  @Getter(lazy = true)
  private final List<String> asciiBanner = generateAsciiBanner();

  protected ConfigLoader configLoader;
  protected StorageEngineData storageEngineData;
  protected StorageEngine storageEngine;

  protected AuraBanBase(DependencyClassLoader classLoader, Path configDir) {
    if (instance != null) {
      throw new IllegalStateException("AuraBan has already been initialized!");
    }

    instance = this;

    this.classLoader = classLoader;
    this.configDir = configDir;
    this.libsDir = configDir.resolve("libs");
    this.dependencyDownloader = new DependencyDownloader(classLoader, libsDir);
  }

  public abstract String getBasePlatform();

  public abstract String getPlatformVariant();

  public String getFullPlatform() {
    return getBasePlatform() + " - " + getPlatformVariant();
  }

  public Path getConfigFile() {
    return getConfigDir().resolve(ID + ".conf");
  }

  public Collection<RuntimeDependency> getEarlyDependencies() {
    final List<RuntimeDependency> dependencies = new LinkedList<>();

    // We need Configurate for the config
    dependencies.add(RuntimeDependencies.CONFIGURATE_HOCON);

    // We don't need to download dependencies already present
    dependencies.removeAll(getPlatformDependencies());

    return dependencies;
  }

  public Collection<RuntimeDependency> getDependencies() {
    final List<RuntimeDependency> dependencies = new LinkedList<>();

    // We need all dependencies of the storage type
    dependencies.addAll(storageEngineData.getRequiredRuntimeDependencies());
    // We need caffeine as a loading cache in several classes
    dependencies.add(RuntimeDependencies.CAFFEINE);

    // We don't need to download dependencies already present
    dependencies.removeAll(getPlatformDependencies());

    return dependencies;
  }

  /**
   * This method returns a {@link Collection} of all the dependencies that are already present on
   * the target platform.<br>
   * This allows making sure that they are not downloaded unnecessarily.
   *
   * @return a {@link Collection} of already present dependencies
   */
  public Collection<RuntimeDependency> getPlatformDependencies() {
    return Collections.emptyList();
  }

  protected abstract PlayerManagerCommon generatePlayerManager();

  protected PunishmentManagerCommon generatePunishmentManager() {
    return new PunishmentManagerCommon();
  }

  protected abstract void registerEventListeners();

  // ============================================================================================
  // Actual plugin functionality starts here
  // ============================================================================================
  @SneakyThrows
  public final void preInitPlugin() {
    // Get logger without name to nicely print the banner
    final Logger bannerLogger = LoggerFactory.getLogger("");

    // Print ASCII banner
    getAsciiBanner().forEach(bannerLogger::info);

    logger.info("Preinitializing " + NAME + " Version " + VERSION);

    if (VERSION.contains("SNAPSHOT")) {
      logger.warn("WARNING! This is a snapshot version!");
      logger.warn("Use at your own risk!");
    } else if (VERSION.contains("DEV")) {
      logger.info("This is a unreleased development version!");
      logger.info("Things might not work properly!");
    }

    logger.info("Downloading early dependencies");
    dependencyDownloader.downloadAndInjectInClasspath(getEarlyDependencies());

    configLoader = new ConfigLoader(this);
    configLoader.loadConfig();
  }

  @SneakyThrows
  public final void initPlugin() {
    logger.info("Initializing " + NAME + " Version " + VERSION);

    // Get the storage engine information first
    storageEngineData = configLoader.getConfig().getStorage().getStorageEngineData();

    logger.info("Downloading dependencies");
    dependencyDownloader.downloadAndInjectInClasspath(getDependencies());

    logger.info("Storage Engine: " + storageEngineData.getName());
    storageEngine = storageEngineData.createInstance();

    logger.info("Intializing Storage Engine");
    storageEngine.initialize();

    this.playerManager = generatePlayerManager();
    this.punishmentManager = generatePunishmentManager();

    logger.info("Registering Event Listeners");
    registerEventListeners();

    // TODO
  }

  // Private helper methods
  private List<String> generateAsciiBanner() {
    return Arrays.asList(
        "  §a            §4 __",
        "  §a /\\     _ _ §4|__) _  _    §aAuraBan §4v" + VERSION,
        "  §a/--\\|_|| (_|§4|__)(_|| )   §8Proudly running on " + getFullPlatform(),
        "");
  }
}