Portrait Michael Malura

WoW Addon Entwicklung - Komplette Referenz

Link zum Projekt: GitHub - WoW Addons

Umfassende deutschsprachige Dokumentation für die World of Warcraft Addon-Entwicklung mit Fokus auf TBC/Classic.


Inhaltsverzeichnis

  1. Erste Schritte
  2. Addon-Struktur & TOC-Datei
  3. Lua Grundlagen
  4. Event-System
  5. Widget API - UI Elemente
  6. Häufige API-Funktionen
  7. Slash-Befehle
  8. SavedVariables - Persistente Daten
  9. XML UI Layout
  10. Secure Templates & Combat Lockdown
  11. TBC Classic Besonderheiten
  12. Ressourcen

Erste Schritte

Was du brauchst

  • Texteditor: VS Code, Notepad++, Sublime Text
  • WoW Client: Classic/TBC installiert
  • Grundkenntnisse: Keine Programmiererfahrung nötig

Addon-Speicherort

World of Warcraft\_classic_\Interface\AddOns\DeinAddonName\

Dein erstes Addon

1. Ordner erstellen: Interface\AddOns\HalloWelt\

2. TOC-Datei erstellen (HalloWelt.toc):

## Interface: 11508
## Title: Hallo Welt
## Notes: Mein erstes Addon!
## Author: DeinName
## Version: 1.0.0
HalloWelt.lua

3. Lua-Datei erstellen (HalloWelt.lua):

local frame = CreateFrame("Frame")
frame:RegisterEvent("PLAYER_LOGIN")
frame:SetScript("OnEvent", function(self, event)
    print("Hallo, Welt!")
end)

4. Addon laden: /reload im Spiel eingeben

Entwicklungswerkzeuge

| Befehl | Beschreibung | |--------|--------------| | /reload | UI neu laden | | /dump ausdruck | Lua-Ausdruck auswerten | | /etrace | Event-Trace-Fenster | | /fstack | Frame-Stack-Inspektor |


Addon-Struktur & TOC-Datei

Typische Ordnerstruktur

MeinAddon/
├── MeinAddon.toc        # Pflicht: Addon-Manifest
├── MeinAddon.lua        # Haupt-Code-Datei
├── Config.lua           # Einstellungen
├── embeds.xml           # Bibliotheks-Includes
├── libs/                # Externe Bibliotheken
└── Locales/             # Lokalisierung

TOC-Datei Format

## Interface: 11508
## Title: Mein Addon
## Notes: Beschreibung des Addons
## Author: Dein Name
## Version: 1.0.0
## SavedVariables: MeinAddonDB
## SavedVariablesPerCharacter: MeinAddonCharDB
## OptionalDeps: Ace3
embeds.xml
Core.lua
Config.lua

Wichtige TOC-Direktiven

| Direktive | Beschreibung | |-----------|--------------| | Interface | Client-Version | | Title | Anzeigename in der Addon-Liste | | Notes | Beschreibung als Tooltip | | SavedVariables | Account-weite gespeicherte Daten | | SavedVariablesPerCharacter | Pro-Charakter-Daten | | Dependencies | Benötigte Addons | | OptionalDeps | Optionale Abhängigkeiten | | LoadOnDemand | Bei Bedarf laden (1 = ja) |

Interface-Versionen

| Client | Version | |--------|---------| | Classic Era/Anniversary | 11508 | | TBC Classic | 20504 | | Wrath Classic | 30403 | | Cataclysm Classic | 40400 |

Aktuelle Version prüfen: /dump select(4, GetBuildInfo())


Lua Grundlagen

Variablen

-- Lokale Variable (bevorzugt)
local meinWert = "Hallo"
-- Globale Variable (vermeiden wenn möglich)
MeineGlobaleVar = "Welt"
-- Datentypen
local text = "String"           -- Text
local zahl = 100                -- Zahl
local dezimal = 0.75            -- Dezimalzahl
local aktiv = true              -- Boolean
local nichts = nil              -- Nil (kein Wert)
local tabelle = {1, 2, 3}       -- Array
local dict = {name = "Held"}    -- Dictionary

Operatoren

