use crate::CurrentWorkspace;
use bevy::ecs::hierarchy::ChildOf;
use bevy::prelude::*;
use rmf_site_camera::{active_camera_maybe, resources::CameraConfig, ActiveCameraQuery};
use rmf_site_format::{
LevelElevation, LevelProperties, NameInSite, NameOfSite, Pose, ScenarioModifiers,
UserCameraPoseMarker,
};
use super::{ChangeCurrentScenario, CreateScenario, DefaultScenario};
#[derive(Clone, Copy, Debug, Event)]
pub struct ChangeCurrentSite {
pub site: Entity,
pub level: Option<Entity>,
pub scenario: Option<Entity>,
}
#[derive(Clone, Copy, Debug, Default, Deref, DerefMut, Resource)]
pub struct CurrentLevel(pub Option<Entity>);
#[derive(Clone, Copy, Debug, Default, Deref, DerefMut, Resource)]
pub struct CurrentScenario(pub Option<Entity>);
#[derive(Component, Clone, Deref, DerefMut, Debug)]
pub struct CachedLevel(Entity);
#[derive(Component, Clone, Copy, Debug, Deref, DerefMut)]
pub struct NextSiteID(pub u32);
pub fn change_site(
mut commands: Commands,
mut change_current_site: EventReader<ChangeCurrentSite>,
mut change_current_scenario: EventWriter<ChangeCurrentScenario>,
mut create_new_scenario: EventWriter<CreateScenario>,
mut current_workspace: ResMut<CurrentWorkspace>,
mut current_level: ResMut<CurrentLevel>,
current_scenario: ResMut<CurrentScenario>,
cached_levels: Query<&CachedLevel>,
default_scenario: Res<DefaultScenario>,
mut visibility: Query<&mut Visibility>,
open_sites: Query<Entity, With<NameOfSite>>,
children: Query<&Children>,
child_of: Query<&ChildOf>,
levels: Query<Entity, With<LevelElevation>>,
scenarios: Query<Entity, With<ScenarioModifiers<Entity>>>,
) {
let mut set_visibility = |entity, value| {
if let Ok(mut v) = visibility.get_mut(entity) {
*v = value;
}
};
if let Some(cmd) = change_current_site.read().last() {
if open_sites.get(cmd.site).is_err() {
error!(
"Requested workspace change to an entity that is not an open site: {:?}",
cmd.site
);
return;
}
if let Some(chosen_level) = cmd.level {
if child_of
.get(chosen_level)
.ok()
.filter(|child_of| child_of.parent() == cmd.site)
.is_none()
{
error!(
"Requested level change to an entity {:?} that is not a level of the requested site {:?}",
chosen_level, cmd.site,
);
return;
}
}
current_workspace.root = Some(cmd.site);
current_workspace.display = true;
if let Some(new_level) = cmd.level {
if let Some(previous_level) = current_level.0 {
if previous_level != new_level {
set_visibility(previous_level, Visibility::Hidden);
}
}
set_visibility(new_level, Visibility::Inherited);
commands.entity(cmd.site).insert(CachedLevel(new_level));
current_level.0 = Some(new_level);
} else {
if let Ok(cached_level) = cached_levels.get(cmd.site) {
set_visibility(**cached_level, Visibility::Inherited);
current_level.0 = Some(**cached_level);
} else {
if let Ok(children) = children.get(cmd.site) {
let mut found_level = false;
for child in children {
if let Ok(level) = levels.get(*child) {
commands.entity(cmd.site).insert(CachedLevel(level));
current_level.0 = Some(level);
found_level = true;
set_visibility(level, Visibility::Inherited);
}
}
if !found_level {
let new_level = commands
.spawn((Transform::default(), Visibility::default()))
.insert(LevelProperties {
name: NameInSite("<unnamed level>".to_owned()),
elevation: LevelElevation(0.),
global_floor_visibility: default(),
global_drawing_visibility: default(),
})
.insert(ChildOf(cmd.site))
.id();
commands.entity(cmd.site).insert(CachedLevel(new_level));
current_level.0 = Some(new_level);
}
}
}
}
if let Some(new_scenario) = cmd.scenario {
if let Some(previous_scenario) = current_scenario.0 {
if previous_scenario != new_scenario {
change_current_scenario.write(ChangeCurrentScenario(new_scenario));
}
}
} else {
if let Ok(children) = children.get(cmd.site) {
let any_scenario = default_scenario.0.or_else(|| {
children
.iter()
.filter(|child| scenarios.get(*child).is_ok())
.next()
});
if let Some(new_scenario) = any_scenario {
change_current_scenario.write(ChangeCurrentScenario(new_scenario));
} else {
create_new_scenario.write(CreateScenario {
name: None,
parent: None,
});
}
}
}
}
}
pub fn set_camera_transform_for_changed_site(
current_workspace: Res<CurrentWorkspace>,
current_level: Res<CurrentLevel>,
active_cam: ActiveCameraQuery,
mut camera_config: ResMut<CameraConfig>,
children: Query<&Children>,
user_camera_poses: Query<&Pose, With<UserCameraPoseMarker>>,
mut transforms: Query<&mut Transform>,
) {
if current_workspace.is_changed() {
let Some(level) = current_level.0 else {
return;
};
if let Some(pose) = children
.get(level)
.ok()
.and_then(|children| children.iter().find_map(|c| user_camera_poses.get(c).ok()))
{
let Ok(active_camera) = active_camera_maybe(&active_cam) else {
return;
};
if let Ok(mut tf) = transforms.get_mut(active_camera) {
*tf = pose.transform();
}
let mut translation = pose.transform().translation;
translation.x = translation.x + 10.0;
translation.y = translation.y + 10.0;
translation.z = 0.0;
camera_config.orbit_center = Some(translation);
}
}
}