use std::{collections::HashMap, fmt::Display, sync::{Arc, Mutex}}; use bevy_ecs::system::Resource; use futures::channel::oneshot::{Receiver, Sender}; use image::EncodableLayout; use tracing::info; use wasm_bindgen_futures::spawn_local; use super::texture::{self, Texture}; #[derive(Debug, Clone)] pub enum AssetError { AssetNotFound, ResponseNotOk(u16), } impl Display for AssetError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { AssetError::AssetNotFound => write!(f, "Asset not found"), AssetError::ResponseNotOk(code) => write!(f, "Server response was not ok {}", code), } } } impl std::error::Error for AssetError {} #[derive(Resource)] pub struct Assets { texture_receivers: Arc>>>>, textures: Arc>>>, } impl Assets { pub fn new() -> Self { Assets { textures: Arc::new(Mutex::new(HashMap::new())), texture_receivers: Arc::new(Mutex::new(HashMap::new())), } } pub fn get(&self, local_path: impl Into) -> Option> { let (tx, rx) = futures::channel::oneshot::channel(); let local_path = local_path.into(); let contains_texture = { self.textures.lock().unwrap().contains_key(&local_path) }; let contains_texture_receiver = { self.texture_receivers.lock().unwrap().contains_key(&local_path) }; if !contains_texture && !contains_texture_receiver { let textures = self.textures.clone(); self.texture_receivers.lock().unwrap().insert(local_path.clone(), rx); spawn_local(async move { let window = web_sys::window().unwrap(); let resp = match reqwest::get(format!("{}/src/textures/{}", window.location().origin().unwrap(), local_path)).await { Ok(resp) => resp, Err(e) => { if e.is_request() { panic!("Error in request {}", e); } else if e.is_body() { panic!("Error in body {}", e); } else if e.is_status() { panic!("Bad status: {}", e.status().unwrap()); } else if e.is_decode() { panic!("Couldn't decode response's body {}", e); } else if e.is_redirect() { panic!("Response caused redirect loop {}", e); } else if e.is_builder() { panic!("Error in builder {}", e); } panic!(); }, }; let bytes = match resp.bytes().await { Ok(bytes) => bytes, Err(e) => todo!(), }.to_vec(); textures.lock().unwrap().insert(local_path, bytes.clone()); tx.send(bytes).unwrap(); }); None } else if !contains_texture { let mut texture_receivers = self.texture_receivers.lock().unwrap(); let rx = texture_receivers.get_mut(&local_path).unwrap(); if let Ok(Some(texture)) = rx.try_recv() { self.texture_receivers.lock().unwrap().remove(&local_path); return Some(texture); } None } else { self.textures.lock().unwrap().get(&local_path).cloned() } } }