mcpField
W
wow-api-lua-environment

wow-api-lua-environment

github.com/jburlison開発4659 回インストール37 週間前に更新
リポジトリ

wow-api-lua-environment について

World of Warcraft Retailのアドオン開発者向けLuaリファレンススキルです。サンドボックス、汚染、安全な実行を扱い、Patch 12.0.0時点のAPIと例をまとめています。

主な機能

  1. 01Lua 5.1サンドボックスの関数と制限
  2. 02汚染チェックとセキュア実行
  3. 03戦闘ロックダウンと保護フレーム
  4. 04タイマー、フック、ステートドライバー
  5. 05ログとデバッグ機能

活用シーン

  1. 01Lua関数の利用可否を確認
  2. 02アドオンの汚染や実行拒否を調査
  3. 03タイマーや安全な関数フックを実装
  4. 04戦闘中やインスタンス内の制限に対応

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jburlison/wowaddonapiagents --skill wow-api-lua-environment

インストール後、Claude Code で/wow-api-lua-environmentを入力して読み込まれたか確認します。

詳細

Lua 環境とセキュリティ(Retail — Patch 12.0.0)

WoW の Lua サンドボックス、セキュリティモデル、汚染システム、安全な実行、タイマー、フック、ログ記録、制限付きアクションに関する包括的なリファレンスです。

ソース: https://warcraft.wiki.gg/wiki/World_of_Warcraft_API 安全な実行: https://warcraft.wiki.gg/wiki/Secure_Execution_and_Tainting Lua 関数: https://warcraft.wiki.gg/wiki/Lua_functions 最終更新: Patch 12.0.0 (Build 65655) — January 28, 2026 対象範囲: Retail のみです。

対象範囲

このスキルでは、以下を扱います。

  • Lua サンドボックス — WoW の Lua 5.1 環境、制限された標準ライブラリ、ブロックされる関数
  • 汚染システム — アドオンのコードがどのように汚染されるか、また汚染されたコードでできないこと
  • 安全な実行 — 保護された関数、安全なフレーム、安全なハンドラー
  • 戦闘中のロックダウン — 戦闘中にアドオンでできること、できないこと
  • C_Timer — タイマー関数(After、NewTicker、NewTimer)
  • フック — hooksecurefunc、securecallfunction、securecallmethod
  • C_RestrictedActions — アドオン制限状態のクエリ
  • C_Log — ログ記録ユーティリティ
  • FrameScript — フレームスクリプト環境、シークレット値、スクラビング
  • デバッグ — エラー処理、スタックトレース、デバッグユーティリティ

このスキルを使用する場面

以下が必要な場合に、このスキルを使用してください。

  • WoW で利用できる Lua 関数と、ブロックされる関数を把握する
  • 汚染の問題に対処したり、デバッグしたりする
  • 安全なフレームや保護されたフレームと連携するコードを書く
  • タイマー、遅延実行、ティッカーパターンを使用する
  • 既存の関数を安全にフックする
  • 戦闘中のロックダウンによる制限を把握する
  • アドオンの制限状態(12.0.0 のインスタンス制限)を処理する
  • デバッグ用のメッセージをログに記録する
  • シークレット値や FrameScript サンドボックスを扱う

WoW Lua 5.1 サンドボックス

WoW は大幅に変更された Lua 5.1.4 を実行します。次の標準ライブラリ関数はブロックされているか、削除されています。

ブロックされる標準関数
ブロック対象理由
loadfile()ファイルシステムにアクセスできません
dofile()ファイルシステムにアクセスできません
io.*ファイルシステムにアクセスできません
os.execute()シェルにアクセスできません
os.exit()クライアントを終了できません
os.remove()ファイルシステムを利用できません
os.rename()ファイルシステムを利用できません
os.tmpname()ファイルシステムを利用できません
os.getenv()環境変数にアクセスできません
package.*パッケージシステムは利用できません
require()モジュールを読み込めません
module()モジュールシステムは利用できません
newproxy()削除されています
getfenv()制限付き — 読み取り専用を返します
setfenv()厳しく制限されています
collectgarbage()使用できるモードが制限されています
利用可能な標準関数

ほとんどのコア Lua 関数は通常どおり動作します。

  • すべての string.*、table.*、math.* 関数
  • type()、tostring()、tonumber()、rawget()、rawset()、rawequal()、rawlen()
  • pairs()、ipairs()、next()、select()、unpack()
  • pcall()、xpcall()、error()、assert()
  • setmetatable()、getmetatable()
  • coroutine.*(コルーチンを完全にサポート)
  • os.time()、os.date()、os.clock()、os.difftime()
  • print() — デフォルトのチャットフレームに出力します
