Glenelg開発メモ/AIロード方式

2007-04-03 (火) 07:05:58 (3945d)
お名前:

Glenelgの機能についてのメモ。
自分のための覚書でもあり、利用者のための豆知識でもあり、他AI開発者のための参考情報でもあり。

2007.Feb.06での「ホム周りいろいろアレなパッチ」での大きな変化点の1つが、 AI起動時間の性能悪化です。
GlenelgではVer0.47で、友瀬の個人的な調査をもとに若干の改善策をうちました。
ですがこれに関するアナウンス・説明が不足しているように思ったので、技術メモとして整理します。

もちろん、この内容は友瀬の独自調査による推論がベースにあります。
これが完全な現実という保証はないので、そのあたりは誤解なきよう。

2007.Apr.03 追記

2007.Mar.27のパッチで、このロード時間は以前の速度に戻されているようです。
つまり、ここのページで解説している内容は気にしなくてもいいレベルになっています。
まあ、すでにGlenelgに組み込んである内容&速くなっても現状でも致命的とまではいかない&パラメータ修整だけで採用しないようにできる、というようにさまざまに猶予がある内容なので、現状維持としておきます。


前提知識:Windowsプログラムの常識と、ROクライアント。

あまりプログラムに詳しくない人のために、簡単な解説。

Windowsに限らないですが、基本的に1つのプログラムは、一度には1つの作業しかできません。
そのため、ある作業をしている間は、別の作業は処理されずに待っている状態になります。
見かけ上複数の作業を平行して行えるように作ることは可能ですが、それにはそれなりの作りこみが必要です。

ROにおいては、「画面へのキャラクター描画」と「ホムAI実行」は、「同時に動くようには作られていない」ようです。
別の言い方をすると、ホムAI周りの実行に時間がかかると、その間画面の描画が行われません。
なぜこんなことを最初に書いたかというと、これが今回の大きな問題につながっているためです。

Ver0.46以前での、GlenelgとROの関係。

Ver0.46 以前でのGlenelgの起動処理は、以下のような感じでした。

  • Step0:コールホムなどで、ホムンクルスが出現
  • Step1:ROクライアントが、AI.lua を読み込む。
  • Step2:ROクライアントが、読み込んだAI.luaを実行(最初のAIサイクル開始)。
  • Step3:実行されたAI.lua内から、AIがAIの追加部分を読み込み要求(require 命令)
  • Step4:ROクライアントは、指示された追加部分を読み込む。
  • Step5:Step3,4を必要分繰り返し、AI全体の読み込みを完了させる。
  • Step6:実際のAI駆動1回目実施。
  • Step7:AI1サイクル分の動作完了。
  • Step8:次のAIサイクル開始。
  • Step9: Step3同様、必要に応じて新たなrequire・・・だが、Glenelg(や、他の多くのAIでは)特になし。
  • Step10:AI1サイクル分の動作完了。
    • 以後、AIサイクルごとにStep8〜10が行われる

このかたちで、2007.Feb.06より前は問題なく動いていました。

ところが、Feb.06パッチで大きな影響が発生しました。
AIの作りが変わったわけではないですし、上記の流れも変わっていません。
何が変わったかというと、
「ROクライアントがAIプログラムを読み込む処理」が遅くなったのです。
上記フローでいうと、Step1〜5 の部分に大きな時間がかかるようになったのです。

その結果、何が起きたか?

最初に書いた通り、ROにおいては、「画面へのキャラクター描画」と「ホムAI実行」は、「同時に動くようには作られていない」ようです。
別の言い方をすると、ホムAI周りの実行に時間がかかると、その間画面の描画が行われません。

ポイントになるのは、上記Step1〜5は「Step2〜Step7という一連のAI処理」の中にあるということ。
ホムの最初の1AIサイクルの処理が完了するまでは、「画面描画も一切行われない」ということです。
友瀬の環境では、このStep6までに1〜2秒の時間がかかっていました。
この結果、見かけ上は・・・

  • ケミ&ホムがテレポアウト
    →画面には友瀬のケミ&ホムだけが表示。
    →そのまま1、2秒、一切操作を受け付けず。
    →その後おもむろに、周囲のPC・NPC・敵類が表示

・・・という感じになっていました。

もちろん画面描画はなされなくても、ROサーバー側では刻一刻と動作は行われています。
その結果、上記で「敵類が表示」されたとたん、実はケミ&ホムが敵に包囲されてぼこぼこにされていた、 ということがありえたのです。

Ver0.47以降での、GlenelgとROの関係。

