Naive and initial thoughts on WebAssembly modding #5908
Replies: 4 comments 2 replies
-
wasm-bindgen has never been supported outside of the browser or node. It's purpose is to bind to javascript api's. For other use cases there is wit-bindgen. It targets both the component model and MVP wasm using the canonical abi. It can generate both the host and guest side for rust and the host side for javascript. |
Beta Was this translation helpful? Give feedback.
-
A follow-up on those thoughts. It was meant to be just a quick summary, but I ended writing a lot 😅 TL;DR PrototypeI was able to find a way to communicate between host and guest across native and web. I'm working on a experimental project here: https://github.com/afonsolage/wabi It's very unstable and shouldn't be used, yet. Client-server likeEverything was easier to understand and to wrap my mind around when I finally understood that host and guest communication is just like a client/server approach (Thanks @erlend-sh for pointing me to Veloren modding ), where they know nothing about each other, except what is defined in a protocol. The difference is that on host/guest communication the latency is in microseconds¹, while on a networking, it is in milliseconds¹, so the challenge is to build an API which use few contexts switching as possible and allow a seamless integration with Bevy. The way they share data is writing/reading to/from a WebAssembly Memory, but unlike client/server, we can pass arguments and receive return values. Sync communicationWasm mods are intended to run in a single-thread, since there is no use case to run a multi-threaded wasm mod² (correct me if I'm wrong here), so we can use this to our advantage and make a simple sync communication workflow between host/guest:
The communication flow is much like a normal function call, except there is an extra step, which is sending arguments and returning result using the wasm memory. So the communication between guest/host is understood. Now it's the API time! Neutral APIThe hardest part has been developing an API which isn't Rust biased, since one of the main selling points of That's another point where previous experience with networking protocols is handy, since usually you can make a client in one language and server in another, it's just a matter of protocol neutrality. Many crates complexityAnother downside of developing a mod for modding in Bevy, using wasm, is because we need many crates, due to high flexibility of this scenario:
This is what I've come up with atm, crates may be merged on new one added and names may change before the first release on crates.io (even tho I loved the name already 😬 ) Next stepsNow it's time to try to refine the API and add Bevy features like ¹ This was a very rough estimation that I made when benchmarking the context switch latency between host/guest using |
Beta Was this translation helpful? Give feedback.
-
What languages have you been designing for besides Rust? I didn't know there were that many other language that could do an okay job targeting Wasm. |
Beta Was this translation helpful? Give feedback.
-
I made a follow-up to those thoughts, narrowing down to a more concrete implementation. There are still many things to tryout, but I'm slowly getting there. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I'm toying with modding on WebAssembly and I'm having a hard time figuring out all pieces together. I'm not experienced with WebAssembly, besides having a good understand on how it works.
So I decided to write all those thoughts somewhere to help me organize my mind and maybe this helps someone if the future (me included).
Runtimes
So far working with
wasmtime
is very easy, the hardest part is getting WebAssembly modding working on it's own home: the Browser.When working with
wasmtime
(and alsowasmer
) it's easy to understand the workflow, you setup a wasm runtime, load modules, inject some imports, compile the module, instantiate it and call the methods. It's fair easy to get this working if you have any previous experience working with embedded runtime.BUT when targeting
wasm32-unknown-unknown
the game IS also a wasm module. So here is where things starts to get tricky. What we are trying to do is something like:Luckily for us, steps 1~3 are handled by
bevy_assets
, so it's easy to get it done.For step 4 there is a OK-ish example on how to do that.
Step 6 and 7 are easy to do.
So where is the struggle? It's on step 5 - inject imports dependencies.
Any modding API needs to provide, well, an API for modules to use, so how to inject those methods calls, from Game wasm module, on another WebAssembly module? Still don't know, but I bet probably this needs to be some JavaScript bindings, so in order to inject those binds, one would need to bind from Rust to JavaScript and from JavaScript to WebAssembly module, seems easy, right?
well...
wasm32-unknown-unknown
vswasm32-wasi
The problem is with regards to
WASI
. My first attempt was trying to build a mod targetingwasm32-wasi
, since any modding would benefit from having access to IO related features, likestdin
,stdout
,stderr
and maybestdio
. Usingstdin
/stdout
to communicate with mods seems a good approach, much like Lapce doesIn order for that work, I need to provide the
WASI
bindings to the wasm module. Again, usingwasmtime
that was a piece of cake, but when targetingwasm32-unknown-unknown
things didn't go that well.wasm_bindgen
doesn't work withwasi
Even tho
cargo-wasi
supportswasm_bindgen
, which detects if the crate useswasm-bindgen
and auto call it for us, the opposite doesn't apply: When trying to generate bindings withwasm_bindgen
targetingwasm32-wasi
, it panics:And it won't be fixed until
Component Model
is out.wasmtime
support doesn'twasm_bindgen
anymoreAnother problem is that
wasmtime
dropped the support forwasm_bindgen
untilComponent Model
is also out.This makes very hard to develop an API that targets both web and native, since for the former
wasm_bindgen
is require, while for the latter, a custom API bindings needs to be used.Final naive and initial thoughts
Since modding for
bevy
only makes sense ifwasm32-unknown-unknown
is also targeted,WASI
won't help us here. Also, the very immature state of WebAssembly outside the browser, makes it very hard to build an API that works for both targets.Next steps
The obvious conclusion here would be to wait for
Component Model
gets done and wait forwasm_bindgen
supportsWASI
andwasmtime
supportswasm_bindgen
, this would make things A LOT easier, but I will do more researches and check if there is some workaround for the problems I listed.I'm hopping also someone hardly disagrees with me and shows me that it can be done in other ways.
Anyway, thanks for reading and any comments, suggestions and thoughts are appreciated!
Beta Was this translation helpful? Give feedback.
All reactions