-
Notifications
You must be signed in to change notification settings - Fork 39
Track sent components for each entity #604
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
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #604 +/- ##
==========================================
- Coverage 91.90% 91.81% -0.09%
==========================================
Files 58 61 +3
Lines 3311 3397 +86
==========================================
+ Hits 3043 3119 +76
- Misses 268 278 +10 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
We'll need this for per-component visibility, but this change is useful on its own because it fixes replication for rules with multiple components that were inserted on different ticks. For example, you have a replication rule for `(A, B)`. You spawn an entity with `A`, and on the next tick you insert `B`. Without this change, `B` is replicated, but `A` is wrongly considered as sent. I added a test for it.
800f5b6 to
2066211
Compare
src/server.rs
Outdated
| for (_, components) in entities.drain(..) { | ||
| pools.components.push(components); | ||
| } |
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.
Change to method on pools that takes entities.drain(...) iterator as input.
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.
Makes sense, already addressed in the hashmap replacement commit.
src/server.rs
Outdated
| for (_, components) in mutate_info.entities.drain(..) { | ||
| pools.components.push(components); | ||
| } |
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.
Change to method on pools that takes mutate_info.entities.drain(...) iterator as input.
| for entity_ticks in ticks.entities.values_mut() { | ||
| entity_ticks.system_tick.check_tick(*check); | ||
| } |
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.
This logic should be inside ClientTicks.
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.
It's a tiny loop and since we already expose the access to tick.entities, I think it reads better this way.
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.
It's not only about readability. These functions are suffering from growing line bloat.
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.
This function is only 9 lines.
It's collect_* functions that are large.
| let Some(entity_ticks) = ticks.entities.get_mut(&entity) else { | ||
| continue; | ||
| }; | ||
| if !entity_ticks.components.remove(&component_id) { | ||
| continue; | ||
| } |
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.
Should also filter on visibility.hidden(entity) to avoid redundantly sending component removals when visibility is lost (which will also send a despawn).
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.
This executed after processing despawns, where the entity removed from ticks.entities if it was despawned or lost visibility.
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.
Added a comment about it.
src/server.rs
Outdated
| client_ticks.mutation_tick(entity.id()) | ||
| && !ticks.is_added(change_tick.last_run(), change_tick.this_run()) | ||
| if let Some(entity_ticks) = client_ticks.entities.get(&entity.id()) | ||
| && entity_ticks.components.contains(&component_id) |
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.
| && entity_ticks.components.contains(&component_id) | |
| && entity_ticks.components.contains(&component_id) |
Hide this behind a method that clearly reveals its meaning here: was the component added this tick or not?
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.
We actually check whether client received the component. But the struct exposes full access to components, it's documented and I think entity_ticks.components.contains(&component_id) is quite clear. So I'd prefer to leave this as is.
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.
it's documented and I think entity_ticks.components.contains(&component_id) is quite clear.
The meaning was not clear to me, and would be even less clear to anyone other than us two reading it.
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.
Let me add a comment about it.
I think having entity_ticks.is_new(component_index) won't clarify things enough.
src/server.rs
Outdated
| } | ||
| ticks.set_mutation_tick(entity.id(), change_tick.this_run(), server_tick); | ||
|
|
||
| match entity_entry { |
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.
Move all this to a method on ClientTicksEntity.
| } | ||
|
|
||
| signature.is_added() || ticks.is_new_for_client(entity) | ||
| signature.is_added() || !ticks.entities.contains_key(&entity) |
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.
Don't like removing clarity like this. Keep the method or use ClientTicksEntity.is_new().
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.
Same as for contains above.
src/server.rs
Outdated
| .extend(updates.drain_changed_entity_ids()); | ||
| } | ||
| Entry::Vacant(entry) => { | ||
| let mut components = pools.component_sets.pop().unwrap_or_default(); |
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.
| let mut components = pools.component_sets.pop().unwrap_or_default(); | |
| let mut components = pools.component_sets.pop().unwrap_or_default(); | |
| components.clear(); |
Either here or when pushing into the pool. Test to catch this?
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.
We clear all data before pushing into the pool.
In the hashmap replacement commit I added a method that clears it.
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.
Pushed a change that properly abstracts this, shouldn't be any confusion anymore.
|
Pushed 2 commits. I'll address your suggestions in a moment. |
Reduces the unsafety and the mount of passed arguments.
a77a706 to
42d8392
Compare
This significantly increases performances.
Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
Since it's used in many places, it's better to abstract it to avoid forgetting to call `clear`.
a538b5f to
34bb995
Compare
Objective
We'll need this for per-component visibility, but this change is useful on its own because it fixes replication for rules with multiple components that were inserted on different ticks.
For example, you have a replication rule for
(A, B). You spawn an entity withA, and on the next tick you insertB. Without this change,Bis replicated, butAis wrongly considered as sent. I added a test for it.Implementation details
Inside
ClientTicks, we now store aHashSet<ComponentId>for each entity in addition to ticks. To make it look nicer, I wrapped them in anEntityTicksstruct. I also renamedmutationstoentitiesbecause it fits better (it's not only for mutation ticks - it's also updated on insertions and removals). To avoid double hashing formutations, I switched to using the entry API and made the field mutable. Because of this change, I also had to remove theis_new_for_clienthelper (in one place I need entry API and in another it's a simplecontainscheck). I adjusted the doc comment and with the new naming it should still be clear.MutateInfonow stores aVec<ComponentId>for each entity, and I update the acknowledged components insideEntityTicks.During removals, we now need to remove components from the acknowledged lists, so I adjusted the logic similarly to how we collect changes.