Skip to content

Creating an Addon Ability

Jacksonnn edited this page Apr 18, 2018 · 1 revision

Table of Contents

Introduction

This will be a simple tutorial on making a basic ProjectKorra ability called "Splash". This will be a simple ability that will splash other players and do a little bit of damage. To start developing abilities, you will need at least basic experience in both Java and Bukkit/Spigot Plugin Development. This tutorial will be using Eclipse but feel free to use another IDE if you wish to do so. For a full list of requirements, you will need:

Creating the Project

This is very similar to how we create plugins. The only difference is we do not have a class that extends JavaPlugin and we have no plugin.yml. If you know how to do this, skip to the next section. First, create a new project called "Splash" in eclipse. Make sure the project JRE is set to JavaSE-1.7. Keeping it as JavaSE-1.8 will cause errors for people on Java 7 (ProjectKorra still supports Java 7 and building it for Java 8 and above means they won't be able to use your move).



Once you have done that, add the Spigot jar and the ProjectKorra 1.8.0 jar into the classpath so we can use them in our project. If you don't know how to do that, look at this page here. You will know you have done this successfully when you can expand the "Referenced Libraries" package and you can see both of the jars listed.



Now create a package within your projects src folder. This should be named something like me.username.project. If my username was JamesBond007, I could name it me.jamesbond007.splash. It is good practice to make sure the package is all lowercase as well, even if your username includes uppercase letters.

Creating the Main Ability Class

The basics

After that, we are going to create a class in the package called "Splash". For this tutorial, we will be making a Water ability so we are going to make the class extend WaterAbility. After that, make the class implement AddonAbility. There will be a few errors so hover over them and import the required classes and generate the constructor. Your code should look something like this.

	@Override
	public Location getLocation() {
		return null;
	}

	@Override
	public String getName() {
		return null;
	}

	@Override
	public boolean isHarmlessAbility() {
		return false;
	}

	@Override
	public boolean isSneakAbility() {
		return false;
	}

	@Override
	public void progress() {

	}

	@Override
	public String getAuthor() {
		return null;
	}

	@Override
	public String getVersion() {
		return null;
	}

	@Override
	public void load() {
		// TODO Auto-generated method stub

	}

	@Override
	public void stop() {
	}
	
	@Override
	public String getDescription() {
		return null;
	}
}

First, you are going to want to fill out the basic information. Here is a brief explanation of what all the methods are:

  • getCooldown() - How long the default cooldown of the move is. This is measured in milliseconds.
  • getLocation() - The default location the move is based at. Ignore this for now.
  • getName() - The name of the ability that users have to bind. Can't contain spaces or any special characters that players can't type in chat (don't use color codes either. PK will color it for you)
  • isHarmlessAbility() - If the ability is harmless to players or not. Should be true or false. In our case, we want to keep this to false since it can damage players.
  • isSneakAbility() - If the ability requires the player to shift at ANY POINT during the move. This should also be true or false. Again, in our case, we are keeping this at false.
  • progress() - This is where all the magic happens. Every tick our ability is active (every 1/20 of a second), this method is run. This is where we make the ability move, show particles, check for collisions, etc. Leave this blank for now; we will get back to it later!
  • getAuthor() - The name of the creator who made this ability. Go on and put your name!
  • getVersion() - The version of the ability. When you add a feature or fix a bug, you should increase this so people know this version is different from the last! Set this to 1.0 for now.
  • load() - This method is run when the ability is added to ProjectKorra and is where we define things like event listeners and load stuff from the config. We will come back to this later as well, so leave this blank for now.
  • stop() - This method is pretty much the opposite of load(). It is run when ProjectKorra is being disabled from something like if the server stops. If you have any code that MUST be run before the plugin is unloaded (for example, running code that stops permanent damage to the world), put it here.
We are also going to define some fields that we are going to use in our ability while we're at it. Put these above the constructor.
	private static double moveSpeed = 0.8; //How fast the ability moves. Measured in blocks per tick.
	private static double collisionRadius = 0.8; //The radius entities can be in to be considered a collision
	private static double damage = 1; //How much damage the ability will do. Measured in half-hearts
	private static int range = 20; //How far the ability can travel before getting removed. Measured in blocks.
	private static long duration = 5000L; //How long the ability can exist before being removed. Measured in milliseconds.
	
	private Location location; //The current location of the ability

After you have that and have filled out the basic fields, it should look something like this!

	private static double moveSpeed = 0.8;
	private static double collisionRadius = 0.8;
	private static double damage = 1;
	private static int range = 20;
	private static long duration = 5000L;
	
	private Location location;

	public Splash(Player player) {
		super(player);
	}

	@Override
	public long getCooldown() {
		return 2000L;
	}

	@Override
	public Location getLocation() {
		return location;
	}

	@Override
	public String getName() {
		return "Splash";
	}

	@Override
	public boolean isHarmlessAbility() {
		return false;
	}

	@Override
	public boolean isSneakAbility() {
		return false;
	}

	@Override
	public void progress() {
		// TODO Auto-generated method stub

	}

	@Override
	public String getAuthor() {
		return "Mr. Fantastic";
	}

	@Override
	public String getVersion() {
		return "1.0";
	}

	@Override
	public void load() {

	}

	@Override
	public void stop() {

	}
}

The Constructor

At the moment, this is all the constructor has.

public class Splash(Player player) {
	super(player);
}
super(player) prepares lots of things for us to use later in the ability. For now, add this code to the constructor.
if (!bPlayer.canBend(this)) {
	return;
}

location = player.getEyeLocation().clone();

bPlayer.addCooldown(this);

start();

To explain it briefly:

  • bPlayer.canBend(this) - This tests if the player can currently use the ability. This tests for things like if they have the required elements, if they are on the correct slot, if the move is on cooldown, etc. bPlayer is defined when super(player) is called and contains lots of bending information on players. We are testing if the player cannot use the move, and if so, return and cancel the move from activating.
  • location = player.getEyeLocation().clone() - Sets the location of the ability to the player's head location.
  • bPlayer.addCooldown(this) - Puts the move currently on cooldown so the player can't activate the move until the cooldown has expired. Passing 'this' as an argument gets the cooldown defined in getCooldown().
  • start() - This makes the ability start progressing and running progress() every tick. If this isn't called, progress() will never be run and nothing will ever happen in the move.

Start, Progress and Remove

There are three methods that we will use mainly to control our ability. start(), progress() and remove()

start()

This method should be run when we want our ability to start progressing (running progress() every tick) and is usually called in the constructor of our abilities.

progress()

We've touched the progress() method briefly above when we explained that this method is run every tick (every 1/20 of a second). Progress() will constantly be run while the ability is active and will continue to run until remove() is called.

remove()

MORE COMING SOON

Please check back later for the rest of the tutorial!

Last updated 10/15/16