Developers

API and placeholders

The API#

ChorusCore registers itself as a Bukkit service, so an addon never has to touch its internals.

ChorusProvider.get().flatMap(ChorusApi::homes)
        .ifPresent(homes -> homes.list(player.getUniqueId()));

Add softdepend: [ ChorusCore ] to your plugin.yml and check the result, or depend and assume it is there.

Everything that belongs to a module comes back as an Optional, because any module can be switched off in its config and an addon has to cope with that.

ChorusApi#

public interface ChorusApi {
    String version();
    Optional<HomeApi> homes();
    Optional<WarpApi> warps();
    Optional<SpawnApi> spawns();
    Economy economy();
    TeleportApi teleports();
    MessageApi messages();
}

HomeApi#

List<Home> list(UUID owner);
Optional<Home> find(UUID owner, String name);
int count(UUID owner);
int limit(Player player);
CompletableFuture<Void> save(Home home);
CompletableFuture<Boolean> delete(UUID owner, String name);

Reads are for players who are online — homes are held in memory only while their owner is here. Writes come back as a future.

WarpApi#

List<NamedLocation> all();
Optional<NamedLocation> find(String name);
List<NamedLocation> visibleTo(Permissible who);
CompletableFuture<Void> save(NamedLocation warp);
CompletableFuture<Boolean> delete(String name);

visibleTo applies the per-warp permission rules, so a menu built on it shows the same warps /warps would.

SpawnApi#

Optional<NamedLocation> find(World world);
Optional<Location> location(World world);
CompletableFuture<Void> moveTo(Location where);

find answers with the spawn a player in that world would actually be sent to, per-world setting and fallback included.

TeleportApi#

void teleport(Player player, Location destination, int warmupSeconds);
Optional<Location> previousLocation(UUID playerId);

The same delayed, cancel-on-move teleport the plugin's own commands use — including safe landing, the countdown and arrival invulnerability.

MessageApi#

void send(CommandSender target, String key, String... placeholders);
Component render(String key, String... placeholders);
Component prefix();

Sends or renders anything from messages.yml, prefix included, in the reader's own language when per-player is on.

Economy#

Balances and transfers. Reports itself disabled when the economy is switched off, so an addon that checks enabled() first never has to handle an exception.

Events#

All cancellable:

Event Fired
ChorusTeleportEvent Before any teleport the plugin performs
ChorusHomeSaveEvent Before a home is written
ChorusPaymentEvent Before money moves between two players

What is stable#

Only the interfaces in dev.chorus.core.api. Everything else is free to change between versions — the modules, the storage layer, the command classes, all of it.

PlaceholderAPI#

If PlaceholderAPI is installed, the expansion registers itself. That is how a tab or scoreboard plugin shows any of this without depending on ChorusCore at all.

Placeholder Shows
%chorus_homes_used% Homes the player has
%chorus_homes_limit% Their cap, or the infinity sign
%chorus_homes_free% How many more they may set
%chorus_warps_total% Warps on the server
%chorus_warps_available% Warps this player may use
%chorus_balance% Their balance, formatted the way the economy writes it
%chorus_balance_raw% The same as a plain number
%chorus_playtime% How long they have played
%chorus_afk% true or false
%chorus_vanished% true or false
%chorus_spawn_set% Whether their world has a spawn
%chorus_version% The plugin version

Every one of them reads from memory. None touch the database, so a scoreboard refreshing several times a second costs nothing.

%chorus_warps_total% works for a console or an offline player; %chorus_playtime%, %chorus_balance% and %chorus_balance_raw% work for an offline player; the rest need the player to be online.

The expansion survives a PlaceholderAPI reload, since the plugin outlives one.

Using them inside ChorusCore#

PlaceholderAPI placeholders work in kit requirements and kit actions — see Kits:

      requirements:
        - condition: 'placeholder: %player_level% >= 10'
          deny: '<red>Come back at level 10.'

That is what makes anything any plugin exposes able to gate a kit.