パーティーとロビーの統合
PlayFab ロビーと PlayFab パーティーは、多くの場合、ネットワークセッションに参加させる前にプレイヤーのグループを作成および調整するために一緒に使用されます。 この記事では、C++ パーティー ライブラリと C++ マルチプレイヤー ライブラリを使用してパーティー ネットワーク記述子を共有するための便利なメカニズムとしてロビーを使用する方法について説明します。
パーティーおよびマルチプレイヤー SDK を設定する
開始するには、「パーティーとロビーのクイックスタート」を参照してください。
Party
ロビー
PlayFab マルチプレイヤー SDK を初期化する
PlayFab マルチプレイヤー SDK を初期化するには「ロビーのクイックスタート」を参照してください。
シリアル化されたネットワーク記述子文字列を使用してロビーを作成する
ロビーを作成し、パーティー ネットワーク記述子を設定して、ロビーのプロパティでパーティー ネットワーク記述子をテキスト形式で設定します。 Party ネットワーク記述子を char 文字列に変換するには、PartyManager::SerializeNetworkDescriptor() を使用します。
以下の定義は、ロビーのプロパティと、検索に使用されるキーと値です。
const char* c_propertyKey_LobbyName{ "LobbyName" };
const char* c_propertyKey_PartyDescriptor{ "PartyDescriptor" };
const char* c_searchKey_LobbyGroup{ "string_key1" }; // For Key to identify lobby group
const char* c_searchValue_LobbyGroup{ "PartySample" }; // Use a identifiable string for search lobby group
// The reason for setting this value is to get the lobby name only from the search results,
// and in practice, change it appropriately for the your game.
const char* c_searchKey_LobbyName{ "string_key2" };
- PFMultiplayerCreateAndJoinLobby に電話します。
- PFMultiplayerStartProcessingLobbyStateChanges を定期的にポーリングして、PFLobbyCreateAndJoinLobbyCompletedStateChange を確認し、非同期完了を確認します。
char descriptor[c_maxSerializedNetworkDescriptorStringLength + 1] = {};
// Serialize our local network descriptor for other peers to use
PartyError err = PartyManager::SerializeNetworkDescriptor(&networkDescriptor, descriptor);
if (PARTY_FAILED(err))
{
// handle immediate create failure
DEBUGLOG("SerializeNetworkDescriptor failed! %s\n", GetErrorMessage(err));
return false;
}
std::vector<const char*> lobbyPropertyKeys;
std::vector<const char*> lobbyPropertyValues;
lobbyPropertyKeys.push_back(c_propertyKey_LobbyName);
lobbyPropertyValues.push_back(lobbyName);
lobbyPropertyKeys.push_back(c_propertyKey_PartyDescriptor);
lobbyPropertyValues.push_back(descriptor);
std::vector<const char*> searchPropertyKeys;
std::vector<const char*> searchPropertyValues;
searchPropertyKeys.push_back(c_searchKey_LobbyGroup);
searchPropertyValues.push_back(c_searchValue_LobbyGroup);
searchPropertyKeys.push_back(c_searchKey_LobbyName);
searchPropertyValues.push_back(lobbyName);
PFLobbyCreateConfiguration lobbyConfiguration{};
lobbyConfiguration.maxMemberCount = 16;
lobbyConfiguration.ownerMigrationPolicy = PFLobbyOwnerMigrationPolicy::Automatic;
lobbyConfiguration.accessPolicy = PFLobbyAccessPolicy::Public;
lobbyConfiguration.lobbyPropertyCount = static_cast<uint32_t>(lobbyPropertyKeys.size());
lobbyConfiguration.lobbyPropertyKeys = lobbyPropertyKeys.data();
lobbyConfiguration.lobbyPropertyValues = lobbyPropertyValues.data();
lobbyConfiguration.searchPropertyCount = static_cast<uint32_t>(searchPropertyKeys.size());
lobbyConfiguration.searchPropertyKeys = searchPropertyKeys.data();
lobbyConfiguration.searchPropertyValues = searchPropertyValues.data();
PFLobbyJoinConfiguration memberConfiguration{};
PFLobbyHandle lobby;
HRESULT hr = PFMultiplayerCreateAndJoinLobby(m_pfmHandle, &userEntity, &lobbyConfiguration, &memberConfiguration, nullptr, &lobby);
if (FAILED(hr))
{
// handle immediate create failure
DEBUGLOG("PFMultiplayerCreateAndJoinLobby failed! %s\n", PFMultiplayerGetErrorMessage(hr));
return false;
}
// NOTE: to simplify this quickstart, we'll synchronously block waiting waiting for the CreateAndJoinLobby operation
// to finish. In a real implementation, this polling would be done asynchronously on a background thread/worker.
bool createAndJoinLobbyFinished = false;
while (!createAndJoinLobbyFinished)
{
uint32_t lobbyStateChangeCount;
const PFLobbyStateChange* const* lobbyStateChanges;
HRESULT hr = PFMultiplayerStartProcessingLobbyStateChanges(m_pfmHandle, &lobbyStateChangeCount, &lobbyStateChanges);
if (FAILED(hr))
{
// handle the failure
DEBUGLOG("PFMultiplayerStartProcessingLobbyStateChanges failed! %s\n", PFMultiplayerGetErrorMessage(hr));
return false;
}
for (uint32_t i = 0; i < lobbyStateChangeCount; ++i)
{
const PFLobbyStateChange* stateChange = lobbyStateChanges[i];
switch (stateChange->stateChangeType)
{
case PFLobbyStateChangeType::CreateAndJoinLobbyCompleted:
{
auto createAndJoinStateChange =
static_cast<const PFLobbyCreateAndJoinLobbyCompletedStateChange*>(stateChange);
if (SUCCEEDED(createAndJoinStateChange->result))
{
// lobby successfully created!
DEBUGLOG("Lobby 0x%p successfully created!\n", createAndJoinStateChange->lobby);
}
createAndJoinLobbyFinished = true;
break;
}
}
}
hr = PFMultiplayerFinishProcessingLobbyStateChanges(m_pfmHandle, lobbyStateChangeCount, lobbyStateChanges);
if (FAILED(hr))
{
DEBUGLOG("PFMultiplayerFinishProcessingLobbyStateChanges failed! %s\n", PFMultiplayerGetErrorMessage(hr));
return false;
}
}
ロビーを検索する
[ロビーの検索] を使用する方法の詳細については、次のリンクをご利用ください: ロビーの検索
これで、ロビー検索 API を使用して、c_searchValue_LobbyType
を使用して上記で作成されたロビーを検索し、シリアル化されたネットワーク記述子を取得できるようになります。
- PFMultiplayerFindLobbies を呼び出す
std::string filterString;
filterString.append(c_searchKey_LobbyGroup);
filterString.append(" eq '");
filterString.append(c_searchValue_LobbyGroup);
filterString.append("'");
PFLobbySearchConfiguration searchConfiguration = { 0 };
searchConfiguration.filterString = filterString.c_str();
HRESULT hr = PFMultiplayerFindLobbies(m_pfmHandle, &localUser, &searchConfiguration, nullptr);
if (FAILED(hr))
{
// handle immediate find lobbies failure
printf("PFMultiplayerFindLobbies failed! %s\n", PFMultiplayerGetErrorMessage(hr));
return false;
}
// NOTE: to simplify this quickstart, we'll synchronously block waiting waiting for the FindLobbies operation
// to finish. In a real implementation, this polling would be done asynchronously on a background thread/worker.
bool findLobbiesFinished = false;
while (!findLobbiesFinished)
{
uint32_t lobbyStateChangeCount;
const PFLobbyStateChange* const* lobbyStateChanges;
HRESULT hr = PFMultiplayerStartProcessingLobbyStateChanges(m_pfmHandle, &lobbyStateChangeCount, &lobbyStateChanges);
if (FAILED(hr))
{
// handle the failure
printf("PFMultiplayerStartProcessingLobbyStateChanges failed! %s\n", PFMultiplayerGetErrorMessage(hr));
return false;
}
for (uint32_t i = 0; i < lobbyStateChangeCount; ++i)
{
const PFLobbyStateChange* stateChange = lobbyStateChanges[i];
switch (stateChange->stateChangeType)
{
case PFLobbyStateChangeType::FindLobbiesCompleted:
{
auto findLobbiesStateChange =
static_cast<const PFLobbyFindLobbiesCompletedStateChange*>(stateChange);
if (FAILED(findLobbiesStateChange->result))
{
printf("PFLobbyStateChangeType::FindLobbiesCompleted failed! %s\n", PFMultiplayerGetErrorMessage(findLobbiesStateChange->result));
break;
}
for (uint32_t i = 0; i < findLobbiesStateChange->searchResultCount; ++i)
{
const PFLobbySearchResult& searchResult = findLobbiesStateChange->searchResults[i];
// Use searchResult.connectionString for connecting a lobby later.
MyGame::GuiPostLobbySearchResultRow(searchResult); // defined elsewhere
}
findLobbiesFinished = true;
break;
}
}
}
hr = PFMultiplayerFinishProcessingLobbyStateChanges(m_pfmHandle, lobbyStateChangeCount, lobbyStateChanges);
if (FAILED(hr))
{
printf("PFMultiplayerFinishProcessingLobbyStateChanges failed! %s\n", PFMultiplayerGetErrorMessage(hr));
return false;
}
ロビーに参加する
次に、PFLobbySearchResult の一部である connectionString を使用して、前の "ロビーの検索" 操作から取得したロビーに参加します。
- PFMultiplayerJoinLobby を呼び出す
// Fill in the member properties of user for referencing in the game.
const char* playerColorPropertyKey = "PlayerColor";
const char* playerColorPropertyValue = MyGame::GetPlayerColorString(localUser);
std::vector<const char*> memberPropertyKeys;
std::vector<const char*> memberPropertyValues;
memberPropertyKeys.push_back(playerColorPropertyKey);
memberPropertyValues.push_back(playerColorPropertyValue);
PFLobbyJoinConfiguration joinConfig;
joinConfig.memberPropertyCount = static_cast<uint32_t>(memberPropertyKeys.size());
joinConfig.memberPropertyKeys = memberPropertyKeys.data();
joinConfig.memberPropertyValues = memberPropertyValues.data();
// Join the lobby using the connection string
HRESULT hr = PFMultiplayerJoinLobby(m_pfmHandle, &localUser, connectionString, &joinConfig, nullptr, &m_lobby);
if (FAILED(hr))
{
// handle immediate join lobby failure
DEBUGLOG("PFMultiplayerJoinLobby failed! %s\n", PFMultiplayerGetErrorMessage(hr));
return false;
}
// NOTE: to simplify this quickstart, we'll synchronously block waiting waiting for the JoinLobby operation
// to finish. In a real implementation, this polling would be done asynchronously on a background thread/worker.
bool joinLobbyFinished = false;
while (!joinLobbyFinished)
{
uint32_t lobbyStateChangeCount;
const PFLobbyStateChange* const* lobbyStateChanges;
HRESULT hr = PFMultiplayerStartProcessingLobbyStateChanges(m_pfmHandle, &lobbyStateChangeCount, &lobbyStateChanges);
if (FAILED(hr))
{
// handle the failure
DEBUGLOG("PFMultiplayerStartProcessingLobbyStateChanges failed! %s\n", PFMultiplayerGetErrorMessage(hr));
return false;
}
for (uint32_t i = 0; i < lobbyStateChangeCount; ++i)
{
const PFLobbyStateChange* stateChange = lobbyStateChanges[i];
switch (stateChange->stateChangeType)
{
case PFLobbyStateChangeType::JoinLobbyCompleted:
{
auto joinStateChange =
static_cast<const PFLobbyJoinLobbyCompletedStateChange*>(stateChange);
if (SUCCEEDED(joinStateChange->result))
{
// lobby successfully joined!
m_lobby = joinStateChange->lobby;
uint32_t propertyCount;
const char* const* keys;
HRESULT hr = PFLobbyGetLobbyPropertyKeys(joinStateChange->lobby, &propertyCount, &keys);
if (SUCCEEDED(hr))
{
std::string descriptor;
for (uint32_t idx = 0; idx < propertyCount; idx++)
{
const char* value;
hr = PFLobbyGetLobbyProperty(joinStateChange->lobby, keys[idx], &value);
if (SUCCEEDED(hr))
{
if (strcmp(keys[idx], c_propertyKey_PartyDescriptor) == 0 && value)
{
descriptor = value;
}
}
}
if (!descriptor.empty())
{
partyDescriptor = descriptor;
}
else
{
// report asynchronous failure
DEBUGLOG("Failed to join lobby 0x%p! No Party descriptor found\n",
joinStateChange->lobby);
}
}
}
joinLobbyFinished = true;
break;
}
}
}
hr = PFMultiplayerFinishProcessingLobbyStateChanges(m_pfmHandle, lobbyStateChangeCount, lobbyStateChanges);
if (FAILED(hr))
{
DEBUGLOG("PFMultiplayerFinishProcessingLobbyStateChanges failed! %s\n", PFMultiplayerGetErrorMessage(hr));
return false;
}
}
次の手順
パーティー ネットワークに接続するには、「パーティーのクイックスタート: パーティー ネットワークに接続する」を参照してください。