Skip to content

Commit

Permalink
First working state
Browse files Browse the repository at this point in the history
  • Loading branch information
voidentente committed Nov 17, 2023
1 parent 5634d82 commit 729962e
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 48 deletions.
18 changes: 3 additions & 15 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,29 +1,17 @@
[package]
authors = ["Johan Helsing <[email protected]>"]
categories = ["network-programming", "game-development", "wasm", "web-programming"]
description = "Bevy asset loader that transparently supports loading over http(s)"
description = "Implementations for http(s) asset sources for Bevy"
edition = "2021"
keywords = ["gamedev", "networking", "wasm", "bevy"]
license = "MIT OR Apache-2.0"
name = "bevy_web_asset"
repository = "https://github.com/johanhelsing/bevy_web_asset"
version = "0.6.0"
version = "0.7.0"

[dependencies]
bevy = {version = "0.12", default-features = false, features = ["bevy_asset"]}

# Copied from https://github.com/bevyengine/bevy/blob/main/crates/bevy_asset/Cargo.toml
crossbeam-channel = "0.5.0"
notify = "5.0.0"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
surf = {version = "2.3", default-features = false, features = ["h1-client-rustls"]}

[target.'cfg(target_arch = "wasm32")'.dependencies]
js-sys = {version = "0.3", default-features = false}
wasm-bindgen = {version = "0.2", default-features = false}
wasm-bindgen-futures = "0.4"
web-sys = {version = "0.3.22", default-features = false}
ehttp = "0.3"

[dev-dependencies]
bevy = {version = "0.12", default-features = false, features = [
Expand Down
5 changes: 4 additions & 1 deletion examples/web_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {

commands.spawn(SpriteBundle {
// Simply use a url where you would normally use an asset folder relative path
texture: asset_server.load("https://s3.johanhelsing.studio/dump/favicon.png"),
texture: asset_server.load(
// TODO: `https://s3.johanhelsing.studio/dump/favicon.png` doesn't seem to work
"https://raw.githubusercontent.com/johanhelsing/bevy_web_asset/main/assets/favicon.png",
),
..default()
});
}
75 changes: 43 additions & 32 deletions src/web_asset_source.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use bevy::asset::io::{PathStream, VecReader};
use bevy::asset::io::PathStream;
use bevy::utils::BoxedFuture;
use std::path::{Path, PathBuf};

use bevy::asset::io::{AssetReader, AssetReaderError, Reader};
use bevy::asset::io::{AssetReader, AssetReaderError, Reader, VecReader};

// Note: Bevy does not retain the asset source identifier (http/https)
// so we need to pass the protocol manually.
Expand Down Expand Up @@ -34,39 +34,50 @@ impl WebAssetReader {
}

async fn get<'a>(uri: PathBuf) -> Result<Box<Reader<'a>>, AssetReaderError> {
let uri_str = uri.to_str().unwrap();

#[cfg(target_arch = "wasm")]
let bytes = {
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
let window = web_sys::window().unwrap();
let response = JsFuture::from(window.fetch_with_str(uri_str))
.await
.map(|r| r.dyn_into::<web_sys::Response>().unwrap())
.map_err(|e| e.dyn_into::<js_sys::TypeError>().unwrap());

if let Err(err) = &response {
// warn!("Failed to fetch asset {uri_str}: {err:?}");
}

let response = response.map_err(|_| AssetReaderError::NotFound(uri))?;

let data = JsFuture::from(response.array_buffer().unwrap())
.await
use ehttp::{fetch, Request};
use std::future::Future;
use std::pin::Pin;
use std::sync::mpsc::{channel, Receiver};
use std::task::{Context, Poll};

let uri_str = uri.to_string_lossy();
bevy::prelude::info!("fetching {uri_str}");
let (sender, receiver) = channel();
fetch(Request::get(uri_str), move |result| {
bevy::prelude::info!("callback");
use std::io::{Error, ErrorKind};
sender
.send(
result
.map_err(|e| AssetReaderError::Io(Error::new(ErrorKind::Other, e)))
.and_then(|response| match response.status {
200 => Ok(response.bytes),
404 => Err(AssetReaderError::NotFound(uri)),
_ => Err(AssetReaderError::Io(Error::from(ErrorKind::Other))),
}),
)
.unwrap();
});

struct AsyncReceiver<T>(Receiver<T>);
impl<T> Future for AsyncReceiver<T> {
type Output = T;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.0.try_recv() {
Err(_) => {
cx.waker().wake_by_ref();
Poll::Pending
}
Ok(t) => {
bevy::prelude::info!("something");
Poll::Ready(t)
}
}
}
}

js_sys::Uint8Array::new(&data).to_vec()
};

#[cfg(not(target_arch = "wasm"))]
let bytes = surf::get(uri_str)
.recv_bytes()
.await
.map_err(|_| AssetReaderError::NotFound(uri))?;

let bytes = AsyncReceiver(receiver).await?;
let reader: Box<Reader> = Box::new(VecReader::new(bytes));

Ok(reader)
}

Expand Down

0 comments on commit 729962e

Please sign in to comment.