/* * This file is part of Prism, licensed under the MIT License (MIT). * * Copyright (c) 2015 Helion3 http://helion3.com/ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.helion3.prism; import com.google.common.base.Preconditions; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.inject.Inject; import com.helion3.prism.api.data.PrismEvent; import com.helion3.prism.api.filters.FilterList; import com.helion3.prism.api.filters.FilterMode; import com.helion3.prism.api.flags.FlagClean; import com.helion3.prism.api.flags.FlagDrain; import com.helion3.prism.api.flags.FlagExtended; import com.helion3.prism.api.flags.FlagHandler; import com.helion3.prism.api.flags.FlagNoGroup; import com.helion3.prism.api.flags.FlagOrder; import com.helion3.prism.api.parameters.ParameterBlock; import com.helion3.prism.api.parameters.ParameterCause; import com.helion3.prism.api.parameters.ParameterEventName; import com.helion3.prism.api.parameters.ParameterHandler; import com.helion3.prism.api.parameters.ParameterPlayer; import com.helion3.prism.api.parameters.ParameterRadius; import com.helion3.prism.api.parameters.ParameterTime; import com.helion3.prism.api.records.ActionableResult; import com.helion3.prism.api.storage.StorageAdapter; import com.helion3.prism.commands.PrismCommands; import com.helion3.prism.configuration.Config; import com.helion3.prism.configuration.Configuration; import com.helion3.prism.listeners.ChangeBlockListener; import com.helion3.prism.listeners.EntityListener; import com.helion3.prism.listeners.InventoryListener; import com.helion3.prism.listeners.RequiredInteractListener; import com.helion3.prism.queues.RecordingQueueManager; import com.helion3.prism.storage.h2.H2StorageAdapter; import com.helion3.prism.storage.mongodb.MongoStorageAdapter; import com.helion3.prism.storage.mysql.MySQLStorageAdapter; import com.helion3.prism.util.PrismEvents; import com.helion3.prism.util.Reference; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.spongepowered.api.Sponge; import org.spongepowered.api.config.DefaultConfig; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.game.state.GameConstructionEvent; import org.spongepowered.api.event.game.state.GameInitializationEvent; import org.spongepowered.api.event.game.state.GamePostInitializationEvent; import org.spongepowered.api.event.game.state.GamePreInitializationEvent; import org.spongepowered.api.event.game.state.GameStartedServerEvent; import org.spongepowered.api.event.game.state.GameStoppedServerEvent; import org.spongepowered.api.plugin.Plugin; import org.spongepowered.api.plugin.PluginContainer; import org.spongepowered.api.scheduler.Task; import java.nio.file.Path; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.concurrent.TimeUnit; /** * Prism is an event logging + rollback/restore engine for Minecraft servers. * * @author viveleroi */ @Plugin( id = Reference.ID, name = Reference.NAME, version = Reference.VERSION, description = Reference.DESCRIPTION, authors = Reference.AUTHORS, url = Reference.WEBSITE ) public final class Prism { private static Prism instance; @Inject private PluginContainer pluginContainer; @Inject private Logger logger; @Inject @DefaultConfig(sharedRoot = false) private Path path; private Configuration configuration; private StorageAdapter storageAdapter; private final Set<UUID> activeWands = Sets.newHashSet(); private final FilterList filterList = new FilterList(FilterMode.BLACKLIST); private final Set<FlagHandler> flagHandlers = Sets.newHashSet(); private final Map<UUID, List<ActionableResult>> lastActionResults = Maps.newHashMap(); private final Set<ParameterHandler> parameterHandlers = Sets.newHashSet(); private final Set<PrismEvent> prismEvents = Sets.newHashSet(); private final RecordingQueueManager recordingQueueManager = new RecordingQueueManager(); @Listener public void onConstruction(GameConstructionEvent event) { instance = this; configuration = new Configuration(getPath()); Sponge.getRegistry().registerModule(PrismEvent.class, PrismEvents.REGISTRY_MODULE); } @Listener public void onPreInitialization(GamePreInitializationEvent event) { getConfiguration().loadConfiguration(); } @Listener public void onInitialization(GameInitializationEvent event) { // Register FlagHandlers registerFlagHandler(new FlagClean()); registerFlagHandler(new FlagDrain()); registerFlagHandler(new FlagExtended()); registerFlagHandler(new FlagNoGroup()); registerFlagHandler(new FlagOrder()); // Register ParameterHandlers registerParameterHandler(new ParameterBlock()); registerParameterHandler(new ParameterCause()); registerParameterHandler(new ParameterEventName()); registerParameterHandler(new ParameterPlayer()); registerParameterHandler(new ParameterRadius()); registerParameterHandler(new ParameterTime()); // Register Commands Sponge.getCommandManager().register(this, PrismCommands.getCommand(), Reference.ID, "pr"); // Register Listeners Sponge.getEventManager().registerListeners(getPluginContainer(), new ChangeBlockListener()); Sponge.getEventManager().registerListeners(getPluginContainer(), new EntityListener()); Sponge.getEventManager().registerListeners(getPluginContainer(), new InventoryListener()); // Events required for internal operation Sponge.getEventManager().registerListeners(getPluginContainer(), new RequiredInteractListener()); } @Listener public void onPostInitialization(GamePostInitializationEvent event) { getConfiguration().saveConfiguration(); } @Listener public void onStartedServer(GameStartedServerEvent event) { String engine = getConfig().getStorageCategory().getEngine(); try { if (StringUtils.equalsIgnoreCase(engine, "h2")) { storageAdapter = new H2StorageAdapter(); } else if (StringUtils.equalsAnyIgnoreCase(engine, "mongo", "mongodb")) { storageAdapter = new MongoStorageAdapter(); } else if (StringUtils.equalsIgnoreCase(engine, "mysql")) { storageAdapter = new MySQLStorageAdapter(); } else { throw new Exception("Invalid storage engine configured."); } Preconditions.checkState(getStorageAdapter().connect()); // Initialize the recording queue manager Task.builder() .async() .name("PrismRecordingQueueManager") .interval(1, TimeUnit.SECONDS) .execute(recordingQueueManager) .submit(getPluginContainer()); getLogger().info("Prism started successfully. Bad guys beware."); } catch (Exception ex) { Sponge.getEventManager().unregisterPluginListeners(getPluginContainer()); getLogger().error("Encountered an error processing {}::onStartedServer", "Prism", ex); } } @Listener public void onStoppedServer(GameStoppedServerEvent event) { // Cancel all scheduled tasks Sponge.getScheduler().getScheduledTasks(getInstance()).forEach(Task::cancel); if (getStorageAdapter() != null) { // Flush any pending records // If the scheduled task is still running this will block until it completes recordingQueueManager.run(); // Shutdown storage getStorageAdapter().close(); } } public static Prism getInstance() { return instance; } public PluginContainer getPluginContainer() { return pluginContainer; } public Logger getLogger() { return logger; } public Path getPath() { return path; } public Configuration getConfiguration() { return configuration; } public Config getConfig() { Preconditions.checkState(getConfiguration() != null, "Prism has not been initialized!"); return getConfiguration().getConfig(); } public StorageAdapter getStorageAdapter() { return storageAdapter; } /** * Returns a list of players who have active inspection wands. * * @return A list of players' UUIDs who have an active inspection wand */ public Set<UUID> getActiveWands() { return activeWands; } /** * Returns the blacklist manager. * * @return Blacklist */ public FilterList getFilterList() { return filterList; } /** * Returns all currently registered flag handlers. * * @return List of {@link FlagHandler} */ public Set<FlagHandler> getFlagHandlers() { return flagHandlers; } /** * Returns a specific handler for a given parameter * * @param flag {@link String} flag name * @return The {@link FlagHandler}, or empty if unsupported */ public Optional<FlagHandler> getFlagHandler(String flag) { for (FlagHandler flagHandler : getFlagHandlers()) { if (flagHandler.handles(flag)) { return Optional.of(flagHandler); } } return Optional.empty(); } /** * Register a flag handler. * * @param flagHandler {@link FlagHandler} * @return True if the {@link FlagHandler} was registered */ public boolean registerFlagHandler(FlagHandler flagHandler) { Preconditions.checkNotNull(flagHandler); return getFlagHandlers().add(flagHandler); } /** * Get a map of players and their last available actionable results. * * @return A map of players' UUIDs to a list of their {@link ActionableResult}s */ public Map<UUID, List<ActionableResult>> getLastActionResults() { return lastActionResults; } /** * Returns all currently registered parameter handlers. * * @return List of {@link ParameterHandler} */ public Set<ParameterHandler> getParameterHandlers() { return parameterHandlers; } /** * Returns a specific handler for a given parameter * * @param alias {@link String} parameter name * @return The {@link ParameterHandler}, or empty if unsupported */ public Optional<ParameterHandler> getParameterHandler(String alias) { for (ParameterHandler parameterHandler : getParameterHandlers()) { if (parameterHandler.handles(alias)) { return Optional.of(parameterHandler); } } return Optional.empty(); } /** * Register a parameter handler. * * @param parameterHandler {@link ParameterHandler} * @return True if the {@link ParameterHandler} was registered */ public boolean registerParameterHandler(ParameterHandler parameterHandler) { Preconditions.checkNotNull(parameterHandler); return getParameterHandlers().add(parameterHandler); } }