Closed GOVYANSONG closed 1 year ago
more info: futures::executor::block_on vs. wasm_bindgen_futures::spawn_local. mainly used by sceneloader and various request methods in resourcemanager.
block_on allows return value. how to achieve the same with spawn_local/task?
I'm running into the same thing, I'm guessing it's something that might be fixed by this bit in the wasm example? https://github.com/invokermain/Fyrox/blob/master/examples/wasm/src/lib.rs#L302
I have been experimenting with various approaches. following is a working code snippet with tokio. I will run the real game and report further progress:
Updated to show nested async/await call chain: tokio runtime -> handle spawn blocking -> to_say() -> say_hello()
tokio = {version = "1.21.2", features=["rt"]}
pub fn main_js() { set_once();
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
rt.block_on(
async {
let handle = tokio::runtime::Handle::current();
let res = handle.spawn(
say_hello()
).await.unwrap();
Log::warn(format!("say_hello : {:?}", res));
let handle = tokio::runtime::Handle::current();
let res = handle.spawn(
to_say()
).await.unwrap();
Log::warn(format!("to_say : {:?}", res));
/*
let mut executor = Executor::new();
executor.add_plugin_constructor(GameConstructor);
executor.run();
*/
}
);
}
async fn say_hello() -> u8 { println!("Hello, world!"); 100 }
async fn to_say() -> u8 { println!("To say!"); say_hello().await + 100 }
Update: SceneLoader::from_file() caused panic with the original error.
So, the issue is that executor
is using block_on
method on every platform. It should use fyrox::core::wasm_bindgen_futures::spawn_local()
instead and wait until the scene is loaded in the main loop. It should be relatively easy to fix. Shame on me: I didn't test executor to run on WASM.
I'll try to fix that today.
So first steps to fix the issue were made. New AsyncSceneLoader
works fine with WebAssembly, now it is time to improve fyrox-template
- it needs a separate executor-wasm
project for WebAssembly. executor
itself cannot be modified (at least I don't see how to do it), because WebAssembly requires very specific project structure:
I hope I can add this today, this is interesting task and I'm eager to see some of my games (this one https://github.com/mrDIMAS/FishFolly specifically) working on WebAssembly targets.
@mrDIMAS , thanks for the quick turnaround and awesome effort. what is the general approach to replace block_on with spawn_local?
The idea is to remove any platform-specific code from user code. WebAssembly does not support std::thread
(at least on wasm32-unknown-unknown
target) and it is only possible to spawn a background task with some custom actions. So AsyncSceneLoader
is that cross-platform solution - internally it "off-threads" scene loading as a background task and provides fetch_result
method that can be used to obtain actual loading result (when it is ready).
fyrox-template
is now updated and generates executor-wasm
crate alongside the executor
. executor-wasm
contains readme with build instructions. All you need to do is to re-generate project with the fyrox-template
and follow build instructions in the readme. Also make sure to follow this guide https://fyrox-book.github.io/fyrox/beginning/scripting.html#using-latest-engine-version when trying to use the latest changes.
This is what I have after building executor-wasm
and running it in Firefox:
I've updated my learning project to use the wasm changes above. It now tries to load!
But it doesn't run 100%, I just get a black screen and the following error messages in the console:
My code doesn't do anything fancy, so I wonder if there is another wasm incompatibility within the library? My guess is something withing my scene that is failing to load?
Also in case it is of note, using the new generated wasm executor file I get quite a few errors/warnings from vscode (although it compiles just fine):
Try to copy the rgs file from data folder (at root of project) to under executor-wasm e.g. executor-wasm/data/scene.rgs. this is in cargo.toml: fyrox = { git = "https://github.com/FyroxEngine/Fyrox", rev="23d81ed" }
Try to copy the rgs file from data folder (at root of project) to under executor-wasm e.g. executor-wasm/data/scene.rgs. this is in cargo.toml: fyrox = { git = "https://github.com/FyroxEngine/Fyrox", rev="23d81ed" }
It's not that unfortunately, data is in there (the unable to load scene error is: [ERROR]: Unable to load data/scene.rgs override scene! Reason: NotSupportedFormat
), I have just .gitignored it to not duplicate the assets in the repo, and Fyrox is up to date with latest as well.
Update:
I have modified code to use the new async scene loader. it worked fine inside both editor and executor. but in browser, fetch_result never returned the scene from model file. At least, i can see a black screen in browser window now.
Update
for running with editor and executor, in the log output, there was warning about player.default and player.clone. for browser wasm, there was a panic: panicked at 'Attempt to borrow object using dangling handle [Idx: 0; Gen: 0]. Record has 1 generation!', /home/mk8s/.cargo/git/checkouts/fyrox-3b28ccbadb9683b5/23d81ed/fyrox-core/src/pool.rs:690:17 . For both browser and native linux, there are complaints about unable to load options file (not found) among others.
Update
I think that i narrowed down the issue with black screen. I modified the sample code with seemingly equivalent logic of my own:
fyrox sample code:
if let Some(loader) = self.loader.as_ref() { if let Some(result) = loader.fetch_result() {
my own code:
let loader = self.loader.as_ref(); if loader.is_none() {return;}
let result = loader.unwrap().fetch_result();
if result.is_none() {return;}
fyrox sample code correctly loaded and rendered the scene. my own logic failed with error and a black screen;
[INFO]: Shader RectangleShader linked successfully!
web.js:1412 Uncaught (in promise) Error: Using exceptions for control flow, don't mind me. This isn't actually an error! at imports.wbg.wbindgen_throw (web.js:1412:15) at web_bg.wasm:0x46700e at web_bg.wasm:0x45f2db at web_bg.wasm:0x3314bd at web_bg.wasm:0x45c167 at main_js (web.js:236:10) at HTMLButtonElement.run (main.js:17:28) imports.wbg.wbindgen_throw @ web.js:1412 $func9053 @ web_bg.wasm:0x46700e $func7686 @ web_bg.wasm:0x45f2db $func2311 @ web_bg.wasm:0x3314bd $main_js @ web_bg.wasm:0x45c167 main_js @ web.js:236 run @ main.js:17 web.js:354 [INFO]: Starting resolve...
It turns out that there's a handful of block_on
s left in the engine code. I'll try to fix that today.
The issue should be fixed, I got @invokermain 's project running in both Firefox and Chrome:
@GOVYANSONG looks like you're trying to get a reference to a non-loaded scene by a null-handle.
WebAssembly is kinda annoying, the fact that you cannot block to execute a future is sad. However, there's one good thing about this - having non-blocking code will make your app much better from user perspective. You can draw a progress bar, or some other stuff while game's assets are loading.
@invokermain If you have any improvements to executor-wasm
template, please make a PR 🙏
Finally, i was able to get scene and model all loaded and rendered in browser. cheers to all. but now, I cannot exit the game by setting *control_flow = ControlFlow::Exit in update method of plugin trait of game. Any thought? what is the expected behavior for browser?
original issue is resolved
I was able to run my game in editor and wasm_pack generated the wasm file without any issue. but when i run it in browser e.g. Chrome, it threw following errors:
panicked at 'condvar wait not supported', library/std/src/sys/wasm/../unsupported/locks/condvar.rs:21:9
panicked at 'assertion failed:
(left == right)
left:true
, right:false
: cannot recursively acquire mutex', library/std/src/sys/wasm/../unsupported/locks/mutex.rs:24:9