- 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>
114 lines
3.5 KiB
PHP
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]);
|