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

AsyncSceneInheritOutline to use SceneInstanceReady / be reversible #35

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 103 additions & 13 deletions src/scene.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,95 @@
use bevy::{prelude::*, scene::SceneInstance};
use bevy::{
prelude::*,
scene::{SceneInstance, SceneInstanceReady},
};

use crate::InheritOutlineBundle;
use crate::{compute_outline, InheritOutlineBundle};

/// A component for triggering the `AsyncSceneInheritOutlinePlugin`.
#[derive(Component)]
pub struct AsyncSceneInheritOutline;

fn process_async_scene_outline(
/// A component marking that `AsyncSceneInheritOutlinePlugin` has processed a scene.
#[derive(Component)]
pub struct AsyncSceneInheritOutlineProcessed;

fn instance_maybe_ready(
mut commands: Commands,
scene_spawner: &SceneSpawner,
entity: Entity,
instance: &SceneInstance,
) {
if scene_spawner.instance_is_ready(**instance) {
for child in scene_spawner.iter_instance_entities(**instance) {
commands
.entity(child)
.insert(InheritOutlineBundle::default());
}
commands
.entity(entity)
.insert(AsyncSceneInheritOutlineProcessed);
}
}

// Handles scenes which are already ready when `AsyncSceneInheritOutline` is added.
#[allow(clippy::type_complexity)]
fn async_added(
mut commands: Commands,
scene_spawner: Res<SceneSpawner>,
async_query: Query<
(Entity, &SceneInstance),
(
Added<AsyncSceneInheritOutline>,
Without<AsyncSceneInheritOutlineProcessed>,
),
>,
) {
for (entity, instance) in async_query.iter() {
instance_maybe_ready(commands.reborrow(), &scene_spawner, entity, instance);
}
}

// Handles scenes which become ready after `AsyncSceneInheritOutline` is added.
#[allow(clippy::type_complexity)]
fn async_ready_event(
mut commands: Commands,
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you need both systems? Isn't SceneInstanceReady emitted every time after an instance spawn?

Copy link
Owner Author

Choose a reason for hiding this comment

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

This supports the use case that you first spawn a scene, the scene becomes ready, and then only later add the outlining components to it.

Personally, I always add the outline components at spawning time and never remove them, but I can't say that an approach where you add and remove the components is wrong. I don't know how efficient the Added query filter is though, so perhaps this is no better than not using the event.

Copy link
Contributor

@Shatur Shatur Mar 14, 2024

Choose a reason for hiding this comment

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

Makes sense.

Regardless complexity see this.

mut ready_events: EventReader<SceneInstanceReady>,
scene_spawner: Res<SceneSpawner>,
async_query: Query<
&SceneInstance,
(
With<AsyncSceneInheritOutline>,
Without<AsyncSceneInheritOutlineProcessed>,
),
>,
) {
for event in ready_events.read() {
if let Ok(instance) = async_query.get(event.parent) {
instance_maybe_ready(commands.reborrow(), &scene_spawner, event.parent, instance);
}
}
}

// Handles cleaning when `AsyncSceneInheritOutline` is removed.
#[allow(clippy::type_complexity)]
fn async_removed(
mut commands: Commands,
scene_spawner: Res<SceneSpawner>,
async_query: Query<(Entity, &SceneInstance), With<AsyncSceneInheritOutline>>,
async_query: Query<
(Entity, &SceneInstance),
(
Without<AsyncSceneInheritOutline>,
With<AsyncSceneInheritOutlineProcessed>,
),
>,
) {
for (entity, instance) in async_query.iter() {
if scene_spawner.instance_is_ready(**instance) {
for child in scene_spawner.iter_instance_entities(**instance) {
commands
.entity(child)
.insert(InheritOutlineBundle::default());
}
commands.entity(entity).remove::<AsyncSceneInheritOutline>();
for child in scene_spawner.iter_instance_entities(**instance) {
commands.entity(child).remove::<InheritOutlineBundle>();
}
commands
.entity(entity)
.remove::<AsyncSceneInheritOutlineProcessed>();
}
}

Expand All @@ -32,8 +102,28 @@ pub struct AsyncSceneInheritOutlinePlugin;
impl Plugin for AsyncSceneInheritOutlinePlugin {
fn build(&self, app: &mut App) {
app.add_systems(
Update,
process_async_scene_outline.run_if(any_with_component::<AsyncSceneInheritOutline>),
PostUpdate,
(
(async_added, async_ready_event).run_if(
|query: Query<
(),
(
With<AsyncSceneInheritOutline>,
Without<AsyncSceneInheritOutlineProcessed>,
),
>| !query.is_empty(),
),
async_removed.run_if(
|query: Query<
(),
(
Without<AsyncSceneInheritOutline>,
With<AsyncSceneInheritOutlineProcessed>,
),
>| !query.is_empty(),
),
)
.before(compute_outline),
);
}
}
Loading