Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add WebPlugin to keep running in background #371

Merged
merged 1 commit into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/auth/assets/settings.ron
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ MySettings(
// transport: WebTransport(
// this is only needed for wasm, the self-signed certificates are only valid for 2 weeks
// the server will print the certificate digest on startup
// certificate_digest: "24:48:ea:6f:13:a4:4f:2f:42:b9:f3:71:3f:79:c5:7a:d1:1d:29:ab:de:b0:03:4d:94:92:7b:84:69:01:85:1d",
// certificate_digest: "1a:83:aa:a3:ec:d4:5f:8f:1c:41:e7:70:8f:78:e3:a8:27:f4:db:4e:73:35:e6:a3:ea:f4:95:82:f1:6f:06:4b",
// ),
server_port: 5001,
transport: Udp,
Expand Down
2 changes: 1 addition & 1 deletion examples/bullet_prespawn/assets/settings.ron
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ MySettings(
transport: WebTransport(
// this is only needed for wasm, the self-signed certificates are only valid for 2 weeks
// the server will print the certificate digest on startup
certificate_digest: "24:48:ea:6f:13:a4:4f:2f:42:b9:f3:71:3f:79:c5:7a:d1:1d:29:ab:de:b0:03:4d:94:92:7b:84:69:01:85:1d",
certificate_digest: "1a:83:aa:a3:ec:d4:5f:8f:1c:41:e7:70:8f:78:e3:a8:27:f4:db:4e:73:35:e6:a3:ea:f4:95:82:f1:6f:06:4b",
),
// server_port: 5001,
// transport: Udp,
Expand Down
18 changes: 9 additions & 9 deletions examples/certificates/cert.pem
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
-----BEGIN CERTIFICATE-----
MIIBfTCCASOgAwIBAgIUdbC/g5dOvo7rlblM9+BRicaVJAMwCgYIKoZIzj0EAwIw
FDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI0MDUwNzE0MTEzNVoXDTI0MDUyMTE0
MTEzNVowFDESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAE3BeCmoE1gzCuMBDnqMdTeWz8nvD9T2otuWlnZOtc6zL/tqv2qL38yRvg
20X7/t7RE8tsMGlc41tEej/Lr11XcaNTMFEwHQYDVR0OBBYEFK7q4bBLqu3219yE
W50GnETHqNY2MB8GA1UdIwQYMBaAFK7q4bBLqu3219yEW50GnETHqNY2MA8GA1Ud
EwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIhAJ6w/WKnpfObuk3XVmn3yaIL
SVCRgsAJVdv1cnAbmlUUAiAng/XpUyJRcdQkVvnXsw6gEUmdAUHZaZd6UhLUGiqu
3A==
MIIBfTCCASOgAwIBAgIUKI27VMWcE8NjR3naSwPmvjYn9lQwCgYIKoZIzj0EAwIw
FDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI0MDUyMjIyMzE0MFoXDTI0MDYwNTIy
MzE0MFowFDESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEqL2JMPpxNZnNu/GGwFCnISMBcBnHQ/aBavlt7cyVnNaa2OwhkIRYTSHw
vlD6CE6thpL/EVXWcbOVw9VXWN0Y8KNTMFEwHQYDVR0OBBYEFMmrC4dORxoH7ivv
qSQcVMeWOKSYMB8GA1UdIwQYMBaAFMmrC4dORxoH7ivvqSQcVMeWOKSYMA8GA1Ud
EwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIhAJptNIhxm05Nz5bUexxT1g0r
XTwdtq+vkYODcX9KBokPAiBFcLJmsRZ8sKTHDeRNDFw3kLGDrbNqLSkBLjaTmD0G
4w==
-----END CERTIFICATE-----
6 changes: 3 additions & 3 deletions examples/certificates/key.pem
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgVp1Kz4Vto1yWQwbt
7XhmfX4UbMDcNbrybKffjEc1mCmhRANCAATcF4KagTWDMK4wEOeox1N5bPye8P1P
ai25aWdk61zrMv+2q/aovfzJG+DbRfv+3tETy2wwaVzjW0R6P8uvXVdx
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg0s/XIM5aTi33W9po
uOAz0JBqR9+dd0JikOb8ZHYOn8uhRANCAASovYkw+nE1mc278YbAUKchIwFwGcdD
9oFq+W3tzJWc1prY7CGQhFhNIfC+UPoITq2Gkv8RVdZxs5XD1VdY3Rjw
-----END PRIVATE KEY-----
2 changes: 1 addition & 1 deletion examples/client_replication/assets/settings.ron
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Settings(
transport: WebTransport(
// this is only needed for wasm, the self-signed certificates are only valid for 2 weeks
// the server will print the certificate digest on startup
certificate_digest: "24:48:ea:6f:13:a4:4f:2f:42:b9:f3:71:3f:79:c5:7a:d1:1d:29:ab:de:b0:03:4d:94:92:7b:84:69:01:85:1d",
certificate_digest: "1a:83:aa:a3:ec:d4:5f:8f:1c:41:e7:70:8f:78:e3:a8:27:f4:db:4e:73:35:e6:a3:ea:f4:95:82:f1:6f:06:4b",
),
// server_port: 5001,
// transport: Udp,
Expand Down
2 changes: 1 addition & 1 deletion examples/interest_management/assets/settings.ron
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Settings(
transport: WebTransport(
// this is only needed for wasm, the self-signed certificates are only valid for 2 weeks
// the server will print the certificate digest on startup
certificate_digest: "24:48:ea:6f:13:a4:4f:2f:42:b9:f3:71:3f:79:c5:7a:d1:1d:29:ab:de:b0:03:4d:94:92:7b:84:69:01:85:1d",
certificate_digest: "1a:83:aa:a3:ec:d4:5f:8f:1c:41:e7:70:8f:78:e3:a8:27:f4:db:4e:73:35:e6:a3:ea:f4:95:82:f1:6f:06:4b",
),
// server_port: 5001,
// transport: Udp,
Expand Down
2 changes: 1 addition & 1 deletion examples/leafwing_inputs/assets/settings.ron
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ MySettings(
transport: WebTransport(
// this is only needed for wasm, the self-signed certificates are only valid for 2 weeks
// the server will print the certificate digest on startup
certificate_digest: "24:48:ea:6f:13:a4:4f:2f:42:b9:f3:71:3f:79:c5:7a:d1:1d:29:ab:de:b0:03:4d:94:92:7b:84:69:01:85:1d",
certificate_digest: "1a:83:aa:a3:ec:d4:5f:8f:1c:41:e7:70:8f:78:e3:a8:27:f4:db:4e:73:35:e6:a3:ea:f4:95:82:f1:6f:06:4b",
),
// server_port: 5001,
// transport: Udp,
Expand Down
2 changes: 1 addition & 1 deletion examples/lobby/assets/settings.ron
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Settings(
// transport: WebTransport(
// // this is only needed for wasm, the self-signed certificates are only valid for 2 weeks
// // the server will print the certificate digest on startup
// certificate_digest: "24:48:ea:6f:13:a4:4f:2f:42:b9:f3:71:3f:79:c5:7a:d1:1d:29:ab:de:b0:03:4d:94:92:7b:84:69:01:85:1d",
// certificate_digest: "1a:83:aa:a3:ec:d4:5f:8f:1c:41:e7:70:8f:78:e3:a8:27:f4:db:4e:73:35:e6:a3:ea:f4:95:82:f1:6f:06:4b",
// ),
server_port: 5001,
transport: Udp,
Expand Down
2 changes: 1 addition & 1 deletion examples/priority/assets/settings.ron
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Settings(
transport: WebTransport(
// this is only needed for wasm, the self-signed certificates are only valid for 2 weeks
// the server will print the certificate digest on startup
certificate_digest: "24:48:ea:6f:13:a4:4f:2f:42:b9:f3:71:3f:79:c5:7a:d1:1d:29:ab:de:b0:03:4d:94:92:7b:84:69:01:85:1d",
certificate_digest: "1a:83:aa:a3:ec:d4:5f:8f:1c:41:e7:70:8f:78:e3:a8:27:f4:db:4e:73:35:e6:a3:ea:f4:95:82:f1:6f:06:4b",
),
// server_port: 5001,
// transport: Udp,
Expand Down
2 changes: 1 addition & 1 deletion examples/replication_groups/assets/settings.ron
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Settings(
transport: WebTransport(
// this is only needed for wasm, the self-signed certificates are only valid for 2 weeks
// the server will print the certificate digest on startup
certificate_digest: "24:48:ea:6f:13:a4:4f:2f:42:b9:f3:71:3f:79:c5:7a:d1:1d:29:ab:de:b0:03:4d:94:92:7b:84:69:01:85:1d",
certificate_digest: "1a:83:aa:a3:ec:d4:5f:8f:1c:41:e7:70:8f:78:e3:a8:27:f4:db:4e:73:35:e6:a3:ea:f4:95:82:f1:6f:06:4b",
),
// server_port: 5001,
// transport: Udp,
Expand Down
2 changes: 1 addition & 1 deletion examples/simple_box/assets/settings.ron
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Settings(
transport: WebTransport(
// this is only needed for wasm, the self-signed certificates are only valid for 2 weeks
// the server will print the certificate digest on startup
certificate_digest: "24:48:ea:6f:13:a4:4f:2f:42:b9:f3:71:3f:79:c5:7a:d1:1d:29:ab:de:b0:03:4d:94:92:7b:84:69:01:85:1d",
certificate_digest: "1a:83:aa:a3:ec:d4:5f:8f:1c:41:e7:70:8f:78:e3:a8:27:f4:db:4e:73:35:e6:a3:ea:f4:95:82:f1:6f:06:4b",
),
// server_port: 5001,
// transport: Udp,
Expand Down
102 changes: 53 additions & 49 deletions lightyear/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,27 @@ exclude = ["/tests"]

[features]
metrics = [
"dep:metrics",
"metrics-util",
"metrics-tracing-context",
"metrics-exporter-prometheus",
"dep:metrics",
"metrics-util",
"metrics-tracing-context",
"metrics-exporter-prometheus",
]
mock_time = ["dep:mock_instant"]
webtransport = [
"dep:wtransport",
"dep:xwt-core",
"dep:xwt-web-sys",
"dep:web-sys",
"dep:ring",
"dep:wasm-bindgen-futures",
"dep:wtransport",
"dep:xwt-core",
"dep:xwt-web-sys",
"dep:web-sys",
"dep:ring",
"dep:wasm-bindgen-futures",
]
leafwing = ["dep:leafwing-input-manager"]
xpbd_2d = ["dep:bevy_xpbd_2d"]
websocket = [
"dep:tokio-tungstenite",
"dep:futures-util",
"dep:web-sys",
"dep:wasm-bindgen",
"dep:tokio-tungstenite",
"dep:futures-util",
"dep:web-sys",
"dep:wasm-bindgen",
]
steam = ["dep:steamworks"]
zstd = ["dep:zstd"]
Expand Down Expand Up @@ -70,7 +70,7 @@ bevy_xpbd_2d = { version = "0.4", optional = true, default-features = false }

# serialization
bitcode = { version = "0.5.1", package = "bitcode_lightyear_patch", path = "../vendor/bitcode", features = [
"serde",
"serde",
] }
bytes = { version = "1.5", features = ["serde"] }
self_cell = "1.0"
Expand All @@ -87,8 +87,8 @@ lightyear_macros = { version = "0.15.1", path = "../macros" }
tracing = "0.1.40"
tracing-log = "0.2.0"
tracing-subscriber = { version = "0.3.17", features = [
"registry",
"env-filter",
"registry",
"env-filter",
] }

# server
Expand All @@ -99,12 +99,12 @@ metrics = { version = "0.22", optional = true }
metrics-util = { version = "0.15", optional = true }
metrics-tracing-context = { version = "0.15", optional = true }
metrics-exporter-prometheus = { version = "0.13.0", optional = true, default-features = false, features = [
"http-listener",
"http-listener",
] }

# bevy
bevy = { version = "0.13", default-features = false, features = [
"multi-threaded",
"multi-threaded",
] }


Expand All @@ -114,8 +114,8 @@ futures-util = { version = "0.3.30", optional = true }
# transport
# we don't need any tokio features, we use only use the tokio channels
tokio = { version = "1.36", features = [
"sync",
"macros",
"sync",
"macros",
], default-features = false }
futures = "0.3.30"
async-compat = "0.2.3"
Expand All @@ -127,13 +127,13 @@ async-channel = "2.2.0"
steamworks = { version = "0.11", optional = true }
# webtransport
wtransport = { version = "=0.1.13", optional = true, features = [
"self-signed",
"dangerous-configuration",
"self-signed",
"dangerous-configuration",
] }
# websocket
tokio-tungstenite = { version = "0.21.0", optional = true, features = [
"connect",
"handshake",
"connect",
"handshake",
] }
# compression
zstd = { version = "0.13.1", optional = true }
Expand All @@ -142,24 +142,28 @@ zstd = { version = "0.13.1", optional = true }
console_error_panic_hook = { version = "0.1.7" }
ring = { version = "0.17.8", optional = true, default-features = false }
web-sys = { version = "0.3", optional = true, features = [
"WebTransport",
"WebTransportHash",
"WebTransportOptions",
"WebTransportBidirectionalStream",
"WebTransportSendStream",
"WebTransportReceiveStream",
"ReadableStreamDefaultReader",
"WritableStreamDefaultWriter",
"WebTransportDatagramDuplexStream",
"WebSocket",
"CloseEvent",
"ErrorEvent",
"MessageEvent",
"BinaryType",
"Document",
"WebTransport",
"WebTransportHash",
"WebTransportOptions",
"WebTransportBidirectionalStream",
"WebTransportSendStream",
"WebTransportReceiveStream",
"ReadableStreamDefaultReader",
"WritableStreamDefaultWriter",
"WebTransportDatagramDuplexStream",
"WebSocket",
"CloseEvent",
"ErrorEvent",
"MessageEvent",
"BinaryType",
"Blob",
"Url",
"Worker",
] }
futures-lite = { version = "2.1.0", optional = true }
getrandom = { version = "0.2.11", features = [
"js", # feature 'js' is required for wasm
"js", # feature 'js' is required for wasm
] }
xwt-core = { version = "0.4", optional = true }
xwt-web-sys = { version = "0.11", optional = true }
Expand All @@ -182,14 +186,14 @@ approx = "0.5.1"
# we cannot use all-features = true, because we need to provide additional features for bevy_xpbd_2d
# when building the docs
features = [
"metrics",
"webtransport",
"leafwing",
"xpbd_2d",
"websocket",
"steam",
"zstd",
"bevy_xpbd_2d/2d",
"bevy_xpbd_2d/f32",
"metrics",
"webtransport",
"leafwing",
"xpbd_2d",
"websocket",
"steam",
"zstd",
"bevy_xpbd_2d/2d",
"bevy_xpbd_2d/f32",
]
rustdoc-args = ["--cfg", "docsrs"]
3 changes: 3 additions & 0 deletions lightyear/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ pub(crate) mod io;
pub(crate) mod message;
pub(crate) mod networking;
pub mod replication;

#[cfg(target_family = "wasm")]
mod web;
9 changes: 7 additions & 2 deletions lightyear/src/client/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl PluginGroup for ClientPlugins {
let builder = PluginGroupBuilder::start::<Self>();
let tick_interval = self.config.shared.tick.tick_duration;
let interpolation_config = self.config.interpolation.clone();
builder
let builder = builder
.add(SetupPlugin {
config: self.config,
})
Expand All @@ -63,7 +63,12 @@ impl PluginGroup for ClientPlugins {
.add(ClientReplicationReceivePlugin { tick_interval })
.add(ClientReplicationSendPlugin { tick_interval })
.add(PredictionPlugin)
.add(InterpolationPlugin::new(interpolation_config))
.add(InterpolationPlugin::new(interpolation_config));

#[cfg(target_family = "wasm")]
let builder = builder.add(crate::client::web::WebPlugin);

builder
}
}

Expand Down
54 changes: 54 additions & 0 deletions lightyear/src/client/web.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//! Module containing extra behaviour that we need when running in wasm

use bevy::prelude::*;
use std::sync::{Arc, RwLock};
use wasm_bindgen::{closure::Closure, JsCast, JsValue};
use web_sys::{js_sys::Array, window, Blob, Url, Worker};

pub struct WebPlugin;

impl Plugin for WebPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, spawn_background_worker);
}
}

/// In wasm, the main thread gets quickly throttled by the browser when it is hidden (e.g. when the user switches tabs).
/// This means that the app.update() function will not be called, because bevy's scheduler only runs `app.update()` when
/// the browser's requestAnimationFrame is called. (and that happens only when the tab is visible)
///
/// This is problematic because:
/// - we stop sending packets so the server disconnects the client because it doesn't receive keep-alives
/// - when the client reconnects, it also disconnects because it hasn't been receiving server packets
/// - the internal transport buffers can overflow because they are not being emptied
///
/// This solution spawns a WebWorker (a background thread) which is not throttled, and which runs
/// `app.update()` at a fixed interval. This way, the client can keep sending and receiving packets,
/// and updating the local World.
fn spawn_background_worker(world: &mut World) {
let world_ptr = Arc::new(RwLock::new(world as *mut World));

// The interval is in milliseconds. We can run app.update() infrequently when in the background
let blob = Blob::new_with_str_sequence(
&Array::of1(&JsValue::from_str(
"setInterval(() => self.postMessage(0), 1000);",
))
.unchecked_into(),
)
.unwrap();

let worker = Worker::new(&Url::create_object_url_with_blob(&blob).unwrap()).unwrap();

let closure = Closure::<dyn FnMut()>::new(move || {
if window().unwrap().document().unwrap().hidden() {
// Imitate app.update()
let world = unsafe { world_ptr.write().unwrap().as_mut().unwrap() };
world.run_schedule(Main);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Magnifique

world.clear_trackers();
}
});

worker.set_onmessage(Some(closure.as_ref().unchecked_ref()));

closure.forget();
}
Loading