返信先: ARMA3 ミッションエディットスレ

ホーム フォーラム TRI Gaming フォーラム ARMA3 ミッションエディットスレ 返信先: ARMA3 ミッションエディットスレ

#100884
アバター画像michy_REV19
キーマスター

どうも皆様こんにちは、ミッションが完成しないことに定評のあるmichyでございます。

Edenエディタがリリースされ早一週間、新しいインターフェイスには賛否両論あるようですね。
ところで、私たちが普段遊んでいるマルチプレイでは、サーバーと複数のクライアントの間で処理した情報を相互に送信し合っており、処理をどこで行うか、その結果をどこに渡すか、ということが重要になっています。私自身もこれを理解するのにかなり苦労しましたが、最近ようやくわかるようになってきたので、本日はマルチプレイミッションでの処理位置について、注意すべきことをまとめたいと思います。上の方に埋もれてしまっている、Lineさんの書き込みも参考にしながらまとめさせていただきました。
※先駆者の皆様の二番煎じなうえに間違ったことを書いているかもしれません。もし何かあったら遠慮なく突っ込み入れてください。
※以下の構文はあくまで私流の書き方です。

1.トリガーやウェイポイントでの処理

例えば、敵の自走式対空砲を破壊するタスクがあったとします。自軍はAltis島南東端の市街地Kavalaからスタートし、対空砲は北東端に位置するMolosの空港に配備されており、これを破壊することでタスク1を完了させます。このとき、対空砲に変数名aagun1を設定したうえでトリガーのコンディション欄には、!alive aagun1といった形で、対空砲が破壊されているかどうか判定を行います。もし破壊されている(コンディション欄がtrueである)なら、タスクの完了を判定する変数task1donetrueに変化させるために、OnAct欄にtask1done=trueと記述します。

タスクの完了判定はこれにて完了していますが、ほとんどのエディタの方は、task1done=trueの記述とセットでpublicVariable "task1done"といった記述をしているかと思います。このpublicVariableとは、変数を”全ての”クライアントに配信するコマンドです。なぜこのような処理が必要かというと、上の例で挙げたAltis島のKavalaとMolos間には直線距離でも20km以上の距離があり、Molosで対空砲が破壊された際にKavalaにいたプレーヤーが破壊を検知できない可能性があるためです。(もしかするとBIが、ユーザーによって変数名が指定したオブジェクトに対しては、ステータスを優先定期にブロードキャストするようなアルゴリズムを組んでいるかもしれませんが…)

またJIP(途中参加)プレイヤーも同じように、参加直後にトリガーの状態を正しく受信できないことがありますが、publicvariableを噛ませることによって、正しく動作させることが出来ます。

まとめますと、タスクなどの重要な情報を処理する際には、publicvariable等のコマンドを使用して、全てのプレイヤーが共有出来るようにすることが重要です。
逆に入れると困るシチュエーションも無くは無いですが例外としておきます。publicvariableコマンド自体はよほど長いデータを配信しない限り重くならないはずなので、盲目的に入れてしまって問題ないと思います。

2.イベントスクリプトでの処理

イベントスクリプトとは、BIによってファイルの名前と配置する位置(ミッションフォルダのルートディレクトリ)が決められており、決められた時にだけ実行されるスクリプトのことです。初めて聞く方もいるかもしれませんが、init.sqfファイルがこれにあたります。init.sqfは、ブリーフィング画面に入る前にサーバー及びクライアントで読み込まれるスクリプトです。この他にもいくつかイベントスクリプトがあるので、4つご紹介いたします。
initServer…ブリーフィング画面に入る前にサーバーのみで読み込まれるスクリプト
initPlayerServer…クライアントがミッションに参加したとき(ミッションスタート時のクライアントとJIPの両方)に、サーバーのみで読み込まれるスクリプト(チケット制PvPに便利?)
initPlayerLocal…クライアントがミッションに参加したとき(ミッションスタート時のクライアントとJIPの両方)に、そのクライアントのみで読み込まれるスクリプト
onPlayerRespawn…クライアントがリスポーンしたときにそのクライアントのみで読み込まれるスクリプト

ちなみに、エディタ上で記述できる各ユニットのinitialization欄のスクリプトは、ミッション参加時(JIP含む)に全てのクライアントとサーバーで読み込まれます。、

また、これらのスクリプトには実行される順番が決められており、複数併用した場合には注意が必要です。

基本的に通常のCOOPミッションでinit.sqf以外を使う機会は無いと思いますが、もし使う場合は実行されるタイミングと、サーバーで実行されるのかクライアントで実行されるのか、JIPに対応しているのか、という点に気を付けて選定してください。

3.スクリプトのグローバル効果

スクリプトコマンドには、効果がグローバルに反映される(=全てのクライアントで反映される)ものと、ローカルなもの(スクリプトを実行したクライアントだけで反映される)があります。スクリプトがグローバルなのかローカルなのかは、Bikiスクリプトコマンドの各ページに記載されています。(コマンド名の下のアイコンの一番右のやつ)
例として、addMagazineCargoaddMagazineCargoGlobalを比較してみます。前者がローカル、後者がグローバルなコマンドです。(Arma3以前の作品では挙動の違いあり)名前から非常に似ていますね。これらはどちらも車輛や弾薬箱などのイベントリ内にマガジンを追加するコマンドですが、前述のとおり、addMagazineCargoではコマンドを実行したクライアントのみでマガジンが追加され、addMagazineCargoGlobalは参加している全てのクライアントでマガジンが追加されます。

ここで注意しなければならないのが、グローバルエフェクトを持つコマンドを全てのクライアントで実行すべきでない場合がある点です。例えばグローバルなaddMagazineCargoGlobalコマンドをinit.sqfに記述してしまうと(init.sqfに書くことは無いと思いますが…)、全てのクライアントで設定した数のマガジンが生成されてしまいます。より具体的にいうと、STANAGを10本追加するように設定していて、30人のプレイヤーが参加していた場合、1つのイベントリに300本のSTANAGが追加されてしまう、という状態になってしまいます。もっと危険な例を挙げると、同じくグローバルなcreatUnitコマンドでこれをやらかしてしまうと、敵の増援が設定した人数×参加しているプレイヤーの人数分召喚されてしまい、味方は阿鼻叫喚状態になってしまいます。

これを避けるためには、サーバーのみで実行するようなコマンドを追加する必要があります。とり鯖で一般的に使用されている、イベントリにマガジン等を追加するスクリプトの頭には、if (!isServer) exitWith {};というコマンドがついていると思います。これは、もしそのスクリプトがサーバー以外で実行されていたら、{}内のスクリプトを実行するという記述で、{}内には何も入っていないため、何もせずに終了する、という動作をします。つまり、サーバーでない=クライアントで読み込まれた場合、1行目でスクリプトが停止するので、適切な数の弾薬を詰めることが出来ます。

逆にテレポートスクリプトなど、サーバー側で実行されると困る場合もあります。その場合は、クライアントでなければスクリプトを停止する、という意味でif !(local player) exitwith {};という構文を追加すれば、クライアントのみで読み込まれるようになります。

まとめますと、スクリプトコマンドには効果がグローバルに反映されるものとローカルで反映されるものがあり、グローバルエフェクトのコマンドを使用する場合には、どこで処理を行うのか考えてスクリプトファイルを作り必要がある、ということです。

いかがでしたか?文章を書くのは好きなのですが文才が無く乱雑で読みにくくてスミマセン…
少しでもエディタの皆様のお役にたてれば幸いです。

  • この返信は10年、 5ヶ月前にアバター画像michy_REV19が編集しました。理由: ☆超☆絶☆読み辛いのを修正