WoW で追加されたグローバル関数
関数説明
strsplit(delimiter, str [, pieces])区切り文字で文字列を分割します
strsplittable(delimiter, str [, pieces])分割してテーブルにします
strjoin(delimiter, ...)文字列を結合します
strtrim(str [, chars])空白を削除します
tContains(table, value)テーブルに値が含まれているか確認します
tInsert(table, value)テーブルに挿入します(エイリアス)
tDeleteItem(table, value)値の最初の出現箇所を削除します
tInvert(table)キーと値のペアを反転します
wipe(table)テーブルをクリアします(参照は維持)
CopyTable(table [, shallow])ディープコピーまたはシャローコピーを作成します
MergeTable(dest, source)source を dest にマージします
Mixin(object, ...)ミックスインのメソッドをオブジェクトにコピーします
CreateFromMixins(...)ミックスインから新しいオブジェクトを作成します
CreateAndInitFromMixin(mixin, ...)作成して Init を呼び出します
format(formatString, ...)string.format のエイリアスです
tostringall(...)すべての引数を文字列に変換します
DevTools_Dump(value, startKey)デバッグ用に値をダンプします

Taint システム

すべてのアドオンコードは**「tainted」(非セキュア)として実行されます。Blizzard の UI コードは「secure」**(非 tainted)として実行されます。Taint システムは、アドオンが保護された関数を呼び出したり、セキュアフレームを変更したりするのを防ぎます。

Taint の仕組み
  1. アドオンコードによって設定された変数は、すべて tainted になります
  2. Tainted な値は伝播します。tainted なデータが Blizzard のコードに流れ込むと、その経路も tainted になります
  3. 保護された関数は実行前に taint を確認し、実行経路が tainted なら失敗します
  4. セキュアフレームは、作成されたコンテキストからセキュリティを継承します
Taint の確認
-- Check if a global variable is tainted
local isTainted, source = issecurevariable("SomeGlobalVar")
-- isTainted: false = secure, true = tainted
-- source: string name of the addon that tainted it (or nil if secure)

-- Check table field
local isTainted, source = issecurevariable(someTable, "someKey")
よくある Taint の落とし穴
-- WRONG — This taints the Blizzard settings table
Settings.RegisterAddOnCategory = myFunc  -- TAINT!

-- WRONG — Modifying secure frame in insecure context
local btn = PlayerFrame  -- This is a secure Blizzard frame
btn:SetAttribute("type", "spell")  -- TAINT — can cause action blocked errors

-- RIGHT — Use hooksecurefunc for observation without tainting
hooksecurefunc("SomeBlizzardFunction", function(...)
    -- Your code runs AFTER the original — doesn't taint
end)

セキュア実行と保護された関数

保護された関数の制限

#protected とマークされた関数は、次の場所からのみ呼び出せます。

  • セキュアな(Blizzard の)コード
  • ハードウェアイベントによって発生したセキュアクリックハンドラー
  • SecureActionButtonTemplate ハンドラー内

保護された関数には、次のものがあります。

  • 戦闘関連の詠唱すべて:CastSpellByName()、CastSpellByID()、UseAction()
  • アイテムの使用:UseItemByName()、UseContainerItem()(戦闘中)
  • ターゲットの変更:TargetUnit()、AssistUnit()、FocusUnit()
  • 移動:MoveForwardStart()、JumpOrAscendStart()
  • UI の状態:セキュアフレームでの SetAttribute()(戦闘中)
戦闘ロックダウン
-- Check if in combat lockdown
if InCombatLockdown() then
    -- Cannot: create/destroy secure frames, change secure attributes
    -- Cannot: set points on secure frames, change parent/visibility of secure frames
    -- Can: read attributes, modify non-secure frames, queue changes for later
    return
end

-- Queue changes for after combat
local frame = CreateFrame("Frame")
frame:RegisterEvent("PLAYER_REGEN_ENABLED")
frame:SetScript("OnEvent", function()
    -- Combat ended — safe to modify secure frames now
    DoSecureFrameChanges()
end)
セキュアハンドラーとテンプレート
-- SecureActionButtonTemplate — allows protected actions via user clicks
local btn = CreateFrame("Button", "MySecureBtn", UIParent, "SecureActionButtonTemplate")
btn:SetAttribute("type", "spell")
btn:SetAttribute("spell", "Fireball")
-- When clicked by hardware event, this will cast Fireball

