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();
}
}