NiklasEi / bevy_asset_loader

Bevy plugin helping with asset loading and organization
Apache License 2.0
507 stars 56 forks source link

Manual dynamic asset do not work in wasm. #172

Closed darkautism closed 11 months ago

darkautism commented 11 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 11 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 11 months ago

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