MPにおけるデータ位置について -ArmA訓練所-

ArmA訓練所
2007/09/26

目次


データ位置とは

MPにおけるデータ位置(原題はLocality in Multiplayer)とは、OFPやArmAのMPにおいて、
それぞれのデータがどのコンピュータで管理され、どのように他のコンピュータに伝えられるかを示したものです。
和訳しても分かりづらい内容もあるので、和訳と私なりの解釈を踏まえた内容にしたいと思います。

まずはじめに、ローカルとリモートの概念があります。
ローカルとは、あるコンピュータ上にデータや処理の中枢が存在していることを指し、
リモートとは、あるコンピュータ上にデータや処理の中枢が存在せず、
別のコンピュータの処理結果をネットワークで受信することに依存していることを指します。

基本的なルール(Basic Rules)

MPにおけるデータ位置について言える基本的なルールは次のようになっています。

サーバー(server) = Dedicated ServerかHostセッションを立ち上げたクライアントを指します。
クライアント(client) = ゲーム中のそれぞれの異なるプレイヤーを担当するコンピュータを指します。 これはプレイヤー毎に異なります。

異なるデータ位置の影響(Effects of different localities)

ユニットのデータ位置を知ることはローカルユニットにだけ影響を与えるコマンドのようにとても重要です。(BIwikiのmoveInDriverの例を参照)
ローカルな効果しか持たない他のコマンドは、コマンドが実行されたコンピュータ以外には何も影響しないでしょう。(BIwikiのsetFogの例を参照)

ユニットは生きている間にデータ位置が変わることがあります。
典型的なケースはプレイヤーが死ぬこと(そのsquadのAIユニットはサーバーに送られる)、
joinコマンドを使うこと、あるいはユニットやプレイヤーが乗り物に乗ったり降りたりすることです。

補足

上記の内容はほぼBIwikiの和訳です。
ただ、それだけでは分かりづらいのでいくつか代表的な例や注意点を挙げて補足したいと思います。

効果が全体に及ばないもの

先の例にsetFogの例がありました。
このコマンドはコマンドが実行されたコンピュータのみに効果があり、実行されなかったコンピュータには全く影響がありません。
たとえばMPミッションで二人の操作可能なプレイヤーを用意しておき、一人にunitA、もう一人にはunitBと名前を付けておきましょう。
トリガーのCondition欄に「player == unitA」という条件を指定し、On Act欄には「10 setFog 1」などと書いてみましょう。
この条件でMPで二人のプレイヤーが同時にミッションを開始すると、unitAを選んだ人だけ濃い霧が発生し、
unitBを選んだ人は霧が発生しないまま同じミッションをプレイすることになります。
つまり、霧が出ているかどうかはプレイヤー次第と言うことが出来ます。
この現象について、不公平だとかチートの温床だという声も否定は出来ませんが、これには利点もあるのです。

ミッションマップ上で北部は霧が濃い地域、南部は霧がほとんど発生しない地域だという設定を考えてみましょう。
誰かが北へ行けば霧が濃くなりますが、この処理をまだ南の方にいるプレイヤーにも適用してしまうと違和感があります。
こうしたプレイヤーによって個別に処理を分けることのメリットを理解することは決して悪いことではないと思います。

効果が全体に及ぶもの

setFogのように一部のプレイヤーにしか効果が現れないコマンドもあれば、MPに参加しているすべてのプレイヤーに効果が現れるものもあります。
このタイプでよく見かけるバグの例はcreateVehicleコマンドによるユニットの大量発生です。
このコマンドを実行するとその実行結果が全体に伝わるようになっています。
理解が難しいところですが、1つのDedicated Serverと5人のプレイヤーがいて、それぞれのサーバーとクライアントでcreateVehicleが実行されると、
6回createVehicleを実行した結果が全体に現れることになります。
ヘリを一機呼び出すつもりが複数現れたりする場合はこの現象に依るものです。
Hostセッションで一人でテストする場合は問題になりませんが、複数のプレイヤーがいる環境で問題になりますので、注意が必要です。
この問題を回避するには後述のサーバーによるデータ管理の項目を参照してください。

サーバーによるデータ管理

MPでCTFやFFのフラッグのスコアを扱ったり、createVehicleのようなプレイヤー数に依らず1回しかコマンドを実行したくない場合の方法を紹介します。

ArmAでは途中参加できるようになったため、スクリプト中の変数の値がミッション開始時点からいた人と途中参加した人とで同期が取れなくなります。
ミッション開始時点からいた人はすでに10ポイント取得したことになっていても、途中参加した人はみんな0ポイントの状態に見えるのです。
このままゲームを続けると、味方と敵のどちらが何ポイント勝っているかという判断がプレイヤー毎に異なってしまいます。
こうしたスコアはプレイヤー毎に管理されるのではなく、サーバーで中央管理すべきです。
そのため、スコア処理をサーバーだけで実行する必要があります。
では、どうすればスクリプトをサーバーだけで実行させることが出来るでしょうか。
setFogの例ではあるプレイヤーのみに処理を実行させることは出来ましたが、
スコア処理をunitAのように名前を付けた特定のプレイヤーユニットに任せる方法は、出入りが自由なMPミッションでは現実的ではありません。
便利な方法はisServerコマンドを使う方法です。
isServerは実行されたコンピュータがMPにおいてサーバーであるか、SPミッションを実行しているときにtrueを返します。
isServerがtrueのときスクリプトの処理を行うようにすればよいのです。
ただし、isServerコマンドはArmA 1.06から追加されたコマンドですので、それ以前のバージョンやOFPの場合はGameLogicを使う方法を利用します。
エディターで配置可能なGameLogicはサーバー上で常にローカルであるため、「local GameLogic名」がtrueのときスクリプトの処理を行うようにすればよいのです。
こうしたコマンドを利用してスクリプトをサーバーだけが実行するようにします。
ただし、これだけではフラッグのスコアをサーバーが保持するだけで、他のコンピュータはスコアを把握できません。
hintコマンド、cutTextやtitleTextコマンドでスコアを表示するためには各自のコンピュータにスコアデータを配信しなければなりません。
そのため、サーバーが持っているスコアをpublicVariableコマンドを使って全員のプレイヤーに配信します。
間違っても各クライアントのデータをpublicVariableしてはいけません。
サーバーでデータを管理する意味が無くなってしまいます。

ここまで読んだのであれば答えは見えていると思いますが、createVehicleを実行するときも
isServerコマンドか「local GameLogic名」を使ってサーバーのみに処理を実行させるようにすべきです。
こうすることでユニットの作りすぎを防ぐことが出来ます。

目標達成状況の同期

ミッション目標の達成状況も途中参加によって同期されません。
ブリーフィングメニューの目標にチェックが付いている人と付いていない人が発生することがあるのはこのためです。
目標の達成や失敗を扱うには、その変化をもたらす処理の条件文にフラグ(trueかfalseをもつ変数)を使います。
そしてonPlayerConnectedコマンドを利用すると良いでしょう。
このコマンドはプレイヤーが途中参加したときにサーバーでのみ処理を実行するもので、
このコマンドを利用して目標の達成状況を管理するフラグをpublicVariableコマンドで配信します。
こうすることで途中参加した人もミッションの達成状況がどのようになっているのかを正しく把握することが出来ます。


Homeへ