From c29a25652ea353e7bda1908967dd0c0571e02a37 Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Sat, 3 Dec 2022 12:39:08 -0800 Subject: [PATCH 01/77] Reverse Observable <-> Delegate relationship --- src-tauri/src/app.rs | 2 +- src-tauri/src/features/recent_documents.rs | 4 +- src-tauri/src/utils/observable.rs | 202 ++++++++++++--------- 3 files changed, 119 insertions(+), 89 deletions(-) diff --git a/src-tauri/src/app.rs b/src-tauri/src/app.rs index 67aad19..2c3cebd 100644 --- a/src-tauri/src/app.rs +++ b/src-tauri/src/app.rs @@ -197,7 +197,7 @@ impl<'a> App<'a> { }); } - pub fn recent_documents_delegate<'b>(&'b self) -> Delegate<'b, 'a, Vec> { + pub fn recent_documents_delegate(&self) -> &Delegate<'a, Vec> { self.recent_documents.delegate() } diff --git a/src-tauri/src/features/recent_documents.rs b/src-tauri/src/features/recent_documents.rs index dd07e2e..e2fdc30 100644 --- a/src-tauri/src/features/recent_documents.rs +++ b/src-tauri/src/features/recent_documents.rs @@ -5,7 +5,7 @@ use std::sync::mpsc::channel; use tauri::Manager; use crate::app::AppState; -use crate::utils::observable::Observer; +use crate::utils::observable::Response; use crate::utils::paths; pub fn init(tauri_app: &tauri::App) { @@ -24,7 +24,7 @@ pub fn init(tauri_app: &tauri::App) { app.recent_documents_delegate() .subscribe(move |recent_documents| { tx.send(recent_documents.clone()).ok(); - Observer::StaySubscribed + Response::StaySubscribed }); std::thread::spawn(move || loop { diff --git a/src-tauri/src/utils/observable.rs b/src-tauri/src/utils/observable.rs index 859ccad..b4d3c15 100644 --- a/src-tauri/src/utils/observable.rs +++ b/src-tauri/src/utils/observable.rs @@ -4,16 +4,18 @@ use std::{cell::RefCell, collections::HashMap, hash::Hash, ops::Deref}; static NEXT_SUBSCRIPTION_ID: AtomicUsize = AtomicUsize::new(0); -type BoxedCallback<'a, T> = Box Observer + 'a + Send>; +type BoxedCallback<'a, T> = Box Response + 'a + Send>; type SubscriptionId = usize; +#[derive(Debug)] pub struct Observable<'o, T> { value: T, - subscriptions: RefCell>>, + delegate: Delegate<'o, T>, } -pub struct Delegate<'a, 'o, T> { - observable: &'a Observable<'o, T>, +#[derive(Default)] +pub struct Delegate<'d, T> { + subscriptions: RefCell>>, } #[derive(Eq, Hash, PartialEq)] @@ -21,42 +23,32 @@ pub struct Subscription { id: SubscriptionId, } -pub enum Observer { +pub enum Response { StaySubscribed, CancelSubscription, } -impl<'a, 'o, T> Delegate<'a, 'o, T> { - pub fn subscribe Observer + 'o + Send>(&self, callback: C) -> Subscription { - self.observable.subscribe(callback) - } - - pub fn unsubscribe(&self, subscription: &Subscription) { - self.observable.unsubscribe(subscription); - } -} - -impl<'o, T> Observable<'o, T> { - fn new(value: T) -> Self { +impl<'d, T> Delegate<'d, T> { + fn new() -> Self { Self { - value, subscriptions: RefCell::new(HashMap::new()), } } - pub fn delegate<'b>(&'b self) -> Delegate<'b, 'o, T> { - Delegate { observable: self } + pub fn subscribe Response + 'd + Send>(&self, callback: C) -> Subscription { + let id = NEXT_SUBSCRIPTION_ID.fetch_add(1, Ordering::SeqCst); + let subscription = Subscription { id }; + self.subscriptions + .borrow_mut() + .insert(subscription.id, Box::new(callback)); + subscription } - pub fn mutate(&mut self, mutation: M) - where - M: FnOnce(&mut T), - { - mutation(&mut self.value); - self.notify(); + pub fn unsubscribe(&self, subscription: &Subscription) { + self.subscriptions.borrow_mut().remove(&subscription.id); } - pub fn notify(&self) { + pub fn broadcast(&self, value: &T) { let subscriptions_to_notify = self .subscriptions .borrow() @@ -69,9 +61,9 @@ impl<'o, T> Observable<'o, T> { .borrow_mut() .remove_entry(&subscription) .unwrap(); - match callback(&self.value) { - Observer::CancelSubscription => (), - Observer::StaySubscribed => { + match callback(value) { + Response::CancelSubscription => (), + Response::StaySubscribed => { self.subscriptions .borrow_mut() .insert(subscription, callback); @@ -79,28 +71,51 @@ impl<'o, T> Observable<'o, T> { }; } } +} - pub fn subscribe Observer + 'o + Send>(&self, callback: C) -> Subscription { - let id = NEXT_SUBSCRIPTION_ID.fetch_add(1, Ordering::SeqCst); - let subscription = Subscription { id }; - self.subscriptions - .borrow_mut() - .insert(subscription.id, Box::new(callback)); - subscription +impl<'o, T> Observable<'o, T> { + fn new(value: T) -> Self { + Self { + value, + delegate: Delegate { + subscriptions: Default::default(), + }, + } + } + + pub fn subscribe Response + 'o + Send>(&self, callback: C) -> Subscription { + self.delegate.subscribe(callback) } pub fn unsubscribe(&self, subscription: &Subscription) { - self.subscriptions.borrow_mut().remove(&subscription.id); + self.delegate.unsubscribe(subscription); + } + + pub fn delegate(&self) -> &Delegate<'o, T> { + &self.delegate + } + + pub fn mutate(&mut self, mutation: M) + where + M: FnOnce(&mut T), + { + mutation(&mut self.value); + self.delegate.broadcast(&self.value); } } -impl Debug for Observable<'_, T> +impl Delegate<'_, ()> { + pub fn notify(&self) { + self.broadcast(&()); + } +} + +impl Debug for Delegate<'_, T> where T: Debug, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Observable") - .field("value", &self.value) + f.debug_struct("Delegate") .field( "subscriptions", &format_args!("{} active subscriptions", self.subscriptions.borrow().len()), @@ -134,105 +149,120 @@ mod test { use super::*; #[test] - fn can_notify_subscribers() { + fn delegate_can_notify_subscribers() { let mut call_count = 0; { - let o = Observable::new(0); - o.subscribe(|_| { + let d = Delegate::new(); + d.subscribe(|_| { call_count += 1; - Observer::StaySubscribed + Response::StaySubscribed }); - o.notify(); - o.notify(); - o.notify(); + d.notify(); + d.notify(); + d.notify(); } assert_eq!(call_count, 3); } #[test] - fn notifies_after_mutation() { + fn delegate_no_longer_notifies_after_unsubscribe() { let mut call_count = 0; { - let mut o = Observable::new(0); - o.subscribe(|_| { + let d = Delegate::new(); + let subscription = d.subscribe(|_| { call_count += 1; - Observer::StaySubscribed + Response::StaySubscribed }); - o.mutate(|value| *value = 42); - } - assert_eq!(call_count, 1); - } - - #[test] - fn no_longer_notifies_after_unsubscribe() { - let mut call_count = 0; - { - let mut o = Observable::new(0); - let subscription = o.subscribe(|_| { - call_count += 1; - Observer::StaySubscribed - }); - o.unsubscribe(&subscription); - o.mutate(|value| *value = 42); - o.notify(); + d.unsubscribe(&subscription); + d.notify(); } assert_eq!(call_count, 0); } #[test] - fn cannot_unsubscribe_using_subscription_from_a_different_observable() { + fn cannot_unsubscribe_using_subscription_from_a_different_delegate() { let mut call_count = 0; { - let o1 = Observable::new(0); - let o2 = Observable::new(0); - let _s1 = o1.subscribe(|_| { + let d1 = Delegate::<()>::new(); + let d2 = Delegate::<()>::new(); + let _s1 = d1.subscribe(|_| { call_count += 1; - Observer::StaySubscribed + Response::StaySubscribed }); - let s2 = o2.subscribe(|_| Observer::StaySubscribed); - o1.unsubscribe(&s2); - o1.notify(); + let s2 = d2.subscribe(|_| Response::StaySubscribed); + d1.unsubscribe(&s2); + d1.notify(); } assert_eq!(call_count, 1); } #[test] fn unsubscribe_within_callback_is_noop() { - let o = Arc::new(ReentrantMutex::new(Observable::new(0))); + let d = Arc::new(ReentrantMutex::new(Delegate::new())); let call_count = Arc::new(ReentrantMutex::new(RefCell::new(0))); let subscription = Arc::new(ReentrantMutex::new(RefCell::new(None))); - let o_clone = o.clone(); + let d_clone = d.clone(); let call_count_clone = call_count.clone(); let subscription_clone = subscription.clone(); subscription .lock() - .replace(Some(o.lock().subscribe(move |_| { + .replace(Some(d.lock().subscribe(move |_| { let old_count = *call_count_clone.lock().borrow(); *call_count_clone.lock().borrow_mut() = old_count + 1; - o_clone + d_clone .lock() .unsubscribe(subscription_clone.lock().deref().borrow().as_ref().unwrap()); - Observer::StaySubscribed + Response::StaySubscribed }))); - o.lock().notify(); - o.lock().notify(); + d.lock().notify(); + d.lock().notify(); assert_eq!(*call_count.lock().borrow(), 2); } #[test] fn can_unsubscribe_using_callback_return_value() { + let mut call_count = 0; + { + let d = Delegate::new(); + d.subscribe(|_| { + call_count += 1; + Response::CancelSubscription + }); + d.notify(); + d.notify(); + } + assert_eq!(call_count, 1); + } + + #[test] + fn observable_notifies_after_mutation() { let mut call_count = 0; { let mut o = Observable::new(0); o.subscribe(|_| { call_count += 1; - Observer::CancelSubscription + Response::StaySubscribed + }); + o.mutate(|value| *value = 42); + } + assert_eq!(call_count, 1); + } + + #[test] + fn observable_no_longer_notifies_after_unsubscribe() { + let mut call_count = 0; + { + let mut o = Observable::new(0); + let s = o.subscribe(|_| { + call_count += 1; + Response::StaySubscribed }); o.mutate(|value| *value = 42); - o.notify(); + o.unsubscribe(&s); + o.mutate(|value| *value = 43); } assert_eq!(call_count, 1); } From 651c6a7757418f6a5922510da854108e85a6c0dd Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Sat, 3 Dec 2022 17:36:02 -0800 Subject: [PATCH 02/77] Use published version of squeak --- src-tauri/Cargo.lock | 7 + src-tauri/Cargo.toml | 1 + src-tauri/src/app.rs | 2 +- src-tauri/src/features/recent_documents.rs | 2 +- src-tauri/src/utils.rs | 1 - src-tauri/src/utils/observable.rs | 269 --------------------- 6 files changed, 10 insertions(+), 272 deletions(-) delete mode 100644 src-tauri/src/utils/observable.rs diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index ade632a..5f5eb66 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2912,6 +2912,12 @@ dependencies = [ "lock_api", ] +[[package]] +name = "squeak" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8877cd452161d4defa7ba365915854438f7c6ce97745a72ec415846e7b9a173e" + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -3346,6 +3352,7 @@ dependencies = [ "serde", "serde_json", "simplelog", + "squeak", "sugar_path", "tauri", "tauri-build", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 0dca9db..9861a78 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -36,6 +36,7 @@ pathdiff = "0.2.1" serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } simplelog = "0.12.0" +squeak = "0.1.0" sugar_path = "0.0.9" tauri = { version = "1.1", features = ["clipboard", "clipboard-read-text", "clipboard-write-text", "dialog-open", "dialog-save", "protocol-asset", "shell-open", "window-close", "window-maximize", "window-minimize", "window-start-dragging", "window-unmaximize"] } thiserror = "1.0" diff --git a/src-tauri/src/app.rs b/src-tauri/src/app.rs index 2c3cebd..765f39a 100644 --- a/src-tauri/src/app.rs +++ b/src-tauri/src/app.rs @@ -1,4 +1,5 @@ use parking_lot::Mutex; +use squeak::{Delegate, Observable}; use std::{ path::{Path, PathBuf}, sync::Arc, @@ -6,7 +7,6 @@ use std::{ use thiserror::Error; use crate::document::{ClipboardManifest, Document, DocumentError}; -use crate::utils::observable::{Delegate, Observable}; #[derive(Error, Debug)] pub enum AppError { diff --git a/src-tauri/src/features/recent_documents.rs b/src-tauri/src/features/recent_documents.rs index e2fdc30..a82c231 100644 --- a/src-tauri/src/features/recent_documents.rs +++ b/src-tauri/src/features/recent_documents.rs @@ -1,11 +1,11 @@ use log::error; +use squeak::Response; use std::fs::File; use std::path::PathBuf; use std::sync::mpsc::channel; use tauri::Manager; use crate::app::AppState; -use crate::utils::observable::Response; use crate::utils::paths; pub fn init(tauri_app: &tauri::App) { diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 69ad9c0..ef0c0a9 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -1,3 +1,2 @@ pub mod file_watcher; -pub mod observable; pub mod paths; diff --git a/src-tauri/src/utils/observable.rs b/src-tauri/src/utils/observable.rs deleted file mode 100644 index b4d3c15..0000000 --- a/src-tauri/src/utils/observable.rs +++ /dev/null @@ -1,269 +0,0 @@ -use std::fmt::Debug; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::{cell::RefCell, collections::HashMap, hash::Hash, ops::Deref}; - -static NEXT_SUBSCRIPTION_ID: AtomicUsize = AtomicUsize::new(0); - -type BoxedCallback<'a, T> = Box Response + 'a + Send>; -type SubscriptionId = usize; - -#[derive(Debug)] -pub struct Observable<'o, T> { - value: T, - delegate: Delegate<'o, T>, -} - -#[derive(Default)] -pub struct Delegate<'d, T> { - subscriptions: RefCell>>, -} - -#[derive(Eq, Hash, PartialEq)] -pub struct Subscription { - id: SubscriptionId, -} - -pub enum Response { - StaySubscribed, - CancelSubscription, -} - -impl<'d, T> Delegate<'d, T> { - fn new() -> Self { - Self { - subscriptions: RefCell::new(HashMap::new()), - } - } - - pub fn subscribe Response + 'd + Send>(&self, callback: C) -> Subscription { - let id = NEXT_SUBSCRIPTION_ID.fetch_add(1, Ordering::SeqCst); - let subscription = Subscription { id }; - self.subscriptions - .borrow_mut() - .insert(subscription.id, Box::new(callback)); - subscription - } - - pub fn unsubscribe(&self, subscription: &Subscription) { - self.subscriptions.borrow_mut().remove(&subscription.id); - } - - pub fn broadcast(&self, value: &T) { - let subscriptions_to_notify = self - .subscriptions - .borrow() - .keys() - .copied() - .collect::>(); - for subscription in subscriptions_to_notify { - let (_, mut callback) = self - .subscriptions - .borrow_mut() - .remove_entry(&subscription) - .unwrap(); - match callback(value) { - Response::CancelSubscription => (), - Response::StaySubscribed => { - self.subscriptions - .borrow_mut() - .insert(subscription, callback); - } - }; - } - } -} - -impl<'o, T> Observable<'o, T> { - fn new(value: T) -> Self { - Self { - value, - delegate: Delegate { - subscriptions: Default::default(), - }, - } - } - - pub fn subscribe Response + 'o + Send>(&self, callback: C) -> Subscription { - self.delegate.subscribe(callback) - } - - pub fn unsubscribe(&self, subscription: &Subscription) { - self.delegate.unsubscribe(subscription); - } - - pub fn delegate(&self) -> &Delegate<'o, T> { - &self.delegate - } - - pub fn mutate(&mut self, mutation: M) - where - M: FnOnce(&mut T), - { - mutation(&mut self.value); - self.delegate.broadcast(&self.value); - } -} - -impl Delegate<'_, ()> { - pub fn notify(&self) { - self.broadcast(&()); - } -} - -impl Debug for Delegate<'_, T> -where - T: Debug, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Delegate") - .field( - "subscriptions", - &format_args!("{} active subscriptions", self.subscriptions.borrow().len()), - ) - .finish() - } -} - -impl Default for Observable<'_, T> -where - T: Default, -{ - fn default() -> Self { - Self::new(Default::default()) - } -} - -impl Deref for Observable<'_, T> { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.value - } -} - -#[cfg(test)] -mod test { - - use parking_lot::ReentrantMutex; - use std::{cell::RefCell, ops::Deref, sync::Arc}; - - use super::*; - - #[test] - fn delegate_can_notify_subscribers() { - let mut call_count = 0; - { - let d = Delegate::new(); - d.subscribe(|_| { - call_count += 1; - Response::StaySubscribed - }); - d.notify(); - d.notify(); - d.notify(); - } - assert_eq!(call_count, 3); - } - - #[test] - fn delegate_no_longer_notifies_after_unsubscribe() { - let mut call_count = 0; - { - let d = Delegate::new(); - let subscription = d.subscribe(|_| { - call_count += 1; - Response::StaySubscribed - }); - d.unsubscribe(&subscription); - d.notify(); - } - assert_eq!(call_count, 0); - } - - #[test] - fn cannot_unsubscribe_using_subscription_from_a_different_delegate() { - let mut call_count = 0; - { - let d1 = Delegate::<()>::new(); - let d2 = Delegate::<()>::new(); - let _s1 = d1.subscribe(|_| { - call_count += 1; - Response::StaySubscribed - }); - let s2 = d2.subscribe(|_| Response::StaySubscribed); - d1.unsubscribe(&s2); - d1.notify(); - } - assert_eq!(call_count, 1); - } - - #[test] - fn unsubscribe_within_callback_is_noop() { - let d = Arc::new(ReentrantMutex::new(Delegate::new())); - let call_count = Arc::new(ReentrantMutex::new(RefCell::new(0))); - let subscription = Arc::new(ReentrantMutex::new(RefCell::new(None))); - - let d_clone = d.clone(); - let call_count_clone = call_count.clone(); - let subscription_clone = subscription.clone(); - - subscription - .lock() - .replace(Some(d.lock().subscribe(move |_| { - let old_count = *call_count_clone.lock().borrow(); - *call_count_clone.lock().borrow_mut() = old_count + 1; - d_clone - .lock() - .unsubscribe(subscription_clone.lock().deref().borrow().as_ref().unwrap()); - Response::StaySubscribed - }))); - - d.lock().notify(); - d.lock().notify(); - assert_eq!(*call_count.lock().borrow(), 2); - } - - #[test] - fn can_unsubscribe_using_callback_return_value() { - let mut call_count = 0; - { - let d = Delegate::new(); - d.subscribe(|_| { - call_count += 1; - Response::CancelSubscription - }); - d.notify(); - d.notify(); - } - assert_eq!(call_count, 1); - } - - #[test] - fn observable_notifies_after_mutation() { - let mut call_count = 0; - { - let mut o = Observable::new(0); - o.subscribe(|_| { - call_count += 1; - Response::StaySubscribed - }); - o.mutate(|value| *value = 42); - } - assert_eq!(call_count, 1); - } - - #[test] - fn observable_no_longer_notifies_after_unsubscribe() { - let mut call_count = 0; - { - let mut o = Observable::new(0); - let s = o.subscribe(|_| { - call_count += 1; - Response::StaySubscribed - }); - o.mutate(|value| *value = 42); - o.unsubscribe(&s); - o.mutate(|value| *value = 43); - } - assert_eq!(call_count, 1); - } -} From 3c5593dc705d8a4d572df1b7a639465726601a1d Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Sat, 3 Dec 2022 17:38:48 -0800 Subject: [PATCH 03/77] Updated roadmap --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 21cb4a2..0c273b6 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -28,7 +28,6 @@ ## Tiger 0.9 - [ ] Document keyboard shortcuts -- [ ] Can preview export image and metadata output - [ ] More template file examples in documentation - [ ] Documentation about use of file paths in .tiger files - [ ] Auto-updates @@ -57,6 +56,7 @@ - [ ] Root motion - [ ] Onion skin? - [ ] Hitbox colors +- [ ] Can preview export image and metadata output - [ ] Interop with specific game engines (TBD) - [ ] Import frames from single sheet image - [ ] Import animation data from other software (Asesprite, TBD) From 677e619f8880a32a757900b7f6a263737d103c3b Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Sun, 4 Dec 2022 16:25:38 -0800 Subject: [PATCH 04/77] Fixed error log line when confirming a renaming by pressing enter --- src/components/basic/InputRename.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/basic/InputRename.vue b/src/components/basic/InputRename.vue index 7b95bb2..d15ab1e 100644 --- a/src/components/basic/InputRename.vue +++ b/src/components/basic/InputRename.vue @@ -9,7 +9,7 @@ import { computed, Ref, ref } from "@vue/reactivity" import { onMounted } from "vue" -type RenameState = "active" | "cancelled"; +type RenameState = "active" | "cancelled" | "complete"; const props = defineProps(["modelValue"]) const emit = defineEmits(["update:modelValue", "completeRename", "cancelRename"]) @@ -33,7 +33,8 @@ onMounted(() => { }); function onRenameInputComplete() { - if (state.value != "cancelled") { + if (state.value == "active") { + state.value = "complete"; emit("completeRename", { newName: props.modelValue }); } } From 38e62a6f0acbef405228df5a51a01d85f9299603 Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Sun, 4 Dec 2022 18:24:13 -0800 Subject: [PATCH 05/77] Can press F2 to rename animations or hitboxes --- ROADMAP.md | 2 +- src-tauri/src/api.rs | 80 ++++++++++++++++----- src-tauri/src/document.rs | 4 ++ src-tauri/src/document/command.rs | 34 ++++++--- src-tauri/src/document/selection.rs | 8 +++ src-tauri/src/document/transient.rs | 96 +++++++++++++++++++++++++ src-tauri/src/dto.rs | 4 ++ src-tauri/src/main.rs | 12 ++-- src/api/document.ts | 62 +++++++++------- src/api/dto.ts | 2 + src/components/animations/Animation.vue | 27 +++---- src/components/keyframe/Hitbox.vue | 27 +++---- src/utils/keyboard.ts | 5 +- 13 files changed, 277 insertions(+), 86 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 0c273b6..fc65c78 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -3,7 +3,7 @@ ## Tiger 0.7 - [ ] Tooltips everywhere -- [ ] Can press F2 to rename animations or hitboxes +- [x] Can press F2 to rename animations or hitboxes - [ ] Workbench zoom keeps screen center (mouse cursor when applicable) invariant (not origin) - [ ] Timeline zoom keeps current position invariant - [ ] Can zoom workbench with mousewheel diff --git a/src-tauri/src/api.rs b/src-tauri/src/api.rs index 37b95dc..250a566 100644 --- a/src-tauri/src/api.rs +++ b/src-tauri/src/api.rs @@ -786,15 +786,74 @@ pub fn edit_animation(app_state: tauri::State<'_, AppState>, name: String) -> Re } #[tauri::command] -pub fn rename_animation( +pub fn begin_rename_animation( + app_state: tauri::State<'_, AppState>, + animation_name: String, +) -> Result { + Ok(app_state.mutate(AppTrim::Full, |app| { + if let Some(document) = app.current_document_mut() { + document + .process_command(Command::BeginRenameAnimation(animation_name)) + .ok(); + } + })) +} + +#[tauri::command] +pub fn begin_rename_hitbox( + app_state: tauri::State<'_, AppState>, + hitbox_name: String, +) -> Result { + Ok(app_state.mutate(AppTrim::Full, |app| { + if let Some(document) = app.current_document_mut() { + document + .process_command(Command::BeginRenameHitbox(hitbox_name)) + .ok(); + } + })) +} + +#[tauri::command] +pub fn begin_rename_selection(app_state: tauri::State<'_, AppState>) -> Result { + Ok(app_state.mutate(AppTrim::Full, |app| { + if let Some(document) = app.current_document_mut() { + document.process_command(Command::BeginRenameSelection).ok(); + } + })) +} + +#[tauri::command] +pub fn cancel_rename(app_state: tauri::State<'_, AppState>) -> Result { + Ok(app_state.mutate(AppTrim::Full, |app| { + if let Some(document) = app.current_document_mut() { + document.process_command(Command::CancelRename).ok(); + } + })) +} + +#[tauri::command] +pub fn end_rename_animation( + app_state: tauri::State<'_, AppState>, + new_name: String, +) -> Result { + Ok(app_state.mutate(AppTrim::Full, |app| { + if let Some(document) = app.current_document_mut() { + document + .process_command(Command::EndRenameAnimation(new_name)) + .ok(); + } + })) +} + +#[tauri::command] +pub fn end_rename_hitbox( app_state: tauri::State<'_, AppState>, - old_name: String, new_name: String, ) -> Result { Ok(app_state.mutate(AppTrim::Full, |app| { if let Some(document) = app.current_document_mut() { document - .process_command(Command::RenameAnimation(old_name, new_name)) + .process_command(Command::EndRenameHitbox(new_name)) .ok(); } })) @@ -1265,21 +1324,6 @@ pub fn create_hitbox( })) } -#[tauri::command] -pub fn rename_hitbox( - app_state: tauri::State<'_, AppState>, - old_name: String, - new_name: String, -) -> Result { - Ok(app_state.mutate(AppTrim::Full, |app| { - if let Some(document) = app.current_document_mut() { - document - .process_command(Command::RenameHitbox(old_name, new_name)) - .ok(); - } - })) -} - #[tauri::command] pub fn delete_hitbox(app_state: tauri::State<'_, AppState>, name: String) -> Result { Ok(app_state.mutate(AppTrim::Full, |app| { diff --git a/src-tauri/src/document.rs b/src-tauri/src/document.rs index 8b6ea03..3051c6e 100644 --- a/src-tauri/src/document.rs +++ b/src-tauri/src/document.rs @@ -57,6 +57,10 @@ pub enum DocumentError { NoKeyframeAtTime(Duration), #[error("Sequence does not have a keyframe at index `{0}`")] NoKeyframeAtIndex(usize), + #[error("Not currently renaming an animation")] + NotRenamingAnyAnimation, + #[error("Not currently renaming a hitbox")] + NotRenamingAnyHitbox, #[error("Not currently editing an animation")] NotEditingAnyAnimation, #[error("Not currently editing a sequence")] diff --git a/src-tauri/src/document/command.rs b/src-tauri/src/document/command.rs index ad1f8ee..c50ab63 100644 --- a/src-tauri/src/document/command.rs +++ b/src-tauri/src/document/command.rs @@ -41,7 +41,12 @@ pub enum Command { ShowOrigin, CreateAnimation, EditAnimation(String), - RenameAnimation(String, String), + BeginRenameSelection, + BeginRenameAnimation(String), + BeginRenameHitbox(String), + CancelRename, + EndRenameAnimation(String), + EndRenameHitbox(String), DeleteAnimation(String), DeleteSelectedAnimations, Tick(Duration), @@ -80,7 +85,6 @@ pub enum Command { UpdateNudgeKeyframe(Vector2D, bool), EndNudgeKeyframe(), CreateHitbox(Option>), - RenameHitbox(String, String), DeleteHitbox(String), DeleteSelectedHitboxes, LockHitboxes, @@ -151,9 +155,12 @@ impl Document { Command::ShowOrigin => self.view.hide_origin = false, Command::CreateAnimation => self.create_animation()?, Command::EditAnimation(ref name) => self.edit_animation(name)?, - Command::RenameAnimation(ref old_name, ref new_name) => { - self.rename_animation(old_name, new_name)? - } + Command::BeginRenameSelection => self.begin_rename_selection(), + Command::BeginRenameAnimation(ref n) => self.begin_rename_animation(n.clone()), + Command::BeginRenameHitbox(ref n) => self.begin_rename_hitbox(n.clone()), + Command::CancelRename => self.cancel_rename(), + Command::EndRenameAnimation(ref n) => self.end_rename_animation(n.clone())?, + Command::EndRenameHitbox(ref n) => self.end_rename_hitbox(n.clone())?, Command::DeleteAnimation(ref name) => self.delete_animation(name), Command::DeleteSelectedAnimations => self.delete_selected_animations(), Command::Tick(dt) => self.advance_timeline(dt), @@ -200,9 +207,6 @@ impl Document { Command::UpdateNudgeKeyframe(d, b) => self.update_nudge_keyframe(d, b)?, Command::EndNudgeKeyframe() => self.end_nudge_keyframe(), Command::CreateHitbox(p) => self.create_hitbox(p)?, - Command::RenameHitbox(ref old_name, ref new_name) => { - self.rename_hitbox(old_name, new_name)? - } Command::DeleteHitbox(ref name) => self.delete_hitbox(name)?, Command::DeleteSelectedHitboxes => self.delete_selected_hitboxes()?, Command::LockHitboxes => self.view.lock_hitboxes = true, @@ -245,6 +249,10 @@ impl Document { Command::Tick(_) | Command::Undo | Command::Redo + | Command::BeginRenameAnimation(_) + | Command::BeginRenameHitbox(_) + | Command::BeginRenameSelection + | Command::CancelRename | Command::BeginDragAndDropFrame(_) | Command::BeginDragAndDropKeyframe(_, _) | Command::BeginDragKeyframeDuration(_, _) @@ -413,7 +421,6 @@ impl Display for Command { Command::NudgeSelection(_, _) => f.write_str("Nudge"), Command::CreateAnimation => f.write_str("Create Animation"), Command::EditAnimation(_) => f.write_str("Open Animation"), - Command::RenameAnimation(_, _) => f.write_str("Rename Animation"), Command::DeleteAnimation(_) => f.write_str("Delete Animation"), Command::DeleteSelectedAnimations => f.write_str("Delete Animations"), Command::Tick(_) => f.write_str("Tick"), @@ -427,7 +434,6 @@ impl Display for Command { Command::SetKeyframeOffsetX(_) => f.write_str("Start Keyframe X Offset"), Command::SetKeyframeOffsetY(_) => f.write_str("Start Keyframe Y Offset"), Command::CreateHitbox(_) => f.write_str("Create Hitbox"), - Command::RenameHitbox(_, _) => f.write_str("Rename Hitbox"), Command::DeleteHitbox(_) => f.write_str("Delete Hitbox"), Command::DeleteSelectedHitboxes => f.write_str("Delete Hitboxes"), Command::LockHitboxes => f.write_str("Lock Hitboxes"), @@ -469,6 +475,14 @@ impl Display for Command { Command::BeginResizeHitbox(_, _) | Command::UpdateResizeHitbox(_, _) | Command::EndResizeHitbox => f.write_str("Resize Hitbox"), + + Command::BeginRenameSelection + | Command::BeginRenameAnimation(_) + | Command::BeginRenameHitbox(_) + | Command::CancelRename => f.write_str("Rename"), + + Command::EndRenameAnimation(_) => f.write_str("Rename Animation"), + Command::EndRenameHitbox(_) => f.write_str("Rename Hitbox"), } } } diff --git a/src-tauri/src/document/selection.rs b/src-tauri/src/document/selection.rs index d46daad..c197f80 100644 --- a/src-tauri/src/document/selection.rs +++ b/src-tauri/src/document/selection.rs @@ -53,6 +53,14 @@ impl Document { Ok(()) } + pub(super) fn begin_rename_selection(&mut self) { + if let Some(ref name) = self.view.selection.animations.last_interacted { + self.begin_rename_animation(name.clone()); + } else if let Some((_, _, _, ref name)) = self.view.selection.hitboxes.last_interacted { + self.begin_rename_hitbox(name.clone()); + } + } + pub(super) fn nudge_selection( &mut self, direction: NudgeDirection, diff --git a/src-tauri/src/document/transient.rs b/src-tauri/src/document/transient.rs index 8cb4a36..362c773 100644 --- a/src-tauri/src/document/transient.rs +++ b/src-tauri/src/document/transient.rs @@ -45,8 +45,15 @@ pub(super) struct HitboxResize { pub(super) original_positions: HashMap>, } +#[derive(Clone, Debug)] +pub(super) enum Rename { + Animation(String), + Hitbox(String), +} + #[derive(Debug, Default)] pub struct Transient { + pub(super) rename: Option, pub(super) frame_drag_and_drop: Option, pub(super) keyframe_duration_drag: Option, pub(super) keyframe_drag_and_drop: Option<(Direction, usize)>, @@ -56,6 +63,50 @@ pub struct Transient { } impl Document { + pub(super) fn begin_rename_animation(&mut self, animation_name: String) { + self.transient.rename = Some(Rename::Animation(animation_name)); + } + + pub(super) fn end_rename_animation(&mut self, new_name: String) -> DocumentResult<()> { + if let Some(Rename::Animation(old_name)) = self.transient.rename.clone() { + self.transient.rename = None; + self.rename_animation(old_name, new_name) + } else { + Err(DocumentError::NotRenamingAnyAnimation) + } + } + + pub(super) fn begin_rename_hitbox(&mut self, hitbox_name: String) { + self.transient.rename = Some(Rename::Hitbox(hitbox_name)); + } + + pub(super) fn end_rename_hitbox(&mut self, new_name: String) -> DocumentResult<()> { + if let Some(Rename::Hitbox(old_name)) = self.transient.rename.clone() { + self.transient.rename = None; + self.rename_hitbox(old_name, new_name) + } else { + Err(DocumentError::NotRenamingAnyHitbox) + } + } + + pub(super) fn cancel_rename(&mut self) { + self.transient.rename = None; + } + + pub fn animation_being_renamed(&self) -> Option<&String> { + match self.transient.rename { + Some(Rename::Animation(ref n)) => Some(n), + _ => None, + } + } + + pub fn hitbox_being_renamed(&self) -> Option<&String> { + match self.transient.rename { + Some(Rename::Hitbox(ref n)) => Some(n), + _ => None, + } + } + pub(super) fn begin_drag_and_drop_frame(&mut self, frame: PathBuf) { if !self.view.selection.is_frame_selected(&frame) { self.select_frame_only(frame.clone()); @@ -706,6 +757,51 @@ impl ResizeAxis { } } +#[test] +fn can_rename_animations() { + use std::path::Path; + + let mut d = Document::new("tmp"); + d.sheet + .add_test_animation::<_, &Path>("walk_cycle", HashMap::new()); + d.select_animation("walk_cycle", false, false); + d.begin_rename_selection(); + assert_eq!("walk_cycle", d.animation_being_renamed().unwrap().as_str()); + d.end_rename_animation("renamed".to_owned()).unwrap(); + assert_eq!(None, d.animation_being_renamed()); + + assert!(d.sheet().animation("renamed").is_some()); +} + +#[test] +fn can_rename_hitboxes() { + let mut d = Document::new("tmp"); + d.sheet.add_frames(&vec!["walk_0", "walk_1", "walk_2"]); + d.sheet.add_test_animation( + "walk_cycle", + HashMap::from([(Direction::North, vec!["walk_0", "walk_1", "walk_2"])]), + ); + let keyframe = d.sheet.keyframe_mut("walk_cycle", Direction::North, 0); + keyframe.create_hitbox("my_hitbox"); + + d.edit_animation("walk_cycle").unwrap(); + d.select_hitbox("my_hitbox", false, false).unwrap(); + d.begin_rename_selection(); + assert_eq!("my_hitbox", d.hitbox_being_renamed().unwrap().as_str()); + d.end_rename_hitbox("renamed".to_owned()).unwrap(); + assert_eq!(None, d.hitbox_being_renamed()); + + assert!(d + .sheet() + .animation("walk_cycle") + .unwrap() + .sequence(Direction::North) + .unwrap() + .keyframe(0) + .unwrap() + .has_hitbox("renamed")); +} + #[test] fn can_drag_and_drop_frame_to_timeline() { use std::path::Path; diff --git a/src-tauri/src/dto.rs b/src-tauri/src/dto.rs index a5a68cc..2f00fe1 100644 --- a/src-tauri/src/dto.rs +++ b/src-tauri/src/dto.rs @@ -76,6 +76,8 @@ pub struct Document { hide_origin: bool, lock_hitboxes: bool, preserve_aspect_ratio: bool, + animation_being_renamed: Option, + hitbox_being_renamed: Option, is_dragging_keyframe_duration: bool, frames_being_dragged: HashSet, keyframes_being_dragged: HashSet<(Direction, usize)>, @@ -406,6 +408,8 @@ impl document::Document { hide_origin: self.is_hiding_origin(), lock_hitboxes: self.are_hitboxes_locked(), preserve_aspect_ratio: self.preserves_aspect_ratio(), + animation_being_renamed: self.animation_being_renamed().cloned(), + hitbox_being_renamed: self.hitbox_being_renamed().cloned(), is_dragging_keyframe_duration: self.is_dragging_keyframe_duration(), frames_being_dragged: self.frames_being_dragged(), keyframes_being_dragged: self diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 042c7a5..8473ebd 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -74,9 +74,13 @@ fn main() { api::begin_export_as, api::begin_nudge_hitbox, api::begin_nudge_keyframe, + api::begin_rename_animation, + api::begin_rename_hitbox, + api::begin_rename_selection, api::begin_resize_hitbox, api::browse_selection, api::cancel_export_as, + api::cancel_rename, api::center_workbench, api::clear_selection, api::close_without_saving, @@ -103,6 +107,8 @@ fn main() { api::end_export_as, api::end_nudge_hitbox, api::end_nudge_keyframe, + api::end_rename_animation, + api::end_rename_hitbox, api::end_resize_hitbox, api::export, api::filter_animations, @@ -122,8 +128,6 @@ fn main() { api::pause, api::play, api::redo, - api::rename_animation, - api::rename_hitbox, api::reset_timeline_zoom, api::reset_workbench_zoom, api::save_as, @@ -147,10 +151,10 @@ fn main() { api::set_keyframe_duration, api::set_keyframe_offset_x, api::set_keyframe_offset_y, + api::set_keyframe_snapping_base_duration, api::set_snap_keyframe_durations, - api::set_snap_keyframes_to_other_keyframes, api::set_snap_keyframes_to_multiples_of_duration, - api::set_keyframe_snapping_base_duration, + api::set_snap_keyframes_to_other_keyframes, api::set_timeline_zoom_amount, api::set_workbench_zoom_factor, api::show_hitboxes, diff --git a/src/api/document.ts b/src/api/document.ts index f9c6789..a93cb27 100644 --- a/src/api/document.ts +++ b/src/api/document.ts @@ -86,6 +86,42 @@ export async function deleteSelection(): Promise { appStore.patch(await invoke("delete_selection")); } +export async function beginRenameSelection(): Promise { + const appStore = useAppStore(); + appStore.patch(await invoke("begin_rename_selection")); +} + +export async function beginRenameAnimation( + animationName: String +): Promise { + const appStore = useAppStore(); + appStore.patch( + await invoke("begin_rename_animation", { animationName: animationName }) + ); +} + +export async function beginRenameHitbox(hitboxName: String): Promise { + const appStore = useAppStore(); + appStore.patch( + await invoke("begin_rename_hitbox", { hitboxName: hitboxName }) + ); +} + +export async function endRenameAnimation(newName: String): Promise { + const appStore = useAppStore(); + appStore.patch(await invoke("end_rename_animation", { newName: newName })); +} + +export async function endRenameHitbox(newName: String): Promise { + const appStore = useAppStore(); + appStore.patch(await invoke("end_rename_hitbox", { newName: newName })); +} + +export async function cancelRename(): Promise { + const appStore = useAppStore(); + appStore.patch(await invoke("cancel_rename")); +} + export async function nudgeSelection( direction: NudgeDirection, largeNudge: boolean @@ -263,19 +299,6 @@ export async function editAnimation(name: string): Promise { appStore.patch(await invoke("edit_animation", { name: name })); } -export async function renameAnimation( - oldName: string, - newName: string -): Promise { - const appStore = useAppStore(); - appStore.patch( - await invoke("rename_animation", { - oldName: oldName, - newName: newName, - }) - ); -} - export async function deleteAnimation(name: string): Promise { const appStore = useAppStore(); appStore.patch(await invoke("delete_animation", { name: name })); @@ -542,19 +565,6 @@ export async function createHitbox( appStore.patch(await invoke("create_hitbox", { position: position })); } -export async function renameHitbox( - oldName: string, - newName: string -): Promise { - const appStore = useAppStore(); - appStore.patch( - await invoke("rename_hitbox", { - oldName: oldName, - newName: newName, - }) - ); -} - export async function deleteHitbox(name: string): Promise { const appStore = useAppStore(); appStore.patch(await invoke("delete_hitbox", { name: name })); diff --git a/src/api/dto.ts b/src/api/dto.ts index b4f662c..b23e704 100644 --- a/src/api/dto.ts +++ b/src/api/dto.ts @@ -60,6 +60,8 @@ export type Document = { lockHitboxes: boolean; preserveAspectRatio: boolean; isDraggingKeyframeDuration: boolean; + animationBeingRenamed: string | null; + hitboxBeingRenamed: string | null; framesBeingDragged: string[]; keyframesBeingDragged: [Direction, number][]; hitboxesBeingNudged: string[]; diff --git a/src/components/animations/Animation.vue b/src/components/animations/Animation.vue index a38e28e..2804ded 100644 --- a/src/components/animations/Animation.vue +++ b/src/components/animations/Animation.vue @@ -8,8 +8,7 @@ { icon: XMarkIcon, callback: onDeleteClicked } ]"> @@ -17,10 +16,11 @@ \ No newline at end of file diff --git a/src/components/workbench/WorkbenchPane.vue b/src/components/workbench/WorkbenchPane.vue index 919102e..c65b95a 100644 --- a/src/components/workbench/WorkbenchPane.vue +++ b/src/components/workbench/WorkbenchPane.vue @@ -25,7 +25,7 @@ --> + class="flex-1 graph-paper h-full pointer-events-auto transition-all" :style="graphPaperStyle" />
- +
{{ app.currentAnimation?.name }}
@@ -49,8 +50,9 @@ import { onUnmounted, watch } from "vue" import { computed, Ref, ref } from "@vue/reactivity" import { Direction, Keyframe, Hitbox as HitboxDTO } from "@/api/dto" import { closeDocument, focusDocument } from "@/api/app" -import { clearSelection, disableSpriteDarkening, enableSpriteDarkening, pan, zoomInWorkbench, zoomOutWorkbench } from "@/api/document" +import { clearSelection, pan } from "@/api/document" import { useAppStore } from "@/stores/app" +import { isStable } from "@/utils/animation" import DragArea, { DragAreaEvent } from "@/components/basic/DragArea.vue" import Pane from "@/components/basic/Pane.vue" import PaneTab from "@/components/basic/PaneTab.vue" @@ -62,12 +64,15 @@ import Toolbar from "@/components/workbench/Toolbar.vue" const app = useAppStore(); const drawingArea: Ref = ref(null); -const drawingAreaSize = ref([0, 0]); +const drawingAreaHalfSize = ref([0, 0]); +const zoom = computed(() => app.currentDocument?.workbenchZoom || 1); +const workbenchOffset = computed(() => app.currentDocument?.workbenchOffset || [0, 0]); +const isZoomStable = isStable([zoom]); const resizeObserver = new ResizeObserver(entries => { for (let entry of entries) { if (entry.target === drawingArea.value) { - drawingAreaSize.value = [entry.contentRect.width, entry.contentRect.height]; + drawingAreaHalfSize.value = [entry.contentRect.width / 2, entry.contentRect.height / 2]; } } }); @@ -75,9 +80,11 @@ const resizeObserver = new ResizeObserver(entries => { watch(drawingArea, (newArea, oldArea) => { if (oldArea) { resizeObserver.unobserve(oldArea); + oldArea.removeEventListener("wheel", onWheel); } if (newArea) { resizeObserver.observe(newArea); + newArea.addEventListener("wheel", onWheel); } }); @@ -86,30 +93,35 @@ onUnmounted(() => { }); const graphPaperStyle = computed(() => { + const x = drawingAreaHalfSize.value[0] + workbenchOffset.value[0] * zoom.value; + const y = drawingAreaHalfSize.value[1] + workbenchOffset.value[1] * zoom.value; return { - "background-position": `${origin.value[0]}px ${origin.value[1]}px`, + backgroundPosition: `${x}px ${y}px`, + transitionProperty: isZoomStable.value ? "none" : "background-position", } }); -const origin = computed((): [number, number] => { - const workbenchOffset = app.currentDocument?.workbenchOffset || [0, 0]; - return [ - Math.floor(drawingAreaSize.value[0] / 2) + workbenchOffset[0], - Math.floor(drawingAreaSize.value[1] / 2) + workbenchOffset[1], - ]; +const originTransform = computed(() => { + const x = drawingAreaHalfSize.value[0] + workbenchOffset.value[0] * zoom.value; + const y = drawingAreaHalfSize.value[1] + workbenchOffset.value[1] * zoom.value; + return { + transform: `translate(${x}px, ${y}px)`, + transitionProperty: isZoomStable.value ? "none" : "transform", + }; }); const zoomTransform = computed(() => { - const zoom = app.currentDocument?.workbenchZoom || 1; return { - transform: `scale(${zoom}, ${zoom})`, - transformOrigin: `${origin.value[0]}px ${origin.value[1]}px`, + transform: `scale(${zoom.value}, ${zoom.value})`, + transformOrigin: `${drawingAreaHalfSize.value[0]}px ${drawingAreaHalfSize.value[1]}px`, }; }); const panningTransform = computed(() => { + const x = drawingAreaHalfSize.value[0] + workbenchOffset.value[0]; + const y = drawingAreaHalfSize.value[1] + workbenchOffset.value[1]; return { - transform: `translate(${origin.value[0]}px, ${origin.value[1]}px)`, + transform: `translate(${x}px, ${y}px)`, }; }); @@ -127,7 +139,6 @@ const allAnimationKeyframes = computed((): { direction: Direction, index: number return keyframes; }); - const sortedHitboxes = computed((): HitboxDTO[] => { if (!app.currentKeyframe) { return []; @@ -154,6 +165,13 @@ function onClick() { function updatePanning(event: DragAreaEvent) { pan([event.mouseEvent.movementX, event.mouseEvent.movementY]); } + +function onWheel(event: WheelEvent) { + if (!event.ctrlKey) { + return; + } + // TODO +} \ No newline at end of file + diff --git a/src/components/keyframe/KeyframePane.vue b/src/components/keyframe/KeyframePane.vue index c74a725..01ddf26 100644 --- a/src/components/keyframe/KeyframePane.vue +++ b/src/components/keyframe/KeyframePane.vue @@ -5,8 +5,10 @@
- + + +
@@ -40,6 +42,7 @@ import PaneInset from "@/components/basic/PaneInset.vue" import Hitbox from "@/components/keyframe/Hitbox.vue"; import StatefulScroll from "@/components/basic/StatefulScroll.vue" import Toggle from "@/components/basic/Toggle.vue" +import TooltipArea from "@/components/basic/TooltipArea.vue" const app = useAppStore(); const contextMenu: Ref = ref(null); @@ -85,4 +88,4 @@ function onOpenContextMenu(event: MouseEvent) { contextMenu.value.show(event); } } - \ No newline at end of file + diff --git a/src/components/timeline/TimelinePane.vue b/src/components/timeline/TimelinePane.vue index 4ab6da9..d624aa6 100644 --- a/src/components/timeline/TimelinePane.vue +++ b/src/components/timeline/TimelinePane.vue @@ -3,19 +3,23 @@
- + + +
- - - + + + + +
@@ -70,6 +74,7 @@ import Slider from "@/components/basic/Slider.vue" import Pane from "@/components/basic/Pane.vue" import PaneInset from "@/components/basic/PaneInset.vue" import Toggle from "@/components/basic/Toggle.vue" +import TooltipArea from "@/components/basic/TooltipArea.vue" import PerspectivePicker from "@/components/timeline/PerspectivePicker.vue" import PlaybackControls from "@/components/timeline/PlaybackControls.vue" import Ruler from "@/components/timeline/Ruler.vue" diff --git a/src/components/workbench/Toolbar.vue b/src/components/workbench/Toolbar.vue index 47be62d..fd2058d 100644 --- a/src/components/workbench/Toolbar.vue +++ b/src/components/workbench/Toolbar.vue @@ -6,11 +6,19 @@ outline outline-4 outline-neutral-900 "> - + + +
- - - + + + + + + + + +
@@ -22,6 +30,7 @@ import { disableSpriteDarkening, enableSpriteDarkening, hideHitboxes, hideOrigin import { useAppStore } from "@/stores/app" import FlatMultiSwitch, { FlatMultiSwitchItem } from "@/components/basic/FlatMultiSwitch.vue"; import FlatToggle from "@/components/basic/FlatToggle.vue" +import TooltipArea from "@/components/basic/TooltipArea.vue" const app = useAppStore(); @@ -87,4 +96,4 @@ const drawOrigin: WritableComputedRef = computed({ } }, }); - \ No newline at end of file + From 2c5e3b1fed38cbe99480d676c592fa47f09c0881 Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Mon, 26 Dec 2022 15:35:51 +0100 Subject: [PATCH 56/77] Added selection tests for deletion / nudge --- src-tauri/src/document/selection.rs | 43 +++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src-tauri/src/document/selection.rs b/src-tauri/src/document/selection.rs index 8f2a885..95b24c1 100644 --- a/src-tauri/src/document/selection.rs +++ b/src-tauri/src/document/selection.rs @@ -1204,4 +1204,47 @@ mod test { to_set(vec!["0d", "1a", "1b", "1c", "1d", "2a", "2b", "2c"]) ); } + + #[test] + fn can_delete_selection_frames() { + let mut d = Document::new("tmp"); + d.sheet.add_frames(&vec!["A", "B", "C"]); + d.select_frame("B", false, false); + assert!(d.sheet.frame("B").is_some()); + d.delete_selection().unwrap(); + assert_eq!(d.sheet.frames_iter().count(), 2); + assert!(d.sheet.frame("B").is_none()); + } + + #[test] + fn can_nudge_keyframe() { + let mut d = Document::new("tmp"); + d.sheet.add_frames(&vec!["walk_0", "walk_1", "walk_2"]); + d.sheet.add_test_animation( + "walk_cycle", + HashMap::from([(Direction::North, vec!["walk_0", "walk_1", "walk_2"])]), + ); + d.edit_animation("walk_cycle").unwrap(); + d.select_keyframes_only(vec![("walk_cycle".to_owned(), Direction::North, 1)]); + d.nudge_selection(NudgeDirection::Up, true).unwrap(); + assert_eq!( + d.selected_keyframes().unwrap().get(0).unwrap().2.offset(), + vec2(0, -10) + ); + d.nudge_selection(NudgeDirection::Right, false).unwrap(); + assert_eq!( + d.selected_keyframes().unwrap().get(0).unwrap().2.offset(), + vec2(1, -10) + ); + d.nudge_selection(NudgeDirection::Left, true).unwrap(); + assert_eq!( + d.selected_keyframes().unwrap().get(0).unwrap().2.offset(), + vec2(-9, -10) + ); + d.nudge_selection(NudgeDirection::Down, false).unwrap(); + assert_eq!( + d.selected_keyframes().unwrap().get(0).unwrap().2.offset(), + vec2(-9, -9) + ); + } } From f6ebb1eadff6950d8e69277332217bc08d40554c Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Mon, 26 Dec 2022 16:10:09 +0100 Subject: [PATCH 57/77] Added test for browsing keyframes --- src-tauri/src/document/selection.rs | 51 +++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src-tauri/src/document/selection.rs b/src-tauri/src/document/selection.rs index 95b24c1..5885f7a 100644 --- a/src-tauri/src/document/selection.rs +++ b/src-tauri/src/document/selection.rs @@ -1205,6 +1205,57 @@ mod test { ); } + #[test] + fn can_browse_keyframes() { + let to_set = |v: Vec<(Direction, usize)>| { + v.into_iter() + .map(|(d, i)| ("walk_cycle".into(), d, i)) + .collect() + }; + + let mut d = Document::new("tmp"); + d.sheet.add_frames(&vec!["walk_0", "walk_1", "walk_2"]); + d.sheet.add_test_animation( + "walk_cycle", + HashMap::from([ + (Direction::North, vec!["walk_0", "walk_1", "walk_2"]), + (Direction::South, vec!["walk_0", "walk_1", "walk_2"]), + ]), + ); + d.edit_animation("walk_cycle").unwrap(); + + { + d.select_keyframe(Direction::North, 1, false, false) + .unwrap(); + d.browse_selection(BrowseDirection::Right, false).unwrap(); + assert_eq!( + d.view.selection.keyframes.selected_items, + to_set(vec![(Direction::North, 2)]) + ); + d.browse_selection(BrowseDirection::Left, false).unwrap(); + assert_eq!( + d.view.selection.keyframes.selected_items, + to_set(vec![(Direction::North, 1)]) + ); + } + + { + d.select_keyframe(Direction::North, 1, false, false) + .unwrap(); + d.browse_selection(BrowseDirection::Right, true).unwrap(); + d.browse_selection(BrowseDirection::Down, true).unwrap(); + assert_eq!( + d.view.selection.keyframes.selected_items, + to_set(vec![ + (Direction::North, 1), + (Direction::North, 2), + (Direction::South, 1), + (Direction::South, 2) + ]) + ); + } + } + #[test] fn can_delete_selection_frames() { let mut d = Document::new("tmp"); From 0f3ea5c3ff3193c4485a6835855b1b174b57fb64 Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Mon, 26 Dec 2022 18:10:17 +0100 Subject: [PATCH 58/77] More selection logic tests --- src-tauri/src/document/selection.rs | 73 +++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 4 deletions(-) diff --git a/src-tauri/src/document/selection.rs b/src-tauri/src/document/selection.rs index 5885f7a..1e1b876 100644 --- a/src-tauri/src/document/selection.rs +++ b/src-tauri/src/document/selection.rs @@ -1134,16 +1134,21 @@ mod test { d.select_animation("A", false, false); let just_a = HashSet::from(["A".to_owned()]); let just_b = HashSet::from(["B".to_owned()]); + let just_c = HashSet::from(["C".to_owned()]); let b_and_c = HashSet::from(["B".to_owned(), "C".to_owned()]); - assert_eq!(&d.view.selection.animations.selected_items, &just_a,); + assert_eq!(&d.view.selection.animations.selected_items, &just_a); d.browse_selection(BrowseDirection::Down, false).unwrap(); - assert_eq!(&d.view.selection.animations.selected_items, &just_b,); + assert_eq!(&d.view.selection.animations.selected_items, &just_b); d.browse_selection(BrowseDirection::Down, true).unwrap(); assert_eq!(&d.view.selection.animations.selected_items, &b_and_c); d.browse_selection(BrowseDirection::Up, false).unwrap(); - assert_eq!(&d.view.selection.animations.selected_items, &just_b,); + assert_eq!(&d.view.selection.animations.selected_items, &just_b); d.browse_selection(BrowseDirection::Left, false).unwrap(); - assert_eq!(&d.view.selection.animations.selected_items, &just_b,); + assert_eq!(&d.view.selection.animations.selected_items, &just_b); + d.browse_to_end(false).unwrap(); + assert_eq!(&d.view.selection.animations.selected_items, &just_c); + d.browse_to_start(false).unwrap(); + assert_eq!(&d.view.selection.animations.selected_items, &just_a); } #[test] @@ -1154,6 +1159,7 @@ mod test { d.select_frame("A", false, false); let just_a = HashSet::from([PathBuf::from("A")]); let just_b = HashSet::from([PathBuf::from("B")]); + let just_c = HashSet::from([PathBuf::from("C")]); let b_and_c = HashSet::from([PathBuf::from("B"), PathBuf::from("C")]); assert_eq!(&d.view.selection.frames.selected_items, &just_a,); d.browse_selection(BrowseDirection::Down, false).unwrap(); @@ -1164,6 +1170,10 @@ mod test { assert_eq!(&d.view.selection.frames.selected_items, &just_b,); d.browse_selection(BrowseDirection::Left, false).unwrap(); assert_eq!(&d.view.selection.frames.selected_items, &just_b,); + d.browse_to_end(false).unwrap(); + assert_eq!(&d.view.selection.frames.selected_items, &just_c); + d.browse_to_start(false).unwrap(); + assert_eq!(&d.view.selection.frames.selected_items, &just_a); } #[test] @@ -1254,6 +1264,61 @@ mod test { ]) ); } + + d.browse_to_end(false).unwrap(); + assert_eq!( + d.view.selection.keyframes.selected_items, + to_set(vec![(Direction::South, 2)]) + ); + + d.browse_to_start(false).unwrap(); + assert_eq!( + d.view.selection.keyframes.selected_items, + to_set(vec![(Direction::South, 0)]) + ); + } + + #[test] + fn can_browse_hitboxes() { + let to_set = |v: Vec<&str>| { + v.into_iter() + .map(|h| ("walk_cycle".into(), Direction::North, 0, h.into())) + .collect() + }; + + let mut d = Document::new("tmp"); + d.sheet.add_frames(&vec!["walk_0", "walk_1", "walk_2"]); + d.sheet.add_test_animation( + "walk_cycle", + HashMap::from([(Direction::North, vec!["walk_0", "walk_1", "walk_2"])]), + ); + d.edit_animation("walk_cycle").unwrap(); + + let keyframe = d.sheet.keyframe_mut("walk_cycle", Direction::North, 0); + keyframe.create_hitbox("H0"); + keyframe.create_hitbox("H2"); + keyframe.create_hitbox("H1"); + + d.select_hitbox("H0", false, false).unwrap(); + assert_eq!(d.view.selection.hitboxes.selected_items, to_set(vec!["H0"])); + + d.browse_selection(BrowseDirection::Down, false).unwrap(); + assert_eq!(d.view.selection.hitboxes.selected_items, to_set(vec!["H1"])); + + d.browse_selection(BrowseDirection::Down, true).unwrap(); + assert_eq!( + d.view.selection.hitboxes.selected_items, + to_set(vec!["H1", "H2"]) + ); + + d.browse_selection(BrowseDirection::Up, false).unwrap(); + assert_eq!(d.view.selection.hitboxes.selected_items, to_set(vec!["H1"])); + + d.browse_to_end(false).unwrap(); + assert_eq!(d.view.selection.hitboxes.selected_items, to_set(vec!["H2"])); + + d.browse_to_start(false).unwrap(); + assert_eq!(d.view.selection.hitboxes.selected_items, to_set(vec!["H0"])); } #[test] From 39662dc0ff8c14a0d49556913a85f83aa5cdbf66 Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Fri, 30 Dec 2022 16:38:08 +0100 Subject: [PATCH 59/77] Exercise select all code paths --- src-tauri/src/document/selection.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src-tauri/src/document/selection.rs b/src-tauri/src/document/selection.rs index 1e1b876..4f5afff 100644 --- a/src-tauri/src/document/selection.rs +++ b/src-tauri/src/document/selection.rs @@ -1136,6 +1136,7 @@ mod test { let just_b = HashSet::from(["B".to_owned()]); let just_c = HashSet::from(["C".to_owned()]); let b_and_c = HashSet::from(["B".to_owned(), "C".to_owned()]); + let a_b_c = HashSet::from(["A".to_owned(), "B".to_owned(), "C".to_owned()]); assert_eq!(&d.view.selection.animations.selected_items, &just_a); d.browse_selection(BrowseDirection::Down, false).unwrap(); assert_eq!(&d.view.selection.animations.selected_items, &just_b); @@ -1149,6 +1150,8 @@ mod test { assert_eq!(&d.view.selection.animations.selected_items, &just_c); d.browse_to_start(false).unwrap(); assert_eq!(&d.view.selection.animations.selected_items, &just_a); + d.select_all().unwrap(); + assert_eq!(&d.view.selection.animations.selected_items, &a_b_c); } #[test] @@ -1161,6 +1164,7 @@ mod test { let just_b = HashSet::from([PathBuf::from("B")]); let just_c = HashSet::from([PathBuf::from("C")]); let b_and_c = HashSet::from([PathBuf::from("B"), PathBuf::from("C")]); + let a_b_c = HashSet::from([PathBuf::from("A"), PathBuf::from("B"), PathBuf::from("C")]); assert_eq!(&d.view.selection.frames.selected_items, &just_a,); d.browse_selection(BrowseDirection::Down, false).unwrap(); assert_eq!(&d.view.selection.frames.selected_items, &just_b,); @@ -1174,6 +1178,8 @@ mod test { assert_eq!(&d.view.selection.frames.selected_items, &just_c); d.browse_to_start(false).unwrap(); assert_eq!(&d.view.selection.frames.selected_items, &just_a); + d.select_all().unwrap(); + assert_eq!(&d.view.selection.frames.selected_items, &a_b_c); } #[test] @@ -1276,6 +1282,19 @@ mod test { d.view.selection.keyframes.selected_items, to_set(vec![(Direction::South, 0)]) ); + + d.select_all().unwrap(); + assert_eq!( + d.view.selection.keyframes.selected_items, + to_set(vec![ + (Direction::North, 0), + (Direction::North, 1), + (Direction::North, 2), + (Direction::South, 0), + (Direction::South, 1), + (Direction::South, 2) + ]) + ); } #[test] @@ -1319,6 +1338,12 @@ mod test { d.browse_to_start(false).unwrap(); assert_eq!(d.view.selection.hitboxes.selected_items, to_set(vec!["H0"])); + + d.select_all().unwrap(); + assert_eq!( + d.view.selection.hitboxes.selected_items, + to_set(vec!["H0", "H1", "H2"]) + ); } #[test] From 99cf37c123076eea27620a83db0d1c88fec676aa Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Fri, 30 Dec 2022 18:06:17 +0100 Subject: [PATCH 60/77] Adds DTO trim tests --- src-tauri/src/dto.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src-tauri/src/dto.rs b/src-tauri/src/dto.rs index 41d5731..a24c24b 100644 --- a/src-tauri/src/dto.rs +++ b/src-tauri/src/dto.rs @@ -699,3 +699,60 @@ impl From<&document::ExportSettingsError> for ExportSettingsError { } } } + +#[cfg(test)] +mod test { + + use super::*; + use crate::document; + + #[test] + fn can_preserve_all() { + let mut app = app::App::default(); + app.open_document(document::Document::open("test-data/sample_sheet_1.tiger").unwrap()); + app.open_document(document::Document::open("test-data/sample_sheet_2.tiger").unwrap()); + let dto = app.to_dto(AppTrim::Full); + assert_eq!(dto.documents.len(), 2); + assert!(!dto.documents[0].sheet.animations.is_empty()); + assert!(!dto.documents[1].sheet.animations.is_empty()); + } + + #[test] + fn can_trim_inactive_documents() { + let mut app = app::App::default(); + app.open_document(document::Document::open("test-data/sample_sheet_1.tiger").unwrap()); + app.open_document(document::Document::open("test-data/sample_sheet_2.tiger").unwrap()); + let dto = app.to_dto(AppTrim::OnlyCurrentDocument); + assert_eq!(dto.documents.len(), 2); + assert!(dto.documents[0].sheet.animations.is_empty()); + assert!(!dto.documents[1].sheet.animations.is_empty()); + } + + #[test] + fn can_trim_all_except_workbench() { + let mut app = app::App::default(); + app.open_document(document::Document::open("test-data/sample_sheet_1.tiger").unwrap()); + app.open_document(document::Document::open("test-data/sample_sheet_2.tiger").unwrap()); + let animation_name = app + .current_document() + .unwrap() + .current_animation() + .as_ref() + .cloned() + .unwrap(); + let dto = app.to_dto(AppTrim::OnlyWorkbench); + assert_eq!(dto.documents.len(), 2); + assert!(dto.documents[0].sheet.animations.is_empty()); + assert_eq!(dto.documents[1].sheet.animations.len(), 1); + assert_eq!(dto.documents[1].sheet.animations[0].name, animation_name); + } + + #[test] + fn can_trim_all_documents() { + let mut app = app::App::default(); + app.open_document(document::Document::open("test-data/sample_sheet_1.tiger").unwrap()); + let dto = app.to_dto(AppTrim::NoDocuments); + assert!(!dto.documents.is_empty()); + assert!(dto.documents[0].sheet.animations.is_empty()); + } +} From 2afd9cf9c801895523dd6cf6d71ea460df628af4 Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Fri, 30 Dec 2022 22:20:33 +0100 Subject: [PATCH 61/77] Added test assets --- src-tauri/test-data/flame-hit-0.png | Bin 0 -> 708 bytes src-tauri/test-data/flame-hit-1.png | Bin 0 -> 704 bytes src-tauri/test-data/flame-hit-2.png | Bin 0 -> 717 bytes src-tauri/test-data/flame-idle-0.png | Bin 0 -> 662 bytes src-tauri/test-data/flame-idle-1.png | Bin 0 -> 670 bytes src-tauri/test-data/flame-idle-2.png | Bin 0 -> 676 bytes src-tauri/test-data/flame-idle-3.png | Bin 0 -> 663 bytes src-tauri/test-data/flame-idle-4.png | Bin 0 -> 659 bytes src-tauri/test-data/flame.tiger | 199 +++++++++ src-tauri/test-data/samurai-attack-east.png | Bin 0 -> 468 bytes src-tauri/test-data/samurai-attack-north.png | Bin 0 -> 459 bytes src-tauri/test-data/samurai-attack-south.png | Bin 0 -> 463 bytes src-tauri/test-data/samurai-attack-west.png | Bin 0 -> 471 bytes src-tauri/test-data/samurai-dead-all.png | Bin 0 -> 2973 bytes src-tauri/test-data/samurai-idle-east.png | Bin 0 -> 470 bytes src-tauri/test-data/samurai-idle-north.png | Bin 0 -> 449 bytes src-tauri/test-data/samurai-idle-south.png | Bin 0 -> 469 bytes src-tauri/test-data/samurai-idle-west.png | Bin 0 -> 470 bytes src-tauri/test-data/samurai-walk-east-0.png | Bin 0 -> 470 bytes src-tauri/test-data/samurai-walk-east-1.png | Bin 0 -> 462 bytes src-tauri/test-data/samurai-walk-east-2.png | Bin 0 -> 470 bytes src-tauri/test-data/samurai-walk-east-3.png | Bin 0 -> 460 bytes src-tauri/test-data/samurai-walk-north-0.png | Bin 0 -> 449 bytes src-tauri/test-data/samurai-walk-north-1.png | Bin 0 -> 439 bytes src-tauri/test-data/samurai-walk-north-2.png | Bin 0 -> 449 bytes src-tauri/test-data/samurai-walk-north-3.png | Bin 0 -> 439 bytes src-tauri/test-data/samurai-walk-south-0.png | Bin 0 -> 469 bytes src-tauri/test-data/samurai-walk-south-1.png | Bin 0 -> 461 bytes src-tauri/test-data/samurai-walk-south-2.png | Bin 0 -> 469 bytes src-tauri/test-data/samurai-walk-south-3.png | Bin 0 -> 461 bytes src-tauri/test-data/samurai-walk-west-0.png | Bin 0 -> 470 bytes src-tauri/test-data/samurai-walk-west-1.png | Bin 0 -> 464 bytes src-tauri/test-data/samurai-walk-west-2.png | Bin 0 -> 470 bytes src-tauri/test-data/samurai-walk-west-3.png | Bin 0 -> 461 bytes src-tauri/test-data/samurai.tiger | 442 +++++++++++++++++++ 35 files changed, 641 insertions(+) create mode 100644 src-tauri/test-data/flame-hit-0.png create mode 100644 src-tauri/test-data/flame-hit-1.png create mode 100644 src-tauri/test-data/flame-hit-2.png create mode 100644 src-tauri/test-data/flame-idle-0.png create mode 100644 src-tauri/test-data/flame-idle-1.png create mode 100644 src-tauri/test-data/flame-idle-2.png create mode 100644 src-tauri/test-data/flame-idle-3.png create mode 100644 src-tauri/test-data/flame-idle-4.png create mode 100644 src-tauri/test-data/flame.tiger create mode 100644 src-tauri/test-data/samurai-attack-east.png create mode 100644 src-tauri/test-data/samurai-attack-north.png create mode 100644 src-tauri/test-data/samurai-attack-south.png create mode 100644 src-tauri/test-data/samurai-attack-west.png create mode 100644 src-tauri/test-data/samurai-dead-all.png create mode 100644 src-tauri/test-data/samurai-idle-east.png create mode 100644 src-tauri/test-data/samurai-idle-north.png create mode 100644 src-tauri/test-data/samurai-idle-south.png create mode 100644 src-tauri/test-data/samurai-idle-west.png create mode 100644 src-tauri/test-data/samurai-walk-east-0.png create mode 100644 src-tauri/test-data/samurai-walk-east-1.png create mode 100644 src-tauri/test-data/samurai-walk-east-2.png create mode 100644 src-tauri/test-data/samurai-walk-east-3.png create mode 100644 src-tauri/test-data/samurai-walk-north-0.png create mode 100644 src-tauri/test-data/samurai-walk-north-1.png create mode 100644 src-tauri/test-data/samurai-walk-north-2.png create mode 100644 src-tauri/test-data/samurai-walk-north-3.png create mode 100644 src-tauri/test-data/samurai-walk-south-0.png create mode 100644 src-tauri/test-data/samurai-walk-south-1.png create mode 100644 src-tauri/test-data/samurai-walk-south-2.png create mode 100644 src-tauri/test-data/samurai-walk-south-3.png create mode 100644 src-tauri/test-data/samurai-walk-west-0.png create mode 100644 src-tauri/test-data/samurai-walk-west-1.png create mode 100644 src-tauri/test-data/samurai-walk-west-2.png create mode 100644 src-tauri/test-data/samurai-walk-west-3.png create mode 100644 src-tauri/test-data/samurai.tiger diff --git a/src-tauri/test-data/flame-hit-0.png b/src-tauri/test-data/flame-hit-0.png new file mode 100644 index 0000000000000000000000000000000000000000..a148912e208e87ac8660f0ac00f3f9a4c8375b97 GIT binary patch literal 708 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_>3?$zOPHh5GEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBC?OQ!6XFV_A6WYQpBnQ2 zVekL{|DWVqxu<#Z07V%~g8YIR9G=}s196hP-CbDvGj0X~IqW5#zOL-gc;tlG%>M7a zH5n+K=jq}YVsU!yl-s$74R~B1^XlX(R51ricicR1vwmuvozCgJOWzhVH65_oQPX+l z@yFkhLBAY~F8=a(ZOt1PxnhmH%gj?}y97FCbnV>35G5=a&ZN0rfZ>Qw$a=*LUldQg7IpdO zvPDSsckcoj)!)SeTU0!_netCKM~8R|td%!2_+jIEQ%FGnMdp&-9FjMtPmbN!8FBMO zwbBcF{`G%-9KTvAGWP^Ew{#u9u#zJ@@)i)Z&-=Kgj(*IIB%Wzvi1N1n=e+}G+B zmSgU@`apt7enFJmoINLN`~th~$u97-p5i{$=6I*}_C;S}uJN7Ty7TL{=v{|*Ew{RO z`5()vJm33qEPJdaN@~UL?NNI9cJ*ib=iI_u=0t|AKf4qd8LB0&5hW>!C8<`)MX5lF z!N|bKNY~Iv*VrJ$(89{V%*w=2+rYrez@TGQUoeV>-29Zxv`X9>ettK557eLmx1l66 gH?_DVF}DCykEsd75`zK@PM{tJPgg&ebxsLQ04DAWa{vGU literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/flame-hit-1.png b/src-tauri/test-data/flame-hit-1.png new file mode 100644 index 0000000000000000000000000000000000000000..415820d2d10b4ac88015cbd69908b5343b073fef GIT binary patch literal 704 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_>3?$zOPHh5GEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBC?OQ!6XFV_MWm%4So%E4 zwR%6%|NsC0%J;3zfTD~gL4Lsu4$p3+fjCLt?k=o9@?RbYa@b2eeO=j~@yH3Wnf>2; zYcfze%hSa%#NzbQDcOC86?j@EOD9Z`V|dOsgFB?4@!yT#@u{}Y0&n;(Stqu1)uHQ> z_E|T!{a-WpMO#JM_KCYM8MM!B-Yr`mQS=`9U211(L1 zl$Wc87HRF$k-4;ZmP1g`^vvo<3QH%mMEc+HIQDJxsjx-2-4`yFdX{#bBT)INa+8;X zoPEbM=1i*z$pOc&+NVviDWR$dYReO{L5Hvg?*J*s7&81ZFAwswTfsxU~PovgO+r2n(m4oSVRK*Ci;^v&Kayz|C`NPvVk$ zZ7KXkum5ig4xBmtOHqt?=>-$BlDZJhy_uJgTe~DWM4fU4#Ya literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/flame-hit-2.png b/src-tauri/test-data/flame-hit-2.png new file mode 100644 index 0000000000000000000000000000000000000000..2136a0258ff78447451d076642549fb5799ae551 GIT binary patch literal 717 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_>3?$zOPHh5GEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBC?OQ!6XFV_MWm%4So%E4 zwR%6%|NsC0%J;3zfTD~gL4Lsu4$p3+fjCLt?k=o9@?RbYa@b2eeO=j~@yH3Wnf>2; zYcf!}+|$J|#NzbcDQ|O+DDbo$W|O$f+i;U%vqOs54*9$FQ-5i@2Sl$7S{l{mcYN~o zx`P(SKi;3nP^Z9ZC_iEQ^uO^=YdBxaPTl3g`r2>O6b6+w(>_hp6+P47A=`RoZ-r=s zOGmA8P_)Bq6{TC3M9<#u=|1I z?4o7pb=E6Y)#S@pLscEk)?&@Y+;YqI3hz4+aOh#oNt2>oIXN!V8C8Zlr#Iy6T|%- z9ydSj<+$A#zfos~yyYp@q}9qED}L;9IC<+p+anHxV@@tQ`b7enOh+UltSmbW65oC_ zG~i!zZ104qKE}?oeJ|EpoOr)5O8v>yn2BrL%N+{0d)Jwte6QT3?$zOPHh5GEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBC?Oi)6XFV_MWm%4So%E4 zwR%6%|MADK|NsB@aD9CPD8X0~9AK@^o@HjPw0nSPLII8a#h|(yOTni1U^q~S(U^g`l~fXmA5)~ zZ(OwpyUQBhaLd3|D-{=C*s9^sev3_*FRI&RB{N^zl&vC}{1bHe<*w9DEDb+&Wl3a- zSSsUVg)56UYixPw(b_5?E$OyO{g3RG&C>e*L0_8hMvCMZ?@?F2*Pb)`;oroR51Bh| ztqJn#dNb|7#DzglJ_51Q%C46*UltT*ZuZ{vW^xRh$N59?{E{*c-x#0FYsu$WzR3Hk zSkW%$c`I0#SWkI8Eq=rL;KfS{Z&Ws$i`=Yy+n;V_b-358yH9IUbje?)F zK#IZ0z{p6~&`8(VAjHtZ%D~*p#8lhBz{3?$zOPHh5GEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBC?Oi)6XFV_MWm&lge|G%5X}#3u>g$=Fm*>2@pz}z~bN3IgBcUIU@~T{&behF`+nZ-M zSr=NduRP`G^2i~g?EGhjGmajg9H#Y7QRuGR6_<2WkY$?fMkkLDW`~r*b%G+#R-9ru z<@7Rj+DzX?JOMj=**#Otf_hpS6}AiRQ7q0%J5jr;%9N>6IYTZa{L-q&ACwBhZC-B{ zlF{C3mKElNTCcy5%&-f3?$zOPHh5GEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBC?Oi)6XFV_MWm%4So%E4 zwR%6%|MADK|NsB@aD9CPD8X0~Vz)HcapxvZEe%t@BZz``uV`^_)PnD7V zJaMx8iA{gbi#`(eOpSce$+C=n>w!NCoI&pnHyXIS>@)H6F`v}P8h3G%%-RbcI=$R> zi-R}B3us>aB(Zwq{*drSiA6^hnW7gm1?@QHAe5hUOWOI->(|7Pm3&OLJ~ z9K{z+c`Mmj>b||}Ox|8Qe!jKg+5X#gFSSi>zS?)z-fHg4doO&~`F?k>D{Na*zMOe( zshpqmE2YnCSa$o|p0!?sZKC3i=F>U?d5hO;Z^$gL{yR@@N8;U^|2NbzeEE>dV!Vtm z7#Py3C9V-ADTyViR>?)FK#IZ0z{p6~&`8(VAjHtZ%D~*p#8lhBz{3?$zOPHh5GEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBC?Oi)6XFV_MWm&l{myYc6@Ou_ z{WrtSi&>YwwAcU7a_9Masmd$2Ca<*-OfS#lJ9_idR;!J#KJMRjR?cnOk!#%@ogQbd z&6wkH{h}O;!{UR6rJg4C;Ttr}WzNpYEDef1HS^3>mIYJRa9q3_VbaW?B31Tt;tMWT z&T`(AlToTmHJnS5y4ZSCbZ5o*?^Oy>p0f02zsh2-T1E?zgZUgqgG)UBU>OPt3)H@BVHy+YCN zbIDfO!056{4TsmdD^{%izWiy+*OK2&uE)NAT>h0e>2I3Wk~15sfPt%8;u=wsl30>z zm0Xkxq!^40jEr;*jdYC-LJTde49u-eOtlRRtPBh$s~@aG(U6;;l9^VCTf?KO%0oa6 m8gLs*GILXlOA>PnF!h)kK`hyml*S9x!{F)a=d#Wzp$Pzr+xsp6 literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/flame-idle-4.png b/src-tauri/test-data/flame-idle-4.png new file mode 100644 index 0000000000000000000000000000000000000000..16c26fcf8931f716e380cbdaf50ef4e8a42e8807 GIT binary patch literal 659 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_>3?$zOPHh5GEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBC?Oi)6XFV_MWm%4So%E4 zwR%6%|MADK|NsB@aD9CPD8X0~00oZD^r_pv1ER6Nx)>eSli z65?Vc7*2)!h53WfK&ZbgU9))i3{Xwfo23 ziRG&mk8An{2!#mw8!K*L5w;Sh3H$)jOC90m5Mog`DWXSl^xS&FM969 zym?-J^YzP>?AMR(Vpdo#{+drfUhl*GBl>|6IdlAW{#gzTSk)5Oh?11Vl2ohYqEsNo zU}Ruqq-$uTYitl=XklewZe?PsZD3$!U@%$zU>%Bv-29Zxv`X9>9#vHy0&38J+fb63 gn_66wm|K9U$J7X7$)2P%UZ5TZPgg&ebxsLQ0NlXtP5=M^ literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/flame.tiger b/src-tauri/test-data/flame.tiger new file mode 100644 index 0000000..5347378 --- /dev/null +++ b/src-tauri/test-data/flame.tiger @@ -0,0 +1,199 @@ +{ + "version": "Tiger4", + "sheet": { + "frames": [ + { + "source": "flame-hit-0.png" + }, + { + "source": "flame-hit-1.png" + }, + { + "source": "flame-hit-2.png" + }, + { + "source": "flame-idle-0.png" + }, + { + "source": "flame-idle-1.png" + }, + { + "source": "flame-idle-2.png" + }, + { + "source": "flame-idle-3.png" + }, + { + "source": "flame-idle-4.png" + } + ], + "animations": { + "hit": { + "sequences": { + "North": { + "keyframes": [ + { + "frame": "flame-hit-0.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -22 + ] + }, + { + "frame": "flame-hit-1.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -22 + ] + }, + { + "frame": "flame-hit-2.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -22 + ] + } + ] + } + }, + "is_looping": false + }, + "idle": { + "sequences": { + "North": { + "keyframes": [ + { + "frame": "flame-idle-0.png", + "hitboxes": { + "hit": { + "geometry": { + "Rectangle": { + "top_left": [ + -12, + -28 + ], + "size": [ + 24, + 24 + ] + } + } + } + }, + "duration_millis": 100, + "offset": [ + 0, + -22 + ] + }, + { + "frame": "flame-idle-1.png", + "hitboxes": { + "hit": { + "geometry": { + "Rectangle": { + "top_left": [ + -12, + -28 + ], + "size": [ + 24, + 24 + ] + } + } + } + }, + "duration_millis": 100, + "offset": [ + 0, + -22 + ] + }, + { + "frame": "flame-idle-2.png", + "hitboxes": { + "hit": { + "geometry": { + "Rectangle": { + "top_left": [ + -12, + -28 + ], + "size": [ + 24, + 24 + ] + } + } + } + }, + "duration_millis": 100, + "offset": [ + 0, + -22 + ] + }, + { + "frame": "flame-idle-3.png", + "hitboxes": { + "hit": { + "geometry": { + "Rectangle": { + "top_left": [ + -12, + -28 + ], + "size": [ + 24, + 24 + ] + } + } + } + }, + "duration_millis": 100, + "offset": [ + 0, + -22 + ] + }, + { + "frame": "flame-idle-4.png", + "hitboxes": { + "hit": { + "geometry": { + "Rectangle": { + "top_left": [ + -12, + -28 + ], + "size": [ + 24, + 24 + ] + } + } + } + }, + "duration_millis": 100, + "offset": [ + 0, + -22 + ] + } + ] + } + }, + "is_looping": true + } + }, + "export_settings": null + } +} \ No newline at end of file diff --git a/src-tauri/test-data/samurai-attack-east.png b/src-tauri/test-data/samurai-attack-east.png new file mode 100644 index 0000000000000000000000000000000000000000..09e1b0602f3d151075986bbdbe44383b5d0292f2 GIT binary patch literal 468 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5LX~AA}#&#Na5p; zU$1w2&0fChqPNNWiT-{bUe;#L|NsC0;cZw zMq&*d8k*8Z9TtreT75h{3e&n5GcYG-baZzoNOdr>JWX|I%go5wuyKI`bMuCc8w=gt zEiWh}C!d~~aO})XWA&ybDppde>0Ax02g;ZkIyyx6%BZ`409vhD;u=wsl30>zm0Xkx zq!^40jEr;*jdYC-LJTde3{9*|jI<35tPBilEN2^|Xvob^$xN%nt${a1xgV%O18ze} hW^QV6Nn&mR7Cn{_OCrj`Rsr=ec)I$ztaD0e0sw!eh@1cb literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai-attack-north.png b/src-tauri/test-data/samurai-attack-north.png new file mode 100644 index 0000000000000000000000000000000000000000..bc48a778d45d04595550ac35dc22f6392edf77b5 GIT binary patch literal 459 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5LX~AA}xK<+vMYs z!t32$k3W8$y?m9QhnKaP^ZSYZ|NsAAb|<_DsEDy7$S;_|;n|He5GTpo-GwXT!j~{0 zhrPtp*OmPlkDL&n;Yx<17C@miPZ!4!j_b(@0zoMv2@H&iu8GbD-T^mmNStB1H6J42+Hw*6|(e>zgUS?!h3*&>Anvkv20h9cZI!iEBhjN@7W>RdP`(kYX@0Ff!6L zG}1LT2r;y@?RfWQC% literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai-attack-south.png b/src-tauri/test-data/samurai-attack-south.png new file mode 100644 index 0000000000000000000000000000000000000000..aa45890d094dfb0dbde330a5b20532ca5cf64141 GIT binary patch literal 463 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5LX~AA}#&#Na5p; zU$1w2&0fChqPNNWiT>7R&VC+V|NsBzvlar`%2*QQ7tG-B>_!@hljQC0!j*C1OBj&D zUgGKN%KnT;PKeKNCBsn*piq{li(?4K_2dKxrXHq%D33q}CvDBfNC&ACOk5h8n$nt@ zoDD2Jy^c;w0&U97i-kSBSXV>|EQt_U;cXJ26KE39(0I{ekIvpJI)Wz*%)HIad{Pnw z%-EXTCOn!sxmQ=ZQLVf~+^eL7gMlG*jgUx(`M3W-TUAS3BT7;dOH!?pi&B9UgOP!e zk*=YUuCYOgp@o&9iIs_wwt<0_fkBPsY-1D+x%nxXX_dG&@TMsD12t&CZ79jiO)V}- b%q_s8#}Z;mL|ND>pdJQKS3j3^P6@P5LX~AA}#&#Na5p; zU$1w2UGz4Yy?oXCiT-{bUe;#L|NsC0;CuK8P!VHEkY6x^!?PP{AWo9Ey9-ywg)d=1 z4tt5GuPggA9yuXC!<7t2Er3Ero-U3d9M^Sw4f&cKcv!C6Z(w%S*!YQYgA2daQ}#eP zftULne9Ltgeaipnxb5aek=+aqJ=$Mh{LH)BE!F!)aZQuatib%MdRya-SNLv~{4#OM zJXRC;@w7`S*NS*GIcX9eBzNg>(_kW?^yk}wsCl^>H0&Q0FOw0}eAZu_2-Y5k*7<6+wa` z28@Oxu_B6vfMCHMkRYJMU=&eNc{8$Bbmir}mzUokXMJm*z4tw5?|s&~0Fb=>xx92( z3V<}8fFI)JN{@_+repg74DbL0%m84rGBW}~J;Q)VJ|1rLOpz1#A_#ytcf>0IH;uf5 z=ydS^Nt%_x7l_gXiP(b8$z+MRP{gU(f()^JM#R+k6fwgnG4n+S6tTRR6BpU=v(F+s zi!Zs{4hd~RZrfUe8Zqnp{{O0G zU=+k;r7-zyx?6f$29uWyz~Y@hOGaEo1g?xHu29w318~u5R|8d}7 zpTjVOlfdC~c%q1K(Ufs{iK2G%*jxcOok!>L{!k z0Z0NWPyi}G1Ly)HU=D16J#Ypdz!wC9Fc1Y+0TxICX@C#1K|a_Bia-h20d|9GPzxGB z6KDY^KnFMtE`ZD6I=BIDg9l&)jDzQ32D}0D5CmZ%GDLwCAXP{UGJwn>2IL5NK>kn& z6a~dWi4YGGLix}ps01p9s-Zfl3Hly71zmuyLW9sfXcU@)euv(}2uy;hurjO-o4^d% z1@?o(;FWM9yc*7f3*qf>6CN~9iXLAsD$ClpY8|Q+RgF4=YDe{;ZlXp} zGpJ8!GFl03fVM;Xpd-VXR18&z>O)PYmQcT=_ETqMWn?X7!)0@1Yh=&Jj?fUAHqD2YN-LwCpxvRpms6H= zk>kj1lWUP1lADuXBJV8EkuR2SmA@_jUV*OQp^&1mQ=voQks?Y_UoluQTk(M6CB^9_ z)Ft*ySWAkRoLF*S30Bfq3Q=04bV#XBX;xW9*-JS?d9U(CNC15-G!b?ucG(RXVjF`yw!wib!z=;^XfY4%he0iTh$+F5HuJX2^tj| z-5N8Rs+s|s`I^m|_qFg^46P)sJzBk5bJ{xE5!zd{JG3Wt@^qSY9_o^Hope|0 z*6ZHV!{{;eQuOxg-Oz{it@M-hYxD;UU;}FduEBnTK|{2mts&2_-f-B6WaMI$Wz=jm zYD_csH!d*lFn(d8X%cO+)1=qrlc|+ys%eAi12Y*jU$X+UF0n%DhURoMhax4#6-nF7w1z2sd>bCl5ZDY;1Zn2)S(X@%P*=IA%pfZ9OrHm`KXj@m? z^|q&N-`QE)3G7bT{bp}upJIR1esZbKQqIzbrDG224ortShY?4*W1Qnb#}OwrC#F-q z(-UV6XSQ>r^Ms3@OR~!`mlv+4u6)-v*Eu&kx3zBP-4S;$_hR>c4;hc;9@QR?J=HxE zJ)1peysW&|c%An~d;59s^d9z6_F?%n`ONs*_^$Qs@gw<#`c?Zq@z?j~`*#Jv0lopd z0v;~YTE<(}5eNc(0(S*I3epK$9rR-`CO9a#CirQHSxA0JZzv@+HuPxdn=sd~vakos zb(ag5cZW-c$AmY9&qcULlt+w2nnbRRydI?(#f|EW#zu!nH%8B{@K~{X#dwTWOi|38 zl{zbPR$g7DxGHtknOMnKX6(s0bX-K-(YO!HKxRF2Hr^+GU;GTqjkSmMobAl6U{7%z zIOUv)1c!w3gvmsQ#9fI~Nlrer7PULy!eY*y=hP9?UUoC%Q{^(klwRP*Db@A)E*K4dVTtB|SYr~O^ zgpDa1e=0C7C@*-uDPmJsp>pAd!m-U>o12RyiugstTkN;gZbfb7ZtdS@v2E|RPsQxw zYbB;7l_eiaS*6#$G5ewA3os zmejsK$US(s&a1AyUc0{X5av+Up{EVu4ZYtozHMq$Y%FQ~c$jy16$aLXUfhJ&K90sIG1;B_I$?q=?jS$ z#=2v>A6$&Qc&jJ4r~i`Qr7M>`FJJ6+={@ z`mOuh2W$p9Z`j`G8eBSfcF1Yy!cF&^mv8ypx_*1v?ZG?C@7x`Z86LUIzB_p@_1??- zS@-83Y=u0 zch3gRK7Nz-W`3^tt-{+Q?-=iT-$%Tkn9u%z{ZRE$?_<{|zfTVr(iRr}1p}D#{KvJf zbN~PWFG)l}R5*>@k}*gFF&KrvlsZ{-IRpt#qJtnPh>H}5E~j19LLKbxB#0n53W5lB zaj%1gs;gQG9i*aLzO-Xp)`yb?o|1C>OWl5=`Ji-J5 zJeO7g7|oml@a8x@eh~!*6&Bt{W$$T9EVM(d>4i4Gg+yKl!;I9p!8DUAO?jD~gUtR#P^m@YB z{w)C2sbK(8_b&i6w`MpWS_QyfOfx+(P8=Xn$YSS;0Jx-Sk_DhuaXb*f%@wh`O%jD4 zPaNOF+SM0Fr8C@a7?pVs)LPFhbG*>!-37qhY|7jB>zk@*zki1A|Hxp!2ztK(8CiFk TW`P{600000NkvXXu0mjf0baSE literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai-idle-east.png b/src-tauri/test-data/samurai-idle-east.png new file mode 100644 index 0000000000000000000000000000000000000000..f1fdd2ba043d99e59280cda0edf4e270922b3018 GIT binary patch literal 470 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5LX~AA}#&#Na5p; zU$1w2&0fChqPNNWiT>7R&VC+V|NsBzvlar`%2*QQ7tG-B>_!@hljQC0!j*C1OBj&D zUgGKN%KnT;PKd|kbxg1+P^i$;#W95AdU65~h$JvDyD7Rda;#m#lE#>+s_MLep(D&l ztbs#AQ`)G*qESMtkEcgrTK8fG=H!fy?(PJs4n~%zsSa(K85tWkN?uS%Ocr1;l9=7A zJFAh+$fKmB#H5S)YRQ>7H!pGo@rb+-5D{iz$d(nGP+#Z=3If#<*NBpo#FA92CkWni$S;VLMA5E^pxQ!>*kacekwH`fiQK?80> jNoH1vcVK4FY zb!C6XBPYaT@;WBi6etw$>Eal|aox7(AZLRE4~x01iq^lqd{49l7KvssHqDX!vAx*5 z{6S6G4PHiuz>p=gx1@Sqona!ja?#q3RryBFMJdm=rY3Pk@^1>ZIbz9c68~d)%)97^ zUqp)jCmoO|+9xm4Cc40@P5LX~AA}#&#Na5p; zU$1w2&0fChqPNNWiT>7R&VC+V|NsBzvlar`%2*QQ7tG-B>_!@hljQC0!j*C1OBj&D zUgGKN%KnT;PKd|kbxg1+P^iGu#W95Ay6UNeyv+_gEDrJPb|P~hbb7KzYMv6WTEK9m znQzDUzcEgia<4r&-*-)0X;R2K@4G9?XT>H3>6}?MeWn|u%hw%--cgUfKCwD(QM@NF zReQD2SDP$`iuVi?5B@gs+{%7u_LRl>hu?ees4ly1uUsXjaj9hG3ZUJpC9V-ADTyVi zR>?)FK#IZ0z{p6~&`8(VAjHtZ%FxKl#8lhBz{i_@% literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai-idle-west.png b/src-tauri/test-data/samurai-idle-west.png new file mode 100644 index 0000000000000000000000000000000000000000..aae264a29ac30d191417c6178c7084c744936ec0 GIT binary patch literal 470 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5LX~AA}#&#Na5p; zU$1w2UGz4Yy?oXCiT>7R&VC+V|NsAIv*W7-Dq<`N@(X5gcy=QV#7XjYcj3yo@Ffh$ zVK4FYb!C6XBPYaT@;WBi6ev{a>Eal|aXmQ!2t*PXnB5dz89CN2VM*iEW^7anI3RH( zKqx`LEU1a2)1om$)Sb;uP+UOwzyS%Z7mprIV@qk7zMPS9f?!V0v}x0LQY4xi6i+yG zrzLYQIN8%GBr7Z1>)^J-<@lMIvJR$=O%4@P5LX~AA}#&#Na5p; zU$1w2&0fChqPNNWiT>7R&VC+V|NsBzvlar`%2*QQ7tG-B>_!@hljQC0!j*C1OBj&D zUgGKN%KnT;PKZ}U`Lr0jA zSObTKrnFIqMWcjPA5V|MwC=?W%*h!Y-Q5XN9gHkbQytneGcq=8l)Rvjm@L3xBr&^J zcUB{tkw-~MiAfjp)si!FZeHXF;t_cvAR^4bkS!}Vp}x=$6a=azt`Q|Ei6yC4$wjF^ ziowXh$Vk`FNY~gP#L&XZ(AdhrLfgQ=%D`aX{fqxlH00)|WTsW()^NTl(+Q|S18ze} iW^QV6Nn&mRrXE9ch$V|kEnWfjFnGH9xvX@P5LX~AA}#&#Na5p; zU$1w2&0fChqPNNWiT>7R&VC+V|NsBzvlar`%2*QQ7tG-B>_!@hljQC0!j*C1OBj&D zUgGKN%KnT;PKZ}CIl zDlmDSYU5GzQ)uf_W>)Ta`bguz0ST!`kCbMxB{4WwN=`_Wl9I~FVM~!{Zcx17!kPTI zkME-s+p)gBzH>7lb@B)~xVbAQD={1h5H0grEXfVDRJFu4q9i4;B-JXpC>2OC7#SED z=^7g88XJTdT38txTNzkr8yHv_80@=$@gItY-29Zxv`X9>&NpQ`0X1mAZ79jiO)V}- c%q_swV`vVsWKpTbE1(_*Pgg&ebxsLQ0C*vXMF0Q* literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai-walk-east-2.png b/src-tauri/test-data/samurai-walk-east-2.png new file mode 100644 index 0000000000000000000000000000000000000000..47a7bc4b7ac20c4f596d76f0835e4b6adb8a00c5 GIT binary patch literal 470 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5LX~AA}#&#Na5p; zU$1w2&0fChqPNNWiT>7R&VC+V|NsBzvlar`%2*QQ7tG-B>_!@hljQC0!j*C1OBj&D zUgGKN%KnT;PKZ}U`Lr0jA zSObTKrnFIqMWcjPA5V|MwC=?W%*h!Y-Q5XN9gHkbQytneGcq=8l)Rvjm@L3xBr&^J zcUB{tkw-~MiAfjp)si!FZeHXF;t_cvAR^4bkS!}Vp}x=$6a=azt`Q|Ei6yC4$wjF^ ziowXh$Vk`FNY~gP#L&XZ(AdhrLfgQ=%D`aX{fqxlH00)|WTsW()^NTl(+Q|S18ze} iW^QV6Nn&mRrXE9ch$V|kEnWfjFnGH9xvX@P5LX~AA}#&#Na5p; zU$1w2&0fChqPNNWiT>7R&VC+V|NsBzvlar`%2*QQ7tG-B>_!@hljQC0!j*C1OBj&D zUgGKN%KnT;PKZ}CIl zDlmDSYU5GzQ)uf_W>)Ta`bguz0ST!`kCbMxB{4WwN=`_Wl9I~FVM~!{Zcx17!kPTI zkMEU3kH#km19^u=TOX+l5EPIe=EGmbgZgq$HN4S|t~y0x1R~10y3{ zLnB>dgAhXtD??)|0}E{f11kfAefKZ^L(!0%pOTqYiCe?@rc5WG1`W6kC7HRY#U+Wk b1(gTe~DWM4fU-*bJ literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai-walk-north-0.png b/src-tauri/test-data/samurai-walk-north-0.png new file mode 100644 index 0000000000000000000000000000000000000000..eeba16790d67979f65e9799b5f60a7230f9b6a08 GIT binary patch literal 449 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF1vcVK4FY zb!C6XBPYZwxYK!?F;FPp)5S4_qcV|%fA z`GcCW8@!ARfgwv~Z%OsKI>SV4<)XD6tMZMUi&CC#O-u}`z|Ed_ERjMVf5hW>!C8<`)MX5lF!N|bKNY~Iv*VrJ$(89{l z*vh~{+rYrez+m6~i~mqGZbM0CZfbE!Vr~JZ9z%18C5uWe RUIFzmc)I$ztaD0e0sxD0i@5** literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai-walk-north-1.png b/src-tauri/test-data/samurai-walk-north-1.png new file mode 100644 index 0000000000000000000000000000000000000000..fa91d12d9042d615e2680fdd3b8aaffce969780c GIT binary patch literal 439 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFY6hHzX@PHFH8uz_w6HQXwlc8LHZZU0&38J+fb63n_66wm|K9U$Iu*N$)Zw=S3o@sp00i_>zopr E0GrZ!y8r+H literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai-walk-north-2.png b/src-tauri/test-data/samurai-walk-north-2.png new file mode 100644 index 0000000000000000000000000000000000000000..49b26932262d0416f008eb02304c5cac5b436992 GIT binary patch literal 449 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF1vcVK4FY zb!C6XBPYZwxYK!?F;FPp)5S4_1GbWni%H{>6VN8glbfGSez?YdGJO=>*iE0k@$fGdH!kBr&%DQ;(rJ#F9m& S7O#MM7(8A5T-G@yGywpnQjU`V literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai-walk-north-3.png b/src-tauri/test-data/samurai-walk-north-3.png new file mode 100644 index 0000000000000000000000000000000000000000..fa91d12d9042d615e2680fdd3b8aaffce969780c GIT binary patch literal 439 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFY6hHzX@PHFH8uz_w6HQXwlc8LHZZU0&38J+fb63n_66wm|K9U$Iu*N$)Zw=S3o@sp00i_>zopr E0GrZ!y8r+H literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai-walk-south-0.png b/src-tauri/test-data/samurai-walk-south-0.png new file mode 100644 index 0000000000000000000000000000000000000000..57440ee27c8e8d914067281d26a7f253c2e2992f GIT binary patch literal 469 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5LX~AA}#&#Na5p; zU$1w2&0fChqPNNWiT>7R&VC+V|NsBzvlar`%2*QQ7tG-B>_!@hljQC0!j*C1OBj&D zUgGKN%KnT;PKZ}74I1)9{g?Mxt0CS>?w=$55M=`QC)W3Ub#w4<5J1W6+pXHOI#yLQW8s2 zt&)pUffR$0fsv7}p^>h!L5QJ+m7%effrYk#ft7*5zWW#dp=ij>PsvQH#I50cQ>GJ8 ng9hA&lFZ!H;*!MN0!%%I<`7F3m0G+4>S6G7^>bP0l+XkKH_({R literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai-walk-south-1.png b/src-tauri/test-data/samurai-walk-south-1.png new file mode 100644 index 0000000000000000000000000000000000000000..9eee67e40008cfadcb467a3dfe2fea6ea3f169e0 GIT binary patch literal 461 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5LX~AA}#&#Na5p; zU$1w2&0fChqPNNWiT>7R&VC+V|NsBzvlar`%2*QQ7tG-B>_!@hljQC0!j*C1OBj&D zUgGKN%KnT;PKZ}|EQt_UVPO)e6Q~oya6&`hTc6#qr}yln-dh!L5QJ+m7%effrYk#ft7*5zWW#dp=ij>PsvQH#I50cQ>GJ8g9hA&lFZ!H;*!MN b0!%%I<`7F3m0G+4>S6G7^>bP0l+XkKpTdS| literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai-walk-south-2.png b/src-tauri/test-data/samurai-walk-south-2.png new file mode 100644 index 0000000000000000000000000000000000000000..57440ee27c8e8d914067281d26a7f253c2e2992f GIT binary patch literal 469 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5LX~AA}#&#Na5p; zU$1w2&0fChqPNNWiT>7R&VC+V|NsBzvlar`%2*QQ7tG-B>_!@hljQC0!j*C1OBj&D zUgGKN%KnT;PKZ}74I1)9{g?Mxt0CS>?w=$55M=`QC)W3Ub#w4<5J1W6+pXHOI#yLQW8s2 zt&)pUffR$0fsv7}p^>h!L5QJ+m7%effrYk#ft7*5zWW#dp=ij>PsvQH#I50cQ>GJ8 ng9hA&lFZ!H;*!MN0!%%I<`7F3m0G+4>S6G7^>bP0l+XkKH_({R literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai-walk-south-3.png b/src-tauri/test-data/samurai-walk-south-3.png new file mode 100644 index 0000000000000000000000000000000000000000..9eee67e40008cfadcb467a3dfe2fea6ea3f169e0 GIT binary patch literal 461 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5LX~AA}#&#Na5p; zU$1w2&0fChqPNNWiT>7R&VC+V|NsBzvlar`%2*QQ7tG-B>_!@hljQC0!j*C1OBj&D zUgGKN%KnT;PKZ}|EQt_UVPO)e6Q~oya6&`hTc6#qr}yln-dh!L5QJ+m7%effrYk#ft7*5zWW#dp=ij>PsvQH#I50cQ>GJ8g9hA&lFZ!H;*!MN b0!%%I<`7F3m0G+4>S6G7^>bP0l+XkKpTdS| literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai-walk-west-0.png b/src-tauri/test-data/samurai-walk-west-0.png new file mode 100644 index 0000000000000000000000000000000000000000..3256db3e5e0859e4534ff04d3aa23ba2be8a14e1 GIT binary patch literal 470 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5LX~AA}#&#Na5p; zU$1w2UGz4Yy?oXCiT>7R&VC+V|NsAIv*W7-Dq<`N@(X5gcy=QV#7XjYcj3yo@Ffh$ zVK4FYb!C6XBPYZwxYK!?F;J+`)5S4_<9c!e5Qro&FuN(bGIFe4!ji_R&Df|Ea6sZn zfKY;fSx^&4r$u9is5_gRptykUfddj+FCIOb#+K4DeK{lJ1i_q~Y15|hq)0S3D4uZW zPD|!qaI&XWNLE(1*THRv%keWaWgSc#n;a(cF)}327OQQZ?;Z!VT(!hCq9i4;B-JXp zC>2OC7#SED=^7g88XJTdT38txTNzkr8yHv_80@=$@gItY-29Zxv`X9>&NpQ`0X1mA kZ79jiO)V}-%q_swV`vVsWKpTbE1(_*Pgg&ebxsLQ04BqVL;wH) literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai-walk-west-1.png b/src-tauri/test-data/samurai-walk-west-1.png new file mode 100644 index 0000000000000000000000000000000000000000..c391eea2f7f100d51c904517e7184eb7814356e8 GIT binary patch literal 464 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5LX~AA}#&#Na5p; zU$1w2UGz4Yy?oXCiT>7R&VC+V|NsAIv*W7-Dq<`N@(X5gcy=QV#7XjYcj3yo@Ffh$ zVK4FYb!C6XBPYZwxYK!?F;FPm)5S4_<9c#}15*!EK$J%ygOj#qW8@((hXouW25g2? zSR`6{rzkin`6)ylo!A(7gw=)Hz@Uw5*Nz=a86_V+&2(T$VUeD_bg3${vxpU%xLX<_Zo4b2EL-UFTmI?1NSQt)fi@pkCFH!(nt6Jh3QIe8al4_M)lnSI6 zj0}v7bPbJkjSWH!EvyWUtqd%*4GgRd4EEi>_zy)xZhlH;S|x4`=bJK}fEqO5Hk4%M grWThZ<`!V;F*Ju*vZ&PJ6;Ka@r>mdKI;Vst07}w|2mk;8 literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai-walk-west-2.png b/src-tauri/test-data/samurai-walk-west-2.png new file mode 100644 index 0000000000000000000000000000000000000000..3256db3e5e0859e4534ff04d3aa23ba2be8a14e1 GIT binary patch literal 470 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5LX~AA}#&#Na5p; zU$1w2UGz4Yy?oXCiT>7R&VC+V|NsAIv*W7-Dq<`N@(X5gcy=QV#7XjYcj3yo@Ffh$ zVK4FYb!C6XBPYZwxYK!?F;J+`)5S4_<9c!e5Qro&FuN(bGIFe4!ji_R&Df|Ea6sZn zfKY;fSx^&4r$u9is5_gRptykUfddj+FCIOb#+K4DeK{lJ1i_q~Y15|hq)0S3D4uZW zPD|!qaI&XWNLE(1*THRv%keWaWgSc#n;a(cF)}327OQQZ?;Z!VT(!hCq9i4;B-JXp zC>2OC7#SED=^7g88XJTdT38txTNzkr8yHv_80@=$@gItY-29Zxv`X9>&NpQ`0X1mA kZ79jiO)V}-%q_swV`vVsWKpTbE1(_*Pgg&ebxsLQ04BqVL;wH) literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai-walk-west-3.png b/src-tauri/test-data/samurai-walk-west-3.png new file mode 100644 index 0000000000000000000000000000000000000000..0a5f64c2b3bed2d52991717df4e49e83645edbd2 GIT binary patch literal 461 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF@P5LX~AA}#&#Na5p; zU$1w2UGz4Yy?oXCiT>7R&VC+V|NsAIv*W7-Dq<`N@(X5gcy=QV#7XjYcj3yo@Ffh$ zVK4FYb!C6XBPYZwxYK!?F;FPO)5S4_<9c#}15*!EK$J%ygOj#qW8@((hXouW25g2? zSR`6{rzkin`6)ylo!A(7gw=)Hz@Uw5*Nz=a86_V+&2(T$VUeD_bg3${vxpU%xLX<_Zn>%}l;zdRlCLV^9OGSgEpC-lt?NlvsjVMV;EJ?LWE=mPb3`Pb< zM!JSZy2b_}h89+a##ROv+6D$z1_t}?U;KxnAvZrIGp!Q0hVxCCPCyMBa2rZ8b5n~; d5_1bM^%$B%ELl`)@d~Ji!PC{xWt~$(69C3ihvonP literal 0 HcmV?d00001 diff --git a/src-tauri/test-data/samurai.tiger b/src-tauri/test-data/samurai.tiger new file mode 100644 index 0000000..2347f5a --- /dev/null +++ b/src-tauri/test-data/samurai.tiger @@ -0,0 +1,442 @@ +{ + "version": "Tiger4", + "sheet": { + "frames": [ + { + "source": "samurai-attack-east.png" + }, + { + "source": "samurai-attack-north.png" + }, + { + "source": "samurai-attack-south.png" + }, + { + "source": "samurai-attack-west.png" + }, + { + "source": "samurai-dead-all.png" + }, + { + "source": "samurai-idle-east.png" + }, + { + "source": "samurai-idle-north.png" + }, + { + "source": "samurai-idle-south.png" + }, + { + "source": "samurai-idle-west.png" + }, + { + "source": "samurai-walk-east-0.png" + }, + { + "source": "samurai-walk-east-1.png" + }, + { + "source": "samurai-walk-east-2.png" + }, + { + "source": "samurai-walk-east-3.png" + }, + { + "source": "samurai-walk-north-0.png" + }, + { + "source": "samurai-walk-north-1.png" + }, + { + "source": "samurai-walk-north-2.png" + }, + { + "source": "samurai-walk-north-3.png" + }, + { + "source": "samurai-walk-south-0.png" + }, + { + "source": "samurai-walk-south-1.png" + }, + { + "source": "samurai-walk-south-2.png" + }, + { + "source": "samurai-walk-south-3.png" + }, + { + "source": "samurai-walk-west-0.png" + }, + { + "source": "samurai-walk-west-1.png" + }, + { + "source": "samurai-walk-west-2.png" + }, + { + "source": "samurai-walk-west-3.png" + } + ], + "animations": { + "attack": { + "sequences": { + "East": { + "keyframes": [ + { + "frame": "samurai-attack-east.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + } + ] + }, + "North": { + "keyframes": [ + { + "frame": "samurai-attack-north.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + } + ] + }, + "West": { + "keyframes": [ + { + "frame": "samurai-attack-west.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + } + ] + }, + "South": { + "keyframes": [ + { + "frame": "samurai-attack-south.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + } + ] + } + }, + "is_looping": false + }, + "dead": { + "sequences": { + "North": { + "keyframes": [ + { + "frame": "samurai-dead-all.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + } + ] + } + }, + "is_looping": false + }, + "idle": { + "sequences": { + "East": { + "keyframes": [ + { + "frame": "samurai-idle-east.png", + "hitboxes": { + "weak": { + "geometry": { + "Rectangle": { + "top_left": [ + -5, + -13 + ], + "size": [ + 10, + 10 + ] + } + } + } + }, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + } + ] + }, + "North": { + "keyframes": [ + { + "frame": "samurai-idle-north.png", + "hitboxes": { + "weak": { + "geometry": { + "Rectangle": { + "top_left": [ + -5, + -13 + ], + "size": [ + 10, + 10 + ] + } + } + } + }, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + } + ] + }, + "West": { + "keyframes": [ + { + "frame": "samurai-idle-west.png", + "hitboxes": { + "weak": { + "geometry": { + "Rectangle": { + "top_left": [ + -5, + -13 + ], + "size": [ + 10, + 10 + ] + } + } + } + }, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + } + ] + }, + "South": { + "keyframes": [ + { + "frame": "samurai-idle-south.png", + "hitboxes": { + "weak": { + "geometry": { + "Rectangle": { + "top_left": [ + -5, + -13 + ], + "size": [ + 10, + 10 + ] + } + } + } + }, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + } + ] + } + }, + "is_looping": false + }, + "walk": { + "sequences": { + "East": { + "keyframes": [ + { + "frame": "samurai-walk-east-0.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + }, + { + "frame": "samurai-walk-east-1.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + }, + { + "frame": "samurai-walk-east-2.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + }, + { + "frame": "samurai-walk-east-3.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + } + ] + }, + "North": { + "keyframes": [ + { + "frame": "samurai-walk-north-0.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + }, + { + "frame": "samurai-walk-north-1.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + }, + { + "frame": "samurai-walk-north-2.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + }, + { + "frame": "samurai-walk-north-3.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + } + ] + }, + "West": { + "keyframes": [ + { + "frame": "samurai-walk-west-0.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + }, + { + "frame": "samurai-walk-west-1.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + }, + { + "frame": "samurai-walk-west-2.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + }, + { + "frame": "samurai-walk-west-3.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + } + ] + }, + "South": { + "keyframes": [ + { + "frame": "samurai-walk-south-0.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + }, + { + "frame": "samurai-walk-south-1.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + }, + { + "frame": "samurai-walk-south-2.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + }, + { + "frame": "samurai-walk-south-3.png", + "hitboxes": {}, + "duration_millis": 100, + "offset": [ + 0, + -8 + ] + } + ] + } + }, + "is_looping": true + } + }, + "export_settings": null + } +} \ No newline at end of file From 3f6d96c8a293b106dce01cf6c93d496c104c75f2 Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Fri, 30 Dec 2022 22:52:52 +0100 Subject: [PATCH 62/77] Fixed a bug where workbench diffs could affect incorrect animations --- src-tauri/src/dto.rs | 51 +++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/src-tauri/src/dto.rs b/src-tauri/src/dto.rs index a24c24b..89198f7 100644 --- a/src-tauri/src/dto.rs +++ b/src-tauri/src/dto.rs @@ -110,7 +110,7 @@ pub struct Frame { filtered_out: bool, } -#[derive(Clone, Serialize)] +#[derive(Clone, Default, Serialize)] #[serde(rename_all = "camelCase")] pub struct Animation { name: String, @@ -461,12 +461,17 @@ impl sheet::Sheet

{ animations: self .sorted_animations() .into_iter() - .filter(|(name, _)| match &trim { - SheetTrim::Full => true, - SheetTrim::OnlyAnimation(n) => *name == n, - SheetTrim::Empty => false, + .filter_map(|(name, animation)| match &trim { + SheetTrim::Full => Some(animation.to_dto(name)), + SheetTrim::OnlyAnimation(n) => { + if name == n { + Some(animation.to_dto(name)) + } else { + Some(Animation::default()) + } + } + SheetTrim::Empty => None, }) - .map(|(name, animation)| (name, animation).into()) .collect(), } } @@ -483,23 +488,19 @@ impl From<&sheet::Frame

> for Frame { } } -impl From<(T, &sheet::Animation

)> for Animation -where - T: AsRef, -{ - fn from(animation: (T, &sheet::Animation

)) -> Self { - Self { - name: animation.0.as_ref().to_owned(), +impl sheet::Animation

{ + fn to_dto>(&self, name: T) -> Animation { + Animation { + name: name.as_ref().to_owned(), selected: false, filtered_out: false, - sequences: animation - .1 + sequences: self .sequences_iter() .map(|(d, s)| ((*d).into(), s.into())) .collect(), - direction_preset: animation.1.direction_preset().map(|p| p.into()), - is_looping: animation.1.looping(), - key: animation.1.key(), + direction_preset: self.direction_preset().map(|p| p.into()), + is_looping: self.looping(), + key: self.key(), } } } @@ -743,8 +744,18 @@ mod test { let dto = app.to_dto(AppTrim::OnlyWorkbench); assert_eq!(dto.documents.len(), 2); assert!(dto.documents[0].sheet.animations.is_empty()); - assert_eq!(dto.documents[1].sheet.animations.len(), 1); - assert_eq!(dto.documents[1].sheet.animations[0].name, animation_name); + // Must preserve size of animations array to avoid patching incorrect array entries + assert_eq!( + dto.documents[1].sheet.animations.len(), + app.current_document() + .unwrap() + .sheet() + .animations_iter() + .count() + ); + for animation in &dto.documents[1].sheet.animations { + assert!(animation.sequences.is_empty() || animation.name == animation_name); + } } #[test] From 393f120276228e2c7d8856e8b34fa05f4d21c479 Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Fri, 30 Dec 2022 23:38:06 +0100 Subject: [PATCH 63/77] Added export test --- src-tauri/.gitignore | 1 + src-tauri/src/export.rs | 30 +++++++++++ src-tauri/src/export/texture.rs | 17 +++--- src-tauri/test-data/export.template | 22 ++++++++ src-tauri/test-data/flame.tiger | 11 +++- src-tauri/test-data/samurai.export | 81 +++++++++++++++++++++++++++++ src-tauri/test-data/samurai.tiger | 11 +++- 7 files changed, 163 insertions(+), 10 deletions(-) create mode 100644 src-tauri/test-data/export.template create mode 100644 src-tauri/test-data/samurai.export diff --git a/src-tauri/.gitignore b/src-tauri/.gitignore index c123704..c201234 100644 --- a/src-tauri/.gitignore +++ b/src-tauri/.gitignore @@ -1,4 +1,5 @@ # Generated by Cargo # will have compiled files and executables /target/ +/test-output/ WixTools diff --git a/src-tauri/src/export.rs b/src-tauri/src/export.rs index b7bf10a..d8abb8e 100644 --- a/src-tauri/src/export.rs +++ b/src-tauri/src/export.rs @@ -76,3 +76,33 @@ fn create_file(path: &Path) -> Result { fn create_dir(path: &Path) -> Result<(), ExportError> { create_dir_all(path).map_err(|e| ExportError::IoError(path.to_owned(), e)) } + +#[cfg(test)] +mod test { + + use parking_lot::Mutex; + use std::collections::HashMap; + use std::sync::Arc; + + use super::*; + use crate::{app, document, export}; + + #[test] + fn export_matches_known_output() { + let texture_cache = Arc::new(Mutex::new(HashMap::new())); + let mut app = app::App::default(); + app.open_document(document::Document::open("test-data/samurai.tiger").unwrap()); + let document = app.current_document().unwrap(); + let packed_sheet = export::pack_sheet(document.sheet(), texture_cache).unwrap(); + let exported = generate_sheet_metadata( + document.sheet(), + document.sheet().export_settings().as_ref().unwrap(), + packed_sheet.layout(), + ) + .unwrap(); + assert_eq!( + exported, + std::fs::read_to_string("test-data/samurai.export").unwrap() + ); + } +} diff --git a/src-tauri/src/export/texture.rs b/src-tauri/src/export/texture.rs index 3bc43ff..4891d68 100644 --- a/src-tauri/src/export/texture.rs +++ b/src-tauri/src/export/texture.rs @@ -53,12 +53,17 @@ pub(super) fn pack_sheet( } } - let items = bitmaps.iter().map(|(path, bitmap)| crunch::Item { - data: path, - w: bitmap.width() as usize, - h: bitmap.height() as usize, - rot: crunch::Rotation::None, - }); + let mut items = bitmaps + .iter() + .map(|(path, bitmap)| crunch::Item { + data: path, + w: bitmap.width() as usize, + h: bitmap.height() as usize, + rot: crunch::Rotation::None, + }) + .collect::>(); + items.sort_by_key(|i| i.data); + let (width, height, layout) = crunch::pack_into_po2(8_192, items).map_err(|_| PackError::Packing)?; let layout = layout diff --git a/src-tauri/test-data/export.template b/src-tauri/test-data/export.template new file mode 100644 index 0000000..cb68ba8 --- /dev/null +++ b/src-tauri/test-data/export.template @@ -0,0 +1,22 @@ +TEXTURE +{{ replace sheet_image "\\" "/" }} + +FRAMES +{{ #each frames as |frame| }} +{{ frame.index }} x = {{ frame.x }}, y = {{ frame.y }}, w = {{ frame.width }}, h = {{ frame.height }} +{{ /each }} + +ANIMATIONS +{{ #each animations as |animation| }} +[{{ animation.name }}] +loop = {{ animation.is_looping }}, +{{ #each sequences as |sequence| }} + direction = {{ sequence.direction }} + {{ #each sequence.keyframes as |keyframe| }} + id = {{ keyframe.frame.index }}, duration = {{ keyframe.duration }}, ox = {{ keyframe.x }}, oy = {{ keyframe.y }} + {{ #each keyframe.hitboxes as |hitbox| }} + [{{ hitbox.name }}] x = {{ hitbox.x }}, y = {{ hitbox.y }}, w = {{ hitbox.width }}, h = {{ hitbox.height }} + {{ /each }} + {{ /each }} +{{ /each }} +{{ /each }} diff --git a/src-tauri/test-data/flame.tiger b/src-tauri/test-data/flame.tiger index 5347378..a1517c4 100644 --- a/src-tauri/test-data/flame.tiger +++ b/src-tauri/test-data/flame.tiger @@ -194,6 +194,13 @@ "is_looping": true } }, - "export_settings": null + "export_settings": { + "Template": { + "template_file": "export.template", + "texture_file": "..\\test-output\\flame.png", + "metadata_file": "..\\test-output\\flame.export", + "metadata_paths_root": "..\\test-output" + } + } } -} \ No newline at end of file +} diff --git a/src-tauri/test-data/samurai.export b/src-tauri/test-data/samurai.export new file mode 100644 index 0000000..b7b9765 --- /dev/null +++ b/src-tauri/test-data/samurai.export @@ -0,0 +1,81 @@ +TEXTURE +samurai.png + +FRAMES +0 x = 96, y = 16, w = 16, h = 16 +1 x = 80, y = 16, w = 16, h = 16 +2 x = 64, y = 48, w = 16, h = 16 +3 x = 64, y = 32, w = 16, h = 16 +4 x = 64, y = 16, w = 16, h = 16 +5 x = 112, y = 0, w = 16, h = 16 +6 x = 96, y = 0, w = 16, h = 16 +7 x = 80, y = 0, w = 16, h = 16 +8 x = 64, y = 0, w = 16, h = 16 +9 x = 48, y = 48, w = 16, h = 16 +10 x = 48, y = 32, w = 16, h = 16 +11 x = 48, y = 16, w = 16, h = 16 +12 x = 48, y = 0, w = 16, h = 16 +13 x = 32, y = 48, w = 16, h = 16 +14 x = 32, y = 32, w = 16, h = 16 +15 x = 32, y = 16, w = 16, h = 16 +16 x = 32, y = 0, w = 16, h = 16 +17 x = 16, y = 48, w = 16, h = 16 +18 x = 16, y = 32, w = 16, h = 16 +19 x = 16, y = 16, w = 16, h = 16 +20 x = 16, y = 0, w = 16, h = 16 +21 x = 0, y = 48, w = 16, h = 16 +22 x = 0, y = 32, w = 16, h = 16 +23 x = 0, y = 16, w = 16, h = 16 +24 x = 0, y = 0, w = 16, h = 16 + +ANIMATIONS +[attack] +loop = false, + direction = East + id = 0, duration = 100, ox = -8, oy = -16 + direction = North + id = 1, duration = 100, ox = -8, oy = -16 + direction = West + id = 3, duration = 100, ox = -8, oy = -16 + direction = South + id = 2, duration = 100, ox = -8, oy = -16 +[dead] +loop = false, + direction = North + id = 4, duration = 100, ox = -8, oy = -16 +[idle] +loop = false, + direction = East + id = 5, duration = 100, ox = -8, oy = -16 + [weak] x = -5, y = -13, w = 10, h = 10 + direction = North + id = 6, duration = 100, ox = -8, oy = -16 + [weak] x = -5, y = -13, w = 10, h = 10 + direction = West + id = 8, duration = 100, ox = -8, oy = -16 + [weak] x = -5, y = -13, w = 10, h = 10 + direction = South + id = 7, duration = 100, ox = -8, oy = -16 + [weak] x = -5, y = -13, w = 10, h = 10 +[walk] +loop = true, + direction = East + id = 9, duration = 100, ox = -8, oy = -16 + id = 10, duration = 100, ox = -8, oy = -16 + id = 11, duration = 100, ox = -8, oy = -16 + id = 12, duration = 100, ox = -8, oy = -16 + direction = North + id = 13, duration = 100, ox = -8, oy = -16 + id = 14, duration = 100, ox = -8, oy = -16 + id = 15, duration = 100, ox = -8, oy = -16 + id = 16, duration = 100, ox = -8, oy = -16 + direction = West + id = 21, duration = 100, ox = -8, oy = -16 + id = 22, duration = 100, ox = -8, oy = -16 + id = 23, duration = 100, ox = -8, oy = -16 + id = 24, duration = 100, ox = -8, oy = -16 + direction = South + id = 17, duration = 100, ox = -8, oy = -16 + id = 18, duration = 100, ox = -8, oy = -16 + id = 19, duration = 100, ox = -8, oy = -16 + id = 20, duration = 100, ox = -8, oy = -16 diff --git a/src-tauri/test-data/samurai.tiger b/src-tauri/test-data/samurai.tiger index 2347f5a..6e0c2b7 100644 --- a/src-tauri/test-data/samurai.tiger +++ b/src-tauri/test-data/samurai.tiger @@ -437,6 +437,13 @@ "is_looping": true } }, - "export_settings": null + "export_settings": { + "Template": { + "template_file": "export.template", + "texture_file": "..\\test-output\\samurai.png", + "metadata_file": "..\\test-output\\samurai.export", + "metadata_paths_root": "..\\test-output" + } + } } -} \ No newline at end of file +} From 4edd2ad98bbd58cc25285b1f7fa581f6ac852d03 Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Sat, 31 Dec 2022 00:29:50 +0100 Subject: [PATCH 64/77] Always store paths with forward slashes in tiger fields --- src-tauri/src/sheet.rs | 5 +++++ src-tauri/src/sheet/version4.rs | 8 +++++++- src-tauri/test-data/flame.tiger | 8 ++++---- src-tauri/test-data/samurai.tiger | 8 ++++---- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src-tauri/src/sheet.rs b/src-tauri/src/sheet.rs index 521d794..0c6021c 100644 --- a/src-tauri/src/sheet.rs +++ b/src-tauri/src/sheet.rs @@ -1089,6 +1089,11 @@ fn ordered_slice( sorted.serialize(serializer) } +fn portable_path(value: &PathBuf, serializer: S) -> Result { + let cleaned = value.to_string_lossy().replace('\\', "/"); + cleaned.serialize(serializer) +} + #[test] fn can_read_write_sheet_from_disk() { let original = Sheet::::read("test-data/sample_sheet_1.tiger") diff --git a/src-tauri/src/sheet/version4.rs b/src-tauri/src/sheet/version4.rs index 9532ed0..67f8dc7 100644 --- a/src-tauri/src/sheet/version4.rs +++ b/src-tauri/src/sheet/version4.rs @@ -6,7 +6,7 @@ use std::path::PathBuf; use uuid::Uuid; use crate::sheet::version3 as previous_version; -use crate::sheet::{ordered_map, ordered_slice, Any, Paths, SheetError, Version}; +use crate::sheet::{ordered_map, ordered_slice, portable_path, Any, Paths, SheetError, Version}; const THIS_VERSION: Version = Version::Tiger4; @@ -28,6 +28,7 @@ pub struct Sheet { #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct Frame { + #[serde(serialize_with = "portable_path")] pub(in crate::sheet) source: PathBuf, #[serde(skip)] pub(in crate::sheet) paths: std::marker::PhantomData

, @@ -89,6 +90,7 @@ pub struct Sequence { #[derivative(PartialEq)] #[derive(Clone, Debug, Eq, Serialize, Deserialize)] pub struct Keyframe { + #[serde(serialize_with = "portable_path")] pub(in crate::sheet) frame: PathBuf, #[serde(serialize_with = "ordered_map")] pub(in crate::sheet) hitboxes: HashMap, @@ -123,9 +125,13 @@ pub enum ExportSettings { #[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] pub struct TemplateExportSettings { + #[serde(serialize_with = "portable_path")] pub(in crate::sheet) template_file: PathBuf, + #[serde(serialize_with = "portable_path")] pub(in crate::sheet) texture_file: PathBuf, + #[serde(serialize_with = "portable_path")] pub(in crate::sheet) metadata_file: PathBuf, + #[serde(serialize_with = "portable_path")] pub(in crate::sheet) metadata_paths_root: PathBuf, #[serde(skip)] pub(in crate::sheet) paths: std::marker::PhantomData

, diff --git a/src-tauri/test-data/flame.tiger b/src-tauri/test-data/flame.tiger index a1517c4..367c45c 100644 --- a/src-tauri/test-data/flame.tiger +++ b/src-tauri/test-data/flame.tiger @@ -197,10 +197,10 @@ "export_settings": { "Template": { "template_file": "export.template", - "texture_file": "..\\test-output\\flame.png", - "metadata_file": "..\\test-output\\flame.export", - "metadata_paths_root": "..\\test-output" + "texture_file": "../test-output/flame.png", + "metadata_file": "../test-output/flame.export", + "metadata_paths_root": "../test-output" } } } -} +} \ No newline at end of file diff --git a/src-tauri/test-data/samurai.tiger b/src-tauri/test-data/samurai.tiger index 6e0c2b7..1e5437f 100644 --- a/src-tauri/test-data/samurai.tiger +++ b/src-tauri/test-data/samurai.tiger @@ -440,10 +440,10 @@ "export_settings": { "Template": { "template_file": "export.template", - "texture_file": "..\\test-output\\samurai.png", - "metadata_file": "..\\test-output\\samurai.export", - "metadata_paths_root": "..\\test-output" + "texture_file": "../test-output/samurai.png", + "metadata_file": "../test-output/samurai.export", + "metadata_paths_root": "../test-output" } } } -} +} \ No newline at end of file From e298585bdba88b8b73d38dd80044bacc60e915e5 Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Sat, 31 Dec 2022 00:49:39 +0100 Subject: [PATCH 65/77] Fix broken test on linux --- src-tauri/src/sheet.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src-tauri/src/sheet.rs b/src-tauri/src/sheet.rs index 0c6021c..f6e96d0 100644 --- a/src-tauri/src/sheet.rs +++ b/src-tauri/src/sheet.rs @@ -1096,21 +1096,18 @@ fn portable_path(value: &PathBuf, serializer: S) -> Result #[test] fn can_read_write_sheet_from_disk() { - let original = Sheet::::read("test-data/sample_sheet_1.tiger") + let original = Sheet::::read("test-data/samurai.tiger") .unwrap() .with_relative_paths("test-data") .unwrap() .with_absolute_paths(); - original - .clone() - .write("test-data/sample_sheet_copy.tiger") - .unwrap(); - let copy = Sheet::::read("test-data/sample_sheet_copy.tiger") + original.clone().write("test-data/copy.tiger").unwrap(); + let copy = Sheet::::read("test-data/copy.tiger") .unwrap() .with_relative_paths("test-data") .unwrap() .with_absolute_paths(); - std::fs::remove_file("test-data/sample_sheet_copy.tiger").unwrap(); + std::fs::remove_file("test-data/copy.tiger").unwrap(); assert_eq!(original, copy); } From 3c00008497f8e302c425b293cbb36ba6df520527 Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Sat, 31 Dec 2022 10:39:04 +0100 Subject: [PATCH 66/77] Removed old test files --- src-tauri/src/app.rs | 65 +- src-tauri/src/dto.rs | 14 +- src-tauri/test-data/sample_sheet_1.tiger | 3215 ---------------------- src-tauri/test-data/sample_sheet_2.tiger | 978 ------- 4 files changed, 39 insertions(+), 4233 deletions(-) delete mode 100644 src-tauri/test-data/sample_sheet_1.tiger delete mode 100644 src-tauri/test-data/sample_sheet_2.tiger diff --git a/src-tauri/src/app.rs b/src-tauri/src/app.rs index 765f39a..9f389a0 100644 --- a/src-tauri/src/app.rs +++ b/src-tauri/src/app.rs @@ -220,42 +220,42 @@ mod test { fn can_open_and_close_documents() { let mut app = App::default(); - app.open_document(Document::open("test-data/sample_sheet_1.tiger").unwrap()); + app.open_document(Document::open("test-data/samurai.tiger").unwrap()); assert_eq!(app.documents_iter().count(), 1); - assert!(app.document("test-data/sample_sheet_1.tiger").is_some()); - assert!(app.document_mut("test-data/sample_sheet_1.tiger").is_some()); + assert!(app.document("test-data/samurai.tiger").is_some()); + assert!(app.document_mut("test-data/samurai.tiger").is_some()); - app.open_document(Document::open("test-data/sample_sheet_2.tiger").unwrap()); + app.open_document(Document::open("test-data/flame.tiger").unwrap()); assert_eq!(app.documents_iter().count(), 2); - assert!(app.document("test-data/sample_sheet_2.tiger").is_some()); - assert!(app.document_mut("test-data/sample_sheet_2.tiger").is_some()); + assert!(app.document("test-data/flame.tiger").is_some()); + assert!(app.document_mut("test-data/flame.tiger").is_some()); - app.close_document("test-data/sample_sheet_2.tiger"); + app.close_document("test-data/flame.tiger"); assert_eq!(app.documents_iter().count(), 1); - assert!(app.document("test-data/sample_sheet_2.tiger").is_none()); - assert!(app.document_mut("test-data/sample_sheet_2.tiger").is_none()); + assert!(app.document("test-data/flame.tiger").is_none()); + assert!(app.document_mut("test-data/flame.tiger").is_none()); } #[test] fn open_and_close_updates_focused_document() { let mut app = App::default(); - app.open_document(Document::open("test-data/sample_sheet_1.tiger").unwrap()); + app.open_document(Document::open("test-data/samurai.tiger").unwrap()); assert_eq!( app.current_document().unwrap().path(), - Path::new("test-data/sample_sheet_1.tiger") + Path::new("test-data/samurai.tiger") ); - app.open_document(Document::open("test-data/sample_sheet_2.tiger").unwrap()); + app.open_document(Document::open("test-data/flame.tiger").unwrap()); assert_eq!( app.current_document().unwrap().path(), - Path::new("test-data/sample_sheet_2.tiger") + Path::new("test-data/flame.tiger") ); - app.close_document("test-data/sample_sheet_2.tiger"); + app.close_document("test-data/flame.tiger"); assert_eq!( app.current_document().unwrap().path(), - Path::new("test-data/sample_sheet_1.tiger") + Path::new("test-data/samurai.tiger") ); } @@ -263,13 +263,12 @@ mod test { fn can_manually_focus_a_document() { let mut app = App::default(); - app.open_document(Document::open("test-data/sample_sheet_1.tiger").unwrap()); - app.open_document(Document::open("test-data/sample_sheet_2.tiger").unwrap()); - app.focus_document("test-data/sample_sheet_1.tiger") - .unwrap(); + app.open_document(Document::open("test-data/samurai.tiger").unwrap()); + app.open_document(Document::open("test-data/flame.tiger").unwrap()); + app.focus_document("test-data/samurai.tiger").unwrap(); assert_eq!( app.current_document().unwrap().path(), - Path::new("test-data/sample_sheet_1.tiger") + Path::new("test-data/samurai.tiger") ); } @@ -277,37 +276,37 @@ mod test { fn keeps_track_of_recently_opened_documents() { let mut app = App::default(); - app.open_document(Document::open("test-data/sample_sheet_1.tiger").unwrap()); + app.open_document(Document::open("test-data/samurai.tiger").unwrap()); assert_eq!( *app.recent_documents, - vec![PathBuf::from("test-data/sample_sheet_1.tiger")] + vec![PathBuf::from("test-data/samurai.tiger")] ); - app.open_document(Document::open("test-data/sample_sheet_2.tiger").unwrap()); + app.open_document(Document::open("test-data/flame.tiger").unwrap()); assert_eq!( *app.recent_documents, vec![ - PathBuf::from("test-data/sample_sheet_2.tiger"), - PathBuf::from("test-data/sample_sheet_1.tiger") + PathBuf::from("test-data/flame.tiger"), + PathBuf::from("test-data/samurai.tiger") ] ); - app.open_document(Document::open("test-data/sample_sheet_1.tiger").unwrap()); + app.open_document(Document::open("test-data/samurai.tiger").unwrap()); assert_eq!( *app.recent_documents, vec![ - PathBuf::from("test-data/sample_sheet_1.tiger"), - PathBuf::from("test-data/sample_sheet_2.tiger"), + PathBuf::from("test-data/samurai.tiger"), + PathBuf::from("test-data/flame.tiger"), ] ); - app.relocate_document("test-data/sample_sheet_1.tiger", "relocated"); + app.relocate_document("test-data/samurai.tiger", "relocated"); assert_eq!( *app.recent_documents, vec![ PathBuf::from("relocated"), - PathBuf::from("test-data/sample_sheet_1.tiger"), - PathBuf::from("test-data/sample_sheet_2.tiger"), + PathBuf::from("test-data/samurai.tiger"), + PathBuf::from("test-data/flame.tiger"), ] ); @@ -317,8 +316,8 @@ mod test { vec![ PathBuf::from("new"), PathBuf::from("relocated"), - PathBuf::from("test-data/sample_sheet_1.tiger"), - PathBuf::from("test-data/sample_sheet_2.tiger"), + PathBuf::from("test-data/samurai.tiger"), + PathBuf::from("test-data/flame.tiger"), ] ); } diff --git a/src-tauri/src/dto.rs b/src-tauri/src/dto.rs index 89198f7..eab463b 100644 --- a/src-tauri/src/dto.rs +++ b/src-tauri/src/dto.rs @@ -710,8 +710,8 @@ mod test { #[test] fn can_preserve_all() { let mut app = app::App::default(); - app.open_document(document::Document::open("test-data/sample_sheet_1.tiger").unwrap()); - app.open_document(document::Document::open("test-data/sample_sheet_2.tiger").unwrap()); + app.open_document(document::Document::open("test-data/samurai.tiger").unwrap()); + app.open_document(document::Document::open("test-data/flame.tiger").unwrap()); let dto = app.to_dto(AppTrim::Full); assert_eq!(dto.documents.len(), 2); assert!(!dto.documents[0].sheet.animations.is_empty()); @@ -721,8 +721,8 @@ mod test { #[test] fn can_trim_inactive_documents() { let mut app = app::App::default(); - app.open_document(document::Document::open("test-data/sample_sheet_1.tiger").unwrap()); - app.open_document(document::Document::open("test-data/sample_sheet_2.tiger").unwrap()); + app.open_document(document::Document::open("test-data/samurai.tiger").unwrap()); + app.open_document(document::Document::open("test-data/flame.tiger").unwrap()); let dto = app.to_dto(AppTrim::OnlyCurrentDocument); assert_eq!(dto.documents.len(), 2); assert!(dto.documents[0].sheet.animations.is_empty()); @@ -732,8 +732,8 @@ mod test { #[test] fn can_trim_all_except_workbench() { let mut app = app::App::default(); - app.open_document(document::Document::open("test-data/sample_sheet_1.tiger").unwrap()); - app.open_document(document::Document::open("test-data/sample_sheet_2.tiger").unwrap()); + app.open_document(document::Document::open("test-data/samurai.tiger").unwrap()); + app.open_document(document::Document::open("test-data/flame.tiger").unwrap()); let animation_name = app .current_document() .unwrap() @@ -761,7 +761,7 @@ mod test { #[test] fn can_trim_all_documents() { let mut app = app::App::default(); - app.open_document(document::Document::open("test-data/sample_sheet_1.tiger").unwrap()); + app.open_document(document::Document::open("test-data/samurai.tiger").unwrap()); let dto = app.to_dto(AppTrim::NoDocuments); assert!(!dto.documents.is_empty()); assert!(dto.documents[0].sheet.animations.is_empty()); diff --git a/src-tauri/test-data/sample_sheet_1.tiger b/src-tauri/test-data/sample_sheet_1.tiger deleted file mode 100644 index c747c71..0000000 --- a/src-tauri/test-data/sample_sheet_1.tiger +++ /dev/null @@ -1,3215 +0,0 @@ -{ - "version": "Tiger1", - "sheet": { - "frames": [ - { - "source": "attack_down_0_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -12, - -6 - ], - "size": [ - 16, - 14 - ] - } - } - } - ] - }, - { - "source": "attack_down_0_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -2 - ], - "size": [ - 14, - 20 - ] - } - } - } - ] - }, - { - "source": "attack_down_0_2.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -21, - -2 - ], - "size": [ - 42, - 21 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -13, - -9 - ], - "size": [ - 20, - 14 - ] - } - } - } - ] - }, - { - "source": "attack_down_0_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -13, - -9 - ], - "size": [ - 21, - 14 - ] - } - } - } - ] - }, - { - "source": "attack_down_1_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -1, - -6 - ], - "size": [ - 11, - 15 - ] - } - } - } - ] - }, - { - "source": "attack_down_1_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -10 - ], - "size": [ - 13, - 14 - ] - } - } - } - ] - }, - { - "source": "attack_down_1_2.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -8, - -2 - ], - "size": [ - 12, - 26 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -8, - -11 - ], - "size": [ - 16, - 11 - ] - } - } - } - ] - }, - { - "source": "attack_down_1_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -8, - -10 - ], - "size": [ - 15, - 10 - ] - } - } - } - ] - }, - { - "source": "attack_down_2_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -8 - ], - "size": [ - 9, - 20 - ] - } - } - } - ] - }, - { - "source": "attack_down_2_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -6 - ], - "size": [ - 11, - 16 - ] - } - } - } - ] - }, - { - "source": "attack_down_2_2.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -14, - -7 - ], - "size": [ - 27, - 30 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -3, - -11 - ], - "size": [ - 13, - 17 - ] - } - } - } - ] - }, - { - "source": "attack_down_2_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -1, - -6 - ], - "size": [ - 11, - 16 - ] - } - } - } - ] - }, - { - "source": "attack_down_3_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -3, - -5 - ], - "size": [ - 11, - 15 - ] - } - } - } - ] - }, - { - "source": "attack_down_3_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -8, - -13 - ], - "size": [ - 16, - 8 - ] - } - } - } - ] - }, - { - "source": "attack_down_3_2.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -34, - -5 - ], - "size": [ - 55, - 32 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -14, - -14 - ], - "size": [ - 14, - 17 - ] - } - } - } - ] - }, - { - "source": "attack_down_3_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -10, - -5 - ], - "size": [ - 12, - 15 - ] - } - } - } - ] - }, - { - "source": "attack_left_0_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -7, - -7 - ], - "size": [ - 10, - 17 - ] - } - } - } - ] - }, - { - "source": "attack_left_0_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -3, - 0 - ], - "size": [ - 11, - 16 - ] - } - } - } - ] - }, - { - "source": "attack_left_0_2.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -24, - -15 - ], - "size": [ - 25, - 39 - ] - } - } - } - ] - }, - { - "source": "attack_left_0_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -7 - ], - "size": [ - 13, - 13 - ] - } - } - } - ] - }, - { - "source": "attack_left_1_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -7 - ], - "size": [ - 14, - 15 - ] - } - } - } - ] - }, - { - "source": "attack_left_1_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -7, - -6 - ], - "size": [ - 15, - 16 - ] - } - } - } - ] - }, - { - "source": "attack_left_1_2.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -26, - -3 - ], - "size": [ - 30, - 17 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - 0, - -7 - ], - "size": [ - 15, - 16 - ] - } - } - } - ] - }, - { - "source": "attack_left_1_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -1, - -5 - ], - "size": [ - 15, - 14 - ] - } - } - } - ] - }, - { - "source": "attack_left_2_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -10, - -7 - ], - "size": [ - 12, - 17 - ] - } - } - } - ] - }, - { - "source": "attack_left_2_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -1, - -3 - ], - "size": [ - 14, - 18 - ] - } - } - } - ] - }, - { - "source": "attack_left_2_2.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -23, - -21 - ], - "size": [ - 24, - 34 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -3, - -4 - ], - "size": [ - 16, - 13 - ] - } - } - } - ] - }, - { - "source": "attack_left_2_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -5 - ], - "size": [ - 18, - 11 - ] - } - } - } - ] - }, - { - "source": "attack_left_3_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -10, - -5 - ], - "size": [ - 14, - 14 - ] - } - } - } - ] - }, - { - "source": "attack_left_3_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -1, - -5 - ], - "size": [ - 13, - 14 - ] - } - } - } - ] - }, - { - "source": "attack_left_3_2.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -23, - -15 - ], - "size": [ - 26, - 29 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - 4, - -7 - ], - "size": [ - 12, - 16 - ] - } - } - } - ] - }, - { - "source": "attack_left_3_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -8, - -4 - ], - "size": [ - 13, - 13 - ] - } - } - } - ] - }, - { - "source": "attack_right_0_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -1, - -8 - ], - "size": [ - 9, - 17 - ] - } - } - } - ] - }, - { - "source": "attack_right_0_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -1 - ], - "size": [ - 10, - 16 - ] - } - } - } - ] - }, - { - "source": "attack_right_0_2.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - 0, - -14 - ], - "size": [ - 20, - 39 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -11, - 5 - ], - "size": [ - 18, - 11 - ] - } - } - } - ] - }, - { - "source": "attack_right_0_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -9, - -3 - ], - "size": [ - 15, - 9 - ] - } - } - } - ] - }, - { - "source": "attack_right_1_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -4, - -5 - ], - "size": [ - 10, - 12 - ] - } - } - } - ] - }, - { - "source": "attack_right_1_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -7, - -6 - ], - "size": [ - 14, - 14 - ] - } - } - } - ] - }, - { - "source": "attack_right_1_2.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -1, - -3 - ], - "size": [ - 26, - 16 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -11, - -7 - ], - "size": [ - 12, - 16 - ] - } - } - } - ] - }, - { - "source": "attack_right_1_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -12, - -6 - ], - "size": [ - 12, - 14 - ] - } - } - } - ] - }, - { - "source": "attack_right_2_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - 0, - -6 - ], - "size": [ - 10, - 15 - ] - } - } - } - ] - }, - { - "source": "attack_right_2_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -13, - -2 - ], - "size": [ - 13, - 14 - ] - } - } - } - ] - }, - { - "source": "attack_right_2_2.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -2, - -22 - ], - "size": [ - 25, - 35 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -11, - -4 - ], - "size": [ - 14, - 11 - ] - } - } - } - ] - }, - { - "source": "attack_right_2_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -7, - -5 - ], - "size": [ - 14, - 10 - ] - } - } - } - ] - }, - { - "source": "attack_right_3_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -3, - -6 - ], - "size": [ - 14, - 12 - ] - } - } - } - ] - }, - { - "source": "attack_right_3_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -11, - -5 - ], - "size": [ - 12, - 11 - ] - } - } - } - ] - }, - { - "source": "attack_right_3_2.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -3, - -14 - ], - "size": [ - 26, - 27 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -14, - -6 - ], - "size": [ - 11, - 13 - ] - } - } - } - ] - }, - { - "source": "attack_right_3_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -3 - ], - "size": [ - 14, - 11 - ] - } - } - } - ] - }, - { - "source": "attack_up_0_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -2, - -6 - ], - "size": [ - 10, - 13 - ] - } - } - } - ] - }, - { - "source": "attack_up_0_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -1, - -2 - ], - "size": [ - 12, - 14 - ] - } - } - } - ] - }, - { - "source": "attack_up_0_2.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -17, - -15 - ], - "size": [ - 33, - 31 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -4, - -5 - ], - "size": [ - 12, - 14 - ] - } - } - } - ] - }, - { - "source": "attack_up_0_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -7 - ], - "size": [ - 14, - 12 - ] - } - } - } - ] - }, - { - "source": "attack_up_1_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - 0, - -6 - ], - "size": [ - 11, - 14 - ] - } - } - } - ] - }, - { - "source": "attack_up_1_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -3, - -6 - ], - "size": [ - 10, - 13 - ] - } - } - } - ] - }, - { - "source": "attack_up_1_2.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -7, - -27 - ], - "size": [ - 13, - 27 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -4 - ], - "size": [ - 11, - 19 - ] - } - } - } - ] - }, - { - "source": "attack_up_1_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -2 - ], - "size": [ - 12, - 20 - ] - } - } - } - ] - }, - { - "source": "attack_up_2_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -11, - -9 - ], - "size": [ - 9, - 19 - ] - } - } - } - ] - }, - { - "source": "attack_up_2_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - 2, - 1 - ], - "size": [ - 11, - 15 - ] - } - } - } - ] - }, - { - "source": "attack_up_2_2.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -17, - -20 - ], - "size": [ - 24, - 31 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - 2, - -3 - ], - "size": [ - 11, - 13 - ] - } - } - } - ] - }, - { - "source": "attack_up_2_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -1, - -5 - ], - "size": [ - 11, - 13 - ] - } - } - } - ] - }, - { - "source": "attack_up_3_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - 3, - -6 - ], - "size": [ - 11, - 12 - ] - } - } - } - ] - }, - { - "source": "attack_up_3_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -7, - -4 - ], - "size": [ - 11, - 16 - ] - } - } - } - ] - }, - { - "source": "attack_up_3_2.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -30, - -24 - ], - "size": [ - 52, - 33 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -14, - 1 - ], - "size": [ - 11, - 12 - ] - } - } - } - ] - }, - { - "source": "attack_up_3_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -14, - -7 - ], - "size": [ - 9, - 13 - ] - } - } - } - ] - }, - { - "source": "death_0.png", - "hitboxes": [] - }, - { - "source": "death_1.png", - "hitboxes": [] - }, - { - "source": "idle_down.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -8 - ], - "size": [ - 11, - 19 - ] - } - } - } - ] - }, - { - "source": "idle_left.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -9 - ], - "size": [ - 11, - 20 - ] - } - } - } - ] - }, - { - "source": "idle_right.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -11 - ], - "size": [ - 12, - 22 - ] - } - } - } - ] - }, - { - "source": "idle_up.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -10 - ], - "size": [ - 12, - 22 - ] - } - } - } - ] - }, - { - "source": "knockback_down.png", - "hitboxes": [] - }, - { - "source": "knockback_left.png", - "hitboxes": [] - }, - { - "source": "knockback_right.png", - "hitboxes": [] - }, - { - "source": "knockback_up.png", - "hitboxes": [] - }, - { - "source": "walk_down_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -8 - ], - "size": [ - 10, - 16 - ] - } - } - } - ] - }, - { - "source": "walk_down_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -8 - ], - "size": [ - 10, - 18 - ] - } - } - } - ] - }, - { - "source": "walk_down_2.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -7 - ], - "size": [ - 11, - 18 - ] - } - } - } - ] - }, - { - "source": "walk_down_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -4, - -7 - ], - "size": [ - 10, - 17 - ] - } - } - } - ] - }, - { - "source": "walk_down_4.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -3, - -5 - ], - "size": [ - 9, - 15 - ] - } - } - } - ] - }, - { - "source": "walk_down_5.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -4, - -6 - ], - "size": [ - 9, - 16 - ] - } - } - } - ] - }, - { - "source": "walk_left_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -5 - ], - "size": [ - 11, - 16 - ] - } - } - } - ] - }, - { - "source": "walk_left_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -5 - ], - "size": [ - 12, - 15 - ] - } - } - } - ] - }, - { - "source": "walk_left_2.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -4 - ], - "size": [ - 13, - 14 - ] - } - } - } - ] - }, - { - "source": "walk_left_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -4 - ], - "size": [ - 11, - 15 - ] - } - } - } - ] - }, - { - "source": "walk_left_4.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -4, - -4 - ], - "size": [ - 12, - 15 - ] - } - } - } - ] - }, - { - "source": "walk_left_5.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -4 - ], - "size": [ - 13, - 13 - ] - } - } - } - ] - }, - { - "source": "walk_right_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -4, - -5 - ], - "size": [ - 11, - 15 - ] - } - } - } - ] - }, - { - "source": "walk_right_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -5 - ], - "size": [ - 12, - 14 - ] - } - } - } - ] - }, - { - "source": "walk_right_2.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -3 - ], - "size": [ - 12, - 13 - ] - } - } - } - ] - }, - { - "source": "walk_right_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -4 - ], - "size": [ - 11, - 14 - ] - } - } - } - ] - }, - { - "source": "walk_right_4.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -5 - ], - "size": [ - 12, - 15 - ] - } - } - } - ] - }, - { - "source": "walk_right_5.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -4 - ], - "size": [ - 12, - 13 - ] - } - } - } - ] - }, - { - "source": "walk_up_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -4, - -6 - ], - "size": [ - 9, - 15 - ] - } - } - } - ] - }, - { - "source": "walk_up_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -5 - ], - "size": [ - 10, - 15 - ] - } - } - } - ] - }, - { - "source": "walk_up_2.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -6 - ], - "size": [ - 9, - 15 - ] - } - } - } - ] - }, - { - "source": "walk_up_3.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -6 - ], - "size": [ - 10, - 15 - ] - } - } - } - ] - }, - { - "source": "walk_up_4.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -4, - -6 - ], - "size": [ - 11, - 15 - ] - } - } - } - ] - }, - { - "source": "walk_up_5.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -4, - -7 - ], - "size": [ - 10, - 16 - ] - } - } - } - ] - } - ], - "animations": [ - { - "name": "idle_up", - "timeline": [ - { - "frame": "idle_up.png", - "duration": 100, - "offset": [ - -1, - -13 - ] - } - ], - "is_looping": false - }, - { - "name": "idle_down", - "timeline": [ - { - "frame": "idle_down.png", - "duration": 100, - "offset": [ - 1, - -13 - ] - } - ], - "is_looping": false - }, - { - "name": "idle_left", - "timeline": [ - { - "frame": "idle_left.png", - "duration": 100, - "offset": [ - 1, - -13 - ] - } - ], - "is_looping": false - }, - { - "name": "idle_right", - "timeline": [ - { - "frame": "idle_right.png", - "duration": 100, - "offset": [ - -2, - -13 - ] - } - ], - "is_looping": false - }, - { - "name": "walk_left", - "timeline": [ - { - "frame": "walk_left_1.png", - "duration": 146, - "offset": [ - 0, - -14 - ] - }, - { - "frame": "walk_left_2.png", - "duration": 149, - "offset": [ - -1, - -14 - ] - }, - { - "frame": "walk_left_3.png", - "duration": 152, - "offset": [ - 0, - -14 - ] - }, - { - "frame": "walk_left_4.png", - "duration": 149, - "offset": [ - -3, - -15 - ] - }, - { - "frame": "walk_left_5.png", - "duration": 152, - "offset": [ - -1, - -13 - ] - }, - { - "frame": "walk_left_0.png", - "duration": 155, - "offset": [ - -3, - -15 - ] - } - ], - "is_looping": true - }, - { - "name": "walk_right", - "timeline": [ - { - "frame": "walk_right_0.png", - "duration": 158, - "offset": [ - 2, - -15 - ] - }, - { - "frame": "walk_right_1.png", - "duration": 142, - "offset": [ - 0, - -15 - ] - }, - { - "frame": "walk_right_2.png", - "duration": 151, - "offset": [ - -1, - -14 - ] - }, - { - "frame": "walk_right_3.png", - "duration": 150, - "offset": [ - 0, - -14 - ] - }, - { - "frame": "walk_right_4.png", - "duration": 151, - "offset": [ - 2, - -15 - ] - }, - { - "frame": "walk_right_5.png", - "duration": 148, - "offset": [ - 1, - -13 - ] - } - ], - "is_looping": true - }, - { - "name": "walk_up", - "timeline": [ - { - "frame": "walk_up_0.png", - "duration": 152, - "offset": [ - -2, - -13 - ] - }, - { - "frame": "walk_up_1.png", - "duration": 149, - "offset": [ - 1, - -13 - ] - }, - { - "frame": "walk_up_2.png", - "duration": 153, - "offset": [ - 3, - -12 - ] - }, - { - "frame": "walk_up_3.png", - "duration": 147, - "offset": [ - 1, - -13 - ] - }, - { - "frame": "walk_up_4.png", - "duration": 152, - "offset": [ - -2, - -13 - ] - }, - { - "frame": "walk_up_5.png", - "duration": 148, - "offset": [ - -3, - -12 - ] - } - ], - "is_looping": true - }, - { - "name": "walk_down", - "timeline": [ - { - "frame": "walk_down_0.png", - "duration": 148, - "offset": [ - 0, - -13 - ] - }, - { - "frame": "walk_down_1.png", - "duration": 153, - "offset": [ - 0, - -14 - ] - }, - { - "frame": "walk_down_2.png", - "duration": 153, - "offset": [ - 0, - -13 - ] - }, - { - "frame": "walk_down_3.png", - "duration": 152, - "offset": [ - 0, - -13 - ] - }, - { - "frame": "walk_down_4.png", - "duration": 150, - "offset": [ - 0, - -14 - ] - }, - { - "frame": "walk_down_5.png", - "duration": 153, - "offset": [ - 0, - -13 - ] - } - ], - "is_looping": true - }, - { - "name": "death", - "timeline": [ - { - "frame": "death_0.png", - "duration": 196, - "offset": [ - -4, - -11 - ] - }, - { - "frame": "death_1.png", - "duration": 303, - "offset": [ - -5, - -9 - ] - } - ], - "is_looping": false - }, - { - "name": "knockback_left", - "timeline": [ - { - "frame": "knockback_left.png", - "duration": 100, - "offset": [ - 6, - -14 - ] - } - ], - "is_looping": true - }, - { - "name": "knockback_right", - "timeline": [ - { - "frame": "knockback_right.png", - "duration": 100, - "offset": [ - -7, - -14 - ] - } - ], - "is_looping": false - }, - { - "name": "knockback_up", - "timeline": [ - { - "frame": "knockback_up.png", - "duration": 100, - "offset": [ - 0, - -14 - ] - } - ], - "is_looping": false - }, - { - "name": "knockback_down", - "timeline": [ - { - "frame": "knockback_down.png", - "duration": 100, - "offset": [ - -2, - -16 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_down_0", - "timeline": [ - { - "frame": "attack_down_0_0.png", - "duration": 152, - "offset": [ - 8, - -13 - ] - }, - { - "frame": "attack_down_0_1.png", - "duration": 77, - "offset": [ - 4, - -20 - ] - }, - { - "frame": "attack_down_0_2.png", - "duration": 110, - "offset": [ - 11, - -8 - ] - }, - { - "frame": "attack_down_0_3.png", - "duration": 160, - "offset": [ - 11, - -7 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_down_1", - "timeline": [ - { - "frame": "attack_down_1_1.png", - "duration": 80, - "offset": [ - 1, - -3 - ] - }, - { - "frame": "attack_down_1_0.png", - "duration": 147, - "offset": [ - -2, - -13 - ] - }, - { - "frame": "attack_down_1_2.png", - "duration": 56, - "offset": [ - 1, - 0 - ] - }, - { - "frame": "attack_down_1_3.png", - "duration": 72, - "offset": [ - 1, - 0 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_down_2", - "timeline": [ - { - "frame": "attack_down_2_0.png", - "duration": 147, - "offset": [ - 3, - -16 - ] - }, - { - "frame": "attack_down_2_1.png", - "duration": 69, - "offset": [ - 2, - -13 - ] - }, - { - "frame": "attack_down_2_2.png", - "duration": 74, - "offset": [ - -2, - -9 - ] - }, - { - "frame": "attack_down_2_3.png", - "duration": 140, - "offset": [ - -3, - -14 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_down_3", - "timeline": [ - { - "frame": "attack_down_3_0.png", - "duration": 158, - "offset": [ - -1, - -13 - ] - }, - { - "frame": "attack_down_3_1.png", - "duration": 77, - "offset": [ - 0, - -2 - ] - }, - { - "frame": "attack_down_3_2.png", - "duration": 71, - "offset": [ - 13, - -6 - ] - }, - { - "frame": "attack_down_3_3.png", - "duration": 157, - "offset": [ - 12, - -14 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_up_0", - "timeline": [ - { - "frame": "attack_up_0_0.png", - "duration": 155, - "offset": [ - 2, - -14 - ] - }, - { - "frame": "attack_up_0_1.png", - "duration": 69, - "offset": [ - -4, - -21 - ] - }, - { - "frame": "attack_up_0_2.png", - "duration": 73, - "offset": [ - 9, - -15 - ] - }, - { - "frame": "attack_up_0_3.png", - "duration": 169, - "offset": [ - 9, - -11 - ] - } - ], - "is_looping": true - }, - { - "name": "attack_up_1", - "timeline": [ - { - "frame": "attack_up_1_0.png", - "duration": 158, - "offset": [ - -3, - -12 - ] - }, - { - "frame": "attack_up_1_1.png", - "duration": 75, - "offset": [ - -1, - -14 - ] - }, - { - "frame": "attack_up_1_2.png", - "duration": 69, - "offset": [ - -1, - -24 - ] - }, - { - "frame": "attack_up_1_3.png", - "duration": 186, - "offset": [ - 0, - -25 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_up_2", - "timeline": [ - { - "frame": "attack_up_2_0.png", - "duration": 189, - "offset": [ - 10, - -15 - ] - }, - { - "frame": "attack_up_2_1.png", - "duration": 60, - "offset": [ - -6, - -21 - ] - }, - { - "frame": "attack_up_2_2.png", - "duration": 54, - "offset": [ - -6, - -15 - ] - }, - { - "frame": "attack_up_2_3.png", - "duration": 210, - "offset": [ - -3, - -15 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_up_3", - "timeline": [ - { - "frame": "attack_up_3_0.png", - "duration": 159, - "offset": [ - -13, - -13 - ] - }, - { - "frame": "attack_up_3_1.png", - "duration": 55, - "offset": [ - 0, - -21 - ] - }, - { - "frame": "attack_up_3_2.png", - "duration": 48, - "offset": [ - 8, - -22 - ] - }, - { - "frame": "attack_up_3_3.png", - "duration": 193, - "offset": [ - 9, - -14 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_left_0", - "timeline": [ - { - "frame": "attack_left_0_0.png", - "duration": 156, - "offset": [ - 8, - -14 - ] - }, - { - "frame": "attack_left_0_1.png", - "duration": 61, - "offset": [ - -3, - -21 - ] - }, - { - "frame": "attack_left_0_2.png", - "duration": 63, - "offset": [ - -11, - -21 - ] - }, - { - "frame": "attack_left_0_3.png", - "duration": 191, - "offset": [ - -11, - -11 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_left_1", - "timeline": [ - { - "frame": "attack_left_1_0.png", - "duration": 165, - "offset": [ - -2, - -11 - ] - }, - { - "frame": "attack_left_1_1.png", - "duration": 81, - "offset": [ - -9, - -11 - ] - }, - { - "frame": "attack_left_1_2.png", - "duration": 66, - "offset": [ - -16, - -12 - ] - }, - { - "frame": "attack_left_1_3.png", - "duration": 164, - "offset": [ - -16, - -12 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_left_2", - "timeline": [ - { - "frame": "attack_left_2_0.png", - "duration": 180, - "offset": [ - 5, - -14 - ] - }, - { - "frame": "attack_left_2_1.png", - "duration": 81, - "offset": [ - -12, - -18 - ] - }, - { - "frame": "attack_left_2_2.png", - "duration": 76, - "offset": [ - -12, - -12 - ] - }, - { - "frame": "attack_left_2_3.png", - "duration": 148, - "offset": [ - -9, - -9 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_left_3", - "timeline": [ - { - "frame": "attack_left_3_0.png", - "duration": 165, - "offset": [ - -2, - -10 - ] - }, - { - "frame": "attack_left_3_1.png", - "duration": 65, - "offset": [ - -15, - -12 - ] - }, - { - "frame": "attack_left_3_2.png", - "duration": 76, - "offset": [ - -13, - -13 - ] - }, - { - "frame": "attack_left_3_3.png", - "duration": 172, - "offset": [ - -1, - -15 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_right_0", - "timeline": [ - { - "frame": "attack_right_0_0.png", - "duration": 180, - "offset": [ - -10, - -13 - ] - }, - { - "frame": "attack_right_0_1.png", - "duration": 81, - "offset": [ - 1, - -21 - ] - }, - { - "frame": "attack_right_0_2.png", - "duration": 78, - "offset": [ - 10, - -21 - ] - }, - { - "frame": "attack_right_0_3.png", - "duration": 142, - "offset": [ - 10, - -11 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_right_1", - "timeline": [ - { - "frame": "attack_right_1_0.png", - "duration": 169, - "offset": [ - 0, - -12 - ] - }, - { - "frame": "attack_right_1_1.png", - "duration": 82, - "offset": [ - 5, - -12 - ] - }, - { - "frame": "attack_right_1_2.png", - "duration": 78, - "offset": [ - 11, - -13 - ] - }, - { - "frame": "attack_right_1_3.png", - "duration": 143, - "offset": [ - 12, - -13 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_right_2", - "timeline": [ - { - "frame": "attack_right_2_0.png", - "duration": 171, - "offset": [ - -9, - -15 - ] - }, - { - "frame": "attack_right_2_1.png", - "duration": 72, - "offset": [ - 7, - -19 - ] - }, - { - "frame": "attack_right_2_2.png", - "duration": 47, - "offset": [ - 8, - -12 - ] - }, - { - "frame": "attack_right_2_3.png", - "duration": 169, - "offset": [ - 4, - -10 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_right_3", - "timeline": [ - { - "frame": "attack_right_3_0.png", - "duration": 186, - "offset": [ - 1, - -11 - ] - }, - { - "frame": "attack_right_3_1.png", - "duration": 63, - "offset": [ - 12, - -13 - ] - }, - { - "frame": "attack_right_3_2.png", - "duration": 64, - "offset": [ - 11, - -12 - ] - }, - { - "frame": "attack_right_3_3.png", - "duration": 187, - "offset": [ - 0, - -14 - ] - } - ], - "is_looping": false - }, - { - "name": "dash_down", - "timeline": [ - { - "frame": "attack_down_1_0.png", - "duration": 260, - "offset": [ - -2, - -13 - ] - }, - { - "frame": "attack_down_1_1.png", - "duration": 78, - "offset": [ - 1, - -4 - ] - }, - { - "frame": "attack_down_1_2.png", - "duration": 75, - "offset": [ - 1, - -2 - ] - }, - { - "frame": "attack_down_1_3.png", - "duration": 76, - "offset": [ - 1, - -2 - ] - } - ], - "is_looping": false - }, - { - "name": "dash_up", - "timeline": [ - { - "frame": "attack_up_1_0.png", - "duration": 248, - "offset": [ - -4, - -13 - ] - }, - { - "frame": "attack_up_1_1.png", - "duration": 53, - "offset": [ - -2, - -15 - ] - }, - { - "frame": "attack_up_1_2.png", - "duration": 69, - "offset": [ - 2, - -24 - ] - }, - { - "frame": "attack_up_1_3.png", - "duration": 76, - "offset": [ - 3, - -25 - ] - } - ], - "is_looping": false - }, - { - "name": "dash_left", - "timeline": [ - { - "frame": "attack_left_1_0.png", - "duration": 245, - "offset": [ - -2, - -11 - ] - }, - { - "frame": "attack_left_1_1.png", - "duration": 51, - "offset": [ - -8, - -11 - ] - }, - { - "frame": "attack_left_1_2.png", - "duration": 60, - "offset": [ - -15, - -12 - ] - }, - { - "frame": "attack_left_1_3.png", - "duration": 65, - "offset": [ - -15, - -12 - ] - } - ], - "is_looping": false - }, - { - "name": "dash_right", - "timeline": [ - { - "frame": "attack_right_1_0.png", - "duration": 243, - "offset": [ - -1, - -12 - ] - }, - { - "frame": "attack_right_1_1.png", - "duration": 61, - "offset": [ - 5, - -12 - ] - }, - { - "frame": "attack_right_1_2.png", - "duration": 58, - "offset": [ - 11, - -13 - ] - }, - { - "frame": "attack_right_1_3.png", - "duration": 61, - "offset": [ - 12, - -13 - ] - } - ], - "is_looping": false - } - ], - "export_settings": { - "format": { - "Template": "..\\..\\..\\crystal.template" - }, - "texture_destination": "..\\..\\..\\..\\game\\arpg\\assets\\texture\\sprite\\duran.png", - "metadata_destination": "..\\..\\..\\..\\game\\arpg\\assets\\spritesheet\\duran.lua" - } - } -} \ No newline at end of file diff --git a/src-tauri/test-data/sample_sheet_2.tiger b/src-tauri/test-data/sample_sheet_2.tiger deleted file mode 100644 index cd16e6b..0000000 --- a/src-tauri/test-data/sample_sheet_2.tiger +++ /dev/null @@ -1,978 +0,0 @@ -{ - "version": "Tiger1", - "sheet": { - "frames": [ - { - "source": "attack_down_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -9, - -6 - ], - "size": [ - 17, - 16 - ] - } - } - } - ] - }, - { - "source": "attack_down_1.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -8, - -4 - ], - "size": [ - 7, - 24 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -18 - ], - "size": [ - 16, - 13 - ] - } - } - } - ] - }, - { - "source": "attack_down_2.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -15 - ], - "size": [ - 17, - 13 - ] - } - } - } - ] - }, - { - "source": "attack_left_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -7, - -7 - ], - "size": [ - 15, - 15 - ] - } - } - } - ] - }, - { - "source": "attack_left_1.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -21, - 0 - ], - "size": [ - 24, - 7 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - 5, - -8 - ], - "size": [ - 14, - 16 - ] - } - } - } - ] - }, - { - "source": "attack_left_2.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -1, - -8 - ], - "size": [ - 13, - 16 - ] - } - } - } - ] - }, - { - "source": "attack_right_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -7, - -7 - ], - "size": [ - 14, - 15 - ] - } - } - } - ] - }, - { - "source": "attack_right_1.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - -2, - 0 - ], - "size": [ - 24, - 7 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -17, - -8 - ], - "size": [ - 13, - 16 - ] - } - } - } - ] - }, - { - "source": "attack_right_2.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -13, - -9 - ], - "size": [ - 15, - 16 - ] - } - } - } - ] - }, - { - "source": "attack_up_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -7, - -7 - ], - "size": [ - 14, - 14 - ] - } - } - } - ] - }, - { - "source": "attack_up_1.png", - "hitboxes": [ - { - "name": "hit", - "geometry": { - "Rectangle": { - "top_left": [ - 2, - -20 - ], - "size": [ - 7, - 24 - ] - } - } - }, - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - 5 - ], - "size": [ - 16, - 14 - ] - } - } - } - ] - }, - { - "source": "attack_up_2.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -1 - ], - "size": [ - 14, - 13 - ] - } - } - } - ] - }, - { - "source": "idle_down.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -6 - ], - "size": [ - 14, - 15 - ] - } - } - } - ] - }, - { - "source": "idle_left.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -9, - -9 - ], - "size": [ - 15, - 14 - ] - } - } - } - ] - }, - { - "source": "idle_right.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -4, - -10 - ], - "size": [ - 12, - 15 - ] - } - } - } - ] - }, - { - "source": "idle_up.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -7, - -6 - ], - "size": [ - 15, - 15 - ] - } - } - } - ] - }, - { - "source": "knockback.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -3, - -6 - ], - "size": [ - 17, - 14 - ] - } - } - } - ] - }, - { - "source": "smashed.png", - "hitboxes": [] - }, - { - "source": "walk_down_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -8, - -8 - ], - "size": [ - 15, - 15 - ] - } - } - } - ] - }, - { - "source": "walk_down_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -2, - -8 - ], - "size": [ - 15, - 16 - ] - } - } - } - ] - }, - { - "source": "walk_left_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -5, - -11 - ], - "size": [ - 14, - 16 - ] - } - } - } - ] - }, - { - "source": "walk_left_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -10, - -9 - ], - "size": [ - 13, - 15 - ] - } - } - } - ] - }, - { - "source": "walk_right_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -9, - -10 - ], - "size": [ - 14, - 14 - ] - } - } - } - ] - }, - { - "source": "walk_right_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -3, - -9 - ], - "size": [ - 14, - 15 - ] - } - } - } - ] - }, - { - "source": "walk_up_0.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -6, - -8 - ], - "size": [ - 14, - 15 - ] - } - } - } - ] - }, - { - "source": "walk_up_1.png", - "hitboxes": [ - { - "name": "weak", - "geometry": { - "Rectangle": { - "top_left": [ - -13, - -9 - ], - "size": [ - 15, - 14 - ] - } - } - } - ] - } - ], - "animations": [ - { - "name": "idle_left", - "timeline": [ - { - "frame": "idle_left.png", - "duration": 100, - "offset": [ - 1, - -4 - ] - } - ], - "is_looping": false - }, - { - "name": "idle_right", - "timeline": [ - { - "frame": "idle_right.png", - "duration": 100, - "offset": [ - -1, - -4 - ] - } - ], - "is_looping": false - }, - { - "name": "idle_up", - "timeline": [ - { - "frame": "idle_up.png", - "duration": 100, - "offset": [ - 0, - -8 - ] - } - ], - "is_looping": false - }, - { - "name": "idle_down", - "timeline": [ - { - "frame": "idle_down.png", - "duration": 100, - "offset": [ - -1, - -7 - ] - } - ], - "is_looping": false - }, - { - "name": "walk_left", - "timeline": [ - { - "frame": "walk_left_0.png", - "duration": 151, - "offset": [ - -2, - -4 - ] - }, - { - "frame": "idle_left.png", - "duration": 151, - "offset": [ - 1, - -4 - ] - }, - { - "frame": "walk_left_1.png", - "duration": 148, - "offset": [ - 3, - -5 - ] - }, - { - "frame": "idle_left.png", - "duration": 151, - "offset": [ - 1, - -4 - ] - } - ], - "is_looping": true - }, - { - "name": "walk_right", - "timeline": [ - { - "frame": "walk_right_0.png", - "duration": 152, - "offset": [ - 2, - -4 - ] - }, - { - "frame": "idle_right.png", - "duration": 145, - "offset": [ - -1, - -4 - ] - }, - { - "frame": "walk_right_1.png", - "duration": 153, - "offset": [ - -3, - -5 - ] - }, - { - "frame": "idle_right.png", - "duration": 152, - "offset": [ - -1, - -4 - ] - } - ], - "is_looping": true - }, - { - "name": "smashed", - "timeline": [ - { - "frame": "smashed.png", - "duration": 100, - "offset": [ - -5, - 2 - ] - } - ], - "is_looping": true - }, - { - "name": "knockback_left", - "timeline": [ - { - "frame": "knockback.png", - "duration": 100, - "offset": [ - -7, - -8 - ] - } - ], - "is_looping": true - }, - { - "name": "walk_up", - "timeline": [ - { - "frame": "walk_up_0.png", - "duration": 149, - "offset": [ - -1, - -6 - ] - }, - { - "frame": "idle_up.png", - "duration": 154, - "offset": [ - 0, - -8 - ] - }, - { - "frame": "walk_up_1.png", - "duration": 154, - "offset": [ - 6, - -5 - ] - }, - { - "frame": "idle_up.png", - "duration": 145, - "offset": [ - 0, - -8 - ] - } - ], - "is_looping": true - }, - { - "name": "walk_down", - "timeline": [ - { - "frame": "walk_down_0.png", - "duration": 150, - "offset": [ - 1, - -5 - ] - }, - { - "frame": "idle_down.png", - "duration": 151, - "offset": [ - -1, - -7 - ] - }, - { - "frame": "walk_down_1.png", - "duration": 148, - "offset": [ - -6, - -6 - ] - }, - { - "frame": "idle_down.png", - "duration": 152, - "offset": [ - -1, - -7 - ] - } - ], - "is_looping": true - }, - { - "name": "knockback_right", - "timeline": [ - { - "frame": "knockback.png", - "duration": 100, - "offset": [ - -7, - -8 - ] - } - ], - "is_looping": true - }, - { - "name": "knockback_down", - "timeline": [ - { - "frame": "knockback.png", - "duration": 100, - "offset": [ - -7, - -8 - ] - } - ], - "is_looping": true - }, - { - "name": "knockback_up", - "timeline": [ - { - "frame": "knockback.png", - "duration": 100, - "offset": [ - -7, - -8 - ] - } - ], - "is_looping": true - }, - { - "name": "attack_left", - "timeline": [ - { - "frame": "attack_left_0.png", - "duration": 302, - "offset": [ - 2, - -8 - ] - }, - { - "frame": "attack_left_1.png", - "duration": 81, - "offset": [ - -13, - -7 - ] - }, - { - "frame": "attack_left_2.png", - "duration": 83, - "offset": [ - -7, - -7 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_right", - "timeline": [ - { - "frame": "attack_right_0.png", - "duration": 300, - "offset": [ - -2, - -8 - ] - }, - { - "frame": "attack_right_1.png", - "duration": 80, - "offset": [ - 12, - -7 - ] - }, - { - "frame": "attack_right_2.png", - "duration": 82, - "offset": [ - 7, - -7 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_up", - "timeline": [ - { - "frame": "attack_up_0.png", - "duration": 301, - "offset": [ - 1, - -7 - ] - }, - { - "frame": "attack_up_1.png", - "duration": 79, - "offset": [ - -1, - -18 - ] - }, - { - "frame": "attack_up_2.png", - "duration": 84, - "offset": [ - -1, - -12 - ] - } - ], - "is_looping": false - }, - { - "name": "attack_down", - "timeline": [ - { - "frame": "attack_down_0.png", - "duration": 301, - "offset": [ - 1, - -9 - ] - }, - { - "frame": "attack_down_1.png", - "duration": 82, - "offset": [ - -1, - 5 - ] - }, - { - "frame": "attack_down_2.png", - "duration": 81, - "offset": [ - -1, - 2 - ] - } - ], - "is_looping": false - } - ], - "export_settings": { - "format": { - "Template": "..\\..\\..\\crystal.template" - }, - "texture_destination": "..\\..\\..\\..\\game\\arpg\\assets\\texture\\sprite\\sahagin.png", - "metadata_destination": "..\\..\\..\\..\\game\\arpg\\assets\\spritesheet\\sahagin.lua" - } - } -} From 9e092e167716b7bbcd0335c3aa8c8c81e5c384aa Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Sat, 31 Dec 2022 11:41:05 +0100 Subject: [PATCH 67/77] Fixed a bug where warning dialog appeared when choosing template file --- src/components/export/ExportOverlay.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/export/ExportOverlay.vue b/src/components/export/ExportOverlay.vue index 4814510..c53cb1f 100644 --- a/src/components/export/ExportOverlay.vue +++ b/src/components/export/ExportOverlay.vue @@ -38,7 +38,7 @@

Metadata Format