Skip to content

API Stability

Leaf26 edited this page Jun 17, 2026 · 1 revision

This page tells addon authors what they can rely on staying put and what may move under them. Build against the contract tier, pin a version, and you should survive LeafRTP upgrades with at most a recompile.

!!! note "Why a two-tier policy exists" LeafRTP splits its public surface into two tiers (see ADR-051) precisely so that the stuff most addons touch can be held stable while the engine internals stay free to evolve. Knowing which tier a symbol lives on tells you how much churn to expect.

The two tiers

Tier Module Stability promise Typical symbols
Contract tier rtp-api Stable within a major version. Source-compatible; breaking changes are announced and deprecated first. RTPAPI (getAllowedTargets, teleport, getTargetStatus, getMetricsSnapshot, hooks()), RtpTarget, RtpTargetStatus, RTPResult, RTPAddon, MenuRenderer
Implementation-extension tier rtp-core Evolves with the engine. May change between minor versions; depend on it only when the contract tier cannot express what you need. RTP.addShape(Shape), RTP.addVerticalAdjustor(VerticalAdjustor), RTP.selectionAPI, RTP.configs, concrete pipeline/region types

!!! tip "Depend on the lowest tier that does the job" Menus, triggers, exporters, effects, and verifiers all live entirely on the contract tier (rtp-api). Only reach into rtp-core when you are adding a genuinely new kind of geometry or height picker. The more rtp-core types you touch, the more likely a minor upgrade asks you to recompile.

What "stable" means here

  • Source compatibility within a major. A contract-tier method that exists in 3.x will still exist, with the same meaning, across 3.x. You may need to recompile against a new tag, but you should not have to rewrite logic.
  • Deprecate before removal. A contract-tier symbol that is going away is marked @Deprecated (with a pointer to its replacement) for at least one minor release before it is removed in a later major.
  • Additive minors. New methods/types may appear in minor releases; existing ones do not change shape.
  • No promise across a major bump. A 4.0 may reshape the contract tier. Such changes are called out in CHANGELOG.md.

Pinning a version

Always build against a release tag or commit hash, never a moving branch:

=== "Gradle"

```groovy
repositories { maven { url 'https://jitpack.io' } }
dependencies {
    compileOnly 'com.github.DailyStruggle.RTP:rtp-api:3.0.1'
    // only if you need implementation-tier types:
    // compileOnly 'com.github.DailyStruggle.RTP:rtp-core:3.0.1'
}
```

=== "Maven"

```xml
<repository>
    <id>jitpack.io</id>
    <url>https://jitpack.io</url>
</repository>
<dependency>
    <groupId>com.github.DailyStruggle.RTP</groupId>
    <artifactId>rtp-api</artifactId>
    <version>3.0.1</version>
    <scope>provided</scope>
</dependency>
```

!!! warning "Use compileOnly / provided, not implementation" LeafRTP is present at runtime; bundling (shading) rtp-api or rtp-core into your addon jar risks classloader conflicts and pins a stale copy of the API. Compile against it, do not ship it.

Runtime stability rules you must honour

The API's stability is a two-way contract. These rules are part of staying compatible, not just style:

  • Never call an extension entry point before core has loaded. Contract-tier methods throw IllegalStateException (S-006) when called pre-init; they do not silently no-op. Do your registration from RTPAddon.onLoad(), not from a static initializer or your own plugin's constructor.
  • Never block, do main-thread chunk I/O, or swallow exceptions in a verifier or post-teleport callback (S-004 / S-005). Code that violates the threading contract can break when the engine changes how it schedules that callback.
  • Schedule through RTP.scheduler, never raw Thread/Executors. The scheduler SPI is the stable seam; the thread it lands on is an implementation detail that may change per platform.

Where to read about changes

See also: API, Addon troubleshooting.

Clone this wiki locally