How to create a basic plugin [part 4]

Denic

Supporter
INTRODUCTION
In this tutorial we will be extending the 3 previous tutorials. This tutorial will be mainly focused on applying the knowledge you've learned thus far to make a functional AND useful plugin. We will be recreating my Hud Plugin in this tutorial.The Javadocs will be referred to a lot in this tutorial. I would recommend pulling them up, or looking through the github repository and exploring through there.

SETUP
At this point you should be fairly familiar with the basic plugin skeleton, so please create a new plugin with the basic skeleton.

CODE
Now that we have our basic plugin skeleton, we can get started! Currently your main class should look like the following:
Code:
public class main extends PluginBase{
    @Override
    public void onEnable()
    {
        this.getLogger().info(TextFormat.GREEN + "Plugin Enabled");
    }
  
    @Override
    public void onDisable()
    {
        this.getLogger().info(TextFormat.RED + "Plugin Disabled");
    }
}
This may seem quite redundant but hear me out. Before any of you should start creating plugins, you should map out the problem at hand. Exactly what the product you are trying to create should look like in the final phase. So coming back to the plugin we are trying to create, (Simple HUD plugin), the main thing that this plugin should feature is its real time coordinate system. The coordinate system should only update once a player moves so right off the bat you can probably tell that we are going to need some sort of event. Now with a quick at the javadocs we can see that we will need the PlayerMoveEvent. Like the name states, this event will fire everytime a player moves. Perfect. So lets create a new events class with the following:
Code:
public class EventsClass implements Listener {

   @EventHandler
   public void onMove(PlayerMoveEvent event) {

   }
}
And lets register this event in the main class
Code:
public class main extends PluginBase{
    @Override
    public void onEnable()
    {
        this.getLogger().info(TextFormat.GREEN + "Plugin Enabled");
        this.getServer().getPluginManager().registerEvents(newEventsClass(), this);
    }
  
    @Override
    public void onDisable()
    {
        this.getLogger().info(TextFormat.RED + "Plugin Disabled");
    }
}
Alright, now we have our event setup and ready to go! Now that we have events class setup, we can simply grab the players X, Y, and Z coordinates that we can then send to the player through an actionbar message. This is what I like to call the action phase. This phase refers to the actual output or results that the player is seeing when doing actions. So add the following code to your EventsClass:
Code:
public class EventsClass implements Listener {

   @EventHandler
   public void onMove(PlayerMoveEvent event) {
        Player movedPlayer = event.getPlayer();
        int x = (int) movedPlayer.x;
        int y = (int) movedPlayer.y;
        int z = (int) movedPlayer.z;
        movedPlayer.sendPopup(x + ", " + y + ", " + z);
   }
}
Great! Now we are outputting the coordinates to the player when they move. But there are a few flaws in this design. First off, storing variables every time in this scenario is redundant because not only does it add more clutter to the code, it also creates more values in memory. And secondly, there is no sort of customization outside of the code. These are two design flaws that can be fixed in the final phase called the polishing phase. This phase is meant for better looking code and optimization that can speed up the server performance and your coding efficiency. This phase can lead to many different paths depending on your satisfactory in the code. The first path being a final polish and being satisfied with your code. This path will become more frequent as time goes on and you adopt a developer mindset. The second path and most diminishing path is the path I like to call the "Oh frick oh no path". This path generally leads to a complete or partial rewrite of the code you just wrote with a better approach. Well thats enough ranting. So lets fix these design flaws. Now to fix the customization design flaw we can simply add a String to the config.yml called format. Lets add this now:
Code:
format: %X%, %Y%, %Z%
This might be a bit confusing but hear me out. These %value% things are called placeholders. There is no real reason for the % symbols. That part is all up to preference, but for the sake of this tutorial we will be using that standard format. Now that we have that, lets explain what exactly these so called "placeholders" are. Well, they are simply values or pieces in a string that will be replaced later on with a new value. For example, if I have the String "%subject% is cool!" and I replace the placeholder called %subject% with math we will get the output of "math is cool!" and so on. Now that we have this format set inside of our config, we should grab it from the config file and store it to a local variable inside of our EventsClass class by adding the following to the Main class:
Code:
public class main extends PluginBase{
    @Override
    public void onEnable()
    {
        this.getLogger().info(TextFormat.GREEN + "Plugin Enabled");
        this.getServer().getPluginManager().registerEvents(newEventsClass(), this);
        EventsClass.format = this.getConfig().getString("format");
    }
  
    @Override
    public void onDisable()
    {
        this.getLogger().info(TextFormat.RED + "Plugin Disabled");
    }
}
And creating the variable for format inside of the EventsClass class by doing the following:
Code:
public class EventsClass implements Listener {
   public static String format;
   @EventHandler
   public void onMove(PlayerMoveEvent event) {
        Player movedPlayer = event.getPlayer();
        int x = (int) movedPlayer.x;
        int y = (int) movedPlayer.y;
        int z = (int) movedPlayer.z;
        movedPlayer.sendPopup(x + ", " + y + ", " + z);
   }
}
Great! And for the final step, we can replace these placeholders inside of the format with the corresponding value WHILE getting rid of the local variables and redundancy! Two birds with one stone must I say. We can do so with the following:

Code:
public class EventsClass implements Listener {
   public static String format;
   @EventHandler
   public void onMove(PlayerMoveEvent event) {
        Player movedPlayer = event.getPlayer();
        movedPlayer.sendPopup(format
        .replace("%X%", "" + (int) movedPlayer.x)
        .replace("%Y%", "" + (int) movedPlayer.y)
        .replace("%Z%", "" + (int) movedPlayer.Z));
   }
}
And that's it! You have successfully created a Hud Plugin. Simply compile the plugin and place it in your server plugins folder. In the end both classes should look like this:

Main

Code:
public class main extends PluginBase{
    @Override
    public void onEnable()
    {
        this.getLogger().info(TextFormat.GREEN + "Plugin Enabled");
        this.getServer().getPluginManager().registerEvents(newEventsClass(), this);
        EventsClass.format = this.getConfig().getString("format");
    }
  
    @Override
    public void onDisable()
    {
        this.getLogger().info(TextFormat.RED + "Plugin Disabled");
    }
}
EventsClass
Code:
public class EventsClass implements Listener {
   public static String format;
   @EventHandler
   public void onMove(PlayerMoveEvent event) {
        Player movedPlayer = event.getPlayer();
        movedPlayer.sendPopup(format
        .replace("%X%", "" + (int) movedPlayer.x)
        .replace("%Y%", "" + (int) movedPlayer.y)
        .replace("%Z%", "" + (int) movedPlayer.Z));
   }
}

CONCLUSION
Congratulations! In this tutorial you should have learned how to apply the knowledge from the previous three tutorials to create a fully functional Hud Plugin whilst learning about a developer mindset that will allow you to create almost any plugin you desire.

Thank you all for reading this tutorial! If you have any questions or suggestions feel free to send them to my Discord: Civiled#8337
 
Top