NiklasEi / bevy_asset_loader

Bevy plugin helping with asset loading and organization
Apache License 2.0
449 stars 53 forks source link

Manual dynamic asset do not work in wasm. #172

Closed darkautism closed 6 months ago

darkautism commented 6 months ago

In some case we cannot know which assets we should load in compile time. I have an ldtk project and it containe a lot of image so i need this crate to help me to manage this. I write a ldtk event to track all file should load in current level and it work perfect in PC envirement.

First i write a assets with ldtk key. I set vec type as UntypedHandle because i do not really want to use theme i just want to be sure all of assets should loaded befor game start.

#[derive(AssetCollection, Resource, Debug)]
pub struct PreloadAssets {
    #[asset(key = "ldtk", collection)]
    pub ldtk: Vec<UntypedHandle>,
}

Second i iterate all of entity in current level and add all Filepath type into a vec and register as dynamic assets.

fn ldtk_assets_check_system(
    mut level_events: EventReader<LevelEvent>,
    mut dynamic_assets: ResMut<DynamicAssets>,
    projects: Query<&Handle<LdtkProject>>,
    project_assets: Res<Assets<LdtkProject>>,
) {
    let fi2vec = |vec: &mut Vec<Option<String>>, fi: &[ldtk::FieldInstance]| {
        for field in fi.iter() {
            if field.field_instance_type == "Array<FilePath>" {
                match &field.value {
                    FieldValue::Strings(str_opt_vec) => vec.extend(str_opt_vec.clone()),
                    _ => {}
                }
            }
            match &field.value {
                FieldValue::FilePath(str_opt) => vec.push(str_opt.clone()),
                FieldValue::FilePaths(str_opt_vec) => vec.extend(str_opt_vec.clone()),
                _ => {}
            }
        }
    };
    for level_event in level_events.read() {
        match level_event {
            LevelEvent::SpawnTriggered(level_iid) => {
                let mut strs: Vec<Option<String>> = Vec::new();
                let level_data = project_assets
                    .get(projects.single())
                    .expect("project asset should be loaded if levels are spawned")
                    .get_raw_level_by_iid(&level_iid.to_string())
                    .expect("spawned level should exist in the loaded project");

                fi2vec(&mut strs, level_data.field_instances());
                if let Some(layers) = &level_data.layer_instances {
                    for layer in layers {
                        for entity in &layer.entity_instances {
                            fi2vec(&mut strs, entity.field_instances());
                        }
                    }
                }
                let mut set = std::collections::HashSet::new();
                let vec: Vec<_> = strs
                    .into_iter()
                    .filter_map(|x| x)
                    .filter(|x| set.insert(x.clone()))
                    .collect();
                dynamic_assets
                    .register_asset("ldtk", Box::new(StandardDynamicAsset::Files { paths: vec }));
            }
            _ => {}
        }
    }
}

That progress work very good in PC but it seems not work in wasm:

saraqael.js:424 panicked at src/utils.rs:144:10:
Failed to get asset for key 'ldtk'

Stack:

