Crate bevy_subworlds

Source
Expand description

Threaded multi-world management and signal transmission for bevy.

A SubWorld is a Component that stores a JoinHandle to a thread running an App. Supported operations include sending an exit signal, checking if the SubWorld has completed its startup schedule, and extracting data with pollable extract systems.

Extraction is when a system is sent to a SubWorld to be ran. The output of this system can be polled with an ExtractHandle, similar to an async task or a bevy task.

Signals are either components or resources. When a Signal is a Resource, it sends or receives signals from a parent world. When a Signal is a Component, it sends and receives signals to/from a subworld. Signals receivers/transmitters are automatically inserted onto the SubWorld as components and within the SubWorld as Resources when SubWorldBuilder::with_signal is called.

§Usage

This simple example spawns a SubWorld and ping/pongs a signal back and forth. It also demonstrates extraction by reading and mutating a resource in the SubWorld.

use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(MinimalPlugins)
        .add_systems(Startup, spawn_subworld)
        .add_systems(Update, (
            send_pings,
            extract_data,
        ))
        .run();
}

// Your custom signal type
enum MySignal {
    Ping,
    Pong
}

#[derive(Resource)]
struct GameData {
    num: u32,
}

fn spawn_subworld(
    world_id: WorldId,
    mut commands: Commands,
) {
    SubWorld::build(world_id, &mut commands)
        .with_signal::<MySignal>() // < register your signal type
        .start(move |app| {
            app
                .insert_resource(GameData { num: 1 })
                .add_systems(Update, respond_to_pings);
        });
}

/// Extract and increment the GameState's `num` variable from each system.
fn extract_data(
    mut query: Query<(&SubWorld, Entity, Option<&mut ExtractHandle<u32>>)>,
    mut commands: Commands,
) {
    for (subworld, entity, handle) in &mut query {
        if let Some(mut handle) = handle {
            if let Ok(num) = handle.poll() {
                log::info!("Extracted Number: '{num}'. Time: '{:?}'", handle.duration().unwrap());
                commands.entity(entity).remove::<ExtractHandle<u32>>();
 
                if num > 100 {
                    subworld.exit();
                }
            }
        } else {
            let handle: ExtractHandle<u32> = subworld.extract(
                move |mut state: ResMut<GameData>| {
                    state.num += 1;
                    state.num
                }
            );

            commands.entity(entity).insert(handle);
        }
    }
}

/// Send pings to Subworlds
fn send_pings(
    mut query: Query<(&mut SignalRx<MySignal>, &SignalTx<MySignal>), With<SubWorld>>,
) {
    for (mut rx, tx) in &mut query {
        for signal in &mut rx {
            match signal {
                MySignal::Ping => log::info!("Ping Received!"),
                MySignal::Pong => {
                    tx.send(MySignal::Ping)
                }
            }
        }

        tx.send(MySignal::Ping);
    }
}

/// Respond to pings as a SubWorld
fn respond_to_pings(
    mut signal_rx: ResMut<SignalRx<MySignal>>,
    signal_tx: Res<SignalTx<MySignal>>,
) {
    for signal in &mut signal_rx {
        match signal {
            MySignal::Ping => {
                let _ = signal_tx.send(MySignal::Pong);
            },
            MySignal::Pong => {}
        }
    }
}

Structs§

ExtractHandle
A Handle to a system running in a SubWorld. This handle can be polled to get the output.
SignalRx
A signal receiver between a SubWorld and SuperWorld. When used as a Resource, these are signals from the SuperWorld it belongs to. When used as a Component, these are signals from the SubWorld it is attached to.
SignalTx
A signal transmitter between a SubWorld and SuperWorld. When used as a Resource, these are signals to the SuperWorld it belongs to. When used as a Component, these are signals to a SubWorld it is attached to.
SubWorld
A Handle to a bevy App running in its own thread.
SubWorldBuilder
SuperWorld
A handle to the parent World of a SubWorld.

Enums§

ExtractError