1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use crate::{TaskContext, WithWorld};
use bevy_ecs::{
bundle::{Bundle, BundleFromComponents},
entity::Entity,
world::{error::EntityMutableFetchError, EntityWorldMut},
};
#[derive(Clone)]
pub struct AsyncEntity {
pub entity: Entity,
pub task_context: TaskContext,
}
impl AsyncEntity {
/// Adds a [`Bundle`] of components to the entity.
///
/// This will overwrite any previous value(s) of the same component type.
pub fn insert(&self, bundle: impl Bundle) -> WithWorld<()> {
let e = self.entity;
self.task_context.with_world(move |world| {
world.entity_mut(e).insert(bundle);
})
}
/// Despawns the given `entity`, if it exists. This will also remove all of the entity's
/// [`Component`]s. Returns `true` if the `entity` is successfully despawned and `false` if
/// the `entity` does not exist.
pub fn despawn(&self) -> WithWorld<bool> {
let e = self.entity;
self.task_context.with_world(move |world| world.despawn(e))
}
/// Removes a [`Bundle`] of components from the entity.
pub fn remove<T: Bundle>(&self) -> WithWorld<()> {
let e = self.entity;
self.task_context.with_world(move |world| {
world.entity_mut(e).remove::<T>();
})
}
/// Removes all components associated with the entity.
pub fn clear(&self) -> WithWorld<()> {
let e = self.entity;
self.task_context.with_world(move |world| {
world.entity_mut(e).clear();
})
}
/// Removes all components in the [`Bundle`] from the entity and returns their previous values.
///
/// **Note:** If the entity does not have every component in the bundle, this method will not
/// remove any of them.
pub fn take<T: Bundle + BundleFromComponents>(&self) -> WithWorld<Option<T>> {
let e = self.entity;
self.task_context
.with_world(move |world| world.entity_mut(e).take::<T>())
}
}
pub trait AsyncEntityTaskExt {
/// Returns an [`AsyncEntity`], which is a thin wrapper over [`TaskContext`] that allows async
/// operations on an entity:
///
/// ```
/// # use bevy::prelude::*;
/// # use bevy_mod_async::prelude::*;
/// # use std::time::Duration;
/// # #[derive(Component)]
/// # struct Player;
/// # #[derive(Component)]
/// # struct Dead;
/// # App::new()
/// # .add_plugins((MinimalPlugins, AssetPlugin::default(), AsyncTasksPlugin))
/// # .add_systems(Startup, |world: &mut World| {
/// # world.spawn_task(|cx| async move {
/// let entity = cx.spawn(Player).await;
/// cx.entity(entity).insert(Dead).await;
/// cx.sleep(Duration::from_secs(1)).await;
/// cx.entity(entity).despawn().await;
/// # cx.write_message(AppExit::Success).await;
/// # });
/// # }).run();
/// ```
///
/// Note that, since all methodss on [`AsyncEntity`] return a [`WithWorld`], there will be a
/// one-frame delay between tasks that are `.awwait`ed (rather than `.detach()`ed).
fn entity(&self, entity: Entity) -> AsyncEntity;
/// Execute a task with exclusive, mutable access so the given entity. This is a thin wrapper
/// around [`TaskContext::with_world`] that provides an [`EntityWorldMut`] for the given entity.
///
/// ```
/// # use bevy::prelude::*;
/// # use bevy_mod_async::prelude::*;
/// # #[derive(Component)]
/// # struct Player;
/// # #[derive(Component)]
/// # struct Controls;
/// # #[derive(Component)]
/// # struct Dead;
/// # App::new()
/// # .add_plugins((MinimalPlugins, AssetPlugin::default(), AsyncTasksPlugin))
/// # .add_systems(Startup, |world: &mut World| {
/// # world.spawn_task(|cx| async move {
/// let entity = cx.spawn((Player, Controls)).await;
/// cx.with_entity(entity, |mut player| {
/// player.insert(Dead).remove::<Controls>();
/// }).await;
/// # });
/// # world.write_message(AppExit::Success);
/// # })
/// # .run();
/// ```
fn with_entity<R, F>(
&self,
entity: Entity,
f: F,
) -> WithWorld<Result<R, EntityMutableFetchError>>
where
R: Send + 'static,
F: FnOnce(EntityWorldMut) -> R + Send + 'static;
}
impl AsyncEntityTaskExt for TaskContext {
fn entity(&self, entity: Entity) -> AsyncEntity {
AsyncEntity {
entity,
task_context: self.clone(),
}
}
fn with_entity<R, F>(
&self,
entity: Entity,
f: F,
) -> WithWorld<Result<R, EntityMutableFetchError>>
where
R: Send + 'static,
F: FnOnce(EntityWorldMut) -> R + Send + 'static,
{
self.with_world(move |world| Ok(f(world.get_entity_mut(entity)?)))
}
}