-- SecureHandlerBaseTemplate — run secure snippets
local frame = CreateFrame("Frame", nil, UIParent, "SecureHandlerBaseTemplate")
frame:SetAttribute("_onstate-combat", [[
    -- This snippet runs in the secure environment
    if newstate == "combat" then
        self:Hide()
    else
        self:Show()
    end
]])
RegisterStateDriver(frame, "combat", "[combat] combat; nocombat")
ステートドライバー
-- Register a state driver for automatic secure attribute updates
RegisterStateDriver(frame, "stateName", "conditionalString")
-- e.g., RegisterStateDriver(frame, "visibility", "[combat] hide; show")

UnregisterStateDriver(frame, "stateName")

C_Timer — タイマー API

Wiki: https://warcraft.wiki.gg/wiki/API_C_Timer.After

タイマー関数
関数戻り値説明
C_Timer.After(seconds, callback)—1 回限りのタイマー
C_Timer.NewTimer(seconds, callback)timerキャンセル可能な 1 回限りのタイマー
C_Timer.NewTicker(seconds, callback [, iterations])ticker繰り返しタイマー
タイマーオブジェクトのメソッド
local timer = C_Timer.NewTimer(5, function()
    print("5 seconds elapsed")
end)
timer:Cancel()  -- Cancel before it fires

local ticker = C_Timer.NewTicker(1, function()
    print("Every second")
end, 10)  -- Stop after 10 iterations
ticker:Cancel()  -- Or cancel early

-- Simple delay (non-cancellable)
C_Timer.After(2, function()
    print("2 seconds later")
end)

Hooks — 関数フック

hooksecurefunc

主要な安全なフック機構です。フックは元の関数を taint せずに、実行後に呼び出されます。

-- Hook a global function
hooksecurefunc("UseAction", function(slot, checkCursor, onSelf)
    print("Action used:", slot)
end)

-- Hook a method on an object
hooksecurefunc(GameTooltip, "SetUnitAura", function(self, ...)
    -- Runs after GameTooltip:SetUnitAura
end)

-- IMPORTANT: You CANNOT prevent the original from executing
-- IMPORTANT: You CANNOT modify the return values
-- IMPORTANT: Your hook does NOT taint the original function
securecallfunction / securecallmethod
-- Call a function in secure context (if possible)
securecallfunction(func, arg1, arg2)

-- Call a method in secure context
securecallmethod(object, "MethodName", arg1, arg2)

C_RestrictedActions — アドオン制限状態

12.0.0 で追加されました。アドオンの制限が有効なタイミング(例:インスタンス内)を追跡します。

関数戻り値説明
C_RestrictedActions.GetAddOnRestrictionState(type)state現在の制限状態
C_RestrictedActions.IsAddOnRestrictionActive(type)active現在、制限が有効かどうか
C_RestrictedActions.CheckAllowProtectedFunctions(object [, silent])protectedFunctionsAllowedオブジェクトが保護された関数を呼び出せるかどうか
InCombatLockdown()inCombatLockdown戦闘ロックダウンが有効かどうか
制限イベント
イベント説明
ADDON_RESTRICTION_STATE_CHANGED制限状態が変更されました(インスタンスへの出入り)
PLAYER_REGEN_DISABLED戦闘開始
PLAYER_REGEN_ENABLED戦闘終了

C_Log — ロギング

関数説明
C_Log.LogMessage(message)情報メッセージをログに記録します
C_Log.LogWarningMessage(message)警告をログに記録します
C_Log.LogErrorMessage(message)エラーをログに記録します
C_Log.LogMessageWithPriority(priority, message)指定した優先度でログに記録します

注: ConsolePrint() は 12.0.0 で削除されました。代わりに C_Log.LogMessage() を使用してください。


FrameScript 関数

WoW には、セキュア/シークレット値システムを扱うための特別な FrameScript 関数があります。

