Skip to content
Shared Services

Shared Services

Deliveries

The mailbox: things an addon owes a player but could not hand over. Written once, given on their next join.

delivery().sendItem(uuid, item, "Auction sale", "XAuctionHouse");
delivery().sendMoney(uuid, "coins", 250.0, "Vote reward", "XVote");
delivery().countPending(uuid).thenAccept(count -> ...);

Money always goes through. An item is only closed once it is really in the inventory, so a full inventory postpones it rather than losing it.

Leaderboards

Declared once, refreshed on a timer, read from memory. Reading one never touches the database, which matters when a scoreboard asks for it several times a second.

leaderboards().define("kills")
    .table("myaddon_stats").value("kills")
    .size(10).refreshEvery(300)
    .register();

leaderboards().get("kills").top(10);   // the last snapshot

That also publishes %xcore_top_kills_1_name% and %xcore_top_kills_1_value%.

Network

Every server announces itself on the sync channel, so an addon can know what the network looks like instead of guessing.

network().servers();       // name, players, TPS, version
network().locate(uuid);    // which server holds this player
network().totalOnline();   // across the network
network().send("lobby", "mychannel", new SyncMessage("KICK", uuid.toString()));

Discord

One queue for the whole installation, with retries and rate-limit handling. Each addon keeps its own webhook address in its own config.

discord().send(url, DiscordNotifier.embed()
        .title("Ban")
        .description(player + " was banned by " + staff)
        .color(0xC0362C)
        .field("Reason", reason, false)
        .timestamp()
        .build());

discord().sendRaw(url, json) takes a payload an addon has already assembled.

Toolbox

ClassPurpose
ItemsItems to base64 and back, giving without losing the overflow, counting, taking
CooldownsPer-player cooldowns that expire on their own
NotifyTitles, action bars and boss bars
FormatsDurations both ways, thousands separators, compact numbers, byte sizes
CommandHelpersSuggestions, offline target resolution, the silent flag
WorldConfigPer-world overrides, resolved once at load
BlinkCacheBoth faces of a blinking item, built once
ranks()Primary group, weight, numbered permission levels

Placeholders without an expansion

placeholders()
    .register("kits", (player, arg) -> String.valueOf(available(player)))
    .register("cooldown", (player, arg) -> Formats.duration(remaining(player, arg)));
placeholders().publish();

The identifier is the addon name in lower case, so those become %mykits_kits% and %mykits_cooldown_starter%.

Play Time

XCore counts how long each player has been connected, across sessions, in the playtime column of the shared table.

long seconds = api().getPlaytime(uuid);

The session in progress is included, so the value moves while a player is online rather than only when they disconnect. %xcore_playtime% gives it formatted.