NOTE: VERSION 1.X.X WILL BE YANKED AND REPLACE WITH VERSION 0.X.X TO ALIGN WITH BEVY'S VERSIONING SCHEME
This plugin will provide you with:
- A resource
StdbConnectionto call your reducers, subscribe to tables, etc. - Connection lifecycle messages:
StdbConnectedMessage,StdbDisconnectedMessage,StdbConnectionErrorMessageas Bevy'sMessageReader - All the table messages (row inserted/updated/deleted):
MessageReader:ReadInsertMessage<T>ReadUpdateMessage<T>ReadInsertUpdateMessage<T>ReadDeleteMessage<T>
Check the example app in /example_app for a complete example of how to use the plugin.
This plugin is compatible with Bevy 0.15.x, 0.16.x, and 0.17.x; the latest version targets Bevy 0.17.x.
| bevy_spacetimedb version | Bevy version |
|---|---|
| <= 0.3.x | 0.15.x |
| 0.4.x - 1.0.x | 0.16.x |
| >= 0.7.0 | 0.17.x |
- Add the plugin to your project:
cargo add bevy_spacetimedb - Add the plugin to your Bevy application:
use bevy::{log::LogPlugin, prelude::*};
App::new()
.add_plugins((MinimalPlugins, LogPlugin::default()))
.add_plugins(
StdbPlugin::default()
.with_uri("http://localhost:3000")
.with_module_name("chat")
.with_run_fn(DbConnection::run_threaded)
.add_table(RemoteTables::lobby)
.add_table(RemoteTables::user)
.add_partial_table(RemoteTables::player, TableMessages::no_update())
.add_reducer::<CreateLobby>()
.add_reducer::<SetName>(),
)- Add a system handling connection messages
You can also add systems for
StdbDisconnectedMessageandStdbConnectionErrorMessage
fn on_connected(
mut messages: ReadStdbConnectedMessage,
stdb: Res<StdbConnection<DbConnection>>,
) {
for _ in messages.read() {
info!("Connected to SpacetimeDB");
// Call any reducers
stdb.reducers()
.my_super_reducer("A suuuuppeeeeer argument for a suuuuppeeeeer reducer")
.unwrap();
// Subscribe to any tables
stdb.subscription_builder()
.on_applied(|_| info!("Subscription to players applied"))
.on_error(|_, err| error!("Subscription to players failed for: {}", err))
.subscribe("SELECT * FROM players");
// Access your database cache (since it's not yet populated here this line might return 0)
info!("Players count: {}", stdb.db().players().count());
}
}- Add any systems that you need in order to handle the table messages you declared and do whatever you want:
fn on_player_inserted(mut messages: ReadInsertMessage<Player>, mut commands: Commands) {
for message in messages.read() {
commands.spawn(Player { id: message.row.id });
info!("Player inserted: {:?} -> {:?}", message.row);
}
}
fn on_player_updated(mut messages: ReadUpdateMessage<Player>) {
for message in messages.read() {
info!("Player updated: {:?} -> {:?}", message.old, message.new);
}
}
fn on_player_insert_update(mut messages: ReadInsertUpdateMessage<Player>, q_players: Query<Entity, Player>) {
for message in messages.read() {
info!("Player deleted: {:?} -> {:?}", message.row);
// Delete the player's entity
}
}
fn on_player_deleted(mut messages: ReadDeleteMessage<Player>, q_players: Query<Entity, Player>) {
for message in messages.read() {
info!("Player deleted: {:?} -> {:?}", message.row);
// Delete the player's entity
}
}You can use Res<StdbConnection<DbConnection>> to get the resource but this is
quite verbose, you can create the following type alias for convenience:
pub type SpacetimeDB<'a> = Res<'a, StdbConnection<DbConnection>>;
fn my_system(stdb: SpacetimeDB) {
// Use the `DbConnection` type alias
stdb.reducers().my_reducer("some argument").unwrap();
}Special thanks to:
- @abos-gergo for the improvements toward reducing the boilerplate needed to use the plugin
- @PappAdam for the improvements toward reducing the boilerplate needed to use the plugin