1use crate::prelude::Mut;
2use crate::reflect::AppTypeRegistry;
3use crate::system::{EntityCommands, Resource};
4use crate::world::Command;
5use crate::{entity::Entity, reflect::ReflectComponent, world::World};
6use bevy_reflect::{Reflect, TypeRegistry};
7use std::borrow::Cow;
8use std::marker::PhantomData;
9
10pub trait ReflectCommandExt {
12 fn insert_reflect(&mut self, component: Box<dyn Reflect>) -> &mut Self;
73
74 fn insert_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
85 &mut self,
86 component: Box<dyn Reflect>,
87 ) -> &mut Self;
88
89 fn remove_reflect(&mut self, component_type_name: impl Into<Cow<'static, str>>) -> &mut Self;
136 fn remove_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
139 &mut self,
140 component_type_name: impl Into<Cow<'static, str>>,
141 ) -> &mut Self;
142}
143
144impl ReflectCommandExt for EntityCommands<'_> {
145 fn insert_reflect(&mut self, component: Box<dyn Reflect>) -> &mut Self {
146 self.commands.add(InsertReflect {
147 entity: self.entity,
148 component,
149 });
150 self
151 }
152
153 fn insert_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
154 &mut self,
155 component: Box<dyn Reflect>,
156 ) -> &mut Self {
157 self.commands.add(InsertReflectWithRegistry::<T> {
158 entity: self.entity,
159 _t: PhantomData,
160 component,
161 });
162 self
163 }
164
165 fn remove_reflect(&mut self, component_type_path: impl Into<Cow<'static, str>>) -> &mut Self {
166 self.commands.add(RemoveReflect {
167 entity: self.entity,
168 component_type_path: component_type_path.into(),
169 });
170 self
171 }
172
173 fn remove_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
174 &mut self,
175 component_type_name: impl Into<Cow<'static, str>>,
176 ) -> &mut Self {
177 self.commands.add(RemoveReflectWithRegistry::<T> {
178 entity: self.entity,
179 _t: PhantomData,
180 component_type_name: component_type_name.into(),
181 });
182 self
183 }
184}
185
186fn insert_reflect(
188 world: &mut World,
189 entity: Entity,
190 type_registry: &TypeRegistry,
191 component: Box<dyn Reflect>,
192) {
193 let type_info = component
194 .get_represented_type_info()
195 .expect("component should represent a type.");
196 let type_path = type_info.type_path();
197 let Some(mut entity) = world.get_entity_mut(entity) else {
198 panic!("error[B0003]: Could not insert a reflected component (of type {type_path}) for entity {entity:?} because it doesn't exist in this World. See: https://bevyengine.org/learn/errors/#b0003");
199 };
200 let Some(type_registration) = type_registry.get_with_type_path(type_path) else {
201 panic!("Could not get type registration (for component type {type_path}) because it doesn't exist in the TypeRegistry.");
202 };
203 let Some(reflect_component) = type_registration.data::<ReflectComponent>() else {
204 panic!("Could not get ReflectComponent data (for component type {type_path}) because it doesn't exist in this TypeRegistration.");
205 };
206 reflect_component.insert(&mut entity, &*component, type_registry);
207}
208
209pub struct InsertReflect {
214 pub entity: Entity,
216 pub component: Box<dyn Reflect>,
218}
219
220impl Command for InsertReflect {
221 fn apply(self, world: &mut World) {
222 let registry = world.get_resource::<AppTypeRegistry>().unwrap().clone();
223 insert_reflect(world, self.entity, ®istry.read(), self.component);
224 }
225}
226
227pub struct InsertReflectWithRegistry<T: Resource + AsRef<TypeRegistry>> {
232 pub entity: Entity,
234 pub _t: PhantomData<T>,
235 pub component: Box<dyn Reflect>,
237}
238
239impl<T: Resource + AsRef<TypeRegistry>> Command for InsertReflectWithRegistry<T> {
240 fn apply(self, world: &mut World) {
241 world.resource_scope(|world, registry: Mut<T>| {
242 let registry: &TypeRegistry = registry.as_ref().as_ref();
243 insert_reflect(world, self.entity, registry, self.component);
244 });
245 }
246}
247
248fn remove_reflect(
250 world: &mut World,
251 entity: Entity,
252 type_registry: &TypeRegistry,
253 component_type_path: Cow<'static, str>,
254) {
255 let Some(mut entity) = world.get_entity_mut(entity) else {
256 return;
257 };
258 let Some(type_registration) = type_registry.get_with_type_path(&component_type_path) else {
259 return;
260 };
261 let Some(reflect_component) = type_registration.data::<ReflectComponent>() else {
262 return;
263 };
264 reflect_component.remove(&mut entity);
265}
266
267pub struct RemoveReflect {
272 pub entity: Entity,
274 pub component_type_path: Cow<'static, str>,
277}
278
279impl Command for RemoveReflect {
280 fn apply(self, world: &mut World) {
281 let registry = world.get_resource::<AppTypeRegistry>().unwrap().clone();
282 remove_reflect(
283 world,
284 self.entity,
285 ®istry.read(),
286 self.component_type_path,
287 );
288 }
289}
290
291pub struct RemoveReflectWithRegistry<T: Resource + AsRef<TypeRegistry>> {
296 pub entity: Entity,
298 pub _t: PhantomData<T>,
299 pub component_type_name: Cow<'static, str>,
302}
303
304impl<T: Resource + AsRef<TypeRegistry>> Command for RemoveReflectWithRegistry<T> {
305 fn apply(self, world: &mut World) {
306 world.resource_scope(|world, registry: Mut<T>| {
307 let registry: &TypeRegistry = registry.as_ref().as_ref();
308 remove_reflect(world, self.entity, registry, self.component_type_name);
309 });
310 }
311}
312
313#[cfg(test)]
314mod tests {
315 use crate::prelude::{AppTypeRegistry, ReflectComponent};
316 use crate::reflect::ReflectCommandExt;
317 use crate::system::{Commands, SystemState};
318 use crate::{self as bevy_ecs, component::Component, world::World};
319 use bevy_ecs_macros::Resource;
320 use bevy_reflect::{Reflect, TypeRegistry};
321
322 #[derive(Resource)]
323 struct TypeRegistryResource {
324 type_registry: TypeRegistry,
325 }
326
327 impl AsRef<TypeRegistry> for TypeRegistryResource {
328 fn as_ref(&self) -> &TypeRegistry {
329 &self.type_registry
330 }
331 }
332
333 #[derive(Component, Reflect, Default, PartialEq, Eq, Debug)]
334 #[reflect(Component)]
335 struct ComponentA(u32);
336
337 #[test]
338 fn insert_reflected() {
339 let mut world = World::new();
340
341 let type_registry = AppTypeRegistry::default();
342 {
343 let mut registry = type_registry.write();
344 registry.register::<ComponentA>();
345 registry.register_type_data::<ComponentA, ReflectComponent>();
346 }
347 world.insert_resource(type_registry);
348
349 let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
350 let mut commands = system_state.get_mut(&mut world);
351
352 let entity = commands.spawn_empty().id();
353 let entity2 = commands.spawn_empty().id();
354
355 let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn Reflect>;
356 let boxed_reflect_component_a_clone = boxed_reflect_component_a.clone_value();
357
358 commands
359 .entity(entity)
360 .insert_reflect(boxed_reflect_component_a);
361 commands
362 .entity(entity2)
363 .insert_reflect(boxed_reflect_component_a_clone);
364 system_state.apply(&mut world);
365
366 assert_eq!(
367 world.entity(entity).get::<ComponentA>(),
368 world.entity(entity2).get::<ComponentA>()
369 );
370 }
371
372 #[test]
373 fn insert_reflected_with_registry() {
374 let mut world = World::new();
375
376 let mut type_registry = TypeRegistryResource {
377 type_registry: TypeRegistry::new(),
378 };
379
380 type_registry.type_registry.register::<ComponentA>();
381 type_registry
382 .type_registry
383 .register_type_data::<ComponentA, ReflectComponent>();
384 world.insert_resource(type_registry);
385
386 let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
387 let mut commands = system_state.get_mut(&mut world);
388
389 let entity = commands.spawn_empty().id();
390
391 let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn Reflect>;
392
393 commands
394 .entity(entity)
395 .insert_reflect_with_registry::<TypeRegistryResource>(boxed_reflect_component_a);
396 system_state.apply(&mut world);
397
398 assert_eq!(
399 world.entity(entity).get::<ComponentA>(),
400 Some(&ComponentA(916))
401 );
402 }
403
404 #[test]
405 fn remove_reflected() {
406 let mut world = World::new();
407
408 let type_registry = AppTypeRegistry::default();
409 {
410 let mut registry = type_registry.write();
411 registry.register::<ComponentA>();
412 registry.register_type_data::<ComponentA, ReflectComponent>();
413 }
414 world.insert_resource(type_registry);
415
416 let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
417 let mut commands = system_state.get_mut(&mut world);
418
419 let entity = commands.spawn(ComponentA(0)).id();
420
421 let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn Reflect>;
422
423 commands
424 .entity(entity)
425 .remove_reflect(boxed_reflect_component_a.reflect_type_path().to_owned());
426 system_state.apply(&mut world);
427
428 assert_eq!(world.entity(entity).get::<ComponentA>(), None);
429 }
430
431 #[test]
432 fn remove_reflected_with_registry() {
433 let mut world = World::new();
434
435 let mut type_registry = TypeRegistryResource {
436 type_registry: TypeRegistry::new(),
437 };
438
439 type_registry.type_registry.register::<ComponentA>();
440 type_registry
441 .type_registry
442 .register_type_data::<ComponentA, ReflectComponent>();
443 world.insert_resource(type_registry);
444
445 let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
446 let mut commands = system_state.get_mut(&mut world);
447
448 let entity = commands.spawn(ComponentA(0)).id();
449
450 let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn Reflect>;
451
452 commands
453 .entity(entity)
454 .remove_reflect_with_registry::<TypeRegistryResource>(
455 boxed_reflect_component_a.reflect_type_path().to_owned(),
456 );
457 system_state.apply(&mut world);
458
459 assert_eq!(world.entity(entity).get::<ComponentA>(), None);
460 }
461}