You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hello. I'm raising this topic to follow up on discussion on the community Discord. When trying to use scenes to save and load my world state (as part of a save game system) I ran into quite a few issues caused by difficulties in making sure all the types in my components implement Reflect.
For my structs which contain only types which have the a Reflect impl created in bevy_reflect, there are no issues with using the typical #[derive(Reflect)]. But I ran into a lot of trouble when trying to get things to work components containing external types. Examples include:
Components which contain types from external crates which (obviously) have no Reflect impl.
Example: Decimal from the rust_decimal crate, which I was using to store high-precision numeric values in some components.
Components which contain standard library types which happen to be missing a Reflect implementation (either manual or via macro) from std.rs in bevy_reflect.
Example: VecDeque from std::collections would probably need a manual impl but doesn't have one.
Components which contain types from bevy itself but which lack either Reflect or Default/FromWorld
Example: Entity has a Reflect impl via macro but no Default/FromWorld. Quite possibly putting entities in components like this causes an entirely different set of different problems, but ignoring that for now...
Concrete examples and workarounds(?)
There may be solutions to some or all of the above, but based on my meagre experience they are quite difficult and/or unintuitive.
For example, for point (1) above, I was, with the help of a very knowledgeable Discord member, able to get Decimal to serialize with the following incantation:
In this example I can use DecimalWrapper as a component which can be serialized successfully. However if I uncomment the first // #[reflect(Component)] and try to serialize that struct directly, it fails at runtime with a rather cryptic "Type 'DecimalComponent' does not support ReflectValue serialization". I assume there is a variant of this incantation to get it working, but at this point I think it's fair to say we're over the average user's head, and certainly way over mine...
I was also able to get the above working by editing bevy_reflect locally to depend on rust_decimal and calling the macro directly from there to avoid the coherence restrictions which prevent me from invoking the macro from my crate:
Again this worked but I once again needed help from the very smart people on Discord to figure out the correct trait parameters here, as my naive attempts to simply call impl_reflect_value!(Decimal) did not work.
Returning to the wrapper solution above though, I figured perhaps this "newtype wrapper for a type which implements Serialize and Deserialize" might solve my problems for all the external types I'm using so I proceeded to attempt to craft a generic wrapper, but my attempts there failed so miserably they are not worth sharing.
Points of discussion
I raise these issues not because I have any solution in mind but primarily to share my experience as a user whose experience went from smooth sailing to "trait hell" upon attempting to implement a save system. But to humbly raise some points for discussion:
If there are recommended solutions to some of these problems, a more complex scenes example demonstrating them may help others like me in the future.
If these issues are likely to cause difficult or insurmountable problems with saving/loading worlds, it may be good to warn users about using external types in their components (but of course we may lose access to some very useful crates this way...).
If there is some approach other than scenes for saving and loading games which doesn't have these issues (even if it's a more "manual way") it would be good to know about it. Currently the Bevy webpage seems to suggest scenes ought to be used for this.
I wonder if it would be possible to have some alternative serialization/deserialization strategy based on serde traits alone, since these are already ubiquitous in the Rust ecosystem, whereas Reflect is (at best) only ever going to cover core/stdlib and Bevy internal types.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Hello. I'm raising this topic to follow up on discussion on the community Discord. When trying to use scenes to save and load my world state (as part of a save game system) I ran into quite a few issues caused by difficulties in making sure all the types in my components implement
Reflect
.For my structs which contain only types which have the a
Reflect
impl created inbevy_reflect
, there are no issues with using the typical#[derive(Reflect)]
. But I ran into a lot of trouble when trying to get things to work components containing external types. Examples include:Reflect
impl.Decimal
from therust_decimal
crate, which I was using to store high-precision numeric values in some components.std.rs
inbevy_reflect
.VecDeque
fromstd::collections
would probably need a manual impl but doesn't have one.Reflect
orDefault
/FromWorld
Entity
has aReflect
impl via macro but noDefault
/FromWorld
. Quite possibly putting entities in components like this causes an entirely different set of different problems, but ignoring that for now...Concrete examples and workarounds(?)
There may be solutions to some or all of the above, but based on my meagre experience they are quite difficult and/or unintuitive.
For example, for point (1) above, I was, with the help of a very knowledgeable Discord member, able to get Decimal to serialize with the following incantation:
In this example I can use DecimalWrapper as a component which can be serialized successfully. However if I uncomment the first
// #[reflect(Component)]
and try to serialize that struct directly, it fails at runtime with a rather cryptic"Type 'DecimalComponent' does not support ReflectValue serialization"
. I assume there is a variant of this incantation to get it working, but at this point I think it's fair to say we're over the average user's head, and certainly way over mine...I was also able to get the above working by editing
bevy_reflect
locally to depend onrust_decimal
and calling the macro directly from there to avoid the coherence restrictions which prevent me from invoking the macro from my crate:Again this worked but I once again needed help from the very smart people on Discord to figure out the correct trait parameters here, as my naive attempts to simply call
impl_reflect_value!(Decimal)
did not work.Returning to the wrapper solution above though, I figured perhaps this "newtype wrapper for a type which implements
Serialize
andDeserialize
" might solve my problems for all the external types I'm using so I proceeded to attempt to craft a generic wrapper, but my attempts there failed so miserably they are not worth sharing.Points of discussion
I raise these issues not because I have any solution in mind but primarily to share my experience as a user whose experience went from smooth sailing to "trait hell" upon attempting to implement a save system. But to humbly raise some points for discussion:
Thanks.
Beta Was this translation helpful? Give feedback.
All reactions