OBSEv0019で搭載された「EventHandler」を研究

独自に検証した単なるメモ的なものなので勘違い等があるかもしれません。
その場合は「この部分が違ってるぜ」と優しく突っ込んでください(´・ω・`)
 
下記の内容は随時更新していきます。

★基本事項
・登録関数が「SetEventHandler」という名前なので
 「同一イベント条件で登録できるハンドラは1個だけかな?」と思ったのですが
 実際は「同一イベント条件でもハンドラを何個も登録できます」。
 ActionScriptにおける「addEventListner」と同等と考えて良さそうです。
 例)
 SetEventHandler "OnKnockout" FnOnKnockout1
 SetEventHandler "OnKnockout" FnOnKnockout2
 SetEventHandler "OnKnockout" FnOnKnockout3
 誰かがノックアウトした際にFnOnKnockout1、FnOnKnockout2、FnOnKnockout3
 それぞれが正しく呼び出されます。
・「同一イベント条件 かつ 同一イベントハンドラ関数」を
 2回以上登録しようとすると戻り値に0(失敗)が返されて登録を拒否されます。
 例)
 SetEventHandler "OnKnockout" FnOnKnockout1 ;初登録
 SetEventHandler "OnKnockout" FnOnKnockout1 ;重複登録(2回目)
 SetEventHandler "OnKnockout" FnOnKnockout1 ;重複登録(3回目)
 こうやって3回登録したとしても重複登録はスルーされているので
 誰かがノックアウトしてもFnOnKnockout1は1回しか呼ばれません。
・イベント型名「eventID:string」の説明に書いてある「引数」は
 「イベントハンドラ関数で受け取るべき引数」と一致しますが
 「SetEventHandlerで登録する際の引数」と一致するとは限りません。
 例えば「OnHit」の引数は…
 第1引数 = target:ref (攻撃を食らった側)
 第2引数 = attacker:ref (攻撃をした側)
 イベントハンドラ関数は…
 scn FnOnHit
 ref target
 ref attacker
 Begin Function { target attacker }
  printC "%n が %n からの攻撃を受けました" target attacker
 End
 これは普通なのでわかりやすいと思います。
 しかしSetEventHandlerで登録する際の引数は…
 SetEventHandler "OnHit" FnOnHit object::PlayerRef
 この例の場合、FnOnHitの次の引数に「PlayerRef」を渡しているので
 第1引数である「攻撃を食らった側」が「PlayerRef」だとイベントが発生する
 …だと思いますよね?でも実際には違います。
 上記例の場合「誰かがプレイヤーからの攻撃を受けた場合に発生」します。
 この辺り引数の扱いで混乱をきたす危険性があると思います(主に私自身が)。

 ドキュメントに書いてあるサンプルソースの↓
 SetEventHandler "OnHit" FnOnHit object::PlayerRef
 これだと正常に動作せず
 SetEventHandler "OnHit" FnOnHit ref::PlayerRef
 にすると正しく動作するので、引数が一致しない件については思いっ切り勘違いかも(´Д`;;;

★他MODとの競合問題
・基本事項でも述べたように、OBSEv0019のイベントハンドラは
 「同一イベント条件でも複数のハンドラを登録できる(追加式)」ので
 少なくとも「イベントハンドラを上書き乗っ取りされて動かなくなる」
 という競合問題は起きなさそうです。

★留意すべき動作仕様
・「アイテムや魔法効果に添付したスクリプトの処理」には制約があり
 「スクリプトが処理されるのは対象アクターがプレイヤー付近にいる場合のみ
 (屋内であれば同一セル、屋外であれば周囲セル)」となっています。
 OBSEv0019のイベントハンドラの発生条件にも同じような制約があるようです。
 例えば上記でも扱った「"OnKnockout"のイベントハンドラ」の場合
 マップの遙か遠方にいるアクターに対してmodav2 fatigue -9999等を行い
 ノックダウンさせたとしても【その瞬間にはイベント処理が発生しません】。
 その状態にした後に対象アクターの付近(処理範囲内)へ移動した際に
 初めて「ノックダウンした」というイベントが発生します。

★要注意な動作仕様
・「SetEventHandler」で登録したイベントは
 「他のセーブデータをロードした後にも【残り続けます】」(´Д`;
 例えば、まだSetEventHandlerをしていない「セーブデータA」をロードします。
 その後何らかの手順でSetEventHandlerにて「イベントハンドラ」を登録します。
 でもやっぱやめた~!と先ほどの「セーブデータA」をロードし直します。
 この際、先ほど登録した「イベントハンドラ」が残っており動き続けています。
・上記とは逆に
 Oblivionを再起動すると登録済みのイベントハンドラは全て削除されます。
・上記2点の動作仕様を踏まえた上で判断すると…
 1)イベントハンドラは必要に応じて動的に登録/解除するのではなく
  必ず登録しておいて走り続けている状態の方が管理しやすいと思われる
  (動的な登録/解除を実装しようとするとセーブデータのロード時や
   オブリ再起動時の突発的な状態変動に対処しにくい)
 2)それを実現する為にQuestスクリプトで初回動作時やGetGameRestarted時に
  イベントハンドラを登録する(登録し直す)処理を実装するとよさそう
スポンサーサイト

コメント

非公開コメント

プロフィール

r_basilico

バジリコ風味 (r_basilico)
Twitter: r_basilico
Steam: r_basilico
艦これ: 嫁艦は祥鳳

リンク
最新記事
最新コメント
月別アーカイブ
カテゴリ
検索フォーム