using System;
using System.Threading;
using System.Threading.Tasks;
using JXHelper.Config;
using JXHelper.Platform;
namespace JXHelper.Core;
///
/// Động cơ phục hồi sinh lực & nội lực (Recovery Engine - Học tập theo Tab P.hồi của AutoVLBS).
/// Chuyên trách: Bơm máu 2 mức, bơm mana 2 mức, chuông cảnh báo an toàn.
/// Tuân thủ nghiêm ngặt bất biến: INV-BG-INPUT-NO-HIJACK.
///
public class RecoveryEngine : IDisposable
{
private CancellationTokenSource? _cts;
private Task? _recoveryLoopTask;
private DateTime _lastHp1Time = DateTime.MinValue;
private DateTime _lastHp2Time = DateTime.MinValue;
private DateTime _lastMp1Time = DateTime.MinValue;
private DateTime _lastMp2Time = DateTime.MinValue;
private DateTime _lastNewbiePouchTime = DateTime.MinValue;
public bool IsRunning { get; private set; }
public bool IsPaused { get; set; }
public event Action? OnLog;
public void Start(IntPtr hWnd, BotConfig config)
{
if (IsRunning) return;
IsRunning = true;
IsPaused = false;
_cts = new CancellationTokenSource();
_recoveryLoopTask = Task.Run(() => RecoveryLoopAsync(hWnd, config, _cts.Token));
OnLog?.Invoke("[P.HỒI] Động cơ phục hồi máu/mana đã khởi động.");
}
public void Stop()
{
if (!IsRunning) return;
IsRunning = false;
IsPaused = false;
_cts?.Cancel();
try
{
_recoveryLoopTask?.Wait(500);
}
catch
{
// Bỏ qua lỗi hủy task
}
_cts?.Dispose();
_cts = null;
_recoveryLoopTask = null;
OnLog?.Invoke("[P.HỒI] Đã dừng động cơ phục hồi.");
}
private async Task RecoveryLoopAsync(IntPtr hWnd, BotConfig config, CancellationToken token)
{
while (!token.IsCancellationRequested)
{
try
{
if (!IsPaused)
{
DateTime now = DateTime.Now;
// 1. Bơm Sinh Lực mức 1
if (config.HpPump1Enabled && (now - _lastHp1Time).TotalMilliseconds >= config.HpPump1DelayMs)
{
await BackgroundInput.SendKeyAsync(hWnd, config.HpPump1Key);
_lastHp1Time = now;
}
// 2. Bơm Sinh Lực mức 2
if (config.HpPump2Enabled && (now - _lastHp2Time).TotalMilliseconds >= config.HpPump2DelayMs)
{
await BackgroundInput.SendKeyAsync(hWnd, config.HpPump2Key);
_lastHp2Time = now;
}
// 3. Bơm Nội Lực mức 1
if (config.MpPump1Enabled && (now - _lastMp1Time).TotalMilliseconds >= config.MpPump1DelayMs)
{
await BackgroundInput.SendKeyAsync(hWnd, config.MpPump1Key);
_lastMp1Time = now;
}
// 4. Bơm Nội Lực mức 2
if (config.MpPump2Enabled && (now - _lastMp2Time).TotalMilliseconds >= config.MpPump2DelayMs)
{
await BackgroundInput.SendKeyAsync(hWnd, config.MpPump2Key);
_lastMp2Time = now;
}
// 5. Tự động sử dụng Túi Máu Tân Thủ (Chuẩn Auto Kim Yến)
if (config.AutoNewbiePouchEnabled)
{
bool needPouch = false;
int intervalSec = Math.Max(15, config.NewbiePouchIntervalSeconds);
if ((now - _lastNewbiePouchTime).TotalSeconds >= intervalSec)
{
needPouch = true;
}
else if ((now - _lastNewbiePouchTime).TotalSeconds >= 10)
{
// Kiểm tra khẩn cấp qua RAM: HP tụt thấp < NewbiePouchEmergencyHpPercent
NativeMethods.GetWindowThreadProcessId(hWnd, out uint pid);
var stats = PlayerStatsReader.ReadLiveStats((int)pid);
if (stats != null && stats.MaxHp > 0 && stats.HpPercent < config.NewbiePouchEmergencyHpPercent)
{
needPouch = true;
OnLog?.Invoke($"[TÚI MÁU KHẨN CẤP] Sinh lực còn {stats.HpPercent:F1}% (< {config.NewbiePouchEmergencyHpPercent}%), kích hoạt bổ sung máu ngay!");
}
}
if (needPouch)
{
_lastNewbiePouchTime = now;
await ActionExecutor.ExecuteUseNewbiePouchAsync(hWnd, config, msg => OnLog?.Invoke(msg), token);
}
}
}
await Task.Delay(200, token);
}
catch (OperationCanceledException)
{
break;
}
catch (Exception ex)
{
OnLog?.Invoke($"[P.HỒI LỖI] {ex.Message}");
await Task.Delay(1000, token);
}
}
}
public static void PlayTdpAlarm()
{
try
{
System.Media.SystemSounds.Exclamation.Play();
}
catch
{
// Bỏ qua lỗi âm thanh nếu hệ thống tắt loa
}
}
public void Dispose()
{
Stop();
}
}