2 releases

new 0.15.0-rc.2 Oct 27, 2024
0.15.0-rc.1 Oct 22, 2024

#2205 in Game dev

Download history 516/week @ 2024-10-22

517 downloads per month

MIT/Apache

4MB
66K SLoC

An implementation of the Bevy Remote Protocol, to allow for remote control of a Bevy app.

Adding the RemotePlugin to your [App] will setup everything needed without starting any transports. To start accepting remote connections you will need to add a second plugin like the RemoteHttpPlugin to enable communication over HTTP. These remote clients can inspect and alter the state of the entity-component system.

The Bevy Remote Protocol is based on the JSON-RPC 2.0 protocol.

Request objects

A typical client request might look like this:

{
    "method": "bevy/get",
    "id": 0,
    "params": {
        "entity": 4294967298,
        "components": [
            "bevy_transform::components::transform::Transform"
        ]
    }
}

The id and method fields are required. The params field may be omitted for certain methods:

  • id is arbitrary JSON data. The server completely ignores its contents, and the client may use it for any purpose. It will be copied via serialization and deserialization (so object property order, etc. can't be relied upon to be identical) and sent back to the client as part of the response.

  • method is a string that specifies one of the possible BrpRequest variants: bevy/query, bevy/get, bevy/insert, etc. It's case-sensitive.

  • params is parameter data specific to the request.

For more information, see the documentation for BrpRequest. BrpRequest is serialized to JSON via serde, so the serde documentation may be useful to clarify the correspondence between the Rust structure and the JSON format.

Response objects

A response from the server to the client might look like this:

{
    "jsonrpc": "2.0",
    "id": 0,
    "result": {
        "bevy_transform::components::transform::Transform": {
            "rotation": { "x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0 },
            "scale": { "x": 1.0, "y": 1.0, "z": 1.0 },
            "translation": { "x": 0.0, "y": 0.5, "z": 0.0 }
        }
    }
}

The id field will always be present. The result field will be present if the request was successful. Otherwise, an error field will replace it.

  • id is the arbitrary JSON data that was sent as part of the request. It will be identical to the id data sent during the request, modulo serialization and deserialization. If there's an error reading the id field, it will be null.

  • result will be present if the request succeeded and will contain the response specific to the request.

  • error will be present if the request failed and will contain an error object with more information about the cause of failure.

Error objects

An error object might look like this:

{
    "code": -32602,
    "message": "Missing \"entity\" field"
}

The code and message fields will always be present. There may also be a data field.

  • code is an integer representing the kind of an error that happened. Error codes documented in the error_codes module.

  • message is a short, one-sentence human-readable description of the error.

  • data is an optional field of arbitrary type containing additional information about the error.

Built-in methods

The Bevy Remote Protocol includes a number of built-in methods for accessing and modifying data in the ECS. Each of these methods uses the bevy/ prefix, which is a namespace reserved for BRP built-in methods.

bevy/get

Retrieve the values of one or more components from an entity.

params:

  • entity: The ID of the entity whose components will be fetched.
  • components: An array of fully-qualified type names of components to fetch.
  • strict (optional): A flag to enable strict mode which will fail if any one of the components is not present or can not be reflected. Defaults to false.

If strict is false:

result:

  • components: A map associating each type name to its value on the requested entity.
  • errors: A map associating each type name with an error if it was not on the entity or could not be reflected.

If strict is true:

result: A map associating each type name to its value on the requested entity.

bevy/query

Perform a query over components in the ECS, returning all matching entities and their associated component values.

All of the arrays that comprise this request are optional, and when they are not provided, they will be treated as if they were empty.

params:

  • data:
    • components (optional): An array of fully-qualified type names of components to fetch.
    • option (optional): An array of fully-qualified type names of components to fetch optionally.
    • has (optional): An array of fully-qualified type names of components whose presence will be reported as boolean values.
  • filter (optional):
    • with (optional): An array of fully-qualified type names of components that must be present on entities in order for them to be included in results.
    • without (optional): An array of fully-qualified type names of components that must not be present on entities in order for them to be included in results.

result: An array, each of which is an object containing:

  • entity: The ID of a query-matching entity.
  • components: A map associating each type name from components/option to its value on the matching entity if the component is present.
  • has: A map associating each type name from has to a boolean value indicating whether or not the entity has that component. If has was empty or omitted, this key will be omitted in the response.

bevy/spawn

Create a new entity with the provided components and return the resulting entity ID.

params:

result:

  • entity: The ID of the newly spawned entity.

bevy/destroy

Despawn the entity with the given ID.

params:

  • entity: The ID of the entity to be despawned.

result: null.

bevy/remove

Delete one or more components from an entity.

params:

  • entity: The ID of the entity whose components should be removed.
  • components: An array of fully-qualified type names of components to be removed.

result: null.

bevy/insert

Insert one or more components into an entity.

params:

  • entity: The ID of the entity to insert components into.
  • components: A map associating each component's fully-qualified type name with its value.

result: null.

bevy/reparent

Assign a new parent to one or more entities.

params:

  • entities: An array of entity IDs of entities that will be made children of the parent.
  • parent (optional): The entity ID of the parent to which the child entities will be assigned. If excluded, the given entities will be removed from their parents.

result: null.

bevy/list

List all registered components or all components present on an entity.

When params is not provided, this lists all registered components. If params is provided, this lists only those components present on the provided entity.

params (optional):

  • entity: The ID of the entity whose components will be listed.

result: An array of fully-qualified type names of components.

bevy/get+watch

Watch the values of one or more components from an entity.

params:

  • entity: The ID of the entity whose components will be fetched.
  • components: An array of fully-qualified type names of components to fetch.
  • strict (optional): A flag to enable strict mode which will fail if any one of the components is not present or can not be reflected. Defaults to false.

If strict is false:

result:

  • components: A map of components added or changed in the last tick associating each type name to its value on the requested entity.
  • removed: An array of fully-qualified type names of components removed from the entity in the last tick.
  • errors: A map associating each type name with an error if it was not on the entity or could not be reflected.

If strict is true:

result:

  • components: A map of components added or changed in the last tick associating each type name to its value on the requested entity.
  • removed: An array of fully-qualified type names of components removed from the entity in the last tick.

bevy/list+watch

Watch all components present on an entity.

When params is not provided, this lists all registered components. If params is provided, this lists only those components present on the provided entity.

params:

  • entity: The ID of the entity whose components will be listed.

result:

  • added: An array of fully-qualified type names of components added to the entity in the last tick.
  • removed: An array of fully-qualified type names of components removed from the entity in the last tick.

Custom methods

In addition to the provided methods, the Bevy Remote Protocol can be extended to include custom methods. This is primarily done during the initialization of RemotePlugin, although the methods may also be extended at runtime using the RemoteMethods resource.

Example

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(
            // `default` adds all of the built-in methods, while `with_method` extends them
            RemotePlugin::default()
                .with_method("super_user/cool_method", path::to::my::cool::handler)
                // ... more methods can be added by chaining `with_method`
        )
        .add_systems(
            // ... standard application setup
        )
        .run();
}

The handler is expected to be a system-convertible function which takes optional JSON parameters as input and returns a BrpResult. This means that it should have a type signature which looks something like this:

fn handler(In(params): In<Option<Value>>, world: &mut World) -> BrpResult {
    todo!()
}

Arbitrary system parameters can be used in conjunction with the optional Value input. The handler system will always run with exclusive World access.

Dependencies

~10–23MB
~340K SLoC