/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.shininet.bukkit.itemrenamer;
import java.io.File;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.milkbowl.vault.chat.Chat;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
import org.shininet.bukkit.itemrenamer.component.Component;
import org.shininet.bukkit.itemrenamer.component.Components;
import org.shininet.bukkit.itemrenamer.component.PluginComponent;
import org.shininet.bukkit.itemrenamer.component.ToggleComponent;
import org.shininet.bukkit.itemrenamer.configuration.ItemRenamerConfiguration;
import org.shininet.bukkit.itemrenamer.listeners.DisguiseComponent;
import org.shininet.bukkit.itemrenamer.listeners.ListenerCleanupComponent;
import org.shininet.bukkit.itemrenamer.listeners.ProtocolComponent;
import org.shininet.bukkit.itemrenamer.listeners.UpdateNotifierComponent;
import org.shininet.bukkit.itemrenamer.listeners.StackRestrictorComponent;
import org.shininet.bukkit.itemrenamer.metrics.BukkitMetrics;
import org.shininet.bukkit.itemrenamer.metrics.Updater;
import org.shininet.bukkit.itemrenamer.metrics.Updater.UpdateResult;
import com.comphenix.protocol.ProtocolLibrary;
import com.google.common.eventbus.EventBus;
public class ItemRenamerPlugin extends JavaPlugin {
/**
* The BukkitDev project ID for ItemRenamer.
* <p>
* This can be retrieved using the
* <a href="https://api.curseforge.com/servermods/projects?search=itemrenamer">Curse API</a>
*/
public static final int BUKKIT_DEV_ID = 46933;
/**
* The current BukkitDev slug. May change in the future.
*/
public static final String BUKKIT_DEV_SLUG = "itemrenamer";
// The current API
private static ItemRenamerAPI RENAMER_API;
// The current updater
private Updater updater;
private Logger logger;
private RefreshInventoryTask refreshTask;
private ItemRenamerConfiguration config;
private RenameProcessor processor;
// Current registered components
private UpdateNotifierComponent updateNotifyComponent;
private Component compositeComponent;
// For tracking the currently selected item
private SelectedItemTracker selectedTracker;
// For restricting the current stack
private ToggleComponent toggleRestrictor;
// Rename listeners
private RenameListenerManager listenerManager;
// Handling saving
private int lastSaveCount;
private Chat chat;
// Common event bus
private EventBus bus = new EventBus();
/**
* Retrieve the renamer API.
* @return The renamer API.
*/
public static ItemRenamerAPI getRenamerAPI() {
return RENAMER_API;
}
@Override
public void onLoad() {
logger = getLogger();
config = new ItemRenamerConfiguration(this, new File(getDataFolder(), "config.yml").getAbsolutePath()) {
protected void onSynchronized() {
lastSaveCount = getModificationCount();
refreshTask.forceRefresh();
}
};
if (setupChat()) {
logger.info("Found Vault!");
}
// Initialize helpers
listenerManager = new RenameListenerManager(this);
processor = new RenameProcessor(listenerManager, config, chat);
selectedTracker = new SelectedItemTracker();
// The stack restrictor that can be enabled or disabled
toggleRestrictor = Components.asToggleable(new StackRestrictorComponent(processor));
// Update stack restrictor
if (config.hasStackRestrictor()) {
logger.info("Starting stack restrictor.");
} else {
logger.warning("Stack restrictor has been disabled.");
}
refreshStackRestrictor();
// Packet and Bukkit listeners
ProtocolComponent listenerPacket = new ProtocolComponent(processor, ProtocolLibrary.getProtocolManager(), logger);
ListenerCleanupComponent cleanupComponent = new ListenerCleanupComponent(this);
updateNotifyComponent = new UpdateNotifierComponent(this);
// Components that will only be enabled if a corresponding plugin is enabled
PluginComponent pluginComponent = new PluginComponent();
pluginComponent.add("DisguiseCraft", DisguiseComponent.class);
// Every component
compositeComponent = Components.asComposite(toggleRestrictor, listenerPacket,
updateNotifyComponent, cleanupComponent, pluginComponent);
// Initialize the API
RENAMER_API = new ItemRenamerAPI(config, processor);
getLogger().info("Loaded ItemRenamer API.");
}
@Override
public void onEnable() {
startMetrics();
startUpdater();
// Start every component
compositeComponent.register(this, bus);
// Prepare commands
ItemRenamerCommands commandExecutor = new ItemRenamerCommands(this, config, selectedTracker);
getCommand("ItemRenamer").setExecutor(commandExecutor);
// Tasks
refreshTask = new RefreshInventoryTask(getServer().getScheduler(), this, config);
refreshTask.start();
checkWorlds();
}
private void checkWorlds() {
Set<String> specifiedWorlds = config.getWorldKeys();
// Warn if a world cannot be found
for (String world : specifiedWorlds) {
if (getServer().getWorld(world) == null) {
logger.warning("Unable to find world " + world + ". Config may be invalid.");
} else {
// Is the pack valid
String pack = config.getEffectiveWorldPack(world);
if (config.getRenameConfig().hasPack(pack))
logger.info("Item renaming enabled for world " + world);
else
logger.warning("Cannot find pack " + pack + " for world " + world);
}
}
// "Load" default packs as well
if (config.getDefaultPack() != null) {
for (World world : getServer().getWorlds()) {
if (!specifiedWorlds.contains(world.getName())) {
logger.info("Item renaming enabled for world " + world.getName());
}
}
}
}
/**
* Ensure that the stack restrictor is registered or not.
*/
public void refreshStackRestrictor() {
toggleRestrictor.setEnabled(config.hasStackRestrictor());
}
private void startUpdater() {
try {
if (config.isAutoUpdate() && updater == null) {
// Start Updater but just do a version check
updater = new Updater(this, BUKKIT_DEV_ID, this.getFile(), Updater.UpdateType.NO_DOWNLOAD, false);
logger.info("Checking for updates ...");
// Inform the console too
updater.addListener(new Runnable() {
@Override
public void run() {
updateNotifyComponent.notifySender(Bukkit.getConsoleSender());
}
});
updater.start();
}
} catch (Exception e) {
logger.log(Level.WARNING, "Failed to start Updater", e);
}
}
private void startMetrics() {
try {
BukkitMetrics metrics = new BukkitMetrics(this);
metrics.start();
} catch (Exception e) {
logger.log(Level.WARNING, "Failed to start Metrics", e);
}
}
/**
* Initialize reference to Vault.
* @return TRUE if Vault was detected and loaded, FALSE otherwise.
*/
private boolean setupChat() {
try {
RegisteredServiceProvider<Chat> chatProvider = getServer().getServicesManager().getRegistration(Chat.class);
if (chatProvider != null) {
chat = chatProvider.getProvider();
}
return (chat != null);
} catch (NoClassDefFoundError e) {
// Nope
return false;
}
}
@Override
public void onDisable() {
// Save all changes if anything has changed
if (config.getModificationCount() != lastSaveCount) {
config.save();
logger.info("Saving configuration.");
}
compositeComponent.unregister(this);
refreshTask.stop();
// Clear API
RENAMER_API = null;
}
/**
* Clean up every listener associated with the given plugin.
* @param plugin - the plugin.
*/
public void cleanupPlugin(Plugin plugin) {
listenerManager.removeListeners(plugin);
}
public boolean getUpdateReady() {
return updater != null && updater.getResult() == UpdateResult.UPDATE_AVAILABLE;
}
public String getUpdateName() {
return updater != null ? updater.getLatestName() : null;
}
}