use std::any::TypeId;
use bevy_asset::{Asset, AssetServer, Assets, ReflectAsset, UntypedAssetId};
use bevy_ecs::query::{QueryFilter, WorldQuery};
use bevy_ecs::system::CommandQueue;
use bevy_ecs::{component::ComponentId, prelude::*};
use bevy_hierarchy::{Children, Parent};
use bevy_reflect::{Reflect, TypeRegistry};
use pretty_type_name::pretty_type_name;
pub(crate) mod errors;
pub mod hierarchy;
use crate::reflect_inspector::{Context, InspectorUi};
use crate::restricted_world_view::RestrictedWorldView;
pub fn ui_for_value(value: &mut dyn Reflect, ui: &mut egui::Ui, world: &mut World) -> bool {
let type_registry = world.resource::<AppTypeRegistry>().0.clone();
let type_registry = type_registry.read();
let mut queue = CommandQueue::default();
let mut cx = Context {
world: Some(RestrictedWorldView::new(world)),
queue: Some(&mut queue),
};
let mut env = InspectorUi::for_bevy(&type_registry, &mut cx);
let changed = env.ui_for_reflect(value, ui);
queue.apply(world);
changed
}
pub fn ui_for_world(world: &mut World, ui: &mut egui::Ui) {
egui::CollapsingHeader::new("Entities")
.default_open(true)
.show(ui, |ui| {
ui_for_world_entities(world, ui);
});
egui::CollapsingHeader::new("Resources").show(ui, |ui| {
ui_for_resources(world, ui);
});
egui::CollapsingHeader::new("Assets").show(ui, |ui| {
ui_for_all_assets(world, ui);
});
}
pub fn ui_for_resources(world: &mut World, ui: &mut egui::Ui) {
let type_registry = world.resource::<AppTypeRegistry>().0.clone();
let type_registry = type_registry.read();
let mut resources: Vec<_> = type_registry
.iter()
.filter(|registration| registration.data::<ReflectResource>().is_some())
.map(|registration| {
(
registration.type_info().type_path_table().short_path(),
registration.type_id(),
)
})
.collect();
resources.sort_by(|(name_a, ..), (name_b, ..)| name_a.cmp(name_b));
for (name, type_id) in resources {
ui.collapsing(name, |ui| {
by_type_id::ui_for_resource(world, type_id, ui, name, &type_registry);
});
}
}
pub fn ui_for_resource<R: Resource + Reflect>(world: &mut World, ui: &mut egui::Ui) {
let type_registry = world.resource::<AppTypeRegistry>().0.clone();
let type_registry = type_registry.read();
let Some((mut resource, world_view)) =
RestrictedWorldView::new(world).split_off_resource_typed::<R>()
else {
errors::resource_does_not_exist(ui, &pretty_type_name::<R>());
return;
};
let mut queue = CommandQueue::default();
let mut cx = Context {
world: Some(world_view),
queue: Some(&mut queue),
};
let mut env = InspectorUi::for_bevy(&type_registry, &mut cx);
if env.ui_for_reflect(resource.bypass_change_detection(), ui) {
resource.set_changed();
}
queue.apply(world);
}
pub fn ui_for_all_assets(world: &mut World, ui: &mut egui::Ui) {
let type_registry = world.resource::<AppTypeRegistry>().0.clone();
let type_registry = type_registry.read();
let mut assets: Vec<_> = type_registry
.iter()
.filter(|registration| registration.data::<ReflectAsset>().is_some())
.map(|registration| {
(
registration.type_info().type_path_table().short_path(),
registration.type_id(),
)
})
.collect();
assets.sort_by(|(name_a, ..), (name_b, ..)| name_a.cmp(name_b));
for (name, type_id) in assets {
ui.collapsing(name, |ui| {
by_type_id::ui_for_assets(world, type_id, ui, &type_registry);
});
}
}
pub fn ui_for_assets<A: Asset + Reflect>(world: &mut World, ui: &mut egui::Ui) {
let asset_server = world.get_resource::<AssetServer>().cloned();
let type_registry = world.resource::<AppTypeRegistry>().0.clone();
let type_registry = type_registry.read();
let Some((mut assets, world_view)) =
RestrictedWorldView::new(world).split_off_resource_typed::<Assets<A>>()
else {
errors::resource_does_not_exist(ui, &pretty_type_name::<Assets<A>>());
return;
};
let mut queue = CommandQueue::default();
let mut cx = Context {
world: Some(world_view),
queue: Some(&mut queue),
};
let mut assets: Vec<_> = assets.iter_mut().collect();
assets.sort_by(|(a, _), (b, _)| a.cmp(b));
for (handle_id, asset) in assets {
let id = egui::Id::new(handle_id);
egui::CollapsingHeader::new(handle_name(handle_id.untyped(), asset_server.as_ref()))
.id_source(id)
.show(ui, |ui| {
let mut env = InspectorUi::for_bevy(&type_registry, &mut cx);
env.ui_for_reflect_with_options(asset, ui, id, &());
});
}
queue.apply(world);
}
pub fn ui_for_state<T: States + Reflect>(world: &mut World, ui: &mut egui::Ui) {
let type_registry = world.resource::<AppTypeRegistry>().0.clone();
let type_registry = type_registry.read();
let Some((state, world_view)) =
RestrictedWorldView::new(world).split_off_resource_typed::<State<T>>()
else {
errors::state_does_not_exist(ui, &pretty_type_name::<T>());
return;
};
let Some((mut next_state, world_view)) = world_view.split_off_resource_typed::<NextState<T>>()
else {
errors::state_does_not_exist(ui, &pretty_type_name::<T>());
return;
};
let mut queue = CommandQueue::default();
let mut cx = Context {
world: Some(world_view),
queue: Some(&mut queue),
};
let mut env = InspectorUi::for_bevy(&type_registry, &mut cx);
let mut current = state.get().clone();
let changed = env.ui_for_reflect(&mut current, ui);
if changed {
next_state.0 = Some(current);
}
queue.apply(world);
}
pub fn ui_for_world_entities(world: &mut World, ui: &mut egui::Ui) {
ui_for_world_entities_filtered::<Without<Parent>>(world, ui, true);
}
pub fn ui_for_world_entities_filtered<F: WorldQuery + QueryFilter>(
world: &mut World,
ui: &mut egui::Ui,
with_children: bool,
) {
let type_registry = world.resource::<AppTypeRegistry>().0.clone();
let type_registry = type_registry.read();
let mut root_entities = world.query_filtered::<Entity, F>();
let mut entities = root_entities.iter(world).collect::<Vec<_>>();
entities.sort();
let id = egui::Id::new("world ui");
for entity in entities {
let id = id.with(entity);
let entity_name = guess_entity_name(world, entity);
egui::CollapsingHeader::new(&entity_name)
.id_source(id)
.show(ui, |ui| {
if with_children {
ui_for_entity_with_children_inner(world, entity, ui, id, &type_registry);
} else {
let mut queue = CommandQueue::default();
ui_for_entity_components(
&mut world.into(),
Some(&mut queue),
entity,
ui,
id,
&type_registry,
);
queue.apply(world);
}
});
}
}
pub fn ui_for_entity_with_children(world: &mut World, entity: Entity, ui: &mut egui::Ui) {
let type_registry = world.resource::<AppTypeRegistry>().0.clone();
let type_registry = type_registry.read();
let entity_name = guess_entity_name(world, entity);
ui.label(entity_name);
ui_for_entity_with_children_inner(world, entity, ui, egui::Id::new(entity), &type_registry)
}
fn ui_for_entity_with_children_inner(
world: &mut World,
entity: Entity,
ui: &mut egui::Ui,
id: egui::Id,
type_registry: &TypeRegistry,
) {
let mut queue = CommandQueue::default();
ui_for_entity_components(
&mut world.into(),
Some(&mut queue),
entity,
ui,
id,
type_registry,
);
let children = world
.get::<Children>(entity)
.map(|children| children.iter().copied().collect::<Vec<_>>());
if let Some(children) = children {
if !children.is_empty() {
ui.label("Children");
for &child in children.iter() {
let id = id.with(child);
let child_entity_name = guess_entity_name(world, child);
egui::CollapsingHeader::new(&child_entity_name)
.id_source(id)
.show(ui, |ui| {
ui.label(&child_entity_name);
ui_for_entity_with_children_inner(world, child, ui, id, type_registry);
});
}
}
}
queue.apply(world);
}
pub fn ui_for_entity(world: &mut World, entity: Entity, ui: &mut egui::Ui) {
let type_registry = world.resource::<AppTypeRegistry>().0.clone();
let type_registry = type_registry.read();
let entity_name = guess_entity_name(world, entity);
ui.label(entity_name);
let mut queue = CommandQueue::default();
ui_for_entity_components(
&mut world.into(),
Some(&mut queue),
entity,
ui,
egui::Id::new(entity),
&type_registry,
);
queue.apply(world);
}
pub(crate) fn ui_for_entity_components(
world: &mut RestrictedWorldView<'_>,
mut queue: Option<&mut CommandQueue>,
entity: Entity,
ui: &mut egui::Ui,
id: egui::Id,
type_registry: &TypeRegistry,
) {
let Some(components) = components_of_entity(world, entity) else {
errors::entity_does_not_exist(ui, entity);
return;
};
for (name, component_id, component_type_id, size) in components {
let id = id.with(component_id);
let header = egui::CollapsingHeader::new(&name).id_source(id);
let Some(component_type_id) = component_type_id else {
header.show(ui, |ui| errors::no_type_id(ui, &name));
continue;
};
if size == 0 {
header.show(ui, |_| {});
continue;
}
let (mut component_view, world) = world.split_off_component((entity, component_type_id));
let mut cx = Context {
world: Some(world),
#[allow(clippy::needless_option_as_deref)]
queue: queue.as_deref_mut(),
};
let (value, is_changed, set_changed) = match component_view.get_entity_component_reflect(
entity,
component_type_id,
type_registry,
) {
Ok(value) => value,
Err(e) => {
header.show(ui, |ui| errors::show_error(e, ui, &name));
continue;
}
};
if is_changed {
#[cfg(feature = "highlight_changes")]
set_highlight_style(ui);
}
header.show(ui, |ui| {
ui.reset_style();
let inspector_changed = InspectorUi::for_bevy(type_registry, &mut cx)
.ui_for_reflect_with_options(value, ui, id.with(component_id), &());
if inspector_changed {
set_changed();
}
});
ui.reset_style();
}
}
#[cfg(feature = "highlight_changes")]
fn set_highlight_style(ui: &mut egui::Ui) {
let highlight_color = egui::Color32::GOLD;
let visuals = &mut ui.style_mut().visuals;
visuals.collapsing_header_frame = true;
visuals.widgets.inactive.bg_stroke = egui::Stroke {
width: 1.0,
color: highlight_color,
};
visuals.widgets.active.bg_stroke = egui::Stroke {
width: 1.0,
color: highlight_color,
};
visuals.widgets.hovered.bg_stroke = egui::Stroke {
width: 1.0,
color: highlight_color,
};
visuals.widgets.noninteractive.bg_stroke = egui::Stroke {
width: 1.0,
color: highlight_color,
};
}
fn components_of_entity(
world: &mut RestrictedWorldView<'_>,
entity: Entity,
) -> Option<Vec<(String, ComponentId, Option<TypeId>, usize)>> {
let entity_ref = world.world().get_entity(entity)?;
let archetype = entity_ref.archetype();
let mut components: Vec<_> = archetype
.components()
.map(|component_id| {
let info = world.world().components().get_info(component_id).unwrap();
let name = pretty_type_name::pretty_type_name_str(info.name());
(name, component_id, info.type_id(), info.layout().size())
})
.collect();
components.sort_by(|(name_a, ..), (name_b, ..)| name_a.cmp(name_b));
Some(components)
}
pub fn ui_for_entities_shared_components(
world: &mut World,
entities: &[Entity],
ui: &mut egui::Ui,
) {
let type_registry = world.resource::<AppTypeRegistry>().0.clone();
let type_registry = type_registry.read();
let Some(&first) = entities.first() else {
return;
};
let Some(mut components) = components_of_entity(&mut world.into(), first) else {
return errors::entity_does_not_exist(ui, first);
};
for &entity in entities.iter().skip(1) {
components.retain(|(_, id, _, _)| {
world
.get_entity(entity)
.map_or(true, |entity| entity.contains_id(*id))
})
}
let (resources_view, components_view) = RestrictedWorldView::resources_components(world);
let mut queue = CommandQueue::default();
let mut cx = Context {
world: Some(resources_view),
queue: Some(&mut queue),
};
let mut env = InspectorUi::for_bevy(&type_registry, &mut cx);
let id = egui::Id::NULL;
for (name, component_id, component_type_id, size) in components {
let id = id.with(component_id);
egui::CollapsingHeader::new(&name)
.id_source(id)
.show(ui, |ui| {
if size == 0 {
return;
}
let Some(component_type_id) = component_type_id else {
return errors::no_type_id(ui, &name);
};
let mut values = Vec::with_capacity(entities.len());
let mut mark_changeds = Vec::with_capacity(entities.len());
for (i, &entity) in entities.iter().enumerate() {
if entities[0..i].contains(&entity) {
continue;
};
match unsafe {
components_view.get_entity_component_reflect_unchecked(
entity,
component_type_id,
&type_registry,
)
} {
Ok((value, mark_changed)) => {
values.push(value);
mark_changeds.push(mark_changed);
}
Err(error) => {
errors::show_error(error, ui, &name);
return;
}
}
}
let changed = env.ui_for_reflect_many_with_options(
component_type_id,
&name,
ui,
id.with(component_id),
&(),
values.as_mut_slice(),
&|a| a,
);
if changed {
mark_changeds.into_iter().for_each(|f| f());
}
});
}
queue.apply(world);
}
pub mod by_type_id {
use std::any::TypeId;
use bevy_asset::{AssetServer, ReflectAsset, ReflectHandle, UntypedAssetId, UntypedHandle};
use bevy_ecs::{prelude::*, system::CommandQueue};
use bevy_reflect::TypeRegistry;
use crate::{
reflect_inspector::{Context, InspectorUi},
restricted_world_view::RestrictedWorldView,
};
use super::{
errors::{self, name_of_type},
handle_name,
};
pub fn ui_for_resource(
world: &mut World,
resource_type_id: TypeId,
ui: &mut egui::Ui,
name_of_type: &str,
type_registry: &TypeRegistry,
) {
let mut queue = CommandQueue::default();
{
let mut world_view = RestrictedWorldView::new(world);
let (mut resource_view, world_view) = world_view.split_off_resource(resource_type_id);
let mut cx = Context {
world: Some(world_view),
queue: Some(&mut queue),
};
let mut env = InspectorUi::for_bevy(type_registry, &mut cx);
let (resource, set_changed) = match resource_view
.get_resource_reflect_mut_by_id(resource_type_id, type_registry)
{
Ok(resource) => resource,
Err(err) => return errors::show_error(err, ui, name_of_type),
};
let changed = env.ui_for_reflect(resource, ui);
if changed {
set_changed();
}
}
queue.apply(world);
}
pub fn ui_for_assets(
world: &mut World,
asset_type_id: TypeId,
ui: &mut egui::Ui,
type_registry: &TypeRegistry,
) {
let asset_server = world.get_resource::<AssetServer>().cloned();
let Some(registration) = type_registry.get(asset_type_id) else {
return crate::reflect_inspector::errors::not_in_type_registry(
ui,
&name_of_type(asset_type_id, type_registry),
);
};
let Some(reflect_asset) = registration.data::<ReflectAsset>() else {
return errors::no_type_data(
ui,
&name_of_type(asset_type_id, type_registry),
"ReflectAsset",
);
};
let Some(reflect_handle) =
type_registry.get_type_data::<ReflectHandle>(reflect_asset.handle_type_id())
else {
return errors::no_type_data(
ui,
&name_of_type(reflect_asset.handle_type_id(), type_registry),
"ReflectHandle",
);
};
let ids: Vec<_> = reflect_asset.ids(world).collect();
let world_view = RestrictedWorldView::new(world);
let mut queue = CommandQueue::default();
let mut cx = Context {
world: Some(world_view),
queue: Some(&mut queue),
};
for handle_id in ids {
let id = egui::Id::new(handle_id);
let mut handle = reflect_handle.typed(UntypedHandle::Weak(handle_id));
egui::CollapsingHeader::new(handle_name(handle_id, asset_server.as_ref()))
.id_source(id)
.show(ui, |ui| {
let mut env = InspectorUi::for_bevy(type_registry, &mut cx);
env.ui_for_reflect_with_options(&mut *handle, ui, id, &());
});
}
queue.apply(world)
}
pub fn ui_for_asset(
world: &mut World,
asset_type_id: TypeId,
handle: UntypedAssetId,
ui: &mut egui::Ui,
type_registry: &TypeRegistry,
) -> bool {
let Some(registration) = type_registry.get(asset_type_id) else {
crate::reflect_inspector::errors::not_in_type_registry(
ui,
&name_of_type(asset_type_id, type_registry),
);
return false;
};
let Some(reflect_asset) = registration.data::<ReflectAsset>() else {
errors::no_type_data(
ui,
&name_of_type(asset_type_id, type_registry),
"ReflectAsset",
);
return false;
};
let Some(reflect_handle) =
type_registry.get_type_data::<ReflectHandle>(reflect_asset.handle_type_id())
else {
errors::no_type_data(
ui,
&name_of_type(reflect_asset.handle_type_id(), type_registry),
"ReflectHandle",
);
return false;
};
let _: Vec<_> = reflect_asset.ids(world).collect();
let world_view = RestrictedWorldView::new(world);
let mut queue = CommandQueue::default();
let mut cx = Context {
world: Some(world_view),
queue: Some(&mut queue),
};
let id = egui::Id::new(handle);
let mut handle = reflect_handle.typed(UntypedHandle::Weak(handle));
let mut env = InspectorUi::for_bevy(type_registry, &mut cx);
let changed = env.ui_for_reflect_with_options(&mut *handle, ui, id, &());
queue.apply(world);
changed
}
}
fn handle_name(handle: UntypedAssetId, asset_server: Option<&AssetServer>) -> String {
if let Some(path) = asset_server
.as_ref()
.and_then(|server| server.get_path(handle))
{
return path.to_string();
}
match handle {
UntypedAssetId::Index { index, .. } => {
format!("{:?}", egui::Id::new(index))
}
UntypedAssetId::Uuid { uuid, .. } => {
format!("{}", uuid)
}
}
}
impl<'a, 'c> InspectorUi<'a, 'c> {
pub fn for_bevy(
type_registry: &'a TypeRegistry,
context: &'a mut Context<'c>,
) -> InspectorUi<'a, 'c> {
InspectorUi::new(
type_registry,
context,
Some(short_circuit::short_circuit),
Some(short_circuit::short_circuit_readonly),
Some(short_circuit::short_circuit_many),
)
}
}
pub mod short_circuit {
use std::any::{Any, TypeId};
use bevy_asset::ReflectAsset;
use bevy_reflect::Reflect;
use crate::reflect_inspector::{Context, InspectorUi};
use super::errors::{self, name_of_type};
pub fn short_circuit(
env: &mut InspectorUi,
value: &mut dyn Reflect,
ui: &mut egui::Ui,
id: egui::Id,
options: &dyn Any,
) -> Option<bool> {
if let Some(reflect_handle) = env
.type_registry
.get_type_data::<bevy_asset::ReflectHandle>(Any::type_id(value))
{
let handle = reflect_handle
.downcast_handle_untyped(value.as_any())
.unwrap();
let handle_id = handle.id();
let Some(reflect_asset) = env
.type_registry
.get_type_data::<ReflectAsset>(reflect_handle.asset_type_id())
else {
errors::no_type_data(
ui,
&name_of_type(reflect_handle.asset_type_id(), env.type_registry),
"ReflectAsset",
);
return Some(false);
};
let Context {
world: Some(world),
queue,
} = &mut env.context
else {
errors::no_world_in_context(ui, value.reflect_short_type_path());
return Some(false);
};
let (assets_view, world) =
world.split_off_resource(reflect_asset.assets_resource_type_id());
let asset_value = {
assert!(
assets_view.allows_access_to_resource(reflect_asset.assets_resource_type_id())
);
let asset_value =
unsafe { reflect_asset.get_unchecked_mut(world.world(), handle) };
match asset_value {
Some(value) => value,
None => {
errors::dead_asset_handle(ui, handle_id);
return Some(false);
}
}
};
let mut restricted_env = InspectorUi {
type_registry: env.type_registry,
context: &mut Context {
world: Some(world),
queue: queue.as_deref_mut(),
},
short_circuit: env.short_circuit,
short_circuit_readonly: env.short_circuit_readonly,
short_circuit_many: env.short_circuit_many,
};
return Some(restricted_env.ui_for_reflect_with_options(
asset_value,
ui,
id.with("asset"),
options,
));
}
None
}
pub fn short_circuit_many(
env: &mut InspectorUi,
type_id: TypeId,
type_name: &str,
ui: &mut egui::Ui,
id: egui::Id,
options: &dyn Any,
values: &mut [&mut dyn Reflect],
projector: &dyn Fn(&mut dyn Reflect) -> &mut dyn Reflect,
) -> Option<bool> {
if let Some(reflect_handle) = env
.type_registry
.get_type_data::<bevy_asset::ReflectHandle>(type_id)
{
let Some(reflect_asset) = env
.type_registry
.get_type_data::<ReflectAsset>(reflect_handle.asset_type_id())
else {
errors::no_type_data(
ui,
&name_of_type(reflect_handle.asset_type_id(), env.type_registry),
"ReflectAsset",
);
return Some(false);
};
let Context {
world: Some(world),
queue,
} = &mut env.context
else {
errors::no_world_in_context(ui, type_name);
return Some(false);
};
let (assets_view, world) =
world.split_off_resource(reflect_asset.assets_resource_type_id());
let mut new_values = Vec::with_capacity(values.len());
let mut used_handles = Vec::with_capacity(values.len());
for value in values {
let handle = projector(*value);
let handle = reflect_handle
.downcast_handle_untyped(handle.as_any())
.unwrap();
let handle_id = handle.id();
if used_handles.contains(&handle_id) {
continue;
};
used_handles.push(handle_id);
let asset_value = {
assert!(assets_view
.allows_access_to_resource(reflect_asset.assets_resource_type_id()));
let asset_value =
unsafe { reflect_asset.get_unchecked_mut(world.world(), handle) };
match asset_value {
Some(value) => value,
None => {
errors::dead_asset_handle(ui, handle_id);
return Some(false);
}
}
};
new_values.push(asset_value);
}
let mut restricted_env = InspectorUi {
type_registry: env.type_registry,
context: &mut Context {
world: Some(world),
queue: queue.as_deref_mut(),
},
short_circuit: env.short_circuit,
short_circuit_readonly: env.short_circuit_readonly,
short_circuit_many: env.short_circuit_many,
};
return Some(restricted_env.ui_for_reflect_many_with_options(
reflect_handle.asset_type_id(),
"",
ui,
id.with("asset"),
options,
new_values.as_mut_slice(),
&|a| a,
));
}
None
}
pub fn short_circuit_readonly(
env: &mut InspectorUi,
value: &dyn Reflect,
ui: &mut egui::Ui,
id: egui::Id,
options: &dyn Any,
) -> Option<()> {
if let Some(reflect_handle) = env
.type_registry
.get_type_data::<bevy_asset::ReflectHandle>(Any::type_id(value))
{
let handle = reflect_handle
.downcast_handle_untyped(value.as_any())
.unwrap();
let handle_id = handle.id();
let Some(reflect_asset) = env
.type_registry
.get_type_data::<ReflectAsset>(reflect_handle.asset_type_id())
else {
errors::no_type_data(
ui,
&name_of_type(reflect_handle.asset_type_id(), env.type_registry),
"ReflectAsset",
);
return Some(());
};
let Context {
world: Some(world),
queue,
} = &mut env.context
else {
errors::no_world_in_context(ui, value.reflect_short_type_path());
return Some(());
};
let (assets_view, world) =
world.split_off_resource(reflect_asset.assets_resource_type_id());
let asset_value = {
let interior_mutable_world = unsafe { assets_view.world().world() };
assert!(
assets_view.allows_access_to_resource(reflect_asset.assets_resource_type_id())
);
let asset_value = reflect_asset.get(interior_mutable_world, handle);
match asset_value {
Some(value) => value,
None => {
errors::dead_asset_handle(ui, handle_id);
return Some(());
}
}
};
let mut restricted_env = InspectorUi {
type_registry: env.type_registry,
context: &mut Context {
world: Some(world),
queue: queue.as_deref_mut(),
},
short_circuit: env.short_circuit,
short_circuit_readonly: env.short_circuit_readonly,
short_circuit_many: env.short_circuit_many,
};
restricted_env.ui_for_reflect_readonly_with_options(
asset_value,
ui,
id.with("asset"),
options,
);
return Some(());
}
None
}
}
pub use crate::utils::guess_entity_name::guess_entity_name;