14 KiB
Overview
This page will cover how you can create your own PlaceholderExpansion
which you can either Upload to the eCloud or integrate into your own plugin.
It's worth noting that PlaceholderAPI relies on expansions being installed. PlaceholderAPI only acts as the core replacing utility while the expansions allow other plugins to use any installed placeholder in their own messages. You can download Expansions either directly from the eCloud yourself, or download them through the download command of PlaceholderAPI.
Table of Contents
- Getting started
- Without a Plugin
- With a Plugin (External Jar)
- With a Plugin (Internal Class)
- Relational Placeholders
Getting started
For starters, you need to decide what type of PlaceholderExpansion
you want to create. There are various ways to create an expansion. This page will cover the most common ones.
Common Parts
All shown examples will share the same common parts that belong to the PlaceholderExpansion
class.
In order to not repeat the same basic info for each method throughout this page, and to greatly reduce its overall length, we will cover the most basic/necessary ones here.
Basic PlaceholderExpansion Structure
package at.helpch.placeholderapi.example.expansions;
import org.bukkit.OfflinePlayer;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
public class SomeExpansion extends PlaceholderExpansion {
@Override
public String getAuthor() {
return "someauthor";
}
@Override
public String getIdentifier() {
return "example";
}
@Override
public String getVersion() {
return "1.0.0";
}
}
Let's quickly break down the different methods you have to implement.
-
getAuthor
This method allows you to set the name of the expansion's author.
-
getIdentifier
The name that should be used to identify the placeholders for this expansion.
The identifier is the string after the starting%
and before the first_
(%identifier_values%
) and, therefore, cannot contain_
,%
or spaces.If you still want to use the previously mentioned symbols can you override the
getName()
method to change the Expansion's displayname. -
getVersion
This is a string, which means it can contain more than just a number. This is used to determine if a new update is available or not when the expansion is shared on the eCloud. For expansions that are part of a plugin, this does not really matter.
Those are all the neccessary parts for your PlaceholderExpansion.
Any other methods that are part of the PlaceholderExpansion
class are optional and will usually not be used, or will default to a specific value. Please read the Javadoc comments of those methods for more information.
You must choose between one of these two methods for handling the actual parsing of placeholders:
-
onRequest(OfflinePlayer, String)
If not explicitly set, this will automatically callonPlaceholderRequest(Player, String)
. This method is recommended as it allows the usage ofnull
and can therefore be used in placeholders that don't require a valid player to be used. -
onPlaceholderRequest(Player, String)
If not set, this method will returnnull
which PlaceholderAPI sees as an invalid placeholder.
Without a Plugin
An expansion does not always need a plugin to rely on. If the placeholders it provides can return values from just the server itself or some other source (i.e. Java itself), then it can work independently.
Common examples of such Expansions are:
These kinds of expansions don't require any additional plugins to function.
When creating such an expansion is it recommended to use onRequest(OfflinePlayer, String)
.
Full Example
Please see the Common parts section for info on the other methods.
package at.helpch.placeholderapi.example.expansions;
import org.bukkit.OfflinePlayer;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
public class SomeExpansion extends PlaceholderExpansion {
@Override
public String getAuthor() {
return "someauthor";
}
@Override
public String getIdentifier() {
return "example";
}
@Override
public String getVersion() {
return "1.0.0";
}
@Override
public String onRequest(OfflinePlayer player, String params) {
if(params.equalsIgnoreCase("name")) {
return player == null ? null : player.getName(); // "name" requires the player to be valid
}
if(params.equalsIgnoreCase("placeholder1")) {
return "Placeholder Text 1";
}
if(params.equalsIgnoreCase("placeholder2")) {
return "Placeholder Text 2";
}
return null; // Placeholder is unknown by the Expansion
}
}
With a Plugin (External Jar)
If your expansion relies on a plugin to provide its placeholder values, you will need to override a few more methods to make sure everything will work correctly.
Your expansion will need to override the getRequiredPlugin()
method to return the name of the plugin your expansion depends on.
PlaceholderAPI automatically checks if this method will either return null, or if the name defined results in a non-null plugin.
It is worth noting that it is a bit more difficult to make a separate jar file that depends on a plugin, as it will require the plugin to have some sort of accessible API in order to get the required values.
One way to bypass this is to override the canRegister()
method with the following code:
private SomePlugin plugin = null; // This would be the plugin your expansion depends on
@Override
public boolean canregister() {
// This sets plugin to the SomePlugin instance you get through the PluginManager
return (plugin = (SomePlugin) Bukkit.getPluginManager().getPlugin(getRequiredPlugin())) != null;
}
Using this code-snippet, you can get a direct instance of the plugin and access things such as config values.
With that said, it is recommended instead to use an API if one is available, as this kind of plugin access is a relatively poor approach.
Full Example
Please see the Common parts section for info on the other methods.
package at.helpch.placeholderapi.example.expansions;
import at.helpch.placeholderapi.example.SomePlugin;
import org.bukkit.OfflinePlayer;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
public class SomeExpansion extends PlaceholderExpansion {
private SomePlugin plugin; // This instance is assigned in canRegister()
@Override
public String getAuthor() {
return "someauthor";
}
@Override
public String getIdentifier() {
return "example";
}
@Override
public String getVersion() {
return "1.0.0";
}
@Override
public String getRequiredPlugin() {
return "SomePlugin";
}
@Override
public boolean canRegister() {
return (plugin = (SomePlugin) Bukkit.getPluginManager().getPlugin(getRequiredPlugin())) != null;
}
@Override
public String onRequest(OfflinePlayer player, String params) {
if(params.equalsIgnoreCase("placeholder1")){
return plugin.getConfig().getString("placeholders.placeholder1", "default1");
}
if(params.equalsIgnoreCase("placeholder2")){
return plugin.getConfig().getString("placeholders.placeholder2", "default2");
}
return null; // Placeholder is unknown by the expansion
}
}
With a Plugin (Internal Class)
The way expansions are handled when they are part of the plugin itself is fairly similar to when you make an expansion without a plugin dependency.
In fact, you don't even have to override the getRequiredPlugin()
and canRegister()
methods as it is always guaranteed that the plugin is available.
Something worth noting, however, is that you need to override the persist()
method and make it return true. This ensures that the expansion won't be unregistered by PlaceholderAPI whenever it is reloaded.
Finally, you can also use dependency injection as an easier way to access a plugin's methods. Here is a small code example of how dependency injection may look:
public class SomeExpansion extends PlaceholderExpansion {
private final SomePlugin plugin; // The instance is created in the constructor and won't be modified, so it can be final
public SomeExpansion(SomePlugin plugin) {
this.plugin = plugin;
}
}
Full Example
Please see the Common parts section for info on the other methods.
package at.helpch.placeholderapi.example.expansions;
import at.helpch.placeholderapi.example.SomePlugin;
import org.bukkit.OfflinePlayer;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
public class SomeExpansion extends PlaceholderExpansion {
private final SomePlugin plugin;
public SomeExpansion(SomePlugin plugin) {
this.plugin = plugin;
}
@Override
public String getAuthor() {
return "someauthor";
}
@Override
public String getIdentifier() {
return "example";
}
@Override
public String getVersion() {
return "1.0.0";
}
@Override
public boolean persist() {
return true; // This is required or else PlaceholderAPI will unregister the Expansion on reload
}
@Override
public String onRequest(OfflinePlayer player, String params) {
if(params.equalsIgnoreCase("placeholder1")){
return plugin.getConfig().getString("placeholders.placeholder1", "default1");
}
if(params.equalsIgnoreCase("placeholder2")) {
return plugin.getConfig().getString("placeholders.placeholder2", "default2");
}
return null; // Placeholder is unknown by the Expansion
}
}
Register the Expansion
To register the expansion, you will need to call the register()
method yourself.
This should be done in your plugin's onEnable()
method after you make sure that PlaceholderAPI is installed and enabled.
package at.helpch.placeholderapi.example
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
public class SomePlugin extends JavaPlugin {
@Override
public void onEnable() {
// Small check to make sure that PlaceholderAPI is installed
if(Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
new SomeExpansion(this).register();
}
}
}
Relational Placeholders
Relational Placeholders are a bit more specific compared to the previous examples.
While they do use the same common parts that the other examples do, they have a different method to return placeholders.
In order to use the relational placeholders feature, you will need to implement the Relational
interface, which in return adds the onPlaceholderRequest(Player, Player, String)
method to use.
Full Example
Please see the Common parts section for info on the other methods.
In this example, we use the Internal class setup and SomePlugin
has an areFriends(Player, Player)
method that returns true or false based on if the given players are friends.
package at.helpch.placeholderapi.example.expansions;
import at.helpch.placeholderapi.example.SomePlugin;
import org.bukkit.ChatColor;
import org.bukkit.Player;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Relational;
public class SomeExpansion extends PlaceholderExpansion implements Relational {
private final SomePlugin plugin;
public SomeExpansion(SomePlugin plugin) {
this.plugin = plugin;
}
@Override
public String getAuthor() {
return "someauthor";
}
@Override
public String getIdentifier() {
return "example";
}
@Override
public String getVersion() {
return "1.0.0";
}
@Override
public boolean persist() {
return true; // This is required or else PlaceholderAPI will unregister the Expansion on reload
}
@Override
public String onPlaceholderRequest(Player one, Player two, String identifier) {
if(one == null || two == null)
return null; // We require both Players to be online
if(params.equalsIgnoreCase("friend")) {
if(plugin.areFriends(one, two)) {
return ChatColor.GREEN + one.getName() + " and " + two.getName() + " are friends!";
} else {
return ChatColor.GREEN + one.getName() + " and " + two.getName() + " are not friends!";
}
}
return null; // Placeholder is unknown by the Expansion
}
}
Notes about Relational Placeholders
Relational placeholders will always start with %rel_
to properly identify them.
So in the above example, the full placeholder will look like %rel_example_friend%
.