-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Make entity generation a new type and remove identifier #19121
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
Make entity generation a new type and remove identifier #19121
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly just some nitpicking. The changes look good and I love that this PR demonstrates the rolling updates we can do to migration guides.
|
||
/// Returns the [`EntityGeneration`] that would result from this many more `versions` of the corresponding [`EntityRow`] from passing. | ||
#[inline] | ||
pub const fn after_versions(self, versions: u32) -> Self { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Future PR: might be nice to implement Iterator<Item = Self>
for EntityGeneration
. That gives an idiomatic next
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noticed some typos in the migration guide
Co-authored-by: Mark Nokalt <[email protected]>
Benchmarks looks good, sparse set change detection was the only thing that was slowed down by anything notable. But I don't think that's a big deal. Other than that, I think this is generally an improvement in perf. (Less checks when changing the generation.) Also want to point out that we loose a niche on |
…9121) # Objective This is a followup to bevyengine#18704 . There's lots more followup work, but this is the minimum to unblock bevyengine#18670, etc. This direction has been given the green light by Alice [here](bevyengine#18704 (comment)). ## Solution I could have split this over multiple PRs, but I figured skipping straight here would be easiest for everyone and would unblock things the quickest. This removes the now no longer needed `identifier` module and makes `Entity::generation` go from `NonZeroU32` to `struct EntityGeneration(u32)`. ## Testing CI --------- Co-authored-by: Mark Nokalt <[email protected]>
# Objective Recently the `u32` `Entity::generation` was replaced with the new `EntityGeneration` in #19121. This made meanings a lot more clear, and prevented accidental misuse. One common misuse was assuming that `u32`s that were greater than others came after those others. Wrapping makes this assumption false. When `EntityGeneration` was created, it retained the `u32` ordering, which was useless at best and wrong at worst. This pr fixes the ordering implementation, so new generations are greater than older generations. Some users were already accounting for this ordering issue (which was still present in 0.16 and before) by manually accessing the `u32` representation. This made migrating difficult for avian physics; see [here](https://discord.com/channels/691052431525675048/749335865876021248/1377431569228103780). I am generally of the opinion that this type should be kept opaque to prevent accidental misuse. As we find issues like this, the functionality should be added to `EntityGeneration` directly. ## Solution Fix the ordering implementation through `Ord`. Alternatively, we could keep `Ord` the same and make a `cmp_age` method, but I think this is better, even though sorting entity ids may be *marginally* slower now (but more correct). This is a tradeoff. ## Testing I improved documentation for aliasing and ordering, adding some doc tests.
Otherwise creation with index = 1 and generation = 1 looks like this: ```rust let expected_entity = Entity::from_bits((1 ^ u32::MAX) as u64 | (1 << 32)); ``` I also removed outdated comment which left untouched after the generation rework (bevyengine#19121)
For details see bevyengine/bevy#19121 bevyengine/bevy#18704 The niche is now in the index, which makes the compression logic even simpler. The index now represented by NonMaxU32, which internally represented as NonZeroU32 with all bits reversed, so we have to xor the bits. I opened a PR to make it more ergonomic and avoid us relying on the internal layout: bevyengine/bevy#21246
# Objective Entity serialization is necessary for networking. Entities can exist inside components and events. After deserialization, we simply map remote entities to local entities. To serialize entities efficiently, we split them into index and generation, which benefits from varint serialization. #19121 and #18704 changed the entity layout, and I like the new layout a lot. We can now use the extra bit from the index to store whether the generation is zero or not, avoiding the need to serialize the generation entirely. However, constructing new entities requires relying on the internal layout, which is not very ergonomic. For example, here is how an entity with index = 1 and generation = 1 can be created: ```rust let expected_entity = Entity::from_bits((1 ^ u32::MAX) as u64 | (1 << 32)); ``` ## Solution - Make `Entity::from_raw_and_generation` public. While at it, I also removed outdated comment. - Add `EntityRow::from_raw_u32` to make the initialization nicer. ## Testing - It's a trivial change, but I re-used `EntityRow::from_raw_u32` in unit tests to simplify them. ## Notes I'd probably rename `Entity::from_raw_and_generation` into `Entity::from_row_and_generation` or `Entity::from_index_and_generation`.
# Objective I think "raw" is a leftover from old Entity methods where a raw u32 value was accepted. Since we pass a _row_ now, I think it worth renaming. ## Solution - Adjusted a single letter in 2 methods 😅 - While at it, adjusted the comment about generation since it can be zero since #19121.
# Objective Entity serialization is necessary for networking. Entities can exist inside components and events. After deserialization, we simply map remote entities to local entities. To serialize entities efficiently, we split them into index and generation, which benefits from varint serialization. #19121 and #18704 changed the entity layout, and I like the new layout a lot. We can now use the extra bit from the index to store whether the generation is zero or not, avoiding the need to serialize the generation entirely. However, constructing new entities requires relying on the internal layout, which is not very ergonomic. For example, here is how an entity with index = 1 and generation = 1 can be created: ```rust let expected_entity = Entity::from_bits((1 ^ u32::MAX) as u64 | (1 << 32)); ``` ## Solution - Make `Entity::from_raw_and_generation` public. While at it, I also removed outdated comment. - Add `EntityRow::from_raw_u32` to make the initialization nicer. ## Testing - It's a trivial change, but I re-used `EntityRow::from_raw_u32` in unit tests to simplify them. ## Notes I'd probably rename `Entity::from_raw_and_generation` into `Entity::from_row_and_generation` or `Entity::from_index_and_generation`.
# Objective I think "raw" is a leftover from old Entity methods where a raw u32 value was accepted. Since we pass a _row_ now, I think it worth renaming. ## Solution - Adjusted a single letter in 2 methods 😅 - While at it, adjusted the comment about generation since it can be zero since #19121.
# Objective Entity serialization is necessary for networking. Entities can exist inside components and events. After deserialization, we simply map remote entities to local entities. To serialize entities efficiently, we split them into index and generation, which benefits from varint serialization. #19121 and #18704 changed the entity layout, and I like the new layout a lot. We can now use the extra bit from the index to store whether the generation is zero or not, avoiding the need to serialize the generation entirely. However, constructing new entities requires relying on the internal layout, which is not very ergonomic. For example, here is how an entity with index = 1 and generation = 1 can be created: ```rust let expected_entity = Entity::from_bits((1 ^ u32::MAX) as u64 | (1 << 32)); ``` ## Solution - Make `Entity::from_raw_and_generation` public. While at it, I also removed outdated comment. - Add `EntityRow::from_raw_u32` to make the initialization nicer. ## Testing - It's a trivial change, but I re-used `EntityRow::from_raw_u32` in unit tests to simplify them. ## Notes I'd probably rename `Entity::from_raw_and_generation` into `Entity::from_row_and_generation` or `Entity::from_index_and_generation`.
# Objective I think "raw" is a leftover from old Entity methods where a raw u32 value was accepted. Since we pass a _row_ now, I think it worth renaming. ## Solution - Adjusted a single letter in 2 methods 😅 - While at it, adjusted the comment about generation since it can be zero since #19121.
For details see bevyengine/bevy#19121 bevyengine/bevy#18704 The niche is now in the index, which makes the compression logic even simpler. The index now represented by NonMaxU32, which internally represented as NonZeroU32 with all bits reversed, so we have to xor the bits. I opened a PR to make it more ergonomic and avoid us relying on the internal layout: bevyengine/bevy#21246
For details see bevyengine/bevy#19121 bevyengine/bevy#18704 The niche is now in the index, which makes the compression logic even simpler.
For details see bevyengine/bevy#19121 bevyengine/bevy#18704 The niche is now in the index, which makes the compression logic even simpler.
For details see bevyengine/bevy#19121 bevyengine/bevy#18704 The niche is now in the index, which makes the compression logic even simpler.
* Bump Bevy version * Migrate to the new Entity layout For details see bevyengine/bevy#19121 bevyengine/bevy#18704 The niche is now in the index, which makes the compression logic even simpler. * Migrate to the new `SystemParam` changes For details see bevyengine/bevy#16885 bevyengine/bevy#19143 * Remove `*_trigger_targets` * Simplify fns logic We no longer need custom sed/de to additionally serialize targets. This allows us to express things a bit nicer using conversion traits. * Rename all "event" into "message". * Rename all "trigger" into "event". * Rename "resend locally" into just "send locally" Fits better. * Split channel methods --------- Co-authored-by: UkoeHB <[email protected]>
Objective
This is a followup to #18704 . There's lots more followup work, but this is the minimum to unblock #18670, etc.
This direction has been given the green light by Alice here.
Solution
I could have split this over multiple PRs, but I figured skipping straight here would be easiest for everyone and would unblock things the quickest.
This removes the now no longer needed
identifier
module and makesEntity::generation
go fromNonZeroU32
tostruct EntityGeneration(u32)
.Testing
CI