Creating your own powers - sirrus86/S86Powers GitHub Wiki
Note: This page is a work in progress and is not yet complete.
Since S86 Powers v4.0, it's been possible for those familiar with Java development to create and import their own power classes into S86 Powers. With the complete rewrite of the plugin in v5.0, the old process is similar but with a few key differences. This page will describe the whole process of starting your own power class.
Before getting started, let me first state the following:
- I consider myself at best a novice in Java. Some of my coding methods may be improper and inefficient. If you know a better way to accomplish something here, by all means use it.
- I use the Eclipse IDE for creating Java applications, and will refer to it on this page.
- While using something like Maven or Gradle is an option, the below steps will take the more direct approach of adding the plugin into the build path.
To create and test your own power classes, the following is required:
- Basic knowledge of creating a Java application.
- An IDE for creating Java applications (e.g. Eclipse, IntelliJ, etc).
- S86 Powers v5.0 or higher.
- A recent version of Bukkit, CraftBukkit, Spigot, or Paper for accessing the server API and, optionally, the server's NMS classes.
- A dedicated server to test the created power class.
Again, keep in mind that these steps follow the process as though Eclipse is the IDE being used. If you prefer a different one, follow the equivalent steps.
- Create a new Java Project. Minecraft currently requires Java 8, so build the project with JavaSE-1.8 or comparable.
- Add both the server JAR file and the S86 Powers JAR file to the build path of the project.
- Within the project, create a package where you will store your power classes. Note that unlike when creating plugins, your classes don't have to extends JavaPlugin or have a main class.
- Create a new class within the created package. The name of the class is important, as players need to use this name when referencing the power in game. For example, the power Acid Blood comes from the class AcidBlood. The proper name of the power will be set in the next section.
By this point you should have a class that looks like this:
package me.sirrus86.s86test;
public class TestPower {
}
For a class to be read by S86 Powers, it requires two things: it must include a complete PowerManifest
annotation, and it must extend the Power
class.
- Above the
public class
line, type@PowerManifest
. You will need to import theme.sirrus86.s86powers.powers.PowerManifest
class for this step. -
PowerManifest
has a several required fields, along with a few optional ones:-
name
must be set to the proper name for the power. This can include spaces and some special characters. -
type
is the power's type. This requires importingme.sirrus86.s86powers.powers.PowerType
.PowerType
is an enum from which you can pick fromDEFENSE
,OFFENSE
,PASSIVE
, andUTILITY
. Note that pickingUTILITY
makes the power unassignable and active for everyone. -
author
is the name of whoever created this power. This can be your name or an alias. -
concept
is the name of whoever came up with the idea for this power. If it's your own idea, then just put your name here again. -
icon
is the item material used for creating the 'icon' for this power in the GUI. This requires importingorg.bukkit.Material
. -
description
is the full description of what this power does. Since what powers do can change depending on what options are set, this field is kept dynamic by changing parts of the description when viewed by players. More info on how to accomplish this is provided below. -
server
is an optional field (plugin version 5.1.5+) denoting which server software this power was built for. This requires importing the enumeratorme.sirrus86.s86powers.tools.version.MCServer
. This field should be set if it contains code that can't be read by all server software. The current available values are Bukkit, Spigot, and Paper. Paper is assumed to be able to do nearly anything Spigot can, and Spigot is assumed to be able to do nearly anything Bukkit can. Therefore, setting this to Paper will prevent Spigot and Bukkit servers from loading the power, whereas setting this to Bukkit means any of the three can load it. If this field is omitted, it is assumed any Bukkit-based server software can run this power. -
version
is an optional field denoting the minimum version of Minecraft required to use this power. This requires importing the enumeratorme.sirrus86.s86powers.tools.version.MCVersion
. This field should be set if it contains code that can't be read by previous versions of Minecraft or the server API. For example, if your power makes use of fox mobs, you would set this to MCVersion.v1_14 since versions before 1.13 didn't have foxes. In this example, if a server running MC 1.13 tries to load this power, it will be told not to because the server version is too low. If this field is omitted, it is assumed that any version of Minecraft from 1.13 and up can run this power. -
incomplete
is an optional field denoting that this power class isn't complete and shouldn't normally be loaded. Setting this field totrue
will prevent servers from loading this power unless they have the server optionpowers.load-incomplete-powers
set totrue
. If omitted, this field is set tofalse
.
-
- Next, the class must extend the
Power
class to work. This requires importingme.sirrus86.s86powers.powers.Power
. - Power classes currently only have one required method, a void method called
options()
. Create this method within the main class and have it override the super method.
At this point your class should look something like this:
package me.sirrus86.s86test;
import org.bukkit.Material;
import me.sirrus86.s86powers.powers.Power;
import me.sirrus86.s86powers.powers.PowerManifest;
import me.sirrus86.s86powers.powers.PowerType;
@PowerManifest(name = "Test Power", type = PowerType.OFFENSE, author = "sirrus86", concept = "someone else", icon = Material.LAVA_BUCKET,
description = "Lets the user do some fancy stuff.")
public final class TestPower extends Power {
@Override
protected void options() {
}
}
Congrats, you now have the core elements of a power class! Everything that follows may vary wildly depending on the needs for the power.
Options are what allow servers to customize powers how they see fit. The more options a power has, the more possibilities that exist. The process of creating configurable options has been made to work as easily and smoothly as possible for all involved, including both servers and developers.
To create an option, you must first create the field which will read the option value. To make it accessible to the entire class, it is recommended (and usually mandatory) to create the field in the main class.
public final class TestPower extends Power {
private int count;
private double percent;
private String phrase;
private ItemStack stack;
@Override
protected void options() {
}
}
With these created, you will now use the option() method within the options() method to initialize their values.
public final class TestPower extends Power {
private int count;
private double percent;
private String phrase;
private ItemStack stack;
@Override
protected void options() {
count = option("number-count", 5, "Number to count to before something happens.");
percent = option("percentage", 50.0D, "Percent chance for something else to happen.");
phrase = option("strings-for-things", "I am a customizable phrase!", "Phrase to be sent to a player.");
stack = option("held-item", new ItemStack(Material.STICK, 1), "Item player must hold to use this power.");
}
}
In the above example, we've assigned a value to all four fields, while also giving them a path in the power's config, as well as a description of what each option does. Below we'll break down what each part of the option() method does:
The first argument is a string denoting the config path for this option. When the power is loaded on a server for the first time, it creates a config file. Shortly after, the options() method is read, along with each option() method inside. The path in the option() method tells the plugin where to store this option in the config, as well as where to read it later.
The second argument is the initial value of this option. This not only tells the plugin what value to use should the config be missing or unreadable, but also determines the field type of the method. This is also the value put into the config file when it is originally created.
The third argument is the description of the option. This isn't saved to the config file, and is only viewed when someone tries to look up info on the option via command /powers power <power> option <option>
.