------ #### V1.0.2404.1201 - 新增支持手动运行规则。 - 规则播放时间间隔不再针对全局声效,而只针对当前规则声效。 - 修复规则中播放文件夹可能导致无法执行的BUG。 - 修复规则不勾选礼物和点赞,则无法执行的BUG。
379 lines
20 KiB
C#
379 lines
20 KiB
C#
using CommunityToolkit.Mvvm.Messaging;
|
|
using LiveTools.Data;
|
|
using Newtonsoft.Json.Linq;
|
|
using ryCommon;
|
|
using System.Collections;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Data;
|
|
using System.Windows.Documents;
|
|
using System.Windows.Input;
|
|
using System.Windows.Interop;
|
|
using System.Windows.Media;
|
|
using System.Windows.Media.Animation;
|
|
using System.Windows.Media.Imaging;
|
|
using System.Windows.Navigation;
|
|
using System.Windows.Shapes;
|
|
|
|
namespace LiveTools
|
|
{
|
|
/// <summary>
|
|
/// Interaction logic for MainWindow.xaml
|
|
/// </summary>
|
|
public partial class FrmEffects : Window
|
|
{
|
|
public FrmEffects()
|
|
{
|
|
InitializeComponent();
|
|
cvsGround.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#00ff00"));
|
|
this.Background = cvsGround.Background;
|
|
}
|
|
public DirectInfo DirectInfo { get; set; } = new DirectInfo();
|
|
public BitmapImage GetImage(string path)
|
|
{
|
|
BitmapImage bi = new BitmapImage();
|
|
// BitmapImage.UriSource must be in a BeginInit/EndInit block.
|
|
bi.BeginInit();
|
|
bi.UriSource = new Uri(path, UriKind.RelativeOrAbsolute);
|
|
bi.EndInit();
|
|
return bi;
|
|
}
|
|
private void Button_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
List<BitmapImage> imgList = new List<BitmapImage>();
|
|
imgList.Add(GetImage("C:\\Users\\李凤鑫\\Desktop\\微信图片_20240329144830.png"));
|
|
imgList.Add(GetImage("C:\\Users\\李凤鑫\\Desktop\\微信图片_20240307182811.png"));
|
|
imgList.Add(GetImage("C:\\Users\\李凤鑫\\Desktop\\微信图片_20240329144727.png"));
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
Random rd2 = new Random(Guid.NewGuid().GetHashCode());
|
|
Image simpleImage = new Image();
|
|
simpleImage.Width = 50;
|
|
//Canvas.SetLeft(simpleImage, i * 300);
|
|
// Set the image source.
|
|
simpleImage.Source = imgList[rd2.Next(0,imgList.Count)];
|
|
cvsGround.Children.Add(simpleImage);
|
|
RotateTransform rotateTransform = new RotateTransform(rd2.Next(0,181));
|
|
simpleImage.RenderTransform = rotateTransform;
|
|
KK(simpleImage);
|
|
}
|
|
//KK(GroupboxArea);
|
|
//KK(GroupboxArea3);
|
|
|
|
}
|
|
void KK(Image grid)
|
|
{
|
|
var IsLandscape = false;//是否是横屏
|
|
Random rd = new Random(Guid.NewGuid().GetHashCode());
|
|
var endPos = new Point(this.Width / 2, this.Height / 2);
|
|
var mm = rd.Next(0, 4);
|
|
var startPos = new Point(0, rd.Next(0, 500));
|
|
|
|
switch (mm)
|
|
{
|
|
case 0://左边
|
|
startPos = new Point(0, rd.NextDouble() * this.Height);
|
|
break;
|
|
case 1://上边
|
|
startPos = new Point(this.Width * rd.NextDouble(), 0);
|
|
break;
|
|
case 2://右边
|
|
startPos = new Point(this.Width, rd.NextDouble() * this.Height);
|
|
break;
|
|
case 3://下边
|
|
startPos = new Point(rd.NextDouble() * this.Width, this.Height);
|
|
break;
|
|
}
|
|
var story = StartAnim(startPos, endPos);
|
|
story.Completed += delegate (object? sender2, EventArgs e2)
|
|
{
|
|
cvsGround.Children.Remove(grid);
|
|
};//完成后要做的事
|
|
story.Begin();
|
|
//story.RepeatBehavior = RepeatBehavior.Forever;//无限次循环,需要的自己加上
|
|
Storyboard StartAnim(Point startPos, Point endPos)
|
|
{
|
|
var Duration = rd.NextDouble() * 0.4;
|
|
// 创建两个DoubleAnimation来描述X和Y方向的移动
|
|
DoubleAnimation animX = new DoubleAnimation();
|
|
animX.From = startPos.X;//起点
|
|
animX.To = endPos.X; // 目标X坐标值
|
|
animX.Duration = TimeSpan.FromSeconds(Duration); // 动画持续时间
|
|
|
|
DoubleAnimation animY = new DoubleAnimation();
|
|
animY.From = startPos.Y; // 目标Y坐标值
|
|
animY.To = endPos.Y; // 目标Y坐标值
|
|
animY.Duration = TimeSpan.FromSeconds(Duration); // 动画持续时间
|
|
//
|
|
// 使用Storyboard来关联动画和物体
|
|
Storyboard.SetTarget(animX, grid);
|
|
Storyboard.SetTargetProperty(animX, new PropertyPath(Canvas.LeftProperty));
|
|
|
|
Storyboard.SetTarget(animY, grid);
|
|
Storyboard.SetTargetProperty(animY, new PropertyPath(Canvas.TopProperty));
|
|
Storyboard _story = new Storyboard();
|
|
_story.Children.Add(animX);
|
|
_story.Children.Add(animY);
|
|
//第二段动画
|
|
// 创建两个DoubleAnimation来描述X和Y方向的移动
|
|
//DoubleAnimation animX_end = new DoubleAnimation();
|
|
//animX_end.From = endPos.X;//起点
|
|
//animX_end.To = startPos.X; // 目标X坐标值
|
|
//animX_end.BeginTime = TimeSpan.FromSeconds(Duration);
|
|
//animX_end.Duration = TimeSpan.FromSeconds(1.5); // 动画持续时间
|
|
//PathGeometry pathGeometry = PathGeometry.CreateFromGeometry(Geometry.Parse("M "+ endPos.X+ ","+ endPos.Y+ " Q "+ (endPos.X+20)+ ","+ (endPos.Y+20)+ " "+ (endPos.X+10)+ ",0"));
|
|
// Y轴方向上的动画
|
|
//DoubleAnimationUsingPath animationY = new DoubleAnimationUsingPath
|
|
//{
|
|
// Source = PathAnimationSource.Y,
|
|
// BeginTime = TimeSpan.FromSeconds(Duration),
|
|
// Duration = TimeSpan.FromSeconds(Duration),
|
|
// PathGeometry = pathGeometry
|
|
//};
|
|
//DoubleAnimation animY_end = new DoubleAnimation();
|
|
//animY_end.From = endPos.Y; // 目标Y坐标值
|
|
//animY_end.To = this.Height; // 目标Y坐标值
|
|
//animY_end.BeginTime = TimeSpan.FromSeconds(Duration);
|
|
//animY_end.Duration = TimeSpan.FromSeconds(Duration); // 动画持续时间
|
|
//animY_end.AccelerationRatio = 0.6;
|
|
var offset = rd.Next(-200, 200);
|
|
var offset2 = offset > 0 ? offset + 200 : offset - 200;
|
|
var time = rd.NextDouble();
|
|
var xx = IsLandscape ? endPos.Y : endPos.X;
|
|
var yy = IsLandscape ? endPos.X : endPos.Y;
|
|
DoubleAnimationUsingKeyFrames animationX = new DoubleAnimationUsingKeyFrames();
|
|
animationX.BeginTime = TimeSpan.FromSeconds(Duration);
|
|
animationX.KeyFrames.Add(new LinearDoubleKeyFrame(xx, TimeSpan.FromSeconds(0))); // X from 0
|
|
animationX.KeyFrames.Add(new LinearDoubleKeyFrame(xx + offset, TimeSpan.FromSeconds(0.3))); // X to 50 in 1 second
|
|
animationX.KeyFrames.Add(new LinearDoubleKeyFrame(xx + offset2, TimeSpan.FromSeconds(time * 2))); // X to 100 in another 1 second
|
|
|
|
|
|
DoubleAnimationUsingKeyFrames animationY = new DoubleAnimationUsingKeyFrames();
|
|
animationY.BeginTime = TimeSpan.FromSeconds(Duration);
|
|
animationY.KeyFrames.Add(new EasingDoubleKeyFrame(yy, TimeSpan.FromSeconds(0), new QuadraticEase() { EasingMode = EasingMode.EaseOut })); // Y from 0
|
|
animationY.KeyFrames.Add(new EasingDoubleKeyFrame(yy - rd.Next(50, 200), TimeSpan.FromSeconds(0.3), new QuadraticEase() { EasingMode = EasingMode.EaseIn })); // Y to -50 in 1 second
|
|
animationY.KeyFrames.Add(new EasingDoubleKeyFrame(IsLandscape ? 0 : this.Height, TimeSpan.FromSeconds(time * 2), new BounceEase() { EasingMode = EasingMode.EaseOut })); // Y to 300 in another 1 second
|
|
Storyboard.SetTarget(animationX, grid);
|
|
Storyboard.SetTargetProperty(animationX, new PropertyPath(Canvas.LeftProperty));
|
|
Storyboard.SetTarget(animationY, grid);
|
|
Storyboard.SetTargetProperty(animationY, new PropertyPath(Canvas.TopProperty));
|
|
_story.Children.Add(animationX);
|
|
_story.Children.Add(animationY);
|
|
return _story;
|
|
}
|
|
}
|
|
private bool IsProcUse { get; set; } = false;
|
|
/// <summary>
|
|
/// 正在播放的列表
|
|
/// </summary>
|
|
Hashtable PlayingList { get; set; } = new Hashtable();
|
|
/// <summary>
|
|
/// 上一次播放时间
|
|
/// </summary>
|
|
Hashtable LastPlayTimeList { get; set; } = new Hashtable();
|
|
private void OnReceive(object recipient, MsgToken message)
|
|
{
|
|
if(message.Value is EffectInfo info)
|
|
{
|
|
if(message.Msg== "Close" && message.From == "Web")
|
|
{
|
|
IsProcUse = true;
|
|
this.Close();
|
|
return;
|
|
}
|
|
if ((info.ID == DirectInfo.Id || info.ID==0) && message.From=="Web")
|
|
{
|
|
///如果已经过期
|
|
if (Config.UserInfo.UserId.Length==0 || Config.UserInfo.OutTime<DateTime.Now.ToInt64() ||Config.UserInfo.isOut==1)
|
|
{
|
|
return;
|
|
}
|
|
if(info.ActionList!=null)
|
|
{
|
|
for (int a = 0; a < info.ActionList.Count; a++)
|
|
{
|
|
var action_item = (JObject)info.ActionList[a];
|
|
var name = action_item.GetJsonValue("Name","");
|
|
switch (name)
|
|
{
|
|
case "Rule_ShowPic":
|
|
ShowPic();
|
|
void ShowPic()
|
|
{
|
|
#region 砸图片
|
|
var PicPath = API.GetTruePath(action_item.GetJsonValue("PicPath", ""));
|
|
if (System.IO.File.Exists(PicPath))
|
|
{
|
|
for (int m = 0; m < info.LoopCount; m++)
|
|
{
|
|
var count = action_item.GetJsonValue("PicCount", 10);
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
Random rd2 = new Random(Guid.NewGuid().GetHashCode());
|
|
this.Dispatcher.Invoke(new Action(() =>
|
|
{
|
|
Image simpleImage = new Image();
|
|
simpleImage.Width = action_item.GetJsonValue("PicSize", 70);
|
|
//Canvas.SetLeft(simpleImage, i * 300);
|
|
// Set the image source.
|
|
simpleImage.Source = GetImage(PicPath);
|
|
cvsGround.Children.Add(simpleImage);
|
|
RotateTransform rotateTransform = new RotateTransform(rd2.Next(0, 181));
|
|
simpleImage.RenderTransform = rotateTransform;
|
|
KK(simpleImage);
|
|
}));
|
|
}
|
|
}
|
|
if (action_item.GetJsonValue("PlaySound", true))
|
|
{
|
|
var th = new Thread(StartPlay);
|
|
th.Start();
|
|
void StartPlay()
|
|
{
|
|
//var md5 = rySafe.MD5Sha1.GetMD5("AA|" +info.ID+"|"+ DateTime.Now + "|" + Guid.NewGuid());
|
|
if (System.IO.File.Exists(Config.SysDbFolder + "\\audio\\砸.mp3"))
|
|
{
|
|
Thread.Sleep(300);
|
|
LiveTools.SoundPlay sound = new LiveTools.SoundPlay
|
|
{
|
|
Volume = 100 / 100f
|
|
};
|
|
sound.Play(Config.SysDbFolder + "\\audio\\砸.mp3");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
break;
|
|
case "Rule_SoundPlay":
|
|
MSoundPlay();
|
|
void MSoundPlay()
|
|
{
|
|
if (!action_item.GetJsonValue("MultiPlaySound", false))
|
|
{
|
|
if (info.RuleID > 0)
|
|
{
|
|
if (IsPlaying) { return; }
|
|
if (PlayingList.Count > 0) { return; }
|
|
if (LastPlayTimeList.ContainsKey(info.RuleID))
|
|
{
|
|
var time= (DateTime)LastPlayTimeList[info.RuleID];
|
|
if (time >= DateTime.Now.AddSeconds(-action_item.GetJsonValue("PlaySoundInterval", 10)))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var th = new Thread(StartPlay);
|
|
th.Start();
|
|
void StartPlay()
|
|
{
|
|
IsPlaying = true;
|
|
var PlayCustomSound_Path =API.GetTruePath(action_item.GetJsonValue("PlayCustomSound_Path", ""));
|
|
var md5 = rySafe.MD5Sha1.GetMD5(PlayCustomSound_Path + "|" + DateTime.Now + "|" + Guid.NewGuid());
|
|
if (System.IO.File.Exists(PlayCustomSound_Path))
|
|
{
|
|
LiveTools.SoundPlay sound = new LiveTools.SoundPlay
|
|
{
|
|
Volume = action_item.GetJsonValue("Vol", 100) / 100f
|
|
};
|
|
PlayingList[md5]=sound;
|
|
sound.Play(PlayCustomSound_Path);
|
|
PlayingList.Remove(md5);
|
|
}
|
|
else if (System.IO.Directory.Exists(PlayCustomSound_Path))
|
|
{
|
|
var files = RyFiles.GetFiles(PlayCustomSound_Path, "*.mp3;*.wav;*.flac;*.wma");
|
|
if (files.Count > 0)
|
|
{
|
|
Random rd = new Random(Guid.NewGuid().GetHashCode());
|
|
LiveTools.SoundPlay sound = new LiveTools.SoundPlay
|
|
{
|
|
Volume = action_item.GetJsonValue("Vol", 100) / 100f
|
|
};
|
|
PlayingList[md5]= sound;
|
|
sound.Play(files[rd.Next(0, files.Count)]);
|
|
PlayingList.Remove(md5);
|
|
}
|
|
}
|
|
if (LastPlayTimeList.ContainsKey(info.RuleID))
|
|
{
|
|
LastPlayTimeList[info.RuleID] = DateTime.Now;
|
|
}
|
|
else
|
|
{
|
|
LastPlayTimeList[info.RuleID]= DateTime.Now;
|
|
}
|
|
IsPlaying = false;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
private DateTime LastPlayTime = DateTime.Now;
|
|
private bool IsPlaying =false;
|
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
|
{
|
|
//Title = DirectInfo.Name + "[" + DirectInfo.Platform + "]特效";
|
|
WeakReferenceMessenger.Default.Register<MsgToken>(this, OnReceive);
|
|
}
|
|
|
|
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
|
{
|
|
if (!IsProcUse)
|
|
{
|
|
if (HandyControl.Controls.MessageBox.Show("关闭特效窗口,将导致当前直播特效对应Web功能也同步关闭.\r\n是否确定要关闭?", "关闭确认", MessageBoxButton.OKCancel) != MessageBoxResult.OK)
|
|
{
|
|
e.Cancel = true;
|
|
}
|
|
else
|
|
{
|
|
EffectInfo effectInfo = new EffectInfo();
|
|
effectInfo.ID = DirectInfo.Id;
|
|
effectInfo.EffectMode = -1;
|
|
WeakReferenceMessenger.Default.Send<MsgToken>(new MsgToken(effectInfo) { ID = MsgTokenId.Effects, From = "Effects", Msg = "Close" });
|
|
}
|
|
}
|
|
try
|
|
{
|
|
foreach (var item in PlayingList.Values)
|
|
{
|
|
if (item is LiveTools.SoundPlay sound)
|
|
{
|
|
sound.Stop();
|
|
}
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 特效信息
|
|
/// </summary>
|
|
public class EffectInfo
|
|
{
|
|
public int ID { get; set; } = 0;
|
|
public int RuleID { get; set; } = 0;
|
|
/// <summary>
|
|
/// 事件类型,0表示发生特效,-1表示要关闭当前窗口。
|
|
/// </summary>
|
|
public int EffectMode { get; set; } = 0;
|
|
/// <summary>
|
|
/// 循环次数
|
|
/// </summary>
|
|
public int LoopCount { get; set; } = 1;
|
|
/// <summary>
|
|
/// 动作列表
|
|
/// </summary>
|
|
public JArray ActionList { get; set; } =null;
|
|
}
|
|
} |