Abstract Plugin Wrapper (w/new onCommand support)

Discussion in 'Plugin Development' started by Schirf, Feb 3, 2011.

Thread Status:
Not open for further replies.
  1. Offline

    Schirf

    The idea behind these three classes is that I can throw them into any of my plugins and have uniform command and configuration file handling ... I simply need to extend XrfBukkitPlugin instead of JavaPlugin.

    Code:
    import java.io.File;
    import org.bukkit.Server;
    import org.bukkit.plugin.PluginDescriptionFile;
    import org.bukkit.plugin.PluginLoader;
    import org.bukkit.plugin.java.JavaPlugin;
    import org.bukkit.entity.Player;
    import org.bukkit.command.CommandSender;
    import org.bukkit.command.Command;
    
    public abstract class XrfBukkitPlugin extends JavaPlugin {
        protected final XrfCommandListener commandListener = new XrfCommandListener(this);
        static String pluginName;
        static String pluginVersion;
    
        public XrfBukkitPlugin(PluginLoader pluginLoader, Server instance,
                PluginDescriptionFile desc, File folder, File plugin,
                ClassLoader cLoader)
        {
            super(pluginLoader, instance, desc, folder, plugin, cLoader);
    
            PluginDescriptionFile ymlFile = this.getDescription();
    
            pluginName = ymlFile.getName();
            pluginVersion = ymlFile.getVersion();
    
            new File(pluginName).mkdir();
            String propertiesFile = ymlFile.getName() + "/Config.properties";
            XrfPluginProperties properties = new XrfPluginProperties(propertiesFile);
            properties.load();
    
            this.initialize(properties);
    
            properties.save("== " + pluginName + " Configuration ==");
        }
    
        @Override
        public void onDisable() {
            System.out.println ( pluginName + " disabled.");
        }
    
        @Override
        public void onEnable() {
            System.out.println ( pluginName + " version " + pluginVersion + " enabled." );
        }
    
        protected abstract void initialize(XrfPluginProperties properties);
        public abstract boolean isPlayerRequired();
        public abstract boolean isCommandValid(String commandtext);
        public abstract boolean isArgArrayValid(String commandtext, String[] args);
        public abstract void processCommand(Player player, String commandtext, String[] args);
        public abstract void processInvalid(Player player, String commandtext, String[] args);
    
        public boolean onCommand(CommandSender sender, Command command, String commandLabel, String[] args)    {
            String commandtext = command.getName();
    
            if (this.isEnabled())
            {
                if (this.isCommandValid(commandtext)) {
                    if (sender instanceof Player) {
                        Player player = (Player)sender;
                        if (this.isArgArrayValid(commandtext, args)) {
                                this.processCommand(player, commandtext, args);
                                return true;
                        } else {
                                this.processInvalid(player, commandtext, args);
                                return true;
                        }
                    } else {
                        if (!this.isPlayerRequired()) {
                            if (this.isArgArrayValid(commandtext, args)) {
                                this.processCommand(null, commandtext, args);
                                return true;
                            }
                        }
                    }
                }
            }
            return false;
        }
    }
    
    Code:
    
    import org.bukkit.event.player.PlayerListener;
    
    public class XrfCommandListener extends PlayerListener {
        @SuppressWarnings("unused")
        private static XrfBukkitPlugin plugin;
        public XrfCommandListener (XrfBukkitPlugin instance) {
            plugin = instance;
    
        }
    }
    
    
    Code:
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.Properties;
    
    public class XrfPluginProperties extends Properties {
        static final long serialVersionUID = 0L;
        private String fileName;
    
        public XrfPluginProperties(String file) {
            this.fileName = file;
        }
    
        public void load() {
            File file = new File(this.fileName);
    
            if (file.exists()) {
                try { load(new FileInputStream(this.fileName));
                } catch ( IOException ex ) {
    
                }
            }
        }
    
        public int getInteger(String key, int defaultValue) {
            int result = defaultValue;
            boolean found = false;
            if (containsKey(key)) {
                try {
                    result = Integer.parseInt(getProperty(key));
                    found = true;
                }
                catch (NumberFormatException nfe)
                { }
            }
    
            if (!found) {
                put(key,String.valueOf(defaultValue));
                result = defaultValue;
            }
    
            return result;
        }
    
        public double getDouble(String key, double defaultValue) {
            double result = defaultValue;
            boolean found = false;
    
            if (containsKey(key)) {
                try {
                    result = Double.parseDouble(getProperty(key));
                    found = true;
                }
                catch (NumberFormatException nfe)
                { }
            }
    
            if (!found) {
                put(key, String.valueOf(defaultValue));
                result = defaultValue;
            }
            return result;
        }
    
        public String getString(String key, String defaultValue) {
            if (containsKey(key)) {
                return getProperty(key);
            }
    
            put(key, defaultValue);
            return defaultValue;
        }
    
        public boolean getBoolean(String key, boolean defaultValue) {
            if (containsKey(key)) {
                String boolString = getProperty(key);
                return (boolString.length() > 0)
                        && (boolString.toLowerCase().charAt(0) == 't');
            }
            put(key, defaultValue ? "true" : "false");
            return defaultValue;
        }
    
        public void save(String firstLine) {
            try
            { this.store(new FileOutputStream(this.fileName), firstLine ); }
            catch (IOException ex)
            {    }
        }
    }
    --- merged: Feb 4, 2011 2:11 AM ---
    Tomorrow, permissions support...
     
  2. Offline

    Mixcoatl

    This is pretty neat.
    I've been working on something similar, although it's not updated for the new command changes yet. It moves command handling away from the onCommand/onPlayerCommand hooks entirely. Instead, the programmer implements an interface for each command and registers it with a dispatcher.
    The framework supports some interesting features:
    • More than one command alias can refer to the same command implementation.
    • Programmatic command discovery (you can enumerate the registered command implementations).
    • Commands expose their help text through accessors so all commands, regardless of the plug-in that provides them, appear in the help list in a consistent, uniform manner.
    Permissions will be fully integrated when I finish writing them (we need multiple permission groups per player on my server so I cannot using the existing permissions plug-in to pull this off).
    --- merged: Feb 4, 2011 3:12 AM ---
    Upon taking a glance at GitHub, it appears one can get about 2/3rds of what I've done by directly subclassing the new Command class. I suppose an interesting question might be, "What do we break by doing this?" Quite simply, I abhor the if-switch of string comparisons we must do to handle commands now. There is no reason the framework shouldn't do the lookup and dispatch for us.
     
Thread Status:
Not open for further replies.

Share This Page