Skip to content
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

Track entity generation in ComponentEvent (fixes #720) #724

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft

Track entity generation in ComponentEvent (fixes #720) #724

wants to merge 2 commits into from

Conversation

LoganDark
Copy link

@LoganDark LoganDark commented Feb 24, 2021

Checklist

  • I've added tests for all code changes and additions (where applicable)
  • I've updated the book to reflect my changes

API changes

  • ComponentEvent now contains an Entity instead of an Index
  • Join::get works with Entitys now
  • JoinIter::get_unchecked has been removed, since there is no way to obtain generation from a pure function
  • FlaggedAccessMut, OccupiedEntry, VacantEntry, and PairedStorage all store an Entity instead of an Index
  • UnprotectedStorages now work with Entitys instead of Indexes

Obviously, this feature requires many far-reaching changes across many different components of Specs in order to provide the required information all the way down to the level where ComponentEvents are generated and consumed. This is definitely a breaking change in so many different areas and it's unlikely it would be accepted even without the core problems that prevent it from being fully implemented as-is.

Help needed

There are three remaining compiler errors that I need to fix:

   Compiling specs v0.16.1 (/Users/LoganDark/specs)
error[E0308]: mismatched types
  --> src/changeset.rs:83:35
   |
83 |                 self.inner.remove(id);
   |                                   ^^ expected struct `entity::Entity`, found `u32`

error[E0308]: mismatched types
   --> src/join/mod.rs:394:58
    |
394 |             .map(|idx| unsafe { J::get(&mut self.values, idx) })
    |                                                          ^^^ expected struct `entity::Entity`, found `u32`

error[E0308]: mismatched types
   --> src/join/par_join.rs:136:40
    |
136 |             J::get(&mut *values.get(), idx)
    |                                        ^^^ expected struct `entity::Entity`, found `u32`

error: aborting due to 3 previous errors

Perhaps those are a sign that this PR is impossible. Perhaps it's a sign that I need someone more skilled than myself to fix the issue.

  1. The first compiler error has to do with removing all components from a ChangeSet. It iterates through its bitmask and removes every component found inside. The issue is that while it has a bitmask of IDs it does not know the generations for each ID. This will require some deeper modifications to fix.
  2. The second compiler error has to do with the core join logic so it's a bit more complicated. Namely, it's inside the next method of JoinIter. This iterator not only needs to know the IDs it's iterating over but also the generations. This is complicated to implement because the iterator itself is created from only the bitmask and storage from an implementor of Join, which would mean that all implementors of Join would have to store generations in addition to the bitmask, which would probably lead to high memory usage and/or inefficiency. Because of the complexity of this issue it's possible that it will prevent this PR from ever being implemented since it would hurt performance and efficiency.
  3. The third compiler error is another one like the second, complex enough for us to lose all hope. It has to do with parallel joins and producers and other complex things, so we need to drill through the chain a fair bit to find the root of the issue. We see that a map function on BitIter<J::Mask> is providing an index but no generation, and that's really all we need to know. It's iterating over a bitmask again with no generation information. We see that the BitProducer itself that contains the BitIter is stored inside a JoinProducer, which is created using the BitProducer as a component, which means that the BitProducer is what needs to provide generations. Well, the BitProducer is first created in JoinParIter::drive_unindexed which once again produces the BitProducer using only an implementor of Join, which brings us back to the exact same issue as the second compiler error. This makes me sad and it makes the compiler sad too and it also probably makes @Imberflur sad.

These issues are so complex and involved that it's entirely possible that the architecture of Specs completely prohibits this feature from being implemented effectively unless every Join stored generation information. And no, we can't just not change Joins to work with Entitys because the Join is how you access FlaggedStorages and that's where the FlaggedStorage gets information for constructing ComponentEvents.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant