ff14-mitigator/CLAUDE.md
xziino d792d5b718 Initial commit: FFLogs mitigation analyzer
Two-tab app: report viewer + analysis tab with AoE timeline,
per-player mitigation icons (local XIVAPI PNGs), and fight-wide
buff/debuff window tracking.

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

8.7 KiB
Raw Blame History

ff14-mitigator — FFLogs Mitigation Analyzer

Projekt

PHP/HTML/JS-Tool zum Analysieren von FFXIV-Raidlogs via FFLogs OAuth2 PKCE + GraphQL API. Kein Framework, kein Composer, kein npm — Plain PHP für Shared Hosting.

Zwei Tabs:

  • Report-Tab: Report-Code eingeben, Fight auswählen, Raw-JSON-Ausgabe
  • Analyse-Tab: Spielerübersicht + AoE-Timeline mit Mitigation-Tracking

Architektur & Konventionen

Trennung von PHP, HTML und JS

  • PHP-Logik gehört ausschließlich in index.php (und API/Auth-Endpunkte). Keine Geschäftslogik in Templates.
  • HTML gehört in templates/. Jede logisch in sich geschlossene Komponente ist eine eigene Datei.
  • CSS gehört in css/. Jede CSS-Datei hat einen klar abgegrenzten Scope (base, layout, components, analysis).
  • JavaScript gehört in js/. Keine Inline-Scripts in Templates außer dem <script src="..."> Tag in page.php.

Template-System

index.php setzt alle Variablen und ruft dann require templates/page.php auf. Templates sind reine Ausgabe — sie lesen Variablen aus dem Scope, setzen aber keine.

Geteilter JS-State

window.App in app.js hält den gemeinsamen State für alle Tabs:

window.App = { reportCode, fightId, fightStart, fightEnd }

window.analysisTab (definiert in analysis.js) stellt Hooks bereit:

  • onFightSelected() — wird von app.js aufgerufen wenn ein Fight gewählt wird
  • onTabOpen() — wird von tabs.js aufgerufen wenn der Analyse-Tab geöffnet wird
  • reset() — wird von app.js aufgerufen wenn ein neuer Report geladen wird

Dateistruktur

index.php                   — PHP-Logik: Auth-Check, Variablen, require page.php
config.php                  — Konstanten (CLIENT_ID, URIs) + session_start_safe()
templates/
  page.php                  — HTML-Skeleton (head, body), routet zu login oder app
  login.php                 — Login-Overlay (nicht authentifiziert / Token abgelaufen)
  topbar.php                — Topbar mit Logo + Tab-Navigation + Token-Ablaufzeit
  tab-report.php            — Report-Tab: includes report-form, fight-select, output-card
  tab-analysis.php          — Analyse-Tab: Spieler-Grid + AoE-Timeline HTML
  report-form.php           — Report-Code-Eingabe Card
  fight-select.php          — Fight-Auswahl Dropdown Card
  output-card.php           — Terminal-Ausgabe Card + Initial-Hint
css/
  base.css                  — CSS-Variablen, Reset, Basis-Styles, Feedback-Klassen
  layout.css                — App-Shell, Topbar, Tabs, Login-Overlay, Form-Helpers
  components.css            — Cards, Inputs, Buttons, Badges, Terminal
  analysis.css              — Spieler-Grid, AoE-Timeline, Mitigation-Icons
js/
  app.js                    — Formular, Fight-Dropdown, Fetch, window.App State
  tabs.js                   — Tab-Switching, ruft window.analysisTab.onTabOpen() auf
  analysis.js               — Analyse-Tab: Daten laden, Spieler rendern, Timeline rendern
auth/
  start.php                 — PKCE generieren, Session speichern, Redirect zu FFLogs
  callback.php              — Code gegen Token tauschen, Token in Session speichern
api/
  fight.php                 — POST-Endpunkt: Fight-Liste via GraphQL → JSON
  analysis.php              — POST-Endpunkt: Spieler + AoE-Events + Mitigations → JSON
assets/
  icons/mitigation/         — Lokal gespeicherte Ability-Icons (PNG, von XIVAPI)
debug/
  schema.php                — Einmaliges Schema-Explorer Tool (nicht produktiv deployen)

Design-System

