diff --git a/CHANGELOG.md b/CHANGELOG.md index 8253a300..1c2c5e44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Serialize entities in optimal way by writing its index and generation as separate varints. - Hide `ReplicationId`, `ReplicationInfo` and related methods from `ReplicationRules` from public API. - Rename `ReplicationRules::replication_id` into `ReplicationRules::replication_marker_id`. - Use serialization buffer cache per client for replication. diff --git a/src/client.rs b/src/client.rs index a0ab76ea..58e134ae 100644 --- a/src/client.rs +++ b/src/client.rs @@ -122,7 +122,7 @@ fn deserialize_tick(cursor: &mut Cursor, world: &mut World) -> Result, world: &mut World, @@ -132,7 +132,7 @@ fn deserialize_component_diffs( ) -> Result<(), bincode::Error> { let entities_count: u16 = bincode::deserialize_from(&mut *cursor)?; for _ in 0..entities_count { - let entity = DefaultOptions::new().deserialize_from(&mut *cursor)?; + let entity = deserialize_entity(&mut *cursor)?; let mut entity = entity_map.get_by_server_or_spawn(world, entity); let components_count: u8 = bincode::deserialize_from(&mut *cursor)?; for _ in 0..components_count { @@ -150,7 +150,7 @@ fn deserialize_component_diffs( Ok(()) } -/// Deserializes despawns and applies them to the [`World`]. +/// Deserializes despawns and applies them to the `world`. fn deserialize_despawns( cursor: &mut Cursor, world: &mut World, @@ -161,7 +161,7 @@ fn deserialize_despawns( // The entity might have already been deleted with the last diff, // but the server might not yet have received confirmation from the // client and could include the deletion in the latest diff. - let server_entity = DefaultOptions::new().deserialize_from(&mut *cursor)?; + let server_entity = deserialize_entity(&mut *cursor)?; if let Some(client_entity) = entity_map.remove_by_server(server_entity) { world.entity_mut(client_entity).despawn_recursive(); } @@ -170,6 +170,21 @@ fn deserialize_despawns( Ok(()) } +/// Deserializes `entity` from compressed index and generation, for details see [`ReplicationBuffer::write_entity()`]. +fn deserialize_entity(cursor: &mut Cursor) -> Result { + let flagged_index: u64 = DefaultOptions::new().deserialize_from(&mut *cursor)?; + let has_generation = (flagged_index & 1) > 0; + let generation = if has_generation { + DefaultOptions::new().deserialize_from(&mut *cursor)? + } else { + 0u32 + }; + + let bits = (generation as u64) << 32 | (flagged_index >> 1); + + Ok(Entity::from_bits(bits)) +} + /// Type of component change. /// /// Parameter for [`deserialize_component_diffs`]. diff --git a/src/server.rs b/src/server.rs index 28af77d4..e470651d 100644 --- a/src/server.rs +++ b/src/server.rs @@ -446,14 +446,14 @@ struct ReplicationBuffer { /// The number of empty arrays at the end. Can be removed using [`Self::trim_empty_arrays`] trailing_empty_arrays: usize, - /// Position of the entity map from last call of [`Self::start_entity_data`] or [`Self::write_current_entity`]. + /// Position of entity after [`Self::start_entity_data`] or its data after [`Self::write_data_entity`]. entity_data_pos: u64, - /// Length of the map that updated automatically after writing data. + /// Length of the data for entity that updated automatically after writing data. entity_data_len: u8, /// Entity from last call of [`Self::start_entity_data`]. - current_entity: Entity, + data_entity: Entity, } impl ReplicationBuffer { @@ -476,7 +476,7 @@ impl ReplicationBuffer { trailing_empty_arrays: Default::default(), entity_data_pos: Default::default(), entity_data_len: Default::default(), - current_entity: Entity::PLACEHOLDER, + data_entity: Entity::PLACEHOLDER, }) } @@ -547,7 +547,7 @@ impl ReplicationBuffer { self.trailing_empty_arrays = 0; } - /// Starts writing entity and its data by remembering [`Entity`]. + /// Starts writing entity and its data by remembering `entity`. /// /// Arrays can contain component changes or removals inside. /// Length will be increased automatically after writing data. @@ -556,14 +556,14 @@ impl ReplicationBuffer { fn start_entity_data(&mut self, entity: Entity) { debug_assert_eq!(self.entity_data_len, 0); - self.current_entity = entity; + self.data_entity = entity; } /// Writes entity for current data and updates remembered position for it to write length later. /// /// Should be called only after first data write. - fn write_current_entity(&mut self) -> Result<(), bincode::Error> { - DefaultOptions::new().serialize_into(&mut self.message, &self.current_entity)?; + fn write_data_entity(&mut self) -> Result<(), bincode::Error> { + self.write_entity(self.data_entity)?; self.entity_data_pos = self.message.position(); self.message .set_position(self.entity_data_pos + mem::size_of_val(&self.entity_data_len) as u64); @@ -595,7 +595,7 @@ impl ReplicationBuffer { Ok(()) } - /// Serializes [`ReplicationId`] and component into the buffer data. + /// Serializes `replication_id` and component from `ptr` into the buffer data. /// /// Should be called only inside entity data. /// Increases entity data length by 1. @@ -607,7 +607,7 @@ impl ReplicationBuffer { ptr: Ptr, ) -> Result<(), bincode::Error> { if self.entity_data_len == 0 { - self.write_current_entity()?; + self.write_data_entity()?; } DefaultOptions::new().serialize_into(&mut self.message, &replication_id)?; @@ -617,14 +617,14 @@ impl ReplicationBuffer { Ok(()) } - /// Serializes [`ReplicationId`] of the removed component into the buffer data. + /// Serializes `replication_id` of the removed component into the buffer data. /// /// Should be called only inside entity data. /// Increases entity data length by 1. /// See also [`Self::start_entity_data`]. fn write_removal(&mut self, replication_id: ReplicationId) -> Result<(), bincode::Error> { if self.entity_data_len == 0 { - self.write_current_entity()?; + self.write_data_entity()?; } DefaultOptions::new().serialize_into(&mut self.message, &replication_id)?; @@ -633,13 +633,13 @@ impl ReplicationBuffer { Ok(()) } - /// Serializes despawned [`Entity`]. + /// Serializes despawned `entity`. /// /// Should be called only inside array. /// Increases array length by 1. /// See also [`Self::start_array`]. fn write_despawn(&mut self, entity: Entity) -> Result<(), bincode::Error> { - DefaultOptions::new().serialize_into(&mut self.message, &entity)?; + self.write_entity(entity)?; self.array_len = self .array_len .checked_add(1) @@ -647,4 +647,22 @@ impl ReplicationBuffer { Ok(()) } + + /// Serializes `entity` by writing its index and generation as separate varints. + /// + /// The index is first prepended with a bit flag to indicate if the generation + /// is serialized or not (it is not serialized if equal to zero). + #[inline] + fn write_entity(&mut self, entity: Entity) -> Result<(), bincode::Error> { + let mut flagged_index = (entity.index() as u64) << 1; + let flag = entity.generation() > 0; + flagged_index |= flag as u64; + + DefaultOptions::new().serialize_into(&mut self.message, &flagged_index)?; + if flag { + DefaultOptions::new().serialize_into(&mut self.message, &entity.generation())?; + } + + Ok(()) + } }