Compare commits
2 Commits
c18659139c
...
844176f297
Author | SHA1 | Date |
---|---|---|
Lixou | 844176f297 | |
DasLixou | e464c49592 |
|
@ -2,37 +2,24 @@ use std::{alloc::Layout, cell::Cell, num::NonZeroU32};
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
core::Name,
|
core::Name,
|
||||||
ecs::world::DeferredWorld,
|
ecs::system::SystemParam,
|
||||||
gltf::GltfExtras,
|
gltf::GltfExtras,
|
||||||
log::{info, warn},
|
log::{info, warn},
|
||||||
prelude::{HierarchyQueryExt, Parent, QueryState, With, World},
|
prelude::{HierarchyQueryExt, Parent, Query, With},
|
||||||
reflect::ReflectDeserialize,
|
reflect::ReflectDeserialize,
|
||||||
scene::{InstanceId, SceneInstance},
|
scene::{InstanceId, SceneInstance},
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
pub(crate) struct BadWorldAccess {
|
#[derive(SystemParam)]
|
||||||
world: *mut World,
|
pub(crate) struct BadWorldAccess<'w, 's> {
|
||||||
names: QueryState<(bevy::ecs::entity::Entity, &'static Name), With<GltfExtras>>,
|
pub(crate) names: Query<'w, 's, (bevy::ecs::entity::Entity, &'static Name), With<GltfExtras>>,
|
||||||
hierarchy: QueryState<&'static Parent, ()>,
|
pub(crate) hierarchy: Query<'w, 's, &'static Parent, ()>,
|
||||||
scene_instances: QueryState<&'static SceneInstance, ()>,
|
pub(crate) scene_instances: Query<'w, 's, &'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>> = Cell::new(None);
|
pub(crate) static BAD_WORLD_ACCESS: Cell<Option<BadWorldAccess<'static, 'static>>> = 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,25 +57,20 @@ 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 {
|
||||||
world,
|
names,
|
||||||
mut names,
|
hierarchy,
|
||||||
mut hierarchy,
|
scene_instances,
|
||||||
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;
|
||||||
let w = unsafe { &*world.cast_const() };
|
'search: for (e, n) in names.iter() {
|
||||||
'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(w, parent) else {
|
let Ok(id) = scene_instances.get(parent) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if instance.eq(id) {
|
if instance.eq(id) {
|
||||||
|
@ -99,7 +81,6 @@ 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,
|
||||||
|
|
|
@ -6,12 +6,13 @@ use bevy::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
query::{Added, Without},
|
query::{Added, Without},
|
||||||
reflect::{AppTypeRegistry, ReflectComponent},
|
reflect::{AppTypeRegistry, ReflectComponent},
|
||||||
world::{DeferredWorld, World},
|
system::{SystemParam, SystemState},
|
||||||
|
world::World,
|
||||||
},
|
},
|
||||||
gltf::{GltfExtras, GltfMaterialExtras, GltfMeshExtras, GltfSceneExtras},
|
gltf::{GltfExtras, GltfMaterialExtras, GltfMeshExtras, GltfSceneExtras},
|
||||||
hierarchy::Parent,
|
hierarchy::Parent,
|
||||||
log::{debug, warn},
|
log::{debug, warn},
|
||||||
prelude::HierarchyQueryExt,
|
prelude::{HierarchyQueryExt, Local, Query, Res},
|
||||||
reflect::{Reflect, TypeRegistration},
|
reflect::{Reflect, TypeRegistration},
|
||||||
scene::SceneInstance,
|
scene::SceneInstance,
|
||||||
utils::HashMap,
|
utils::HashMap,
|
||||||
|
@ -61,18 +62,56 @@ 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(world: &mut World) {
|
pub fn add_components_from_gltf_extras(
|
||||||
let mut extras = world.query_filtered::<(Entity, Option<&Name>, &GltfExtras), (Added<GltfExtras>, Without<GltfProcessed>)>();
|
world: &mut World,
|
||||||
let mut scene_extras = world.query_filtered::<(Entity, Option<&Name>, &GltfSceneExtras), (Added<GltfSceneExtras>, Without<GltfProcessed>)>();
|
mut queries_state: Local<Option<SystemState<ExtrasComponentQueries<'_, '_>>>>,
|
||||||
let mut mesh_extras = world.query_filtered::<(Entity, Option<&Name>, &GltfMeshExtras), (Added<GltfMeshExtras>, Without<GltfProcessed>)>();
|
) {
|
||||||
let mut material_extras = world.query_filtered::<(Entity, Option<&Name>, &GltfMaterialExtras), (Added<GltfMaterialExtras>, Without<GltfProcessed>)>();
|
let state = queries_state.get_or_insert_with(|| SystemState::new(world));
|
||||||
|
let ExtrasComponentQueries {
|
||||||
let mut scene_instances = world.query::<&SceneInstance>();
|
extras,
|
||||||
|
scene_extras,
|
||||||
let mut hierarchy_state = world.query::<&Parent>();
|
mesh_extras,
|
||||||
let mut __unsafe_dw = DeferredWorld::from(unsafe { &mut *(world as *mut _) });
|
material_extras,
|
||||||
let hierarchy = __unsafe_dw.query(&mut hierarchy_state);
|
bad_world_access,
|
||||||
|
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();
|
||||||
|
@ -80,11 +119,11 @@ pub fn add_components_from_gltf_extras(world: &mut World) {
|
||||||
// let gltf_components_config = world.resource::<GltfComponentsConfig>();
|
// let gltf_components_config = world.resource::<GltfComponentsConfig>();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// SAFETY: we don't do anything harmful until taking this, and have full world access
|
// SAFETY: we set this to `None` again before using world again and fake_entity just uses it in that time.
|
||||||
fake_entity::BAD_WORLD_ACCESS.set(Some(BadWorldAccess::new(world)));
|
fake_entity::BAD_WORLD_ACCESS.set(Some(core::mem::transmute(bad_world_access)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (entity, name, extra) in extras.iter(world) {
|
for (entity, name, extra) in extras.iter() {
|
||||||
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 {:?}",
|
||||||
|
@ -93,7 +132,7 @@ pub fn add_components_from_gltf_extras(world: &mut World) {
|
||||||
|
|
||||||
if let Some(instance) = hierarchy
|
if let Some(instance) = hierarchy
|
||||||
.iter_ancestors(entity)
|
.iter_ancestors(entity)
|
||||||
.find_map(|p| scene_instances.get(world, p).ok())
|
.find_map(|p| scene_instances.get(p).ok())
|
||||||
{
|
{
|
||||||
fake_entity::INSTANCE_ID.set(Some(*instance.deref()));
|
fake_entity::INSTANCE_ID.set(Some(*instance.deref()));
|
||||||
} else {
|
} else {
|
||||||
|
@ -101,7 +140,6 @@ pub fn add_components_from_gltf_extras(world: &mut World) {
|
||||||
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(""));
|
||||||
|
@ -112,7 +150,7 @@ pub fn add_components_from_gltf_extras(world: &mut World) {
|
||||||
entity_components.insert(target_entity, updated_components);
|
entity_components.insert(target_entity, updated_components);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (entity, name, extra) in scene_extras.iter(world) {
|
for (entity, name, extra) in scene_extras.iter() {
|
||||||
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 {:?}",
|
||||||
|
@ -121,7 +159,7 @@ pub fn add_components_from_gltf_extras(world: &mut World) {
|
||||||
|
|
||||||
if let Some(instance) = hierarchy
|
if let Some(instance) = hierarchy
|
||||||
.iter_ancestors(entity)
|
.iter_ancestors(entity)
|
||||||
.find_map(|p| scene_instances.get(world, p).ok())
|
.find_map(|p| scene_instances.get(p).ok())
|
||||||
{
|
{
|
||||||
fake_entity::INSTANCE_ID.set(Some(*instance.deref()));
|
fake_entity::INSTANCE_ID.set(Some(*instance.deref()));
|
||||||
} else {
|
} else {
|
||||||
|
@ -129,7 +167,6 @@ pub fn add_components_from_gltf_extras(world: &mut World) {
|
||||||
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);
|
||||||
|
|
||||||
|
@ -138,7 +175,7 @@ pub fn add_components_from_gltf_extras(world: &mut World) {
|
||||||
entity_components.insert(target_entity, updated_components);
|
entity_components.insert(target_entity, updated_components);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (entity, name, extra) in mesh_extras.iter(world) {
|
for (entity, name, extra) in mesh_extras.iter() {
|
||||||
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 {:?}",
|
||||||
|
@ -147,7 +184,7 @@ pub fn add_components_from_gltf_extras(world: &mut World) {
|
||||||
|
|
||||||
if let Some(instance) = hierarchy
|
if let Some(instance) = hierarchy
|
||||||
.iter_ancestors(entity)
|
.iter_ancestors(entity)
|
||||||
.find_map(|p| scene_instances.get(world, p).ok())
|
.find_map(|p| scene_instances.get(p).ok())
|
||||||
{
|
{
|
||||||
fake_entity::INSTANCE_ID.set(Some(*instance.deref()));
|
fake_entity::INSTANCE_ID.set(Some(*instance.deref()));
|
||||||
} else {
|
} else {
|
||||||
|
@ -155,7 +192,6 @@ pub fn add_components_from_gltf_extras(world: &mut World) {
|
||||||
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);
|
||||||
|
|
||||||
|
@ -164,7 +200,7 @@ pub fn add_components_from_gltf_extras(world: &mut World) {
|
||||||
entity_components.insert(target_entity, updated_components);
|
entity_components.insert(target_entity, updated_components);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (entity, name, extra) in material_extras.iter(world) {
|
for (entity, name, extra) in material_extras.iter() {
|
||||||
let parent = hierarchy.get(entity).ok();
|
let parent = hierarchy.get(entity).ok();
|
||||||
debug!(
|
debug!(
|
||||||
"Name: {:?}, entity {:?}, parent: {:?}, material_extras {:?}",
|
"Name: {:?}, entity {:?}, parent: {:?}, material_extras {:?}",
|
||||||
|
@ -173,7 +209,7 @@ pub fn add_components_from_gltf_extras(world: &mut World) {
|
||||||
|
|
||||||
if let Some(instance) = hierarchy
|
if let Some(instance) = hierarchy
|
||||||
.iter_ancestors(entity)
|
.iter_ancestors(entity)
|
||||||
.find_map(|p| scene_instances.get(world, p).ok())
|
.find_map(|p| scene_instances.get(p).ok())
|
||||||
{
|
{
|
||||||
fake_entity::INSTANCE_ID.set(Some(*instance.deref()));
|
fake_entity::INSTANCE_ID.set(Some(*instance.deref()));
|
||||||
} else {
|
} else {
|
||||||
|
@ -181,7 +217,6 @@ pub fn add_components_from_gltf_extras(world: &mut World) {
|
||||||
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);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
|
|
||||||
use bevy::log::{debug, info, warn};
|
use bevy::log::{debug, warn};
|
||||||
use bevy::reflect::serde::{ReflectDeserializer, ReflectSerializer};
|
use bevy::reflect::serde::ReflectDeserializer;
|
||||||
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;
|
||||||
|
|
Loading…
Reference in New Issue