Anvil
Building blocksPlayersCapabilities

Session

Connect and reconnect a native player and wait for login, disconnection, or a kick.

Session controls the current network connection. Install the session unit or explicitly select the default capability unit; the bundled implementation requires MCProtocol. All fragments below use a live test's ScenarioContext anvil and import me.whereareiam.anvil.capability.session.Session.

Connect and await login

var alice = anvil.players().create("Alice");
var session = alice.capability(Session.class);
session.connect();
session.connected();

connect() starts login. connected() waits for it to complete. The overload without a duration uses the player default timeout of ten seconds; add import java.time.Duration; to supply another bound:

session.connected(Duration.ofSeconds(20));

To await arrival on a named backend, watch that backend's Players capability before connect() and call joined(player) on the watch after login.

Disconnect and rejoin

After Alice has connected, use the existing session to leave and start a fresh connection:

session.disconnect();
session.disconnected();

session.rejoin();
session.connected();

Disconnecting keeps the player object registered. Rejoining retains that player and its capability instances, uses its configured identity and target, and resets Session's connection and kick state. It does not create a replacement player or prove that plugin data survived. Other capabilities can retain observations; see Messages history. After login, wait for the player's join on the expected backend and assert the application state you need. A proxy or backend may report a profile different from the configured one; see watching players on a process.

Observe a kick

For the direct Paper scenario from the first test, after Alice joins:

anvil.processes().server("server").console()
		.sendCommand("kick Alice anvil-reconnect-test");
String reason = session.kicked();

kicked() waits for the current session's kick and returns its plain-text reason. Assert the expected reason using JUnit rather than treating any disconnect as the correct application behavior. A network disconnect and a server kick are different observations.

When a kick is only one of several correct outcomes, pass session.expectKicked(), or session.expectDisconnected() for any disconnect, to player.awaitFirst(...); see waiting for whichever outcome comes first.

To try a fresh session afterwards:

session.rejoin();
session.connected();

Read state without waiting

session.state().connected() and session.state().kickReason() read the current snapshot immediately. They are useful after a wait or for diagnostics. Reading connected() on the snapshot directly after starting login may still return false; use the capability's wait for an asynchronous assertion.

Tell why a connection ended

session.state().disconnectCause() says what ended the last connection:

CauseMeaning
SERVERThe server or proxy disconnected the player and sent a reason, as a kick does.
AUTHENTICATION_REQUIREDThe entry point required online authentication from a player that signs in with no account.
CONNECTION_LOSTThe connection closed without a reason from the server.
CLIENTThe player disconnected itself through disconnect() or rejoin().
String reason = session.kicked();
assertEquals(DisconnectCause.SERVER, session.state().disconnectCause());

Import me.whereareiam.anvil.api.type.DisconnectCause. A server's reason always wins over the closed connection that follows it, so a kick reads as SERVER with its text even when the connection closes first. A connection that closes without a reason is reported about 300 milliseconds later, once no reason has followed. The cause is null while the player is connected.

To permanently release the player and reuse its name, see releasing and replacing players.

On this page