Files
better-genshin-impact/BetterGenshinImpact/GameTask/GameLoading/GameLoading.cs
2025-07-31 14:10:41 +08:00

455 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BetterGenshinImpact.Core.Config;
using BetterGenshinImpact.GameTask.GameLoading.Assets;
using System;
using System.Diagnostics;
using BetterGenshinImpact.GameTask.Common;
using BetterGenshinImpact.GameTask.Common.BgiVision;
using BetterGenshinImpact.GameTask.Common.Element.Assets;
using BetterGenshinImpact.GameTask.Model.Area;
using Microsoft.Extensions.Logging;
using BetterGenshinImpact.Genshin.Paths;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Channels;
using Microsoft.Win32;
using System.Windows.Documents;
using System.Linq;
using System.Threading;
using System.Runtime.InteropServices;
using System.Text;
using BetterGenshinImpact.Core.Recognition.OpenCv;
using BetterGenshinImpact.Helpers.Extensions;
using Vanara.PInvoke;
namespace BetterGenshinImpact.GameTask.GameLoading;
public class GameLoadingTrigger : ITaskTrigger
{
public string Name => "自动开门";
public bool IsEnabled { get; set; }
public int Priority => 999;
public bool IsExclusive => false;
public bool IsBackgroundRunning => true;
private readonly GameLoadingAssets _assets;
private readonly GenshinStartConfig _config = TaskContext.Instance().Config.GenshinStartConfig;
private static ILogger<GameLoadingTrigger> _logger = App.GetLogger<GameLoadingTrigger>();
// private int _enterGameClickCount = 0;
// private int _welkinMoonClickCount = 0;
// private int _noneClickCount, _wmNoneClickCount;
private DateTime _prevExecuteTime = DateTime.MinValue;
private DateTime _triggerStartTime = DateTime.Now;
private string GameServer = "";
private string channelValue = "";
private string FileName = "";
private bool biliLoginClicked = false;
public GameLoadingTrigger()
{
GameLoadingAssets.DestroyInstance();
_assets = GameLoadingAssets.Instance;
}
public void Init()
{
IsEnabled = _config.AutoEnterGameEnabled;
// // 前面没有联动启动原神,这个任务也不用启动
// if ((DateTime.Now - TaskContext.Instance().LinkedStartGenshinTime).TotalMinutes >= 5)
// {
// IsEnabled = false;
// }
if (_config.RecordGameTimeEnabled)
{
FileName = Path.GetFileName(_config.InstallPath);
if (FileName == "GenshinImpact.exe")
{
GameServer = "hk4e_global";
StartStarward();
}
if (FileName == "YuanShen.exe")
{
string iniPath = Path.GetDirectoryName(_config.InstallPath) + "//config.ini";
string iniContent;
string pattern = @"
^\s*\[General\]\s*$
(?:(?!\[).|\r?\n)*
^\s*channel=(\S+)
";
try
{
iniContent = File.ReadAllText(iniPath);
Regex regex = new Regex(pattern,
RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase);
Match match = regex.Match(iniContent);
channelValue = match.Success ? match.Groups[1].Value : "";
}
catch (Exception e)
{
}
// channelValue = 1 官服
// channelValue = 14 B服
if (channelValue == "1")
{
GameServer = "hk4e_cn";
StartStarward();
}
if (channelValue == "14")
{
GameServer = "hk4e_bilibili";
StartStarward();
}
Debug.WriteLine($"[GameLoading] 从文件读取到游戏区服:{GameServer}");
// 这里注册表的优先级要比读取文件低因为使用starward安装原神不会写入注册表
if (GameServer == null)
{
GameServer = GetGameServerRegistry();
Debug.WriteLine($"[GameLoading] 从注册表读取到游戏区服:{GameServer}");
StartStarward();
}
}
}
}
public bool StartStarward()
{
try
{
Debug.WriteLine($"[GameLoading] 服务器:{GameServer}");
if (IsStarwardProtocolRegistered())
{
Process.Start(new ProcessStartInfo($"starward://playtime/{GameServer}") { UseShellExecute = true });
return true;
}
else
{
TaskControl.Logger.LogWarning("没有检测到 Starward 协议注册,请查看帮助文档!");
return false;
}
}
catch (Exception ex)
{
Debug.WriteLine("[GameLoading] Starward记录时间失败");
return false;
}
}
public string GetGameServerRegistry()
{
try
{
var cn =
Registry.GetValue($@"HKEY_CURRENT_USER\Software\miHoYo\HYP\1_1\hk4e_cn", "GameInstallPath",
null) as string;
if (!string.IsNullOrEmpty(cn))
{
var filePath = Path.Combine(cn, "YuanShen.exe");
GameServer = "hk4e_cn";
return GameServer;
}
var global = Registry.GetValue($@"HKEY_CURRENT_USER\Software\Cognosphere\HYP\1_0\hk4e_global",
"GameInstallPath", null) as string;
if (!string.IsNullOrEmpty(global))
{
var filePath = Path.Combine(global, "GenshinImpact.exe");
GameServer = "hk4e_global";
return GameServer;
}
var bilibili =
Registry.GetValue($@"HKEY_CURRENT_USER\Software\miHoYo\HYP\standalone\14_0\hk4e_cn\umfgRO5gh5\hk4e_cn",
"GameInstallPath", null) as string;
if (!string.IsNullOrEmpty(bilibili))
{
var filePath = Path.Combine(bilibili, "YuanShen.exe");
GameServer = "hk4e_bilibili";
return GameServer;
}
}
catch (Exception e)
{
TaskControl.Logger.LogDebug(e, "获取服务器失败");
}
return "";
}
public bool IsStarwardProtocolRegistered()
{
try
{
// 打开注册表路径 HKEY_CLASSES_ROOT\starward
using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("starward"))
{
// 如果键存在
if (key != null)
{
// 检查是否存在 URL Protocol 值
object urlProtocol = key.GetValue("URL Protocol");
// 如果 URL Protocol 存在且值为空字符串(标准配置),认为协议已注册
if (urlProtocol != null && urlProtocol.ToString() == "")
{
return true;
}
}
}
}
catch (Exception ex)
{
// 如果访问注册表时发生错误,记录调试信息
Debug.WriteLine($"[GameLoading] 检查 Starward 协议时发生错误: {ex.Message}");
}
// 如果键不存在或不符合条件,返回 false
return false;
}
public void OnCapture(CaptureContent content)
{
// 2s 一次
if ((DateTime.Now - _prevExecuteTime).TotalMilliseconds <= 2000)
{
return;
}
_prevExecuteTime = DateTime.Now;
// 5min 后自动停止
if ((DateTime.Now - _triggerStartTime).TotalMinutes >= 5)
{
IsEnabled = false;
return;
}
if (Bv.IsInMainUi(content.CaptureRectArea) || Bv.IsInAnyClosableUi(content.CaptureRectArea))
{
IsEnabled = false;
return;
}
// B服判断逻辑
bool isBili = false;
try
{
var exePath = _config.InstallPath;
if (!string.IsNullOrEmpty(exePath))
{
var configIni = Path.Combine(Path.GetDirectoryName(exePath)!, "config.ini");
if (File.Exists(configIni))
{
var lines = File.ReadAllLines(configIni);
foreach (var line in lines)
{
var kv = line.Trim();
if (kv.StartsWith("channel=") && kv.EndsWith("14"))
{
isBili = true;
break;
}
}
}
}
}
catch (Exception ex)
{
TaskControl.Logger.LogWarning("B服判断异常: " + ex.Message);
}
// 官服流程:先识别并点击顶号或切号的后一次“进入游戏”弹窗按钮
if (!isBili)
{
var extraEnterGameBtn = content.CaptureRectArea.Find(_assets.ChooseEnterGameRo);
if (!extraEnterGameBtn.IsEmpty())
{
extraEnterGameBtn.Click();
return;
}
}
// 官服流程:点击进入游戏按钮(作为外层包装)
using var ra = content.CaptureRectArea.Find(_assets.EnterGameRo);
if (!ra.IsEmpty())
{
if (isBili)
{
// B服流程处理登录窗口
if (!biliLoginClicked)
{
int failCount = 0;
while (true)
{
var process = Process.GetProcessesByName("YuanShen").FirstOrDefault();
var (loginWindow, windowType) = GetBiliLoginWindow(process);
if (process != null && loginWindow != IntPtr.Zero)
{
if (windowType.Contains("协议"))
{
// 点击协议窗口
GameCaptureRegion.GameRegion1080PPosClick(1000, 600);
Thread.Sleep(2000);
// 检查窗口是否还存在
var (remainingWindow, remainingType) = GetBiliLoginWindow(process);
if (remainingWindow == IntPtr.Zero || !remainingType.Contains("协议"))
{
// 协议窗口已消失,继续等待登录窗口
continue;
}
failCount++;
continue;
}
if (windowType.Contains("登录"))
{
// 点击登录窗口
GameCaptureRegion.GameRegion1080PPosClick(960, 630);
Thread.Sleep(2000);
// 检查窗口是否还存在
var (remainingWindow, remainingType) = GetBiliLoginWindow(process);
if (remainingWindow == IntPtr.Zero)
{
biliLoginClicked = true;
break; // 登录成功,跳出循环
}
failCount++;
continue;
}
}
if (failCount > 20)
{
break;
}
Thread.Sleep(500);
}
}
Thread.Sleep(5000);
ClickEnterGameButton();
}
else
{
// 官服流程:直接点击进入游戏按钮
ClickEnterGameButton();
}
return;
}
var wmRa = content.CaptureRectArea.Find(_assets.WelkinMoonRo);
if (!wmRa.IsEmpty())
{
TaskContext.Instance().PostMessageSimulator.LeftButtonClickBackground();
Debug.WriteLine("[GameLoading] Click blessing of the welkin moon");
// TaskControl.Logger.LogInformation("自动点击月卡");
return;
}
// 原石
var ysRa = content.CaptureRectArea.Find(ElementAssets.Instance.PrimogemRo);
if (!ysRa.IsEmpty())
{
GameCaptureRegion.GameRegion1080PPosMove(10, 10);
TaskContext.Instance().PostMessageSimulator.LeftButtonClickBackground();
Debug.WriteLine("[GameLoading] 跳过原石");
return;
}
}
// B服登录窗口检测(参考Login3rdParty)
private static (IntPtr windowHandle, string windowType) GetBiliLoginWindow(Process process)
{
IntPtr bHWnd = IntPtr.Zero;
string windowType = "";
User32.EnumWindows((hWnd, lParam) =>
{
try
{
// 获取窗口标题
int titleLength = User32.GetWindowTextLength(hWnd);
if (titleLength > 0)
{
StringBuilder title = new StringBuilder(titleLength + 1);
User32.GetWindowText(hWnd, title, title.Capacity);
string titleText = title.ToString();
// _logger.LogInformation($"窗口标题: {titleText}");
// 检查是否是B服登录窗口通过标题匹配
if (titleText.Contains("bilibili", StringComparison.OrdinalIgnoreCase))
{
// 检查窗口所有者是否是原神进程
var owner = User32.GetWindow(hWnd, User32.GetWindowCmd.GW_OWNER);
if (owner != IntPtr.Zero)
{
User32.GetWindowThreadProcessId(owner, out uint ownerPid);
if (ownerPid == process.Id)
{
// 检查窗口是否可见和启用
bool isVisible = User32.IsWindowVisible(hWnd);
bool isEnabled = User32.IsWindowEnabled(hWnd);
// 检查协议窗口
if (titleText.Contains("协议", StringComparison.OrdinalIgnoreCase))
{
if (isEnabled)
{
bHWnd = hWnd.DangerousGetHandle();
windowType = "协议";
return false;
}
}
// 检查登录窗口
if (titleText.Contains("登录", StringComparison.OrdinalIgnoreCase))
{
if (isEnabled)
{
bHWnd = hWnd.DangerousGetHandle();
windowType = "登录";
return false;
}
}
}
}
}
}
}
catch (Exception ex)
{
_logger.LogDebug($"枚举窗口时出错: {ex.Message}");
}
return true;
}, IntPtr.Zero);
return (bHWnd, windowType);
}
private void ClickEnterGameButton()
{
TaskContext.Instance().PostMessageSimulator.LeftButtonClickBackground();
}
};