动画系统支持外置

This commit is contained in:
ZouJin 2023-06-01 03:47:23 +10:00
parent 689f655403
commit 67b394055e
12 changed files with 530 additions and 93 deletions

View File

@ -80,20 +80,24 @@ namespace VPet_Simulator.Core
var ig = Core.Graph.FindGraph(GraphCore.GraphType.StartUP, core.Save.Mode);
//var ig2 = Core.Graph.FindGraph(GraphCore.GraphType.Default, core.GameSave.Mode);
PetGrid2.Visibility = Visibility.Collapsed;
ig.WaitForReadyRun(PetGrid, () =>
Task.Run(() =>
{
IsWorking = true;
Dispatcher.Invoke(() =>
while (!ig.IsReady)
{
PetGrid.Tag = ig;
PetGrid2.Tag = ig;
Thread.Sleep(100);
}
ig.Run(PetGrid, () =>
{
IsWorking = true;
Dispatcher.Invoke(() =>
{
PetGrid.Tag = ig;
PetGrid2.Tag = ig;
});
DisplayNomal();
});
DisplayNomal();
});
EventTimer.Elapsed += EventTimer_Elapsed;
MoveTimer.Elapsed += MoveTimer_Elapsed;
SmartMoveTimer.Elapsed += SmartMoveTimer_Elapsed;

View File

@ -101,13 +101,13 @@
<UniformGrid Columns="5" />
</ItemsPanelTemplate>
</Menu.ItemsPanel>
<MenuItem x:Name="MenuFeed" Header="投喂" HorizontalContentAlignment="Center" Width="99" Padding="0">
<MenuItem x:Name="MenuFeed" Header="投喂" HorizontalContentAlignment="Center" Padding="0">
<MenuItem Header="食物" HorizontalContentAlignment="Center" IsEnabled="False" />
<MenuItem Header="饮料" HorizontalContentAlignment="Center" IsEnabled="False" />
<MenuItem Header="药品" HorizontalContentAlignment="Center" IsEnabled="False" />
</MenuItem>
<MenuItem x:Name="MenuPanel" Header="面板" MouseEnter="MenuPanel_MouseEnter" MouseLeave="MenuPanel_MouseLeave"
HorizontalContentAlignment="Center" Width="99" Padding="0" />
HorizontalContentAlignment="Center" Padding="0" />
<MenuItem x:Name="MenuInteract" Header="互动" HorizontalContentAlignment="Center" Width="99" Padding="0">
<MenuItem Header="睡觉" HorizontalContentAlignment="Center" Click="Sleep_Click" />
<MenuItem Header="学习" HorizontalContentAlignment="Center" Click="Study_Click" />
@ -118,9 +118,9 @@
<MenuItem Header="说话" HorizontalContentAlignment="Center" IsEnabled="False" />
</MenuItem>
<MenuItem x:Name="MenuDIY" Header="自定" HorizontalContentAlignment="Center" Click="MenuDIY_Click"
x:FieldModifier="public" Width="99" Padding="0" />
x:FieldModifier="public" Padding="0" />
<MenuItem x:Name="MenuSetting" Header="系统" HorizontalContentAlignment="Center" x:FieldModifier="public"
Width="99" Padding="0" />
Padding="0" />
</Menu>
</Grid>
</UserControl>

View File

@ -0,0 +1,180 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using static System.Windows.Forms.AxHost;
using System.Windows.Media;
using static VPet_Simulator.Core.Picture;
namespace VPet_Simulator.Core
{
public class FoodAnimation : IGraph
{
/// <summary>
/// 前层名字
/// </summary>
public string Front_Lay;
/// <summary>
/// 后层名字
/// </summary>
public string Back_Lay;
/// <summary>
/// 所有动画帧
/// </summary>
public List<Animation> Animations;
/// <summary>
/// 当前动画播放状态
/// </summary>
public bool PlayState { get; set; } = false;
/// <summary>
/// 当前动画是否执行ENDACTION
/// </summary>
private bool DoEndAction = true;
/// <summary>
/// 是否循环播放
/// </summary>
public bool IsLoop { get; set; }
/// <summary>
/// 是否循环播放
/// </summary>
public bool IsContinue { get; set; } = false;
public GameSave.ModeType ModeType { get; private set; }
public GraphCore.GraphType GraphType { get; private set; }
/// <summary>
/// 是否准备完成
/// </summary>
public bool IsReady { get; private set; } = false;
/// <summary>
/// 动画停止时运行的方法
/// </summary>
private Action StopAction;
int nowid;
/// <summary>
/// 图片资源
/// </summary>
public string Path;
private GraphCore GraphCore;
/// <summary>
/// 单帧动画
/// </summary>
public class Animation
{
private FoodAnimation parent;
public Thickness MarginWI;
public double Rotate;
/// <summary>
/// 帧时间
/// </summary>
public int Time;
/// <summary>
/// 创建单帧动画
/// </summary>
/// <param name="parent">FoodAnimation</param>
/// <param name="time">持续时间</param>
/// <param name="wx"></param>
public Animation(FoodAnimation parent, int time, Thickness wx, double rotate)
{
this.parent = parent;
Time = time;
MarginWI = wx;
Rotate = rotate;
}
/// <summary>
/// 运行该图层
/// </summary>
public void Run(FrameworkElement This, Action EndAction = null)
{
//先显示该图层
This.Dispatcher.Invoke(() =>
{
This.Margin = MarginWI;
This.LayoutTransform = new RotateTransform(Rotate);
});
//然后等待帧时间毫秒
Thread.Sleep(Time);
//判断是否要下一步
if (parent.PlayState)
{
if (++parent.nowid >= parent.Animations.Count)
if (parent.IsLoop)
parent.nowid = 0;
else if (parent.IsContinue)
{
parent.IsContinue = false;
parent.nowid = 0;
}
else
{
//parent.endwilldo = () => parent.Dispatcher.Invoke(Hidden);
//parent.Dispatcher.Invoke(Hidden);
parent.PlayState = false;
if (parent.DoEndAction)
EndAction?.Invoke();//运行结束动画时事件
parent.StopAction?.Invoke();
parent.StopAction = null;
////延时隐藏
//Task.Run(() =>
//{
// Thread.Sleep(25);
// parent.Dispatcher.Invoke(Hidden);
//});
return;
}
//要下一步,现在就隐藏图层
//隐藏该图层
//parent.Dispatcher.Invoke(Hidden);
parent.Animations[parent.nowid].Run(This, EndAction);
return;
}
else
{
parent.IsContinue = false;
//parent.Dispatcher.Invoke(Hidden);
if (parent.DoEndAction)
EndAction?.Invoke();//运行结束动画时事件
parent.StopAction?.Invoke();
parent.StopAction = null;
//Task.Run(() =>
//{
// Thread.Sleep(25);
// parent.Dispatcher.Invoke(Hidden);
//});
}
}
}
public static FoodAnimatGrid FoodGrid = new FoodAnimatGrid();
public class FoodAnimatGrid : Grid
{
public FoodAnimatGrid()
{
Width = 500;
Height = 500;
Front = new Image();
Back = new Image();
Food = new Image();
Food.RenderTransformOrigin = new Point(0.5, 0.5);
this.Children.Add(Front);
this.Children.Add(Back);
}
public Image Front;
public Image Food;
public Image Back;
}
public void Run(Border parant, Action EndAction = null)
{
throw new NotImplementedException();
}
public void Stop(bool StopEndAction = false)
{
throw new NotImplementedException();
}
}
}

View File

@ -1,10 +0,0 @@
<UserControl x:Class="VPet_Simulator.Core.Graph.FoodAnimation"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" d:DesignHeight="500" d:DesignWidth="500">
<Grid>
</Grid>
</UserControl>

View File

@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace VPet_Simulator.Core.Graph
{
/// <summary>
/// FoodAnimation.xaml 的交互逻辑
/// </summary>
public partial class FoodAnimation : UserControl
{
public FoodAnimation()
{
InitializeComponent();
}
}
}

View File

@ -28,6 +28,10 @@ namespace VPet_Simulator.Core
/// </summary>
public enum GraphType
{
/// <summary>
/// 不被启用/使用的 不包含在GrapType
/// </summary>
Not_Able,
/// <summary>
/// 被提起动态 (循环)
/// </summary>
@ -316,6 +320,10 @@ namespace VPet_Simulator.Core
/// 口渴
/// </summary>
Switch_Thirsty,
/// <summary>
/// 吃东西
/// </summary>
Eat,
}
/// <summary>
@ -323,6 +331,10 @@ namespace VPet_Simulator.Core
/// </summary>
public Dictionary<GraphType, List<IGraph>> Graphs = new Dictionary<GraphType, List<IGraph>>();
/// <summary>
/// 图像字典(不被主要引用)
/// </summary>
public Dictionary<string, List<IGraph>> CommGraphs = new Dictionary<string, List<IGraph>>();
/// <summary>
/// 通用UI资源
/// </summary>
public Dictionary<string, UIElement> CommUIElements = new Dictionary<string, UIElement>();
@ -352,6 +364,24 @@ namespace VPet_Simulator.Core
Graphs[type].Add(graph);
}
/// <summary>
/// 添加动画
/// </summary>
/// <param name="graph">动画</param>
public void AddGraph(IGraph graph) => AddGraph(graph, graph.GraphType);
/// <summary>
/// 添加动画
/// </summary>
/// <param name="graph">动画</param>
/// <param name="type">类型</param>
public void AddCOMMGraph(IGraph graph, string Name)
{
if (!CommGraphs.ContainsKey(Name))
{
CommGraphs.Add(Name, new List<IGraph>());
}
CommGraphs[Name].Add(graph);
}
/// <summary>
/// 添加动画 自动创建
/// </summary>
/// <param name="path">位置</param>
@ -373,7 +403,7 @@ namespace VPet_Simulator.Core
/// 随机数字典(用于确保随机动画不会错位)
/// </summary>
public Dictionary<int, int> RndGraph = new Dictionary<int, int>();
/// <summary>
/// 查找动画
/// </summary>
@ -413,6 +443,45 @@ namespace VPet_Simulator.Core
}
return null;// FindGraph(GraphType.Default, mode);
}
/// <summary>
/// 查找动画
/// </summary>
/// <param name="type">动画类型</param>
/// <param name="mode">状态类型,找不到就找相同动画类型</param>
///// <param name="storernd">是否储存随机数字典</param>
public IGraph FindCOMMGraph(string Name, GameSave.ModeType mode)
{
if (CommGraphs.ContainsKey(Name))
{
var list = CommGraphs[Name].FindAll(x => x.ModeType == mode);
if (list.Count > 0)
{
if (list.Count == 1)
return list[0];
if (GraphConfig.StoreRnd.Contains(Name))
if (RndGraph.TryGetValue(list.Count, out int index))
{
return list[index];
}
else
{
index = Function.Rnd.Next(list.Count);
RndGraph.Add(list.Count, index);
return list[index];
}
else
return list[Function.Rnd.Next(list.Count)];
}
if (mode != GameSave.ModeType.Ill)
{
list = CommGraphs[Name].FindAll(x => x.ModeType != GameSave.ModeType.Ill);
if (list.Count > 0)
return list[Function.Rnd.Next(list.Count)];
}
}
return null;// FindGraph(GraphType.Default, mode);
}
static string[] graphtypevalue = null;
/// <summary>
/// 动画类型默认前文本

