[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. Offline

    tips48

    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. Offline

    tips48

    is this outdated?
     
  9. Offline

    Adamki11s

  10. Offline

    BLAH

    Can someone update this?
     
  11. Offline

    kkreato

    yer im looking for a template to start a simple plugin alot like the /rules command, that displays some texts of line.
     
  12. 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