Error
    at imports.wbg.__wbg_new_abda76e883ba8a5f (https://darkautism.github.io/saraqael/saraqael.js:408:21)
    at console_error_panic_hook::hook::hfa74eddbe3f41541 (https://darkautism.github.io/saraqael/saraqael_bg.wasm:wasm-function[18083]:0x179b106)
    at core::ops::function::Fn::call::h49003c83f2ff978d (https://darkautism.github.io/saraqael/saraqael_bg.wasm:wasm-function[82971]:0x1f1b6ae)
    at std::panicking::rust_panic_with_hook::hbf46ef0245cc9589 (https://darkautism.github.io/saraqael/saraqael_bg.wasm:wasm-function[30939]:0x1bea016)
    at std::panicking::begin_panic_handler::{{closure}}::hc07db454214d2c87 (https://darkautism.github.io/saraqael/saraqael_bg.wasm:wasm-function[34877]:0x1caa508)
    at std::sys_common::backtrace::__rust_end_short_backtrace::hf9e2f055fb5ef672 (https://darkautism.github.io/saraqael/saraqael_bg.wasm:wasm-function[82070]:0x1f1973f)
    at rust_begin_unwind (https://darkautism.github.io/saraqael/saraqael_bg.wasm:wasm-function[43857]:0x1dd9529)
    at core::panicking::panic_fmt::h14c85a61aa3d538e (https://darkautism.github.io/saraqael/saraqael_bg.wasm:wasm-function[49007]:0x1e43d99)
    at <saraqael::utils::PreloadAssets as bevy_asset_loader::asset_collection::AssetCollection>::load::{{closure}}::hf536c016a927566d (https://darkautism.github.io/saraqael/saraqael_bg.wasm:wasm-function[48319]:0x1e38b82)
    at <saraqael::utils::PreloadAssets as bevy_asset_loader::asset_collection::AssetCollection>::load::hd7e0ed3b3bd96c40 (https://darkautism.github.io/saraqael/saraqael_bg.wasm:wasm-function[693]:0x3927b3)

imports.wbg.__wbg_error_f851667af71bcfc6 @ saraqael.js:424
$console_error_panic_hook::hook::hfa74eddbe3f41541 @ saraqael_bg.wasm:0x179b1e4
$core::ops::function::Fn::call::h49003c83f2ff978d @ saraqael_bg.wasm:0x1f1b6ae
$std::panicking::rust_panic_with_hook::hbf46ef0245cc9589 @ saraqael_bg.wasm:0x1bea016
$std::panicking::begin_panic_handler::{{closure}}::hc07db454214d2c87 @ saraqael_bg.wasm:0x1caa508
$std::sys_common::backtrace::__rust_end_short_backtrace::hf9e2f055fb5ef672 @ saraqael_bg.wasm:0x1f1973f
$rust_begin_unwind @ saraqael_bg.wasm:0x1dd9529
$core::panicking::panic_fmt::h14c85a61aa3d538e @ saraqael_bg.wasm:0x1e43d99
$<saraqael::utils::PreloadAssets as bevy_asset_loader::asset_collection::AssetCollection>::load::{{closure}}::hf536c016a927566d @ saraqael_bg.wasm:0x1e38b82
$<saraqael::utils::PreloadAssets as bevy_asset_loader::asset_collection::AssetCollection>::load::hd7e0ed3b3bd96c40 @ saraqael_bg.wasm:0x3927b3
$core::ops::function::impls::<impl core::ops::function::FnMut<A> for &mut F>::call_mut::he877a40bedf4ba1b @ saraqael_bg.wasm:0x741838
$<bevy_ecs::system::exclusive_function_system::ExclusiveFunctionSystem<Marker,F> as bevy_ecs::system::system::System>::run::h73ea3aff034e5329 @ saraqael_bg.wasm:0x1d7c4ba
$<bevy_ecs::schedule::executor::single_threaded::SingleThreadedExecutor as bevy_ecs::schedule::executor::SystemExecutor>::run::h1907799b9edb159a @ saraqael_bg.wasm:0x8bfff7
$bevy_ecs::schedule::schedule::Schedule::run::hf7e057abef9cdc7b @ saraqael_bg.wasm:0x1b39f3b
$bevy_ecs::world::World::schedule_scope::h2aed66c2ce6d94d4 @ saraqael_bg.wasm:0xda5477
$core::ops::function::impls::<impl core::ops::function::FnMut<A> for &mut F>::call_mut::h280ae2dab73b7a0f @ saraqael_bg.wasm:0x98a5c7
$<bevy_ecs::system::exclusive_function_system::ExclusiveFunctionSystem<Marker,F> as bevy_ecs::system::system::System>::run::h727ba857acfd1ab6 @ saraqael_bg.wasm:0x1da3e8b
$<bevy_ecs::schedule::executor::single_threaded::SingleThreadedExecutor as bevy_ecs::schedule::executor::SystemExecutor>::run::h1907799b9edb159a @ saraqael_bg.wasm:0x8bfff7
$bevy_ecs::schedule::schedule::Schedule::run::hf7e057abef9cdc7b @ saraqael_bg.wasm:0x1b39f3b
$bevy_ecs::world::World::resource_scope::hb80598eb2ab040b0 @ saraqael_bg.wasm:0x74a5c4
$<bevy_ecs::system::exclusive_function_system::ExclusiveFunctionSystem<Marker,F> as bevy_ecs::system::system::System>::run::hd02d668612f7e229 @ saraqael_bg.wasm:0x1d1028d
$<bevy_ecs::schedule::executor::single_threaded::SingleThreadedExecutor as bevy_ecs::schedule::executor::SystemExecutor>::run::h1907799b9edb159a @ saraqael_bg.wasm:0x8bfff7
$bevy_ecs::schedule::schedule::Schedule::run::hf7e057abef9cdc7b @ saraqael_bg.wasm:0x1b39f3b
$bevy_ecs::world::World::schedule_scope::h44d4dce25aeca254 @ saraqael_bg.wasm:0xdaf6c1
$bevy_app::app::App::update::hd874ec8a683f4e28 @ saraqael_bg.wasm:0x1b62cdd
$winit::platform_impl::platform::event_loop::EventLoop<T>::spawn::{{closure}}::h7bd21b598e16d2c0 @ saraqael_bg.wasm:0x21f8c7
$winit::platform_impl::platform::event_loop::runner::Shared<T>::handle_event::h4175e5f3e33eaf4a @ saraqael_bg.wasm:0xe8ca03
$winit::platform_impl::platform::event_loop::runner::Shared<T>::run_until_cleared::h969817f2b8e89b56 @ saraqael_bg.wasm:0x11f017e
$winit::platform_impl::platform::backend::timeout::AnimationFrameRequest::new::{{closure}}::h0548ddb74dd3bae1 @ saraqael_bg.wasm:0x1e3bab9
$<dyn core::ops::function::FnMut<()>+Output = R as wasm_bindgen::closure::WasmClosure>::describe::invoke::hb5891319f26a8f67 @ saraqael_bg.wasm:0x1e8c91d
__wbg_adapter_51 @ saraqael.js:222
real @ saraqael.js:203
requestAnimationFrame (async)
(anonymous) @ saraqael.js:918
handleError @ saraqael.js:239
imports.wbg.__wbg_requestAnimationFrame_74309aadebde12fa @ saraqael.js:917
$web_sys::features::gen_Window::Window::request_animation_frame::h8a9bad7a22bf124f @ saraqael_bg.wasm:0x1e235a8
$winit::platform_impl::platform::backend::timeout::AnimationFrameRequest::new::h82bf17e6fbc67027 @ saraqael_bg.wasm:0x1a88aef
$winit::platform_impl::platform::event_loop::runner::Shared<T>::apply_control_flow::hb922737f15484ed6 @ saraqael_bg.wasm:0x1079fa5
$winit::platform_impl::platform::event_loop::runner::Shared<T>::run_until_cleared::h969817f2b8e89b56 @ saraqael_bg.wasm:0x11f030c
$winit::platform_impl::platform::backend::timeout::AnimationFrameRequest::new::{{closure}}::h0548ddb74dd3bae1 @ saraqael_bg.wasm:0x1e3bab9
$<dyn core::ops::function::FnMut<()>+Output = R as wasm_bindgen::closure::WasmClosure>::describe::invoke::hb5891319f26a8f67 @ saraqael_bg.wasm:0x1e8c91d
__wbg_adapter_51 @ saraqael.js:222
real @ saraqael.js:203
saraqael_bg.wasm:0x1f1da1c Uncaught RuntimeError: unreachable
    at __rust_start_panic (saraqael_bg.wasm:0x1f1da1c)
    at rust_panic (saraqael_bg.wasm:0x1f0b81a)
    at std::panicking::rust_panic_with_hook::hbf46ef0245cc9589 (saraqael_bg.wasm:0x1bea046)
    at std::panicking::begin_panic_handler::{{closure}}::hc07db454214d2c87 (saraqael_bg.wasm:0x1caa508)
    at std::sys_common::backtrace::__rust_end_short_backtrace::hf9e2f055fb5ef672 (saraqael_bg.wasm:0x1f1973f)
    at rust_begin_unwind (saraqael_bg.wasm:0x1dd9529)
    at core::panicking::panic_fmt::h14c85a61aa3d538e (saraqael_bg.wasm:0x1e43d99)
    at <saraqael::utils::PreloadAssets as bevy_asset_loader::asset_collection::AssetCollection>::load::{{closure}}::hf536c016a927566d (saraqael_bg.wasm:0x1e38b82)
    at <saraqael::utils::PreloadAssets as bevy_asset_loader::asset_collection::AssetCollection>::load::hd7e0ed3b3bd96c40 (saraqael_bg.wasm:0x3927b3)
    at core::ops::function::impls::<impl core::ops::function::FnMut<A> for &mut F>::call_mut::he877a40bedf4ba1b (saraqael_bg.wasm:0x741838)

What can i do?

NiklasEi commented 6 months ago

You are inserting the ldtk asset in a loop over all level events. Have you debugged that you get such an event and insert the dynamic asset before the loading state starts on WASM?

darkautism commented 6 months ago

I write a new state to prevent this bug. LoadLdtk -> AssetLoading - > Playing. This flow also work on wasm. :-)