Developer API
For plugins that open worlds from templates: minigames resetting an arena, duels opening one world per match, events, build servers. The server owner installs FastWorldLoader; your plugin only compiles against the API.
Dependency
The API is free to compile against; the API classes come from the installed FastWorldLoader jar at runtime, so don't shade them.
Not on Maven Central yet
The FastWorldLoader-API artifact will be published to Maven Central soon; the coordinates below are the ones it will have.
dependencies {
compileOnly("io.github.erano01:FastWorldLoader-API:1.0.0")
}<dependency>
<groupId>io.github.erano01</groupId>
<artifactId>FastWorldLoader-API</artifactId>
<version>1.0.0</version>
<scope>provided</scope>
</dependency>plugin.yml: softdepend: [FastWorldLoader] (or depend if your plugin can't work without it), so FastWorldLoader enables first.
Getting the service
FastWorlds worlds = null;
if (Bukkit.getPluginManager().isPluginEnabled("FastWorldLoader")) {
worlds = Bukkit.getServicesManager().load(FastWorlds.class);
}With softdepend, keep every reference to me.erano.com.fwl.api classes in a class you only load when FastWorldLoader is enabled; on a server without it, loading that class would throw NoClassDefFoundError.
Templates and worlds
// Once (an admin command, or at setup): a world folder becomes a template.
worlds.importFolder(new File(Bukkit.getWorldContainer(), "maps/castle"), "castle")
.whenComplete((ok, error) -> { /* runs off the server thread */ });
// Every game (server thread): open, play, close.
World arena = worlds.open("castle", "castle-game-12");
// ...
for (Player player : arena.getPlayers()) {
player.teleport(lobby); // close refuses while players are inside
}
worlds.close(arena); // changes are thrown away, the folder deleted| Method | Thread | Notes |
|---|---|---|
importFolder(folder, template) | any, future | the folder's overworld, else its only dimension |
importFolder(folder, template, environment) | any, future | one dimension of a folder that has several |
open(template, world) / open(template, world, options) | server | throws IllegalArgumentException (no template, bad name), IllegalStateException (name taken, couldn't open, or a template saved by a newer server) |
close(world) | server | false while players are inside or if the server refuses to unload |
saveAsTemplate(world, template) | server, future | an admin's edit becomes the template; the old one is replaced only once the new one is written |
exportTemplate(template, folder) | server, future | the template as a normal world folder; the folder must not exist or be empty |
deleteTemplate(template) | any, future | worlds open from it keep working |
hasTemplate, templates, templateOf(world), openWorlds() | any / server | templateOf is empty for worlds FastWorldLoader didn't open |
apiVersion() | any | the newest API the installed FastWorldLoader has |
Names (templates and worlds): letters, digits, _ - ., at most 64 characters.
Open options
World end = worlds.open("castle", "castle-end-1", OpenOptions.builder()
.environment(World.Environment.THE_END) // open the template as another dimension
.keepSpawnLoaded(false) // default: config keep-spawn-loaded
.build());Events
| Event | When | Thread |
|---|---|---|
FastWorldOpenEvent | a world was opened (after Bukkit's WorldLoadEvent) | server |
FastWorldCloseEvent | a world opened by FastWorldLoader is about to close (still loaded) | server |
TemplateSaveEvent | a template was imported (Cause.IMPORT) or saved from a world (Cause.SAVE) | async |
TemplateDeleteEvent | a template was deleted | async |
On a shared (MYSQL) store, TemplateSaveEvent and TemplateDeleteEvent fire on the server that made the change.
Versioning
The API follows semantic versioning: 1.x only adds. Methods and events carry @since; apiVersion() returns the newest the installed FastWorldLoader has, so a plugin built against a newer API can check before calling something an older FastWorldLoader doesn't have.
if (worlds.apiVersion() >= 2) {
// a method added in API 2
}Only FastWorldLoader implements FastWorlds; don't implement it yourself — new methods would break your class.