Skip to content

Commit 71f8b4a

Browse files
committed
Use default serde impls for Entity (#6194)
# Objective Currently for entities we serialize only `id`. But this is not very expected behavior. For example, in networking, when the server sends its state, it contains entities and components. On the client, I create new objects and map them (using `EntityMap`) to those received from the server (to know which one matches which). And if `generation` field is missing, this mapping can be broken. Example: 1. Server sends an entity `Entity{ id: 2, generation: 1}` with components. 2. Client puts the received entity in a map and create a new entity that maps to this received entity. The new entity have different `id` and `generation`. Let's call it `Entity{ id: 12, generation: 4}`. 3. Client sends a command for `Entity{ id: 12, generation: 4}`. To do so, it maps local entity to the one from server. But `generation` field is 0 because it was omitted for serialization on the server. So it maps to `Entity{ id: 2, generation: 0}`. 4. Server receives `Entity{ id: 2, generation: 0}` which is invalid. In my game I worked around it by [writing custom serialization](https://github.com/dollisgame/dollis/blob/master/src/core/network/entity_serde.rs) and using `serde(with = "...")`. But it feels like a bad default to me. Using `Entity` over a custom `NetworkId` also have the following advantages: 1. Re-use `MapEntities` trait to map `Entity`s in replicated components. 2. Instead of server `Entity <-> NetworkId ` and `Entity <-> NetworkId`, we map entities only on client. 3. No need to handling uniqueness. It's a rare case, but makes things simpler. For example, I don't need to query for a resource to create an unique ID. Closes #6143. ## Solution Use default serde impls. If anyone want to avoid wasting memory on `generation`, they can create a new type that holds `u32`. This is what Bevy do for [DynamicEntity](https://docs.rs/bevy/latest/bevy/scene/struct.DynamicEntity.html) to serialize scenes. And I don't see any use case to serialize an entity id expect this one. --- ## Changelog ### Changed - Entity now serializes / deserializes `generation` field. ## Migration Guide - Entity now fully serialized. If you want to serialze only `id`, as it was before, you can create a new type that wraps `u32`.
1 parent d8bf5f8 commit 71f8b4a

File tree

3 files changed

+3
-48
lines changed

3 files changed

+3
-48
lines changed

crates/bevy_ecs/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ thread_local = "1.1.4"
2626
fixedbitset = "0.4"
2727
fxhash = "0.2"
2828
downcast-rs = "1.2"
29-
serde = "1"
29+
serde = { version = "1", features = ["derive"] }
3030

3131
[dev-dependencies]
3232
rand = "0.8"

crates/bevy_ecs/src/entity/mod.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,11 @@
3131
//! [`EntityMut::insert`]: crate::world::EntityMut::insert
3232
//! [`EntityMut::remove`]: crate::world::EntityMut::remove
3333
mod map_entities;
34-
mod serde;
3534

36-
pub use self::serde::*;
3735
pub use map_entities::*;
3836

3937
use crate::{archetype::ArchetypeId, storage::SparseSetIndex};
38+
use serde::{Deserialize, Serialize};
4039
use std::{convert::TryFrom, fmt, mem, sync::atomic::Ordering};
4140

4241
#[cfg(target_has_atomic = "64")]
@@ -104,7 +103,7 @@ type IdCursor = isize;
104103
/// [`EntityMut::id`]: crate::world::EntityMut::id
105104
/// [`EntityCommands`]: crate::system::EntityCommands
106105
/// [`Query::get`]: crate::system::Query::get
107-
#[derive(Clone, Copy, Hash, Eq, Ord, PartialEq, PartialOrd)]
106+
#[derive(Clone, Copy, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
108107
pub struct Entity {
109108
pub(crate) generation: u32,
110109
pub(crate) id: u32,

crates/bevy_ecs/src/entity/serde.rs

-44
This file was deleted.

0 commit comments

Comments
 (0)