mirror of
https://github.com/babalae/better-genshin-impact.git
synced 2026-05-17 09:26:50 +08:00
* 修改调度器任务和部分独立任务失去焦点时,强制切换回游戏窗口,如果用常规的方式无法激活窗口,则第10次会尝试最小化所有窗口后激活游戏。 * 去除未引入的类引用 * 修正战斗结束后,大概率打开队伍界面的问题 * 修复有些电脑上因未知原因,战斗0秒打断 * 把失焦激活放入了设置-通用设置-其他设置中,默认关闭。暂停恢复时,重置移动的起始时间,防止因暂停而导致超时放弃任务。 * 在调度器里面的任务之前,增加月卡处理,解决4点如果未进入任务会卡住的问题。增加了日志分析小怪详细。解决日志分析兜底结束日期不生效的问题。 * 在设置=》其他设置中 增加调度器任务传送过程中自动领取探索奖励功能配置。 * 调整自动派遣后恢复原任务的逻辑 * 自动领取派遣奖励时,跳过异常,防止整个配置组任务被打断。 * 把打开大地图方法从TpTask中抽出为公共方法,自动领取派遣代码调整到了调度器中。 * 去除了未使用的引用 * 暂停恢复逻辑增加恢复中条件和非空判断 * 增加了临时暂停自动拾取的逻辑(RunnerContext.AutoPickTriggerStopCount 为0时不限制,大于0时停止,多次暂停会累加该值,每次恢复-1),支持嵌套情况的暂停,在自动派遣(和结束后5秒)或暂停调度器任务时,同时暂停自动拾取功能。 * 调整暂停拾取方法 * 调整个日志输出 * 路径追踪复苏时,暂停拾取 * 增加根据点位配置,支持能在点位未识别情况下,使用大地图中心点的方式来定位,从而支持像铜锁小岛处这种小地图无法识别的点位。调整了对未识别点位的默认逻辑,未配置点位配置情况下,未识别点位,会取上一个识别的点位,从而支持在某些地方断续小地图能识别情况下的脚本。 * Changes * 修复暂停后,距离过远,小地图无法识别时,无限取当前一个坐标,导致无法正常恢复的问题。调度器管理增加了按天为单位的周期配置,适用于批量执行时,无需人工判断当天执行哪个任务。 * 调度器配置增加,或开启万叶拾取,并且不存在万叶,但配置了万叶队伍情况下,会切换队伍进行拾取。 * 调度器配置,增加了 只拾取精英掉落模式 ,根据编辑器点位配置,可设定非标记精英或传奇的点位跳过拾取。 * 解决卡换成复活形式的任务卡死 * 判断主界面时,复活界面返回false * 完全跳过的配置组,不发送通知。给周期配置增加说明。
244 lines
7.5 KiB
C#
244 lines
7.5 KiB
C#
using BetterGenshinImpact.GameTask.Common.Element.Assets;
|
||
using BetterGenshinImpact.GameTask.Model.Area;
|
||
using BetterGenshinImpact.GameTask.QuickTeleport.Assets;
|
||
using OpenCvSharp;
|
||
using System;
|
||
using System.Linq;
|
||
using System.Threading.Tasks;
|
||
using BetterGenshinImpact.Core.Recognition;
|
||
using System.Threading;
|
||
|
||
using BetterGenshinImpact.GameTask.AutoFight.Assets;
|
||
using BetterGenshinImpact.GameTask.AutoSkip.Assets;
|
||
using BetterGenshinImpact.GameTask.GameLoading.Assets;
|
||
|
||
|
||
namespace BetterGenshinImpact.GameTask.Common.BgiVision;
|
||
|
||
/// <summary>
|
||
/// 模仿OpenCv的静态类
|
||
/// 用于原神的各类识别与控制操作
|
||
///
|
||
/// 此处主要是对游戏内的一些状态进行识别
|
||
/// </summary>
|
||
public static partial class Bv
|
||
{
|
||
|
||
public static string WhichGameUi()
|
||
{
|
||
throw new NotImplementedException();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否在主界面
|
||
/// </summary>
|
||
/// <param name="captureRa"></param>
|
||
/// <returns></returns>
|
||
public static bool IsInMainUi(ImageRegion captureRa)
|
||
{
|
||
return captureRa.Find(ElementAssets.Instance.PaimonMenuRo).IsExist() && !IsInRevivePrompt(captureRa);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 等待主界面加载完成
|
||
/// </summary>
|
||
/// <param name="ct"></param>
|
||
/// <param name="retryTimes"></param>
|
||
/// <returns></returns>
|
||
public static async Task<bool> WaitForMainUi(CancellationToken ct, int retryTimes = 10)
|
||
{
|
||
for (var i = 0; i < retryTimes; i++)
|
||
{
|
||
await TaskControl.Delay(1000, ct);
|
||
using var ra3 = TaskControl.CaptureToRectArea();
|
||
if (IsInMainUi(ra3))
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在任意可以关闭的UI界面(识别关闭按钮)
|
||
/// </summary>
|
||
/// <param name="captureRa"></param>
|
||
/// <returns></returns>
|
||
public static bool IsInAnyClosableUi(ImageRegion captureRa)
|
||
{
|
||
return captureRa.Find(QuickTeleportAssets.Instance.MapCloseButtonRo).IsExist();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否在队伍选择界面
|
||
/// </summary>
|
||
/// <param name="captureRa"></param>
|
||
/// <returns></returns>
|
||
public static bool IsInPartyViewUi(ImageRegion captureRa)
|
||
{
|
||
return captureRa.Find(ElementAssets.Instance.PartyBtnChooseView).IsExist();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 等待队伍选择界面加载完成
|
||
/// </summary>
|
||
/// <param name="ct"></param>
|
||
/// <param name="retryTimes"></param>
|
||
/// <returns></returns>
|
||
public static async Task<bool> WaitForPartyViewUi(CancellationToken ct, int retryTimes = 5)
|
||
{
|
||
return await NewRetry.WaitForAction(() => IsInPartyViewUi(TaskControl.CaptureToRectArea()), ct, retryTimes);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否在大地图界面
|
||
/// </summary>
|
||
/// <param name="captureRa"></param>
|
||
/// <returns></returns>
|
||
public static bool IsInBigMapUi(ImageRegion captureRa)
|
||
{
|
||
return captureRa.Find(QuickTeleportAssets.Instance.MapScaleButtonRo).IsExist();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 大地图界面是否在地底
|
||
/// 鼠标悬浮在地下图标或者处于切换动画的时候可能会误识别
|
||
/// </summary>
|
||
/// <param name="captureRa"></param>
|
||
/// <returns></returns>
|
||
public static bool BigMapIsUnderground(ImageRegion captureRa)
|
||
{
|
||
return captureRa.Find(QuickTeleportAssets.Instance.MapUndergroundSwitchButtonRo).IsExist();
|
||
}
|
||
|
||
public static double GetBigMapScale(ImageRegion region)
|
||
{
|
||
var scaleRa = region.Find(QuickTeleportAssets.Instance.MapScaleButtonRo);
|
||
if (scaleRa.IsEmpty())
|
||
{
|
||
throw new Exception("当前未处于大地图界面,不能使用GetBigMapScale方法");
|
||
}
|
||
|
||
// 原先这里的起止区间和config里写死的值差1
|
||
var start = TaskContext.Instance().Config.TpConfig.ZoomStartY;
|
||
var end = TaskContext.Instance().Config.TpConfig.ZoomEndY;
|
||
var cur = (scaleRa.Y + scaleRa.Height / 2.0) * TaskContext.Instance().SystemInfo.ZoomOutMax1080PRatio; // 转换到1080p坐标系,主要是小于1080p的情况
|
||
|
||
return (end * 1.0 - cur) / (end - start);
|
||
}
|
||
|
||
public static MotionStatus GetMotionStatus(ImageRegion captureRa)
|
||
{
|
||
var spaceExist = captureRa.Find(ElementAssets.Instance.SpaceKey).IsExist();
|
||
var xExist = captureRa.Find(ElementAssets.Instance.XKey).IsExist();
|
||
if (spaceExist)
|
||
{
|
||
return xExist ? MotionStatus.Climb : MotionStatus.Fly;
|
||
}
|
||
else
|
||
{
|
||
return MotionStatus.Normal;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否出现复苏提示
|
||
/// </summary>
|
||
/// <param name="region"></param>
|
||
/// <returns></returns>
|
||
public static bool IsInRevivePrompt(ImageRegion region)
|
||
{
|
||
using var confirmRectArea = region.Find(AutoFightAssets.Instance.ConfirmRa);
|
||
if (!confirmRectArea.IsEmpty())
|
||
{
|
||
var list = region.FindMulti(new RecognitionObject
|
||
{
|
||
RecognitionType = RecognitionTypes.Ocr,
|
||
RegionOfInterest = new Rect(0, 0, region.Width, region.Height / 2)
|
||
});
|
||
if (list.Any(r => r.Text.Contains("复苏")))
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否出现全队死亡和复苏提示
|
||
/// </summary>
|
||
/// <param name="region"></param>
|
||
/// <returns></returns>
|
||
public static bool ClickIfInReviveModal(ImageRegion region)
|
||
{
|
||
var list = region.FindMulti(new RecognitionObject
|
||
{
|
||
RecognitionType = RecognitionTypes.Ocr,
|
||
RegionOfInterest = new Rect(0, region.Height / 4 * 3, region.Width, region.Height / 4)
|
||
});
|
||
var r = list.FirstOrDefault(r => r.Text.Contains("复苏"));
|
||
if (r != null)
|
||
{
|
||
r.Click();
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前角色是否低血量
|
||
/// </summary>
|
||
/// <param name="captureRa"></param>
|
||
/// <returns></returns>
|
||
public static bool CurrentAvatarIsLowHp(ImageRegion captureRa)
|
||
{
|
||
var assetScale = TaskContext.Instance().SystemInfo.AssetScale;
|
||
|
||
// 获取 (808, 1010) 位置的像素颜色
|
||
var pixelColor = captureRa.SrcMat.At<Vec3b>((int)(1010 * assetScale), (int)(808 * assetScale));
|
||
|
||
// 判断颜色是否是 (255, 90, 90)
|
||
return pixelColor is { Item2: 255, Item1: 90, Item0: 90 };
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在空月祝福界面
|
||
/// </summary>
|
||
/// <param name="captureRa"></param>
|
||
/// <returns></returns>
|
||
public static bool IsInBlessingOfTheWelkinMoon(ImageRegion captureRa)
|
||
{
|
||
return captureRa.Find(GameLoadingAssets.Instance.WelkinMoonRo).IsExist();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否在对话界面
|
||
/// </summary>
|
||
/// <param name="captureRa"></param>
|
||
/// <returns></returns>
|
||
public static bool IsInTalkUi(ImageRegion captureRa)
|
||
{
|
||
return captureRa.Find(AutoSkipAssets.Instance.DisabledUiButtonRo).IsExist();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 等到对话界面加载完成
|
||
/// </summary>
|
||
/// <param name="ct"></param>
|
||
/// <param name="retryTimes"></param>
|
||
/// <returns></returns>
|
||
public static async Task<bool> WaitAndSkipForTalkUi(CancellationToken ct, int retryTimes = 5)
|
||
{
|
||
return await NewRetry.WaitForAction(() => IsInTalkUi(TaskControl.CaptureToRectArea()), ct, retryTimes, 500);
|
||
}
|
||
}
|
||
|
||
public enum MotionStatus
|
||
{
|
||
Normal, // 正常
|
||
Fly, // 飞行
|
||
Climb, // 攀爬
|
||
} |