1use crate::{
2 entity::Entity,
3 prelude::Mut,
4 reflect::{AppTypeRegistry, ReflectBundle, ReflectComponent},
5 system::{EntityCommands, Resource},
6 world::{Command, World},
7};
8use alloc::borrow::Cow;
9use bevy_reflect::{PartialReflect, TypeRegistry};
10use core::marker::PhantomData;
11
12pub trait ReflectCommandExt {
14 fn insert_reflect(&mut self, component: Box<dyn PartialReflect>) -> &mut Self;
89
90 fn insert_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
101 &mut self,
102 component: Box<dyn PartialReflect>,
103 ) -> &mut Self;
104
105 fn remove_reflect(&mut self, component_type_name: impl Into<Cow<'static, str>>) -> &mut Self;
163 fn remove_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
166 &mut self,
167 component_type_name: impl Into<Cow<'static, str>>,
168 ) -> &mut Self;
169}
170
171impl ReflectCommandExt for EntityCommands<'_> {
172 fn insert_reflect(&mut self, component: Box<dyn PartialReflect>) -> &mut Self {
173 self.commands.queue(InsertReflect {
174 entity: self.entity,
175 component,
176 });
177 self
178 }
179
180 fn insert_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
181 &mut self,
182 component: Box<dyn PartialReflect>,
183 ) -> &mut Self {
184 self.commands.queue(InsertReflectWithRegistry::<T> {
185 entity: self.entity,
186 _t: PhantomData,
187 component,
188 });
189 self
190 }
191
192 fn remove_reflect(&mut self, component_type_path: impl Into<Cow<'static, str>>) -> &mut Self {
193 self.commands.queue(RemoveReflect {
194 entity: self.entity,
195 component_type_path: component_type_path.into(),
196 });
197 self
198 }
199
200 fn remove_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
201 &mut self,
202 component_type_name: impl Into<Cow<'static, str>>,
203 ) -> &mut Self {
204 self.commands.queue(RemoveReflectWithRegistry::<T> {
205 entity: self.entity,
206 _t: PhantomData,
207 component_type_name: component_type_name.into(),
208 });
209 self
210 }
211}
212
213fn insert_reflect(
215 world: &mut World,
216 entity: Entity,
217 type_registry: &TypeRegistry,
218 component: Box<dyn PartialReflect>,
219) {
220 let type_info = component
221 .get_represented_type_info()
222 .expect("component should represent a type.");
223 let type_path = type_info.type_path();
224 let Ok(mut entity) = world.get_entity_mut(entity) else {
225 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");
226 };
227 let Some(type_registration) = type_registry.get(type_info.type_id()) else {
228 panic!("`{type_path}` should be registered in type registry via `App::register_type<{type_path}>`");
229 };
230
231 if let Some(reflect_component) = type_registration.data::<ReflectComponent>() {
232 reflect_component.insert(&mut entity, component.as_partial_reflect(), type_registry);
233 } else if let Some(reflect_bundle) = type_registration.data::<ReflectBundle>() {
234 reflect_bundle.insert(&mut entity, component.as_partial_reflect(), type_registry);
235 } else {
236 panic!("`{type_path}` should have #[reflect(Component)] or #[reflect(Bundle)]");
237 }
238}
239
240pub struct InsertReflect {
245 pub entity: Entity,
247 pub component: Box<dyn PartialReflect>,
250}
251
252impl Command for InsertReflect {
253 fn apply(self, world: &mut World) {
254 let registry = world.get_resource::<AppTypeRegistry>().unwrap().clone();
255 insert_reflect(world, self.entity, ®istry.read(), self.component);
256 }
257}
258
259pub struct InsertReflectWithRegistry<T: Resource + AsRef<TypeRegistry>> {
264 pub entity: Entity,
266 pub _t: PhantomData<T>,
267 pub component: Box<dyn PartialReflect>,
269}
270
271impl<T: Resource + AsRef<TypeRegistry>> Command for InsertReflectWithRegistry<T> {
272 fn apply(self, world: &mut World) {
273 world.resource_scope(|world, registry: Mut<T>| {
274 let registry: &TypeRegistry = registry.as_ref().as_ref();
275 insert_reflect(world, self.entity, registry, self.component);
276 });
277 }
278}
279
280fn remove_reflect(
282 world: &mut World,
283 entity: Entity,
284 type_registry: &TypeRegistry,
285 component_type_path: Cow<'static, str>,
286) {
287 let Ok(mut entity) = world.get_entity_mut(entity) else {
288 return;
289 };
290 let Some(type_registration) = type_registry.get_with_type_path(&component_type_path) else {
291 return;
292 };
293 if let Some(reflect_component) = type_registration.data::<ReflectComponent>() {
294 reflect_component.remove(&mut entity);
295 } else if let Some(reflect_bundle) = type_registration.data::<ReflectBundle>() {
296 reflect_bundle.remove(&mut entity);
297 }
298}
299
300pub struct RemoveReflect {
305 pub entity: Entity,
307 pub component_type_path: Cow<'static, str>,
311}
312
313impl Command for RemoveReflect {
314 fn apply(self, world: &mut World) {
315 let registry = world.get_resource::<AppTypeRegistry>().unwrap().clone();
316 remove_reflect(
317 world,
318 self.entity,
319 ®istry.read(),
320 self.component_type_path,
321 );
322 }
323}
324
325pub struct RemoveReflectWithRegistry<T: Resource + AsRef<TypeRegistry>> {
330 pub entity: Entity,
332 pub _t: PhantomData<T>,
333 pub component_type_name: Cow<'static, str>,
337}
338
339impl<T: Resource + AsRef<TypeRegistry>> Command for RemoveReflectWithRegistry<T> {
340 fn apply(self, world: &mut World) {
341 world.resource_scope(|world, registry: Mut<T>| {
342 let registry: &TypeRegistry = registry.as_ref().as_ref();
343 remove_reflect(world, self.entity, registry, self.component_type_name);
344 });
345 }
346}
347
348#[cfg(test)]
349mod tests {
350 use crate::{
351 self as bevy_ecs,
352 bundle::Bundle,
353 component::Component,
354 prelude::{AppTypeRegistry, ReflectComponent},
355 reflect::{ReflectBundle, ReflectCommandExt},
356 system::{Commands, SystemState},
357 world::World,
358 };
359 use bevy_ecs_macros::Resource;
360 use bevy_reflect::{PartialReflect, Reflect, TypeRegistry};
361
362 #[derive(Resource)]
363 struct TypeRegistryResource {
364 type_registry: TypeRegistry,
365 }
366
367 impl AsRef<TypeRegistry> for TypeRegistryResource {
368 fn as_ref(&self) -> &TypeRegistry {
369 &self.type_registry
370 }
371 }
372
373 #[derive(Component, Reflect, Default, PartialEq, Eq, Debug)]
374 #[reflect(Component)]
375 struct ComponentA(u32);
376
377 #[derive(Component, Reflect, Default, PartialEq, Eq, Debug)]
378 #[reflect(Component)]
379 struct ComponentB(u32);
380
381 #[derive(Bundle, Reflect, Default, Debug, PartialEq)]
382 #[reflect(Bundle)]
383 struct BundleA {
384 a: ComponentA,
385 b: ComponentB,
386 }
387
388 #[test]
389 fn insert_reflected() {
390 let mut world = World::new();
391
392 let type_registry = AppTypeRegistry::default();
393 {
394 let mut registry = type_registry.write();
395 registry.register::<ComponentA>();
396 registry.register_type_data::<ComponentA, ReflectComponent>();
397 }
398 world.insert_resource(type_registry);
399
400 let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
401 let mut commands = system_state.get_mut(&mut world);
402
403 let entity = commands.spawn_empty().id();
404 let entity2 = commands.spawn_empty().id();
405
406 let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn PartialReflect>;
407 let boxed_reflect_component_a_clone = boxed_reflect_component_a.clone_value();
408
409 commands
410 .entity(entity)
411 .insert_reflect(boxed_reflect_component_a);
412 commands
413 .entity(entity2)
414 .insert_reflect(boxed_reflect_component_a_clone);
415 system_state.apply(&mut world);
416
417 assert_eq!(
418 world.entity(entity).get::<ComponentA>(),
419 world.entity(entity2).get::<ComponentA>()
420 );
421 }
422
423 #[test]
424 fn insert_reflected_with_registry() {
425 let mut world = World::new();
426
427 let mut type_registry = TypeRegistryResource {
428 type_registry: TypeRegistry::new(),
429 };
430
431 type_registry.type_registry.register::<ComponentA>();
432 type_registry
433 .type_registry
434 .register_type_data::<ComponentA, ReflectComponent>();
435 world.insert_resource(type_registry);
436
437 let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
438 let mut commands = system_state.get_mut(&mut world);
439
440 let entity = commands.spawn_empty().id();
441
442 let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn PartialReflect>;
443
444 commands
445 .entity(entity)
446 .insert_reflect_with_registry::<TypeRegistryResource>(boxed_reflect_component_a);
447 system_state.apply(&mut world);
448
449 assert_eq!(
450 world.entity(entity).get::<ComponentA>(),
451 Some(&ComponentA(916))
452 );
453 }
454
455 #[test]
456 fn remove_reflected() {
457 let mut world = World::new();
458
459 let type_registry = AppTypeRegistry::default();
460 {
461 let mut registry = type_registry.write();
462 registry.register::<ComponentA>();
463 registry.register_type_data::<ComponentA, ReflectComponent>();
464 }
465 world.insert_resource(type_registry);
466
467 let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
468 let mut commands = system_state.get_mut(&mut world);
469
470 let entity = commands.spawn(ComponentA(0)).id();
471
472 let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn Reflect>;
473
474 commands
475 .entity(entity)
476 .remove_reflect(boxed_reflect_component_a.reflect_type_path().to_owned());
477 system_state.apply(&mut world);
478
479 assert_eq!(world.entity(entity).get::<ComponentA>(), None);
480 }
481
482 #[test]
483 fn remove_reflected_with_registry() {
484 let mut world = World::new();
485
486 let mut type_registry = TypeRegistryResource {
487 type_registry: TypeRegistry::new(),
488 };
489
490 type_registry.type_registry.register::<ComponentA>();
491 type_registry
492 .type_registry
493 .register_type_data::<ComponentA, ReflectComponent>();
494 world.insert_resource(type_registry);
495
496 let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
497 let mut commands = system_state.get_mut(&mut world);
498
499 let entity = commands.spawn(ComponentA(0)).id();
500
501 let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn Reflect>;
502
503 commands
504 .entity(entity)
505 .remove_reflect_with_registry::<TypeRegistryResource>(
506 boxed_reflect_component_a.reflect_type_path().to_owned(),
507 );
508 system_state.apply(&mut world);
509
510 assert_eq!(world.entity(entity).get::<ComponentA>(), None);
511 }
512
513 #[test]
514 fn insert_reflect_bundle() {
515 let mut world = World::new();
516
517 let type_registry = AppTypeRegistry::default();
518 {
519 let mut registry = type_registry.write();
520 registry.register::<BundleA>();
521 registry.register_type_data::<BundleA, ReflectBundle>();
522 }
523 world.insert_resource(type_registry);
524
525 let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
526 let mut commands = system_state.get_mut(&mut world);
527
528 let entity = commands.spawn_empty().id();
529 let bundle = Box::new(BundleA {
530 a: ComponentA(31),
531 b: ComponentB(20),
532 }) as Box<dyn PartialReflect>;
533 commands.entity(entity).insert_reflect(bundle);
534
535 system_state.apply(&mut world);
536
537 assert_eq!(world.get::<ComponentA>(entity), Some(&ComponentA(31)));
538 assert_eq!(world.get::<ComponentB>(entity), Some(&ComponentB(20)));
539 }
540
541 #[test]
542 fn insert_reflect_bundle_with_registry() {
543 let mut world = World::new();
544
545 let mut type_registry = TypeRegistryResource {
546 type_registry: TypeRegistry::new(),
547 };
548
549 type_registry.type_registry.register::<BundleA>();
550 type_registry
551 .type_registry
552 .register_type_data::<BundleA, ReflectBundle>();
553 world.insert_resource(type_registry);
554
555 let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
556 let mut commands = system_state.get_mut(&mut world);
557
558 let entity = commands.spawn_empty().id();
559 let bundle = Box::new(BundleA {
560 a: ComponentA(31),
561 b: ComponentB(20),
562 }) as Box<dyn PartialReflect>;
563
564 commands
565 .entity(entity)
566 .insert_reflect_with_registry::<TypeRegistryResource>(bundle);
567 system_state.apply(&mut world);
568
569 assert_eq!(world.get::<ComponentA>(entity), Some(&ComponentA(31)));
570 assert_eq!(world.get::<ComponentB>(entity), Some(&ComponentB(20)));
571 }
572
573 #[test]
574 fn remove_reflected_bundle() {
575 let mut world = World::new();
576
577 let type_registry = AppTypeRegistry::default();
578 {
579 let mut registry = type_registry.write();
580 registry.register::<BundleA>();
581 registry.register_type_data::<BundleA, ReflectBundle>();
582 }
583 world.insert_resource(type_registry);
584
585 let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
586 let mut commands = system_state.get_mut(&mut world);
587
588 let entity = commands
589 .spawn(BundleA {
590 a: ComponentA(31),
591 b: ComponentB(20),
592 })
593 .id();
594
595 let boxed_reflect_bundle_a = Box::new(BundleA {
596 a: ComponentA(1),
597 b: ComponentB(23),
598 }) as Box<dyn Reflect>;
599
600 commands
601 .entity(entity)
602 .remove_reflect(boxed_reflect_bundle_a.reflect_type_path().to_owned());
603 system_state.apply(&mut world);
604
605 assert_eq!(world.entity(entity).get::<ComponentA>(), None);
606 assert_eq!(world.entity(entity).get::<ComponentB>(), None);
607 }
608
609 #[test]
610 fn remove_reflected_bundle_with_registry() {
611 let mut world = World::new();
612
613 let mut type_registry = TypeRegistryResource {
614 type_registry: TypeRegistry::new(),
615 };
616
617 type_registry.type_registry.register::<BundleA>();
618 type_registry
619 .type_registry
620 .register_type_data::<BundleA, ReflectBundle>();
621 world.insert_resource(type_registry);
622
623 let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
624 let mut commands = system_state.get_mut(&mut world);
625
626 let entity = commands
627 .spawn(BundleA {
628 a: ComponentA(31),
629 b: ComponentB(20),
630 })
631 .id();
632
633 let boxed_reflect_bundle_a = Box::new(BundleA {
634 a: ComponentA(1),
635 b: ComponentB(23),
636 }) as Box<dyn Reflect>;
637
638 commands
639 .entity(entity)
640 .remove_reflect_with_registry::<TypeRegistryResource>(
641 boxed_reflect_bundle_a.reflect_type_path().to_owned(),
642 );
643 system_state.apply(&mut world);
644
645 assert_eq!(world.entity(entity).get::<ComponentA>(), None);
646 assert_eq!(world.entity(entity).get::<ComponentB>(), None);
647 }
648}