Bevy Remote Events
Magically send and receive events to an arbitrary remote server. Websockets under the hood; web & desktop support
Description
This repository contains a plugin for the Bevy game engine. This plugin allows games to easily define events that can be sent and received from some arbitary websocket server.
TODO
This library is quite immature; many features still need to be added for it to be considered "complete".
- WS Connection from desktop
- WS Connection from wasm
- Frame independent event buffering
- User initiated disconnect on desktop
- User initiated disconnect on wasm
- Handle remote disconnect
- Emit events for non-user-initiated lifecycle events
- Correctly track status of underlying connection
- Automatic reconnection
- Map received events to user defined types
- Send events of a user defined type
Installation
remote_events
is not currently available on Cargo; instead, you need to use a Git dependency. Add the following to your project's Cargo.toml
file:
remote_events = { git = "https://lab.lcr.gr/microhacks/micro-bevy-remote-events", branch = "trunk" }
Usage
You need to define two event types; one for events you expect to send to the remote server, and one for events you expect to receive. Typically this will be an enum
type.
These types need to implement ToSocketMessage
and FromSocketMessage
respectively.
remote_events
expects every received event to be mapped to a type within your project; this might require a custom None
type added to your event enum
(see below).
A client will only be created when you emit a SocketControlEvent::Connect(String)
event containing the URL of the remote host to connect to.
The Desktop
target can only handle insecure websocket connections (ws://
, not wss://
).
use remote_events::events::{FromSocketMessage, SocketControlEvent, ToSocketMessage};
use serde::{Serialize, Deserialize};
use serde_json::from_string;
#[derive(Default, Clone, Debug, Deserialize)]
pub enum ReceivedEvents {
PlayerJoined {
player_id: String,
},
PlayerHasClicked {
player_id: String,
},
SetPlayerClickCount {
player_id: String,
amount: usize,
},
#[default]
// Catch and handle invalid data as part of our events
InvalidEvent,
}
impl FromSocketMessage for ReceivedEvents {
// Our server sends string encoded JSON values
fn from_text(value: String) -> Self {
serde_json::from_str(&value)
.unwrap_or_default()
}
// Our server only sends text values, assume binary is just encoded text
fn from_binary(value: Vec<u8>) -> Self {
Self::from_text(String::from_utf8(value).unwrap_or(String::new()))
}
}
pub fn connect_to_server(mut events: EventWriter<SocketControlEvent>) {
events.send(SocketControlEvent::Connect(String::from("ws://localhost:3000")));
}
#[derive(Default, Clone, Debug, Serialize)]
pub enum SentEvents {
ButtonClicked,
SpendClicks {
amount: usize,
},
}
impl ToSocketMessage for ReceivedEvents {
fn to_text(&self) -> String {
serde_json::to_string(&self).unwrap()
}
}
pub fn main() {
App::new()
// .. Other plugins ..
.add_startup_system(connect_to_server)
.add_plugin(
RemoteEventPlugin::<SentEvents, ReceivedEvents>::new()
);
}