From e3b3f08b6bceeffcf97583719b933f772c76a39a Mon Sep 17 00:00:00 2001 From: Hakoyu Date: Wed, 20 Sep 2023 23:32:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E8=A3=85=E5=8A=A8=E7=94=BB=E7=BC=96?= =?UTF-8?q?=E8=BE=91=20Touch=5FBody=20=E5=92=8C=20Touch=5FHead?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- VPet.ModMaker/Converters.xaml | 1 + .../Converters/FalseToHiddenConverter.cs | 26 ++++ VPet.ModMaker/Models/ModModel/AnimeModel.cs | 133 ++++++++++++++--- VPet.ModMaker/Models/ModModel/ModInfoModel.cs | 136 ++++++++++++++---- VPet.ModMaker/Models/Utils.cs | 1 + VPet.ModMaker/VPet.ModMaker.csproj | 1 + .../ModEdit/AnimeEdit/AnimeEditWindowVM.cs | 45 +++++- .../ModEdit/AnimeEdit/AnimeEditWindow.xaml | 7 + .../ModEdit/AnimeEdit/AnimeEditWindow.xaml.cs | 36 +---- 9 files changed, 309 insertions(+), 77 deletions(-) create mode 100644 VPet.ModMaker/Converters/FalseToHiddenConverter.cs diff --git a/VPet.ModMaker/Converters.xaml b/VPet.ModMaker/Converters.xaml index 78c7b7d..48c470e 100644 --- a/VPet.ModMaker/Converters.xaml +++ b/VPet.ModMaker/Converters.xaml @@ -8,4 +8,5 @@ + \ No newline at end of file diff --git a/VPet.ModMaker/Converters/FalseToHiddenConverter.cs b/VPet.ModMaker/Converters/FalseToHiddenConverter.cs new file mode 100644 index 0000000..40d8c67 --- /dev/null +++ b/VPet.ModMaker/Converters/FalseToHiddenConverter.cs @@ -0,0 +1,26 @@ +using Panuon.WPF; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Data; + +namespace VPet.ModMaker.Converters; + +public class FalseToHiddenConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return (bool.TryParse(value.ToString(), out var result) && result) + ? Visibility.Visible + : Visibility.Hidden; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return value is Visibility visibility && visibility == Visibility.Hidden; + } +} diff --git a/VPet.ModMaker/Models/ModModel/AnimeModel.cs b/VPet.ModMaker/Models/ModModel/AnimeModel.cs index fd2e5fd..5746a6d 100644 --- a/VPet.ModMaker/Models/ModModel/AnimeModel.cs +++ b/VPet.ModMaker/Models/ModModel/AnimeModel.cs @@ -48,40 +48,137 @@ public class AnimeTypeModel GraphType.Value = graphType; if (graphType is GraphInfo.GraphType.Default) LoadDefault(path); + else if (graphType is GraphInfo.GraphType.Touch_Head or GraphInfo.GraphType.Touch_Body) + LoadMultiTypeAnime(path); + else + throw new Exception(); + } + + public static AnimeTypeModel? Create(GraphInfo.GraphType graphType, string path) + { + try + { + var model = new AnimeTypeModel(graphType, path); + return model; + } + catch + { + return null; + } } private void LoadDefault(string path) { - foreach (var modeDir in Directory.EnumerateDirectories(path)) + foreach (var dir in Directory.EnumerateDirectories(path)) { - var mode = Enum.Parse(typeof(GameSave.ModeType), Path.GetFileName(modeDir), true); + var mode = Enum.Parse(typeof(GameSave.ModeType), Path.GetFileName(dir), true); if (mode is GameSave.ModeType.Happy) { - foreach (var imagesDir in Directory.EnumerateDirectories(modeDir)) - { - HappyAnimes.Add(new(imagesDir)); - } + AddAnime(HappyAnimes, dir); } else if (mode is GameSave.ModeType.Nomal) { - foreach (var imagesDir in Directory.EnumerateDirectories(modeDir)) - { - NomalAnimes.Add(new(imagesDir)); - } + AddAnime(NomalAnimes, dir); } else if (mode is GameSave.ModeType.PoorCondition) { - foreach (var imagesDir in Directory.EnumerateDirectories(modeDir)) - { - PoorConditionAnimes.Add(new(imagesDir)); - } + AddAnime(PoorConditionAnimes, dir); } else if (mode is GameSave.ModeType.Ill) { - foreach (var imagesDir in Directory.EnumerateDirectories(modeDir)) + AddAnime(IllAnimes, dir); + } + } + } + + private void LoadMultiTypeAnime(string path) + { + foreach (var dir in Directory.EnumerateDirectories(path)) + { + var dirName = Path.GetFileName(dir); + var dirInfo = dirName.Split(Utils.Separator, StringSplitOptions.RemoveEmptyEntries); + if (dirInfo.Length == 2) + { + // 判断 A_Happy 类型文件夹 + var typeName = dirInfo[0]; + var modeName = dirInfo[1]; + var type = GetAnimatType(typeName[0]); + var mode = Enum.Parse(typeof(GameSave.ModeType), Path.GetFileName(modeName), true); + if (mode is GameSave.ModeType.Happy) { - IllAnimes.Add(new(imagesDir)); + AddAnime(HappyAnimes, dir, type); } + else if (mode is GameSave.ModeType.Nomal) + { + AddAnime(NomalAnimes, dir, type); + } + else if (mode is GameSave.ModeType.PoorCondition) + { + AddAnime(PoorConditionAnimes, dir, type); + } + else if (mode is GameSave.ModeType.Ill) + { + AddAnime(IllAnimes, dir, type); + } + } + else + { + // 判断 Happy/A 型文件夹 + var mode = Enum.Parse(typeof(GameSave.ModeType), Path.GetFileName(dirName), true); + foreach (var typePath in Directory.EnumerateDirectories(dir)) + { + var type = GetAnimatType(Path.GetFileName(typePath)[0]); + if (mode is GameSave.ModeType.Happy) + { + AddAnime(HappyAnimes, dir, type); + } + else if (mode is GameSave.ModeType.Nomal) + { + AddAnime(NomalAnimes, dir, type); + } + else if (mode is GameSave.ModeType.PoorCondition) + { + AddAnime(PoorConditionAnimes, dir, type); + } + else if (mode is GameSave.ModeType.Ill) + { + AddAnime(IllAnimes, dir, type); + } + } + } + } + } + + private static GraphInfo.AnimatType GetAnimatType(char c) + { + return c switch + { + 'A' => GraphInfo.AnimatType.A_Start, + 'B' => GraphInfo.AnimatType.B_Loop, + 'C' => GraphInfo.AnimatType.C_End, + _ => GraphInfo.AnimatType.Single, + }; + } + + public static void AddAnime( + ObservableCollection collection, + string path, + GraphInfo.AnimatType animatType = AnimatType.Single + ) + { + if (Directory.EnumerateFiles(path).Any()) + { + var animeModel = new AnimeModel(path); + animeModel.AnimeType.Value = animatType; + collection.Add(animeModel); + } + else + { + foreach (var imagesDir in Directory.EnumerateDirectories(path)) + { + var animeModel = new AnimeModel(imagesDir); + animeModel.AnimeType.Value = animatType; + collection.Add(animeModel); } } } @@ -96,7 +193,6 @@ public class AnimeModel //public ObservableValue ModeType { get; } = new(); public ObservableCollection Images { get; } = new(); - private static readonly char[] _splits = new char[] { '_' }; public AnimeModel() { } @@ -104,8 +200,7 @@ public class AnimeModel { foreach (var file in Directory.EnumerateFiles(imagesPath)) { - var info = Path.GetFileNameWithoutExtension(file) - .Split(_splits, StringSplitOptions.RemoveEmptyEntries); + var info = Path.GetFileNameWithoutExtension(file).Split(Utils.Separator); Id.Value = info[0]; var duration = info.Last(); var imageModel = new ImageModel(Utils.LoadImageToStream(file), int.Parse(duration)); diff --git a/VPet.ModMaker/Models/ModModel/ModInfoModel.cs b/VPet.ModMaker/Models/ModModel/ModInfoModel.cs index 35d0cdd..914d5f8 100644 --- a/VPet.ModMaker/Models/ModModel/ModInfoModel.cs +++ b/VPet.ModMaker/Models/ModModel/ModInfoModel.cs @@ -84,8 +84,8 @@ public class ModInfoModel : I18nModel true, out var animeType ); - if (animeType is GraphInfo.GraphType.Default) - petModel.Animes.Add(new(animeType, dir)); + if (AnimeTypeModel.Create(animeType, dir) is AnimeTypeModel model) + petModel.Animes.Add(model); } } } @@ -250,6 +250,88 @@ public class ModInfoModel : I18nModel var petAnimePath = Path.Combine(petPath, pet.Id.Value); Directory.CreateDirectory(petAnimePath); SaveAnime_Default(petAnimePath, pet); + SaveAnime_MultiType(petAnimePath, pet); + } + } + + void SaveAnime_MultiType(string path, PetModel pet) + { + if ( + pet.Animes.FirstOrDefault(m => m.GraphType.Value is GraphInfo.GraphType.Touch_Head) + is AnimeTypeModel animeType1 + ) + { + SaveMultiTypeAnime( + Path.Combine(path, nameof(GraphInfo.GraphType.Touch_Head)), + animeType1 + ); + } + if ( + pet.Animes.FirstOrDefault(m => m.GraphType.Value is GraphInfo.GraphType.Touch_Body) + is AnimeTypeModel animeType2 + ) + { + SaveMultiTypeAnime( + Path.Combine(path, nameof(GraphInfo.GraphType.Touch_Body)), + animeType2 + ); + } + + static void SaveMultiTypeAnime(string animePath, AnimeTypeModel model) + { + Directory.CreateDirectory(animePath); + if (model.HappyAnimes.Count > 0) + { + var modePath = Path.Combine(animePath, nameof(GameSave.ModeType.Happy)); + SaveAnimes(modePath, model.HappyAnimes); + } + if (model.NomalAnimes.Count > 0) + { + var modePath = Path.Combine(animePath, nameof(GameSave.ModeType.Nomal)); + SaveAnimes(modePath, model.NomalAnimes); + } + if (model.PoorConditionAnimes.Count > 0) + { + var modePath = Path.Combine(animePath, nameof(GameSave.ModeType.PoorCondition)); + SaveAnimes(modePath, model.PoorConditionAnimes); + } + if (model.IllAnimes.Count > 0) + { + var modePath = Path.Combine(animePath, nameof(GameSave.ModeType.Ill)); + SaveAnimes(modePath, model.IllAnimes); + } + } + + static void SaveAnimes(string animePath, ObservableCollection animes) + { + Directory.CreateDirectory(animePath); + var countA = 0; + var countB = 0; + var countC = 0; + foreach (var anime in animes) + { + if (anime.AnimeType.Value is GraphInfo.AnimatType.A_Start) + { + var animatTypePath = Path.Combine(animePath, "A"); + Directory.CreateDirectory(animatTypePath); + SaveImages(Path.Combine(animatTypePath, countA.ToString()), anime); + countA++; + } + else if (anime.AnimeType.Value is GraphInfo.AnimatType.B_Loop) + { + var animatTypePath = Path.Combine(animePath, "B"); + Directory.CreateDirectory(animatTypePath); + SaveImages(Path.Combine(animatTypePath, countB.ToString()), anime); + countB++; + } + else if (anime.AnimeType.Value is GraphInfo.AnimatType.C_End) + { + var animatTypePath = Path.Combine(animePath, "C"); + Directory.CreateDirectory(animatTypePath); + SaveImages(Path.Combine(animatTypePath, countC.ToString()), anime); + countC++; + } + } } } @@ -265,53 +347,55 @@ public class ModInfoModel : I18nModel if (animeType.HappyAnimes.Count > 0) { var modePath = Path.Combine(animePath, nameof(GameSave.ModeType.Happy)); - SaveImage(animeType.HappyAnimes, animeType, modePath); + SaveAnimes(modePath, animeType.HappyAnimes); } if (animeType.NomalAnimes.Count > 0) { var modePath = Path.Combine(animePath, nameof(GameSave.ModeType.Nomal)); - SaveImage(animeType.NomalAnimes, animeType, modePath); + SaveAnimes(modePath, animeType.NomalAnimes); } if (animeType.PoorConditionAnimes.Count > 0) { var modePath = Path.Combine(animePath, nameof(GameSave.ModeType.PoorCondition)); - SaveImage(animeType.PoorConditionAnimes, animeType, modePath); + SaveAnimes(modePath, animeType.PoorConditionAnimes); } if (animeType.IllAnimes.Count > 0) { var modePath = Path.Combine(animePath, nameof(GameSave.ModeType.Ill)); - SaveImage(animeType.IllAnimes, animeType, modePath); + SaveAnimes(modePath, animeType.IllAnimes); } - - static void SaveImage( - ObservableCollection animes, - AnimeTypeModel animeType, - string modePath - ) + static void SaveAnimes(string animePath, ObservableCollection animes) { - Directory.CreateDirectory(modePath); + Directory.CreateDirectory(animePath); var count = 0; foreach (var anime in animes) { - var imagePath = Path.Combine(modePath, count.ToString()); + var imagePath = Path.Combine(animePath, count.ToString()); Directory.CreateDirectory(imagePath); - var imageIndex = 0; - foreach (var image in anime.Images) - { - File.Copy( - image.Image.Value.GetSourceFile(), - Path.Combine( - imagePath, - $"{anime.Id.Value}_{imageIndex:000}_{image.Duration.Value}.png" - ) - ); - imageIndex++; - } + SaveImages(Path.Combine(imagePath, count.ToString()), anime); count++; } } } + static void SaveImages(string imagesPath, AnimeModel model) + { + Directory.CreateDirectory(imagesPath); + var imageIndex = 0; + foreach (var image in model.Images) + { + File.Copy( + image.Image.Value.GetSourceFile(), + Path.Combine( + imagesPath, + $"{model.Id.Value}_{imageIndex:000}_{image.Duration.Value}.png" + ), + true + ); + imageIndex++; + } + } + void GetMoveInfo(LPS lps, PetModel pet) { foreach (var move in pet.Moves) diff --git a/VPet.ModMaker/Models/Utils.cs b/VPet.ModMaker/Models/Utils.cs index 2265c93..5dc97ef 100644 --- a/VPet.ModMaker/Models/Utils.cs +++ b/VPet.ModMaker/Models/Utils.cs @@ -13,6 +13,7 @@ public static class Utils { public const int DecodePixelWidth = 250; public const int DecodePixelHeight = 250; + public static char[] Separator { get; } = new char[] { '_' }; public static BitmapImage LoadImageToStream(string imagePath) { diff --git a/VPet.ModMaker/VPet.ModMaker.csproj b/VPet.ModMaker/VPet.ModMaker.csproj index 9229814..dcdec11 100644 --- a/VPet.ModMaker/VPet.ModMaker.csproj +++ b/VPet.ModMaker/VPet.ModMaker.csproj @@ -92,6 +92,7 @@ + diff --git a/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimeEditWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimeEditWindowVM.cs index e244e42..482d2fb 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimeEditWindowVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimeEditWindowVM.cs @@ -23,6 +23,8 @@ public class AnimeEditWindowVM public ObservableValue CurrentAnimeModel { get; } = new(); public GameSave.ModeType CurrentMode { get; set; } public ObservableValue Loop { get; } = new(); + + public ObservableValue HasMultiType { get; } = new(false); #region Command public ObservableCommand PlayCommand { get; } = new(); public ObservableCommand StopCommand { get; } = new(); @@ -41,7 +43,6 @@ public class AnimeEditWindowVM _playerTask = new(Play); CurrentAnimeModel.ValueChanged += CurrentAnimeModel_ValueChanged; - ; PlayCommand.ExecuteEvent += PlayCommand_ExecuteEvent; StopCommand.ExecuteEvent += StopCommand_ExecuteEvent; @@ -49,6 +50,23 @@ public class AnimeEditWindowVM ClearImageCommand.ExecuteEvent += ClearImageCommand_ExecuteEvent; RemoveAnimeCommand.ExecuteEvent += RemoveAnimeCommand_ExecuteEvent; RemoveImageCommand.ExecuteEvent += RemoveImageCommand_ExecuteEvent; + + Anime.ValueChanged += Anime_ValueChanged; + } + + private void Anime_ValueChanged(AnimeTypeModel oldValue, AnimeTypeModel newValue) + { + CheckGraphType(newValue); + } + + private void CheckGraphType(AnimeTypeModel model) + { + if ( + model.GraphType.Value + is GraphInfo.GraphType.Touch_Body + or GraphInfo.GraphType.Touch_Head + ) + HasMultiType.Value = true; } private void CurrentAnimeModel_ValueChanged(AnimeModel oldValue, AnimeModel newValue) @@ -115,6 +133,31 @@ public class AnimeEditWindowVM } } + public void AddImages(AnimeModel model, IEnumerable paths) + { + try + { + foreach (string path in paths) + { + if (File.Exists(path)) + { + model.Images.Add(new(Utils.LoadImageToStream(path))); + } + else if (Directory.Exists(path)) + { + foreach (var file in Directory.EnumerateFiles(path, "*.png")) + { + model.Images.Add(new(Utils.LoadImageToStream(path))); + } + } + } + } + catch (Exception ex) + { + MessageBox.Show("添加失败 \n{0}".Translate(ex)); + } + } + private void StopCommand_ExecuteEvent() { if (_playing is false) diff --git a/VPet.ModMaker/Views/ModEdit/AnimeEdit/AnimeEditWindow.xaml b/VPet.ModMaker/Views/ModEdit/AnimeEdit/AnimeEditWindow.xaml index 2645310..bb7daa9 100644 --- a/VPet.ModMaker/Views/ModEdit/AnimeEdit/AnimeEditWindow.xaml +++ b/VPet.ModMaker/Views/ModEdit/AnimeEdit/AnimeEditWindow.xaml @@ -48,6 +48,7 @@ + @@ -59,6 +60,12 @@ + i.Id.Value == ViewModel.Work.Value.Id.Value) - //) - //{ - // MessageBox.Show("此Id已存在".Translate(), "", MessageBoxButton.OK, MessageBoxImage.Warning); - // return; - //} IsCancel = false; Close(); } - //private void ListBox_Drop(object sender, DragEventArgs e) - //{ - // var fileName = ((System.Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString(); - //} - private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e) { if ( @@ -125,13 +97,15 @@ public partial class AnimeEditWindow : Window private void ListBox_Drop(object sender, DragEventArgs e) { - if (sender.Equals(_dropSender) is false) + if (sender is not ListBox listBox) + return; + if (e.Data.GetData(DataFormats.FileDrop) is Array array) + ViewModel.AddImages((AnimeModel)listBox.DataContext, array.Cast()); + if (_dropSender is not null && sender.Equals(_dropSender) is false) { MessageBox.Show("无法移动不同动画的图片"); return; } - if (sender is not ListBox listBox) - return; var pos = e.GetPosition(listBox); var result = VisualTreeHelper.HitTest(listBox, pos); if (result == null)