View File

@ -31,9 +31,13 @@ namespace VPet_Simulator.Core
/// </summary>
bool IsContinue { get; set; }
/// <summary>
/// 从0开始运行该动画, 等待部署完成后执行
/// 是否准备完成
/// </summary>
void WaitForReadyRun(Border parant, Action EndAction = null);
bool IsReady { get; }
///// <summary>
///// 从0开始运行该动画, 等待部署完成后执行
///// </summary>
//void WaitForReadyRun(Border parant, Action EndAction = null);
///// <summary>//经过测试,储存到内存好处多多,不储存也要占用很多内存,干脆存了吧
///// 是否储存到内存以支持快速显示
///// </summary>

View File

@ -22,13 +22,15 @@ using Panuon.WPF.UI;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TaskbarClock;
using System.Security.Policy;
using System.Runtime.InteropServices.ComTypes;
using static VPet_Simulator.Core.GraphCore;
using static VPet_Simulator.Core.Picture;
namespace VPet_Simulator.Core
{
/// <summary>
/// PNGAnimation.xaml 的交互逻辑
/// </summary>
public partial class PNGAnimation : IGraph
public partial class PNGAnimation : IGraph, IImageRun
{
/// <summary>
/// 所有动画帧
@ -155,6 +157,63 @@ namespace VPet_Simulator.Core
//}
}
public static void LoadGraph(GraphCore graph, FileSystemInfo path, ILine info)
{
if(!(path is DirectoryInfo p))
{
Picture.LoadGraph(graph, path, info);
return;
}
var paths = p.GetFiles();
GameSave.ModeType modetype;
var path_name = path.FullName.Trim('_').ToLower();
if (!Enum.TryParse(info[(gstr)"mode"], true, out modetype))
{
if (path_name.Contains("happy"))
{
modetype = GameSave.ModeType.Happy;
}
else if (path_name.Contains("nomal"))
{
modetype = GameSave.ModeType.Nomal;
}
else if (path_name.Contains("poorcondition"))
{
modetype = GameSave.ModeType.PoorCondition;
}
else if (path_name.Contains("ill"))
{
modetype = GameSave.ModeType.Ill;
}
else
{
modetype = GameSave.ModeType.Nomal;
}
}
GraphType graphtype = GraphType.Not_Able;
if (!Enum.TryParse(info[(gstr)"graph"], true, out graphtype))
{
for (int i = 0; i < GraphTypeValue.Length; i++)
{
if (path_name.StartsWith(GraphTypeValue[i]))
{
graphtype = (GraphType)i;
break;
}
}
}
bool isLoop = info[(gbol)"loop"];
PNGAnimation pa = new PNGAnimation(graph, path.FullName, paths, modetype, graphtype, isLoop);
if(graphtype == GraphType.Not_Able)
{
graph.AddCOMMGraph(pa, info.info);
}
else
{
graph.AddGraph(pa, graphtype);
}
}
public double Width;
private void startup(string path, FileInfo[] paths)
@ -348,24 +407,34 @@ namespace VPet_Simulator.Core
Task.Run(() => Animations[0].Run((System.Windows.Controls.Image)parant.Child, EndAction));
});
}
/// <summary>
/// 指定图像图像控件准备运行该动画
/// </summary>
/// <param name="img">用于显示的Image</param>
/// <param name="EndAction">结束动画</param>
/// <returns>准备好的线程</returns>
public Thread Run(System.Windows.Controls.Image img, Action EndAction = null)
{
nowid = 0;
PlayState = true;
DoEndAction = true;
return img.Dispatcher.Invoke(() =>
{
if (img.Tag == this)
{
return new Thread(() => Animations[0].Run(img, EndAction));
}
img.Tag = this;
img.Source = new BitmapImage(new Uri(Path));
img.Width = Width;
return new Thread(() => Animations[0].Run(img, EndAction));
});
}
public void Stop(bool StopEndAction = false)
{
DoEndAction = !StopEndAction;
PlayState = false;
//IsResetPlay = false;
}
public void WaitForReadyRun(Border parant, Action EndAction = null)
{
Task.Run(() =>
{
while (!IsReady)
{
Thread.Sleep(100);
}
Run(parant, EndAction);
});
}
}
}

