Interacting through agents
Use process capabilities backed by native server or proxy agents without creating a player.
Use an agent-backed process capability when a test needs to read or change state through the server or proxy's native API. Retrieve the capability directly from the running process. The process owns the behavior; its platform agent supplies the native implementation. This does not require a simulated player or a game session.
Retrieve a process capability
Look up a capability on the process handle, for example
anvil.processes().server("lobby").capability(Dispatch.class) with the built-in
Dispatch capability, which runs a command as the console through the platform agent.
Capability retrieval fails with CapabilityUnavailableException when the installed providers do not supply the
requested type. Use process.hasCapability(type) only when absence is an intentional supported case; it reports
whether the capability is installed, not whether its next request will succeed.
Choose the owner and interaction
| Task | Entry point |
|---|---|
| Run a command as the console and know whether the platform accepted it | The process's Dispatch capability |
| Send console input or inspect captured process output | The process's console |
| Read or change plugin state with a typed result | An installed process capability calling a native operation |
| Know who is on a server or proxy, the profile it sees, or a player's backend | The process's Players capability |
| Restart one process | Restarting processes |
A capability's owner follows who can normally do or know the thing, not how it is implemented.
Dispatch and Players belong to the process because running a console command and knowing who is
on it are what a server or proxy does; both happen to use its agent. A custom process capability can
use another implementation without exposing an agent in its public API.
Call an external capability
The Echo example supplies a process capability
that calls an installed handler. Add its host adapter to anvilImplementation, and install its
handler JAR in lobby.
Inside a test with the running ScenarioContext anvil, use:
import com.example.echo.Echo;
import static org.junit.jupiter.api.Assertions.assertEquals;
var lobby = anvil.processes().server("lobby");
assertEquals("echo:hello", lobby.capability(Echo.class).send("hello"));Success establishes that the handler in lobby returned echo:hello. Replace Echo with an
operation that returns the application state your test needs to assert. The result contains
serializable values, not the platform's live objects.
Process capability instances remain stable across a JVM restart. Retrieve the current process handle for state and console observations; the replacement handle exposes the same capability instances. Agent-backed requests can fail while the replacement connection is unavailable; retry only after the process has started successfully.
Closing the scenario closes process capabilities after players and before their agent connections.
Subsequent capability lookup fails and hasCapability(...) returns false. Do not use retained
capability instances after that cleanup.
Add native behavior
A host capability provider calls a typed operation through its borrowed RequestChannel.
Anvil connects that channel to the process's agent client. The matching AgentOperationProvider
installs the handler inside the managed JVM. These are separate
extension points: adding the host dependency does not install the native handler.
Follow Agent providers for host wiring
and Contracts and handlers for native
implementation. Install handlers as workspace assets under plugins/anvil-agent-extensions.
Handlers access native services through PlatformAgent.requireService(...). The bundled Bukkit
agent exposes org.bukkit.Server; Velocity and BungeeCord agents expose their proxy APIs.
Use platform.call(...) and follow the native API's threading rules.
If a request fails, check agent readiness, handler installation and service descriptors, matching
operation contracts, and the target process's anvil-console.log.