From 5b602d864d8e08bbc1f6cfb76c4a5144a443b208 Mon Sep 17 00:00:00 2001 From: Hakoyu Date: Fri, 6 Oct 2023 18:36:49 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- VPet.ModMaker/Models/EnumFlagsVM.cs | 30 +- VPet.ModMaker/Models/Expansions.cs | 38 ++ VPet.ModMaker/Models/I18nHelper.cs | 25 ++ VPet.ModMaker/Models/I18nModel.cs | 57 ++- VPet.ModMaker/Models/ModLoader.cs | 390 ++++++++++-------- .../{ModMakerHistory.cs => ModMakeHistory.cs} | 23 +- VPet.ModMaker/Models/ModMakerInfo.cs | 14 + .../Models/ModModel/ClickTextModel.cs | 4 +- VPet.ModMaker/Models/ModModel/MoveModel.cs | 6 +- .../Models/ModModel/SelectTextModel.cs | 2 +- VPet.ModMaker/Models/ObservableRange.cs | 33 +- VPet.ModMaker/Models/Utils.cs | 15 + VPet.ModMaker/VPet.ModMaker.csproj | 2 +- .../ModEdit/AnimeEdit/AnimeEditWindowVM.cs | 151 +++++-- .../ModEdit/AnimeEdit/AnimePageVM.cs | 50 ++- .../ClickTextEdit/ClickTextEditWindowVM.cs | 8 +- .../ModEdit/ClickTextEdit/ClickTextPageVM.cs | 33 ++ VPet.ModMaker/ViewModels/ModMakerWindowVM.cs | 31 +- VPet.ModMaker/Views/ModMakerWindow.xaml.cs | 2 +- 19 files changed, 661 insertions(+), 253 deletions(-) rename VPet.ModMaker/Models/{ModMakerHistory.cs => ModMakeHistory.cs} (66%) diff --git a/VPet.ModMaker/Models/EnumFlagsVM.cs b/VPet.ModMaker/Models/EnumFlagsVM.cs index f711b0b..853f366 100644 --- a/VPet.ModMaker/Models/EnumFlagsVM.cs +++ b/VPet.ModMaker/Models/EnumFlagsVM.cs @@ -2,29 +2,53 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Text; using System.Threading.Tasks; namespace VPet.ModMaker.Models; -public class ObservableEnumFlagsVM +/// +/// 可观察的枚举标签模型 +/// +/// +public class ObservableEnumFlags where T : Enum { + /// + /// 枚举值 + /// public ObservableValue EnumValue { get; } = new(); + /// + /// 添加枚举命令 + /// public ObservableCommand AddCommand { get; } = new(); + + /// + /// 删除枚举命令 + /// public ObservableCommand RemoveCommand { get; } = new(); + /// + /// 枚举类型 + /// public Type EnumType = typeof(T); + + /// + /// 枚举基类 + /// public Type UnderlyingType { get; } = Enum.GetUnderlyingType(typeof(T)); - public ObservableEnumFlagsVM() + public ObservableEnumFlags() { + if (Attribute.IsDefined(EnumType, typeof(FlagsAttribute)) is false) + throw new Exception("此枚举类型未使用特性 [Flags]"); AddCommand.ExecuteEvent += AddCommand_ExecuteEvent; RemoveCommand.ExecuteEvent += RemoveCommand_ExecuteEvent; } - public ObservableEnumFlagsVM(T value) + public ObservableEnumFlags(T value) : this() { EnumValue.Value = value; diff --git a/VPet.ModMaker/Models/Expansions.cs b/VPet.ModMaker/Models/Expansions.cs index 71953f4..0883804 100644 --- a/VPet.ModMaker/Models/Expansions.cs +++ b/VPet.ModMaker/Models/Expansions.cs @@ -13,8 +13,18 @@ using VPet_Simulator.Core; namespace VPet.ModMaker.Models; +/// +/// 拓展 +/// public static class Extensions { + /// + /// + /// + /// + /// + /// + /// public static bool Contains(this string source, string value, StringComparison comparisonType) { return source.IndexOf(value, comparisonType) >= 0; @@ -25,6 +35,10 @@ public static class Extensions // return ((FileStream)image.StreamSource).Name; //} + /// + /// 关闭流 + /// + /// 图像资源 public static void CloseStream(this ImageSource source) { if (source is BitmapImage image) @@ -33,6 +47,11 @@ public static class Extensions } } + /// + /// 图像复制 + /// + /// 图像 + /// 复制的图像 public static BitmapImage Copy(this BitmapImage image) { BitmapImage newImage = new(); @@ -54,6 +73,11 @@ public static class Extensions return newImage; } + /// + /// 保存至Png图片 + /// + /// 图片资源 + /// 路径 public static void SaveToPng(this BitmapSource image, string path) { if (path.EndsWith(".png") is false) @@ -64,6 +88,15 @@ public static class Extensions encoder.Save(fs); } + /// + /// 尝试添加 + /// + /// 键类型 + /// + /// + /// 键 + /// 值 + /// 成功为 失败为 public static bool TryAdd( this IDictionary dictionary, TKey key, @@ -76,6 +109,11 @@ public static class Extensions return true; } + /// + /// 是含有名称的动画 + /// + /// + /// public static bool IsHasNameAnime(this GraphInfo.GraphType graphType) { return AnimeTypeModel.HasNameAnimes.Contains(graphType); diff --git a/VPet.ModMaker/Models/I18nHelper.cs b/VPet.ModMaker/Models/I18nHelper.cs index 71718b7..e2fc724 100644 --- a/VPet.ModMaker/Models/I18nHelper.cs +++ b/VPet.ModMaker/Models/I18nHelper.cs @@ -8,10 +8,24 @@ using System.Threading.Tasks; namespace VPet.ModMaker.Models; +/// +/// I18n助手 +/// public class I18nHelper { + /// + /// 当前数据 + /// public static I18nHelper Current { get; set; } = new(); + + /// + /// 当前文化名称 + /// public ObservableValue CultureName { get; } = new(); + + /// + /// 文化列表 + /// public ObservableCollection CultureNames { get; } = new(); public I18nHelper() @@ -42,8 +56,19 @@ public class I18nHelper } } + /// + /// 添加文化事件 + /// public event CultureEventHandler AddCulture; + + /// + /// 删除文化事件 + /// public event CultureEventHandler RemoveCulture; + + /// + /// 修改文化事件 + /// public event ReplaceCultureEventHandler ReplaceCulture; public delegate void CultureEventHandler(string culture); diff --git a/VPet.ModMaker/Models/I18nModel.cs b/VPet.ModMaker/Models/I18nModel.cs index 82f039c..c1752fd 100644 --- a/VPet.ModMaker/Models/I18nModel.cs +++ b/VPet.ModMaker/Models/I18nModel.cs @@ -7,18 +7,29 @@ using System.Threading.Tasks; namespace VPet.ModMaker.Models; +/// +/// I18n模型 +/// +/// 类型 public class I18nModel where T : class, new() { + /// + /// 当前I18n数据 + /// public ObservableValue CurrentI18nData { get; } = new(); + + /// + /// 所有I18n数据 + /// public Dictionary I18nDatas { get; } = new(); public I18nModel() { - I18nHelper.Current.CultureName.ValueChanged += LangChanged; - I18nHelper.Current.AddCulture += AddLang; - I18nHelper.Current.RemoveCulture += RemoveLang; - I18nHelper.Current.ReplaceCulture += ReplaceLang; + I18nHelper.Current.CultureName.ValueChanged += CultureChanged; + I18nHelper.Current.AddCulture += AddCulture; + I18nHelper.Current.RemoveCulture += RemoveCulture; + I18nHelper.Current.ReplaceCulture += ReplaceCulture; if (I18nHelper.Current.CultureNames.Count == 0) return; foreach (var item in I18nHelper.Current.CultureNames) @@ -28,27 +39,45 @@ public class I18nModel CurrentI18nData.Value = I18nDatas[I18nHelper.Current.CultureName.Value]; } - private void LangChanged(string oldValue, string newValue) + /// + /// 文化改变 + /// + /// + /// + private void CultureChanged(string oldValue, string newValue) { if (I18nDatas.TryGetValue(newValue, out var result)) CurrentI18nData.Value = result; } - private void AddLang(string lang) + /// + /// 添加文化 + /// + /// 文化名称 + private void AddCulture(string culture) { - if (I18nDatas.ContainsKey(lang) is false) - I18nDatas.Add(lang, new()); + if (I18nDatas.ContainsKey(culture) is false) + I18nDatas.Add(culture, new()); } - private void RemoveLang(string lang) + /// + /// 删除文化 + /// + /// 文化名称 + private void RemoveCulture(string culture) { - I18nDatas.Remove(lang); + I18nDatas.Remove(culture); } - private void ReplaceLang(string oldLang, string newLang) + /// + /// 替换文化 + /// + /// 旧文化名称 + /// 新文化名称 + private void ReplaceCulture(string oldCulture, string newCulture) { - var item = I18nDatas[oldLang]; - I18nDatas.Remove(oldLang); - I18nDatas.Add(newLang, item); + var item = I18nDatas[oldCulture]; + I18nDatas.Remove(oldCulture); + I18nDatas.Add(newCulture, item); } } diff --git a/VPet.ModMaker/Models/ModLoader.cs b/VPet.ModMaker/Models/ModLoader.cs index 5747166..c106a2e 100644 --- a/VPet.ModMaker/Models/ModLoader.cs +++ b/VPet.ModMaker/Models/ModLoader.cs @@ -12,9 +12,19 @@ using VPet_Simulator.Windows.Interface; namespace VPet.ModMaker.Models; +/// +/// 模组加载器 +/// public class ModLoader { + /// + /// 名称 + /// public string Name { get; } + + /// + /// 作者 + /// public string Author { get; } /// @@ -26,193 +36,231 @@ public class ModLoader /// 上传至Steam的ItemID /// public ulong ItemID { get; } - public string Intro { get; } - public DirectoryInfo ModPath { get; } - public int GameVer { get; } - public int Ver { get; } - public HashSet Tag { get; } = new(); - public bool SuccessLoad { get; } = true; - public DateTime CacheDate { get; } = DateTime.MinValue; - public List Pets { get; } = new(); - public List Foods { get; } = new(); - public List LowTexts { get; } = new(); - public List ClickTexts { get; } = new(); - public List SelectTexts { get; } = new(); - public Dictionary MultiGraphs { get; } = new(); + /// + /// 简介 + /// + public string Intro { get; } + + /// + /// 模组路径 + /// + public DirectoryInfo ModPath { get; } + + /// + /// 支持的游戏版本 + /// + public int GameVer { get; } + + /// + /// 版本 + /// + public int Ver { get; } + + /// + /// 标签 + /// + public HashSet Tag { get; } = new(); + + /// + /// 缓存数据 + /// + public DateTime CacheDate { get; } = DateTime.MinValue; + + /// + /// 宠物列表 + /// + public List Pets { get; } = new(); + + /// + /// 食物列表 + /// + public List Foods { get; } = new(); + + /// + /// 低状态文本列表 + /// + public List LowTexts { get; } = new(); + + /// + /// 点击文本列表 + /// + public List ClickTexts { get; } = new(); + + /// + /// 选择文本列表 + /// + public List SelectTexts { get; } = new(); + + /// + /// I18n数据 + /// public Dictionary I18nDatas { get; } = new(); + /// + /// 其它I18n数据 + /// public Dictionary> OtherI18nDatas { get; } = new(); public ModLoader(DirectoryInfo path) { - try + ModPath = path; + LpsDocument modlps = new LpsDocument(File.ReadAllText(path.FullName + @"\info.lps")); + Name = modlps.FindLine("vupmod").Info; + Intro = modlps.FindLine("intro").Info; + GameVer = modlps.FindSub("gamever").InfoToInt; + Ver = modlps.FindSub("ver").InfoToInt; + Author = modlps.FindSub("author").Info.Split('[').First(); + if (modlps.FindLine("authorid") != null) + AuthorID = modlps.FindLine("authorid").InfoToInt64; + else + AuthorID = 0; + if (modlps.FindLine("itemid") != null) + ItemID = Convert.ToUInt64(modlps.FindLine("itemid").info); + else + ItemID = 0; + CacheDate = modlps.GetDateTime("cachedate", DateTime.MinValue); + + //MOD未加载时支持翻译 + foreach (var line in modlps.FindAllLine("lang")) { - ModPath = path; - LpsDocument modlps = new LpsDocument(File.ReadAllText(path.FullName + @"\info.lps")); - Name = modlps.FindLine("vupmod").Info; - Intro = modlps.FindLine("intro").Info; - GameVer = modlps.FindSub("gamever").InfoToInt; - Ver = modlps.FindSub("ver").InfoToInt; - Author = modlps.FindSub("author").Info.Split('[').First(); - if (modlps.FindLine("authorid") != null) - AuthorID = modlps.FindLine("authorid").InfoToInt64; - else - AuthorID = 0; - if (modlps.FindLine("itemid") != null) - ItemID = Convert.ToUInt64(modlps.FindLine("itemid").info); - else - ItemID = 0; - CacheDate = modlps.GetDateTime("cachedate", DateTime.MinValue); - - //MOD未加载时支持翻译 - foreach (var line in modlps.FindAllLine("lang")) + var i18nData = new I18nModInfoModel(); + foreach (var sub in line) { - var i18nData = new I18nModInfoModel(); - foreach (var sub in line) - { - if (sub.Name == Name) - i18nData.Name.Value = sub.Info; - else if (sub.Name == Intro) - i18nData.Description.Value = sub.Info; - } - I18nDatas.Add(line.Info, i18nData); + if (sub.Name == Name) + i18nData.Name.Value = sub.Info; + else if (sub.Name == Intro) + i18nData.Description.Value = sub.Info; } - DirectoryInfo? langDirectory = null; - foreach (DirectoryInfo di in path.EnumerateDirectories()) + I18nDatas.Add(line.Info, i18nData); + } + DirectoryInfo? langDirectory = null; + foreach (DirectoryInfo di in path.EnumerateDirectories()) + { + switch (di.Name.ToLower()) { - switch (di.Name.ToLower()) - { - case "pet": - //宠物模型 - Tag.Add("pet"); - foreach (FileInfo fi in di.EnumerateFiles("*.lps")) - { - var lps = new LpsDocument(File.ReadAllText(fi.FullName)); - if (lps.First().Name.ToLower() == "pet") - { - var name = lps.First().Info; - var pet = new PetLoader(lps, di); - Pets.Add(pet); - // ! : 此方法会导致 LoadImageToStream 无法使用 - //var graphCore = new GraphCore(0); - //foreach (var p in pet.path) - // PetLoader.LoadGraph(graphCore, di, p); - //MultiGraphs.Add(pet.Name, graphCore); - } - } - break; - case "food": - Tag.Add("food"); - foreach (FileInfo fi in di.EnumerateFiles("*.lps")) - { - var tmp = new LpsDocument(File.ReadAllText(fi.FullName)); - foreach (ILine li in tmp) - { - var food = LPSConvert.DeserializeObject(li); - var imagePath = $"{path.FullName}\\image\\food\\{food.Name}.png"; - if (File.Exists(imagePath)) - food.Image = imagePath; - Foods.Add(food); - //string tmps = li.Find("name").info; - //mw.Foods.RemoveAll(x => x.Id == tmps); - //mw.Foods.Add(LPSConvert.DeserializeObject(li)); - } - } - break; - case "image": - Tag.Add("image"); - break; - case "text": - Tag.Add("text"); - foreach (FileInfo fi in di.EnumerateFiles("*.lps")) - { - var tmp = new LpsDocument(File.ReadAllText(fi.FullName)); - foreach (ILine li in tmp) - { - switch (li.Name.ToLower()) - { - case "lowfoodtext": - LowTexts.Add(LPSConvert.DeserializeObject(li)); - break; - case "lowdrinktext": - LowTexts.Add(LPSConvert.DeserializeObject(li)); - break; - case "clicktext": - ClickTexts.Add(LPSConvert.DeserializeObject(li)); - break; - case "selecttext": - SelectTexts.Add( - LPSConvert.DeserializeObject(li) - ); - break; - } - } - } - break; - case "lang": - Tag.Add("lang"); - langDirectory = di; - //foreach (FileInfo fi in di.EnumerateFiles("*.lps")) - //{ - // //LocalizeCore.AddCulture( - // // fi.Id.Substring(0, fi.Id.Length - fi.Extension.Length), - // // new LPS_D(File.ReadAllText(fi.FullName)) - // //); - //} - //foreach (DirectoryInfo dis in di.EnumerateDirectories()) - //{ - // foreach (FileInfo fi in dis.EnumerateFiles("*.lps")) - // { - // //LocalizeCore.AddCulture( - // // dis.Id, - // // new LPS_D(File.ReadAllText(fi.FullName)) - // //); - // } - //} - - //if (mw.Set.Language == "null") - //{ - // LocalizeCore.LoadDefaultCulture(); - //} - //else - // LocalizeCore.LoadCulture(mw.Set.Language); - break; - } - } - if (langDirectory is null) - return; - foreach (DirectoryInfo dis in langDirectory.EnumerateDirectories()) - { - OtherI18nDatas.Add(dis.Name, new()); - foreach (FileInfo fi in dis.EnumerateFiles("*.lps")) - { - var lps = new LPS(File.ReadAllText(fi.FullName)); - foreach (var item in lps) + case "pet": + //宠物模型 + Tag.Add("pet"); + foreach (FileInfo fi in di.EnumerateFiles("*.lps")) { - if (OtherI18nDatas[dis.Name].ContainsKey(item.Name) is false) - OtherI18nDatas[dis.Name].TryAdd(item.Name, item.Info); + var lps = new LpsDocument(File.ReadAllText(fi.FullName)); + if (lps.First().Name.ToLower() == "pet") + { + var name = lps.First().Info; + var pet = new PetLoader(lps, di); + Pets.Add(pet); + // ! : 此方法会导致 LoadImageToStream 无法使用 + //var graphCore = new GraphCore(0); + //foreach (var p in pet.path) + // PetLoader.LoadGraph(graphCore, di, p); + //MultiGraphs.Add(pet.Name, graphCore); + } } + break; + case "food": + Tag.Add("food"); + foreach (FileInfo fi in di.EnumerateFiles("*.lps")) + { + var tmp = new LpsDocument(File.ReadAllText(fi.FullName)); + foreach (ILine li in tmp) + { + var food = LPSConvert.DeserializeObject(li); + var imagePath = $"{path.FullName}\\image\\food\\{food.Name}.png"; + if (File.Exists(imagePath)) + food.Image = imagePath; + Foods.Add(food); + //string tmps = li.Find("name").info; + //mw.Foods.RemoveAll(x => x.Id == tmps); + //mw.Foods.Add(LPSConvert.DeserializeObject(li)); + } + } + break; + case "image": + Tag.Add("image"); + break; + case "text": + Tag.Add("text"); + foreach (FileInfo fi in di.EnumerateFiles("*.lps")) + { + var tmp = new LpsDocument(File.ReadAllText(fi.FullName)); + foreach (ILine li in tmp) + { + switch (li.Name.ToLower()) + { + case "lowfoodtext": + LowTexts.Add(LPSConvert.DeserializeObject(li)); + break; + case "lowdrinktext": + LowTexts.Add(LPSConvert.DeserializeObject(li)); + break; + case "clicktext": + ClickTexts.Add(LPSConvert.DeserializeObject(li)); + break; + case "selecttext": + SelectTexts.Add(LPSConvert.DeserializeObject(li)); + break; + } + } + } + break; + case "lang": + Tag.Add("lang"); + langDirectory = di; + //foreach (FileInfo fi in di.EnumerateFiles("*.lps")) + //{ + // //LocalizeCore.AddCulture( + // // fi.Id.Substring(0, fi.Id.Length - fi.Extension.Length), + // // new LPS_D(File.ReadAllText(fi.FullName)) + // //); + //} + //foreach (DirectoryInfo dis in di.EnumerateDirectories()) + //{ + // foreach (FileInfo fi in dis.EnumerateFiles("*.lps")) + // { + // //LocalizeCore.AddCulture( + // // dis.Id, + // // new LPS_D(File.ReadAllText(fi.FullName)) + // //); + // } + //} + + //if (mw.Set.Language == "null") + //{ + // LocalizeCore.LoadDefaultCulture(); + //} + //else + // LocalizeCore.LoadCulture(mw.Set.Language); + break; + } + } + if (langDirectory is null) + return; + foreach (DirectoryInfo dis in langDirectory.EnumerateDirectories()) + { + OtherI18nDatas.Add(dis.Name, new()); + foreach (FileInfo fi in dis.EnumerateFiles("*.lps")) + { + var lps = new LPS(File.ReadAllText(fi.FullName)); + foreach (var item in lps) + { + if (OtherI18nDatas[dis.Name].ContainsKey(item.Name) is false) + OtherI18nDatas[dis.Name].TryAdd(item.Name, item.Info); } } } - catch (Exception ex) - { - Tag.Add("该模组已损坏"); - SuccessLoad = false; - } } - public void WriteFile() - { - var lps = new LpsDocument(File.ReadAllText(ModPath.FullName + @"\info.lps")); - lps.FindLine("vupmod").Info = Name; - lps.FindLine("intro").Info = Intro; - lps.FindSub("gamever").InfoToInt = GameVer; - lps.FindSub("ver").InfoToInt = Ver; - lps.FindSub("author").Info = Author; - lps.FindorAddLine("authorid").InfoToInt64 = AuthorID; - lps.FindorAddLine("itemid").info = ItemID.ToString(); - File.WriteAllText(ModPath.FullName + @"\info.lps", lps.ToString()); - } + //public void WriteFile() + //{ + // var lps = new LpsDocument(File.ReadAllText(ModPath.FullName + @"\info.lps")); + // lps.FindLine("vupmod").Info = Name; + // lps.FindLine("intro").Info = Intro; + // lps.FindSub("gamever").InfoToInt = GameVer; + // lps.FindSub("ver").InfoToInt = Ver; + // lps.FindSub("author").Info = Author; + // lps.FindorAddLine("authorid").InfoToInt64 = AuthorID; + // lps.FindorAddLine("itemid").info = ItemID.ToString(); + // File.WriteAllText(ModPath.FullName + @"\info.lps", lps.ToString()); + //} } diff --git a/VPet.ModMaker/Models/ModMakerHistory.cs b/VPet.ModMaker/Models/ModMakeHistory.cs similarity index 66% rename from VPet.ModMaker/Models/ModMakerHistory.cs rename to VPet.ModMaker/Models/ModMakeHistory.cs index 76c8942..7d4dfe4 100644 --- a/VPet.ModMaker/Models/ModMakerHistory.cs +++ b/VPet.ModMaker/Models/ModMakeHistory.cs @@ -9,15 +9,30 @@ using System.Windows.Media.Imaging; namespace VPet.ModMaker.Models; -public class ModMakerHistory +/// +/// 模组制作历史 +/// +public class ModMakeHistory { + /// + /// 图片 + /// public BitmapImage Image { get; set; } + /// + /// Id + /// [Line(ignoreCase: true)] public string Id { get; set; } + /// + /// 路径 + /// private string _path; + /// + /// 资源路径 + /// [Line(ignoreCase: true)] public string SourcePath { @@ -31,8 +46,14 @@ public class ModMakerHistory } } + /// + /// 模组信息文件 + /// public string InfoFile => Path.Combine(SourcePath, "info.lps"); + /// + /// 最后编辑时间 + /// [Line(ignoreCase: true)] public DateTime LastTime { get; set; } } diff --git a/VPet.ModMaker/Models/ModMakerInfo.cs b/VPet.ModMaker/Models/ModMakerInfo.cs index 8dfed66..0d24e91 100644 --- a/VPet.ModMaker/Models/ModMakerInfo.cs +++ b/VPet.ModMaker/Models/ModMakerInfo.cs @@ -6,9 +6,23 @@ using System.Threading.Tasks; namespace VPet.ModMaker.Models; +/// +/// 模组制作器信息 +/// public static class ModMakerInfo { + /// + /// 基础目录 + /// public const string BaseDirectory = nameof(ModMaker); + + /// + /// 历史文件 + /// public const string HistoryFile = $"{BaseDirectory}\\history.lps"; + + /// + /// 信息文件 + /// public const string InfoFile = "info.lps"; } diff --git a/VPet.ModMaker/Models/ModModel/ClickTextModel.cs b/VPet.ModMaker/Models/ModModel/ClickTextModel.cs index 89f6ec4..ad571e0 100644 --- a/VPet.ModMaker/Models/ModModel/ClickTextModel.cs +++ b/VPet.ModMaker/Models/ModModel/ClickTextModel.cs @@ -24,9 +24,9 @@ public class ClickTextModel : I18nModel public ObservableValue Id { get; } = new(); public ObservableValue Working { get; } = new(); - public ObservableEnumFlagsVM Mode { get; } = new(); + public ObservableEnumFlags Mode { get; } = new(); public ObservableValue WorkingState { get; } = new(); - public ObservableEnumFlagsVM DayTime { get; } = new(); + public ObservableEnumFlags DayTime { get; } = new(); public ObservableRange Like { get; } = new(0, int.MaxValue); public ObservableRange Health { get; } = new(0, int.MaxValue); diff --git a/VPet.ModMaker/Models/ModModel/MoveModel.cs b/VPet.ModMaker/Models/ModModel/MoveModel.cs index 307d1ac..c204b66 100644 --- a/VPet.ModMaker/Models/ModModel/MoveModel.cs +++ b/VPet.ModMaker/Models/ModModel/MoveModel.cs @@ -36,12 +36,12 @@ public class MoveModel public ObservableValue TriggerTop { get; } = new(100); public ObservableValue TriggerBottom { get; } = new(100); - public ObservableEnumFlagsVM LocateType { get; } = + public ObservableEnumFlags LocateType { get; } = new(GraphHelper.Move.DirectionType.None); - public ObservableEnumFlagsVM TriggerType { get; } = + public ObservableEnumFlags TriggerType { get; } = new(GraphHelper.Move.DirectionType.None); - public ObservableEnumFlagsVM ModeType { get; } = + public ObservableEnumFlags ModeType { get; } = new(GraphHelper.Move.ModeType.Nomal); public MoveModel() { } diff --git a/VPet.ModMaker/Models/ModModel/SelectTextModel.cs b/VPet.ModMaker/Models/ModModel/SelectTextModel.cs index 629a446..8ba4436 100644 --- a/VPet.ModMaker/Models/ModModel/SelectTextModel.cs +++ b/VPet.ModMaker/Models/ModModel/SelectTextModel.cs @@ -28,7 +28,7 @@ public class SelectTextModel : I18nModel public ObservableValue Id { get; } = new(); public ObservableValue ChooseId { get; } = new(); - public ObservableEnumFlagsVM Mode { get; } = new(); + public ObservableEnumFlags Mode { get; } = new(); //public ObservableValue Working { get; } = new(); //public ObservableValue WorkingState { get; } = new(); diff --git a/VPet.ModMaker/Models/ObservableRange.cs b/VPet.ModMaker/Models/ObservableRange.cs index acaa0a1..bf41ba5 100644 --- a/VPet.ModMaker/Models/ObservableRange.cs +++ b/VPet.ModMaker/Models/ObservableRange.cs @@ -2,11 +2,25 @@ namespace VPet.ModMaker.Models; +/// +/// 可观察的范围 +/// +/// 类型 public class ObservableRange { + /// + /// 最小值 + /// public ObservableValue Min { get; } = new(); + + /// + /// 最大值 + /// public ObservableValue Max { get; } = new(); + /// + /// 信息 + /// public ObservableValue Info { get; } = new(); public ObservableRange() @@ -15,23 +29,32 @@ public class ObservableRange Max.ValueChanged += ValueChanged; } - private void ValueChanged(T oldValue, T newValue) - { - Info.Value = $"({Min.Value}, {Max.Value})"; - } - public ObservableRange(T min, T max) : this() { SetValue(min, max); } + private void ValueChanged(T oldValue, T newValue) + { + Info.Value = $"({Min.Value}, {Max.Value})"; + } + + /// + /// 设置值 + /// + /// 最小值 + /// 最大值 public void SetValue(T min, T max) { Min.Value = min; Max.Value = max; } + /// + /// 复制 + /// + /// public ObservableRange Copy() { return new(Min.Value, Max.Value); diff --git a/VPet.ModMaker/Models/Utils.cs b/VPet.ModMaker/Models/Utils.cs index 0edccfc..73d8533 100644 --- a/VPet.ModMaker/Models/Utils.cs +++ b/VPet.ModMaker/Models/Utils.cs @@ -9,9 +9,19 @@ using System.Windows.Media.Imaging; namespace VPet.ModMaker.Models; +/// +/// 工具 +/// public static class Utils { + /// + /// 解码像素宽度 + /// public const int DecodePixelWidth = 250; + + /// + /// 节码像素高度 + /// public const int DecodePixelHeight = 250; public static char[] Separator { get; } = new char[] { '_' }; @@ -31,6 +41,11 @@ public static class Utils // return bitmapImage; //} + /// + /// 载入图片至内存流 + /// + /// + /// public static BitmapImage LoadImageToMemoryStream(string imagePath) { BitmapImage bitmapImage = new(); diff --git a/VPet.ModMaker/VPet.ModMaker.csproj b/VPet.ModMaker/VPet.ModMaker.csproj index 9357f37..45539af 100644 --- a/VPet.ModMaker/VPet.ModMaker.csproj +++ b/VPet.ModMaker/VPet.ModMaker.csproj @@ -110,7 +110,7 @@ - + diff --git a/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimeEditWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimeEditWindowVM.cs index 9046604..a8ffa1f 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimeEditWindowVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimeEditWindowVM.cs @@ -3,6 +3,7 @@ using LinePutScript.Localization.WPF; using Microsoft.Win32; using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.IO; using System.Linq; using System.Text; @@ -16,27 +17,91 @@ namespace VPet.ModMaker.ViewModels.ModEdit.AnimeEdit; public class AnimeEditWindowVM { + /// + /// 当前宠物 + /// public PetModel CurrentPet { get; set; } + + /// + /// 旧动画 + /// public AnimeTypeModel OldAnime { get; set; } + + /// + /// 动画 + /// public ObservableValue Anime { get; } = new(new()); + + /// + /// 当前图像模型 + /// public ObservableValue CurrentImageModel { get; } = new(); + + /// + /// 当前动画模型 + /// public ObservableValue CurrentAnimeModel { get; } = new(); + + /// + /// 当前模式 + /// public GameSave.ModeType CurrentMode { get; set; } + + /// + /// 循环 + /// public ObservableValue Loop { get; } = new(); + /// + /// 含有多个状态 参见 + /// public ObservableValue HasMultiType { get; } = new(false); + + /// + /// 含有动画名称 参见 + /// public ObservableValue HasAnimeName { get; } = new(false); + #region Command + /// + /// 播放命令 + /// public ObservableCommand PlayCommand { get; } = new(); + + /// + /// 停止命令 + /// public ObservableCommand StopCommand { get; } = new(); + /// + /// 添加图片命令 + /// public ObservableCommand AddImageCommand { get; } = new(); + + /// + /// 清除图片命令 + /// public ObservableCommand ClearImageCommand { get; } = new(); + + /// + /// 删除动画命令 + /// public ObservableCommand RemoveAnimeCommand { get; } = new(); + + /// + /// 删除图片命令 + /// public ObservableCommand RemoveImageCommand { get; } = new(); #endregion + /// + /// 正在播放 + /// private bool _playing = false; + + /// + /// 动画任务 + /// private Task _playerTask; public AnimeEditWindowVM() @@ -55,6 +120,7 @@ public class AnimeEditWindowVM Anime.ValueChanged += Anime_ValueChanged; } + #region LoadAnime private void Anime_ValueChanged(AnimeTypeModel oldValue, AnimeTypeModel newValue) { CheckGraphType(newValue); @@ -68,29 +134,11 @@ public class AnimeEditWindowVM if (AnimeTypeModel.HasNameAnimes.Contains(model.GraphType.Value)) HasAnimeName.Value = true; } - - private void CurrentAnimeModel_ValueChanged(AnimeModel oldValue, AnimeModel newValue) - { - StopCommand_ExecuteEvent(); - if (oldValue is not null) - oldValue.Images.CollectionChanged -= Images_CollectionChanged; - if (newValue is not null) - newValue.Images.CollectionChanged += Images_CollectionChanged; - } - - private void Images_CollectionChanged( - object sender, - System.Collections.Specialized.NotifyCollectionChangedEventArgs e - ) - { - StopCommand_ExecuteEvent(); - } - - private void RemoveImageCommand_ExecuteEvent(AnimeModel value) - { - CurrentImageModel.Value.Close(); - value.Images.Remove(CurrentImageModel.Value); - } + #endregion + /// + /// 删除动画 + /// + /// 动画模型 private void RemoveAnimeCommand_ExecuteEvent(AnimeModel value) { @@ -110,6 +158,10 @@ public class AnimeEditWindowVM } } + /// + /// 清空图片 + /// + /// 动画模型 private void ClearImageCommand_ExecuteEvent(AnimeModel value) { if ( @@ -121,20 +173,25 @@ public class AnimeEditWindowVM } } + /// + /// 添加图片 + /// + /// 动画模型 private void AddImageCommand_ExecuteEvent(AnimeModel value) { OpenFileDialog openFileDialog = - new() - { - Title = "选择图片".Translate(), - Filter = $"图片|*.jpg;*.jpeg;*.png;*.bmp".Translate() - }; + new() { Title = "选择图片".Translate(), Filter = $"图片|*.png".Translate() }; if (openFileDialog.ShowDialog() is true) { value.Images.Add(new(Utils.LoadImageToMemoryStream(openFileDialog.FileName))); } } + /// + /// 添加图片 + /// + /// 动画模型 + /// 路径 public void AddImages(AnimeModel model, IEnumerable paths) { try @@ -160,6 +217,34 @@ public class AnimeEditWindowVM } } + /// + /// 删除图片 + /// + /// 动画模型 + private void RemoveImageCommand_ExecuteEvent(AnimeModel value) + { + CurrentImageModel.Value.Close(); + value.Images.Remove(CurrentImageModel.Value); + } + + #region Player + private void CurrentAnimeModel_ValueChanged(AnimeModel oldValue, AnimeModel newValue) + { + StopCommand_ExecuteEvent(); + if (oldValue is not null) + oldValue.Images.CollectionChanged -= Images_CollectionChanged; + if (newValue is not null) + newValue.Images.CollectionChanged += Images_CollectionChanged; + } + + private void Images_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + StopCommand_ExecuteEvent(); + } + + /// + /// 停止播放 + /// private void StopCommand_ExecuteEvent() { if (_playing is false) @@ -167,6 +252,9 @@ public class AnimeEditWindowVM Reset(); } + /// + /// 开始播放 + /// private void PlayCommand_ExecuteEvent() { if (_playing) @@ -183,6 +271,9 @@ public class AnimeEditWindowVM _playerTask.Start(); } + /// + /// 播放 + /// private void Play() { do @@ -198,9 +289,13 @@ public class AnimeEditWindowVM Reset(); } + /// + /// 重置 + /// private void Reset() { _playing = false; _playerTask = new(Play); } + #endregion } diff --git a/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimePageVM.cs b/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimePageVM.cs index e0ee85b..b96a6b4 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimePageVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimePageVM.cs @@ -16,16 +16,45 @@ namespace VPet.ModMaker.ViewModels.ModEdit.AnimeEdit; public class AnimePageVM { #region Value + /// + /// 显示的动画 + /// public ObservableValue> ShowAnimes { get; } = new(); + + /// + /// 动画 + /// public ObservableCollection Animes => CurrentPet.Value.Animes; + /// + /// 宠物列表 + /// public ObservableCollection Pets => ModInfoModel.Current.Pets; + + /// + /// 当前宠物 + /// public ObservableValue CurrentPet { get; } = new(new()); + + /// + /// 搜索 + /// public ObservableValue Search { get; } = new(); #endregion #region Command + /// + /// 添加命令 + /// public ObservableCommand AddCommand { get; } = new(); + + /// + /// 编辑命令 + /// public ObservableCommand EditCommand { get; } = new(); + + /// + /// 删除命令 + /// public ObservableCommand RemoveCommand { get; } = new(); #endregion public AnimePageVM() @@ -58,8 +87,9 @@ public class AnimePageVM } } - public void Close() { } - + /// + /// 添加动画 + /// private void Add() { var selectGraphTypeWindow = new SelectGraphTypeWindow(); @@ -79,6 +109,10 @@ public class AnimePageVM Animes.Add(vm.Anime.Value); } + /// + /// 编辑动画 + /// + /// 动画类型模型 public void Edit(AnimeTypeModel model) { var window = new AnimeEditWindow(); @@ -100,18 +134,22 @@ public class AnimePageVM } } - private void Remove(AnimeTypeModel food) + /// + /// 删除动画 + /// + /// 动画类型模型 + private void Remove(AnimeTypeModel model) { if (MessageBox.Show("确定删除吗".Translate(), "", MessageBoxButton.YesNo) is MessageBoxResult.No) return; if (ShowAnimes.Value.Count == Animes.Count) { - Animes.Remove(food); + Animes.Remove(model); } else { - ShowAnimes.Value.Remove(food); - Animes.Remove(food); + ShowAnimes.Value.Remove(model); + Animes.Remove(model); } } } diff --git a/VPet.ModMaker/ViewModels/ModEdit/ClickTextEdit/ClickTextEditWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/ClickTextEdit/ClickTextEditWindowVM.cs index ef6a73d..e2f8d46 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/ClickTextEdit/ClickTextEditWindowVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/ClickTextEdit/ClickTextEditWindowVM.cs @@ -15,8 +15,14 @@ public class ClickTextEditWindowVM public I18nHelper I18nData => I18nHelper.Current; #region Value - + /// + /// 旧点击文本 + /// public ClickTextModel OldClickText { get; set; } + + /// + /// 点击文本 + /// public ObservableValue ClickText { get; } = new(new()); #endregion public ClickTextEditWindowVM() { } diff --git a/VPet.ModMaker/ViewModels/ModEdit/ClickTextEdit/ClickTextPageVM.cs b/VPet.ModMaker/ViewModels/ModEdit/ClickTextEdit/ClickTextPageVM.cs index 44e5229..3703bd5 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/ClickTextEdit/ClickTextPageVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/ClickTextEdit/ClickTextPageVM.cs @@ -15,13 +15,35 @@ namespace VPet.ModMaker.ViewModels.ModEdit.ClickTextEdit; public class ClickTextPageVM { #region Value + /// + /// 显示的点击文本 + /// public ObservableValue> ShowClickTexts { get; } = new(); + + /// + /// 点击文本 + /// public ObservableCollection ClickTexts => ModInfoModel.Current.ClickTexts; + + /// + /// 搜索 + /// public ObservableValue Search { get; } = new(); #endregion #region Command + /// + /// 添加命令 + /// public ObservableCommand AddCommand { get; } = new(); + + /// + /// 编辑命令 + /// public ObservableCommand EditCommand { get; } = new(); + + /// + /// 删除命令 + /// public ObservableCommand RemoveCommand { get; } = new(); #endregion @@ -50,6 +72,9 @@ public class ClickTextPageVM } } + /// + /// 添加点击文本 + /// private void Add() { var window = new ClickTextEditWindow(); @@ -60,6 +85,10 @@ public class ClickTextPageVM ClickTexts.Add(vm.ClickText.Value); } + /// + /// 编辑点击文本 + /// + /// 模型 public void Edit(ClickTextModel model) { var window = new ClickTextEditWindow(); @@ -80,6 +109,10 @@ public class ClickTextPageVM } } + /// + /// 删除点击文本 + /// + /// 模型 private void Remove(ClickTextModel model) { if (MessageBox.Show("确定删除吗".Translate(), "", MessageBoxButton.YesNo) is MessageBoxResult.No) diff --git a/VPet.ModMaker/ViewModels/ModMakerWindowVM.cs b/VPet.ModMaker/ViewModels/ModMakerWindowVM.cs index 732e11f..38e88b3 100644 --- a/VPet.ModMaker/ViewModels/ModMakerWindowVM.cs +++ b/VPet.ModMaker/ViewModels/ModMakerWindowVM.cs @@ -33,12 +33,12 @@ public class ModMakerWindowVM /// /// 显示的历史 /// - public ObservableValue> ShowHistories { get; } = new(); + public ObservableValue> ShowHistories { get; } = new(); /// /// 历史 /// - public ObservableCollection Histories { get; } = new(); + public ObservableCollection Histories { get; } = new(); #endregion #region Command /// @@ -59,7 +59,7 @@ public class ModMakerWindowVM /// /// 删除历史命令 /// - public ObservableCommand RemoveHistoryCommand { get; } = new(); + public ObservableCommand RemoveHistoryCommand { get; } = new(); #endregion public ModMakerWindowVM(ModMakerWindow window) @@ -83,7 +83,7 @@ public class ModMakerWindowVM } #region History - private void RemoveHistory(ModMakerHistory value) + private void RemoveHistory(ModMakeHistory value) { Histories.Remove(value); SaveHistories(); @@ -99,7 +99,7 @@ public class ModMakerWindowVM var lps = new LPS(File.ReadAllText(ModMakerInfo.HistoryFile)); foreach (var line in lps) { - var history = LPSConvert.DeserializeObject(line); + var history = LPSConvert.DeserializeObject(line); if (Histories.All(h => h.InfoFile != history.InfoFile)) Histories.Add(history); } @@ -136,7 +136,7 @@ public class ModMakerWindowVM { if ( Histories.FirstOrDefault(h => h.SourcePath == modInfo.SourcePath.Value) - is ModMakerHistory history + is ModMakeHistory history ) { history.Id = modInfo.Id.Value; @@ -240,23 +240,22 @@ public class ModMakerWindowVM /// 位置 public void LoadMod(string path) { + ModLoader? loader = null; try { - var mod = new ModLoader(new DirectoryInfo(path)); - if (mod.SuccessLoad is false) - { - MessageBox.Show("模组载入失败".Translate()); - return; - } - var pendingHandler = PendingBox.Show("载入中".Translate()); - var modInfo = new ModInfoModel(mod); - EditMod(modInfo); - pendingHandler.Close(); + loader = new ModLoader(new DirectoryInfo(path)); } catch (Exception ex) { MessageBox.Show("模组载入失败:\n{0}".Translate(ex)); } + if (loader is not null) + { + var pendingHandler = PendingBox.Show("载入中".Translate()); + var modInfo = new ModInfoModel(loader); + EditMod(modInfo); + pendingHandler.Close(); + } } #endregion } diff --git a/VPet.ModMaker/Views/ModMakerWindow.xaml.cs b/VPet.ModMaker/Views/ModMakerWindow.xaml.cs index 059240e..9d8d99c 100644 --- a/VPet.ModMaker/Views/ModMakerWindow.xaml.cs +++ b/VPet.ModMaker/Views/ModMakerWindow.xaml.cs @@ -43,7 +43,7 @@ public partial class ModMakerWindow : Window { if (sender is not ListBoxItem item) return; - if (item.DataContext is not ModMakerHistory history) + if (item.DataContext is not ModMakeHistory history) return; if (Directory.Exists(history.SourcePath) is false) {