Loading your worlds
A rollback, a restore or an undo writes the world, so the world must be loaded. Oasis loads a world that is not loaded by itself when the world has a folder that Oasis saw. A world your plugin keeps in a storage of its own, such as a slime world, has no such folder. Neither does a world that needs your plugin’s settings, border or spawn when it loads. For those worlds, register a world loader: Oasis then asks your plugin for the world when an operation needs it.
oasis.worlds().register(new ArenaLoader(arenas));Without a loader, an operation with edits in such a world fails at once, before it writes anything, and names the world.
Write a loader
Section titled “Write a loader”A WorldLoader has three methods. Oasis calls each of them on the main thread.
| Method | What Oasis asks |
|---|---|
boolean owns(String world) |
Is this world yours, loaded or not? Answer at once, from what your plugin holds in memory. |
CompletableFuture<World> load(String world) |
Load the world, or give it when it is loaded, and keep it loaded until release. |
void release(String world) |
The operation that loaded the world has ended, with its sweeps. Unload it whenever your plugin would. |
A plugin that has not read its own data yet, such as just after the server starts, when Oasis may already recover an operation, owns every name it may keep. Its load then waits for that data, and fails when the world turns out not to exist.
Complete the future of load from any thread. The operation waits for it without holding up the server. When the world cannot load, complete the future exceptionally: the operation stops with Failure.Reason.WORLD_LOAD, and its message names your plugin, the world and the message of your exception.
public final class ArenaLoader implements WorldLoader{ private final Arenas arenas;
public ArenaLoader(Arenas arenas) { this.arenas = arenas; }
@Override public boolean owns(String world) { return arenas.exists(world); }
@Override public CompletableFuture<World> load(String world) { // The idle unload of your plugin leaves a held arena loaded. arenas.hold(world); return arenas.open(world).whenComplete((loaded, failure) -> { if (failure != null) { arenas.letGo(world); } }); }
@Override public void release(String world) { arenas.letGo(world); }}The hold
Section titled “The hold”Before an operation writes into a world you own, loaded or not, Oasis calls load once. When the operation and its sweeps end, Oasis calls release once for each load that completed with the world. A load that failed gets no release.
Between the two, keep the world loaded, even when the last player leaves it. An operation that finds its world unloaded stops with Failure.Reason.PASS. If your plugin unloads worlds that stand empty, count a held world as busy, as the example does with hold and letGo. Oasis never unloads a world that a loader gave it.
An operation with edits in several worlds holds each of your worlds once, for the whole operation. A world that is already loaded is held too, so a player who leaves it during a long rollback does not let your plugin unload it under the rollback.
Which loader
Section titled “Which loader”For each world of an operation, Oasis asks the loaders in the order they were registered, and the first that owns the name loads it. A world that no loader owns loads from its folder.
Oasis never writes a world that a loader owns through the turbo lane. Turbo writes unloaded chunks into region files, and your plugin reads its own storage. Every chunk of such a world takes the live route, even in a turbo operation.
Worlds nobody can load
Section titled “Worlds nobody can load”Before an operation starts, Oasis checks every world it would write into: the worlds the selection names, or, when it names none, each world where the selection has edits to write. A world that is not loaded, that no loader owns, and that has no folder Oasis can load, is one nobody can load. The operation then fails with Failure.Reason.WORLD_GONE. It writes nothing, in that world or in any other, and Failure.message() names each such world. Name the worlds you want with in, or leave the world out with not().in(name), to run the rest.
A world name that no world, no record of Oasis and no edit of the store knows fails with Failure.Reason.NO_SUCH_WORLD instead. That is a typo, and nothing ran.
A staff member who types /rollback with no in gets the same refusal, with the same names.
Register and unregister
Section titled “Register and unregister”oasis.worlds() has two methods.
| Method | What it does |
|---|---|
register(WorldLoader loader) |
Oasis asks this loader for every operation from now on. A loader registered twice counts once. |
unregister(WorldLoader loader) |
Oasis stops asking this loader. An operation that holds a world through it still calls release when it ends. |
Register your loader once, in onEnable. Oasis drops every loader of your plugin when your plugin disables. A plugin that turns a part of itself off while it stays enabled, such as a module, unregisters that part’s loader itself.