View File

@ -9,13 +9,17 @@ using System.Windows;
using System.IO;
using System.Windows.Controls;
using System.Windows.Threading;
using LinePutScript;
using static VPet_Simulator.Core.GraphCore;
using static VPet_Simulator.Core.Picture;
using System.Security.Cryptography;
namespace VPet_Simulator.Core
{
/// <summary>
/// Picture.xaml 的交互逻辑
/// </summary>
public partial class Picture : IGraph
public partial class Picture : IGraph, IImageRun
{
/// <summary>
/// 新建新静态图像
@ -37,6 +41,67 @@ namespace VPet_Simulator.Core
GraphCore.CommUIElements["Image3.Picture"] = new Image() { Width = 500, Height = 500 };
}
}
public static void LoadGraph(GraphCore graph, FileSystemInfo path, ILine info)
{
if (!(path is FileInfo))
{
PNGAnimation.LoadGraph(graph, path, info);
return;
}
GameSave.ModeType modetype;
var path_name = path.FullName.Trim('_').ToLower();
if (!Enum.TryParse(info[(gstr)"mode"], true, out modetype))
{
if (path_name.Contains("happy"))
{
modetype = GameSave.ModeType.Happy;
}
else if (path_name.Contains("nomal"))
{
modetype = GameSave.ModeType.Nomal;
}
else if (path_name.Contains("poorcondition"))
{
modetype = GameSave.ModeType.PoorCondition;
}
else if (path_name.Contains("ill"))
{
modetype = GameSave.ModeType.Ill;
}
else
{
modetype = GameSave.ModeType.Nomal;
}
}
GraphType graphtype = GraphType.Not_Able;
if (!Enum.TryParse(info[(gstr)"graph"], true, out graphtype))
{
for (int i = 0; i < GraphTypeValue.Length; i++)
{
if (path_name.StartsWith(GraphTypeValue[i]))
{
graphtype = (GraphType)i;
break;
}
}
}
int length = info.GetInt("length");
if (length == 0)
{
if (!int.TryParse(path.Name.Split('.').Reverse().ToArray()[1].Split('_').Last(), out length))
length = 1000;
}
bool isLoop = info[(gbol)"loop"];
Picture pa = new Picture(graph, path.FullName, modetype, graphtype, length, isLoop);
if (graphtype == GraphType.Not_Able)
{
graph.AddCOMMGraph(pa, info.info);
}
else
{
graph.AddGraph(pa, graphtype);
}
}
/// <summary>
/// 图片资源
/// </summary>
@ -51,6 +116,8 @@ namespace VPet_Simulator.Core
public GraphCore.GraphType GraphType { get; set; }
public bool IsReady => true;
public void Run(Border parant, Action EndAction = null)
{
if (PlayState)
@ -93,8 +160,9 @@ namespace VPet_Simulator.Core
//bitmap.StreamSource = stream;
//bitmap.CacheOption = BitmapCacheOption.OnLoad;
//bitmap.EndInit();
img.Source = new BitmapImage(new Uri(Path));
parant.Tag = this;
img.Width = 500;
img.Source = new BitmapImage(new Uri(Path));
parant.Tag = this;
}
Task.Run(() =>
{
@ -118,7 +186,59 @@ namespace VPet_Simulator.Core
PlayState = false;
this.DoEndAction = !StopEndAction;
}
public void WaitForReadyRun(Border parant, Action EndAction = null) => Run(parant, EndAction);
public Thread Run(System.Windows.Controls.Image img, Action EndAction = null)
{
PlayState = true;
DoEndAction = true;
return img.Dispatcher.Invoke(() =>
{
if (img.Tag == this)
{
return new Thread(() =>
{
Thread.Sleep(Length);
if (IsLoop && PlayState)
{
Run(img, EndAction);
}
else
{
PlayState = false;
if (DoEndAction)
EndAction?.Invoke();//运行结束动画时事件
}
});
}
img.Tag = this;
img.Source = new BitmapImage(new Uri(Path));
img.Width = 500;
return new Thread(() =>
{
Thread.Sleep(Length);
if (IsLoop && PlayState)
{
Run(img, EndAction);
}
else
{
PlayState = false;
if (DoEndAction)
EndAction?.Invoke();//运行结束动画时事件
}
});
});
}
public interface IImageRun
{
/// <summary>
/// 指定图像图像控件准备运行该动画
/// </summary>
/// <param name="img">用于显示的Image</param>
/// <param name="EndAction">结束动画</param>
/// <returns>准备好的线程</returns>
Thread Run(System.Windows.Controls.Image img, Action EndAction = null);
}
}
}

