use crate::scene::EntityInfo;
use crate::{
command::{make_command, Command, SetPropertyCommand},
fyrox::{
core::log::Log,
core::pool::ErasedHandle,
core::pool::Handle,
core::reflect::Reflect,
core::variable::InheritableVariable,
engine::Engine,
generic_animation::machine::Machine,
generic_animation::machine::{PoseNode, State, Transition},
graph::{SceneGraph, SceneGraphNode},
gui::inspector::PropertyChanged,
scene::SceneContainer,
},
message::MessageSender,
plugins::absm::command::fetch_machine,
scene::controller::SceneController,
scene::GameScene,
scene::SelectionContainer,
ui_scene::UiScene,
};
use std::fmt::{Debug, Formatter};
use std::ops::Deref;
#[derive(Eq)]
pub enum SelectedEntity<N: Reflect> {
Transition(Handle<Transition<Handle<N>>>),
State(Handle<State<Handle<N>>>),
PoseNode(Handle<PoseNode<Handle<N>>>),
}
impl<N> Debug for SelectedEntity<N>
where
N: Reflect,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Transition(v) => write!(f, "{v}"),
Self::State(v) => write!(f, "{v}"),
Self::PoseNode(v) => write!(f, "{v}"),
}
}
}
impl<N> Clone for SelectedEntity<N>
where
N: Reflect,
{
fn clone(&self) -> Self {
match self {
Self::Transition(v) => Self::Transition(*v),
Self::State(v) => Self::State(*v),
Self::PoseNode(v) => Self::PoseNode(*v),
}
}
}
impl<N> PartialEq for SelectedEntity<N>
where
N: Reflect,
{
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Transition(a), Self::Transition(b)) => *a == *b,
(Self::State(a), Self::State(b)) => *a == *b,
(Self::PoseNode(a), Self::PoseNode(b)) => *a == *b,
_ => false,
}
}
}
#[derive(Eq, Default)]
pub struct AbsmSelection<N: Reflect> {
pub absm_node_handle: Handle<N>,
pub layer: Option<usize>,
pub entities: Vec<SelectedEntity<N>>,
}
impl<N> Debug for AbsmSelection<N>
where
N: Reflect,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{} {:?} {:?}",
self.absm_node_handle, self.layer, self.entities
)
}
}
impl<N> Clone for AbsmSelection<N>
where
N: Reflect,
{
fn clone(&self) -> Self {
Self {
absm_node_handle: self.absm_node_handle,
layer: self.layer,
entities: self.entities.clone(),
}
}
}
impl<N> PartialEq for AbsmSelection<N>
where
N: Reflect,
{
fn eq(&self, other: &Self) -> bool {
self.entities == other.entities
&& self.layer == other.layer
&& self.absm_node_handle == other.absm_node_handle
}
}
pub fn get_machine_ref<'a, N: Reflect>(
controller: &'a dyn SceneController,
node_handle: Handle<N>,
scene_container: &'a SceneContainer,
) -> Option<&'a Machine<Handle<N>>> {
if let Some(game_scene) = controller.downcast_ref::<GameScene>() {
scene_container[game_scene.scene]
.graph
.node(ErasedHandle::from(node_handle).into())
.component_ref::<InheritableVariable<Machine<Handle<N>>>>()
.map(|v| v.deref())
} else if let Some(ui) = controller.downcast_ref::<UiScene>() {
ui.ui
.node(ErasedHandle::from(node_handle).into())
.component_ref::<InheritableVariable<Machine<Handle<N>>>>()
.map(|v| v.deref())
} else {
None
}
}
impl<N: Reflect> SelectionContainer for AbsmSelection<N> {
fn len(&self) -> usize {
self.entities.len()
}
fn first_selected_entity(
&self,
controller: &dyn SceneController,
scenes: &SceneContainer,
callback: &mut dyn FnMut(EntityInfo),
) {
if let Some(machine) = get_machine_ref(controller, self.absm_node_handle, scenes) {
if let Some(first) = self.entities.first() {
if let Some(layer_index) = self.layer {
if let Some(layer) = machine.layers().get(layer_index) {
match first {
SelectedEntity::Transition(transition) => (callback)(
EntityInfo::with_no_parent(&layer.transitions()[*transition]),
),
SelectedEntity::State(state) => (callback)(EntityInfo::with_no_parent(
&layer.states()[*state] as &dyn Reflect,
)),
SelectedEntity::PoseNode(pose) => (callback)(
EntityInfo::with_no_parent(&layer.nodes()[*pose] as &dyn Reflect),
),
};
}
}
}
}
}
fn on_property_changed(
&mut self,
_controller: &mut dyn SceneController,
args: &PropertyChanged,
_engine: &mut Engine,
sender: &MessageSender,
) {
let group = if let Some(layer_index) = self.layer {
let absm_node_handle = self.absm_node_handle;
self.entities
.iter()
.filter_map(|ent| match *ent {
SelectedEntity::Transition(transition) => make_command(args, move |ctx| {
let machine = fetch_machine(ctx, absm_node_handle);
machine
.layers_mut()
.get_mut(layer_index)?
.transitions_mut()
.try_borrow_mut(transition)
.ok()
.map(|t| t as &mut dyn Reflect)
}),
SelectedEntity::State(state) => make_command(args, move |ctx| {
let machine = fetch_machine(ctx, absm_node_handle);
machine
.layers_mut()
.get_mut(layer_index)?
.states_mut()
.try_borrow_mut(state)
.ok()
.map(|s| s as &mut dyn Reflect)
}),
SelectedEntity::PoseNode(pose) => make_command(args, move |ctx| {
let machine = fetch_machine(ctx, absm_node_handle);
machine
.layers_mut()
.get_mut(layer_index)?
.nodes_mut()
.try_borrow_mut(pose)
.ok()
.map(|p| p as &mut dyn Reflect)
}),
})
.collect()
} else {
vec![]
};
if group.is_empty() {
if !args.is_inheritable() {
Log::err(format!("Failed to handle a property {}", args.path()))
}
} else if group.len() == 1 {
sender.do_command_group(group);
}
}
fn paste_property(&mut self, path: &str, value: &dyn Reflect, sender: &MessageSender) {
let group = if let Some(layer_index) = self.layer {
let absm_node_handle = self.absm_node_handle;
self.entities
.iter()
.filter_map(|ent| match *ent {
SelectedEntity::Transition(transition) => value.try_clone_box().map(|value| {
Command::new(SetPropertyCommand::new(
path.to_string(),
value,
move |ctx| {
let machine = fetch_machine(ctx, absm_node_handle);
machine
.layers_mut()
.get_mut(layer_index)?
.transitions_mut()
.try_borrow_mut(transition)
.ok()
.map(|t| t as &mut dyn Reflect)
},
))
}),
SelectedEntity::State(state) => value.try_clone_box().map(|value| {
Command::new(SetPropertyCommand::new(
path.to_string(),
value,
move |ctx| {
let machine = fetch_machine(ctx, absm_node_handle);
machine
.layers_mut()
.get_mut(layer_index)?
.states_mut()
.try_borrow_mut(state)
.ok()
.map(|s| s as &mut dyn Reflect)
},
))
}),
SelectedEntity::PoseNode(pose) => value.try_clone_box().map(|value| {
Command::new(SetPropertyCommand::new(
path.to_string(),
value,
move |ctx| {
let machine = fetch_machine(ctx, absm_node_handle);
machine
.layers_mut()
.get_mut(layer_index)?
.nodes_mut()
.try_borrow_mut(pose)
.ok()
.map(|n| n as &mut dyn Reflect)
},
))
}),
})
.collect()
} else {
vec![]
};
if group.len() == 1 {
sender.do_command_group(group);
}
}
fn provide_docs(&self, _controller: &dyn SceneController, _engine: &Engine) -> Option<String> {
None
}
}