package io.github.lucaseasedup.logit; import static io.github.lucaseasedup.logit.message.MessageHelper.t; import io.github.lucaseasedup.logit.account.Account; import io.github.lucaseasedup.logit.account.AccountKeys; import io.github.lucaseasedup.logit.account.AccountManager; import io.github.lucaseasedup.logit.account.AccountWatcher; import io.github.lucaseasedup.logit.backup.BackupManager; import io.github.lucaseasedup.logit.command.AcclockCommand; import io.github.lucaseasedup.logit.command.AccunlockCommand; import io.github.lucaseasedup.logit.command.ChangeEmailCommand; import io.github.lucaseasedup.logit.command.ChangePassCommand; import io.github.lucaseasedup.logit.command.DisabledCommandExecutor; import io.github.lucaseasedup.logit.command.LogItTabCompleter; import io.github.lucaseasedup.logit.command.LoginCommand; import io.github.lucaseasedup.logit.command.LoginHistoryCommand; import io.github.lucaseasedup.logit.command.LogoutCommand; import io.github.lucaseasedup.logit.command.ProfileCommand; import io.github.lucaseasedup.logit.command.RecoverPassCommand; import io.github.lucaseasedup.logit.command.RegisterCommand; import io.github.lucaseasedup.logit.command.RememberCommand; import io.github.lucaseasedup.logit.command.UnregisterCommand; import io.github.lucaseasedup.logit.common.CancellableEvent; import io.github.lucaseasedup.logit.common.Disposable; import io.github.lucaseasedup.logit.common.FatalReportedException; import io.github.lucaseasedup.logit.common.PlayerCollections; import io.github.lucaseasedup.logit.common.Timer; import io.github.lucaseasedup.logit.common.Wrapper; import io.github.lucaseasedup.logit.config.ConfigurationManager; import io.github.lucaseasedup.logit.config.InvalidPropertyValueException; import io.github.lucaseasedup.logit.config.PredefinedConfiguration; import io.github.lucaseasedup.logit.config.TimeUnit; import io.github.lucaseasedup.logit.cooldown.CooldownManager; import io.github.lucaseasedup.logit.craftreflect.CraftReflect; import io.github.lucaseasedup.logit.hooks.VaultHook; import io.github.lucaseasedup.logit.listener.BlockEventListener; import io.github.lucaseasedup.logit.listener.EntityEventListener; import io.github.lucaseasedup.logit.listener.InventoryEventListener; import io.github.lucaseasedup.logit.listener.JoinMessage; import io.github.lucaseasedup.logit.listener.PlayerEventListener; import io.github.lucaseasedup.logit.listener.PlayerKicker; import io.github.lucaseasedup.logit.listener.QuitMessage; import io.github.lucaseasedup.logit.listener.ServerEventListener; import io.github.lucaseasedup.logit.listener.SessionEventListener; import io.github.lucaseasedup.logit.locale.EnglishLocale; import io.github.lucaseasedup.logit.locale.GermanLocale; import io.github.lucaseasedup.logit.locale.LocaleManager; import io.github.lucaseasedup.logit.locale.PolishLocale; import io.github.lucaseasedup.logit.logging.CommandSilencer; import io.github.lucaseasedup.logit.logging.LogItCoreLogger; import io.github.lucaseasedup.logit.logging.timing.TakeoffTiming; import io.github.lucaseasedup.logit.logging.timing.Timing; import io.github.lucaseasedup.logit.message.LogItMessageDispatcher; import io.github.lucaseasedup.logit.message.MessageHelper; import io.github.lucaseasedup.logit.persistence.AirBarSerializer; import io.github.lucaseasedup.logit.persistence.ExperienceSerializer; import io.github.lucaseasedup.logit.persistence.HealthBarSerializer; import io.github.lucaseasedup.logit.persistence.HungerBarSerializer; import io.github.lucaseasedup.logit.persistence.LocationSerializer; import io.github.lucaseasedup.logit.persistence.PersistenceManager; import io.github.lucaseasedup.logit.persistence.PersistenceSerializer; import io.github.lucaseasedup.logit.profile.ProfileManager; import io.github.lucaseasedup.logit.security.GlobalPasswordManager; import io.github.lucaseasedup.logit.security.SecurityHelper; import io.github.lucaseasedup.logit.session.SessionManager; import io.github.lucaseasedup.logit.storage.CacheType; import io.github.lucaseasedup.logit.storage.DataType; import io.github.lucaseasedup.logit.storage.Storage; import io.github.lucaseasedup.logit.storage.StorageFactory; import io.github.lucaseasedup.logit.storage.StorageType; import io.github.lucaseasedup.logit.storage.UnitKeys; import io.github.lucaseasedup.logit.storage.WrapperStorage; import io.github.lucaseasedup.logit.tab.TabListUpdater; import io.github.lucaseasedup.logit.util.CollectionUtils; import io.github.lucaseasedup.logit.util.IoUtils; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.Set; import java.util.logging.Level; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.command.CommandExecutor; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitTask; import org.mcsg.double0negative.tabapi.TabAPI; /** * The central part of LogIt. * * <p> There is only one instance of {@code LogItCore}, obtainable using * {@link #getInstance()}. */ public final class LogItCore { private LogItCore(LogItPlugin plugin) { if (plugin == null) throw new IllegalArgumentException(); this.plugin = plugin; } /** * Starts up the LogIt core. * * @return A {@code CancellableState} indicating whether this operation * has been cancelled by one of the {@code LogItCoreStartEvent} * handlers. * * @throws FatalReportedException * If a critical error occurred and LogIt could not start. * * @throws IllegalStateException * If the LogIt core is already running. * * @see #isStarted() * @see #stop() */ public CancelledState start() throws FatalReportedException { if (isStarted()) { throw new IllegalStateException( "The LogIt core has already been started." ); } TakeoffTiming timing = new TakeoffTiming(); timing.start(); // ======================================= timing.startEvent(); CancellableEvent evt = new LogItCoreStartEvent(this); Bukkit.getPluginManager().callEvent(evt); if (evt.isCancelled()) return CancelledState.CANCELLED; timing.endEvent(); // ======================================= scheduleTask(new BukkitRunnable() { @Override public void run() { globalClock.advance(); } }, 0L, globalClock.getInterval()); getDataFolder().mkdir(); firstRun = !getDataFile("config.yml").exists(); if (isFirstRun()) { doFirstRunStuff(); } // ======================================= timing.startConfigurationManager(); setUpConfiguration(); timing.endConfigurationManager(); // ======================================= // ======================================= timing.startLogger(); setUpLogger(); timing.endLogger(); // ======================================= timing.startMessages(); try { getPlugin().loadMessages( getConfig("config.yml").getString("locale") ); } catch (IOException ex) { log(Level.WARNING, "Could not load messages.", ex); } timing.endMessages(); // ======================================= if (getConfig("config.yml").getBoolean("passwordRecovery.enabled")) { File bodyFile = getDataFile( getConfig("config.yml").getString("passwordRecovery.bodyTemplate") ); if (!bodyFile.isFile()) { log(Level.SEVERE, "File " + bodyFile + " not found"); FatalReportedException.throwNew(); } } if (getConfig("secret.yml").getBoolean("debug.enableSelfTests")) { log(Level.WARNING, "Self-tests for LogIt have been enabled." + " Using them will DESTROY ALL YOUR DATA!"); tellConsole(""); tellConsole(ChatColor.RED + "()()()()()()()()()()()()()()()()()()()()"); tellConsole(ChatColor.RED + "========================================"); tellConsole(""); tellConsole(ChatColor.RED + " !!! ATTENTION !!!"); tellConsole(""); tellConsole(ChatColor.RED + " Self-tests for LogIt have been enabled."); tellConsole(ChatColor.RED + " Using them will DESTROY ALL YOUR DATA!"); tellConsole(""); tellConsole(ChatColor.RED + "========================================"); tellConsole(ChatColor.RED + "()()()()()()()()()()()()()()()()()()()()"); tellConsole(""); } // ======================================= timing.startCraftReflect(); setUpCraftReflect(); timing.endCraftReflect(); // ======================================= setUpLocaleManager(); // ======================================= timing.startAccountManager(); setUpAccountManager(); timing.endAccountManager(); // ======================================= // ======================================= timing.startPersistenceManager(); setUpPersistenceManager(); timing.endPersistenceManager(); // ======================================= disposables.add(securityHelper = new SecurityHelper()); disposables.add(backupManager = new BackupManager(getAccountManager())); disposables.add(sessionManager = new SessionManager()); disposables.add(messageDispatcher = new LogItMessageDispatcher()); disposables.add(tabCompleter = new LogItTabCompleter()); if (getConfig("config.yml").getBoolean("profiles.enabled")) { setUpProfileManager(); } disposables.add(globalPasswordManager = new GlobalPasswordManager()); disposables.add(cooldownManager = new CooldownManager()); disposables.add(accountWatcher = new AccountWatcher()); tabApiWrapper = new Wrapper<>(); if (getConfig("config.yml").getBoolean("forceLogin.hideFromTabList")) { disposables.add(tabListUpdater = new TabListUpdater( tabApiWrapper, craftReflect )); new BukkitRunnable() { @Override public void run() { if (Bukkit.getPluginManager().getPlugin("ProtocolLib") != null) { tabApiWrapper.set(new TabAPI()); tabApiWrapper.get().onEnable(); } } }.runTaskLater(getPlugin(), 1L); } startTasks(); enableCommands(); registerEventListeners(); timing.end(); if (getConfig("secret.yml").getBoolean("timings.enabled")) { clearTimings(); saveTiming(timing); } started = true; log(Level.FINE, t("startPlugin.success")); if (isFirstRun()) { tellConsole(t("firstRun1")); tellConsole(t("firstRun2")); tellConsole(t("firstRun3")); } doPostStartDuties(); return CancelledState.NOT_CANCELLED; } private void doFirstRunStuff() { getDataFile("backup").mkdir(); getDataFile("lib").mkdir(); getDataFile("mail").mkdir(); extractMailTemplate("password-recovery.html"); } private void setUpConfiguration() throws FatalReportedException { String configHeader = "# # # # # # # # # # # # # # #\n" + " LogIt Configuration File #\n" + "# # # # # # # # # # # # # # #\n"; String statsHeader = "# # # # # # # # # # # # # # #\n" + " LogIt Statistics File #\n" + "# # # # # # # # # # # # # # #\n"; String secretHeader = "# # # # # # # # # # # # # # # # # # # # # # # # # # # #\n" + " LogIt Secret Settings File #\n" + " #\n" + " Do not touch unless you are 100% what you're doing! #\n" + "# # # # # # # # # # # # # # # # # # # # # # # # # # # #\n"; File oldConfigDefFile = getDataFile("config-def.b64"); if (oldConfigDefFile.isFile()) { File newConfigDefFile = getDataFile(".doNotTouch/config-def.b64"); try { IoUtils.copyFile(oldConfigDefFile, newConfigDefFile); oldConfigDefFile.delete(); } catch (IOException ex) { log(Level.WARNING, ex); } } disposables.add(configurationManager = new ConfigurationManager()); configurationManager.registerConfiguration("config.yml", ".doNotTouch/config-def.b64", "config-def.ini", configHeader); configurationManager.registerConfiguration("stats.yml", ".doNotTouch/stats-def.b64", "stats-def.ini", statsHeader); configurationManager.registerConfiguration("secret.yml", ".doNotTouch/secret-def.b64", "secret-def.ini", secretHeader); try { configurationManager.loadAll(); } catch (IOException ex) { log(Level.SEVERE, "Could not load a configuration file.", ex); FatalReportedException.throwNew(ex); } catch (InvalidPropertyValueException ex) { log(Level.SEVERE, ex.getMessage()); FatalReportedException.throwNew(ex); } } private void setUpLogger() { disposables.add(logger = new LogItCoreLogger(this)); logger.open(); disposables.add(commandSilencer = new CommandSilencer(Arrays.asList( getPlugin().getCommand("login"), getPlugin().getCommand("logout"), getPlugin().getCommand("register"), getPlugin().getCommand("unregister"), getPlugin().getCommand("changepass"), getPlugin().getCommand("changeemail"), getPlugin().getCommand("recoverpass"), getPlugin().getCommand("loginhistory") ))); commandSilencer.registerFilters(); } private void extractMailTemplate(String filename) { if (filename == null) throw new IllegalArgumentException(); File templateFile = getDataFile("mail", filename); if (!templateFile.exists()) { try { IoUtils.extractResource(filename, templateFile); } catch (IOException ex) { log(Level.WARNING, "Could not extract mail template: " + filename, ex); } } } private void setUpCraftReflect() { try { String version = LogItPlugin.getCraftBukkitVersion(); String craftClassName = LogItPlugin.PACKAGE + ".craftreflect." + version + ".CraftReflect"; Class<?> craftClass = Class.forName(craftClassName); craftReflect = (CraftReflect) craftClass.getConstructor().newInstance(); } catch (ClassNotFoundException ex) { log(Level.WARNING, "LogIt does not support this version of Bukkit." + " Some features may not work."); } catch (ReflectiveOperationException ex) { log(Level.WARNING, "Could not set up CraftBukkit reflection." + " Some features may not work.", ex); } } private void setUpLocaleManager() { disposables.add(localeManager = new LocaleManager()); localeManager.registerLocale(EnglishLocale.getInstance()); localeManager.registerLocale(PolishLocale.getInstance()); localeManager.registerLocale(GermanLocale.getInstance()); localeManager.setFallbackLocale(EnglishLocale.class); localeManager.switchActiveLocale(getConfig("config.yml").getString("locale")); } private void setUpAccountManager() throws FatalReportedException { StorageType leadingStorageType = StorageType.decode( getConfig("config.yml").getString("storage.accounts.leading.storageType") ); StorageType mirrorStorageType = StorageType.decode( getConfig("config.yml").getString("storage.accounts.mirror.storageType") ); String accountsUnit = getConfig("config.yml") .getString("storage.accounts.leading.unit"); AccountKeys accountKeys = new AccountKeys( getConfig("config.yml").getString("storage.accounts.keys.username"), getConfig("config.yml").getString("storage.accounts.keys.uuid"), getConfig("config.yml").getString("storage.accounts.keys.salt"), getConfig("config.yml").getString("storage.accounts.keys.password"), getConfig("config.yml").getString("storage.accounts.keys.hashing_algorithm"), getConfig("config.yml").getString("storage.accounts.keys.ip"), getConfig("config.yml").getString("storage.accounts.keys.login_session"), getConfig("config.yml").getString("storage.accounts.keys.email"), getConfig("config.yml").getString("storage.accounts.keys.last_active_date"), getConfig("config.yml").getString("storage.accounts.keys.reg_date"), getConfig("config.yml").getString("storage.accounts.keys.is_locked"), getConfig("config.yml").getString("storage.accounts.keys.login_history"), getConfig("config.yml").getString("storage.accounts.keys.display_name"), getConfig("config.yml").getString("storage.accounts.keys.persistence") ); @SuppressWarnings("resource") Storage leadingAccountStorage = new StorageFactory(getConfig("config.yml"), "storage.accounts.leading") .produceStorage(leadingStorageType); @SuppressWarnings("resource") Storage mirrorAccountStorage = new StorageFactory(getConfig("config.yml"), "storage.accounts.mirror") .produceStorage(mirrorStorageType); CacheType accountCacheType = CacheType.decode( getConfig("config.yml").getString("storage.accounts.leading.cache") ); String leadingUnit = getConfig("config.yml") .getString("storage.accounts.leading.unit"); String mirrorUnit = getConfig("config.yml") .getString("storage.accounts.mirror.unit"); @SuppressWarnings("resource") WrapperStorage accountStorage = new WrapperStorage.Builder() .leading(leadingAccountStorage) .cacheType(accountCacheType) .build(); Map<String, String> unitMappings = new HashMap<>(); unitMappings.put(leadingUnit, mirrorUnit); accountStorage.mirrorStorage(mirrorAccountStorage, unitMappings); try { accountStorage.connect(); } catch (IOException ex) { log(Level.SEVERE, "Could not establish database connection", ex); FatalReportedException.throwNew(ex); } try { accountStorage.createUnit(accountsUnit, accountKeys, accountKeys.username()); } catch (IOException ex) { log(Level.SEVERE, "Could not create accounts unit", ex); FatalReportedException.throwNew(ex); } try { accountStorage.setAutobatchEnabled(true); UnitKeys existingKeys = accountStorage.getKeys(accountsUnit); for (Map.Entry<String, DataType> e : accountKeys.entrySet()) { if (!existingKeys.containsKey(e.getKey())) { accountStorage.addKey(accountsUnit, e.getKey(), e.getValue()); } } accountStorage.executeBatch(); accountStorage.clearBatch(); accountStorage.setAutobatchEnabled(false); } catch (IOException ex) { log(Level.SEVERE, "Could not update accounts table columns", ex); FatalReportedException.throwNew(ex); } try { accountStorage.preload(leadingUnit); } catch (IOException ex) { log(Level.SEVERE, "Could not preload accounts", ex); } try { disposables.add(accountManager = new AccountManager( accountStorage, accountsUnit, accountKeys )); } catch (IOException ex) { log(Level.SEVERE, "Could not construct AccountManager", ex); } } private void setUpPersistenceManager() throws FatalReportedException { disposables.add(persistenceManager = new PersistenceManager()); setSerializerEnabled(LocationSerializer.class, getConfig("config.yml").getBoolean("waitingRoom.enabled")); setSerializerEnabled(AirBarSerializer.class, getConfig("config.yml").getBoolean("forceLogin.obfuscate.air")); setSerializerEnabled(HealthBarSerializer.class, getConfig("config.yml").getBoolean("forceLogin.obfuscate.health")); setSerializerEnabled(ExperienceSerializer.class, getConfig("config.yml").getBoolean("forceLogin.obfuscate.experience")); setSerializerEnabled(HungerBarSerializer.class, getConfig("config.yml").getBoolean("forceLogin.obfuscate.hunger")); } private void setSerializerEnabled(Class<? extends PersistenceSerializer> clazz, boolean status) throws FatalReportedException { if (status) { try { getPersistenceManager().registerSerializer(clazz); } catch (ReflectiveOperationException ex) { log(Level.SEVERE, "Could not register persistence serializer: " + clazz.getSimpleName()); FatalReportedException.throwNew(ex); } } else { AccountKeys keys = getAccountManager().getKeys(); for (Player player : Bukkit.getOnlinePlayers()) { Account account = getAccountManager().selectAccount(player.getName(), Arrays.asList( keys.username(), keys.persistence() ) ); if (account != null) { getPersistenceManager().unserializeUsing( account, player, clazz ); } } } } private void setUpProfileManager() { File profilesPath = getDataFile( getConfig("config.yml").getString("profiles.path") ); if (!profilesPath.exists()) { profilesPath.getParentFile().mkdirs(); profilesPath.mkdir(); } disposables.add(profileManager = new ProfileManager( profilesPath, getConfig("config.yml").getValues("profiles.fields") )); } private void startTasks() { long bufferFlushInterval = getConfig("secret.yml") .getTime("bufferFlushInterval", TimeUnit.TICKS); scheduleTask(getAccountManager(), 0L, bufferFlushInterval); scheduleTask(getBackupManager(), 0L, BackupManager.TASK_PERIOD); scheduleTask(getSessionManager(), 0L, SessionManager.TASK_PERIOD); scheduleTask(getGlobalPasswordManager(), 0L, GlobalPasswordManager.TASK_PERIOD); scheduleTask(getAccountWatcher(), 0L, AccountWatcher.TASK_PERIOD); if (getTabListUpdater() != null) { scheduleTask(getTabListUpdater(), 20L, TabListUpdater.TASK_PERIOD); } } private void scheduleTask(Runnable runnable, long delay, long period) { if (runnable == null || delay < 0 || period <= 0) throw new IllegalArgumentException(); tasks.add(Bukkit.getScheduler().runTaskTimer( getPlugin(), runnable, delay, period )); } private void enableCommands() { enableCommand("login", new LoginCommand()); enableCommand("logout", new LogoutCommand()); enableCommand("remember", new RememberCommand(), getConfig("config.yml").getBoolean("loginSessions.enabled")); enableCommand("register", new RegisterCommand()); enableCommand("unregister", new UnregisterCommand()); enableCommand("changepass", new ChangePassCommand(), !getConfig("secret.yml").getBoolean("passwords.disable")); enableCommand("changeemail", new ChangeEmailCommand()); enableCommand("recoverpass", new RecoverPassCommand(), getConfig("config.yml").getBoolean("passwordRecovery.enabled")); enableCommand("profile", new ProfileCommand(), getConfig("config.yml").getBoolean("profiles.enabled")); enableCommand("acclock", new AcclockCommand()); enableCommand("accunlock", new AccunlockCommand()); enableCommand("loginhistory", new LoginHistoryCommand(), getConfig("config.yml").getBoolean("loginHistory.enabled")); } private void enableCommand( String command, CommandExecutor executor, boolean enabled ) { if (command == null || executor == null) throw new IllegalArgumentException(); if (enabled) { getPlugin().getCommand(command).setExecutor(executor); } else { disableCommand(command); } } private void enableCommand(String command, CommandExecutor executor) { enableCommand(command, executor, true); } private void registerEventListeners() { PlayerCollections.registerListener(getPlugin()); registerEventListener(getMessageDispatcher()); registerEventListener(getCooldownManager()); if (getTabListUpdater() != null) { registerEventListener(getTabListUpdater()); } registerEventListener(new ServerEventListener()); registerEventListener(new BlockEventListener()); registerEventListener(new EntityEventListener()); registerEventListener(new PlayerEventListener()); registerEventListener(new InventoryEventListener()); registerEventListener(new SessionEventListener()); } private <T extends Listener> void registerEventListener(T listener) { if (listener == null) throw new IllegalArgumentException(); Bukkit.getPluginManager().registerEvents(listener, getPlugin()); eventListeners.put(listener.getClass(), listener); } private void doPostStartDuties() { if (getConfig("config.yml").getBoolean("backup.forceAtStart")) { backupManager.createBackup(); } File sessionsFile = getDataFile( getConfig("config.yml").getString("storage.sessions.filename") ); if (getSessionManager() != null && sessionsFile.isFile()) { try { getSessionManager().importSessions(sessionsFile); } catch (IOException ex) { log(Level.WARNING, "Could not import sessions.", ex); } sessionsFile.delete(); } PlayerEventListener playerEventListener = getEventListener(PlayerEventListener.class); PlayerKicker playerKicker = new PlayerKicker() { @Override public void kick(Player player, String message) { player.kickPlayer(message); } }; for (final Player player : Bukkit.getOnlinePlayers()) { playerEventListener.onLogin(player, player.getAddress().getAddress(), playerKicker); playerEventListener.onJoin(player, new JoinMessage() { @Override public void set(String joinMessage) { MessageHelper.broadcastMsgExcept(joinMessage, Arrays.asList(player.getName())); } }); } } /** * Stops the LogIt core. * * @return A {@code CancellableState} indicating whether this operation * has been cancelled by one of the {@code LogItCoreStopEvent} * handlers. * * @throws IllegalStateException * If the LogIt core is not running. * * @see #isStarted() * @see #start() */ public CancelledState stop() { if (!isStarted()) throw new IllegalStateException("The LogIt core is not started."); CancellableEvent evt = new LogItCoreStopEvent(this); Bukkit.getPluginManager().callEvent(evt); if (evt.isCancelled()) return CancelledState.CANCELLED; File sessionsFile = getDataFile( getConfig("config.yml").getString("storage.sessions.filename") ); if (getSessionManager() != null) { try { getSessionManager().exportSessions(sessionsFile); } catch (IOException ex) { log(Level.WARNING, "Could not export sessions.", ex); } } PlayerEventListener playerEventListener = getEventListener(PlayerEventListener.class); if (playerEventListener != null) { for (final Player player : Bukkit.getOnlinePlayers()) { playerEventListener.onQuit(player, new QuitMessage() { @Override public void set(String quitMessage) { MessageHelper.broadcastMsgExcept(quitMessage, Arrays.asList(player.getName())); } }); } } disableCommands(); if (getPersistenceManager() != null) { getPersistenceManager() .unregisterSerializer(LocationSerializer.class); getPersistenceManager() .unregisterSerializer(AirBarSerializer.class); getPersistenceManager() .unregisterSerializer(HealthBarSerializer.class); getPersistenceManager() .unregisterSerializer(ExperienceSerializer.class); getPersistenceManager() .unregisterSerializer(HungerBarSerializer.class); } if (getAccountManager() != null) { try { getAccountManager().getStorage().close(); } catch (IOException ex) { log(Level.WARNING, "Could not close database connection.", ex); } } if (commandSilencer != null) { commandSilencer.unregisterFilters(); } if (tabApiWrapper != null && tabApiWrapper.get() != null) { tabApiWrapper.get().onDisable(); tabApiWrapper.set(null); } Bukkit.getScheduler().cancelTasks(getPlugin()); tasks.clear(); // Unregister all event listeners. HandlerList.unregisterAll(getPlugin()); eventListeners.clear(); started = false; dispose(); log(Level.FINE, t("stopPlugin.success")); if (logger != null) { logger.close(); logger = null; } return CancelledState.NOT_CANCELLED; } private void disableCommands() { disableCommand("login"); disableCommand("logout"); disableCommand("remember"); disableCommand("register"); disableCommand("unregister"); disableCommand("changepass"); disableCommand("changeemail"); disableCommand("recoverpass"); disableCommand("profile"); disableCommand("acclock"); disableCommand("accunlock"); disableCommand("loginhistory"); } private void disableCommand(String command) { if (command == null) throw new IllegalArgumentException(); getPlugin().getCommand(command).setExecutor( new DisabledCommandExecutor() ); } /** * Disposes the LogIt core. * * @throws IllegalStateException if the LogIt core is running. */ private void dispose() { if (isStarted()) { throw new IllegalStateException( "Cannot dispose the LogIt core while it's running" ); } Disposable disposable; while ((disposable = disposables.poll()) != null) { disposable.dispose(); } configurationManager = null; commandSilencer = null; localeManager = null; accountManager = null; persistenceManager = null; securityHelper = null; backupManager = null; sessionManager = null; messageDispatcher = null; tabCompleter = null; profileManager = null; globalPasswordManager = null; cooldownManager = null; accountWatcher = null; tabApiWrapper = null; tabListUpdater = null; } /** * Restarts the LogIt core. * * @throws FatalReportedException * If the LogIt core could not be started again. * * @throws IllegalStateException * If the LogIt core is not running. * * @see #isStarted() * @see #start() */ public void restart() throws FatalReportedException { if (!isStarted()) throw new IllegalStateException("The LogIt core is not started."); CancelledState stop = stop(); CancelledState start = start(); if (!stop.isCancelled() && !start.isCancelled()) { log(Level.INFO, t("reloadPlugin.success")); } } /** * Checks if a player is forced to log in. * * <p> Returns {@code true} if the <i>forceLogin.global</i> config setting * is set to <i>true</i>, or the player is in a world with forced login. * * <p> If the player name is contained in the * <i>forceLogin.exemptPlayers</i> config property, it always returns * {@code false} regardless of the above conditions. * * <p> Note that this method does not check if the player is logged in. * For that purpose, use {@link SessionManager#isSessionAlive(Player)} * or {@link SessionManager#isSessionAlive(String)}. * * @param player * The player whom this check will be ran on. * * @return {@code true} if the player is forced to log in; * {@code false} otherwise. */ public boolean isPlayerForcedToLogIn(Player player) { String playerWorldName = player.getWorld().getName(); boolean forcedLoginGlobal = getConfig("config.yml") .getBoolean("forceLogin.global"); List<String> exemptedWorlds = getConfig("config.yml") .getStringList("forceLogin.inWorlds"); List<String> exemptedPlayers = getConfig("config.yml") .getStringList("forceLogin.exemptPlayers"); return (forcedLoginGlobal || exemptedWorlds.contains(playerWorldName)) && !CollectionUtils.containsIgnoreCase( player.getName(), exemptedPlayers ); } /** * Updates permission groups for a player only if LogIt is linked to Vault. * * <p> If Vault is not enabled, no action will be taken. * * <p> Permission groups currently supported: <ul> * <li>Registered</li> * <li>Not registered</li> * <li>Logged in</li> * <li>Logged out</li> * </ul> * * <p> Exact group names will be read from the configuration file. * * @param player * The player whose permission groups should be updated. * * @throws IllegalArgumentException * If {@code player} is {@code null}. */ public void updatePlayerGroup(Player player) { if (player == null) throw new IllegalArgumentException(); if (!VaultHook.isVaultEnabled()) return; if (getAccountManager().isRegistered(player.getName())) { VaultHook.playerRemoveGroup(player, getConfig("config.yml").getString("groups.unregistered")); VaultHook.playerAddGroup(player, getConfig("config.yml").getString("groups.registered")); } else { VaultHook.playerRemoveGroup(player, getConfig("config.yml").getString("groups.registered")); VaultHook.playerAddGroup(player, getConfig("config.yml").getString("groups.unregistered")); } if (getSessionManager().isSessionAlive(player)) { VaultHook.playerRemoveGroup(player, getConfig("config.yml").getString("groups.loggedOut")); VaultHook.playerAddGroup(player, getConfig("config.yml").getString("groups.loggedIn")); } else { VaultHook.playerRemoveGroup(player, getConfig("config.yml").getString("groups.loggedIn")); VaultHook.playerAddGroup(player, getConfig("config.yml").getString("groups.loggedOut")); } } public void clearTimings() { getTimingsFile().delete(); } public void saveTiming(Timing timing) { if (timing == null) throw new IllegalArgumentException(); File timingsFile = getTimingsFile(); try { timing.saveTiming(timingsFile); } catch (IOException ex) { log(Level.WARNING, "Could not save timings", ex); } } private File getTimingsFile() { return getDataFile( getConfig("secret.yml").getString("timings.filename") ); } public void log(Level level, String msg) { if (level == null || msg == null) throw new IllegalArgumentException(); msg = ChatColor.stripColor(msg); if (getLogger() == null) { getPlugin().getLogger().log(level, msg); } else { getLogger().log(level, msg); } } public void log(Level level, String msg, Throwable throwable) { if (level == null || msg == null || throwable == null) throw new IllegalArgumentException(); msg = ChatColor.stripColor(msg); if (getLogger() == null) { getPlugin().getLogger().log(level, msg, throwable); } else { getLogger().log(level, msg, throwable); } } public void log(Level level, Throwable throwable) { if (level == null || throwable == null) throw new IllegalArgumentException(); if (getLogger() == null) { getPlugin().getLogger().log(level, null, throwable); } else { getLogger().log(level, throwable); } } public void tellConsole(String msg) { if (msg == null) throw new IllegalArgumentException(); Bukkit.getConsoleSender().sendMessage(msg); } /** * Returns the {@code LogItPlugin} object. * * <p> Most of times, all the work will be done with the LogIt core, * but the {@code LogItPlugin} may come useful if you want to, * for example, reload the message files. * * @return The {@code LogItPlugin} object. */ public LogItPlugin getPlugin() { return plugin; } /** * Returns the LogIt data folder as a {@code File} object * (<i>/plugins/LogIt/</i>). * * @return The data folder. */ public File getDataFolder() { return getPlugin().getDataFolder(); } /** * Returns a file, as a {@code File} object, * relative to the LogIt data folder (<i>/plugins/LogIt/</i>). * * @param path * The relative path. * * @return The data file. */ public File getDataFile(String path) { if (path == null) throw new IllegalArgumentException(); return new File(getDataFolder(), path); } public File getDataFile(String parent, String path) { if (parent == null || path == null) throw new IllegalArgumentException(); return new File(getDataFolder(), parent + File.separator + path); } /** * Checks if this is the first time LogIt is running on this server. * * @return {@code true} if LogIt is running for the first time; * {@code false} otherwise. */ public boolean isFirstRun() { return firstRun; } /** * Checks if the LogIt core has been successfully started and is running. * * @return {@code true} if the LogIt core is started; * {@code false} otherwise. */ public boolean isStarted() { return started; } public Timer getGlobalClock() { return globalClock; } public ConfigurationManager getConfigurationManager() { return configurationManager; } public PredefinedConfiguration getConfig(String filename) { if (filename == null) throw new IllegalArgumentException(); if (getConfigurationManager() == null) return null; return getConfigurationManager().getConfiguration(filename); } public Location getWaitingRoomLocation() { return getConfig("config.yml") .getLocation("waitingRoom.location").toBukkitLocation(); } private LogItCoreLogger getLogger() { return logger; } public LocaleManager getLocaleManager() { return localeManager; } public AccountManager getAccountManager() { return accountManager; } public PersistenceManager getPersistenceManager() { return persistenceManager; } public SecurityHelper getSecurityHelper() { return securityHelper; } public BackupManager getBackupManager() { return backupManager; } public SessionManager getSessionManager() { return sessionManager; } public LogItMessageDispatcher getMessageDispatcher() { return messageDispatcher; } public LogItTabCompleter getTabCompleter() { return tabCompleter; } public ProfileManager getProfileManager() { return profileManager; } public GlobalPasswordManager getGlobalPasswordManager() { return globalPasswordManager; } public CooldownManager getCooldownManager() { return cooldownManager; } private AccountWatcher getAccountWatcher() { return accountWatcher; } public TabListUpdater getTabListUpdater() { return tabListUpdater; } @SuppressWarnings("unchecked") public <T extends Listener> T getEventListener(Class<T> listenerClass) { if (listenerClass == null) throw new IllegalArgumentException(); return (T) eventListeners.get(listenerClass); } /** * The preferred way to obtain the instance of {@code LogItCore}. * * @return The instance of {@code LogItCore}. */ public static LogItCore getInstance() { if (instance == null) { instance = new LogItCore(LogItPlugin.getInstance()); } return instance; } private static volatile LogItCore instance = null; private final LogItPlugin plugin; private boolean firstRun; private boolean started = false; private final Timer globalClock = new Timer(1L); private ConfigurationManager configurationManager; private LogItCoreLogger logger; private CommandSilencer commandSilencer; private CraftReflect craftReflect; private LocaleManager localeManager; private AccountManager accountManager; private PersistenceManager persistenceManager; private SecurityHelper securityHelper; private BackupManager backupManager; private SessionManager sessionManager; private LogItMessageDispatcher messageDispatcher; private LogItTabCompleter tabCompleter; private ProfileManager profileManager; private GlobalPasswordManager globalPasswordManager; private CooldownManager cooldownManager; private AccountWatcher accountWatcher; private Wrapper<TabAPI> tabApiWrapper; private TabListUpdater tabListUpdater; private final Queue<Disposable> disposables = new LinkedList<>(); private final Set<BukkitTask> tasks = new LinkedHashSet<>(); private final Map<Class<? extends Listener>, Listener> eventListeners = new HashMap<>(); { globalClock.start(); } }