# 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](https://bevyengine.org/) 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". - [x] WS Connection from desktop - [x] WS Connection from wasm - [x] Frame independent event buffering - [x] User initiated disconnect on desktop - [x] User initiated disconnect on wasm - [x] Handle remote disconnect - [ ] Emit events for non-user-initiated lifecycle events - [ ] Correctly track status of underlying connection - [ ] Automatic reconnection - [x] Map received events to user defined types - [x] 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: ```toml 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://`). ```rust 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() ); } ```