Getting started
The API is one small jar, com.oasis:oasis-api. It holds interfaces and a few records and enums. The Oasis plugin on the server holds the code behind them, so your plugin compiles against the jar and Oasis provides it at runtime.
The API needs Java 21 or newer and Paper 1.21.11 or newer.
Set up your plugin
Section titled “Set up your plugin”-
Add the repository and the dependency.
The API is on the Oasis Maven repository,
https://telesphorepo.com/maven/oasis/. The current version is3.0-SNAPSHOT.build.gradle.kts repositories {maven("https://repo.papermc.io/repository/maven-public/")maven("https://telesphorepo.com/maven/oasis/")}dependencies {compileOnly("io.papermc.paper:paper-api:1.21.11-R0.1-SNAPSHOT")compileOnly("com.oasis:oasis-api:3.0-SNAPSHOT")}build.gradle repositories {maven { url = 'https://repo.papermc.io/repository/maven-public/' }maven { url = 'https://telesphorepo.com/maven/oasis/' }}dependencies {compileOnly 'io.papermc.paper:paper-api:1.21.11-R0.1-SNAPSHOT'compileOnly 'com.oasis:oasis-api:3.0-SNAPSHOT'}pom.xml <repositories><repository><id>papermc</id><url>https://repo.papermc.io/repository/maven-public/</url></repository><repository><id>oasis</id><url>https://telesphorepo.com/maven/oasis/</url></repository></repositories><dependencies><dependency><groupId>io.papermc.paper</groupId><artifactId>paper-api</artifactId><version>1.21.11-R0.1-SNAPSHOT</version><scope>provided</scope></dependency><dependency><groupId>com.oasis</groupId><artifactId>oasis-api</artifactId><version>3.0-SNAPSHOT</version><scope>provided</scope></dependency></dependencies> -
Keep the API out of your jar.
Use
compileOnlyin Gradle andprovidedin Maven, as above. Never shade or relocate the API into your plugin. Oasis provides those classes on the server, and a second copy in your jar is a different class to Java. Oasis would not recognize it, andOasis.api(this)would fail. -
Declare Oasis in your plugin file.
Oasis must enable before your plugin, so the API is ready in your
onEnable. Usedependwhen your plugin can’t run without Oasis, andsoftdependwhen Oasis is optional.plugin.yml name: GriefRevertversion: 1.0.0main: com.example.griefrevert.GriefRevertapi-version: '1.21.11'# Oasis is required:depend: [Oasis]# Or, when Oasis is optional:# softdepend: [Oasis]paper-plugin.yml name: GriefRevertversion: 1.0.0main: com.example.griefrevert.GriefRevertapi-version: '1.21.11'dependencies:server:Oasis:load: BEFORE# false when Oasis is optionalrequired: true# Lets your plugin see the com.oasis.api classes.join-classpath: trueA Paper plugin needs
join-classpath: true. Without it, your plugin can’t load thecom.oasis.apiclasses even when Oasis runs. -
Get the API in
onEnable.Ask for the API once, with your own plugin, and keep it in a field.
package com.example.griefrevert;import com.oasis.api.Oasis;import com.oasis.api.OasisApi;import org.bukkit.plugin.java.JavaPlugin;public final class GriefRevert extends JavaPlugin{private OasisApi oasis;@Overridepublic void onEnable(){oasis = Oasis.api(this);}}Oasis.api(this)throwsIllegalStateExceptionwhen Oasis is not enabled. Withdepend, Paper doesn’t enable your plugin without Oasis, so that only happens when Oasis itself failed to start.The API you get acts for your plugin. See What the API acts for.
When Oasis is optional
Section titled “When Oasis is optional”With softdepend, your plugin also runs on servers without Oasis. On those servers the com.oasis.api classes are not on the classpath at all. Java loads a class the first time your code needs it, so any code that names an Oasis type throws NoClassDefFoundError when it runs, or when Java loads the class that holds it.
The safe pattern is to keep every Oasis reference in one class of your own, and to load that class only after you check that Oasis is enabled. Your main class names only that class, never an Oasis type.
package com.example.softdepend;
import com.oasis.api.Cause;import com.oasis.api.Oasis;import com.oasis.api.OasisApi;import org.bukkit.block.BlockState;import org.bukkit.entity.Player;import org.bukkit.plugin.Plugin;
/** Every Oasis call of the plugin. Nothing else in the plugin imports com.oasis.api. */final class OasisHook{ private final OasisApi api;
OasisHook(Plugin plugin) { api = Oasis.api(plugin); }
void placed(Player player, BlockState before, BlockState after) { api.logger().by(player).block(Cause.PLACING, before, after); }}package com.example.softdepend;
import org.bukkit.block.BlockState;import org.bukkit.entity.Player;import org.bukkit.plugin.java.JavaPlugin;
public final class SoftDepend extends JavaPlugin{ /** Null when Oasis is not on the server. */ private OasisHook oasis;
@Override public void onEnable() { if (getServer().getPluginManager().isPluginEnabled("Oasis")) { oasis = new OasisHook(this); getLogger().info("Oasis found. Edits of this plugin go into its history."); } }
/** Called by the rest of the plugin, with or without Oasis. */ public void logPlacement(Player player, BlockState before, BlockState after) { if (oasis != null) { oasis.placed(player, before, after); } }}A field or a variable of type OasisHook is safe, because Java loads OasisHook only when the code first creates one or calls it. Keep these rules:
- No
com.oasis.apiimport in the main class, or in any class that loads when Oasis is missing. - No Oasis type in a field, a parameter, a return type, a lambda or a method reference of those classes.
- Register an Oasis event listener from inside the hook class, after the check. A listener class names the event type, so it must not load on a server without Oasis.
The Javadoc in your IDE
Section titled “The Javadoc in your IDE”Oasis publishes a sources jar and a Javadoc jar beside the API jar. Your IDE shows the Javadoc of every method as you type, and the Javadoc states the same rules as these pages: the thread of each callback, what throws, and what each value means.
IntelliJ IDEA downloads the sources for a Gradle project on its own. In a Maven project, click Download Sources in the editor banner, or run mvn dependency:sources.