Wechsel auf UNIT_COMBAT Engine (WoW Forever Beta Interface 16001)
- Entferne deaktiviertes COMBAT_LOG_EVENT_UNFILTERED - Implementiere UNIT_COMBAT mit Anti-Triplet Filter (unit == 'target') - Doppel-Auslösungs-Schutz bei Selbstheilung - Mapping von school auf lokalisierte Schadensschulen (SCHOOL_NAMES) - Parameter-Validierung mit issecretvalue - AGENT_GUIDE.md aktualisiert
This commit is contained in:
@@ -74,45 +74,71 @@ CritTrackerDB = {
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## 4. Logik- & Entscheidungsfluss (Core Engine)
|
||||
|
||||
### 4.1. Combat Log Filterung (`COMBAT_LOG_EVENT_UNFILTERED`)
|
||||
### 4.1. Warum `UNIT_COMBAT` statt `COMBAT_LOG_EVENT_UNFILTERED`? (Root Cause)
|
||||
Im "WoW Forever"-Client (Interface 16001 / 12.x Engine) ist die sogenannte Addon-Apokalypse aktiv:
|
||||
- `COMBAT_LOG_EVENT_UNFILTERED` wurde von Blizzard für Addons **vollständig deaktiviert** und feuert niemals.
|
||||
- Kritische Treffer und Heilungen müssen zwingend über das Event `UNIT_COMBAT` abgefangen werden.
|
||||
|
||||
Die Engine verwendet `CombatLogGetCurrentEventInfo()` mit folgenden Regeln:
|
||||
### 4.2. Filterregeln & Mehrfachauslösungs-Schutz
|
||||
`UNIT_COMBAT` feuert mit den Argumenten `(unit, action, modifier, amount, school)`.
|
||||
|
||||
1. **Source-Check:** Nur Events mit `sourceGUID == UnitGUID("player")` werden verarbeitet (Spieler-Treffer).
|
||||
2. **Sub-Events:**
|
||||
- **Schaden:** `SWING_DAMAGE`, `SPELL_DAMAGE`, `RANGE_DAMAGE`, `SPELL_PERIODIC_DAMAGE`, `SPELL_BUILDING_DAMAGE`.
|
||||
- Effektiver Schaden: `amount + absorbed` (Absorbe werden dem Treffer zugerechnet).
|
||||
- Bedingung: `critical == true`.
|
||||
- **Heilung:** `SPELL_HEAL`, `SPELL_PERIODIC_HEAL`, `SPELL_BUILDING_HEAL`.
|
||||
- Effektive Heilung: `amount + overhealing` (Overheal wird berücksichtigt, damit große Heiler-Crits bei voller HP nicht fälschlich als "Low Crit" eingestuft werden).
|
||||
- Bedingung: `critical == true`.
|
||||
1. **Forever Secret Values Schutz:**
|
||||
Parameter werden mit `issecretvalue(val)` geprüft. Handelt es sich um ein geschütztes Geheimnis oder `nil`, wird das Event verworfen.
|
||||
2. **Krit-Filter:**
|
||||
Nur Events mit `modifier == "CRITICAL"` und numerischem `amount > 0` werden akzeptiert.
|
||||
3. **Schaden-Filter (Crucial Anti-Triplet):**
|
||||
- Es wird ausschließlich `action == "WOUND"` und `unit == "target"` ausgewertet.
|
||||
- Alle Pseudo-Einheiten wie `nameplate*`, `softenemy` etc. werden verworfen, da der Client denselben Treffer sonst 3-fach meldet.
|
||||
4. **Heilung-Filter (Anti-Selfheal-Duplicate):**
|
||||
- Akzeptiert `action == "HEAL"` für `unit == "target"` oder `unit == "player"`.
|
||||
- Bei Selbstheilung mit sich selbst im Ziel (`UnitIsUnit("player", "target")`) wird die Auswertung auf `unit == "target"` beschränkt, um doppelte Auslösungen zu verhindern.
|
||||
5. **Schadensschulen-Mapping (`SCHOOL_NAMES`):**
|
||||
Da `UNIT_COMBAT` keine konkreten Zaubernamen liefert, wird das Argument `school` auf die jeweilige Schadensart gemappt:
|
||||
- `0` / `1` = Physisch / Physical
|
||||
- `2` = Heilig / Holy
|
||||
- `4` = Feuer / Fire
|
||||
- `8` = Natur / Nature
|
||||
- `16` = Frost / Frost
|
||||
- `32` = Schatten / Shadow
|
||||
- `64` = Arkan / Arcane
|
||||
|
||||
### 4.2. Ablaufdiagramm der Crit-Verarbeitung
|
||||
### 4.3. Ablaufdiagramm der Crit-Verarbeitung
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["Combat Log Crit Event (Player)"] --> B{"Addon aktiviert?"}
|
||||
A["Event: UNIT_COMBAT(unit, action, modifier, amount, school)"] --> B{"IsPublic? modifier == 'CRITICAL'?"}
|
||||
B -- Nein --> End[Abbruch]
|
||||
B -- Ja --> C["Hole bisherigen Rekord (Schaden/Heilung)"]
|
||||
B -- Ja --> C{"action & unit Check"}
|
||||
|
||||
C --> D{"amount > currentRecord?"}
|
||||
D -- Ja --> E["Neuer Rekord! Aktualisiere charData (maxRecord = amount)"]
|
||||
D -- Nein --> F{"enableLowCrit UND currentRecord > 0 UND amount <= (currentRecord * threshold)?"}
|
||||
C -- "WOUND & unit == 'target'" --> D["isDamage = true"]
|
||||
C -- "HEAL & (target oder player ohne Self-Duplicate)" --> E["isHeal = true"]
|
||||
C -- Andere Units/Actions --> End
|
||||
|
||||
F -- Ja --> G["Als Low-Crit markieren (Sound: low.mp3)"]
|
||||
F -- Nein --> H["Als normaler Crit markieren (Sound: critX / healX)"]
|
||||
D --> F["Löse school via SCHOOL_NAMES auf"]
|
||||
E --> F
|
||||
|
||||
E --> I{"GetTime() - lastOutputTime < cooldown?"}
|
||||
G --> I
|
||||
H --> I
|
||||
F --> G["Hole bisherigen Rekord (charData.maxDamage / maxHeal)"]
|
||||
G --> H{"amount > currentRecord?"}
|
||||
|
||||
I -- Ja (im Cooldown) --> J["Ausgabe unterdrückt (Anti-Spam)"]
|
||||
I -- Nein (Cooldown frei) --> K["lastOutputTime = GetTime()"]
|
||||
H -- Ja --> I["Neuer Rekord! Aktualisiere charData (maxRecord = amount)"]
|
||||
H -- Nein --> J{"enableLowCrit UND currentRecord > 0 UND amount <= threshold?"}
|
||||
|
||||
K --> L["PlaySoundFile(soundPath, soundChannel)"]
|
||||
K --> M["DEFAULT_CHAT_FRAME:AddMessage(formatierte Nachricht)"]
|
||||
J -- Ja --> K["Als Low-Crit markieren (Sound: low.mp3)"]
|
||||
J -- Nein --> L["Als normaler Crit markieren (Sound: critX / healX)"]
|
||||
|
||||
I --> M{"GetTime() - lastOutputTime < cooldown?"}
|
||||
K --> M
|
||||
L --> M
|
||||
|
||||
M -- Ja (im Cooldown) --> N["Ausgabe unterdrückt (Anti-Spam)"]
|
||||
M -- Nein (Cooldown frei) --> O["lastOutputTime = GetTime()"]
|
||||
|
||||
O --> P["PlaySoundFile(soundPath, soundChannel)"]
|
||||
O --> Q["DEFAULT_CHAT_FRAME:AddMessage(formatierte Nachricht)"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user