マッチング

Room::stateMatch()

フレームワークでは何をもってマッチング完了とするかは分からないので、アプリケーションで通知する必要がある。

これを行う関数が、Room::stateMatch() である。

SampleRoom::match

stateMatch を呼ぶ他に、サンプルアプリケーション特有のマッチング完了処理を実装したのが SampleRoom::match 関数である。マッチング時に SampleRoomModule から呼んでもらうことを想定している。

bool SampleRoom::match()
{
   const SampleRoomServerInfo* pS = getSampleServerInfo();

   bool ret = false;
   lock();
   {
      const std::vector< const RoomMemberInfo* > v = getMembers();
      for (int i=0; i<v.size(); ++i) {
         if (v[i]->hSession.isNull()) { goto fin; }
      }
      if (! stateMatch()) {
         goto fin;
      }

      for (int i=0; i<v.size(); ++i) {
         std::ostringstream o;
         o << pS->salt << ':' << i << ':' << v[i]->hSession.account()->id();
         mutableMemberInfo(i)->secret = o.str();
      }
   }
   ret = true;

  fin:
   unlock();
   return ret;
}
match() の処理は次の三段階に分かれている:
  1. 満員かどうかの確認
  2. stateMatch 呼び出し
  3. ゲーム開始に使うシークレット情報の生成

満員かどうかの確認は、別にやらなくてもよいのだが、確認のために実装してある。

stateMatch は前節で説明したように、部屋をマッチング状態へ移す処理である。

最後にシークレット情報を生成している。これはこのサンプル特有の仕様であって、マッチング完了時の本質的な処理ではない。

シークレット情報の使い方は、ゲームへの案内の節で説明する。ここでは単にシークレット情報を生成していることを認識してもらえればよい。

マッチング完了判定

サンプルでは、部屋の人数がいっぱいになったことをもってマッチング完了としている。

部屋がいっぱいになるのは、誰かが部屋に入室した場合にのみ起きる。よって、EnterRoom の処理でマッチング判定を行っている。

bool SampleRoomModule::handleEnterRoom(Room* _pRoom, EnterRoomRequest* pMsg, ResponseMessage* pRes, SessionHandle& hSession)
{
  ...
      if (pRoom->countMembers() == pRoom->getMemberSize()) {
         if (! pRoom->match()) {
            pRoom->leave(hSession);
            pRes->setResult(ResponseMessage::ERR_INTERNAL);
            break;
         }
      }
  ...
}

if の条件節は、Room::countMembers() と Room::getMemberSize() が一致した時である。 countMembers() は現在の入室人数を返す関数で、getMemberSize() は部屋に入れる最大人数を返す関数である。これらが同値であるということは、すなわち部屋が満員であることであり、マッチング完了である。

続いて SampleRoom::match() を呼ぶ。これは上で説明したように、部屋をマッチング状態へ移す。

この時の返り値を判定し、SampleRoom::match() が失敗した時には入室そのものを失敗するようにしている。

またこのサンプルでは、部屋を開いた時にはその人を入室するようにしている。 もし部屋の最大人数が一人の場合はここでもマッチング完了となるので、そのためのコードが入っている。

bool SampleRoomModule::handleOpenRoom(Room* _pRoom, OpenRoomRequest* pMsg, ResponseMessage* pRes, SessionHandle& hSession)
{
   ...

      if (pRoom->countMembers() == pRoom->getMemberSize()) {
         if (! pRoom->match()) {
            pRoom->leave(hSession);
            goto err;
         }
      }
   ...
}

やっていることは EnterRoom と変わらない。