package me.desht.scrollingmenusign; import com.comphenix.protocol.ProtocolLibrary; import me.desht.dhutils.*; import me.desht.dhutils.MetaFaker.MetadataFilter; import me.desht.dhutils.commands.CommandManager; import me.desht.dhutils.cost.EconomyCost; import me.desht.dhutils.responsehandler.ResponseHandler; import me.desht.scrollingmenusign.commandlets.*; import me.desht.scrollingmenusign.commands.*; import me.desht.scrollingmenusign.listeners.*; import me.desht.scrollingmenusign.parser.CommandParser; import me.desht.scrollingmenusign.spout.SpoutUtils; import me.desht.scrollingmenusign.util.SMSUtil; import me.desht.scrollingmenusign.util.UUIDMigration; import me.desht.scrollingmenusign.variables.VariablesManager; import me.desht.scrollingmenusign.views.*; import me.desht.scrollingmenusign.views.action.RepaintAction; import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.permission.Permission; import org.bukkit.GameMode; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.configuration.Configuration; import org.bukkit.configuration.serialization.ConfigurationSerialization; import org.bukkit.entity.Player; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; import org.mcstats.Metrics; import org.mcstats.Metrics.Graph; import org.mcstats.Metrics.Plotter; import java.awt.*; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map.Entry; import java.util.UUID; /** * ScrollingMenuSign * * @author desht */ public class ScrollingMenuSign extends JavaPlugin implements ConfigurationListener { public static final int BLOCK_TARGET_DIST = 4; public static final String CONSOLE_OWNER = "[console]"; public static final UUID CONSOLE_UUID = new UUID(0, 0); private static ScrollingMenuSign instance = null; public static Economy economy = null; public static Permission permission = null; private final CommandManager cmds = new CommandManager(this); private final CommandletManager cmdlets = new CommandletManager(this); private final ViewManager viewManager = new ViewManager(this); private final LocationManager locationManager = new LocationManager(); private final VariablesManager variablesManager = new VariablesManager(this); private final MenuManager menuManager = new MenuManager(this); private final SMSHandlerImpl handler = new SMSHandlerImpl(this); private final ConfigCache configCache = new ConfigCache(); private boolean spoutEnabled = false; private ConfigurationManager configManager; public final ResponseHandler responseHandler = new ResponseHandler(this); private boolean protocolLibEnabled = false; private MetaFaker faker; private boolean vaultLegacyMode = false; private boolean holoAPIEnabled; @Override public void onLoad() { ConfigurationSerialization.registerClass(PersistableLocation.class); } @Override public void onEnable() { setInstance(this); LogUtils.init(this); DirectoryStructure.setupDirectoryStructure(); configManager = new ConfigurationManager(this, this); configManager.setPrefix("sms"); configCleanup(); configCache.processConfig(getConfig()); MiscUtil.init(this); MiscUtil.setColouredConsole(getConfig().getBoolean("sms.coloured_console")); Debugger.getInstance().setPrefix("[SMS] "); Debugger.getInstance().setLevel(getConfig().getInt("sms.debug_level")); Debugger.getInstance().setTarget(getServer().getConsoleSender()); PluginManager pm = getServer().getPluginManager(); setupSpout(pm); setupVault(pm); setupProtocolLib(pm); setupHoloAPI(pm); if (protocolLibEnabled) { ItemGlow.init(this); setupItemMetaFaker(); } setupCustomFonts(); new SMSPlayerListener(this); new SMSBlockListener(this); new SMSEntityListener(this); new SMSWorldListener(this); if (spoutEnabled) { new SMSSpoutKeyListener(this); } registerCommands(); registerCommandlets(); MessagePager.setPageCmd("/sms page [#|n|p]"); MessagePager.setDefaultPageSize(getConfig().getInt("sms.pager.lines", 0)); SMSScrollableView.setDefaultScrollType(SMSScrollableView.ScrollType.valueOf(getConfig().getString("sms.scroll_type").toUpperCase())); loadPersistedData(); variablesManager.checkForUUIDMigration(); if (spoutEnabled) { SpoutUtils.precacheTextures(); } setupMetrics(); Debugger.getInstance().debug(getDescription().getName() + " version " + getDescription().getVersion() + " is enabled!"); UUIDMigration.migrateToUUID(this); } @Override public void onDisable() { SMSPersistence.saveMenusAndViews(); SMSPersistence.saveMacros(); SMSPersistence.saveVariables(); for (SMSMenu menu : getMenuManager().listMenus()) { // this also deletes all the menu's views... menu.deleteTemporary(); } for (SMSMacro macro : SMSMacro.listMacros()) { macro.deleteTemporary(); } if (faker != null) { faker.shutdown(); } economy = null; permission = null; setInstance(null); Debugger.getInstance().debug(getDescription().getName() + " version " + getDescription().getVersion() + " is disabled!"); } @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { return cmds.dispatch(sender, command, label, args); } @Override public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) { return cmds.onTabComplete(sender, command, label, args); } public SMSHandler getHandler() { return handler; } public boolean isSpoutEnabled() { return spoutEnabled; } public boolean isProtocolLibEnabled() { return protocolLibEnabled; } public boolean isHoloAPIEnabled() { return holoAPIEnabled; } public static ScrollingMenuSign getInstance() { return instance; } public CommandletManager getCommandletManager() { return cmdlets; } public ConfigurationManager getConfigManager() { return configManager; } /** * @return the viewManager */ public ViewManager getViewManager() { return viewManager; } /** * @return the locationManager */ public LocationManager getLocationManager() { return locationManager; } private void setupMetrics() { if (!getConfig().getBoolean("sms.mcstats")) { return; } try { Metrics metrics = new Metrics(this); Graph graphM = metrics.createGraph("Menu/View/Macro count"); graphM.addPlotter(new Plotter("Menus") { @Override public int getValue() { return getMenuManager().listMenus().size(); } }); graphM.addPlotter(new Plotter("Views") { @Override public int getValue() { return viewManager.listViews().size(); } }); graphM.addPlotter(new Plotter("Macros") { @Override public int getValue() { return SMSMacro.listMacros().size(); } }); Graph graphV = metrics.createGraph("View Types"); for (final Entry<String, Integer> e : viewManager.getViewCounts().entrySet()) { graphV.addPlotter(new Plotter(e.getKey()) { @Override public int getValue() { return e.getValue(); } }); } metrics.start(); } catch (IOException e) { LogUtils.warning("Can't submit metrics data: " + e.getMessage()); } } private static void setInstance(ScrollingMenuSign plugin) { instance = plugin; } private void setupHoloAPI(PluginManager pm) { Plugin holoAPI = pm.getPlugin("HoloAPI"); if (holoAPI != null && holoAPI.isEnabled()) { holoAPIEnabled = true; Debugger.getInstance().debug("Hooked HoloAPI v" + holoAPI.getDescription().getVersion()); } } private void setupSpout(PluginManager pm) { Plugin spout = pm.getPlugin("Spout"); if (spout != null && spout.isEnabled()) { spoutEnabled = true; Debugger.getInstance().debug("Hooked Spout v" + spout.getDescription().getVersion()); } } private void setupVault(PluginManager pm) { Plugin vault = pm.getPlugin("Vault"); if (vault != null && vault.isEnabled()) { int ver = PluginVersionChecker.getRelease(vault.getDescription().getVersion()); Debugger.getInstance().debug("Hooked Vault v" + vault.getDescription().getVersion()); vaultLegacyMode = ver < 1003000; // Vault 1.3.0 if (vaultLegacyMode) { LogUtils.warning("Detected an older version of Vault. Proper UUID functionality requires Vault 1.4.1 or later."); } setupEconomy(); setupPermission(); } else { LogUtils.warning("Vault not loaded: no economy command costs & no permission group support"); } } private void setupEconomy() { RegisteredServiceProvider<Economy> economyProvider = getServer().getServicesManager().getRegistration(Economy.class); economy = economyProvider.getProvider(); if (economyProvider == null) { LogUtils.warning("No economy plugin detected - economy command costs not available"); } } private void setupPermission() { RegisteredServiceProvider<Permission> permissionProvider = getServer().getServicesManager().getRegistration(Permission.class); permission = permissionProvider.getProvider(); if (permission == null) { LogUtils.warning("No permissions plugin detected - no permission group support"); } } public boolean isVaultLegacyMode() { return vaultLegacyMode; } private void setupProtocolLib(PluginManager pm) { Plugin pLib = pm.getPlugin("ProtocolLib"); if (pLib != null && pLib instanceof ProtocolLibrary && pLib.isEnabled()) { protocolLibEnabled = true; Debugger.getInstance().debug("Hooked ProtocolLib v" + pLib.getDescription().getVersion()); } } private void setupItemMetaFaker() { faker = new MetaFaker(this, new MetadataFilter() { @Override public ItemMeta filter(ItemMeta itemMeta, Player player) { if (player.getGameMode() == GameMode.CREATIVE) { // messing with item meta in creative mode can have unwanted consequences return null; } if (!ActiveItem.isActiveItem(itemMeta)) { String[] f = PopupItem.getPopupItemFields(itemMeta); if (f == null) { return null; } } // strip the last line from the lore for active items & popup items List<String> newLore = new ArrayList<String>(itemMeta.getLore()); newLore.remove(newLore.size() - 1); ItemMeta newMeta = itemMeta.clone(); newMeta.setLore(newLore); return newMeta; } }); } private void registerCommands() { cmds.registerCommand(new AddItemCommand()); cmds.registerCommand(new AddMacroCommand()); cmds.registerCommand(new AddViewCommand()); cmds.registerCommand(new CreateMenuCommand()); cmds.registerCommand(new DeleteMenuCommand()); cmds.registerCommand(new EditMenuCommand()); cmds.registerCommand(new FontCommand()); cmds.registerCommand(new GetConfigCommand()); cmds.registerCommand(new GiveCommand()); cmds.registerCommand(new ItemUseCommand()); cmds.registerCommand(new ListMacroCommand()); cmds.registerCommand(new ListMenusCommand()); cmds.registerCommand(new MenuCommand()); cmds.registerCommand(new PageCommand()); cmds.registerCommand(new ReloadCommand()); cmds.registerCommand(new RemoveItemCommand()); cmds.registerCommand(new RemoveMacroCommand()); cmds.registerCommand(new RemoveViewCommand()); cmds.registerCommand(new RepaintCommand()); cmds.registerCommand(new SaveCommand()); cmds.registerCommand(new SetConfigCommand()); cmds.registerCommand(new UndeleteMenuCommand()); cmds.registerCommand(new VarCommand()); cmds.registerCommand(new ViewCommand()); } private void registerCommandlets() { cmdlets.registerCommandlet(new AfterCommandlet()); cmdlets.registerCommandlet(new CooldownCommandlet()); cmdlets.registerCommandlet(new PopupCommandlet()); cmdlets.registerCommandlet(new SubmenuCommandlet()); cmdlets.registerCommandlet(new CloseSubmenuCommandlet()); cmdlets.registerCommandlet(new ScriptCommandlet()); cmdlets.registerCommandlet(new QuickMessageCommandlet()); } private void loadPersistedData() { SMSPersistence.loadMacros(); SMSPersistence.loadVariables(); SMSPersistence.loadMenus(); SMSPersistence.loadViews(); } public static URL makeImageURL(String path) throws MalformedURLException { if (path == null || path.isEmpty()) { throw new MalformedURLException("file must be non-null and not an empty string"); } return makeImageURL(ScrollingMenuSign.getInstance().getConfig().getString("sms.resource_base_url"), path); } public static URL makeImageURL(String base, String path) throws MalformedURLException { if (path == null || path.isEmpty()) { throw new MalformedURLException("file must be non-null and not an empty string"); } if ((base == null || base.isEmpty()) && !path.startsWith("http:")) { throw new MalformedURLException("base URL must be set (use /sms setcfg resource_base_url ..."); } if (path.startsWith("http:") || base == null) { return new URL(path); } else { return new URL(new URL(base), path); } } @Override public Object onConfigurationValidate(ConfigurationManager configurationManager, String key, Object oldVal, Object newVal) { if (key.equals("scroll_type")) { try { SMSScrollableView.ScrollType t = SMSGlobalScrollableView.ScrollType.valueOf(newVal.toString().toUpperCase()); DHValidate.isTrue(t != SMSGlobalScrollableView.ScrollType.DEFAULT, "Scroll type must be one of SCROLL/PAGE"); } catch (IllegalArgumentException e) { throw new DHUtilsException("Scroll type must be one of SCROLL/PAGE"); } } else if (key.equals("debug_level")) { DHValidate.isTrue((Integer) newVal >= 0, "Debug level must be >= 0"); } else if (key.equals("submenus.back_item.material") || key.equals("inv_view.default_icon")) { try { SMSUtil.parseMaterialSpec(newVal.toString()); } catch (IllegalArgumentException e) { throw new DHUtilsException("Invalid material specification: " + newVal.toString()); } } return newVal; } @Override public void onConfigurationChanged(ConfigurationManager configurationManager, String key, Object oldVal, Object newVal) { if (key.startsWith("actions.spout") && isSpoutEnabled()) { // reload & re-cache spout key definitions SpoutUtils.loadKeyDefinitions(); } else if (key.startsWith("spout.") && isSpoutEnabled()) { // settings which affects how spout views are drawn repaintViews("spout"); } else if (key.equalsIgnoreCase("command_log_file")) { CommandParser.setLogFile(newVal.toString()); } else if (key.equalsIgnoreCase("debug_level")) { Debugger.getInstance().setLevel((Integer) newVal); } else if (key.startsWith("item_prefix.") || key.endsWith("_justify") || key.equals("max_title_lines") || key.startsWith("submenus.")) { // settings which affect how all views are drawn if (key.equals("item_prefix.selected")) { configCache.setPrefixSelected(newVal.toString()); } else if (key.equals("item_prefix.not_selected")) { configCache.setPrefixNotSelected(newVal.toString()); } else if (key.equals("submenus.back_item.label")) { configCache.setSubmenuBackLabel(newVal.toString()); } else if (key.equals("submenus.back_item.material")) { configCache.setSubmenuBackIcon(newVal.toString()); } else if (key.equals("submenus.title_prefix")) { configCache.setSubmenuTitlePrefix(newVal.toString()); } repaintViews(null); } else if (key.equals("coloured_console")) { MiscUtil.setColouredConsole((Boolean) newVal); } else if (key.equals("scroll_type")) { SMSScrollableView.setDefaultScrollType(SMSGlobalScrollableView.ScrollType.valueOf(newVal.toString().toUpperCase())); repaintViews(null); } else if (key.equals("no_physics")) { configCache.setPhysicsProtected((Boolean) newVal); } else if (key.equals("no_break_signs")) { configCache.setBreakProtected((Boolean) newVal); } else if (key.equals("inv_view.default_icon")) { configCache.setDefaultInventoryViewIcon(newVal.toString()); } else if (key.equals("user_variables.fallback_sub")) { configCache.setFallbackUserVarSub(newVal.toString()); } } public ConfigCache getConfigCache() { return configCache; } private void repaintViews(String type) { for (SMSView v : viewManager.listViews()) { if (type == null || v.getType().equals(type)) { v.update(null, new RepaintAction()); } } } public void setupCustomFonts() { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); //noinspection ConstantConditions for (File f : DirectoryStructure.getFontsFolder().listFiles()) { String n = f.getName().toLowerCase(); int type; if (n.endsWith(".ttf")) { type = Font.TRUETYPE_FONT; } else if (n.endsWith(".pfa") || n.endsWith(".pfb") || n.endsWith(".pfm") || n.endsWith(".afm")) { type = Font.TYPE1_FONT; } else { continue; } try { ge.registerFont(Font.createFont(type, f)); Debugger.getInstance().debug("registered font: " + f.getName()); } catch (Exception e) { LogUtils.warning("can't load custom font " + f + ": " + e.getMessage()); } } } private void configCleanup() { String[] obsolete = new String[]{ "sms.maps.break_block_id", "sms.autosave", "sms.menuitem_separator", "sms.persistent_user_vars", "uservar", }; boolean changed = false; Configuration config = getConfig(); for (String k : obsolete) { if (config.contains(k)) { config.set(k, null); LogUtils.info("removed obsolete config item: " + k); changed = true; } } if (changed) { saveConfig(); } } public VariablesManager getVariablesManager() { return variablesManager; } public MenuManager getMenuManager() { return menuManager; } }