diff --git a/VPet.ModMaker/Models/I18nHelper.cs b/VPet.ModMaker/Models/I18nHelper.cs index 7391b74..8d29087 100644 --- a/VPet.ModMaker/Models/I18nHelper.cs +++ b/VPet.ModMaker/Models/I18nHelper.cs @@ -38,48 +38,5 @@ public class I18nHelper : ObservableObjectX /// /// 文化列表 /// - public ObservableCollection CultureNames { get; } = new(); - - public I18nHelper() - { - CultureNames.CollectionChanged += Cultures_CollectionChanged; - } - - private void Cultures_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - // 替换 - if (e.NewStartingIndex == e.OldStartingIndex) - { - ReplaceCulture?.Invoke((string)e.OldItems[0], (string)e.NewItems[0]); - return; - } - // 删除 - if (e.OldItems is not null) - { - RemoveCulture?.Invoke((string)e.OldItems[0]); - } - // 新增 - if (e.NewItems is not null) - { - AddCulture?.Invoke((string)e.NewItems[0]); - } - } - - /// - /// 添加文化事件 - /// - public event CultureEventHandler AddCulture; - - /// - /// 删除文化事件 - /// - public event CultureEventHandler RemoveCulture; - - /// - /// 修改文化事件 - /// - public event ReplaceCultureEventHandler ReplaceCulture; - - public delegate void CultureEventHandler(string culture); - public delegate void ReplaceCultureEventHandler(string oldCulture, string newCulture); + public ObservableList CultureNames { get; } = new(); } diff --git a/VPet.ModMaker/Models/I18nModel.cs b/VPet.ModMaker/Models/I18nModel.cs index d395d89..ead4139 100644 --- a/VPet.ModMaker/Models/I18nModel.cs +++ b/VPet.ModMaker/Models/I18nModel.cs @@ -4,7 +4,9 @@ using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; +using HKW.HKWUtils.Extensions; using HKW.HKWUtils.Observable; +using Mapster; namespace VPet.ModMaker.Models; @@ -22,6 +24,7 @@ public class I18nModel : ObservableObjectX> [DebuggerBrowsable(DebuggerBrowsableState.Never)] private T _currentI18nData; + [AdaptIgnore] public T CurrentI18nData { get => _currentI18nData; @@ -32,65 +35,63 @@ public class I18nModel : ObservableObjectX> /// /// 所有I18n数据 /// + [AdaptIgnore] public Dictionary I18nDatas { get; } = new(); public I18nModel() { - //TODO - //I18nHelper.Current.CultureName.ValueChanged += CultureChanged; - I18nHelper.Current.AddCulture += AddCulture; - I18nHelper.Current.RemoveCulture += RemoveCulture; - I18nHelper.Current.ReplaceCulture += ReplaceCulture; - if (I18nHelper.Current.CultureNames.Count == 0) + I18nHelper.Current.PropertyChangedX += Current_PropertyChangedX; + I18nHelper.Current.CultureNames.ListChanged += CultureNames_ListChanged; + if (I18nHelper.Current.CultureNames.HasValue() is false) return; foreach (var item in I18nHelper.Current.CultureNames) - { I18nDatas.Add(item, new()); - } CurrentI18nData = I18nDatas[I18nHelper.Current.CultureName]; } + private void CultureNames_ListChanged( + IObservableList sender, + NotifyListChangedEventArgs e + ) + { + if (e.Action is ListChangeAction.Add && e.NewItems is not null) + { + foreach (var item in e.NewItems) + I18nDatas.TryAdd(item, new()); + } + else if (e.Action is ListChangeAction.Remove && e.OldItems is not null) + { + foreach (var item in e.OldItems) + I18nDatas.Remove(item); + } + else if ( + e.Action is ListChangeAction.Add + && e.NewItems is not null + && e.OldItems is not null + ) + { + var newItem = e.NewItems.First(); + var oldItem = e.OldItems.First(); + if (I18nDatas.ContainsKey(oldItem) is false) + return; + I18nDatas[newItem] = I18nDatas[oldItem]; + I18nDatas.Remove(oldItem); + } + } + /// /// 文化改变 /// - /// - /// - private void CultureChanged(ObservableValue sender, ValueChangedEventArgs e) + /// + /// + private void Current_PropertyChangedX(I18nHelper sender, PropertyChangedXEventArgs e) { - if (e.NewValue is null) - CurrentI18nData = null; - else if (I18nDatas.TryGetValue(e.NewValue, out var result)) - CurrentI18nData = result; - } - - /// - /// 添加文化 - /// - /// 文化名称 - private void AddCulture(string culture) - { - if (I18nDatas.ContainsKey(culture) is false) - I18nDatas.Add(culture, new()); - } - - /// - /// 删除文化 - /// - /// 文化名称 - private void RemoveCulture(string culture) - { - I18nDatas.Remove(culture); - } - - /// - /// 替换文化 - /// - /// 旧文化名称 - /// 新文化名称 - private void ReplaceCulture(string oldCulture, string newCulture) - { - var item = I18nDatas[oldCulture]; - I18nDatas.Remove(oldCulture); - I18nDatas.Add(newCulture, item); + if (e.PropertyName == nameof(I18nHelper.CultureName)) + { + if (e.NewValue is null) + CurrentI18nData = null!; + else if (I18nDatas.TryGetValue((string)e.NewValue, out var result)) + CurrentI18nData = result; + } } } diff --git a/VPet.ModMaker/Models/I18nModelBase.cs b/VPet.ModMaker/Models/I18nModelBase.cs deleted file mode 100644 index 8c5d69d..0000000 --- a/VPet.ModMaker/Models/I18nModelBase.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using HKW.HKWUtils.Observable; - -namespace VPet.ModMaker.Models; - -/// -/// I18n模型 -/// -/// 类型 -public class I18nModelBase : ObservableObjectX> - where T : class, new() -{ - /// - /// 当前I18n数据 - /// - #region CurrentI18nData - private T _currentI18nData = new(); - public T CurrentI18nData - { - get => _currentI18nData; - set => SetProperty(ref _currentI18nData, value); - } - #endregion - /// - /// 所有I18n数据 - /// - public Dictionary I18nDatas { get; } = new(); - - public I18nModelBase() - { - //TODO - //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) - I18nDatas.Add(item, new()); - CurrentI18nData = I18nDatas[I18nHelper.Current.CultureName]; - } - - /// - /// 文化改变 - /// - /// - /// - private void CultureChanged(ObservableValue sender, ValueChangedEventArgs e) - { - if (e.NewValue is null) - CurrentI18nData = null; - else if (I18nDatas.TryGetValue(e.NewValue, out var result)) - CurrentI18nData = result; - } - - /// - /// 添加文化 - /// - /// 文化名称 - private void AddCulture(string culture) - { - if (I18nDatas.ContainsKey(culture) is false) - I18nDatas.Add(culture, new()); - } - - /// - /// 删除文化 - /// - /// 文化名称 - private void RemoveCulture(string culture) - { - I18nDatas.Remove(culture); - } - - /// - /// 替换文化 - /// - /// 旧文化名称 - /// 新文化名称 - private void ReplaceCulture(string oldCulture, string newCulture) - { - var item = I18nDatas[oldCulture]; - I18nDatas.Remove(oldCulture); - I18nDatas.Add(newCulture, item); - } -} diff --git a/VPet.ModMaker/Models/ModModel/ClickTextModel.cs b/VPet.ModMaker/Models/ModModel/ClickTextModel.cs index e0af03c..eade19a 100644 --- a/VPet.ModMaker/Models/ModModel/ClickTextModel.cs +++ b/VPet.ModMaker/Models/ModModel/ClickTextModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Frozen; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; @@ -8,6 +9,7 @@ using System.Threading.Tasks; using HKW.HKWUtils; using HKW.HKWUtils.Observable; using LinePutScript.Converter; +using Mapster; using VPet_Simulator.Windows.Interface; namespace VPet.ModMaker.Models; @@ -17,35 +19,102 @@ namespace VPet.ModMaker.Models; /// public class ClickTextModel : I18nModel { + public ClickTextModel() { } + + public ClickTextModel(ClickTextModel clickText) + : this() + { + ID = clickText.ID; + Mode.Value = clickText.Mode.Value; + Working = clickText.Working; + WorkingState = clickText.WorkingState; + DayTime.Value = clickText.DayTime.Value; + Like = clickText.Like.Clone(); + Health = clickText.Health.Clone(); + Level = clickText.Level.Clone(); + Money = clickText.Money.Clone(); + Food = clickText.Food.Clone(); + Drink = clickText.Drink.Clone(); + Feel = clickText.Feel.Clone(); + Strength = clickText.Strength.Clone(); + foreach (var item in clickText.I18nDatas) + I18nDatas[item.Key] = item.Value.Clone(); + CurrentI18nData = I18nDatas[I18nHelper.Current.CultureName]; + } + + public ClickTextModel(ClickText clickText) + : this() + { + ID = clickText.Text; + Mode.Value = clickText.Mode; + Working = clickText.Working; + WorkingState = clickText.State; + DayTime.Value = clickText.DaiTime; + Like = new(clickText.LikeMin, clickText.LikeMax); + Health = new(clickText.HealthMin, clickText.HealthMax); + Level = new(clickText.LevelMin, clickText.LevelMax); + Money = new(clickText.MoneyMin, clickText.MoneyMax); + Food = new(clickText.FoodMin, clickText.FoodMax); + Drink = new(clickText.DrinkMin, clickText.DrinkMax); + Feel = new(clickText.FeelMin, clickText.FeelMax); + Strength = new(clickText.StrengthMin, clickText.StrengthMax); + } + + public ClickText ToClickText() + { + return new() + { + Text = ID, + Mode = Mode.Value, + Working = Working, + State = WorkingState, + DaiTime = DayTime.Value, + LikeMax = Like.Max, + LikeMin = Like.Min, + HealthMin = Health.Min, + HealthMax = Health.Max, + LevelMin = Level.Min, + LevelMax = Level.Max, + MoneyMin = Money.Min, + MoneyMax = Money.Max, + FoodMin = Food.Min, + FoodMax = Food.Max, + DrinkMin = Drink.Min, + DrinkMax = Drink.Max, + FeelMin = Feel.Min, + FeelMax = Feel.Max, + StrengthMin = Strength.Min, + StrengthMax = Strength.Max, + }; + } + /// /// 模式类型 /// - public static ObservableCollection ModeTypes { get; } = - new(Enum.GetValues(typeof(ClickText.ModeType)).Cast()); + public static FrozenSet ModeTypes { get; } = + Enum.GetValues().ToFrozenSet(); /// /// 日期区间 /// - public static ObservableCollection DayTimes { get; } = - new(Enum.GetValues(typeof(ClickText.DayTime)).Cast()); + public static FrozenSet DayTimes { get; } = + Enum.GetValues().ToFrozenSet(); /// /// 工作状态 /// - public static ObservableCollection WorkingStates { get; } = - new( - Enum.GetValues(typeof(VPet_Simulator.Core.Main.WorkingState)) - .Cast() - ); + public static FrozenSet WorkingStates { get; } = + Enum.GetValues().ToFrozenSet(); - #region Id + #region ID [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string _id = string.Empty; /// - /// Id + /// ID /// - public string Id + [AdaptMember(nameof(ClickText.Text))] + public string ID { get => _id; set => SetProperty(ref _id, value); @@ -59,6 +128,7 @@ public class ClickTextModel : I18nModel /// /// 指定工作 /// + [AdaptMember(nameof(ClickText.Working))] public string Working { get => _working; @@ -79,21 +149,23 @@ public class ClickTextModel : I18nModel #region WorkingState [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private VPet_Simulator.Core.Main.WorkingState _WorkingState; + private VPet_Simulator.Core.Main.WorkingState _workingState; /// /// 行动状态 /// + [AdaptMember(nameof(ClickText.State))] public VPet_Simulator.Core.Main.WorkingState WorkingState { - get => _WorkingState; - set => SetProperty(ref _WorkingState, value); + get => _workingState; + set => SetProperty(ref _workingState, value); } #endregion /// /// 日期区间 /// + public ObservableEnumCommand DayTime { get; } = new( ClickText.DayTime.Morning @@ -141,78 +213,11 @@ public class ClickTextModel : I18nModel /// 体力 /// public ObservableRange Strength { get; } = new(0, int.MaxValue); - - public ClickTextModel() { } - - public ClickTextModel(ClickTextModel clickText) - : this() - { - Id = clickText.Id; - Mode.Value = clickText.Mode.Value; - Working = clickText.Working; - WorkingState = clickText.WorkingState; - DayTime.Value = clickText.DayTime.Value; - Like = clickText.Like.Clone(); - Health = clickText.Health.Clone(); - Level = clickText.Level.Clone(); - Money = clickText.Money.Clone(); - Food = clickText.Food.Clone(); - Drink = clickText.Drink.Clone(); - Feel = clickText.Feel.Clone(); - Strength = clickText.Strength.Clone(); - foreach (var item in clickText.I18nDatas) - I18nDatas[item.Key] = item.Value.Copy(); - CurrentI18nData = I18nDatas[I18nHelper.Current.CultureName]; - } - - public ClickTextModel(ClickText clickText) - : this() - { - Id = clickText.Text; - Mode.Value = clickText.Mode; - Working = clickText.Working; - WorkingState = clickText.State; - DayTime.Value = clickText.DaiTime; - Like = new(clickText.LikeMin, clickText.LikeMax); - Health = new(clickText.HealthMin, clickText.HealthMax); - Level = new(clickText.LevelMin, clickText.LevelMax); - Money = new(clickText.MoneyMin, clickText.MoneyMax); - Food = new(clickText.FoodMin, clickText.FoodMax); - Drink = new(clickText.DrinkMin, clickText.DrinkMax); - Feel = new(clickText.FeelMin, clickText.FeelMax); - Strength = new(clickText.StrengthMin, clickText.StrengthMax); - } - - public ClickText ToClickText() - { - return new() - { - Text = Id, - Mode = Mode.Value, - Working = Working, - State = WorkingState, - DaiTime = DayTime.Value, - LikeMax = Like.Max, - LikeMin = Like.Min, - HealthMin = Health.Min, - HealthMax = Health.Max, - LevelMin = Level.Min, - LevelMax = Level.Max, - MoneyMin = Money.Min, - MoneyMax = Money.Max, - FoodMin = Food.Min, - FoodMax = Food.Max, - DrinkMin = Drink.Min, - DrinkMax = Drink.Max, - FeelMin = Feel.Min, - FeelMax = Feel.Max, - StrengthMin = Strength.Min, - StrengthMax = Strength.Max, - }; - } } -public class I18nClickTextModel : ObservableObjectX +public class I18nClickTextModel + : ObservableObjectX, + ICloneable { #region Text [DebuggerBrowsable(DebuggerBrowsableState.Never)] @@ -225,10 +230,10 @@ public class I18nClickTextModel : ObservableObjectX } #endregion - public I18nClickTextModel Copy() + public I18nClickTextModel Clone() { - var result = new I18nClickTextModel(); - result.Text = Text; - return result; + return this.Adapt(); } + + object ICloneable.Clone() => Clone(); } diff --git a/VPet.ModMaker/Models/ModModel/FoodLocationModel.cs b/VPet.ModMaker/Models/ModModel/FoodAnimeLocationModel.cs similarity index 87% rename from VPet.ModMaker/Models/ModModel/FoodLocationModel.cs rename to VPet.ModMaker/Models/ModModel/FoodAnimeLocationModel.cs index a5e5732..8a92e9e 100644 --- a/VPet.ModMaker/Models/ModModel/FoodLocationModel.cs +++ b/VPet.ModMaker/Models/ModModel/FoodAnimeLocationModel.cs @@ -9,9 +9,9 @@ using HKW.HKWUtils.Observable; namespace VPet.ModMaker.Models.ModModel; /// -/// 食物图像模型 +/// 食物图像位置模型 /// -public class FoodLocationModel : ObservableObjectX +public class FoodAnimeLocationModel : ObservableObjectX { #region Duration [DebuggerBrowsable(DebuggerBrowsableState.Never)] @@ -60,7 +60,7 @@ public class FoodLocationModel : ObservableObjectX } #endregion - public FoodLocationModel() + public FoodAnimeLocationModel() { Rect.PropertyChangedX += (s, e) => { @@ -68,9 +68,9 @@ public class FoodLocationModel : ObservableObjectX }; } - public FoodLocationModel Copy() + public FoodAnimeLocationModel Copy() { - var model = new FoodLocationModel(); + var model = new FoodAnimeLocationModel(); model.Duration = Duration; model.Rect = new(Rect.X, Rect.Y, Rect.Width, Rect.Height); model.Rotate = Rotate; diff --git a/VPet.ModMaker/Models/ModModel/FoodAnimeModel.cs b/VPet.ModMaker/Models/ModModel/FoodAnimeModel.cs index db1b95c..15ab9e7 100644 --- a/VPet.ModMaker/Models/ModModel/FoodAnimeModel.cs +++ b/VPet.ModMaker/Models/ModModel/FoodAnimeModel.cs @@ -41,7 +41,7 @@ public class FoodAnimeModel : ObservableObjectX /// /// 食物定位列表 /// - public ObservableCollection FoodLocations { get; } = new(); + public ObservableCollection FoodLocations { get; } = new(); public FoodAnimeModel() { } @@ -52,7 +52,7 @@ public class FoodAnimeModel : ObservableObjectX { //var index = int.Parse(item.Name.Substring(1)); var infos = item.Info.Split(','); - var foodLocationInfo = new FoodLocationModel(); + var foodLocationInfo = new FoodAnimeLocationModel(); foodLocationInfo.Duration = int.Parse(infos[0]); if (infos.Length > 1) { diff --git a/VPet.ModMaker/Models/ModModel/FoodModel.cs b/VPet.ModMaker/Models/ModModel/FoodModel.cs index a54c03e..5bf55bb 100644 --- a/VPet.ModMaker/Models/ModModel/FoodModel.cs +++ b/VPet.ModMaker/Models/ModModel/FoodModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Frozen; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; @@ -7,9 +8,12 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Media.Imaging; +using CommunityToolkit.Mvvm.Collections; +using CommunityToolkit.Mvvm.ComponentModel; using HKW.HKWUtils.Observable; using LinePutScript; using LinePutScript.Converter; +using Mapster; using VPet_Simulator.Windows.Interface; namespace VPet.ModMaker.Models; @@ -19,210 +23,9 @@ namespace VPet.ModMaker.Models; /// public class FoodModel : I18nModel { - /// - /// 食物类型 - /// - public static ObservableCollection FoodTypes { get; } = - new(Enum.GetValues(typeof(Food.FoodType)).Cast()); - - #region Id - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _id = string.Empty; - - /// - /// Id - /// - public string Id - { - get => _id; - set => SetProperty(ref _id, value); - } - #endregion - - #region DescriptionId - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _descriptionId = string.Empty; - - /// - /// 详情Id - /// - public string DescriptionId - { - get => _descriptionId; - set => SetProperty(ref _descriptionId, value); - } - #endregion - - #region Graph - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _graph = string.Empty; - - /// - /// 指定动画 - /// - public string Graph - { - get => _graph; - set => SetProperty(ref _graph, value); - } - #endregion - - #region Type - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private Food.FoodType _type; - - /// - /// 类型 - /// - public Food.FoodType Type - { - get => _type; - set => SetProperty(ref _type, value); - } - #endregion - - /// - /// 体力 - /// - #region Strength - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private double _Strength; - - public double Strength - { - get => _Strength; - set => SetProperty(ref _Strength, value); - } - #endregion - - /// - /// 饱食度 - /// - #region StrengthFood - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private double _StrengthFood; - - public double StrengthFood - { - get => _StrengthFood; - set => SetProperty(ref _StrengthFood, value); - } - #endregion - - /// - /// 口渴度 - /// - #region StrengthDrink - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private double _StrengthDrink; - - public double StrengthDrink - { - get => _StrengthDrink; - set => SetProperty(ref _StrengthDrink, value); - } - #endregion - - /// - /// 心情 - /// - #region Feeling - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private double _Feeling; - - public double Feeling - { - get => _Feeling; - set => SetProperty(ref _Feeling, value); - } - #endregion - - /// - /// 健康度 - /// - #region Health - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private double _Health; - - public double Health - { - get => _Health; - set => SetProperty(ref _Health, value); - } - #endregion - - /// - /// 好感度 - /// - #region Likability - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private double _Likability; - - public double Likability - { - get => _Likability; - set => SetProperty(ref _Likability, value); - } - #endregion - - /// - /// 价格 - /// - #region Price - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private double _Price; - - public double Price - { - get => _Price; - set => SetProperty(ref _Price, value); - } - #endregion - - /// - /// 经验 - /// - #region Exp - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private int _Exp; - - public int Exp - { - get => _Exp; - set => SetProperty(ref _Exp, value); - } - #endregion - - /// - /// 图片 - /// - #region Image - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private BitmapImage _Image; - - public BitmapImage Image - { - get => _Image; - set => SetProperty(ref _Image, value); - } - #endregion - - #region ReferencePrice - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private double _ReferencePrice; - - public double ReferencePrice - { - get => _ReferencePrice; - set => SetProperty(ref _ReferencePrice, value); - } - #endregion - - private readonly Food _food = new(); - public FoodModel() { - DescriptionId = $"{Id}_{nameof(DescriptionId)}"; + //DescriptionId = $"{Id}_{nameof(DescriptionId)}"; //TODO //Id.ValueChanged += (s, e) => //{ @@ -241,91 +44,310 @@ public class FoodModel : I18nModel //{ // s.Value = Math.Floor(SetValueToFood(_food).RealPrice); //}; + PropertyChangedX += FoodModel_PropertyChangedX; + } + + private static FrozenSet _notifyReferencePrice = FrozenSet.ToFrozenSet( + [ + nameof(Strength), + nameof(StrengthFood), + nameof(StrengthDrink), + nameof(Feeling), + nameof(Health), + nameof(Likability), + nameof(Exp) + ] + ); + + private void FoodModel_PropertyChangedX( + I18nModel sender, + PropertyChangedXEventArgs e + ) + { + if (e.PropertyName == nameof(ID)) + { + DescriptionID = $"{e.NewValue}_{nameof(DescriptionID)}"; + } + else if (_notifyReferencePrice.Contains(e.PropertyName)) + { + this.Adapt(_food); + ReferencePrice = Math.Floor(_food.RealPrice); + } } public FoodModel(FoodModel model) : this() { - Id = model.Id; - DescriptionId = model.DescriptionId; - Graph = model.Graph; - Type = model.Type; - Strength = model.Strength; - StrengthFood = model.StrengthFood; - StrengthDrink = model.StrengthDrink; - Feeling = model.Feeling; - Health = model.Health; - Likability = model.Likability; - Price = model.Price; - Exp = model.Exp; - Image = model.Image.Copy(); + model.Adapt(this); + Image = model.Image?.CloneStream(); foreach (var item in model.I18nDatas) - I18nDatas[item.Key] = item.Value.Copy(); + I18nDatas[item.Key] = item.Value.Clone(); CurrentI18nData = I18nDatas[I18nHelper.Current.CultureName]; } public FoodModel(Food food) : this() { - Id = food.Name; - DescriptionId = food.Desc; - Graph = food.Graph; - Type = food.Type; - Strength = food.Strength; - StrengthDrink = food.StrengthDrink; - StrengthFood = food.StrengthFood; - Feeling = food.Feeling; - Health = food.Health; - Likability = food.Likability; - Price = food.Price; - Exp = food.Exp; + food.Adapt(this); if (File.Exists(food.Image)) Image = NativeUtils.LoadImageToMemoryStream(food.Image); } + /// + /// 食物类型 + /// + public static ObservableCollection FoodTypes { get; } = + new(Enum.GetValues(typeof(Food.FoodType)).Cast()); + + #region ID + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string _id = string.Empty; + + /// + /// ID + /// + [AdaptMember(nameof(Food.Name))] + public string ID + { + get => _id; + set + { + if (SetProperty(ref _id, value) is false) + return; + DescriptionID = $"{ID}_{nameof(DescriptionID)}"; + } + } + #endregion + + #region DescriptionID + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string _descriptionID = string.Empty; + + /// + /// 详情Id + /// + [AdaptMember(nameof(Food.Desc))] + public string DescriptionID + { + get => _descriptionID; + set => SetProperty(ref _descriptionID, value); + } + #endregion + + #region Graph + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string _graph = string.Empty; + + /// + /// 指定动画 + /// + [AdaptMember(nameof(Food.Graph))] + public string Graph + { + get => _graph; + set => SetProperty(ref _graph, value); + } + #endregion + + #region Type + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private Food.FoodType _type; + + /// + /// 类型 + /// + [AdaptMember(nameof(Food.Type))] + public Food.FoodType Type + { + get => _type; + set => SetProperty(ref _type, value); + } + #endregion + + #region Strength + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private double _strength; + + /// + /// 体力 + /// + [AdaptMember(nameof(Food.Strength))] + public double Strength + { + get => _strength; + set => SetProperty(ref _strength, value); + } + #endregion + + #region StrengthFood + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private double _strengthFood; + + /// + /// 饱食度 + /// + [AdaptMember(nameof(Food.StrengthFood))] + public double StrengthFood + { + get => _strengthFood; + set => SetProperty(ref _strengthFood, value); + } + #endregion + + #region StrengthDrink + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private double _strengthDrink; + + /// + /// 口渴度 + /// + [AdaptMember(nameof(Food.StrengthDrink))] + public double StrengthDrink + { + get => _strengthDrink; + set => SetProperty(ref _strengthDrink, value); + } + #endregion + + #region Feeling + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private double _feeling; + + /// + /// 心情 + /// + [AdaptMember(nameof(Food.Feeling))] + public double Feeling + { + get => _feeling; + set => SetProperty(ref _feeling, value); + } + #endregion + + #region Health + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private double _health; + + /// + /// 健康度 + /// + [AdaptMember(nameof(Food.Health))] + public double Health + { + get => _health; + set => SetProperty(ref _health, value); + } + #endregion + + #region Likability + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private double _likability; + + /// + /// 好感度 + /// + [AdaptMember(nameof(Food.Likability))] + public double Likability + { + get => _likability; + set => SetProperty(ref _likability, value); + } + #endregion + + #region Price + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private double _price; + + /// + /// 价格 + /// + [AdaptMember(nameof(Food.Price))] + public double Price + { + get => _price; + set => SetProperty(ref _price, value); + } + #endregion + + #region Exp + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private int _exp; + + /// + /// 经验 + /// + [AdaptMember(nameof(Food.Exp))] + public int Exp + { + get => _exp; + set => SetProperty(ref _exp, value); + } + #endregion + + #region Image + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private BitmapImage? _image; + + /// + /// 图片 + /// + [AdaptIgnore] + public BitmapImage? Image + { + get => _image; + set => SetProperty(ref _image, value); + } + #endregion + + #region ReferencePrice + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private double _ReferencePrice; + + /// + /// 推荐价格 + /// + [AdaptIgnore] + public double ReferencePrice + { + get => _ReferencePrice; + set => SetProperty(ref _ReferencePrice, value); + } + #endregion + + private readonly Food _food = new(); + public Food ToFood() { - return new Food() - { - Name = Id, - Desc = DescriptionId, - Graph = Graph, - Type = Type, - Strength = Strength, - StrengthFood = StrengthFood, - StrengthDrink = StrengthDrink, - Feeling = Feeling, - Health = Health, - Likability = Likability, - Price = Price, - Exp = Exp, - }; - } - - public Food SetValueToFood(Food food) - { - food.Strength = Strength; - food.StrengthFood = StrengthFood; - food.StrengthDrink = StrengthDrink; - food.Feeling = Feeling; - food.Health = Health; - food.Likability = Likability; - food.Exp = Exp; - return food; + return this.Adapt(); + //return new Food() + //{ + // Name = ID, + // Desc = DescriptionID, + // Graph = Graph, + // Type = Type, + // Strength = Strength, + // StrengthFood = StrengthFood, + // StrengthDrink = StrengthDrink, + // Feeling = Feeling, + // Health = Health, + // Likability = Likability, + // Price = Price, + // Exp = Exp, + //}; } public void RefreshId() { - DescriptionId = $"{Id}_{nameof(DescriptionId)}"; + DescriptionID = $"{ID}_{nameof(DescriptionID)}"; } public void Close() { - Image.CloseStream(); + Image?.CloseStream(); } } -public class I18nFoodModel : ObservableObjectX +public class I18nFoodModel : ObservableObjectX, ICloneable { #region Name [DebuggerBrowsable(DebuggerBrowsableState.Never)] @@ -337,6 +359,7 @@ public class I18nFoodModel : ObservableObjectX set => SetProperty(ref _name, value); } #endregion + #region Description [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string _description = string.Empty; @@ -348,11 +371,7 @@ public class I18nFoodModel : ObservableObjectX } #endregion - public I18nFoodModel Copy() - { - var result = new I18nFoodModel(); - result.Name = Name; - result.Description = Description; - return result; - } + public I18nFoodModel Clone() => this.Adapt(); + + object ICloneable.Clone() => Clone(); } diff --git a/VPet.ModMaker/Models/ModModel/ImageModel.cs b/VPet.ModMaker/Models/ModModel/ImageModel.cs index 935ce25..87c74ae 100644 --- a/VPet.ModMaker/Models/ModModel/ImageModel.cs +++ b/VPet.ModMaker/Models/ModModel/ImageModel.cs @@ -51,7 +51,7 @@ public class ImageModel : ObservableObjectX public ImageModel Copy() { - var model = new ImageModel(Image.Copy(), Duration); + var model = new ImageModel(Image.CloneStream(), Duration); return model; } diff --git a/VPet.ModMaker/Models/ModModel/LowTextModel.cs b/VPet.ModMaker/Models/ModModel/LowTextModel.cs index 237e2ca..b267067 100644 --- a/VPet.ModMaker/Models/ModModel/LowTextModel.cs +++ b/VPet.ModMaker/Models/ModModel/LowTextModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Frozen; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; @@ -7,6 +8,7 @@ using System.Text; using System.Threading.Tasks; using System.Xml.Serialization; using HKW.HKWUtils.Observable; +using Mapster; using VPet_Simulator.Windows.Interface; namespace VPet.ModMaker.Models; @@ -16,32 +18,51 @@ namespace VPet.ModMaker.Models; /// public class LowTextModel : I18nModel { + public LowTextModel() { } + + public LowTextModel(LowTextModel lowText) + : this() + { + lowText.Adapt(this); + + foreach (var item in lowText.I18nDatas) + I18nDatas[item.Key] = item.Value.Clone(); + CurrentI18nData = I18nDatas[I18nHelper.Current.CultureName]; + } + + public LowTextModel(LowText lowText) + : this() + { + lowText.Adapt(this); + } + /// /// 状态类型 /// - public static ObservableCollection ModeTypes { get; } = - new(Enum.GetValues(typeof(LowText.ModeType)).Cast()); + public static FrozenSet ModeTypes { get; } = + Enum.GetValues().ToFrozenSet(); /// /// 好感度类型 /// - public static ObservableCollection LikeTypes { get; } = - new(Enum.GetValues(typeof(LowText.LikeType)).Cast()); + public static FrozenSet LikeTypes { get; } = + Enum.GetValues().ToFrozenSet(); /// /// 体力类型 /// - public static ObservableCollection StrengthTypes { get; } = - new(Enum.GetValues(typeof(LowText.StrengthType)).Cast()); + public static FrozenSet StrengthTypes { get; } = + Enum.GetValues().ToFrozenSet(); - #region Id + #region ID [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string _id = string.Empty; /// - /// Id + /// ID /// - public string Id + [AdaptMember(nameof(LowText.Text))] + public string ID { get => _id; set => SetProperty(ref _id, value); @@ -55,6 +76,7 @@ public class LowTextModel : I18nModel /// /// 状态 /// + [AdaptMember(nameof(LowText.Mode))] public LowText.ModeType Mode { get => _mode; @@ -69,6 +91,7 @@ public class LowTextModel : I18nModel /// /// 体力 /// + [AdaptMember(nameof(LowText.Strength))] public LowText.StrengthType Strength { get => _strength; @@ -83,7 +106,7 @@ public class LowTextModel : I18nModel /// /// 好感度 /// - + [AdaptMember(nameof(LowText.Like))] public LowText.LikeType Like { get => _like; @@ -91,45 +114,13 @@ public class LowTextModel : I18nModel } #endregion - public LowTextModel() { } - - public LowTextModel(LowTextModel lowText) - : this() - { - Id = lowText.Id; - Mode = lowText.Mode; - Strength = lowText.Strength; - Like = lowText.Like; - - foreach (var item in lowText.I18nDatas) - I18nDatas[item.Key] = item.Value.Copy(); - CurrentI18nData = I18nDatas[I18nHelper.Current.CultureName]; - } - - public LowTextModel(LowText lowText) - : this() - { - Id = lowText.Text; - Mode = lowText.Mode; - Strength = lowText.Strength; - Like = lowText.Like; - } - - public void Close() { } - public LowText ToLowText() { - return new() - { - Text = Id, - Mode = Mode, - Strength = Strength, - Like = Like, - }; + return this.Adapt(); } } -public class I18nLowTextModel : ObservableObjectX +public class I18nLowTextModel : ObservableObjectX, ICloneable { #region Text [DebuggerBrowsable(DebuggerBrowsableState.Never)] @@ -142,10 +133,10 @@ public class I18nLowTextModel : ObservableObjectX } #endregion - public I18nLowTextModel Copy() + public I18nLowTextModel Clone() { - var result = new I18nLowTextModel(); - result.Text = Text; - return result; + return this.Adapt(); } + + object ICloneable.Clone() => Clone(); } diff --git a/VPet.ModMaker/Models/ModModel/ModInfoModel.cs b/VPet.ModMaker/Models/ModModel/ModInfoModel.cs index 23e0773..cd7fe6c 100644 --- a/VPet.ModMaker/Models/ModModel/ModInfoModel.cs +++ b/VPet.ModMaker/Models/ModModel/ModInfoModel.cs @@ -450,9 +450,9 @@ public class ModInfoModel : I18nModel { if (food.I18nDatas.TryGetValue(key, out var data) is false) continue; - if (i18nData.TryGetValue(food.Id, out var name)) + if (i18nData.TryGetValue(food.ID, out var name)) data.Name = name; - if (i18nData.TryGetValue(food.DescriptionId, out var description)) + if (i18nData.TryGetValue(food.DescriptionID, out var description)) data.Description = description; } } @@ -463,7 +463,7 @@ public class ModInfoModel : I18nModel { if (lowText.I18nDatas.TryGetValue(key, out var data) is false) continue; - if (i18nData.TryGetValue(lowText.Id, out var text)) + if (i18nData.TryGetValue(lowText.ID, out var text)) data.Text = text; } } @@ -474,7 +474,7 @@ public class ModInfoModel : I18nModel { if (clickText.I18nDatas.TryGetValue(key, out var data) is false) continue; - if (i18nData.TryGetValue(clickText.Id, out var text)) + if (i18nData.TryGetValue(clickText.ID, out var text)) data.Text = text; } } @@ -485,9 +485,9 @@ public class ModInfoModel : I18nModel { if (selectText.I18nDatas.TryGetValue(key, out var data) is false) continue; - if (i18nData.TryGetValue(selectText.Id, out var text)) + if (i18nData.TryGetValue(selectText.ID, out var text)) data.Text = text; - if (i18nData.TryGetValue(selectText.ChooseId, out var choose)) + if (i18nData.TryGetValue(selectText.ChooseID, out var choose)) data.Choose = choose; } } @@ -519,7 +519,7 @@ public class ModInfoModel : I18nModel foreach (var food in Foods) food.RefreshId(); foreach (var selectText in SelectTexts) - selectText.RefreshId(); + selectText.RefreshID(); foreach (var pet in Pets) pet.RefreshId(); } @@ -635,9 +635,9 @@ public class ModInfoModel : I18nModel lps.Add(LPSConvert.SerializeObjectToLine(food.ToFood(), "food")); foreach (var cultureName in I18nHelper.Current.CultureNames) { - SaveI18nDatas[cultureName].TryAdd(food.Id, food.I18nDatas[cultureName].Name); + SaveI18nDatas[cultureName].TryAdd(food.ID, food.I18nDatas[cultureName].Name); SaveI18nDatas[cultureName] - .TryAdd(food.DescriptionId, food.I18nDatas[cultureName].Description); + .TryAdd(food.DescriptionID, food.I18nDatas[cultureName].Description); } } File.WriteAllText(foodFile, lps.ToString()); @@ -679,9 +679,9 @@ public class ModInfoModel : I18nModel lps.Add(LPSConvert.SerializeObjectToLine(text.ToSelectText(), "SelectText")); foreach (var cultureName in I18nHelper.Current.CultureNames) { - SaveI18nDatas[cultureName].TryAdd(text.Id, text.I18nDatas[cultureName].Text); + SaveI18nDatas[cultureName].TryAdd(text.ID, text.I18nDatas[cultureName].Text); SaveI18nDatas[cultureName] - .TryAdd(text.ChooseId, text.I18nDatas[cultureName].Choose); + .TryAdd(text.ChooseID, text.I18nDatas[cultureName].Choose); } } File.WriteAllText(textFile, lps.ToString()); @@ -703,7 +703,7 @@ public class ModInfoModel : I18nModel lps.Add(LPSConvert.SerializeObjectToLine(text.ToLowText(), "lowfoodtext")); foreach (var cultureName in I18nHelper.Current.CultureNames) { - SaveI18nDatas[cultureName].TryAdd(text.Id, text.I18nDatas[cultureName].Text); + SaveI18nDatas[cultureName].TryAdd(text.ID, text.I18nDatas[cultureName].Text); } } File.WriteAllText(textFile, lps.ToString()); @@ -725,7 +725,7 @@ public class ModInfoModel : I18nModel lps.Add(LPSConvert.SerializeObjectToLine(text.ToClickText(), "clicktext")); foreach (var cultureName in I18nHelper.Current.CultureNames) { - SaveI18nDatas[cultureName].TryAdd(text.Id, text.I18nDatas[cultureName].Text); + SaveI18nDatas[cultureName].TryAdd(text.ID, text.I18nDatas[cultureName].Text); } } File.WriteAllText(textFile, lps.ToString()); @@ -768,7 +768,7 @@ public class ModInfoModel : I18nModel Directory.CreateDirectory(foodPath); foreach (var food in Foods) { - food.Image.SaveToPng(Path.Combine(foodPath, food.Id)); + food.Image.SaveToPng(Path.Combine(foodPath, food.ID)); } } } diff --git a/VPet.ModMaker/Models/ModModel/SelectTextModel.cs b/VPet.ModMaker/Models/ModModel/SelectTextModel.cs index e6a1383..4a59ff0 100644 --- a/VPet.ModMaker/Models/ModModel/SelectTextModel.cs +++ b/VPet.ModMaker/Models/ModModel/SelectTextModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Frozen; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; @@ -6,6 +7,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using HKW.HKWUtils.Observable; +using Mapster; using VPet.ModMaker.Models; using VPet_Simulator.Windows.Interface; @@ -16,10 +18,53 @@ namespace VPet.ModMaker.Models; /// public class SelectTextModel : I18nModel { + public SelectTextModel() { } + + public SelectTextModel(SelectTextModel model) + : this() + { + //model.Adapt(this); + //Like.Min = -100; + ID = model.ID; + Mode.Value = model.Mode.Value; + Tags = model.Tags; + ToTags = model.ToTags; + Like = model.Like.Clone(); + Health = model.Health.Clone(); + Level = model.Level.Clone(); + Money = model.Money.Clone(); + Food = model.Food.Clone(); + Drink = model.Drink.Clone(); + Feel = model.Feel.Clone(); + Strength = model.Strength.Clone(); + + foreach (var item in model.I18nDatas) + I18nDatas[item.Key] = item.Value.Clone(); + CurrentI18nData = I18nDatas[I18nHelper.Current.CultureName]; + } + + public SelectTextModel(SelectText text) + : this() + { + ID = text.Text; + ChooseID = text.Choose ?? string.Empty; + Mode.Value = text.Mode; + Tags = text.Tags is null ? string.Empty : string.Join(", ", text.Tags); + ToTags = text.ToTags is null ? string.Empty : string.Join(", ", text.ToTags); + Like = new(text.LikeMin, text.LikeMax); + Health = new(text.HealthMin, text.HealthMax); + Level = new(text.LevelMin, text.LevelMax); + Money = new(text.MoneyMin, text.MoneyMax); + Food = new(text.FoodMin, text.FoodMax); + Drink = new(text.DrinkMin, text.DrinkMax); + Feel = new(text.FeelMin, text.FeelMax); + Strength = new(text.StrengthMin, text.StrengthMax); + } + /// /// 模式类型 /// - public static ObservableCollection ModeTypes => ClickTextModel.ModeTypes; + public static FrozenSet ModeTypes => ClickTextModel.ModeTypes; #region Tags [DebuggerBrowsable(DebuggerBrowsableState.Never)] @@ -49,17 +94,21 @@ public class SelectTextModel : I18nModel } #endregion - #region Id + #region ID [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string _id = string.Empty; /// - /// Id + /// ID /// - public string Id + public string ID { get => _id; - set => SetProperty(ref _id, value); + set + { + SetProperty(ref _id, value); + RefreshID(); + } } #endregion @@ -71,7 +120,7 @@ public class SelectTextModel : I18nModel /// 选择Id /// - public string ChooseId + public string ChooseID { get => _chooseId; set => SetProperty(ref _chooseId, value); @@ -129,68 +178,19 @@ public class SelectTextModel : I18nModel /// public ObservableRange Strength { get; } = new(0, int.MaxValue); - public SelectTextModel() + public void RefreshID() { - ChooseId = $"{Id}_{nameof(ChooseId)}"; - //TODO - //Id.ValueChanged += (s, e) => - //{ - // ChooseId.Value = $"{e.NewValue}_{nameof(ChooseId)}"; - //}; + ChooseID = $"{ID}_{nameof(ChooseID)}"; } - public SelectTextModel(SelectTextModel model) - : this() - { - Id = model.Id; - Mode.Value = model.Mode.Value; - Tags = model.Tags; - ToTags = model.ToTags; - Like = model.Like.Clone(); - Health = model.Health.Clone(); - Level = model.Level.Clone(); - Money = model.Money.Clone(); - Food = model.Food.Clone(); - Drink = model.Drink.Clone(); - Feel = model.Feel.Clone(); - Strength = model.Strength.Clone(); - - foreach (var item in model.I18nDatas) - I18nDatas[item.Key] = item.Value.Copy(); - CurrentI18nData = I18nDatas[I18nHelper.Current.CultureName]; - } - - public SelectTextModel(SelectText text) - : this() - { - Id = text.Text; - ChooseId = text.Choose ?? string.Empty; - Mode.Value = text.Mode; - Tags = text.Tags is null ? string.Empty : string.Join(", ", text.Tags); - ToTags = text.ToTags is null ? string.Empty : string.Join(", ", text.ToTags); - Like = new(text.LikeMin, text.LikeMax); - Health = new(text.HealthMin, text.HealthMax); - Level = new(text.LevelMin, text.LevelMax); - Money = new(text.MoneyMin, text.MoneyMax); - Food = new(text.FoodMin, text.FoodMax); - Drink = new(text.DrinkMin, text.DrinkMax); - Feel = new(text.FeelMin, text.FeelMax); - Strength = new(text.StrengthMin, text.StrengthMax); - } - - public void RefreshId() - { - ChooseId = $"{Id}_{nameof(ChooseId)}"; - } - - private static readonly char[] rs_splitChar = { ',', ' ' }; + private static readonly char[] rs_splitChar = [',', ' ']; public SelectText ToSelectText() { return new() { - Text = Id, - Choose = ChooseId, + Text = ID, + Choose = ChooseID, Mode = Mode.Value, Tags = new(Tags.Split(rs_splitChar, StringSplitOptions.RemoveEmptyEntries)), ToTags = new(ToTags.Split(rs_splitChar, StringSplitOptions.RemoveEmptyEntries)), @@ -214,7 +214,9 @@ public class SelectTextModel : I18nModel } } -public class I18nSelectTextModel : ObservableObjectX +public class I18nSelectTextModel + : ObservableObjectX, + ICloneable { #region Choose [DebuggerBrowsable(DebuggerBrowsableState.Never)] @@ -237,11 +239,10 @@ public class I18nSelectTextModel : ObservableObjectX } #endregion - public I18nSelectTextModel Copy() + public I18nSelectTextModel Clone() { - var result = new I18nSelectTextModel(); - result.Text = Text; - result.Choose = Choose; - return result; + return this.Adapt(); } + + object ICloneable.Clone() => Clone(); } diff --git a/VPet.ModMaker/Templates.xaml b/VPet.ModMaker/Templates.xaml index 43083a8..b1d1c71 100644 --- a/VPet.ModMaker/Templates.xaml +++ b/VPet.ModMaker/Templates.xaml @@ -2,7 +2,8 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ll="clr-namespace:LinePutScript.Localization.WPF;assembly=LinePutScript.Localization.WPF" - xmlns:pu="https://opensource.panuon.com/wpf-ui"> + xmlns:pu="https://opensource.panuon.com/wpf-ui" + xmlns:vm="clr-namespace:VPet.ModMaker.ViewModels.ModEdit"> + SelectedItem="{Binding I18nData.CultureName}">