CSS-Variablen in css/base.css:

  • Hintergründe: --bg0 (#08090d) bis --bg3 (#1c2130), --bgcard (#121620)
  • Akzentfarbe: --gold (#c8a84b)
  • Text: --t1 (hell) / --t2 (gedimmt) / --t3 (sehr gedimmt)
  • Farben: --blue, --green, --red, --orange
  • Fonts: --font-d Cinzel (Titel/Logo), --font-b Inter (Body)
  • Border-Radius: --r (klein), --rl (groß)

Analyse-Tab — Konzepte & Entscheidungen

AoE-Erkennung

  • Nur calculateddamage Events (post-Mitigation Snapshot) — nicht damage (Application), da sonst doppelte Events
  • Gruppierung: 300ms-Zeitfenster × abilityGameID → Bucket
  • AoE = Bucket mit ≥ 3 unterschiedlichen targetIDs
  • Auto-Attacks und Fähigkeiten mit abilityGameID ≤ 7 werden gefiltert
  • Tick-Schaden (ev['tick'] = true) wird ignoriert

Spielernamen statt IDs

  • masterData.abilities (gameID → Name) wird zusammen mit playerDetails in einem einzigen Query abgerufen
  • $mitigIdMap (gameID → Mitigation-Meta) wird nur für Abilities gebaut, die tatsächlich im Report vorkommen

Mitigation-Tracking

Getrackte party-wide Buffs + Boss-Debuffs (definiert in MITIGATION_ABILITIES in api/analysis.php):

Ability DR Typ
Passage of Arms 15% buff
Divine Veil Barrier buff
Shake It Off Barrier buff
Dark Missionary 10% buff
Heart of Light 10% buff
Temperance 10% buff
Sacred Soil 10% buff
Expedient 10% buff
Fey Illumination 5% buff
Collective Unconscious 10% buff
Holos 10% buff
Kerachole 10% buff
Panhaima Barrier buff
Troubadour 15% buff
Tactician 15% buff
Shield Samba 15% buff
Reprisal 10% debuff
Feint 10% debuff
Addle 10% debuff

Fenster-Tracking: applybuff/applydebuff öffnet Fenster (nur erstes pro abilityId_sourceId-Key, da party-wide Buffs einmal pro Partymitglied feuern). removebuff/removedebuff schließt das Fenster. Noch offene Fenster am Fight-Ende werden mit endTime geschlossen.

Mitigation-Icons

  • Icons lokal gespeichert in assets/icons/mitigation/ als PNG
  • Quelle: XIVAPI v2 (https://v2.xivapi.com/api/asset?path=...&format=png)
  • Icon-Pfade per Action-Row-ID abgerufen: https://v2.xivapi.com/api/sheet/Action/{id}?fields=Name,Icon
  • Dateinamen: kebab-case des Ability-Namens (z.B. passage-of-arms.png)
  • Mapping in analysis.js: MITIG_ICONS Objekt (Ability-Name → lokaler Pfad)
  • Darstellung: 16×16px Icon unter jedem Spieler-Target, kein Text, title-Tooltip mit Name + DR% + Caster

Geplante Features

HP-Balken pro Spieler (nächstes Feature)

Für jeden Spieler in der AoE-Timeline einen 3-Segment-Balken anzeigen, der den HP-Stand im Kontext des Treffers zeigt:

[████████████▓▓▓░░░░░░░░]
 ^verbleibend  ^Schaden  ^vorher schon fehlend
  • Grün (links): HP nach dem Treffer (als % von MaxHP)
  • Rot/Orange (Mitte): erlittener Schaden (als % von MaxHP)
  • Dunkelgrau (rechts): HP die bereits vor dem Treffer fehlten
  • Grünton dynamisch: >50% grün, 2550% gelb/amber, <25% rot
  • Balken sitzt direkt unter Name+Schaden-Zeile in der Spieler-Box

Datenbedarf: FFLogs calculateddamage Events enthalten hitPoints (HP vor dem Treffer) und maxHitPoints. Diese müssen in api/analysis.php pro Target mitgegeben werden.

Backend-Änderung: In $buckets[$key]['targets'][$tgtId] zusätzlich hp und maxHp aus dem letzten Event speichern und in der Response durchreichen.

Konfiguration

  • config.php: CLIENT_ID, REDIRECT_URI, DEV_MODE anpassen
  • DEV_MODE = true deaktiviert SSL-Verifizierung (nur lokal, nie in Produktion)
  • session.cookie_secure ist bei DEV_MODE automatisch false

FFLogs API

  • OAuth2 PKCE (kein Client Secret, öffentliche App)
  • App registrieren: https://www.fflogs.com/api/clients/
  • GraphQL Endpoint (user-scoped): https://www.fflogs.com/api/v2/user
  • Token Endpoint: https://www.fflogs.com/oauth/token
  • Kein Refresh Token für öffentliche Clients — abgelaufene Sessions starten PKCE neu
  • Event-Typen: calculateddamage (Snapshot nach Mitigation, den wir nutzen) vs. damage (Application, ignorieren)

XIVAPI

  • Basis-URL: https://v2.xivapi.com
  • Action-Lookup per Row-ID: /api/sheet/Action/{id}?fields=Name,Icon
  • Asset-Download: /api/asset?path={tex_path}&format=png
  • Icons nicht hotlinken — lokal speichern (Community-Service, kein SLA)
  • XIVAPI-Suche (/api/search) gibt bei manchen Abilities ClassJob-Daten statt Action-Daten zurück → direkt per Row-ID abrufen

Repository

  • Remote: https://git.epow0.org/xziino/ff14-mitigator
  • Platform: Gitea (git.epow0.org)
  • Branch: main

Lokale Entwicklung

php -S localhost:8080

Dann http://localhost:8080 im Browser öffnen. Redirect URI in FFLogs App und config.php: http://localhost:8080/auth/callback.php

Bekannte Schema-Infos (ReportFight)

Verfügbare aber noch nicht genutzte Felder: friendlyPlayers, enemyNPCs, lastPhase, standardComposition, hasEcho, combatTime, phaseTransitions Vollständiges Schema: siehe debug/schema.php oder fflogs-schema.json

Deployment

  • DEV_MODE auf false setzen
  • REDIRECT_URI auf produktive HTTPS-URL anpassen
  • debug/ Ordner nicht deployen
  • assets/ Ordner deployen (enthält lokale Icons)