Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Spaces

A Space is a place where people hear each other. Putting two participants in the same Space connects them.

Choosing keys

A SpaceKey is a string you choose:

SpaceKey.of("lobby")
SpaceKey.of("team-red")
SpaceKey.of("arena-3")
SpaceKey.of("world:overworld/region:12,-4")

Choose a key that can be computed from your own state. Placing a player then becomes a function, and the rest of your code never has to remember where anyone is:

private SpaceKey spaceOf(Player player) {
    Team team = teamOf(player);
    return team == null
            ? SpaceKey.of("lobby")
            : SpaceKey.of("team-" + team.getName());
}

Lifetime

A Space starts existing when the first participant is placed in it, and stops existing shortly after the last one leaves. The default delay is thirty seconds, so that passing briefly through an empty Space does not destroy and rebuild it. There is no create call and no delete call.

Reusing a key after its Space has closed produces a new Space, not the old one reopened. It carries a different SpaceIncarnation, which prevents a stale snapshot from being read as a current one.

Reading who is in a Space

Useful for a /voice list command, a scoreboard or an admin display.

A Space holding one of your own participants is always visible to you. To read one that holds none, ask for it:

session.observeSpace(SpaceKey.of("lobby"));

The cache can then be read at any time:

SpaceSnapshot lobby = session.spaces().get(SpaceKey.of("lobby"));
if (lobby != null) {
    for (SpaceParticipant participant : lobby.participants()) {
        System.out.println(participant.displayName()
                + (participant.mumbleConnected() ? " (connected)" : " (away)"));
    }
}

Changes can also be pushed to you:

session.addSpaceListener(new SpaceListener() {
    @Override
    public void onSpaceUpdated(ControllerSession session, SpaceSnapshot snapshot) {
        refreshScoreboard(snapshot);
    }
});

Every SpaceSnapshot is a complete replacement rather than a patch. Discard the previous value and use the new one.

observeSpace and unobserveSpace only affect the Spaces you asked for explicitly. Unobserving a Space that still holds one of your participants does not stop its updates, since that Space is visible to you regardless.

One-off reads

fetchSpace reads a Space once, without subscribing to it:

session.fetchSpace(SpaceKey.of("arena-3"))
        .thenAccept(snapshot -> showTo(admin, snapshot));

Use it for a command that answers a question once. It does not touch the cache, does not affect later updates, is never retried automatically, and fails if the connection drops before the answer arrives. It also requires an active session, unlike observeSpace, which can be declared at any time.

Use observeSpace when the answer stays on screen, and fetchSpace when it is printed once.

What a snapshot contains

SpaceSnapshot describes one Space at one instant:

MethodMeaning
spaceKey()The key you asked for
participants()Everyone in it, including participants owned by other applications
incarnation()Which materialization of this key this is
spaceRevision()Version counter within that incarnation
publishedGeneration()Which Mumble generation this reflects

Each SpaceParticipant provides participantId(), displayName(), serverMute(), serverDeaf() and mumbleConnected().

A participant you registered whose player has not opened Mumble yet appears in the snapshot with mumbleConnected() false. They are declared but not present in voice.

To order two snapshots of the same key, compare incarnation() first and spaceRevision() only if the incarnations match. Revisions from different incarnations are unrelated numbers.

Sharing a Space between applications

Several controller sessions can place participants in the same Space, and those participants hear each other. Each session owns only the participants it registered: it sees the others in a snapshot, but cannot move, mute or remove them.

Two plugins owning different players and agreeing on a key convention therefore work together without coordinating with each other.