public final void enable() {
        // load the sender factory instance
        setupSenderFactory();

        // send the startup banner
        Message.STARTUP_BANNER.send(getConsoleSender(), getBootstrap());

        // setup log dispatcher instance early
        this.logDispatcher = new LogDispatcher(this);

        // load configuration
        getLogger().info("Loading configuration...");
        ConfigurationAdapter configFileAdapter = provideConfigurationAdapter();
        this.configuration = new LuckPermsConfiguration(this, new MultiConfigurationAdapter(this,
                new FileSecretConfigAdapter(this),
                new SystemPropertyConfigAdapter(this),
                new EnvironmentVariableConfigAdapter(this),
                configFileAdapter
        ));

        // setup a bytebin instance
        this.httpClient = new OkHttpClient.Builder()
                .callTimeout(15, TimeUnit.SECONDS)
                .build();

        this.bytebin = new BytebinClient(
                this.httpClient,
                getConfiguration().get(ConfigKeys.BYTEBIN_URL),
                "luckperms"
        );
        this.bytesocks = new BytesocksClient(
                this.httpClient,
                getConfiguration().get(ConfigKeys.BYTESOCKS_HOST),
                getConfiguration().get(ConfigKeys.BYTESOCKS_USE_TLS),
                "luckperms/editor"
        );
        this.webEditorStore = new WebEditorStore(this);

        // init translation repo and update bundle files
        this.translationRepository = new TranslationRepository(this);
        this.translationRepository.scheduleRefresh();

        // now the configuration is loaded, we can create a storage factory and load initial dependencies
        StorageFactory storageFactory = new StorageFactory(this);
        this.dependencyManager.loadStorageDependencies(
                storageFactory.getRequiredTypes(),
                getConfiguration().get(ConfigKeys.REDIS_ENABLED),
                getConfiguration().get(ConfigKeys.RABBITMQ_ENABLED),
                getConfiguration().get(ConfigKeys.NATS_ENABLED)
        );

        // register listeners
        registerPlatformListeners();

        // initialise the storage
        // first, setup the file watcher, if enabled
        if (getConfiguration().get(ConfigKeys.WATCH_FILES)) {
            try {
                this.fileWatcher = new FileWatcher(this, getBootstrap().getDataDirectory());
            } catch (Throwable e) {
                // catch throwable here, seems some JVMs throw UnsatisfiedLinkError when trying
                // to create a watch service. see: https://github.com/LuckPerms/LuckPerms/issues/2066
                getLogger().warn("Error occurred whilst trying to create a file watcher:", e);
            }
        }

        // initialise storage
        this.storage = storageFactory.getInstance();
        this.messagingService = provideMessagingFactory().getInstance();

        // setup the update task buffer
        this.syncTaskBuffer = new SyncTask.Buffer(this);

        // register commands
        if (skipCommandRegistration()) {
            getLogger().warn("LuckPerms commands are disabled in the configuration for both console and players. Skipping command registration.");
        } else {
            registerCommands();
        }

        // load internal managers
        getLogger().info("Loading internal permission managers...");
        this.inheritanceGraphFactory = new InheritanceGraphFactory(this);

        // setup user/group/track manager
        setupManagers();

        // init calculator factory
        this.calculatorFactory = provideCalculatorFactory();

        // setup contextmanager & register common calculators
        setupContextManager();
        getContextManager().registerCalculator(new ConfigurationContextCalculator(getConfiguration()));

        // setup platform hooks
        setupPlatformHooks();

        // register with the LP API
        this.apiProvider = new LuckPermsApiProvider(this);
        this.apiProvider.ensureApiWasLoadedByPlugin();
        this.eventDispatcher = new EventDispatcher(provideEventBus(this.apiProvider));
        getBootstrap().getScheduler().executeAsync(GeneratedEventClass::preGenerate);
        ApiRegistrationUtil.registerProvider(this.apiProvider);
        registerApiOnPlatform(this.apiProvider);

        // setup extension manager
        this.extensionManager = new SimpleExtensionManager(this);
        this.extensionManager.loadExtensions(getBootstrap().getConfigDirectory().resolve("extensions"));

        // schedule update tasks
        int syncMins = getConfiguration().get(ConfigKeys.SYNC_TIME);
        if (syncMins > 0) {
            getBootstrap().getScheduler().asyncRepeating(() -> this.syncTaskBuffer.request(), syncMins, TimeUnit.MINUTES);
        }

        // run an update instantly.
        getLogger().info("Performing initial data load...");
        try {
            new SyncTask(this).run();
        } catch (Exception e) {
            e.printStackTrace();
        }

        // init housekeeping tasks
        registerHousekeepingTasks();

        // perform any platform-specific final setup tasks
        performFinalSetup();

        // mark as running
        this.running = true;

        Duration timeTaken = Duration.between(getBootstrap().getStartupTime(), Instant.now());
        getLogger().info("Successfully enabled. (took " + timeTaken.toMillis() + "ms)");
    }
Performs the initial actions to load the plugin
common/src/main/java/me/lucko/luckperms/common/plugin/AbstractLuckPermsPlugin.java