PlaceholderAPI/PlaceholderExpansion.md

437 lines
16 KiB
Markdown
Raw Permalink Normal View History

2022-06-30 21:44:30 +02:00
[placeholderexpansion]: https://github.com/PlaceholderAPI/PlaceholderAPI/blob/master/src/main/java/me/clip/placeholderapi/expansion/PlaceholderExpansion.java
[relational]: https://github.com/PlaceholderAPI/PlaceholderAPI/blob/master/src/main/java/me/clip/placeholderapi/expansion/Relational.java
## Overview
2023-03-27 17:38:42 +02:00
2022-06-30 21:44:30 +02:00
This page will cover how you can create your own [`PlaceholderExpansion`][placeholderexpansion] which you can either [[Upload to the eCloud|Expansion cloud]] 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|Commands#papi-ecloud-download]].
## Table of Contents
- [Getting started](#getting-started)
- [Common Parts](#common-parts)
2023-09-05 13:43:49 +02:00
- [Making an Internal Expansion](#making-an-internal-expansion)
2023-03-27 17:38:42 +02:00
- [Full Example](#full-example)
2023-09-05 13:43:49 +02:00
- [Register Your Expansion](#register-your-expansion)
- [Making an External Expansion](#making-an-external-expansion)
2023-03-27 17:46:30 +02:00
- [Full Example (Without Dependency)](#full-example-without-dependency)
- [Full Example (With Dependency)](#full-example-with-dependency)
2022-06-30 21:44:30 +02:00
- [Relational Placeholders](#relational-placeholders)
2023-03-27 17:38:42 +02:00
- [Quick Notes](#quick-notes)
- [Adding Relational Placeholders](#adding-relational-placeholders)
- [Full Example](#full-example-1)
2022-06-30 21:44:30 +02:00
## Getting started
2023-03-27 17:38:42 +02:00
2022-06-30 21:44:30 +02:00
For starters, you need to decide what type of [`PlaceholderExpansion`][placeholderexpansion] you want to create. There are various ways to create an expansion. This page will cover the most common ones.
### Common Parts
2023-03-27 17:38:42 +02:00
2022-06-30 21:44:30 +02:00
All shown examples will share the same common parts that belong to the [`PlaceholderExpansion`][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
2023-03-27 17:38:42 +02:00
2022-06-30 21:44:30 +02:00
```java
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";
}
}
```
2023-04-09 21:38:06 +02:00
<details><summary>What are these options?</summary>
<p>
2022-06-30 21:44:30 +02:00
- #### getAuthor
This method allows you to set the name of the expansion's author.
- #### getIdentifier
The identifier is the part in the placeholder that is between the first `%` (Or `{` if bracket placeholders are used) and the first `_`.
2022-07-01 14:02:00 +02:00
Because of that can you not use `%`, `{`, `}` or `_` in your identifier.
2022-06-30 21:44:30 +02:00
If you still want to use those symbols can you override the `getName()` method to display a different name.
- #### 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`][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.
2023-04-09 21:38:06 +02:00
</p>
</details>
2023-03-27 17:38:42 +02:00
You must choose between one of these two methods for handling the actual parsing of placeholders (Unless you're using [Relational Placeholders](#relational-placeholders)):
2022-06-30 21:44:30 +02:00
- #### onRequest(OfflinePlayer, String)
If not explicitly set, this will automatically call [`onPlaceholderRequest(Player, String)`](#onplaceholderrequestplayer-string).
2023-03-27 17:38:42 +02:00
This method is recommended as it allows the usage of offline players, meaning the player doesn't need to be online to obtain certain data from them like name or UUID.
2022-06-30 21:44:30 +02:00
- #### onPlaceholderRequest(Player, String)
2022-07-01 14:02:00 +02:00
If not set, this method will return `null` which PlaceholderAPI sees as an invalid placeholder.
The `Player` can be `null`, so keep that in mind when handling your placeholders.
2022-06-30 21:44:30 +02:00
2023-03-27 17:38:42 +02:00
PlaceholderAPI will **always** call `onRequest(OfflinePlayer, String)` in an expansion.
2023-03-27 17:48:12 +02:00
2022-06-30 21:44:30 +02:00
----
2023-09-05 13:43:49 +02:00
## Making an Internal Expansion
2022-06-30 21:44:30 +02:00
2023-03-27 17:38:42 +02:00
Internal PlaceholderExpansions are classes directly implemented into the plugin they depend on. The main benefit is, that you're not required to do any `canRegister()` check for your own plugin, as it is loaded within it.
Another benefit is that you can more easily access plugin data using Dependency Injection should an API not be accessible for the plugin.
2022-06-30 21:44:30 +02:00
2023-03-27 17:38:42 +02:00
It is important to note that PlaceholderExpansions loaded manually through the `register()` method (Therefore not being loaded by PlaceholderAPI itself) **require** to have the `persist()` method return `true` to avoid the expansion being unloaded during a `/papi reload`.
2022-06-30 21:44:30 +02:00
2023-03-27 17:38:42 +02:00
Depending on what info you try to access from your plugin (i.e. through the main class or a dedicated API) can you use Dependency Injection to obtain an instance of whatever you need.
Keep in mind that as mentioned earlier, the Expansion class won't be reloaded when `persist()` is set to `true`, so you have to refresh any info that may get outdated during a reload yourself.
2022-06-30 21:44:30 +02:00
2023-03-27 17:38:42 +02:00
Here is an example of a possible Dependency Injection:
2022-06-30 21:44:30 +02:00
```java
2023-03-27 17:38:42 +02:00
package at.helpch.placeholderapi.example.expansion;
2022-06-30 21:44:30 +02:00
2023-03-27 17:38:42 +02:00
import at.helpch.placeholderapi.example.SomePlugin;
2022-06-30 21:44:30 +02:00
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
public class SomeExpansion extends PlaceholderExpansion {
2023-03-27 17:38:42 +02:00
private final SomePlugin plugin;
public SomeExpansion(SomePlugin plugin) {
this.plugin = plugin;
}
// Imported methods from PlaceholderExpansion
}
```
2023-04-09 21:38:06 +02:00
<details><summary><h3 title="Click to Open/Close">Full Example</h3></summary>
<p>
2023-03-27 17:38:42 +02:00
2023-03-27 17:50:26 +02:00
> Please read the [`Common Parts` Section](#common-parts) for details on all the methods.
2022-06-30 21:44:30 +02:00
2023-03-27 17:38:42 +02:00
Below is a full example of an internal Expansion class. Please note the override of the `persist()` method to guarantee the Expansion isn't unloaded during a `/papi reload` operation.
We also use the provided `SomePlugin` instance for information such as the version and authors. This allows us to keep the code clean while not having to deal with updating the expansion's information every time we make changes to the plugin.
```java
package at.helpch.placeholderapi.example.expansion;
import at.helpch.placeholderapi.example.SomePlugin;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.OfflinePlayer;
public class SomeExpansion extends PlaceholderExpansion {
private final SomePlugin plugin;
public SomeExpansion(SomePlugin plugin) {
this.plugin = plugin;
}
2022-06-30 21:44:30 +02:00
@Override
public String getAuthor() {
2023-03-27 17:38:42 +02:00
return String.join(", ", plugin.getDescription().getAuthors());
2022-06-30 21:44:30 +02:00
}
@Override
public String getIdentifier() {
return "example";
}
2023-03-27 17:38:42 +02:00
2022-06-30 21:44:30 +02:00
@Override
public String getVersion() {
2023-03-27 17:38:42 +02:00
return plugin.getDescription().getVersion();
}
// This override is required or PlaceholderAPI will unregister your expansion on /papi reload
@Override
public boolean persist() {
return true;
2022-06-30 21:44:30 +02:00
}
@Override
public String onRequest(OfflinePlayer player, String params) {
2023-03-27 17:38:42 +02:00
if (params.equalsIgnoreCase("placeholder1")) {
return plugin.getConfig().getString("placeholders.placeholder1", "default1");
2022-06-30 21:44:30 +02:00
}
2023-03-27 17:38:42 +02:00
if (params.equalsIgnoreCase("placeholder2")) {
return plugin.getConfig().getString("placeholders.placeholder2", "default2");
2022-06-30 21:44:30 +02:00
}
2023-03-27 17:38:42 +02:00
return null; // Unknown Placeholder provided
2022-06-30 21:44:30 +02:00
}
}
```
2023-04-09 21:38:06 +02:00
</p>
</details>
2023-09-05 13:43:49 +02:00
### Register Your Expansion
2022-06-30 21:44:30 +02:00
2023-03-27 17:38:42 +02:00
The main downside of an internal expansion is, that it can't be loaded automatically by PlaceholderAPI and instead requires you to manually register it.
To do that, create a new instance of your Expansion class and call the `register()` method of it.
2022-06-30 21:44:30 +02:00
2023-03-27 17:38:42 +02:00
Below is an example of loading the Expansion in the Plugin's main class inside the `onEnable()` method.
2022-06-30 21:44:30 +02:00
```java
2023-03-27 17:38:42 +02:00
package at.helpch.placeholderapi.example;
import at.helpch.placeholderapi.example.expansion.SomeExpansion;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
2022-06-30 21:44:30 +02:00
2023-03-27 17:38:42 +02:00
public class SomePlugin extends JavaPlugin {
@Override
public void onEnable() {
// Make sure PlaceholderAPI is installed and enabled
if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
// Register the expansion
new SomeExpansion(this).register();
}
}
2022-06-30 21:44:30 +02:00
}
```
2023-03-27 17:38:42 +02:00
----
2023-09-05 13:43:49 +02:00
## Making an External Expansion
2023-03-27 17:38:42 +02:00
External expansions are separate Jar files containing the PlaceholderExpansion extending class.
They are recommended for the following scenarios:
- Your Expansion doesn't depend on any Plugin.
- Your Expansion depends on a Plugin AND you can't directly implement the Class into it.
2023-03-27 18:08:06 +02:00
If you'd like to implement PlaceholderAPI expansions for your own plugin consider using the [internal expansion setup](#making-an-internal-expansion) instead.
2023-03-27 17:38:42 +02:00
Benefits of this type of expansion are 1) automatic loading through PlaceholderAPI by adding them to your `expansions` folder and 2) having the option to upload them on the eCloud, allowing it to be downloaded through [[`/papi ecloud download <expansion>`|Commands#papi-ecloud-download]] automatically (After it has been verified).
Downsides can be a more tedious setup to make sure any required plugin/dependency is loaded before registering the Expansion.
2023-04-09 21:38:06 +02:00
<details><summary><h3 title="Click to Open/Close">Full Example (Without Dependency)</h3></summary>
<p>
2023-03-27 17:38:42 +02:00
2023-03-27 17:50:26 +02:00
> Please read the [`Common Parts` Section](#common-parts) for details on all the methods.
2023-03-27 17:38:42 +02:00
Below is a full example of an external PlaceholderExpansion without any dependencies such as plugins.
2022-06-30 21:44:30 +02:00
```java
2023-03-27 17:38:42 +02:00
package at.helpch.placeholderapi.example.expansion;
2022-06-30 21:44:30 +02:00
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
2023-03-27 17:38:42 +02:00
import org.bukkit.OfflinePlayer;
2022-06-30 21:44:30 +02:00
public class SomeExpansion extends PlaceholderExpansion {
@Override
public String getAuthor() {
2023-03-27 17:38:42 +02:00
return "SomeAuthor";
2022-06-30 21:44:30 +02:00
}
@Override
public String getIdentifier() {
return "example";
}
2023-03-27 17:38:42 +02:00
2022-06-30 21:44:30 +02:00
@Override
public String getVersion() {
return "1.0.0";
}
@Override
public String onRequest(OfflinePlayer player, String params) {
2023-03-27 17:38:42 +02:00
if (params.equalsIgnoreCase("player_name")) {
// player_name requires a valid OfflinePlayer
return player == null ? null : player.getName();
2022-06-30 21:44:30 +02:00
}
2023-03-27 17:38:42 +02:00
if (params.equalsIgnoreCase("placeholder1")) {
return "Placeholder Text 1";
2022-06-30 21:44:30 +02:00
}
2023-03-27 17:38:42 +02:00
if (params.equalsIgnoreCase("placeholder2")) {
return "Placeholder Text 2";
}
return null; // Unknown Placeholder provided
2022-06-30 21:44:30 +02:00
}
}
```
2023-04-09 21:38:06 +02:00
</p>
</details>
<details><summary><h3 title="Click to Open/Close">Full Example (With Dependency)</h3></summary>
<p>
2022-06-30 21:44:30 +02:00
2023-03-27 17:50:26 +02:00
> Please read the [`Common Parts` Section](#common-parts) for details on all the methods.
2022-06-30 21:44:30 +02:00
2023-03-27 17:38:42 +02:00
The below example shows a possible setup of an external PlaceholderExpansion that depends on a Plugin to be present.
2022-06-30 21:44:30 +02:00
```java
2023-03-27 17:38:42 +02:00
package at.helpch.placeholderapi.example.expansion;
2022-06-30 21:44:30 +02:00
import at.helpch.placeholderapi.example.SomePlugin;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
2023-03-27 17:38:42 +02:00
import org.bukkit.OfflinePlayer;
2022-06-30 21:44:30 +02:00
public class SomeExpansion extends PlaceholderExpansion {
2023-03-27 17:38:42 +02:00
// This instance is assigned in canRegister() and can therefore not be final
private SomePlugin plugin;
2022-06-30 21:44:30 +02:00
@Override
public String getAuthor() {
2023-03-27 17:38:42 +02:00
return "SomeAuthor";
2022-06-30 21:44:30 +02:00
}
@Override
public String getIdentifier() {
return "example";
}
2023-03-27 17:38:42 +02:00
2022-06-30 21:44:30 +02:00
@Override
public String getVersion() {
return "1.0.0";
}
2023-03-27 17:38:42 +02:00
// Allows us to define a plugin the expansion depends on
2022-06-30 21:44:30 +02:00
@Override
2023-03-27 17:38:42 +02:00
public String getRequiredPlugin() {
return "SomePlugin";
2022-06-30 21:44:30 +02:00
}
2023-03-27 17:38:42 +02:00
/*
* This method needs to be overriden if your Expansion requires
* a plugin or other dependency to be present to work.
*
* Returning false will cancel the Expansion registration.
*/
@Override
public boolean canRegister() {
/*
* We do 2 things here:
* 1. Check if the required plugin is present and enabled
* 2. Obtain an instance of the plugin to use
*/
return (plugin = (SomePlugin) Bukkit.getPluginManager().getPlugin(getRequiredPlugin())) != null;
}
2022-06-30 21:44:30 +02:00
@Override
public String onRequest(OfflinePlayer player, String params) {
2023-03-27 17:38:42 +02:00
if (params.equalsIgnoreCase("placeholder1")) {
2022-06-30 21:44:30 +02:00
return plugin.getConfig().getString("placeholders.placeholder1", "default1");
}
2023-03-27 17:38:42 +02:00
if (params.equalsIgnoreCase("placeholder2")) {
2022-06-30 21:44:30 +02:00
return plugin.getConfig().getString("placeholders.placeholder2", "default2");
}
2023-03-27 17:38:42 +02:00
return null; // Unknown Placeholder provided
2022-06-30 21:44:30 +02:00
}
}
```
2023-04-09 21:38:06 +02:00
</p>
</details>
2023-03-27 17:38:42 +02:00
----
2022-06-30 21:44:30 +02:00
2023-03-27 17:38:42 +02:00
## Relational Placeholders
2022-06-30 21:44:30 +02:00
2023-03-27 17:38:42 +02:00
Relational Placeholders are a special kind of placeholder that allow the usage of 2 Players for whatever you like to do. The most common use is to evaluate their relation to each other (i.e. check if Player one is in the same team as Player two) and return an output based on that.
2022-06-30 21:44:30 +02:00
2023-03-27 17:38:42 +02:00
### Quick Notes
2022-06-30 21:44:30 +02:00
2023-03-27 18:08:06 +02:00
Relational Placeholders are always prefixed with `rel_`, meaning that a relational placeholder with identifier `example` and value `friend` looks like `%rel_example_friend%` when used.
2023-03-27 17:38:42 +02:00
### Adding Relational Placeholders
To add relational placeholders will you need to implement the [`Relational`][relational] interface into your Expansion class and override the `onPlaceholderRequest(Player, Player, String)` method.
2022-06-30 21:44:30 +02:00
2023-04-09 21:38:06 +02:00
<details><summary><h3 title="Click to Open/Close">Full Example</h3></summary>
<p>
2022-06-30 21:44:30 +02:00
2023-03-27 17:50:26 +02:00
> Please read the [`Common Parts` Section](#common-parts) for details on all the methods.
2022-06-30 21:44:30 +02:00
2023-03-27 17:38:42 +02:00
Below is a full example of using Relational Placeholders.
2023-09-05 13:43:49 +02:00
For the sake of simplicity are we using parts of the [Internal Expansion Example](#making-an-internal-expansion) here and assume that the `SomePlugin` class offers a `areFriends(Player, Player)` method that returns a boolean value.
2022-06-30 21:44:30 +02:00
```java
package at.helpch.placeholderapi.example.expansions;
import at.helpch.placeholderapi.example.SomePlugin;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Relational;
2023-03-27 17:38:42 +02:00
import org.bukkit.ChatColor;
import org.bukkit.Player;
2022-06-30 21:44:30 +02:00
public class SomeExpansion extends PlaceholderExpansion implements Relational {
private final SomePlugin plugin;
public SomeExpansion(SomePlugin plugin) {
this.plugin = plugin;
}
@Override
public String getAuthor() {
2023-03-27 17:38:42 +02:00
return String.join(", ", plugin.getDescription().getAuthors());
2022-06-30 21:44:30 +02:00
}
@Override
public String getIdentifier() {
return "example";
}
2023-03-27 17:38:42 +02:00
2022-06-30 21:44:30 +02:00
@Override
public String getVersion() {
2023-03-27 17:38:42 +02:00
return plugin.getDescription().getVersion();
2022-06-30 21:44:30 +02:00
}
2023-03-27 17:38:42 +02:00
// This override is required or PlaceholderAPI will unregister your expansion on /papi reload
2022-06-30 21:44:30 +02:00
@Override
public boolean persist() {
2023-03-27 17:38:42 +02:00
return true;
2022-06-30 21:44:30 +02:00
}
@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
}
}
```
2023-04-09 21:38:06 +02:00
</p>
</details>