-- Arithmetik
local a = 10 + 5    -- 15
local b = 10 - 5    -- 5
local c = 10 * 5    -- 50
local d = 10 / 5    -- 2
local e = 10 % 3    -- 1 (Modulo)
-- Vergleich
a == b              -- gleich
a ~= b              -- ungleich (NICHT !=)
a < b               -- kleiner
a > b               -- größer
-- Logisch
true and false      -- false
true or false       -- true
not true            -- false
-- String-Verkettung
"Hallo" .. " " .. "Welt"  -- "Hallo Welt"

Kontrollstrukturen

-- If/Else
local leben = UnitHealth("player")
if leben > 50 then
    print("Alles gut")
elseif leben > 25 then
    print("Vorsicht!")
else
    print("Kritisch!")
end
-- Ternärer Stil (Lua-Idiom)
local status = (leben > 50) and "Gut" or "Schlecht"

Schleifen

-- For-Schleife (numerisch)
for i = 1, 10 do
    print(i)
end
-- For-Schleife (Array)
local items = {"Schwert", "Schild", "Trank"}
for index, item in ipairs(items) do
    print(index, item)
end
-- For-Schleife (Dictionary)
local stats = {staerke = 100, beweglichkeit = 50}
for key, value in pairs(stats) do
    print(key, value)
end
-- While-Schleife
local count = 0
while count < 5 do
    print(count)
    count = count + 1
end

Funktionen

-- Einfache Funktion
local function gruessen(name)
    print("Hallo, " .. name)
end
gruessen("Spieler")
-- Funktion mit Rückgabe
local function addieren(a, b)
    return a + b
end
local summe = addieren(5, 3)  -- 8
-- Mehrere Rückgabewerte
local function getSpielerInfo()
    return "Spielername", 60, "Krieger"
end
local name, level, klasse = getSpielerInfo()
-- Anonyme Funktion
frame:SetScript("OnClick", function(self, button)
    print("Geklickt mit:", button)
end)

Tabellen

