ff14-mitigator/api/abilities.php
xziino 399e5fad93 Add analysis features: HP bars, death highlight, mitigation via buffs field, Event Explorer
- HP bar per player in AoE timeline (3-segment: remaining/damage/missing)
- Death highlight: red border + background when hp === 0
- Mitigation tracking refactored to read buffs field directly from damage events
  instead of separate applybuff/removebuff window tracking (simpler, more accurate)
- Mitigations are now per-target instead of per-event
- Add Magick Barrier to tracked mitigation abilities
- Player filter text input above AoE timeline
- Player cards as toggle buttons; tanks hidden by default; sorted Healer→DPS→Tank
- Fix Temperance double-display (dedup by name instead of abilityId)
- Event Explorer in Report tab: DataType, raw event type, ability, player dropdowns,
  limit, time range; abilities and players loaded on fight select
- Fight percentage display fix (was divided by 100 twice)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 14:58:10 +02:00

114 lines
3.5 KiB
PHP

<?php
ini_set('display_errors', '0');
require_once __DIR__ . '/../config.php';
session_start_safe();
header('Content-Type: application/json');
if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); echo json_encode(['error' => 'Method not allowed']); exit; }
if (empty($_SESSION['access_token'])) { echo json_encode(['reauth' => true]); exit; }
if (($_SESSION['token_expires'] ?? 0) <= time()) { echo json_encode(['reauth' => true]); exit; }
$reportCode = preg_replace('/[^a-zA-Z0-9]/', '', $_POST['report_code'] ?? '');
$fightId = (int)($_POST['fight_id'] ?? 0);
$startTime = (float)($_POST['start_time'] ?? 0);
$endTime = (float)($_POST['end_time'] ?? 0);
if (!$reportCode || !$fightId || !$endTime) { http_response_code(400); echo json_encode(['error' => 'Missing params']); exit; }
$token = $_SESSION['access_token'];
function ab_gql(string $query): array {
global $token;
$ch = curl_init(GRAPHQL_URI);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(['query' => $query]),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Authorization: Bearer ' . $token],
CURLOPT_SSL_VERIFYPEER => !DEV_MODE,
]);
$body = curl_exec($ch);
curl_close($ch);
return json_decode($body, true) ?? [];
}
// Fetch ability names from masterData
$mdResult = ab_gql(<<<GQL
{
reportData {
report(code: "$reportCode") {
playerDetails(fightIDs: [$fightId])
masterData {
abilities { gameID name }
}
}
}
}
GQL);
$abilityNames = [];
foreach ($mdResult['data']['reportData']['report']['masterData']['abilities'] ?? [] as $ab) {
$abilityNames[(int)$ab['gameID']] = $ab['name'];
}
// Build sorted player list
$pdRaw = $mdResult['data']['reportData']['report']['playerDetails'] ?? null;
$pdParsed = is_string($pdRaw) ? json_decode($pdRaw, true) : $pdRaw;
$pdGroups = $pdParsed['data']['playerDetails'] ?? [];
$players = [];
$roleMap = ['tanks' => 'tank', 'healers' => 'healer', 'dps' => 'dps'];
foreach ($roleMap as $group => $role) {
foreach ($pdGroups[$group] ?? [] as $p) {
$players[] = ['name' => $p['name'], 'role' => $role];
}
}
usort($players, fn($a, $b) => strcmp($a['name'], $b['name']));
// Fetch DamageTaken events from NPC sources only (paginated)
$filterEsc = 'source.type = \\"NPC\\"';
$seenIds = [];
$nextPage = $startTime;
for ($page = 0; $page < 10; $page++) {
$evResult = ab_gql(<<<GQL
{
reportData {
report(code: "$reportCode") {
events(
fightIDs: [$fightId],
dataType: DamageTaken,
startTime: $nextPage,
endTime: $endTime,
filterExpression: "$filterEsc"
) {
data
nextPageTimestamp
}
}
}
}
GQL);
$ev = $evResult['data']['reportData']['report']['events'] ?? [];
foreach ($ev['data'] ?? [] as $event) {
$abId = (int)($event['abilityGameID'] ?? 0);
if ($abId > 7) $seenIds[$abId] = true;
}
$nextPage = $ev['nextPageTimestamp'] ?? null;
if ($nextPage === null || $nextPage >= $endTime) break;
}
// Build sorted ability list
$abilities = [];
foreach (array_keys($seenIds) as $id) {
$abilities[] = [
'id' => $id,
'name' => $abilityNames[$id] ?? ('Ability #' . $id),
];
}
usort($abilities, fn($a, $b) => strcmp($a['name'], $b['name']));
echo json_encode(['abilities' => $abilities, 'players' => $players]);