関数戻り値説明
issecurevariable([table,] name)isSecure, taintSource汚染状態を確認します
issecretvalue(value)isSecret値はシークレットですか?
issecrettable(table)isSecretOrContentsSecretテーブルまたはその内容はシークレットですか?
canaccessvalue(value)isAccessibleアドオンはこの値にアクセスできますか?
hasanysecretvalues(values)isAnyValueSecretいずれかの引数はシークレットですか?
scrubsecretvalues(values)scrubbedシークレットを nil に置き換えます
secretwrap(values)wrapped値をシークレットとしてラップします
mapvalues(func, values)mapped関数を値に適用します(シークレットセーフ)
securecallfunction(func, ...)resultsセキュアコンテキストで呼び出します
securecallmethod(obj, method, ...)resultsセキュアコンテキストでメソッドを呼び出します
forceinsecure()—インセキュアな実行を強制します
seterrorhandler(handler)—グローバルエラーハンドラーを設定します
geterrorhandler()handler現在のエラーハンドラーを取得します

デバッグユーティリティ

エラー処理
-- Set a custom error handler
seterrorhandler(function(msg)
    -- msg is the error string
    print("ERROR:", msg)
end)

-- Protected call with error handling
local success, err = pcall(function()
    -- Code that might error
end)
if not success then
    print("Error:", err)
end

-- xpcall with message handler
local success, err = xpcall(function()
    error("something broke")
end, function(msg)
    return msg .. "\n" .. debugstack(2)
end)
デバッグスタックと情報
-- Get a stack trace
local stack = debugstack([thread,] [start [, count1 [, count2]]])

-- Get debug info
local info = debuglocals([thread,] [level])

-- Profile timing
debugprofilestart()
-- ... code to measure ...
local elapsed = debugprofilestop()  -- microseconds
デバッグ用スラッシュコマンド
-- /dump expression — evaluates and prints
-- /run code — executes Lua code
-- /script code — same as /run
-- /console cvarName [value] — get/set console variables

よく使われるパターン

初期化の遅延(ログインを待機)
local frame = CreateFrame("Frame")
frame:RegisterEvent("PLAYER_LOGIN")
frame:SetScript("OnEvent", function(self, event)
    -- Safe to initialize — player is logged in
    self:UnregisterEvent(event)
    InitializeAddon()
end)
安全な OnUpdate スロットリング
local elapsed = 0
local THROTTLE = 0.1  -- 100ms
frame:SetScript("OnUpdate", function(self, dt)
    elapsed = elapsed + dt
    if elapsed < THROTTLE then return end
    elapsed = 0
    -- Do periodic work
end)
戦闘終了後のアクションキュー
local pendingActions = {}

local function QueueAction(action)
    if InCombatLockdown() then
        tinsert(pendingActions, action)
    else
        action()
    end
end

local frame = CreateFrame("Frame")
frame:RegisterEvent("PLAYER_REGEN_ENABLED")
frame:SetScript("OnEvent", function()
    for _, action in ipairs(pendingActions) do
        action()
    end
    wipe(pendingActions)
end)
シークレット値の適切な処理(12.0.0)
-- When values might be secret, pass them directly to widgets
local name = UnitName(unit)  -- may be secret
myFontString:SetText(name)   -- widgets accept secrets

-- Check if a value is secret before trying operations
if not issecretvalue(someValue) then
    -- Safe to compare, do arithmetic, etc.
    if someValue == "expected" then ... end
else
    -- Cannot inspect — pass to UI widget directly
    myWidget:SetText(someValue)
end

注意点と制限事項

  1. require() は使用できません — WoW にはモジュールシステムがありません。読み込み順序の制御には TOC ファイルを使用してください。ライブラリは直接埋め込まれます。
  2. setfenv() / getfenv() — 厳しく制限されています。環境操作に依存しないでください。
  3. collectgarbage() — "count" モードのみ動作します。GC の実行を強制することはできません。
  4. 汚染は残ります — 変数が一度汚染されると、その状態は維持されます。元の値に戻しても、汚染は残ります。
  5. print() はチャットに出力されます — 標準 Lua とは異なり、print() は標準出力ではなく、デフォルトのチャットフレームに出力します。
  6. 文字列ライブラリの追加機能 — WoW では strsplit、strjoin、strtrim、strmatch がグローバル関数として追加されています(string.match に加えて)。
  7. os.exit() は使用できません — プログラムからクライアントを終了することはできません。
  8. コルーチンは使用できます — コルーチンが完全にサポートされており、非同期パターンで一般的に使用されています。
  9. シークレット値(12.0.0) — 一部の API の戻り値は、検査、比較、算術演算に使用できない不透明な「シークレット」値になりました。詳しくは wow-api-important の手順を参照してください。
  10. インスタンスでの制限(12.0.0) — インスタンス内では SendAddonMessage() がブロックされます。インスタンスコンテンツ中にプレイヤー間通信を行わなくても動作するよう、アドオンを設計してください。

コメント