-
Notifications
You must be signed in to change notification settings - Fork 63
Addons API
Addons are no different than normal plugins, however sometimes these isolated software are purely designed for kingdoms plugin. If you made a compatbility addon for kingdoms, you can ask me to add it too!
This page only contains information about API that is mostly not found in a normal plugin, so a lot of other information is on the main API page instead.
First, you'd need to implement the Addon class from kingdoms. This is usually done in the same class that JavaPlugin is extended.
Before going deeper in the features, there are already many open source addons like Peace Treaties and Outposts that you can take a look at.
First of all, you need to be registering all your Namespace'd values onLoad because you cannot register them later.
Another important thing is to look if the plugin was correctly enabled
Here's an overview of things and where they should go:
public final class OutpostAddon extends JavaPlugin implements Addon {
@Override
public void onDisable() {
if (!loaded) return;
signalDisable(); // Save data if you registered custom data models.
disableAddon();
}
@Override
public void onLoad() {
if (!isKingdomsLoaded()) return; // If something wen't wrong with kingdoms, skip.
// All namespaced registries must be registered here in onLoad().
Kingdoms.get().getPermissionRegistery().register(new Namespace("CUSTOMADDON", "BLAH"));
Kingdoms.get().getAuditLogRegistry().register(LogCustomLog.PROVIDER);
LanguageManager.registerMessenger(CustomAddonLang.class); // More info below
}
@Override
public void onEnable() {
if (!isKingdomsEnabled()) {
// If something wen't wrong with kingdoms, don't start.
getLogger().severe("Kingdoms plugin didn't load correctly. Disabling...");
Bukkit.getPluginManager().disablePlugin(this);
return;
}
reloadAddon(); // we can reuse this method since we're just registering a command in it.
registerAddon();
loaded = true;
}
@Override
public void reloadAddon() { // on /k reload
// re-register commands.
new MyAddonCustomCommand();
}
@Override
public String getAddonName() {
return "custom addon";
}
@Override
public File getFile() {
return super.getFile();
}
}You can register new configs like this and optionally register them for file watchers like this.
If you want to complete your config suite, you can optionally add new config validators for config schemas if you have any new data like this.
Do you want to use Kingdom's language parser model for parsing placeholders and other advanced coloring and formatting features? You can use Messenger classes. The most basic way to send a kingdom-parsed message would be the following:
Player player = ...;
Messenger msg = new StaticMessenger("&2Hello, my kingdom's name is &9%kingdoms_kingdom_name%");
msg.sendMessage(player);This is cool and all, but if you would like to make these messages translatable and configurable through standard language files, you'd have to use DefinedMessenger and an easy way to use this would be an enum just like the default KingdomsLang, specially if you have a lot of entries. You can find a full example for Outposts addon in OutpostsLang.java.
public enum CustomAddonLang implements DefinedMessenger {
COMMAND_CUSTOMADDON_CREATE_BLAH("{$s}Shows the available outpost commands.", 1, 2, 3),
CUSTOMADDON_BLAH_BLAH("{$e}Could not find {$es}%outpost% {$e}outpost.", 1, 2)
;
private final LanguageEntry languageEntry;
private final String defaultValue;
OutpostsLang(String defaultValue, int... group) {
this.defaultValue = defaultValue;
this.languageEntry = DefinedMessenger.getEntry("custom-addon", this, group);
}
@NonNull
@Override
public LanguageEntry getLanguageEntry() {
return languageEntry;
}
@Override
public String getDefaultValue() {
return defaultValue;
}
}Now you can use them like CustomAddonLang.CUSTOMADDON_BLAH_BLAH.sendMessage(player).
Important
Don't forget to register your custom messenger class:
@Override
public void onLoad() {
LanguageManager.registerMessenger(CustomAddonLang.class);
}One important feature here is the numbers after the enum values. These are grouping values for defining the path of these messages inside the language files (e.g. en.yml)
The numbers are refer to the position of the nth underscore _ in the enum's name.
- If the position of an underscore is specified at the end, the next word is considered as a nested YAML entry.
- If the position of an underscore is not specified at all, the next word is concatenated to the previous word separated by a hyphen
-.
Examples:
COMMAND_CUSTOMADDON_CREATE_BLAH("{$s}Shows the available outpost commands.", 1, 2, 3),
// ^ 1 ^ 2 ^ 3Corresponds to the following YAML path:
command:
customaddon:
create:
blah: "..."Another example:
COMMAND_CUSTOMADDON_CREATE_BLAH("{$s}Shows the available outpost commands.", 1, 3),
// ^ 1 ^ - ^ 3Corresponds to the following YAML path:
command:
customaddon-create:
blah: "..."A very very important thing to remember is that you need to call signalDisable() on your onDisable() if you've registered namespace'd values in the plugin. If you don't do this the plugin can't correctly save data.
If you want to register new placeholders to the plugin, you can do so like this, enums are a pretty easy and common way to register placeholders, even tho they'll never be used within the code itself, if you don't like that approach, all you need to do is to register placeholders using KingdomsPlaceholder.of(name, defaultValue, translator) function which ultimately implements KingdomsPlaceholder class and registers it with KingdomsPlaceholder.register(instance).
Finally if you have a main plugin and you want to make an addon for kingdoms compatibility, you can register the addon as an available downloadable content using new AddonRepository(pluginInstance, name, path, metaFileURL, description).register() where name is any displayname and path is the data node (it's not a file or URL path) and metaFileURL points to a URL which must point to an accessible .yml file containing addon information like this one. A direct URL to that file for example would be new URL("https://raw.githubusercontent.com/CryptoMorin/KingdomsX/master/addons/addon-meta.yml")
If you don't have a main plugin, you can simply ask me to add your addon information to the original addon-meta file, but that'd require me to update it every time a new version is out.
This is a completely optional component, but recommended to implement. Please read Data Corruption first for more info. This adds a way to process data when the command is executed so you can do your own corrections for your own addon.
Additionally, you might want to implement a ChunkEditingHandler instead if you wish to perform operations on chunk block/entity data.
public final class MyDataCheckup extends CheckupHandler {
private static final MyDataCheckup INSTANCE = new MyDataCheckup();
private static final Messenger MSG = new StaticMessenger("{$c}Something is corrupted! %broken%");
static {
CheckupHandler.addCheckupHandler(INSTANCE);
}
MyDataCheckup() {
// Another way to handle data which only works for Kingdom, Nation, KingdomPlayer, Land and Mail.
// This is simply to prevent looping the data again and using the main loop used by the default FSCK.
addPredefinedHandlers(Kingdom.class, kingdom -> {
if (something == null) ...
});
}
@Override
public void handle(@NotNull CheckupProcessor checkupProcessor) {
KingdomsDataCenter dataCenter = checkupProcessor.getDataCenter();
for (Kingdom kingdom : dataCenter.getKingdomManager().getLoadedData()) { // Everything is already loaded.
if (something == null) {
checkupProcessor.addEntry(MSG, settings -> {
settings.raw("broken", something);
});
}
}
}
}Terminology - Spigot - Discord - History - Other Info
- ๐ Home
- ๐ฐ Features
- ๐ฅ Installation
- ๐ Setup
- ๐ Compatibility
- โ FAQ
โ๏ธ NFAQ- โ๏ธ Addons
- ๐ฉ Outposts
- โฎ๏ธ Peace Treaties
- ๐บ๏ธ Map Viewers
- ๐ฌ EngineHub
- ๐ Admin Tools
- โ๏ธ Introduction
- โจ๏ธ Commands
- ๐ Permissions
- ๐ฃ Placeholders
- ๐ Config
- ๐ Protection Signs
- โ๏ธ Mails
- ๐ Mechanics
- ๐งฐ Troubleshooting
- ๐ป API
๐น Basics
๐น Turrets & Structures
๐น Metadata
๐น Events
๐น Examples
๐น Addons