mirror of
https://github.com/babalae/better-genshin-impact.git
synced 2026-04-11 15:24:02 +08:00
243 lines
7.5 KiB
C#
243 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 BetterGenshinImpact.Core.Simulator;
|
||
using BetterGenshinImpact.GameTask.AutoFight;
|
||
using Vanara.PInvoke;
|
||
using System.Threading;
|
||
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();
|
||
}
|
||
|
||
/// <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方法");
|
||
}
|
||
|
||
// 452 ~ 627 间隔 35 和截图有关的,截图高24
|
||
var start = QuickTeleportAssets.MapScaleButton1080StartY;
|
||
var end = QuickTeleportAssets.MapScaleButton1080EndY;
|
||
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(AutoFightContext.Instance.FightAssets.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, // 攀爬
|
||
} |