[TEMPLATE] Creating a Command-Driven Plugin

Discussion in 'Resources' started by Zenexer, Jan 20, 2011.

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

    Zenexer

    Getting Started: Command-Driven Plugin Template

    Planning is everything. Before reading any further, sit down and plan out the logic of your program. You want to objectify everything: make it extensible, manipulable, usable, and maintainable.

    Your plugin will have two primary classes. The core class is the plugin class itself:

    Code:
    public class TreeBuilder extends JavaPlugin // JavaPlugin is the base for all plugin cores.
    {
    	// This gets called only ONCE each time the server runs.  Almost no initialization should go here: most should be in onEnable.
    	public TreeBuilder(PluginLoader pluginLoader, Server instance, PluginDescriptionFile desc, File folder, File plugin, ClassLoader cLoader) throws IOException
    	{
    		super(pluginLoader, instance, desc, folder, plugin, cLoader);
    		// Were we to require any initialization logic, we would put it here.  Configuration information goes in onEnable, not here, as we want the ability to refresh it.
    	}
    
    	// Hello, world!
    	public void onEnable()
    	{
    		// Print some basic info about the command.  This won't appear in the server's log file, as that would be unnecessary.
    		System.out.println("Loaded " + this.getDescription().getName() + " version " + this.getDescription().getVersion() + ".");
    		
    		// Now the meat of the class: register our listener class.  More about this later.
    		// The priority is tricky to understand; it is vital to set it properly, or things will break.  This should be part of your planning.  See the sticky on this topic.
    		getServer().getPluginManager().registerEvent(Type.PLAYER_COMMAND, new TreeBuilderListener(this), Priority.Low, this);
    	}
    
    	// Goodbye, world.
    	public void onDisable()
    	{
    		// If we had any persistence, we might do a final save here.
    	}
    }
    
    Pretty straightforward, hard to go wrong. Now comes the messy part: the meat of the plugin.

    Code:
    public class TreeBuilderListener extends PlayerListener
    {
    	private final Server server; // Quick access to the server
    	private final TreeBuilder parent; // The plugin core is our portal to the rest of the server.
    
    	public TreeBuilderListener(GeneReal parent)
    	{
    		// Initialize our final variables.
    		this.parent = parent;
    		this.server = parent.getServer();
    	}
    
    	@Override
    	public void onPlayerCommand(PlayerChatEvent event)
    	{
    		if (event.isCancelled()) return; // IMPORTANT: Don't process any further if the command has already been cancelled!
    		
    		Player player = event.getPlayer(); // The player that issued the command
    		String[] sects = event.getMessage().split(" +", 2); // This will contain two strings: the command, and everything else.
    		String[] args = (sects.length > 1 ? sects[1].split(" +") : new String[0]); // This will contain all the arguments after the command, space-delimited.
    		Commands cmd; // This will hold the command ID.  See the Commands enum at the bottom of this class.
    		try
    		{
    			// Determine a matching command based on sects[0], but remove the leading "/".
    			cmd = Commands.valueOf(sects[0].substring(1).toUpperCase()); 
    		}
    		catch (Exception ex)
    		{
    			// The command is either too short (Bukkit is misbehaving) or doesn't match one for which we are listening.
    			return;
    		}
    
    		try
    		{
    			// We can use a switch because we converted the command string into an enum.
    			switch (cmd)
    			{
    			case TREE: // Command was /tree
    				player.getWorld().generateTree(player.getLocation());
    				break;
    
    			case BIGTREE: // Command was /bigtree
    				player.getWorld().generateBigTree(player.getLocation());
    				break;
    
    			default:
    				return; // We forgot to implement a command: treat it as non-existent.
    			}
    		}
    		catch (NoSuchMethodError ex)
    		{
    			// We are running an old version of CraftBukkit that does not support generateTree or generateBigTree.
    			player.sendMessage("The server is not recent enough to support " + sects[0].toLowerCase() + ".");
    		}
    		catch (Exception ex)
    		{
    			// Unexpected error encountered.  Tell the user.  Can be thrown on purpose to notify the user of syntax errors and such.
    			player.sendMessage("§cError: " + ex.getMessage());
    		}
    		
    		// The command has been processed and should be prevented from bubbling.
    		Logger.getLogger("Minecraft").log(Level.INFO, String.format("%1$s issued command: %2$s", player.getName(), event.getMessage())); // Log the use and interception of the command.
    		event.setCancelled(true); // Prevent other plugins from processing the command.
    	}
    
    	// A list of all supported commands, case-insensitive.
    	private enum Commands
    	{
    		TREE,
    		BIGTREE
    	}
    }
    
    I will update this template to match the new command system once permissions are in place.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 6, 2016
  2. Offline

    Ant59

    Thanks so much! This is great.

    Btw, you have a typo. "NoSuchMethodEror" should be "NoSuchMethodError".
     
  3. Offline

    Zenexer

    Thanks and fixed. :)
     
  4. Offline

    Jinux

    EDIT: Meant to say it a little nicer.

    Does anyone know if this will become a standard template? It's very well written, I'm grateful! I was just wondering since I've already got a finished plugin and I don't want to have to re-write it :p

    I will be making sure all future plugins I write stick to this though, it's V. neat.

    Error found on this line:
    Code:
    public TreeBuilderListener(GeneReal parent)
    It has no idea what "GeneReal" Object is and Eclipse wants me to convert it to "Generated" imported from javax.annotation.

    FIXED: Changed GeneReal to TreeBuilder object (the name of the plugin main core)

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 6, 2016
  5. Offline

    mindless728

    why change the String to an enum when you could just as easily test the String (should be faster anyhow) and use if/else if/else blocks of code

    because you could have the listener keep an array that has all of the commands final so it couldn't be changed
     
  6. thanks so much!
    [MERGETIME="1300136586"][/MERGETIME]
    what if we want to add a varible... IE if you are creating a NPC, then how would you give the player the option to supply the name?? Create a variable and use it in the NPC creation?
     
  7. Offline

    Xaw4

    am i wrong, or is this type of writing it really outdated, and this should be mensured?
     
  8. is this outdated?
     
  9. Can someone update this?
     
  10. Offline

    kkreato

    yer im looking for a template to start a simple plugin alot like the /rules command, that displays some texts of line.
     
  11. Offline

    Tagette

    I just released my plugin template if you wanna take a look see.
    Click! <- Click That
     
Thread Status:
Not open for further replies.

Share This Page