diff --git a/dotlottie-ffi/emscripten_bindings.cpp b/dotlottie-ffi/emscripten_bindings.cpp index ee43e0da..c41ed9eb 100644 --- a/dotlottie-ffi/emscripten_bindings.cpp +++ b/dotlottie-ffi/emscripten_bindings.cpp @@ -160,8 +160,8 @@ EMSCRIPTEN_BINDINGS(DotLottiePlayer) .function("stateMachineFrameworkSetup", &DotLottiePlayer::state_machine_framework_setup) .function("setStateMachineNumericContext", &DotLottiePlayer::set_state_machine_numeric_context) .function("setStateMachineStringContext", &DotLottiePlayer::set_state_machine_string_context) - .function("setStateMachineBooleanContext", &DotLottiePlayer::set_state_machine_boolean_context); - + .function("setStateMachineBooleanContext", &DotLottiePlayer::set_state_machine_boolean_context) + .function("loadStateMachineData", &DotLottiePlayer::load_state_machine_data); // .function("state_machine_subscribe", &DotLottiePlayer::state_machine_subscribe) // .function("state_machine_unsubscribe", &DotLottiePlayer::state_machine_unsubscribe) } diff --git a/dotlottie-ffi/src/dotlottie_player.udl b/dotlottie-ffi/src/dotlottie_player.udl index 53fd9235..cc84e39c 100644 --- a/dotlottie-ffi/src/dotlottie_player.udl +++ b/dotlottie-ffi/src/dotlottie_player.udl @@ -158,4 +158,5 @@ interface DotLottiePlayer { boolean set_state_machine_string_context([ByRef] string key, [ByRef] string value); boolean set_state_machine_boolean_context([ByRef] string key, boolean value); sequence state_machine_framework_setup(); + boolean load_state_machine_data([ByRef] string state_machine); }; diff --git a/dotlottie-ffi/src/dotlottie_player_cpp.udl b/dotlottie-ffi/src/dotlottie_player_cpp.udl index a607f1d6..ebf8fae8 100644 --- a/dotlottie-ffi/src/dotlottie_player_cpp.udl +++ b/dotlottie-ffi/src/dotlottie_player_cpp.udl @@ -85,4 +85,5 @@ interface DotLottiePlayer { boolean stop_state_machine(); boolean post_serialized_event(string event); sequence state_machine_framework_setup(); + boolean load_state_machine_data([ByRef] string state_machine); }; diff --git a/dotlottie-rs/src/dotlottie_player.rs b/dotlottie-rs/src/dotlottie_player.rs index bec6ddea..e803508a 100644 --- a/dotlottie-rs/src/dotlottie_player.rs +++ b/dotlottie-rs/src/dotlottie_player.rs @@ -1781,6 +1781,34 @@ impl DotLottiePlayer { self.player.write().unwrap().load_theme(theme_id) } + pub fn load_state_machine_data(&self, state_machine: &str) -> bool { + let state_machine = StateMachine::new(state_machine, self.player.clone()); + + if state_machine.is_ok() { + match self.state_machine.try_write() { + Ok(mut sm) => { + sm.replace(state_machine.unwrap()); + } + Err(_) => { + return false; + } + } + + let player = self.player.try_write(); + + match player { + Ok(mut player) => { + player.state_machine = self.state_machine.clone(); + } + Err(_) => { + return false; + } + } + } + + false + } + pub fn load_state_machine(&self, state_machine_id: &str) -> bool { let state_machine_string = self .player diff --git a/dotlottie-rs/tests/fixtures/pigeon_fsm.json b/dotlottie-rs/tests/fixtures/pigeon_fsm.json new file mode 100644 index 00000000..db1fa813 --- /dev/null +++ b/dotlottie-rs/tests/fixtures/pigeon_fsm.json @@ -0,0 +1,80 @@ +{ + "descriptor": { + "id": "multi_animation_slideshow", + "initial": 0 + }, + "states": [ + { + "name": "pigeon", + "type": "PlaybackState", + "loop": true, + "autoplay": true, + "mode": "forward", + "speed": 1, + "marker": "bird", + "segment": [], + "frame_interpolation": true, + "entry_actions": [ + { + "type": "LogAction", + "message": "Howdy partner!" + } + ], + "exit_actions": [], + "reset_context": "*" + }, + { + "name": "explosion", + "type": "PlaybackState", + "loop": false, + "autoplay": true, + "mode": "forward", + "speed": 0.5, + "marker": "explosion", + "segment": [], + "frame_interpolation": true, + "entry_actions": [], + "exit_actions": [] + }, + { + "name": "feather", + "type": "PlaybackState", + "loop": false, + "autoplay": true, + "mode": "forward", + "speed": 1, + "marker": "feather", + "segment": [], + "frame_interpolation": true, + "entry_actions": [], + "exit_actions": [] + } + ], + "transitions": [ + { + "type": "Transition", + "from_state": 0, + "to_state": 1, + "on_pointer_down_event": {} + }, + { + "type": "Transition", + "from_state": 1, + "to_state": 2, + "on_pointer_down_event": {} + }, + { + "type": "Transition", + "from_state": 2, + "to_state": 0, + "on_pointer_down_event": {} + } + ], + "listeners": [ + { + "type": "PointerDown" + } + ], + "context_variables": [ + ] +} \ No newline at end of file diff --git a/dotlottie-rs/tests/state_machine.rs b/dotlottie-rs/tests/state_machine.rs index 14e6f713..fe3533fd 100644 --- a/dotlottie-rs/tests/state_machine.rs +++ b/dotlottie-rs/tests/state_machine.rs @@ -4,6 +4,7 @@ mod tests { use dotlottie_player_core::{ listeners::ListenerTrait, + states::StateTrait, transitions::{Transition::Transition, TransitionTrait}, StateMachineObserver, }; @@ -297,6 +298,87 @@ mod tests { assert_eq!(*observer3.custom_data.read().unwrap(), "\"feather\""); } + #[test] + fn state_machine_from_data_test() { + let pigeon_fsm = include_str!("fixtures/pigeon_fsm.json"); + + let player = DotLottiePlayer::new(Config::default()); + + player.load_dotlottie_data(include_bytes!("fixtures/exploding_pigeon.lottie"), 100, 100); + + player.load_state_machine_data(pigeon_fsm); + player.start_state_machine(); + + match player.get_state_machine().read().unwrap().as_ref() { + Some(sm) => { + assert_eq!(sm.states.len(), 3); + } + None => { + panic!("State machine is not loaded"); + } + } + + match player.get_state_machine().read().unwrap().as_ref() { + Some(sm) => { + let cs = sm.get_current_state(); + + match cs { + Some(sm) => match sm.try_read() { + Ok(state) => { + assert_eq!(state.get_name(), "pigeon"); + } + Err(_) => panic!("State is not readable"), + }, + None => panic!("Failed to get current state"), + } + } + None => { + panic!("State machine is not loaded"); + } + } + + player.post_event(&Event::OnPointerDown { x: 0.0, y: 0.0 }); + + match player.get_state_machine().read().unwrap().as_ref() { + Some(sm) => { + let cs = sm.get_current_state(); + + match cs { + Some(sm) => match sm.try_read() { + Ok(state) => { + assert_eq!(state.get_name(), "explosion"); + } + Err(_) => panic!("State is not readable"), + }, + None => panic!("Failed to get current state"), + } + } + None => { + panic!("State machine is not loaded"); + } + } + player.post_event(&Event::OnPointerDown { x: 0.0, y: 0.0 }); + + match player.get_state_machine().read().unwrap().as_ref() { + Some(sm) => { + let cs = sm.get_current_state(); + + match cs { + Some(sm) => match sm.try_read() { + Ok(state) => { + assert_eq!(state.get_name(), "feather"); + } + Err(_) => panic!("State is not readable"), + }, + None => panic!("Failed to get current state"), + } + } + None => { + panic!("State machine is not loaded"); + } + } + } + #[test] fn state_machine_listener_test() { let player = DotLottiePlayer::new(Config::default());