Skip to content
Snippets Groups Projects
Louis Capitanchik's avatar
Louis authored
be0c6b43
Name Last commit Last update
src
.gitignore
Cargo.toml
LICENSE
README.md

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