Skip to content
Snippets Groups Projects
README.md 3.36 KiB
Newer Older
Louis's avatar
Louis committed
# Bevy Remote Events

Magically send and receive events to an arbitrary remote server. Websockets under the hood; web & desktop support

## Description

Louis's avatar
Louis committed
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.
Louis's avatar
Louis committed

Louis's avatar
Louis committed
## TODO
Louis's avatar
Louis committed

Louis's avatar
Louis committed
This library is quite immature; many features still need to be added for it to be considered "complete".
Louis's avatar
Louis committed

Louis's avatar
Louis committed
- [x] WS Connection from desktop
- [x] WS Connection from wasm
- [x] Frame independent event buffering
- [x] User initiated disconnect on desktop
Louis's avatar
Louis committed
- [x] User initiated disconnect on wasm
- [x] Handle remote disconnect
- [ ] Emit events for non-user-initiated lifecycle events
- [ ] Correctly track status of underlying connection
Louis's avatar
Louis committed
- [ ] Automatic reconnection
- [x] Map received events to user defined types
- [x] Send events of a user defined type
Louis's avatar
Louis committed

Louis's avatar
Louis committed
## Installation
Louis's avatar
Louis committed

Louis's avatar
Louis committed
`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:
Louis's avatar
Louis committed

Louis's avatar
Louis committed
```toml
Louis's avatar
Louis committed
remote_events = { git = "https://lab.lcr.gr/microhacks/micro-bevy-remote-events", branch = "trunk" }
Louis's avatar
Louis committed
```
Louis's avatar
Louis committed

Louis's avatar
Louis committed
## Usage
Louis's avatar
Louis committed

Louis's avatar
Louis committed
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.

Louis's avatar
Louis committed
`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://`).
Louis's avatar
Louis committed

```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()))
	}
}

Louis's avatar
Louis committed
pub fn connect_to_server(mut events: EventWriter<SocketControlEvent>) {
    events.send(SocketControlEvent::Connect(String::from("ws://localhost:3000")));
}

Louis's avatar
Louis committed
#[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 ..
Louis's avatar
Louis committed
        .add_startup_system(connect_to_server)
Louis's avatar
Louis committed
        .add_plugin(
            RemoteEventPlugin::<SentEvents, ReceivedEvents>::new()
        );
}
Louis's avatar
Louis committed

Louis's avatar
Louis committed
```