Skip to content

Persistence

Use DataManagerContainer for data that must survive a server restart. Module shuts down its registered data managers as part of the disable lifecycle.

Define persisted data

Use AbstractSerializable for keyed global or feature data. Use SenderSerializable when each record belongs to a player and should be keyed by that player's UUID.

public final class PlayerProfile extends SenderSerializable {
    private int greetings;

    public int getGreetings() {
        return greetings;
    }

    public void incrementGreetings() {
        greetings++;
        change();
    }
}

Persisted classes need a no-argument constructor. Keep runtime-only fields transient, and use change() after mutating an object so an auto-save data manager knows that it needs to be written.

Register and load data

Make the module a DataManagerContainer and register the data class before loading it:

public final class GreetingsModule extends Module implements DataManagerContainer {
    @Override
    public void onEnable() {
        DataManager<PlayerProfile> profiles =
                addDataManager("player-profiles", PlayerProfile.class);
        profiles.setStrictSaving(true);
    }

    public PlayerProfile profile(UUID playerId) {
        return getOrCreate(playerId, PlayerProfile.class);
    }

    @Override
    public void onDisable() {
        // KCommon shuts down registered data managers after this method.
    }
}

The manager uses a local data store by default. Changed cached objects are written on the normal save cycle, and module shutdown saves the remaining cached objects. setStrictSaving(true) makes shutdown write only objects marked with change(), which is useful for larger data sets.

Pass true as the third argument to addDataManager to request the remote Mongo-backed manager:

addDataManager("player-profiles", PlayerProfile.class, true);

Only use the remote manager when MongoDB is configured and available in the runtime environment.

Data operations

DataManagerContainer provides type-safe helpers:

PlayerProfile profile = getOrCreate(player.getUniqueId(), PlayerProfile.class);
PlayerProfile loaded = loadData(player.getUniqueId(), PlayerProfile.class);
boolean exists = dataExists(player.getUniqueId(), PlayerProfile.class);
saveData(profile);
deleteData(profile);

Use saveData when an immediate write is required. Otherwise, mark changed objects and let the registered manager handle its normal persistence cycle.

When a record is a snapshot of transient module state, capture the final state and call saveData from onDisable() before KCommon shuts down the data manager:

@Override
public void onDisable() {
    runtimeData.capture(activeState);
    saveData(runtimeData);
}

If a persisted object owns runtime resources, reattach them after loading:

for (GreetingProfile profile : getAllDataOfType(GreetingProfile.class)) {
    profile.bind(this);
}

Use SenderSerializable when the key is always a player UUID. If the same record can belong to a player, island, block, or another scope, use AbstractSerializable and assign the appropriate stable key yourself.