// $Id$
/*
* CommandBook
* Copyright (C) 2010, 2011 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.commandbook;
import com.sk89q.bukkit.util.CommandsManagerRegistration;
import com.sk89q.commandbook.commands.CommandBookCommands;
import com.sk89q.commandbook.config.LegacyCommandBookConfigurationMigrator;
import com.sk89q.commandbook.session.SessionComponent;
import com.sk89q.minecraft.util.commands.*;
import com.sk89q.util.yaml.YAMLFormat;
import com.sk89q.util.yaml.YAMLProcessor;
import com.zachsthings.libcomponents.InjectComponent;
import com.zachsthings.libcomponents.InjectComponentAnnotationHandler;
import com.zachsthings.libcomponents.bukkit.BasePlugin;
import com.zachsthings.libcomponents.bukkit.DefaultsFileYAMLProcessor;
import com.zachsthings.libcomponents.bukkit.YAMLNodeConfigurationNode;
import com.zachsthings.libcomponents.bukkit.YAMLProcessorConfigurationFile;
import com.zachsthings.libcomponents.config.ConfigurationFile;
import com.zachsthings.libcomponents.loader.ClassLoaderComponentLoader;
import com.zachsthings.libcomponents.loader.ConfigListedComponentLoader;
import com.zachsthings.libcomponents.loader.JarFilesComponentLoader;
import com.zachsthings.libcomponents.loader.StaticComponentLoader;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.yaml.snakeyaml.error.YAMLException;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Base plugin class for CommandBook.
*
* @author sk89q
*/
public final class CommandBook extends BasePlugin {
private static CommandBook instance;
private CommandsManager<CommandSender> commands;
private Map<String, Integer> itemNames;
public boolean broadcastChanges;
public boolean useDisplayNames;
public boolean lookupWithDisplayNames;
public boolean crappyWrapperCompat;
public CommandBook() {
super();
instance = this;
}
public static CommandBook inst() {
return instance;
}
public static Logger logger() {
return inst().getLogger();
}
public static void registerEvents(Listener listener) {
server().getPluginManager().registerEvents(listener, inst());
}
/**
* Called when the plugin is enabled. This is where configuration is loaded,
* and the plugin is setup.
*/
public void onEnable() {
super.onEnable();
// Register the commands that we want to use
final CommandBook plugin = this;
commands = new CommandsManager<CommandSender>() {
@Override
public boolean hasPermission(CommandSender player, String perm) {
return plugin.hasPermission(player, perm);
}
};
final CommandsManagerRegistration cmdRegister = new CommandsManagerRegistration(this, commands);
if (lowPriorityCommandRegistration) {
getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
@Override
public void run() {
cmdRegister.register(CommandBookCommands.CommandBookParentCommand.class);
}
}, 1L);
} else {
cmdRegister.register(CommandBookCommands.CommandBookParentCommand.class);
}
}
public void registerComponentLoaders() {
// -- Component loaders
final File configDir = new File(getDataFolder(), "config/");
componentManager.addComponentLoader(new StaticComponentLoader(getLogger(), configDir, new SessionComponent()) {
@Override
public ConfigurationFile createConfigurationNode(File file) {
return new YAMLProcessorConfigurationFile(new YAMLProcessor(file, true, YAMLFormat.EXTENDED));
}
});
final YAMLProcessor jarComponentAliases = new DefaultsFileYAMLProcessor("components.yml", false);
try {
jarComponentAliases.load();
} catch (IOException e) {
getLogger().severe("Error loading component aliases!");
e.printStackTrace();
} catch (YAMLException e) {
getLogger().severe("Error loading component aliases!");
e.printStackTrace();
}
componentManager.addComponentLoader(new ConfigListedComponentLoader(getLogger(),
new YAMLNodeConfigurationNode(config),
new YAMLNodeConfigurationNode(jarComponentAliases), configDir));
for (String dir : config.getStringList("component-class-dirs", Arrays.asList("component-classes"))) {
final File classesDir = new File(getDataFolder(), dir);
if (!classesDir.exists() || !classesDir.isDirectory()) {
classesDir.mkdirs();
}
componentManager.addComponentLoader(new ClassLoaderComponentLoader(getLogger(), classesDir, configDir) {
@Override
public ConfigurationFile createConfigurationNode(File file) {
return new YAMLProcessorConfigurationFile(new YAMLProcessor(file, true, YAMLFormat.EXTENDED));
}
});
}
for (String dir : config.getStringList("component-jar-dirs", Arrays.asList("component-jars"))) {
final File classesDir = new File(getDataFolder(), dir);
if (!classesDir.exists() || !classesDir.isDirectory()) {
classesDir.mkdirs();
}
componentManager.addComponentLoader(new JarFilesComponentLoader(getLogger(), classesDir, configDir) {
@Override
public ConfigurationFile createConfigurationNode(File file) {
return new YAMLProcessorConfigurationFile(new YAMLProcessor(file, true, YAMLFormat.EXTENDED));
}
});
}
// -- Annotation handlers
componentManager.registerAnnotationHandler(InjectComponent.class, new InjectComponentAnnotationHandler(componentManager));
}
/**
* Called on a command.
*/
@Override
public boolean onCommand(CommandSender sender, Command cmd,
String commandLabel, String[] args) {
try {
commands.execute(cmd.getName(), args, sender, sender);
} catch (CommandPermissionsException e) {
sender.sendMessage(ChatColor.RED + "You don't have permission.");
} catch (MissingNestedCommandException e) {
sender.sendMessage(ChatColor.RED + e.getUsage());
} catch (CommandUsageException e) {
sender.sendMessage(ChatColor.RED + e.getMessage());
sender.sendMessage(ChatColor.RED + e.getUsage());
} catch (WrappedCommandException e) {
if (e.getCause() instanceof NumberFormatException) {
sender.sendMessage(ChatColor.RED + "Number expected, string received instead.");
} else {
sender.sendMessage(ChatColor.RED + "An error has occurred. See console.");
e.printStackTrace();
}
} catch (CommandException e) {
sender.sendMessage(ChatColor.RED + e.getMessage());
}
return true;
}
/**
* Loads the configuration.
*/
@Override
public YAMLProcessor createConfiguration() {
final File configFile = new File(getDataFolder(), "config.yml");
YAMLProcessor config = new YAMLProcessor(configFile, true, YAMLFormat.EXTENDED);
YAMLProcessor comments = new DefaultsFileYAMLProcessor("config-comments.yml", false);
try {
if (!configFile.exists()) {
configFile.getParentFile().mkdirs();
configFile.createNewFile();
}
config.load();
comments.load();
} catch (Exception e) {
getLogger().log(Level.WARNING, "Error loading configuration: ", e);
}
for (Map.Entry<String, Object> e : comments.getMap().entrySet()) {
if (e.getValue() != null) {
config.setComment(e.getKey(), e.getValue().toString());
}
}
// Migrate the old configuration, if we need to
final String result = new LegacyCommandBookConfigurationMigrator(configFile, config).migrate();
if (result != null) {
logger().severe("Error migrating CommandBook configuration: " + result);
}
return config;
}
@Override
public void populateConfiguration(YAMLProcessor config) {
loadItemList(config);
useDisplayNames = config.getBoolean("use-display-names", true);
lookupWithDisplayNames = config.getBoolean("lookup-with-display-names", true);
broadcastChanges = config.getBoolean("broadcast-changes", true);
crappyWrapperCompat = config.getBoolean("crappy-wrapper-compat", true);
if (crappyWrapperCompat) {
getLogger().info("Maximum wrapper compatibility is enabled. " +
"Some features have been disabled to be compatible with " +
"poorly written server wrappers.");
}
}
/**
* Loads the item list.
*
* @param config The {@link YAMLProcessor} to load from
*/
protected void loadItemList(YAMLProcessor config) {
// Load item names aliases list
Object itemNamesTemp = config.getProperty("item-names");
if (itemNamesTemp != null && itemNamesTemp instanceof Map) {
itemNames = new HashMap<String, Integer>();
try {
Map<?, ?> temp = (Map<?, ?>) itemNamesTemp;
for (Map.Entry<?, ?> entry : temp.entrySet()) {
String name = entry.getKey().toString().toLowerCase();
// Check if the item ID is a number
if (entry.getValue() instanceof Integer) {
itemNames.put(name, (Integer) entry.getValue());
}
}
} catch (ClassCastException ignore) {
}
} else {
itemNames = new HashMap<String, Integer>();
}
}
public Map<String, Integer> getItemNames() {
return Collections.unmodifiableMap(itemNames);
}
}