Crate lightyear

source ·
Expand description

§Lightyear

Lightyear is a networking library for Bevy. It is designed for server-authoritative multiplayer games; and aims to be both feature-complete and easy-to-use.

You can find more information in the book or check out the examples!

§Getting started

§Install the plugins

lightyear provides two plugins groups: ServerPlugins and ClientPlugins that will handle the networking for you.

use bevy::utils::Duration;
use bevy::prelude::*;
use lightyear::prelude::*;
use lightyear::prelude::client::*;
use lightyear::prelude::server::*;

fn run_client_app() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(ClientPlugins::new(ClientConfig::default()))
        .run()
}

fn run_server_app() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(ServerPlugins::new(ServerConfig::default()))
        .run()
}

In general, you will have to modify some parts of the ClientConfig and ServerConfig to fit your game. Mostly the SharedConfig, which must be the same on both the client and the server, and the NetConfig which defines how the client and server will communicate.

§Implement the protocol

The Protocol is the set of types that can be sent over the network. You will have to define your protocol in a shared module that is accessible to both the client and the server, since the protocol must be shared between them.

There are several steps:

§Using lightyear

Lightyear provides various commands and resources that can you can use to interact with the plugin.

§Connecting/Disconnecting

On the client, you can initiate the connection by using the connect_client Command. You can also disconnect with the disconnect_client Command.

On the server, you can start listening for connections by using the start_server Command. You can stop the server using the stop_server Command.

While the client or server are disconnected, you can update the ClientConfig and ServerConfig resources, and the new configuration will take effect on the next connection attempt.

§Sending messages

On both the client and the server, you can send messages using the ConnectionManager resource.

use bevy::prelude::*;
use lightyear::prelude::*;
use lightyear::prelude::server::*;

#[derive(Serialize, Deserialize)]
struct MyMessage;

#[derive(Channel)]
struct MyChannel;

fn send_message(mut connection_manager: ResMut<ConnectionManager>) {
    let _ = connection_manager.send_message_to_target::<MyChannel, MyMessage>(&MyMessage, NetworkTarget::All);
}

§Receiving messages

All network events are sent as Bevy events. The full list is available here for the client, and here for the server.

Since they are Bevy events, you can use the Bevy event system to react to them.

use bevy::prelude::*;
use lightyear::prelude::*;
use lightyear::prelude::server::*;


fn receive_message(mut message_reader: EventReader<MessageEvent<MyMessage>>) {
    for message_event in message_reader.read() {
       // the message itself
       let message = message_event.message();
       // the client who sent the message
       let client = message_event.context;
    }
}

§Starting replication

To replicate an entity from the local world to the remote world, you can just add the Replicate bundle to the entity. The Replicate bundle contains many components to customize how the entity is replicated.

The marker component Replicating indicates that the entity is getting replicated to a remote peer. You can remove the Replicating component to pause the replication. This will not despawn the entity on the remote world; it will simply stop sending replication updates.

In contrast, the ReplicationTarget component is used to indicate which clients you want to replicate this entity to. If you update the target to exclude a given client, the entity will get despawned on that client.

On the receiver side, entities that are replicated from a remote peer will have the Replicated marker component.

§Reacting to replication events

Similarly to messages, you can react to replication events using Bevy’s event system.

use bevy::prelude::*;
use lightyear::prelude::*;
use lightyear::prelude::client::*;


fn component_inserted(mut events: EventReader<ComponentInsertEvent<MyComponent>>) {
    for event in events.read() {
       // the entity on which the component was inserted
       let entity = event.entity();
    }
}

Lightyear also inserts the Replicated marker component on every entity that was spawned via replication, so you can achieve the same result with:

use bevy::prelude::*;
use lightyear::prelude::*;
use lightyear::prelude::client::*;


fn component_inserted(query: Query<Entity, (With<Replicated>, Added<MyComponent>)>) {
    for entity in query.iter() {
        println!("MyComponent was inserted via replication on {entity:?}");
    }
}

Modules§

  • Channels are used to add reliability/ordering on top of the transport layer
  • Modules related to the client
  • A connection is an abstraction over an unreliable transport of a connection between a client and server
  • Handles networking client inputs
  • Module to group messages into packets
  • Prelude containing commonly used types
  • The Protocol is used to define all the types that can be sent over the network
  • Serialization and deserialization of types
  • Defines the Server bevy resource
  • Shared code between the server and client.
  • Provides an abstraction over an unreliable transport The transport layer is responsible for sending and receiving raw byte arrays packets through the network.
  • Extra utilities Contains a set of useful utilities