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

SystemBuilder and structural associated changes. #11

Merged
merged 93 commits into from
Nov 7, 2019
Merged

SystemBuilder and structural associated changes. #11

merged 93 commits into from
Nov 7, 2019

Conversation

jaynus
Copy link
Contributor

@jaynus jaynus commented Sep 22, 2019

See inline comments for actual changes. This adds a SystemBuilder allowing usage such as:

#[cfg(test)]
mod tests {
    use super::*;
    use crate::prelude::*;
    use crate::resources::{ResourceAccessType, Resources};

    #[derive(Clone, Copy, Debug, PartialEq)]
    struct Pos(f32, f32, f32);
    #[derive(Clone, Copy, Debug, PartialEq)]
    struct Vel(f32, f32, f32);
    #[derive(Default)]
    struct TestResource(pub i32);

    #[test]
    fn builder_crate_and_execute() {
        let universe = Universe::new();
        let mut world = universe.create_world();
        let mut resources = Resources::default();

        let system = SystemBuilder::<()>::new("TestSystem")
            .with_resource::<TestResource>(ResourceAccessType::Read)
            .with_query(Read::<Pos>::query())
            .with_query(Read::<Vel>::query())
            .build(|resource, queries| {
                println!("Hello world");
                let _ = queries.fetch(); // Fetch the prepared queries. This could be implemented as a Deref on the PreparedQueries struct
            });

        system.run(&resources, &world);
    }
}

@jaynus jaynus changed the base branch from master to systems September 22, 2019 21:41
Copy link
Collaborator

@TomGillen TomGillen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than some things are obviously not implemented yet, this looks to be to be going in the right direction.

I think to be considered feature complete for the next release, we will need:

  • Resource implementation finished
  • Command buffers
  • Archetype query caching
  • Overall system executor
    • System stage declarations
    • Explicit inter-system ordering dependencies
    • Batching and topographical sorting based on above into stage executors
  • Maybe: some handling of one-shot systems that can be scheduled without requiring a rebuild of the stage executors

This PR does not need to do all of these. How far are you planning on taking this PR before you think it is ready for merging?

$(
let storage = world.storage();
$ty.filter.iter_archetype_indexes(storage).for_each(|id| { bitset.insert(id); });
)*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ultimately, I want the results of archetype filtering to be cached, and then re-used inside the prepared query so that we do not need to execute it a second time. I am not sure yet whether we can modify Query to support this, or if it will require a parallel implementation of query and its iterators (which is obviously undesirable). This does not need to be implemented for this PR, though.

Also, it would be ideal if we could resume iter_archetype_indexes from the index of the last archetype that was seen (in the previous frame), such that we only needed to inspect new archetypes each frame.

src/command.rs Outdated
Comment on lines 71 to 83
pub fn insert<T, C>(mut self, tags: T, components: C) -> Self
where
T: 'static + TagSet + TagLayout + for<'a> Filter<ChunksetFilterData<'a>>,
C: 'static + IntoComponentSource,
{
self.commands
.push(EntityCommand::WriteWorld(Arc::new(InsertCommand {
tags,
components,
})));

self
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, we would pre-allocate entity IDs and return them as &[Entity] in this call. This would require that the command buffer were constructed with a &World reference (so it can fetch entiy ID blocks from the world), which would make it difficult for the system to construct the buffer itself.

I also don't want to be allocating on the heap for each call, but rather use some kind of block allocator internally and then re-use that memory in later frames. This does not have to be implemented for the initial release, but it would again make it difficult for the system to construct the buffer itself.

@TomGillen
Copy link
Collaborator

TomGillen commented Oct 4, 2019

With respect to events, what you have here is in line with some of what I want legion to ultimately support, but does not go all the way, and that may impact some of the API design for what you are doing now.

The major use case that I can imagine for events are to allow for systems that are storing state related to entities outside of the ECS (e.g. transform hierarchy cached in a hash map, etc). These systems will want to know when an entity that they are interested in has been created or deleted.

The problem with global added/deleted events is that the entity IDs alone aren't enough to determine if the entity is/was of interest to the system. What it really needs is information about the component composition of the entity, too. This is further complicated by entity mutations, which could move an entity in/out of interest without creating or destroying it.

Entity deletion events can safely be used by a system to clean up it's state, although every system with such state will have to listen to all such events and determine for themselves if said entity is one they are managing.

Entity mutation (component/tag add/remove) events are very difficult to work with. It is not going to be very clear when a given change will cause an entity to no longer be of interest (especially if the system is using complex queries with component | component conditions) and be of no use in determining if the entity has become of interest.

Entity added events are almost useless, outside of some logging or metrics events.

What I would like to do is support an eventing API that allows the user to register to recieve entity events for all entities that match an EntityFilter. Such event channels would attach themselves to all chunks that match the query, and would fire added/removed events when an entity is moved into or out of said chunk.

@jaynus
Copy link
Contributor Author

jaynus commented Oct 24, 2019

As mentioned on discord, I think we should get this merged in now as a good baseline. There are numerous bugfixes and patches throughout the codebase now, fixing various issues such as incorrect comparisons, inefficient parallel iterators, etc.

Overall, the core codebase still operates as it does in master - bug these bug fixes would be nice for general use.

The System scheduler, command buffers and execution are also at a good "initial" point. They work flawlessly now, and provide at least basic scheduling and resource access. There is also an out-of-band use of the StageExecutor, which allows parralel stages as discussed here without explicit stages. This is done by inferred insertion ordering, and can be seen in amethyst.

I believe the only expansions needed on this at this point are some more granular scheduling, and some optimizations can be done around allocations with a bump allocator.

But again, as I said, I believe this code is ready to at least expand and fixup master at this point, and its getting pretty big to hold off on.

@Ralith
Copy link
Contributor

Ralith commented Nov 3, 2019

This breaks the build with --no-default-features. Missing CI?

@TomGillen TomGillen mentioned this pull request Nov 4, 2019
@TomGillen
Copy link
Collaborator

Is this still ready to merge? I agree that this contains a lot of good work that at this point I would rather get merged and fix any issues that arise later, than delay it any further to let the PR grow even more.

@jaynus
Copy link
Contributor Author

jaynus commented Nov 4, 2019

This is ready to merge now as is. There may be some pending bugs in the CommandBuffer, but everything else is good enough (tm)

@TomGillen TomGillen merged commit 4986f47 into amethyst:systems Nov 7, 2019
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.

None yet

7 participants