View File

@ -1,10 +1,13 @@
using LinePutScript;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Threading;
using static VPet_Simulator.Core.GraphCore;
@ -46,11 +49,47 @@ namespace VPet_Simulator.Core
path.Add(directory.FullName + "\\" + lps.First()["path"].Info);
Config = new Config(lps);
}
public delegate void LoadGraphDelegate(GraphCore graph, FileSystemInfo path, ILine info);
/// <summary>
/// 自定义图片加载方法
/// </summary>
public static Dictionary<string, LoadGraphDelegate> IGraphConvert = new Dictionary<string, LoadGraphDelegate>()
{
{ "pnganimation", PNGAnimation.LoadGraph},
};
public static void LoadGraph(GraphCore graph, DirectoryInfo di, string path_name)
{
var list = di.EnumerateDirectories();
if (list.Count() == 0)
if (File.Exists(di.FullName + @"\info.lps"))
{
//如果自带描述信息,则手动加载
LpsDocument lps = new LpsDocument(File.ReadAllText(di.FullName + @"\info.lps"));
foreach (ILine line in lps)
{
if (IGraphConvert.TryGetValue(line.Name.ToLower(), out var func))
{
var str = line.GetString("path");
if (!string.IsNullOrEmpty(str))
{
var p = Path.Combine(di.FullName, str);
if(Directory.Exists(p))
func.Invoke(graph, new DirectoryInfo(p), line);
else if (File.Exists(p))
func.Invoke(graph, new FileInfo(p), line);
else
MessageBox.Show("未知的图像位置: " + p);
}
else
func.Invoke(graph, di, line);
}
else
{
MessageBox.Show("未知的图像类型: " + line.Name.ToLower());
}
}
}
else if (list.Count() == 0)
{
//自动加载 PNG ANMIN
path_name = path_name.Trim('_').ToLower();
@ -87,13 +126,9 @@ namespace VPet_Simulator.Core
}
}
#if DEBUG
//throw new Exception("未知的图像类型: " + path_name);
MessageBox.Show("未知的图像类型: " + path_name);
#endif
}
else if (File.Exists(di.FullName + @"\info.lps"))
{//如果自带描述信息,则手动加载
//TODO:
}
else
foreach (var p in list)
{

View File

@ -131,10 +131,6 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Graph\FoodAnimation.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Display\WorkTimer.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -149,9 +145,7 @@
<Compile Include="Display\ToolBar.xaml.cs">
<DependentUpon>ToolBar.xaml</DependentUpon>
</Compile>
<Compile Include="Graph\FoodAnimation.xaml.cs">
<DependentUpon>FoodAnimation.xaml</DependentUpon>
</Compile>
<Compile Include="Graph\FoodAnimation.cs" />
<Compile Include="Graph\GraphCore.cs" />
<Compile Include="Graph\EyeTracking.xaml.cs">
<DependentUpon>EyeTracking.xaml</DependentUpon>

View File

@ -327,12 +327,12 @@ namespace VPet_Simulator.Windows
}
else if (Set["SingleTips"].GetDateTime("update") <= new DateTime(2023, 5, 26))
{
// if (Set["SingleTips"].GetDateTime("update") <= new DateTime(2023, 3, 4))
// notifyIcon.ShowBalloonTip(10, "更新通知 05/26",
//"现已接入ChatGPT, 右键和桌宠说话吧.\n已根据steamID独立创建的聊天API,调教你独属的桌宠吧", ToolTipIcon.Info);
// else
notifyIcon.ShowBalloonTip(10, "更新通知 05/26",
"新增学习打工等互动,新增开心的默认状态\n新增语音插件,请在设置中MOD管理开启", ToolTipIcon.Info);
if (Set["SingleTips"].GetDateTime("update") <= new DateTime(2023, 3, 4))
notifyIcon.ShowBalloonTip(10, "更新通知 05/26",
"支持外置消息窗/时钟等窗口\n新增语音插件,请在设置中MOD管理开启", ToolTipIcon.Info);
else
notifyIcon.ShowBalloonTip(10, "更新通知 06/01",
"支持外置消息窗/时钟等窗口", ToolTipIcon.Info);
Set["SingleTips"].SetDateTime("update", DateTime.Now);
}
Save();