# Loading your worlds

> Give Oasis a world loader for the worlds your plugin keeps, so a rollback can write into them while nobody is in them.

Source: https://oasis-protection.com/docs/api/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.

```java
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

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.

```java
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

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

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

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`](/docs/api/selections/#where), or leave the world out with [`not().in(name)`](/docs/api/selections/#leaving-edits-out), 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

`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.
