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

archetype access not updated on all systems (Result::unwrap() on an Err value: CannotReadArchetype) #259

Closed
robinvd opened this issue Aug 20, 2020 · 2 comments · Fixed by #383
Labels
A-ECS Entities, components, systems, and events C-Bug An unexpected or incorrect behavior P-Crash A sudden unexpected crash

Comments

@robinvd
Copy link

robinvd commented Aug 20, 2020

In the example i try to access a component by entity, but it fails as the archetype_access for the system is not updated after the spawning of the entity with (A,C)

use bevy::prelude::*;

fn main() {
    App::build()
        .add_default_plugins()
        .add_startup_system(startup_system.system())
        .add_system(normal_system.system())
        .run();
}

fn startup_system(mut commands: Commands) {
    commands.spawn((B(None),));
}

#[derive(Debug)]
struct A;
struct B(Option<Entity>);
struct C;

fn normal_system(mut commands: Commands, a: Query<&mut A>, mut b: Query<&mut B>) {
    for mut b in &mut b.iter() {
        match b.0 {
            Some(entity) => {
                dbg!(a.get::<A>(entity)).unwrap();
            }
            None => {
                let new = commands.spawn((A, C)).current_entity().unwrap();
                b.0 = Some(new);
            }
        }
    }
}

output

thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: CannotReadArchetype', examples/ecs/startup_system.rs:27:42

Something like this fixes it, but im not sure if this is the right solution. (should probably be fixed in parralel_executor). It you could give me some pointers i would love to make a PR.

diff --git a/crates/bevy_ecs/src/system/into_system.rs b/crates/bevy_ecs/src/system/into_system.rs
index 96a4cff4..8cc1e001 100644
--- a/crates/bevy_ecs/src/system/into_system.rs
+++ b/crates/bevy_ecs/src/system/into_system.rs
@@ -4,7 +4,7 @@ use crate::{
     resource::{FetchResource, ResourceQuery, Resources, UnsafeClone},
     system::{ArchetypeAccess, Commands, System, SystemId, ThreadLocalExecution},
 };
-use bevy_hecs::{Fetch, Query as HecsQuery, World};
+use bevy_hecs::{ArchetypesGeneration, Fetch, Query as HecsQuery, World};
 use std::borrow::Cow;
 
 pub(crate) struct SystemFn<State, F, ThreadLocalF, Init, SetArchetypeAccess>
@@ -25,6 +25,7 @@ where
     pub id: SystemId,
     pub archetype_access: ArchetypeAccess,
     pub set_archetype_access: SetArchetypeAccess,
+    last_archetypes_generation: ArchetypesGeneration,
 }
 
 impl<State, F, ThreadLocalF, Init, SetArchetypeAccess> System
@@ -58,6 +63,10 @@ where
 
     #[inline]
     fn run(&mut self, world: &World, resources: &Resources) {
+        if self.last_archetypes_generation != world.archetypes_generation() {
+            self.update_archetype_access(world);
+            self.last_archetypes_generation = world.archetypes_generation();
+        }
         (self.func)(world, resources, &self.archetype_access, &mut self.state);
     }
 
@@ -120,6 +129,7 @@ macro_rules! impl_into_foreach_system {
                         <($($resource,)*)>::initialize(resources, Some(id));
                     },
                     resource_access: <<($($resource,)*) as ResourceQuery>::Fetch as FetchResource>::access(),
+                    last_archetypes_generation: ArchetypesGeneration(u64::MAX),
                     archetype_access: ArchetypeAccess::default(),
                     set_archetype_access: |world, archetype_access, _state| {
                         archetype_access.clear();
@@ -195,6 +205,7 @@ macro_rules! impl_into_query_system {
                     },
                     resource_access: <<($($resource,)*) as ResourceQuery>::Fetch as FetchResource>::access(),
                     archetype_access: ArchetypeAccess::default(),
+                    last_archetypes_generation: ArchetypesGeneration(u64::MAX),
                     set_archetype_access: |world, archetype_access, state| {
                         archetype_access.clear();
                         let mut i = 0;
@@ -321,6 +332,7 @@ where
             name: core::any::type_name::<F>().into(),
             id: SystemId::new(),
             resource_access: TypeAccess::default(),
+            last_archetypes_generation: ArchetypesGeneration(u64::MAX),
             archetype_access: ArchetypeAccess::default(),
         })
     }
@karroffel karroffel added C-Bug An unexpected or incorrect behavior P-Crash A sudden unexpected crash A-ECS Entities, components, systems, and events labels Aug 20, 2020
@mockersf
Copy link
Member

interestingly, if you add an entity with the same group of components in a startup system, it works

fn startup_system(mut commands: Commands) {
    commands.spawn((B(None),))
        .spawn((A, C));
}

@robinvd
Copy link
Author

robinvd commented Aug 28, 2020

@mockersf yea that makes a lot of sense. in the original code the archtype (A, C) does not exist yet, and after creating the new archetype in the system archetype_access is not updated. But if you add the archetype at the start then it will be set correctly the first time. still a good workaround for the crash

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events C-Bug An unexpected or incorrect behavior P-Crash A sudden unexpected crash
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants