First (ish) plugin help

Discussion in 'Spigot Plugin Development' started by Foxtrek_64, Jan 4, 2016.

  1. Hello all!

    I'm here today to get pointers for my first plugin. The "ish" part in the title is because I've written other plugins before but I have never completed them. This plugin, while untested, will likely be my first proper release.

    That being said, the intended function of this plugin is quite simple, at least for version one.

    End User interface:

    Code (Text):
    /title -- Displays this help dialog
    /title ? -- Displays this help dialog
    /title help -- Displays this help dialog
    /title <title> -- Checks if user is a member of the Don1 group (using Vault), and if they are, sets their title to the requested word
    /title [user] <title> -- Checks if the user is in the Don3 group (using Vault), and if they are, sets the requested user's title to the requested word.
    Planned updates in future versions:
    Update deprecated user lookup method from getOfflinePlayer(String)
    Add a (configurable) max length to titles
    Add checking for own username in the last command and allow if they have the Don1 group
    Add a plugin settings yaml to configure user groups, max length, etc.

    Back end functionality:
    This plugin is designed, quite simply, to allow users with permissions (simply by being in the correct group - may need to change this to an actual permission node in near future) to run a command to change their prefix setting inside of PermissionsEx. This prefix node is then passed onto HeroChat to display the user's chosen title.

    Now, the purpose of this plugin in particular is it grants me more granular control over users setting their own or others' prefixes, as well as special formatting added by the program (i.e. the different donator groups get different colors of prefixes to denote each group).

    TL;DR, this is designed mostly to replicate the functionality of EasyTitles, but without restricting a user to a set group of pre-defined titles and in a way that can link in with most available chat plugins (as I'm not handling the hooks).

    So, my reason for coming to you guys today is three fold. First, I would like to get a few opinions on the code itself. I come from a C# background so there are very likely a few syntax errors. If there are any places in the code that can be made more efficient or are done just plain incorrectly, please don't hesitate to tell me. Secondly, if any assistance can be provided on the creation and usage of a configuration yaml file, that would be greatly appreciated. And lastly, is it even worth writing this program? Are there other plugins out there that I may have missed that already do what I'm trying to accomplish?

    I have included the source code below of what I have thus far. The code is mostly commented and written in OOP-style, and has a mix of Java and .NET Camel Case conventions (so sorry if this throws anyone off).

    And of course, there is a license that accompanies this code:
    Code (Text):
    package com.luzfaltex.titles;

    import org.bukkit.Bukkit;
    import org.bukkit.OfflinePlayer;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;
    import org.bukkit.plugin.RegisteredServiceProvider;
    import org.bukkit.plugin.java.JavaPlugin;
    import net.milkbowl.vault.permission.Permission;

    public final class Titles extends JavaPlugin
    {
        //Initialize Vault perms handling
        public static Permission perms = null;
     
        @Override
        public void onEnable()
        {
            getLogger().info("Titles by LuzFaltex is starting...");
            setupPermissions();
        }
     
        @Override
        public void onDisable()
        {
            getLogger().info("Titles by LuzFaltex is closing...");
        }
     
        //Define perms and set up the service provider
        private boolean setupPermissions()
        {
            RegisteredServiceProvider<Permission> rsp = getServer().getServicesManager().getRegistration(Permission.class);
            perms = rsp.getProvider();
            return perms != null;
        }
     
        @Override
        public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args)
        {
            //Only react if they enter /title
            if (cmd.getName().equalsIgnoreCase("title"))
            {
                //That's it? Show them help
                if (args.length == 0)
                {
                    help((Player)sender);
                    return true;
                }
                //They just used one argument
                else if (args.length == 1)
                {
                    //Give them the help they asked for
                    if (args[0].equalsIgnoreCase("help") || args[0].equalsIgnoreCase("?"))
                    {
                        help((Player)sender);
                        return true;
                    }
                    //They want a title
                    else
                    {
                        //Make sure it's a player changing their title and not the console
                        if (sender instanceof Player)
                        {
                            //Do they even have permission?
                            if (perms.has((Player)sender, "don1"))
                            {
                                //Guess so. Send 'sender' as a Player object
                                setPlayerTitle((Player)sender, args[0]);
                                return true;
                            }
                            //They should get permission first
                            else
                            {
                                sender.sendMessage("Sorry! You don't have permission to change your title.");
                                return false;
                            }
                        }
                        //Either the console or an NPC tried to use this
                        else
                        {
                            sender.sendMessage("You must be a player!");
                            return false;
                        }
                    }
                }
                //Changing someone else's
                else if (args.length == 2)
                {
                    //Do they have the perms?
                    if (perms.has((Player)sender, "don3"))
                    {
                        //Indeed they do. Figure out who they're asking for.
                        //Will check string against minecraft.net API in next release
                        Player target = (Player)Bukkit.getOfflinePlayer(args[0]);
                        setPlayertitle(target, (Player)sender, args[1]);
                        return true;
                    }
                 
                    else
                    {
                        sender.sendMessage("Sorry! You don't have permission to change their title.");
                        return false;
                    }
                }
                //They supplied too many arguments
                else
                {
                    sender.sendMessage("Please check syntax.");
                    return false;
                }
            }
            else
            {
                //Not my plugin
                return false;
            }
        }
     
        //Prints usage information
        public void help(Player sender)
        {
            sender.sendMessage("------Plugins------");
            sender.sendMessage("----Version 1.0----");
            sender.sendMessage("Usage:");
            sender.sendMessage("/title [user] <title>");
            sender.sendMessage("Providing the [user] flag allows users with permission");
            sender.sendMessage("to change others' titles");
        }
     
        //Sets the player title. Two overloads. Two arguments changes your own title, three changes another's title
        public void setPlayerTitle(Player target, String title)
        {
            //Get the color code. May change this method as well - possibly a string enum
            String color = donType(target);
         
            try
            {
                //Make sure the player is logged on before sending them the message.
                if (Bukkit.getServer().getPlayer(target.getName()) != null)
                {
                    target.sendMessage(String.format("Your title has been changed to %s", title));
                }
             
                //Log to the console as well
                getLogger().info(String.format("%s has changed their name to %s", target.getName(), title));
             
                //Add the prefix.<prefix> perm -- PermissionsEx /should/ see this and modify their permissions meta node instead
                perms.playerAdd(null, (OfflinePlayer)target, String.format("prefix.%s%s", color, title));
            }
            catch (Exception ex)
            {
                //Spit out any errors to the log we received.
                getLogger().info(ex.getMessage());
            }
         
        }
     
        //Same as last, but has an argument for the person requesting the name change for extra alerting and logging capabilities
        public void setPlayertitle(Player target, Player sender, String title)
        {
            String color = donType(target);
         
            try
            {
                if (Bukkit.getServer().getPlayer(target.getName()) != null)
                {
                    target.sendMessage(String.format("{0} changed your title to {0}", sender, title));
                }
                getLogger().info(String.format("{0} has changed {1}'s name to {2}", sender.getName(), target.getName(), title));
         
                perms.playerAdd(null, (OfflinePlayer)target, String.format("prefix.%s%s", color, title));
            }
            catch (Exception ex)
            {
                getLogger().info(ex.getMessage());
            }
        }
     
        //Returns a color code based off what donator group the user is in. If they're not, they get Grey.
        //This code can be made more efficient by removing donator and having returns under each if.
        public String donType(Player player)
        {
            String donator;
         
            if (perms.has(player, "group.don1"))
            {
                donator = "&7";
            }
            else if (perms.has(player, "group.don2"))
            {
                donator = "&a";
            }
            else if (perms.has(player, "group.don3"))
            {
                donator = "&9";
            }
            //Temporarily removed pending creation
            /*else if (player.hasPermission("group.don4"))
            {
                donator = 4;
            }*/
            else
            {
                donator = "&f";
            }
         
            return donator;
         
        }
    }
     
     
  2. Instead of using getLogger use System.out.prinln(""<yourmsg>);
    instead of using sender.sendMessage(""); add Player p = (Player) sender; then use p.sendMessage("");
     
    • Funny Funny x 2
    • Agree Agree x 1
  3. @Ppeckc using getLogger() the player knows what plugin printed it. You don't need to cast to player to send a message, so using Player#sendMessage is useless if you don't have a player instance for something else.
    @Foxtrek_64 I reccommend making the perms field private and using a getter to retrieve it for the sake of encapsulation. This way no external sources can modify it for some reason. Also, I would recommend making as least things as possible static, as Java is an OOP language as you mentioned. Use constructors to pass the instance to other classes. Also, I would check if the sender is a Player first (using sender instanceof Player). This way, when people make use of the command in the console they don't get spammed by a stacktrace
     
    • Informative Informative x 1
  4. Inkzzz

    Resource Staff

    You don't have to define player object variables if you don't alter player objects. For instance, you could you pass over the CommandSender object and do param#sendMessage(String input)