Compare commits

..

1 Commits

Author SHA1 Message Date
Lixou c18659139c
Merge 20f37715e4 into d5f14bc037 2024-09-06 13:47:11 +01:00
3 changed files with 61 additions and 77 deletions

View File

@ -2,24 +2,37 @@ use std::{alloc::Layout, cell::Cell, num::NonZeroU32};
use bevy::{ use bevy::{
core::Name, core::Name,
ecs::system::SystemParam, ecs::world::DeferredWorld,
gltf::GltfExtras, gltf::GltfExtras,
log::{info, warn}, log::{info, warn},
prelude::{HierarchyQueryExt, Parent, Query, With}, prelude::{HierarchyQueryExt, Parent, QueryState, With, World},
reflect::ReflectDeserialize, reflect::ReflectDeserialize,
scene::{InstanceId, SceneInstance}, scene::{InstanceId, SceneInstance},
}; };
use serde::Deserialize; use serde::Deserialize;
#[derive(SystemParam)] pub(crate) struct BadWorldAccess {
pub(crate) struct BadWorldAccess<'w, 's> { world: *mut World,
pub(crate) names: Query<'w, 's, (bevy::ecs::entity::Entity, &'static Name), With<GltfExtras>>, names: QueryState<(bevy::ecs::entity::Entity, &'static Name), With<GltfExtras>>,
pub(crate) hierarchy: Query<'w, 's, &'static Parent, ()>, hierarchy: QueryState<&'static Parent, ()>,
pub(crate) scene_instances: Query<'w, 's, &'static SceneInstance, ()>, scene_instances: QueryState<&'static SceneInstance, ()>,
}
impl BadWorldAccess {
pub unsafe fn new(world: &mut World) -> Self {
BadWorldAccess {
world,
// We have to check that we focus on a node, not a mesh with the same name.
// Currently, the only possible way of checking this is with `GltfExtras`, so selected entities must at least have one component.
names: world.query_filtered::<(bevy::ecs::entity::Entity, &Name), With<GltfExtras>>(),
hierarchy: world.query::<&Parent>(),
scene_instances: world.query::<&SceneInstance>(),
}
}
} }
thread_local! { thread_local! {
pub(crate) static BAD_WORLD_ACCESS: Cell<Option<BadWorldAccess<'static, 'static>>> = Cell::new(None); pub(crate) static BAD_WORLD_ACCESS: Cell<Option<BadWorldAccess>> = Cell::new(None);
pub(crate) static INSTANCE_ID: Cell<Option<InstanceId>> = Cell::new(None); pub(crate) static INSTANCE_ID: Cell<Option<InstanceId>> = Cell::new(None);
} }
@ -57,20 +70,25 @@ impl<'de> Deserialize<'de> for Entity {
let entity = if let Some(name) = entity_data.name { let entity = if let Some(name) = entity_data.name {
info!("Found name {name}"); info!("Found name {name}");
let BadWorldAccess { let BadWorldAccess {
names, world,
hierarchy, mut names,
scene_instances, mut hierarchy,
mut scene_instances,
} = BAD_WORLD_ACCESS.take().expect("No bad world access :c"); } = BAD_WORLD_ACCESS.take().expect("No bad world access :c");
let instance = INSTANCE_ID.get().expect("No instance id set :c"); let instance = INSTANCE_ID.get().expect("No instance id set :c");
let mut target = None; let mut target = None;
'search: for (e, n) in names.iter() { let w = unsafe { &*world.cast_const() };
'search: for (e, n) in names.iter(w) {
if !name.eq(n.as_str()) { if !name.eq(n.as_str()) {
continue; continue;
} }
let mut dw = DeferredWorld::from(unsafe { &mut *world });
let hierarchy = dw.query(&mut hierarchy);
for parent in hierarchy.iter_ancestors(e) { for parent in hierarchy.iter_ancestors(e) {
let Ok(id) = scene_instances.get(parent) else { let Ok(id) = scene_instances.get(w, parent) else {
continue; continue;
}; };
if instance.eq(id) { if instance.eq(id) {
@ -81,6 +99,7 @@ impl<'de> Deserialize<'de> for Entity {
} }
BAD_WORLD_ACCESS.set(Some(BadWorldAccess { BAD_WORLD_ACCESS.set(Some(BadWorldAccess {
world,
names, names,
hierarchy, hierarchy,
scene_instances, scene_instances,

View File

@ -6,13 +6,12 @@ use bevy::{
entity::Entity, entity::Entity,
query::{Added, Without}, query::{Added, Without},
reflect::{AppTypeRegistry, ReflectComponent}, reflect::{AppTypeRegistry, ReflectComponent},
system::{SystemParam, SystemState}, world::{DeferredWorld, World},
world::World,
}, },
gltf::{GltfExtras, GltfMaterialExtras, GltfMeshExtras, GltfSceneExtras}, gltf::{GltfExtras, GltfMaterialExtras, GltfMeshExtras, GltfSceneExtras},
hierarchy::Parent, hierarchy::Parent,
log::{debug, warn}, log::{debug, warn},
prelude::{HierarchyQueryExt, Local, Query, Res}, prelude::HierarchyQueryExt,
reflect::{Reflect, TypeRegistration}, reflect::{Reflect, TypeRegistration},
scene::SceneInstance, scene::SceneInstance,
utils::HashMap, utils::HashMap,
@ -62,56 +61,18 @@ fn find_entity_components(
(target_entity, reflect_components) (target_entity, reflect_components)
} }
#[derive(SystemParam)]
#[doc(hidden)]
pub struct ExtrasComponentQueries<'w, 's> {
extras: Query<
'w,
's,
(Entity, Option<&'static Name>, &'static GltfExtras),
(Added<GltfExtras>, Without<GltfProcessed>),
>,
scene_extras: Query<
'w,
's,
(Entity, Option<&'static Name>, &'static GltfSceneExtras),
(Added<GltfSceneExtras>, Without<GltfProcessed>),
>,
mesh_extras: Query<
'w,
's,
(Entity, Option<&'static Name>, &'static GltfMeshExtras),
(Added<GltfMeshExtras>, Without<GltfProcessed>),
>,
material_extras: Query<
'w,
's,
(Entity, Option<&'static Name>, &'static GltfMaterialExtras),
(Added<GltfMaterialExtras>, Without<GltfProcessed>),
>,
// Hierarchy and Scene instances are both here and in BadWorldAccess, but they don't clash because read-only.
bad_world_access: BadWorldAccess<'w, 's>,
hierarchy: Query<'w, 's, &'static Parent>,
scene_instances: Query<'w, 's, &'static SceneInstance>,
type_registry: Res<'w, AppTypeRegistry>,
}
/// main function: injects components into each entity in gltf files that have `gltf_extras`, using reflection /// main function: injects components into each entity in gltf files that have `gltf_extras`, using reflection
pub fn add_components_from_gltf_extras( pub fn add_components_from_gltf_extras(world: &mut World) {
world: &mut World, let mut extras = world.query_filtered::<(Entity, Option<&Name>, &GltfExtras), (Added<GltfExtras>, Without<GltfProcessed>)>();
mut queries_state: Local<Option<SystemState<ExtrasComponentQueries<'_, '_>>>>, let mut scene_extras = world.query_filtered::<(Entity, Option<&Name>, &GltfSceneExtras), (Added<GltfSceneExtras>, Without<GltfProcessed>)>();
) { let mut mesh_extras = world.query_filtered::<(Entity, Option<&Name>, &GltfMeshExtras), (Added<GltfMeshExtras>, Without<GltfProcessed>)>();
let state = queries_state.get_or_insert_with(|| SystemState::new(world)); let mut material_extras = world.query_filtered::<(Entity, Option<&Name>, &GltfMaterialExtras), (Added<GltfMaterialExtras>, Without<GltfProcessed>)>();
let ExtrasComponentQueries {
extras, let mut scene_instances = world.query::<&SceneInstance>();
scene_extras,
mesh_extras, let mut hierarchy_state = world.query::<&Parent>();
material_extras, let mut __unsafe_dw = DeferredWorld::from(unsafe { &mut *(world as *mut _) });
bad_world_access, let hierarchy = __unsafe_dw.query(&mut hierarchy_state);
hierarchy,
scene_instances,
type_registry,
} = state.get_mut(world);
let mut entity_components: HashMap<Entity, Vec<(Box<dyn Reflect>, TypeRegistration)>> = let mut entity_components: HashMap<Entity, Vec<(Box<dyn Reflect>, TypeRegistration)>> =
HashMap::new(); HashMap::new();
@ -119,11 +80,11 @@ pub fn add_components_from_gltf_extras(
// let gltf_components_config = world.resource::<GltfComponentsConfig>(); // let gltf_components_config = world.resource::<GltfComponentsConfig>();
unsafe { unsafe {
// SAFETY: we set this to `None` again before using world again and fake_entity just uses it in that time. // SAFETY: we don't do anything harmful until taking this, and have full world access
fake_entity::BAD_WORLD_ACCESS.set(Some(core::mem::transmute(bad_world_access))); fake_entity::BAD_WORLD_ACCESS.set(Some(BadWorldAccess::new(world)));
} }
for (entity, name, extra) in extras.iter() { for (entity, name, extra) in extras.iter(world) {
let parent = hierarchy.get(entity).ok(); let parent = hierarchy.get(entity).ok();
debug!( debug!(
"Gltf Extra: Name: {:?}, entity {:?}, parent: {:?}, extras {:?}", "Gltf Extra: Name: {:?}, entity {:?}, parent: {:?}, extras {:?}",
@ -132,7 +93,7 @@ pub fn add_components_from_gltf_extras(
if let Some(instance) = hierarchy if let Some(instance) = hierarchy
.iter_ancestors(entity) .iter_ancestors(entity)
.find_map(|p| scene_instances.get(p).ok()) .find_map(|p| scene_instances.get(world, p).ok())
{ {
fake_entity::INSTANCE_ID.set(Some(*instance.deref())); fake_entity::INSTANCE_ID.set(Some(*instance.deref()));
} else { } else {
@ -140,6 +101,7 @@ pub fn add_components_from_gltf_extras(
fake_entity::INSTANCE_ID.set(None); fake_entity::INSTANCE_ID.set(None);
}; };
let type_registry: &AppTypeRegistry = world.resource();
let mut type_registry = type_registry.write(); let mut type_registry = type_registry.write();
let reflect_components = ronstring_to_reflect_component(&extra.value, &mut type_registry); let reflect_components = ronstring_to_reflect_component(&extra.value, &mut type_registry);
// let name = name.unwrap_or(&Name::new("")); // let name = name.unwrap_or(&Name::new(""));
@ -150,7 +112,7 @@ pub fn add_components_from_gltf_extras(
entity_components.insert(target_entity, updated_components); entity_components.insert(target_entity, updated_components);
} }
for (entity, name, extra) in scene_extras.iter() { for (entity, name, extra) in scene_extras.iter(world) {
let parent = hierarchy.get(entity).ok(); let parent = hierarchy.get(entity).ok();
debug!( debug!(
"Gltf Scene Extra: Name: {:?}, entity {:?}, parent: {:?}, scene_extras {:?}", "Gltf Scene Extra: Name: {:?}, entity {:?}, parent: {:?}, scene_extras {:?}",
@ -159,7 +121,7 @@ pub fn add_components_from_gltf_extras(
if let Some(instance) = hierarchy if let Some(instance) = hierarchy
.iter_ancestors(entity) .iter_ancestors(entity)
.find_map(|p| scene_instances.get(p).ok()) .find_map(|p| scene_instances.get(world, p).ok())
{ {
fake_entity::INSTANCE_ID.set(Some(*instance.deref())); fake_entity::INSTANCE_ID.set(Some(*instance.deref()));
} else { } else {
@ -167,6 +129,7 @@ pub fn add_components_from_gltf_extras(
fake_entity::INSTANCE_ID.set(None); fake_entity::INSTANCE_ID.set(None);
}; };
let type_registry: &AppTypeRegistry = world.resource();
let mut type_registry = type_registry.write(); let mut type_registry = type_registry.write();
let reflect_components = ronstring_to_reflect_component(&extra.value, &mut type_registry); let reflect_components = ronstring_to_reflect_component(&extra.value, &mut type_registry);
@ -175,7 +138,7 @@ pub fn add_components_from_gltf_extras(
entity_components.insert(target_entity, updated_components); entity_components.insert(target_entity, updated_components);
} }
for (entity, name, extra) in mesh_extras.iter() { for (entity, name, extra) in mesh_extras.iter(world) {
let parent = hierarchy.get(entity).ok(); let parent = hierarchy.get(entity).ok();
debug!( debug!(
"Gltf Mesh Extra: Name: {:?}, entity {:?}, parent: {:?}, mesh_extras {:?}", "Gltf Mesh Extra: Name: {:?}, entity {:?}, parent: {:?}, mesh_extras {:?}",
@ -184,7 +147,7 @@ pub fn add_components_from_gltf_extras(
if let Some(instance) = hierarchy if let Some(instance) = hierarchy
.iter_ancestors(entity) .iter_ancestors(entity)
.find_map(|p| scene_instances.get(p).ok()) .find_map(|p| scene_instances.get(world, p).ok())
{ {
fake_entity::INSTANCE_ID.set(Some(*instance.deref())); fake_entity::INSTANCE_ID.set(Some(*instance.deref()));
} else { } else {
@ -192,6 +155,7 @@ pub fn add_components_from_gltf_extras(
fake_entity::INSTANCE_ID.set(None); fake_entity::INSTANCE_ID.set(None);
}; };
let type_registry: &AppTypeRegistry = world.resource();
let mut type_registry = type_registry.write(); let mut type_registry = type_registry.write();
let reflect_components = ronstring_to_reflect_component(&extra.value, &mut type_registry); let reflect_components = ronstring_to_reflect_component(&extra.value, &mut type_registry);
@ -200,7 +164,7 @@ pub fn add_components_from_gltf_extras(
entity_components.insert(target_entity, updated_components); entity_components.insert(target_entity, updated_components);
} }
for (entity, name, extra) in material_extras.iter() { for (entity, name, extra) in material_extras.iter(world) {
let parent = hierarchy.get(entity).ok(); let parent = hierarchy.get(entity).ok();
debug!( debug!(
"Name: {:?}, entity {:?}, parent: {:?}, material_extras {:?}", "Name: {:?}, entity {:?}, parent: {:?}, material_extras {:?}",
@ -209,7 +173,7 @@ pub fn add_components_from_gltf_extras(
if let Some(instance) = hierarchy if let Some(instance) = hierarchy
.iter_ancestors(entity) .iter_ancestors(entity)
.find_map(|p| scene_instances.get(p).ok()) .find_map(|p| scene_instances.get(world, p).ok())
{ {
fake_entity::INSTANCE_ID.set(Some(*instance.deref())); fake_entity::INSTANCE_ID.set(Some(*instance.deref()));
} else { } else {
@ -217,6 +181,7 @@ pub fn add_components_from_gltf_extras(
fake_entity::INSTANCE_ID.set(None); fake_entity::INSTANCE_ID.set(None);
}; };
let type_registry: &AppTypeRegistry = world.resource();
let mut type_registry = type_registry.write(); let mut type_registry = type_registry.write();
let reflect_components = ronstring_to_reflect_component(&extra.value, &mut type_registry); let reflect_components = ronstring_to_reflect_component(&extra.value, &mut type_registry);

View File

@ -1,7 +1,7 @@
use std::any::TypeId; use std::any::TypeId;
use bevy::log::{debug, warn}; use bevy::log::{debug, info, warn};
use bevy::reflect::serde::ReflectDeserializer; use bevy::reflect::serde::{ReflectDeserializer, ReflectSerializer};
use bevy::reflect::{GetTypeRegistration, Reflect, TypeRegistration, TypeRegistry}; use bevy::reflect::{GetTypeRegistration, Reflect, TypeRegistration, TypeRegistry};
use bevy::utils::HashMap; use bevy::utils::HashMap;
use ron::Value; use ron::Value;