上記状況を省みて、Glenelgでは初期化プロセスを以下のような感じに変更しました。

  • Step0:コールホムなどで、ホムンクルスが出現
  • Step1:ROクライアントが、AI.lua を読み込む。
  • Step2:ROクライアントが、読み込んだAI.luaを実行(最初のAIサイクル開始)。
  • Step3:実行されたAI.lua内から、AIがAIの最低部分だけを読み込み要求(require "AImain.lua" 命令)
  • Step4:ROクライアントは、指示された AImain.lua を読み込む。
  • Step5:GlenelgはAImain.lua部分だけの「簡易モード」でホム動作実施。
  • Step6:AI1サイクル分の動作完了。
  • Step7:次のAIサイクル開始。
  • Step8:Glenelgは自分自身Iの一部分(一部ファイル)だけを requre実施。
  • Step9:ROクライアントは、指示されたファイルだけを読み込む。
  • Step10:GlenelgはAImain.lua部分だけの「簡易モード」でホム動作実施。
  • Step11:AI1サイクル分の動作完了。
    • 以後、何度かStep7〜11が行われる
  • Step12:次のAIサイクル開始。
  • Step13:Glenelgは自分自身Iの最後のファイルを requre実施。
  • Step14:ROクライアントは、指示されたファイルだけを読み込む。
  • Step15:Glenelgは完全モードでホム動作実施。
  • Step16:AI1サイクル分の動作完了。
  • Step17:次のAIサイクル開始。
  • Step18:(すでに全体のrequireが終わっているので)Glenelgは完全モードでホム動作実施。
  • Step19:AI1サイクル分の動作完了。
    • 以後、AIサイクルごとにStep17〜19が行われる

上記のように手順記述すると長いですが、単純に言ってしまうと
「一度にAI全部をロードすると、長い時間固まってしまう。
 だから、一度にまとめてではなく、何回かにわけてロードしよう。」
・・・という話。別の表現をすると、
「2秒間完全に固まるよりは、0.2秒ずつ10回にわけて固まったほうが、マシ」 という感じです。

別の見方をすると・・・Ver0.47でのGlenelgの「ロード時間改善」は無条件の改善ではありません。
ロードに余計な手間をかけているのでオーバーヘッドは確実に増えています。
現在のGlenelgは、自分自身を13分割してロード:言い換えると、全体のロードを完了するまでに13AIサイクルを必要とします。
1AIサイクルは約140msec前後ですから、単純計算でも約1.8秒はかかる計算になります。

全体がロード完了するまでは、Glenelgは「追従動作のみの簡易モード」で動作しています。
つまりこの間は手動も含めて一切戦闘行為が行えないことになります。

この弱点はわかってはいるものの、以前のかたちでも現状は1秒以上固まって一切操作不能。
それなら、ケミだけでも操作可能にしたほうがいい、という判断です。

ただし・・・

現状わかっていないことの1つに、
「このロード速度悪化が、PC環境に依存するのかしないのか」
とい点があります。

友瀬の環境では上述のように「固まって困る」ので、分割処理をいれてそれを軽減しました。
ですが、MMOBBSのAIスレでは人によって温度差がかなり感じられますし、AI作者の間でもまったく気にならない様子の方もいます。
何が現実なのかはわかりませんが、ともあれ、もし2/6パッチ+以前のGlenelgでも問題なく動作していた人がいれば、その人にとってはこの「分割ロード」は単なる劣化処理です。
もしそういう報告があるのなら、この分割ロードもオプション化しなければなりませんね。

また、本質的にはGlenelgが非常に巨大だ、という点もあると思います。
軽量に動作するAIももちろんあると思いますが、そのあたりはAIの機能差and/or設計者の腕の差と考えてください。
残念ながら、友瀬はLUAについては最適化設計できるほどの知識はないもので・・・

おまけ:通常起動方法

前述のように、2/6パッチでの低速化はどれだけのユーザーに実害があったかわかっていません。
しかし、現状のGlenelgでは自動的に「分割ロード」してしまうため、 実は一括ロードしても問題ないユーザーには、性能劣化です。

そこで、Ver0.48aにおいて、「1行だけ内容を書き換える」ことで、分割ロードするか一括ロードするかを変更できるように手をいれました。
AImain.lua をエディタで開き、「localcount」で検索してみてください。
以下のような記述があるはずです。
ということで、ここをいじってみてください。

-- 重要:もし分割ロードしたくないならば、localcount = 15 と記述すること。
localcount = 0