Getting rid of most of unsafe stuff

This commit is contained in:
DasLixou 2024-09-09 12:28:23 +02:00
parent 20f37715e4
commit e464c49592
3 changed files with 77 additions and 61 deletions

View File

@ -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,

View File

@ -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);

View File

@ -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;