using System; using System.IO.MemoryMappedFiles; using System.Runtime.InteropServices; using JXHelper.Core; namespace JXHelper.Platform; [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct JxTelemetryData { public uint Magic; // 0x4A583031 ("JX01") public uint Version; // 1 public ulong SnapshotId; // Bộ đếm nhịp tick O(1) public ulong TimestampMs; // Unix timestamp mili-giây public int State; // BotState enum public int TargetHwnd; // Cửa sổ game đang điều khiển public int TargetPid; // PID tiến trình game public int CompletedCycles; // Số chu kỳ đã hoàn thành public int NextCountdownSeconds; // Số giây còn lại đến chu kỳ sau public int RepairItemX; // Tọa độ Túi Đồ Nghề public int RepairItemY; public int TravelItemX; // Tọa độ Thần Hành Phù public int TravelItemY; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string LastAction; // Hành động gần nhất } /// /// Cung cấp kênh chia sẻ RAM (Shared Memory IPC) giữa JXHelper và Dev/Supervisor. /// Tuân thủ bất biến: INV-SHM-TELEMETRY-SSOT. /// public class SharedMemoryBridge : IDisposable { public const string ShmName = "Local\\JX_Helper_SHM_v1"; public const uint JxMagic = 0x4A583031; private readonly MemoryMappedFile? _mmf; private readonly MemoryMappedViewAccessor? _accessor; private readonly int _structSize; private ulong _snapshotId; public SharedMemoryBridge() { _structSize = Marshal.SizeOf(); try { _mmf = MemoryMappedFile.CreateOrOpen(ShmName, _structSize); _accessor = _mmf.CreateViewAccessor(0, _structSize, MemoryMappedFileAccess.ReadWrite); } catch { // Fallback an toàn nếu không đủ quyền tạo SHM _mmf = null; _accessor = null; } } public void UpdateTelemetry( BotState state, IntPtr hWnd, int pid, int completedCycles, int countdownSec, int repairX, int repairY, int travelX, int travelY, string lastAction) { if (_accessor == null) return; var data = new JxTelemetryData { Magic = JxMagic, Version = 1, SnapshotId = ++_snapshotId, TimestampMs = (ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), State = (int)state, TargetHwnd = hWnd.ToInt32(), TargetPid = pid, CompletedCycles = completedCycles, NextCountdownSeconds = countdownSec, RepairItemX = repairX, RepairItemY = repairY, TravelItemX = travelX, TravelItemY = travelY, LastAction = lastAction.Length > 63 ? lastAction.Substring(0, 63) : lastAction }; try { _accessor.Write(0, ref data); } catch { // Non-blocking, cấm để lỗi SHM làm sập chu trình tự hành } } public void Dispose() { _accessor?.Dispose(); _mmf?.Dispose(); } }