Party 및 Multiplayer SDK 설정
시작하려면 Party 및 Lobby 빠른 시작을 참조하세요.Party
Party QuickstartLobby
Lobby QuickstartPlayFab Multiplayer SDK 초기화
PlayFab Multiplayer SDK 초기화는 Lobby Quickstart를 참조하세요.직렬화된 네트워크 설명자 문자열로 lobby 생성
Party 네트워크 설명자를 텍스트 형식으로 lobby 속성에 설정하여 lobby를 만듭니다. Party 네트워크 설명자를 char 문자열로 변환하려면 PartyManager::SerializeNetworkDescriptor()를 사용합니다. 아래 define들은 Lobby 속성과 검색에 사용되는 키 및 값입니다.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 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;
}
}
Lobby 찾기
Lobby 찾기 사용 방법에 대한 자세한 내용은 다음 링크를 사용하세요. Lobby 찾기 이제 Find Lobbies API를 사용하여 위에서 생성된 lobby를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 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;
}
Lobby 참가
이제 이전 “Find Lobbies” 작업에서 얻은 PFLobbySearchResult의 일부인 connectionString을 사용하여 lobby에 참가합니다.- 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 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;
}
}
다음 단계
Party 네트워크에 연결하려면 Party Quickstart: Connect to a Party network를 자세히 읽어보세요.함께 보기
Party SDK
- Party features
- Party SDKs
- Multiplayer Services
- Party objects and their relationships
- Party API reference documentation