-- Array (1-indiziert!)
local items = {"Schwert", "Schild"}
print(items[1])      -- "Schwert"
print(#items)        -- 2 (Länge)
table.insert(items, "Trank")
table.remove(items, 1)
-- Dictionary
local spieler = {
    name = "Held",
    level = 60,
    klasse = "Krieger"
}
print(spieler.name)       -- "Held"
print(spieler["level"])   -- 60
-- Tabelle als Objekt
local MeinAddon = {}
function MeinAddon:Initialisieren()
    self.aktiv = true
end
MeinAddon:Initialisieren()

Event-System

Grundlegendes Event-Handling

-- 1. Frame erstellen
local frame = CreateFrame("Frame")
-- 2. Events registrieren
frame:RegisterEvent("PLAYER_LOGIN")
frame:RegisterEvent("PLAYER_LOGOUT")
-- 3. Event-Handler setzen
frame:SetScript("OnEvent", function(self, event, ...)
    if event == "PLAYER_LOGIN" then
        print("Spieler eingeloggt!")
    elseif event == "PLAYER_LOGOUT" then
        print("Spieler loggt aus!")
    end
end)

Event-Handler Parameter

| Parameter | Beschreibung | |-----------|--------------| | self | Der empfangende Frame | | event | Event-Name (String) | | ... | Event-spezifische Argumente |

Event-Registrierung

frame:RegisterEvent("UNIT_HEALTH")
frame:UnregisterEvent("UNIT_HEALTH")
frame:UnregisterAllEvents()
-- Unit-spezifisches Event
frame:RegisterUnitEvent("UNIT_HEALTH", "player", "target")

Wichtige Events

Login/Logout:

| Event | Beschreibung | |-------|--------------| | PLAYER_LOGIN | Spieler vollständig eingeloggt | | PLAYER_LOGOUT | Spieler loggt aus | | PLAYER_ENTERING_WORLD | Ladebildschirm beendet | | ADDON_LOADED | Addon geladen (für SavedVariables) |

Kampf:

| Event | Beschreibung | |-------|--------------| | PLAYER_REGEN_DISABLED | Kampf beginnt | | PLAYER_REGEN_ENABLED | Kampf endet | | COMBAT_LOG_EVENT_UNFILTERED | Kampflog-Event | | PLAYER_DEAD | Spieler gestorben |

Einheiten:

| Event | Argumente | Beschreibung | |-------|-----------|--------------| | UNIT_HEALTH | unitId | Leben geändert | | UNIT_POWER_UPDATE | unitId, powerType | Kraft geändert | | UNIT_AURA | unitId | Buffs/Debuffs geändert | | UNIT_TARGET | unitId | Ziel geändert |

Gruppe:

| Event | Beschreibung | |-------|--------------| | GROUP_ROSTER_UPDATE | Gruppenzusammensetzung geändert | | PARTY_MEMBER_ENABLE | Gruppenmitglied online |

Dispatch-Table-Pattern

local frame = CreateFrame("Frame")
local events = {}
function events:PLAYER_LOGIN()
    print("Eingeloggt!")
end
function events:UNIT_HEALTH(unit)
    if unit == "player" then
        print("Leben:", UnitHealth("player"))
    end
end
frame:SetScript("OnEvent", function(self, event, ...)
    if events[event] then
        events[event](self, ...)
    end
end)
for event in pairs(events) do
    frame:RegisterEvent(event)
end

Widget API - UI Elemente

Frame erstellen

-- CreateFrame(frameType, name, parent, template)
local frame = CreateFrame("Frame", "MeinFrame", UIParent)
frame:SetSize(200, 100)
frame:SetPoint("CENTER")

Häufige Frame-Typen

| Typ | Beschreibung | |-----|--------------| | Frame | Basis-Container | | Button | Klickbarer Button | | CheckButton | Checkbox | | EditBox | Texteingabefeld | | ScrollFrame | Scrollbarer Bereich | | Slider | Schieberegler | | StatusBar | Fortschrittsbalken |

Größe und Position

frame:SetSize(200, 100)
frame:SetWidth(200)
frame:SetHeight(100)
-- Ankerpunkte: TOPLEFT, TOP, TOPRIGHT, LEFT, CENTER, RIGHT, BOTTOMLEFT, BOTTOM, BOTTOMRIGHT
frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
frame:SetPoint("TOPLEFT", parentFrame, "BOTTOMLEFT", 10, -5)
frame:ClearAllPoints()

Sichtbarkeit

frame:Show()
frame:Hide()
frame:SetShown(true)
local isShown = frame:IsShown()
local isVisible = frame:IsVisible()

Texturen erstellen

-- Einfarbige Textur
local texture = frame:CreateTexture(nil, "BACKGROUND")
texture:SetAllPoints(frame)
texture:SetColorTexture(0, 0, 0, 0.8)  -- RGBA
-- Bild-Textur
local icon = frame:CreateTexture(nil, "ARTWORK")
icon:SetSize(32, 32)
icon:SetPoint("LEFT", 5, 0)
icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")

FontStrings (Text)

local text = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
text:SetPoint("CENTER")
text:SetText("Hallo Welt")
text:SetTextColor(1, 1, 0)  -- Gelb

Buttons

local button = CreateFrame("Button", "MeinButton", UIParent, "UIPanelButtonTemplate")
button:SetSize(100, 25)
button:SetPoint("CENTER")
button:SetText("Klick mich")
button:SetScript("OnClick", function(self, mouseButton, down)
    print("Button geklickt mit:", mouseButton)
end)

StatusBar (Lebensbalken)

local bar = CreateFrame("StatusBar", nil, UIParent)
bar:SetSize(200, 20)
bar:SetPoint("CENTER")
bar:SetMinMaxValues(0, 100)
bar:SetValue(75)
bar:SetStatusBarTexture("Interface\\TargetingFrame\\UI-StatusBar")
bar:SetStatusBarColor(0, 1, 0)  -- Grün

Script-Handler

frame:SetScript("OnLoad", function(self) end)
frame:SetScript("OnShow", function(self) end)
frame:SetScript("OnHide", function(self) end)
frame:SetScript("OnUpdate", function(self, elapsed) end)
frame:SetScript("OnEvent", function(self, event, ...) end)
frame:SetScript("OnEnter", function(self) end)
frame:SetScript("OnLeave", function(self) end)
frame:SetScript("OnMouseDown", function(self, button) end)
frame:SetScript("OnMouseUp", function(self, button) end)

Häufige API-Funktionen

Unit IDs

| UnitId | Beschreibung | |--------|--------------| | player | Der Spieler | | target | Aktuelles Ziel | | focus | Fokus-Ziel | | pet | Begleiter | | party1-party4 | Gruppenmitglieder | | raid1-raid40 | Schlachtzugmitglieder | | mouseover | Einheit unter Mauszeiger | | targettarget | Ziel des Ziels |

Unit-Funktionen

-- Grundinfos
local name = UnitName("target")
local level = UnitLevel("target")
local class, classFile = UnitClass("target")  -- "Krieger", "WARRIOR"
local race = UnitRace("target")
local guid = UnitGUID("target")
-- Klassifikation
local classification = UnitClassification("target")
-- "normal", "elite", "rareelite", "rare", "worldboss"
-- Fraktion
local faction = UnitFactionGroup("target")  -- "Horde", "Alliance"
local isEnemy = UnitIsEnemy("player", "target")
local isFriend = UnitIsFriend("player", "target")
-- Existenz prüfen
local exists = UnitExists("target")
local isPlayer = UnitIsPlayer("target")
local isSameUnit = UnitIsUnit("player", "target")

Leben und Kraft

-- Leben
local health = UnitHealth("player")
local maxHealth = UnitHealthMax("player")
local healthPercent = (health / maxHealth) * 100
-- Kraft (Mana, Wut, Energie)
local power = UnitPower("player")
local maxPower = UnitPowerMax("player")
local powerType = UnitPowerType("player")
-- 0=Mana, 1=Wut, 2=Fokus, 3=Energie
-- Tot?
local isDead = UnitIsDead("target")
local isGhost = UnitIsGhost("player")

Buff/Debuff-Funktionen

-- Buff nach Name
local name, icon, count, debuffType, duration, expirationTime =
    UnitAura("player", "Segen der Macht", "HELPFUL")
-- Alle Buffs durchlaufen
for i = 1, 40 do
    local name, _, _, _, _, _, source, _, _, spellId =
        UnitAura("player", i, "HELPFUL")
    if not name then break end
    print(i, name, spellId)
end
-- Alle Debuffs durchlaufen
for i = 1, 40 do
    local name = UnitAura("player", i, "HARMFUL")
    if not name then break end
    print(i, name)
end

Zauber-Funktionen

local name, rank, icon, castTime, minRange, maxRange = GetSpellInfo(spellId)
local start, duration, enabled = GetSpellCooldown(spellId)
local remaining = (start + duration) - GetTime()
local isKnown = IsSpellKnown(spellId)

Item-Funktionen

local name, link, quality, ilvl, reqLevel, class, subclass,
      maxStack, equipSlot, texture, vendorPrice = GetItemInfo(itemId)
local count = GetItemCount(itemId)
local countMitBank = GetItemCount(itemId, true)

Chat-Funktionen

SendChatMessage("Hallo!", "SAY")
SendChatMessage("Gruppennachricht", "PARTY")
SendChatMessage("Schlachtzugnachricht", "RAID")
SendChatMessage("Flüstern", "WHISPER", nil, "Spielername")
SendChatMessage("Gildennachricht", "GUILD")
print("Nachricht")
DEFAULT_CHAT_FRAME:AddMessage("Rote Nachricht", 1, 0, 0)

Zeit-Funktionen

local time = GetTime()  -- Sekunden, hohe Präzision
local hours, minutes = GetGameTime()  -- Serverzeit
local formatted = date("%Y-%m-%d %H:%M:%S")

Gruppen-Funktionen

local numMembers = GetNumGroupMembers()
local inRaid = IsInRaid()
local inGroup = IsInGroup()
local name, rank, subgroup, level, class, fileName, zone,
      online, isDead, role, isML = GetRaidRosterInfo(i)

Slash-Befehle

Einfacher Slash-Befehl

SLASH_MEINADDON1 = "/meinaddon"
SLASH_MEINADDON2 = "/ma"
SlashCmdList["MEINADDON"] = function(msg, editBox)
    print("Befehl empfangen:", msg)
end

Argumente parsen

SLASH_MEINADDON1 = "/meinaddon"
SlashCmdList["MEINADDON"] = function(msg)
    msg = msg:lower()
    if msg == "" or msg == "hilfe" then
        print("Nutzung: /meinaddon [an|aus|config|status]")
    elseif msg == "an" then
        MeinAddon.aktiv = true
        print("MeinAddon aktiviert")
    elseif msg == "aus" then
        MeinAddon.aktiv = false
        print("MeinAddon deaktiviert")
    elseif msg == "config" then
        MeinAddon:OpenConfig()
    else
        print("Unbekannter Befehl:", msg)
    end
end

Mehrere Argumente

SlashCmdList["MEINADDON"] = function(msg)
    local befehl, arg1, arg2 = strsplit(" ", msg, 3)
    befehl = (befehl or ""):lower()
    if befehl == "setze" and arg1 == "lautstaerke" and arg2 then
        local wert = tonumber(arg2)
        if wert and wert >= 0 and wert <= 100 then
            MeinAddon.lautstaerke = wert
            print("Lautstärke auf", wert, "gesetzt")
        end
    end
end

SavedVariables - Persistente Daten

Grundeinrichtung

1. In TOC deklarieren:

## SavedVariables: MeinAddonDB
## SavedVariablesPerCharacter: MeinAddonCharDB

2. In Lua initialisieren:

local frame = CreateFrame("Frame")
frame:RegisterEvent("ADDON_LOADED")
frame:SetScript("OnEvent", function(self, event, addonName)
    if addonName == "MeinAddon" then
        MeinAddonDB = MeinAddonDB or {}
        MeinAddonDB.aktiv = MeinAddonDB.aktiv ~= false
        MeinAddonDB.lautstaerke = MeinAddonDB.lautstaerke or 50
        self:UnregisterEvent("ADDON_LOADED")
    end
end)

Speicherorte

| Typ | Pfad | |-----|------| | Account-weit | WTF\Account\NAME\SavedVariables\Addon.lua | | Pro-Charakter | WTF\Account\NAME\Realm\Char\SavedVariables\Addon.lua |

Standardwerte-Pattern

local defaults = {
    aktiv = true,
    lautstaerke = 50,
    position = {x = 0, y = 0}
}
local function InitializeDB()
    MeinAddonDB = MeinAddonDB or {}
    for key, value in pairs(defaults) do
        if MeinAddonDB[key] == nil then
            if type(value) == "table" then
                MeinAddonDB[key] = CopyTable(value)
            else
                MeinAddonDB[key] = value
            end
        end
    end
end

AceDB-3.0 (Empfohlen)

local MeinAddon = LibStub("AceAddon-3.0"):NewAddon("MeinAddon", "AceConsole-3.0")
local defaults = {
    profile = {
        aktiv = true,
        lautstaerke = 50,
    },
    char = {
        position = {x = 0, y = 0}
    }
}
function MeinAddon:OnInitialize()
    self.db = LibStub("AceDB-3.0"):New("MeinAddonDB", defaults, true)
    print(self.db.profile.aktiv)
    print(self.db.char.position.x)
end

Was gespeichert werden kann

| Unterstützt | Nicht unterstützt | |-------------|-------------------| | Strings | Funktionen | | Zahlen | Userdata (Frames) | | Booleans | Metatables | | Tabellen | | | nil | |


XML UI Layout

Basis-Struktur

<Ui xmlns="http://www.blizzard.com/wow/ui/">
    <Script file="Core.lua"/>
    <Include file="Frames.xml"/>
</Ui>

Frame-Definition

<Frame name="MeinFrame" parent="UIParent" enableMouse="true" movable="true">
    <Size x="200" y="100"/>
    <Anchors>
        <Anchor point="CENTER"/>
    </Anchors>
    <Layers>
        <Layer level="BACKGROUND">
            <Texture setAllPoints="true">
                <Color r="0" g="0" b="0" a="0.8"/>
            </Texture>
        </Layer>
        <Layer level="OVERLAY">
            <FontString name="$parentTitle" inherits="GameFontNormal">
                <Anchors><Anchor point="CENTER"/></Anchors>
            </FontString>
        </Layer>
    </Layers>
    <Scripts>
        <OnLoad>self:RegisterForDrag("LeftButton")</OnLoad>
        <OnDragStart>self:StartMoving()</OnDragStart>
        <OnDragStop>self:StopMovingOrSizing()</OnDragStop>
    </Scripts>
</Frame>

Layer-Ebenen

| Layer | Level | Beschreibung | |-------|-------|--------------| | BACKGROUND | 1 | Hintergrund | | BORDER | 2 | Rahmen | | ARTWORK | 3 | Hauptgrafik | | OVERLAY | 4 | Text, Icons | | HIGHLIGHT | 5 | Mouseover |

Button in XML

<Button name="MeinButton" inherits="UIPanelButtonTemplate" text="Klick">
    <Size x="100" y="25"/>
    <Anchors><Anchor point="CENTER"/></Anchors>
    <Scripts>
        <OnClick>print("Geklickt!")</OnClick>
    </Scripts>
</Button>

Secure Templates & Combat Lockdown

Combat Lockdown prüfen

if InCombatLockdown() then
    print("Im Kampf - geschützte Operationen blockiert")
    return
end
mySecureButton:SetAttribute("spell", "Heilende Berührung")

SecureActionButtonTemplate

local button = CreateFrame("Button", "MeinSecureButton", UIParent,
    "SecureActionButtonTemplate")
button:SetSize(50, 50)
button:SetPoint("CENTER")
-- AUSSERHALB des Kampfes konfigurieren!
button:SetAttribute("type", "spell")
button:SetAttribute("spell", "Heilende Berührung")

Aktionstypen

| Typ | Attribute | Beschreibung | |-----|-----------|--------------| | spell | spell | Zauber wirken | | item | item | Item benutzen | | macro | macrotext | Makro ausführen | | target | unit | Einheit anvisieren |

Modifikator-Tasten

button:SetAttribute("type", "spell")
button:SetAttribute("spell", "Blitzheilung")
button:SetAttribute("shift-type", "spell")
button:SetAttribute("shift-spell", "Große Heilung")
button:SetAttribute("ctrl-type", "spell")
button:SetAttribute("ctrl-spell", "Erneuerung")

hooksecurefunc

-- Sicheres Hooking ohne Taint
hooksecurefunc("SecureFunction", function(...)
    print("Funktion wurde aufgerufen mit:", ...)
end)

TBC Classic Besonderheiten

Zauberränge

local name, rank = GetSpellInfo(spellId)
print(name, rank)  -- "Heilende Berührung", "Rang 11"
CastSpellByName("Heilende Berührung(Rang 7)")

Krafttypen

local powerType = UnitPowerType("player")
-- 0 = Mana
-- 1 = Wut
-- 2 = Fokus (Jäger-Begleiter)
-- 3 = Energie

Begleiter-Zufriedenheit (Jäger)

local happiness, damageModifier, loyaltyRate = GetPetHappiness()
-- 1=Unglücklich, 2=Zufrieden, 3=Glücklich

Schamanen-Totems

local haveTotem, totemName, startTime, duration = GetTotemInfo(slot)
-- slot: 1=Feuer, 2=Erde, 3=Wasser, 4=Luft
DestroyTotem(slot)

Kampflog

frame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
frame:SetScript("OnEvent", function(self, event)
    local timestamp, subevent, _, sourceGUID, sourceName, sourceFlags,
          sourceRaidFlags, destGUID, destName, destFlags, destRaidFlags,
          arg12, arg13, arg14, arg15 = CombatLogGetCurrentEventInfo()
    if subevent == "SPELL_DAMAGE" then
        local spellId, spellName, spellSchool = arg12, arg13, arg14
        local amount = arg15
        print(sourceName, "trifft", destName, "für", amount)
    end
end)

Ressourcen

Offizielle Dokumentation

| Ressource | URL | |-----------|-----| | Warcraft Wiki | warcraft.wiki.gg/wiki/World_of_Warcraft_API | | Wowpedia | wowpedia.fandom.com/wiki/World_of_Warcraft_API | | Blizzard Dev Portal | develop.battle.net |

Ace3 Framework

| Bibliothek | Zweck | |------------|-------| | AceAddon-3.0 | Addon-Lebenszyklus | | AceDB-3.0 | SavedVariables mit Profilen | | AceConfig-3.0 | Optionen-Konfiguration | | AceConsole-3.0 | Slash-Befehle | | AceEvent-3.0 | Event-Registrierung | | AceGUI-3.0 | GUI-Widgets |

Tutorials: wowace.com/projects/ace3/pages/getting-started

Entwicklungs-Addons

| Addon | Zweck | |-------|-------| | BugSack + BugGrabber | Fehler sammeln | | DevTool | Tabellen/Frames inspizieren | | WoWLua | Lua-Scripting im Spiel | | IdTip | Spell/Item-IDs in Tooltips |

Addon-Plattformen

| Plattform | URL | |-----------|-----| | CurseForge | curseforge.com/wow/addons | | WoWInterface | wowinterface.com | | GitHub | github.com |

Nützliche In-Game-Befehle

/reload              -- UI neu laden
/dump ausdruck       -- Lua auswerten
/etrace              -- Event-Debugger
/fstack              -- Frames unter Mauszeiger
/console taintLog 1  -- Taint-Logging

Dokumentation erstellt Januar 2025