アドオンからログを制御する[FF11]

f:id:yyoshisaur:20191211101658p:plain
先日、ログの制御についてコメントを頂いただきました。
ログ関連についてのアドオンを作ったことがなかったので、Windowerからの制御方法について少し調べてみました。
簡単ではありますが、調べたことをまとめておきたいと思います。


ログが出力されるタイミングは、register_eventの"incoming text"で知ることが出来るようです。
まず、"incoming text"のコールバック関数の引数を見てみます。

function incoming_text_callback(original, modified, original_mode, modified_mode, blocked)

originalには、ログの文字列が入っています。(日本語の場合、文字コードはShift-JISです。)
例えば、通常攻撃であれば、originalには"Hogehogeの攻撃→Mobに、100ダメージ。"といった感じで1アクション分のログは入っています。

modifiedは、変数名から推測するとログを変更した際にその変更したログを格納する変数のようなものだと思います。
(後述しますが、仮引数なので、modifiedを変更しただけでは実際のログの内容は変化しません。)
コールバックが実行された際には、originalとmodifiedは同じ文字列(ログ)が格納されています。
訂正 2020/03/10
他のアドオンでログの内容が変更されていた場合、modifiedには変更後のログ、originalには変更されていないオリジナルのログが格納されています。
他のアドオンでログが修正されていない場合、modifiedとoriginalが同じ内容が格納されています。
アドオンがロードされた順番(register_eventで登録された順番)で登録したコールバック関数が実行されるようです。

original_modeは、ログの種類を識別する数値が入っています。
例えば、パーティ会話で自身が発言したログの場合はoriginal_mode=5、自身以外が発言したログはoriginal_mode=13といった感じです。
(windower.add_to_chat()で指定するchat_modeと同様のようです。)

modified_modeはmodifiedと同じように変更した際のモードを格納する変数です。

blockedは、ログをブロックするかどうかのフラグを格納する変数です。初期値はblocked = false(ブロックしない)となっています。
訂正 2020/03/10
blockedも同様に他のアドオンでブロックされた場合、blocked = trueが格納されています。

標準のチャットフィルターでフィルターを有効しているログでは"incoming text"のイベントは発生しないようです。

いくつか"incoming text"でのログを制御する例を挙げてみます。

ログのブロック(ログの非表示)

"incoming text"のコールバック関数で戻り値としてbool値を返すと、そのログの表示/非表示を制御できます。
そのbool値はblockedに対応していて、"return true"なら非表示、"return false"やbool値を返さなければ表示となるようです。

"の攻撃"の文字列が入ったログをブロックする
windower.register_event("incoming text", function(original, modified, original_mode, modified_mode, blocked)

    filter = windower.to_shift_jis('*の攻撃*')
    if windower.wc_match(original, filter) then
        blocked = true
        return blocked
    end

end)

※ windower.wc_match(Functions · Windower/Lua Wiki · GitHub)

この例ではすべてのログが対象になるため、PT会話等でも"の攻撃"の文字列が含まれる場合は表示されなくなってしまいます。
モードでの判定やマッチさせる文字列を工夫する必要があります。

サンプル

github.com

文字列の変更

"incoming text"のコールバック関数で戻り値として文字列を返すと、その文字列にログが変更されます。

自身のキャラクター名をジョブ名に変更する
windower.register_event("incoming text", function(original, modified, original_mode, modified_mode, blocked)

    player = windower.ffxi.get_player()
    my_name = player.name
    my_job = player.main_job

    -- ログ内のmy_nameを[my_job]に置換する
    modified = modified:gsub(my_name, '['..my_job..']')
    return modified

end)

f:id:yyoshisaur:20191209190859p:plain

モードの変更

上記の文字列の変更に加えて、ログのモードも一緒に返すと、モードも変更されます。

自身の攻撃ログ(mode=20)をパーティ会話(mode=5)に変更する
windower.register_event("incoming text", function(original, modified, original_mode, modified_mode, blocked)

    if original_mode == 20 then
        modified_mode = 5
        return modified, modified_mode
    end

end)

会話ログのモードになっているので、タイムスタンプが表示されています。
f:id:yyoshisaur:20191209190922p:plain

文字色の変更

ログのモードはログ全体の色が変わりますが、部分的に文字列の色を変更できます。
今回は'chat'のライブラリを読み込み、string.color()を使って文字の色を変更してみます。

require('chat')

windower.register_event("incoming text", function(original, modified, original_mode, modified_mode, blocked)

    player = windower.ffxi.get_player()
    my_name = player.name
    my_job = player.main_job

    modified = modified:gsub(my_name, my_job:color(5))
    return modified

end)

f:id:yyoshisaur:20191209190944p:plain

その他

"incoming text"のコールバック関数内でwindower.add_to_chat()を使うとadd_to_chatの出力の際にも"incoming text"のイベントが発生してしまいます。
そのため、デバッグ等をする際はWindowerのコンソールに出力するか、以下のようにログに追加するほうが良いかと思います。

モードを確認する
windower.register_event("incoming text", function(original, modified, original_mode, modified_mode, blocked)

    -- windower.add_to_chat(5, original_mode) add_to_chatの出力でもイベントが発生してしまう

    return '('..original_mode..')'..original -- ログの先頭にモードを追加して、確認する

end)