Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Web Assembly #228

Closed
Pietrek14 opened this issue Sep 4, 2022 · 15 comments
Closed

Support for Web Assembly #228

Pietrek14 opened this issue Sep 4, 2022 · 15 comments

Comments

@Pietrek14
Copy link

The crate won't work on Web Assembly even with zstd disabled, because the load_tmx_map_from function internally calls File::open, which returns an error on wasm targets.

@aleokdev
Copy link
Contributor

aleokdev commented Sep 6, 2022

Just as a workaround you can use the next branch for now and implement your own ResourceReader which doesn't use File. There is no future support though so you'll need to embed the map into the executable.

@Pietrek14
Copy link
Author

Thanks you. Do you have any idea when it's going to be officially included in the crate?

@aleokdev
Copy link
Contributor

aleokdev commented Sep 6, 2022

Hopefully on 0.12. Futures are a bit tricky to implement. 0.11 will have support for custom sync readers though.

@aleokdev
Copy link
Contributor

aleokdev commented Sep 7, 2022

Leaving this here for other users, as a workaround for the crate to work with wasm you'll need to disable the zstd feature and a fully embedded map (Doesn't refer to external files, with the exception of images).
To disable the zstd feature turn the default features off: tiled = { /* ... */, default-features = false }
If you need to work with external files, then you'll need to use the next branch and implement your own ResourceReader. However, beware that futures are still not supported in the crate so you'll have a bad time trying to load anything that isn't embed in the executable itself.

@aleokdev
Copy link
Contributor

aleokdev commented Sep 7, 2022

Sorry I didn't mention the embedded map thing before, I immediately assumed you needed to refer to external files given your description. If you can choose to use fully embedded maps instead, I recommend using those instead. The crate won't call File::open unless it is required to do so. (It doesn't call it for images either.)

@bjorn
Copy link
Member

bjorn commented Sep 7, 2022

For the record, "embedded map" here is referring to storing a map with all tilesets embedded. However, I would not recommend embedding the tilesets in the working copy of your map if you're sharing them between multiple maps. Instead, you can export the map (File > Export) and rely on the "Embed tilesets" export option (Preferences > General > Export Options).

If you're using templates, be sure to enable the "Detach templates" export option as well.

@petersn
Copy link

petersn commented Feb 11, 2023

I was curious if a very small change would suffice, so I tried adjusting TMX parsing to first check the cache, then use File::open when load_tmx_map_from is called. The idea here is that in your browser build you simply preload all of the tilesets you'll need ahead of time into the cache, then load_tmx_map_from can simply grab these without touching the filesystem.

This is a very small change to the code base, here: current...petersn:rs-tiled:current

I added populate_tsx_cache_from with the same arguments as load_tsx_tileset_from, except that it populates the cache. You can use it like:

use tiled::Loader;

const TSX_PATH: &str = "assets/tilesheet.tsx";
const TSX_CONTENTS: &[u8] = include_bytes!(TSX_PATH);
const TMX_PATH: &str = "assets/map.tmx";
const TMX_CONTENTS: &[u8] = include_bytes!(TMX_PATH);

let mut loader = Loader::new();
let tileset = loader.populate_tsx_cache_from(&TSX_CONTENTS[..], TSX_PATH).unwrap();
// Now that the tileset is preloaded into the cache we may load the map without crashing.
let map = loader.load_tmx_map_from(&TMX_CONTENTS[..], TMX_PATH).unwrap();

If you add

tiled = { git = "https://github.com/petersn/rs-tiled", default-features = false }

to Cargo.toml you can try out this version as a workaround for browser wasm-bindgen builds.

I could turn this into a PR if folks are interested, but I assume that the goal would be to do something less hacky, in particular with this next branch?

@bjorn
Copy link
Member

bjorn commented Feb 11, 2023

@petersn That's a nice approach, and I think actually this can already be done without any changes to rs-tiled when you use the next branch. Since Map was already adjusted to check first, before trying to read a file:

rs-tiled/src/map.rs

Lines 156 to 163 in bfd67ca

EmbeddedParseResultType::ExternalReference { tileset_path } => {
let tileset = if let Some(ts) = cache.get_tileset(&tileset_path) {
ts
} else {
let tileset = Arc::new(crate::parse::xml::parse_tileset(&tileset_path, reader, cache)?);
cache.insert_tileset(tileset_path.clone(), tileset.clone());
tileset
};

The Loader provides a mutable reference to the Cache:

rs-tiled/src/loader.rs

Lines 159 to 162 in bfd67ca

/// Returns a mutable reference to the loader's internal [`ResourceCache`].
pub fn cache_mut(&mut self) -> &mut Cache {
&mut self.cache
}

And the Cache provides a function to insert tilesets:

rs-tiled/src/cache.rs

Lines 42 to 45 in bfd67ca

/// Insert a new tileset into the cache.
///
/// See [`Self::get_tileset()`] for an example.
fn insert_tileset(&mut self, path: impl AsRef<ResourcePath>, tileset: Arc<Tileset>);

Maybe you could let us know whether this already suffices.

@petersn
Copy link

petersn commented Feb 11, 2023

@bjorn Thanks for the pointers, that looks great. Seems like it'll already suffice for my purposes, I'll switch to next. Are there any other gotchas I should be aware of on this branch?

@bjorn
Copy link
Member

bjorn commented Feb 12, 2023

@petersn Check out the 0.11 changelog for a high-level overview of the changes: https://github.com/mapeditor/rs-tiled/blob/next/CHANGELOG.md

@aleokdev Maybe it would make sense to do a 0.11 release, even when not all its goals have been met yet?

@aleokdev
Copy link
Contributor

@aleokdev Maybe it would make sense to do a 0.11 release, even when not all its goals have been met yet?

I'll try to review all the changes done in the next branch this week, and publish a version if I don't see any major issues. Might even bundle the changes done in the unreleased current version along with it.

@bjorn
Copy link
Member

bjorn commented Feb 12, 2023

@aleokdev I've opened #246 for merging current into next, but due to the deprecation of Tile::tile_type and Object::obj_type I think it would make sense to make a 0.10.3 release as well, at least if we want to then remove those deprecated members with the 0.11 release. If we can wait with that until 0.12 then I guess a 0.10.3 isn't really useful.

@aleokdev
Copy link
Contributor

@aleokdev I've opened #246 for merging current into next, but due to the deprecation of Tile::tile_type and Object::obj_type I think it would make sense to make a 0.10.3 release as well, at least if we want to then remove those deprecated members with the 0.11 release. If we can wait with that until 0.12 then I guess a 0.10.3 isn't really useful.

@bjorn Apparently the change in TileData is breaking as we are adding a new public member to a fully public struct, so we need to bundle that with 0.11 anyway. I can stash that change and release 0.10.3 with the other changes.

@bjorn
Copy link
Member

bjorn commented Feb 13, 2023

@aleokdev Ok, then I don't see much value in doing a 0.10.3 and think we could just go for 0.11.0, but up to you.

@aleokdev
Copy link
Contributor

aleokdev commented May 3, 2023

Closing this as next is now merged: 0.11.0 has better load utils, which are more compatible with WASM binaries.

@aleokdev aleokdev closed this as completed May 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants