Closed gcardozo123 closed 1 year ago
So... as far as I understand, Emerald uses Serde to allow users to persist their game worlds. I can see that some of Emerald's structs have a "schema" equivalent which is used for serializaition/deserialization, for example , for Tilemap
there's a TilemapSchema
. With a TilemapSchema
it's possible to obtain a regular Tilemap
via to_tilemap
. On the other hand, I can't find how to obtain the schema via the regular tilemap. I was expecting Emerald would have some utility somewhere to help with serializing custom data, but I can't seem to find it. š
Yo! Thanks for reporting this issue, I sometimes forget to run all examples to make sure they work properly, hopefully someday the CI/CD actions can do this. I can hopefully get to fixing this specific issue soon, but my time is somewhat limited right now as I'm working on engine porting efforts.
As for serialization, unfortunately world serialization is not directly supported by Emerald. A custom serialization method would likely need to be written.
The .wrld files are intended to make world creation simpler for handwriting and (in the future) an editor application.
In the future, we could likely support direct serialization of Emerald components (sprite, label, etc), but users will still be responsible for serialization of their own custom components.
As for serialization, unfortunately world serialization is not directly supported by Emerald. A custom serialization method would likely need to be written.
Oh, yeah, absolutely. I don't mean world serialization literally, let me rephrase that. I'm new to Rust, Emerald and their whole ecosystem. I realized that Emerald ships with Serde and that I can probably work out a way of serializing/deserializing my own custom objects with it, but I'm confused as to how I could serialize Emerald's Tilemap
for example. But if I understood you correctly that's not possible, we can currently only deserialize a Tilemap, but not serialize one. Is that so?
I can hopefully get to fixing this specific issue soon, but my time is somewhat limited right now as I'm working on engine porting efforts.
I mean no pressure whatsoever, I'm more curious from a learning standpoint and hoping I could help rather than asking for features/fixes.
Oh yah, currently Tilemaps and other components can only be deserialized. If we were to serialize it, I think we'd just need to write a function that converts the tilemap back into a TilemapSchema and shove it into the wrld file.
And for sure, I'm always here to answer any questions! And we always welcome contributions š
Got it, thx for the replies! š
About serializing a Tilemap
, would you be interested in something like this?
impl Serialize for Tilemap {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let resource = TilesetResource {
height: self.tilesheet_height,
width: self.tilesheet_width,
texture: String::from(self.tilesheet.label()),
};
let mut tiles: Vec<TileSchema> = vec![];
for (i, tile_id) in self.tiles.iter().enumerate() {
if tile_id.is_none() {
continue;
}
let x = i % self.width();
let y = i / self.width();
tiles.push(TileSchema {
x: x,
y: y,
id: tile_id.unwrap(),
});
}
let tilemap_schema = TilemapSchema {
width: self.width(),
height: self.height(),
tileset: Some(resource),
resource: None,
visible: true, //TODO
z_index: 0.0, //TODO
tiles: tiles,
};
TilemapSchema::serialize(&tilemap_schema, serializer)
}
}
Example usage:
emd.set_asset_folder_root(String::from("./examples/assets/"));
let tileset_key = emd.loader().texture("tileset.png").unwrap();
let mut tilemap = Tilemap::new(tileset_key, Vector2::new(16, 16), 2, 2, 30, 30);
tilemap.set_tile(0, 0, Some(0)).unwrap();
tilemap.set_tile(1, 0, Some(1)).unwrap();
tilemap.set_tile(0, 1, Some(2)).unwrap();
tilemap.set_tile(1, 1, Some(3)).unwrap();
tilemap.set_tile(0, 2, Some(0)).unwrap();
tilemap.set_tile(1, 2, Some(1)).unwrap();
tilemap.set_tile(0, 3, Some(3)).unwrap();
tilemap.set_tile(1, 3, Some(3)).unwrap();
tilemap.set_tile(1, 6, Some(3)).unwrap();
tilemap.set_tile(2, 6, Some(3)).unwrap();
let serialized = serde_json::to_string(&tilemap).unwrap();
println!("serialized: {}", serialized);
Output:
serialized: {"width":30,"height":30,"tileset":{"texture":"tileset.png","height":2,"width":2},"resource":null,"visible":true,"z_index":0.0,"tiles":[{"x":0,"y":0,"id":0},{"x":1,"y":0,"id":1},{"x":0,"y":1,"id":2},{"x":1,"y":1,"id":3},{"x":0,"y":2,"id":0},{"x":1,"y":2,"id":1},{"x":0,"y":3,"id":3},{"x":1,"y":3,"id":3},{"x":1,"y":6,"id":3},{"x":2,"y":6,"id":3}]}
If you're interested I can put up a PR once I fix my //TODO
s, but no pressure, I understand you might have different plans on how a serialization API should look in Emerald.
that looks good to me! I'd definitely be down for that, as long as it's able to serialize to toml and back (for the .wrld file) then it should work perfectly
Good point! For whatever reason it doesn't seem to work with toml. I need to dig more into this and figure out what toml needs that my function is not providing.
Oh, I think I found the issue:
TOML can't have any subtables inside the table, by construction; in other words, all simple fields, like numbers and strings, must be written before the complex types like structs (which are mapped to tables).
So I can give it another try, just need to reorder some attributes in the TilemapSchema
to make Serde happy. :D
Hi,
It seems the
emerald/examples/load_world_file.rs
example is not compatible with the current version of the engine:It would be nice to have a
save_world_file.rs
example that would programmatically create a world and then serialize it intoexamples\assets\example.wrld
. Then in theload_world_file.rs
we could go:this way we could remove the
example.wrld
file from the repo and future proof it against engine changes. I can open an MR if I figure out how to serialize the world (I'm quite new to Rust)š[Edit] The same line
self.world = emd.loader().world("example.wrld").unwrap();
also fails in theent.rs
example.