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:
| Cause | Meaning |
|---|---|
SERVER | The server or proxy disconnected the player and sent a reason, as a kick does. |
AUTHENTICATION_REQUIRED | The entry point required online authentication from a player that signs in with no account. |
CONNECTION_LOST | The connection closed without a reason from the server. |
CLIENT | The 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.