Skip to content
◆ TTS-STUDIO docs Discord

Docs / TTSCore

Developer API

TTSCore publishes a small contract so a plugin can ask the server what it can do and change its settings while it runs. DominionForge uses it for its server page.

One rule comes first: a plugin must work in full on plain Paper. TTSCore unlocks what a plugin cannot reach. It is never a requirement.

What is in it

Package dev.ttsstudio.ttscore.api:

Class Purpose
TTSCoreProvider The entry point: get(), isPresent(), and the contract version
TTSCoreApi What this server is: name, build, capabilities, settings
Capabilities Identifiers for "this server can do X"
Settings The catalogue of settings, with read and write
Setting One setting: type, limits, default and description
SettingType, SettingScope Its type, and whether it is global or per world
Result How a write went, with a message you can show a player

Detecting TTSCore without breaking on Paper

On plain Paper these classes do not exist. Naming one in a class that always loads ends in NoClassDefFoundError at startup. Keep everything that touches TTSCore in its own class and create it only when the brand matches:

// Always loaded. Names nothing from TTSCore.
static boolean serverIsTTSCore() {
    try {
        return "ttsstudio:ttscore".equals(
            io.papermc.paper.ServerBuildInfo.buildInfo().brandId().asString());
    } catch (Throwable ignored) {
        return false;
    }
}

// In onEnable. TTSCoreBridge is loaded on this line and only if needed.
hook = serverIsTTSCore() ? new TTSCoreBridge() : null;

"TTSCore".equals(Bukkit.getName()) works too. TTSCoreProvider.isPresent() does not, because calling it already loads the class.

Ask what it can do, not which version it is

TTSCoreApi core = TTSCoreProvider.get();
if (core.apiVersion() < TTSCoreProvider.API_VERSION) return;
if (core.has(Capabilities.RAID_TNT_FUSE)) {
    core.settings().set(world, "raid.tnt.fuse-ticks", 20);
}

A published capability is never removed and never changes meaning.

The catalogue

settings().all() returns every setting with its type, limits, default and the same comment that is written in ttscore.yml. A menu can draw itself from it:

for (Setting s : core.settings().all()) {
    // s.type(), s.min(), s.max(), s.label(), s.description(), s.scope()
}

A setting added to the server appears in your menu without recompiling the plugin.

Reading and writing

Settings s = core.settings();

s.getInt(world, "raid.tnt.fuse-ticks");        // the value in force there
s.isOverridden(world, "raid.tnt.fuse-ticks");  // its own, or inherited?

Result r = s.set(world, "raid.tnt.fuse-ticks", 20);
if (!r.success()) player.sendMessage(r.message());

s.unset(world, "raid.tnt.fuse-ticks");         // inherit again
s.set(Settings.DEFAULT_WORLD, "raid.tnt.fuse-ticks", 40);

Compiling against it

Depend on the contract with scope provided. At runtime the server supplies the classes.

<dependency>
  <groupId>dev.ttsstudio</groupId>
  <artifactId>ttscore-plugin-api</artifactId>
  <version>1.21.11-R0.1-SNAPSHOT</version>
  <scope>provided</scope>
</dependency>

The artifact is available to TTSCore owners. Ask for it in a ticket on our Discord.

Versioning

TTSCoreProvider.API_VERSION goes up only on an incompatible change. New settings and capabilities do not move it. A plugin compiled against version 1 keeps working on any TTSCore that announces version 1.

Keep reading