nevy 0.3.0

QUIC implementation with quinn for the bevy game engine
Documentation

Nevy

Nevy is a networking library for the bevy game engine. It provides a type erased api over substitutable networking layers.

This is so that your games can use different protocols like QUIC or Web Transport, either at the same time if they are a server, or by choosing a different one depending on what target they are compiled for.

Currently nevy only supports QUIC using quinn, but we will add support for more as we need them.

Getting started

First, insert the plugins.

use nevy::prelude::*;

app.add_plugins(QuicTransportPlugin::default());

An endpoint is an entity that holds an Endpoint component. How you create an endpoint depends on the protocol you are using.

Here, QuicEndpoint::new(...) returns an Endpoint component which you can insert onto an entity.

let endpoint_entity = commands
    .spawn(
        QuicEndpoint::new(
            "0.0.0.0:0",
            quinn_proto::EndpointConfig::default(),
            None,
        ).unwrap(),
    )
    .id();

Connections are represented by an entity that is related to its endpoint by a ConnectionOf component. This component is only ever inserted by you, by either opening or accepting a connection.

Different protocols will expect supporting components on the same entity to start a connection. In this case a QuicConnectionConfig is needed to open a connection.

commands.spawn((
    ConnectionOf(endpoint_entity),
    QuicConnectionConfig {
        client_config: create_connection_config(),
        address: "127.0.0.1:27518".parse().unwrap(),
        server_name: "example.server".to_string(),
    },
));

Whenever a ConnectionOf component exists, a Connection state can be retrieved from its associated Endpoint. This is how you perform operations like sending and receiving data, closing the connection, etc. Any connection entity will also have a ConnectionStatus component, which can be used to check if the connection is connecting, established, closed or failed.

/// When the connection establishes, opens a stream, writes a message, and finishes the stream.
fn write_messages(
    connection_q: Query<(Entity, &ConnectionOf, &ConnectionStatus), Changed<ConnectionStatus>>,
    mut endpoint_q: Query<&mut Endpoint>,
) -> Result {
    for (connection_entity, &ConnectionOf(endpoint_entity), status) in &connection_q {
        let ConnectionStatus::Established = status else {
            continue;
        };

        let mut endpoint = endpoint_q.get_mut(endpoint_entity)?;
        let mut connection = endpoint.get_connection(connection_entity)?;

        let stream = connection.new_stream(StreamRequirements::UNRELIABLE)?;

        let written = connection.write(&stream, "Hello server!".as_bytes().into(), false)?;
        info!("Wrote {} bytes", written);

        connection.close_send_stream(&stream, true)?;
    }

    Ok(())
}

See the examples for more details, including how nevy's messaging crate works for sending structured data instead of just byte streams.

Bevy versions

Bevy Nevy
0.16 0.1
0.17 0.3