Mote-libsのhandle_actions(precastやmidcast)や各種ファンクションは、優先順位別に名前を変えて利用することができますが、少し複雑なので整理しておきたいと思います。
優先順位を変えて処理を組むと、ジョブロジックをシンプルにできるのでメンテナンス性が向上します。
例えば、睡眠時に自動で起床する処理など、全ジョブで共通する処理を共通ファイルに記述し、個別のジョブロジックで個別の定義をすることもできます。
どのファンクションを使えば正解なのかよくわからん状態をスッキリさせます。
やりたいこと
buff_changが分かりやすいと思いますので、これを例にして説明します。
buff_changeの説明
Mote-Include.lua
のbuff_changeは次のように定義されています。
function buff_change(buff, gain)
-- Init a new eventArgs
local eventArgs = {handled = false}
if state.Buff[buff] ~= nil then
state.Buff[buff] = gain
end
-- Allow a global function to be called on buff change.
if user_buff_change then
user_buff_change(buff, gain, eventArgs)
end
-- Allow jobs to handle buff change events.
if not eventArgs.handled then
if job_buff_change then
job_buff_change(buff, gain, eventArgs)
end
end
end
このうち、次のものが利用可能で先に書かれているものが優先的に処理されます。
- user_buff_change
- job_buff_change
user_buff_changeが実行された後に、job_buff_changeが実行されます。
ただし、job_buff_changeはnot eventArgs.handledがフラグになっており、このフラグがfalseの場合に限り処理が実行されるようになっています。eventArgs.handledの初期値はfalseですので、意図的にeventArgs.handledをセットしない限り実行されるようになっています。
活用例
この仕組みを利用することで、ジョブロジックをシンプルにすることができます。
私の共通ファイルでは、次の定義をしています。
function user_buff_change(buff, gain)
if state.Buff['睡眠'] then
equip({main=sets.Weapons.Slip})
equip({range=sets.Weapons.Slip})
elseif buff == "ファランクス" and not gain then
windower.add_to_chat(167,'■■■■■ファランクス切れ■■■■■')
end
end
この処理が何をしているのかというと、次の通りです。
- 睡眠の自動起床
- ファランクス切れの通知
睡眠はプライムウェポンを利用することで自動的に起床できますので、該当ジョブの装備定義にsets.Weapons.Slipでプライムウェポンを書いておけば、自動的に起床可能です。sets.Weapons.Slipの定義がない場合はエラーにならずそのままスルーしてくれます。
buff_changeが必要なジョブは次のように定義します。これは魔道剣士のコードを抜粋したものです。
function job_buff_change(buff, gain)
if buff == 'バットゥタ' and gain then
send_command('gs c set OffenseMode Parry')
elseif buff == 'バットゥタ' and not gain then
send_command('gs c set OffenseMode Normal')
elseif buff == 'エンボルド' and gain then
equip(sets.buff['エンボルド'])
disable('back')
elseif buff == 'エンボルド' and not gain then
enable('back')
Idle()
end
end
このようにjob_buff_changeを定義している場合、GearSwapはuser_buff_changeとjob_buff_changeを順番に実行してくれます。
job_buff_changeを定義しないジョブの場合は、user_buff_changeだけが実行されます。
その他ファンクション
Mote-Include.lua
から抜き出して整理すると次のようになります。
これらはフラグ(cancel,handled)を組み合わせて処理の実行有無を判断できるしくみになっているのですが、フラグの制御はややこしく私は使いこなせていないため、説明は割愛します。
ファンクション名 | 組み合わせ優先順位 |
---|---|
pretarget precast midcast aftercast pet_midcast pet_aftercast | filter_ user_ job_ default_ user_post_ job_post_ cleanup_ |
customize_idle_set | user_customize_idle_set customize_idle_set |
customize_melee_set | customize_melee_set user_customize_melee_set |
status_change | user_status_change job_status_change |
buff_change | user_buff_change job_buff_change |
※customize_melee_setだけ順番が逆になっているのは、単純にバグだと思います。
この仕組みを利用することで、先に処理されるファンクションを共通ファイルに記述し、後に処理されるファンクションが必要なのであれば、個別のジョブファイルに書くことでシンプルに構成することが可能になります。
実行順番の確認
precastやmidcastの着替え、例えば属性帯の着替えなどを上書きするためにはどのファンクションで上書きすれば良いのかを確認するために、次のコードをgs degugmodeを使って検証してみました。
Mote-libsで該当するファンクションは次のものです。
function handle_actions(spell, action)
-- Init an eventArgs that allows cancelling.
local eventArgs = {handled = false, cancel = false}
mote_vars.set_breadcrumbs:clear()
-- Get the spell mapping, since we'll be passing it to various functions and checks.
local spellMap = get_spell_map(spell)
-- General filter checks to see whether this function should be run.
-- If eventArgs.cancel is set, cancels this function, not the spell.
if _G['filter_'..action] then
_G['filter_'..action](spell, spellMap, eventArgs)
end
-- If filter didn't cancel it, process user and default actions.
if not eventArgs.cancel then
-- Global user handling of this action
if _G['user_'..action] then
_G['user_'..action](spell, action, spellMap, eventArgs)
if eventArgs.cancel then
cancel_spell()
end
end
-- Job-specific handling of this action
if not eventArgs.cancel and not eventArgs.handled and _G['job_'..action] then
_G['job_'..action](spell, action, spellMap, eventArgs)
if eventArgs.cancel then
cancel_spell()
end
end
-- Default handling of this action
if not eventArgs.cancel and not eventArgs.handled and _G['default_'..action] then
_G['default_'..action](spell, spellMap)
display_breadcrumbs(spell, spellMap, action)
end
-- Global post-handling of this action
if not eventArgs.cancel and _G['user_post_'..action] then
_G['user_post_'..action](spell, action, spellMap, eventArgs)
end
-- Job-specific post-handling of this action
if not eventArgs.cancel and _G['job_post_'..action] then
_G['job_post_'..action](spell, action, spellMap, eventArgs)
end
end
-- Cleanup once this action is done
if _G['cleanup_'..action] then
_G['cleanup_'..action](spell, spellMap, eventArgs)
end
end
フラグの制御なしで実行すると、次の順番で処理されることになります。
- filter_precast
- user_precast
- job_precast
- default_precast
- user_post_precast
- job_post_precast
- cleanup_precast
次のコードをgs degugmodeを使って検証してみました。ファンクションが実行されるとファンクション名を出力するシンプルなものです。
function filter_precast(spell, action, spellMap, eventArgs)
windower.add_to_chat(167,'filter_precast')
end
function user_precast(spell, action, spellMap, eventArgs)
windower.add_to_chat(167,'user_precast')
end
function job_precast(spell, action, spellMap, eventArgs)
windower.add_to_chat(167,'job_precast')
end
function default_precast(spell, action, spellMap, eventArgs)
windower.add_to_chat(167,'default_precast')
end
function user_post_precast(spell, action, spellMap, eventArgs)
windower.add_to_chat(167,'user_post_precast')
end
function job_post_precast(spell, action, spellMap, eventArgs)
windower.add_to_chat(167,'job_post_precast')
end
function cleanup_precast(spell, action, spellMap, eventArgs)
windower.add_to_chat(167,'cleanup_precast')
end

実行されていないファンクションもありましたが、この結果を見る限り次のことが分かります。
job_precastとuser_post_precastの間、つまりdefault_precastで着替えが行われていたので、sets.precast.RAに定義している内容を上書きできるのはuser_post_precastとjob_post_precastになります。
このことから、装備定義している内容をプログラムから上書きするには、user_post_precastとjob_post_precastで行うのが正解だということが分かりました。
default_precastより前に実行させるべきファンクションの用途がいまいち分かりませんが、おそらくフラグを利用して着替えをキャンセルさせるなどになるのでしょうか。現実的な方法ではないと思うので、とりあえず無視しておきます。
コメント