オンラインサブシステムを使用してプレイヤーをフレンド解除しブロックする - フレンドを管理する - (Unreal Engine モジュール)
注釈:本資料はAI技術を用いて翻訳されています。
サブシステムの展開
このセクションでは、AccelByte Gaming Services (AGS) Online Subsystem (OSS) を使用して、フレンドの解除、プレイヤーのブロック、プレイヤーのブロック解除、およびブロックされたプレイヤーリストの取得機能を実装する方法を学びます。Byte Wars プロジェクトには、ManagingFriendsSubsystem という名前の Game Instance Subsystem がすでに作成されています。このサブシステムには、フレンド管理関連の機能が含まれています。このチュートリアルでは、そのサブシステムのスターター版を使用して、フレンド管理関連の機能をゼロから実装できるようにします。
スターターパックの内容
このチュートリアルを進めるために、ManagingFriendsSubsystem_Starter という名前のスターターサブシステムクラスが用意されています。このクラスはリソースセクションで入手でき、以下のファイルで構成されています:
- ヘッダーファイル:
/Source/AccelByteWars/TutorialModules/Social/ManagingFriends/ManagingFriendsSubsystem_Starter.h - CPP ファイル:
/Source/AccelByteWars/TutorialModules/Social/ManagingFriends/ManagingFriendsSubsystem_Starter.cpp
ManagingFriendsSubsystem_Starter クラスには、以下のいくつかの機能も提供されています:
-
AGS OSS インターフェースの宣言:
FriendsInterfaceとUserInterface。これらのインターフェースを使用して、後でフレンド管理関連の機能を実装します。protected:
// ...
FOnlineUserAccelBytePtr UserInterface;
FOnlineFriendsAccelBytePtr FriendsInterface; -
PlayerControllerからUniqueNetIdを取得するヘルパー関数。上記の AGS OSS インターフェースにこれらのヘルパーが必要になります。FUniqueNetIdPtr UManagingFriendsSubsystem_Starter::GetUniqueNetIdFromPlayerController(const APlayerController* PC) const
{
if (!PC)
{
return nullptr;
}
ULocalPlayer* LocalPlayer = PC->GetLocalPlayer();
if (!LocalPlayer)
{
return nullptr;
}
return LocalPlayer->GetPreferredUniqueNetId().GetUniqueNetId();
} -
PlayerControllerからLocalUserNumを取得するヘルパー関数。これらのヘルパーも後で AGS OSS インターフェースに必要になります。int32 UManagingFriendsSubsystem_Starter::GetLocalUserNumFromPlayerController(const APlayerController* PC) const
{
int32 LocalUserNum = 0;
if (!PC)
{
return LocalUserNum;
}
const ULocalPlayer* LocalPlayer = PC->GetLocalPlayer();
if (LocalPlayer)
{
LocalUserNum = LocalPlayer->GetControllerId();
}
return LocalUserNum;
}
スターターサブシステムに加えて、/Source/AccelByteWars/TutorialModules/Social/FriendsEssentials/FriendsEssentialsModels.h ファイルには定数とデリゲートが用意されています。そのファイルには以下が含まれています:
-
ブロックされたプレイヤーのデータのキャッシュが完了したときのコールバックとして使用されるデリゲート。
// ...
DECLARE_DELEGATE_ThreeParams(FOnGetBlockedPlayerListComplete, bool /*bWasSuccessful*/, TArray<UFriendData*> /*BlockedPlayers*/, const FString& /*ErrorMessage*/);
DECLARE_DELEGATE(FOnGetCacheBlockedPlayersDataUpdated); -
フレンド解除プロセス、プレイヤーブロックプロセス、およびプレイヤーブロック解除プロセスが完了したときのコールバックとして使用されるデリゲート。
// ...
DECLARE_DELEGATE_TwoParams(FOnUnfriendComplete, bool /*bWasSuccessful*/, const FString& /*ErrorMessage*/);
DECLARE_DELEGATE_TwoParams(FOnBlockPlayerComplete, bool /*bWasSuccessful*/, const FString& /*ErrorMessage*/);
DECLARE_DELEGATE_TwoParams(FOnUnblockPlayerComplete, bool /*bWasSuccessful*/, const FString& /*ErrorMessage*/);
ブロックされたプレイヤーの取得を実装する
このセクションでは、ブロックされたプレイヤーリストを取得する機能を実装します。
-
ManagingFriendsSubsystem_Starterクラスのヘッダーファイルを開き、以下の関数を宣言します:public:
// ...
void GetBlockedPlayerList(const APlayerController* PC, bool bQueryUserInfo, const FOnGetBlockedPlayerListComplete& OnComplete = FOnGetBlockedPlayerListComplete()); -
上記の関数の定義を作成します。
ManagingFriendsSubsystem_Starterクラスの CPP ファイルを開き、以下のコードを追加します。ブロックされたプレイヤーリストを取得する基本的な流れは、バックエンドからリストをクエリすることです。完了すると、ブロックされたプレイヤーリストがローカルにキャッシュされます。void UManagingFriendsSubsystem_Starter::GetBlockedPlayerList(const APlayerController* PC, bool bQueryUserInfo, const FOnGetBlockedPlayerListComplete& OnComplete)
{
if (!ensure(FriendsInterface))
{
UE_LOG_MANAGING_FRIENDS(Warning, TEXT("Cannot cache blocked player list. Friends Interface is not valid."));
return;
}
const int32 LocalUserNum = GetLocalUserNumFromPlayerController(PC);
const FUniqueNetIdPtr PlayerNetId = GetUniqueNetIdFromPlayerController(PC);
// Try to get cached blocked player list first.
TArray<TSharedRef<FOnlineBlockedPlayer>> CachedBlockedPlayerList;
if (FriendsInterface->GetBlockedPlayers(PlayerNetId->AsShared().Get(), CachedBlockedPlayerList))
{
if(bQueryUserInfo)
{
// Then, update the cached blocked players' information by querying their user information.
TPartyMemberArray BlockedPlayerIds;
for (const TSharedRef<FOnlineBlockedPlayer>& CachedBlockedPlayer : CachedBlockedPlayerList)
{
BlockedPlayerIds.Add(CachedBlockedPlayer.Get().GetUserId());
}
// Query blocked players' user information.
if (UStartupSubsystem* StartupSubsystem = GetWorld()->GetGameInstance()->GetSubsystem<UStartupSubsystem>())
{
StartupSubsystem->QueryUserInfo(
LocalUserNum,
BlockedPlayerIds,
FOnQueryUsersInfoCompleteDelegate::CreateWeakLambda(this, [this, PlayerNetId, OnComplete, LocalUserNum](
const FOnlineError& Error,
const TArray<TSharedPtr<FUserOnlineAccountAccelByte>>& UsersInfo)
{
/* Refresh blocked players data with queried blocked players' user information.
* Then, return blocked players to the callback. */
TArray<UFriendData*> BlockedPlayers{};
TArray<TSharedRef<FOnlineBlockedPlayer>> NewCachedBlockedPlayerList;
FriendsInterface->GetBlockedPlayers(PlayerNetId->AsShared().Get(), NewCachedBlockedPlayerList);
for (const TSharedRef<FOnlineBlockedPlayer>& NewCachedBlockedPlayer : NewCachedBlockedPlayerList)
{
// Update blocked player's avatar URL based on queried friend's user information.
FString UserAvatarURL = TEXT("");
TSharedPtr<FOnlineUser> UserInfo = UserInterface->GetUserInfo(
LocalUserNum, NewCachedBlockedPlayer.Get().GetUserId().Get());
UserInfo->GetUserAttribute(ACCELBYTE_ACCOUNT_GAME_AVATAR_URL, UserAvatarURL);
// Add the updated blocked player to the list.
UFriendData* BlockedPlayer = UFriendData::ConvertToFriendData(NewCachedBlockedPlayer, this);
BlockedPlayer->AvatarURL = UserAvatarURL;
BlockedPlayers.Add(BlockedPlayer);
}
OnComplete.ExecuteIfBound(true, BlockedPlayers, TEXT(""));
}));
}
}
else
{
TArray<UFriendData*> BlockedPlayers;
for (const TSharedRef<FOnlineBlockedPlayer>& TempData : CachedBlockedPlayerList)
{
BlockedPlayers.Add(UFriendData::ConvertToFriendData(TempData, this));
}
OnComplete.ExecuteIfBound(true, BlockedPlayers, TEXT(""));
}
}
// If none, request to backend then get the cached the blocked player list.
else
{
FriendsInterface->ClearOnQueryBlockedPlayersCompleteDelegate_Handle(OnQueryBlockedPlayersCompleteDelegateHandle);
OnQueryBlockedPlayersCompleteDelegateHandle = FriendsInterface->AddOnQueryBlockedPlayersCompleteDelegate_Handle(
FOnQueryBlockedPlayersCompleteDelegate::CreateUObject(this, &ThisClass::OnQueryBlockedPlayersComplete, OnComplete));
FriendsInterface->QueryBlockedPlayers(PlayerNetId->AsShared().Get());
}
}
プレイヤーのブロックを実装する
このセクションでは、プレイヤーをブロックする機能を実装します。プレイヤーをブロックすると、ブロックされたプレイヤーはブロックした人にフレンドリクエストを送信したり、マッチメイキングしたりできなくなります。
-
ManagingFriendsSubsystem_Starterクラスのヘッダーファイルを開き、以下の関数を宣言します。public:
// ...
void BlockPlayer(const APlayerController* PC, const FUniqueNetIdRepl BlockedPlayerUserId, const FOnBlockPlayerComplete& OnComplete = FOnBlockPlayerComplete()); -
また、プレイヤーブロックプロセスが完了したときに処理するコールバック関数を作成する必要があります。
protected:
// ...
void OnBlockPlayerComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& BlockedPlayerUserId, const FString& ListName, const FString& ErrorStr, const FOnBlockPlayerComplete OnComplete); -
上記の関数を定義します。
ManagingFriendsSubsystem_Starterクラスの CPP ファイルを開き、BlockPlayer()関数を定義します。この関数はプレイヤーをブロックし、OnBlockPlayerComplete()関数を呼び出してコールバックを処理します。void UManagingFriendsSubsystem_Starter::BlockPlayer(const APlayerController* PC, const FUniqueNetIdRepl BlockedPlayerUserId, const FOnBlockPlayerComplete& OnComplete)
{
if (!ensure(FriendsInterface) || !ensure(PromptSubsystem))
{
UE_LOG_MANAGING_FRIENDS(Warning, TEXT("Cannot block a player. Friends Interface or Prompt Subsystem is not valid."));
return;
}
PromptSubsystem->ShowLoading(BLOCK_PLAYER_MESSAGE);
const int32 LocalUserNum = GetLocalUserNumFromPlayerController(PC);
OnBlockPlayerCompleteDelegateHandle = FriendsInterface->AddOnBlockedPlayerCompleteDelegate_Handle(LocalUserNum, FOnBlockedPlayerCompleteDelegate::CreateUObject(this, &ThisClass::OnBlockPlayerComplete, OnComplete));
FriendsInterface->BlockPlayer(LocalUserNum, BlockedPlayerUserId.GetUniqueNetId().ToSharedRef().Get());
} -
プレイヤーブロックプロセスが完了したときに呼び出される
OnBlockPlayerComplete()関数を定義します。この関数は、プレイヤーブロックプロセスが成功したかどうかを示すログを出力し、コールバックデリゲートをトリガーします。void UManagingFriendsSubsystem_Starter::OnBlockPlayerComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& BlockedPlayerUserId, const FString& ListName, const FString& ErrorStr, const FOnBlockPlayerComplete OnComplete)
{
PromptSubsystem->HideLoading();
FriendsInterface->ClearOnBlockedPlayerCompleteDelegate_Handle(LocalUserNum, OnBlockPlayerCompleteDelegateHandle);
if (bWasSuccessful)
{
UE_LOG_MANAGING_FRIENDS(Warning, TEXT("Success to block a player."));
PromptSubsystem->ShowMessagePopUp(MESSAGE_PROMPT_TEXT, SUCCESS_BLOCK_PLAYER);
OnComplete.ExecuteIfBound(true, TEXT(""));
}
else
{
UE_LOG_MANAGING_FRIENDS(Warning, TEXT("Failed to block a player. Error: %s"), *ErrorStr);
PromptSubsystem->ShowMessagePopUp(ERROR_PROMPT_TEXT, FText::FromString(ErrorStr));
OnComplete.ExecuteIfBound(false, ErrorStr);
}
}
プレイヤーのブロック解除を実装する
このセクションでは、プレイヤーのブロックを解除する機能を実装します。
-
ManagingFriendsSubsystem_Starterクラスのヘッダーファイルを開き、以下の関数を宣言します:public:
// ...
void UnblockPlayer(const APlayerController* PC, const FUniqueNetIdRepl BlockedPlayerUserId, const FOnUnblockPlayerComplete& OnComplete = FOnUnblockPlayerComplete()); -
また、プレイヤーブロック解除プロセスが完了したときに処理するコールバック関数を作成する必要があります。
protected:
// ...
void OnUnblockPlayerComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& BlockedPlayerUserId, const FString& ListName, const FString& ErrorStr, const FOnUnblockPlayerComplete OnComplete); -
上記の関数を定義します。
ManagingFriendsSubsystem_Starterクラスの CPP ファイルを開き、UnblockPlayer()関数を定義します。この関数はプレイヤーのブロックを解除し、OnUnblockPlayerComplete()関数を呼び出してコールバックを処理します。void UManagingFriendsSubsystem_Starter::UnblockPlayer(const APlayerController* PC, const FUniqueNetIdRepl BlockedPlayerUserId, const FOnUnblockPlayerComplete& OnComplete)
{
if (!ensure(FriendsInterface) || !ensure(PromptSubsystem))
{
UE_LOG_MANAGING_FRIENDS(Warning, TEXT("Cannot unblock a player. Friends Interface or Prompt Subsystem is not valid."));
return;
}
PromptSubsystem->ShowLoading(UNBLOCK_PLAYER_MESSAGE);
const int32 LocalUserNum = GetLocalUserNumFromPlayerController(PC);
OnUnblockPlayerCompleteDelegateHandle = FriendsInterface->AddOnUnblockedPlayerCompleteDelegate_Handle(LocalUserNum, FOnBlockedPlayerCompleteDelegate::CreateUObject(this, &ThisClass::OnUnblockPlayerComplete, OnComplete));
FriendsInterface->UnblockPlayer(LocalUserNum, BlockedPlayerUserId.GetUniqueNetId().ToSharedRef().Get());
} -
プレイヤーブロック解除プロセスが完了したときに呼び出される
OnUnblockPlayerComplete()関数を定義します。この関数は、プレイヤーブロック解除プロセスが成功したかどうかを示すログを出力し、コールバックデリゲートをトリガーします。void UManagingFriendsSubsystem_Starter::OnUnblockPlayerComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& BlockedPlayerUserId, const FString& ListName, const FString& ErrorStr, const FOnUnblockPlayerComplete OnComplete)
{
PromptSubsystem->HideLoading();
FriendsInterface->ClearOnUnblockedPlayerCompleteDelegate_Handle(LocalUserNum, OnUnblockPlayerCompleteDelegateHandle);
if (bWasSuccessful)
{
UE_LOG_MANAGING_FRIENDS(Warning, TEXT("Success to unblock a player."));
PromptSubsystem->ShowMessagePopUp(MESSAGE_PROMPT_TEXT, SUCCESS_UNBLOCK_PLAYER);
OnComplete.ExecuteIfBound(true, TEXT(""));
}
else
{
UE_LOG_MANAGING_FRIENDS(Warning, TEXT("Failed to unblock a player. Error: %s"), *ErrorStr);
PromptSubsystem->ShowMessagePopUp(ERROR_PROMPT_TEXT, FText::FromString(ErrorStr));
OnComplete.ExecuteIfBound(false, ErrorStr);
}
}
フレンド解除を実装する
このセクションでは、フレンドを解除する機能を実装します。
-
ManagingFriendsSubsystem_Starterクラスのヘッダーファイルを開き、以下の関数を宣言します。public:
// ...
void Unfriend(const APlayerController* PC, const FUniqueNetIdRepl FriendUserId, const FOnUnfriendComplete& OnComplete = FOnUnfriendComplete()); -
また、フレンド解除プロセスが完了したときに処理するコールバック関数を作成する必要があります。
protected:
// ...
void OnUnfriendComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& FriendId, const FString& ListName, const FString& ErrorStr, const FOnUnfriendComplete OnComplete); -
上記の関数を定義します。
ManagingFriendsSubsystem_Starterクラスの CPP ファイルを開き、Unfriend()関数を定義します。この関数はフレンドを解除し、OnUnfriendComplete()関数を呼び出してコールバックを処理します。void UManagingFriendsSubsystem_Starter::Unfriend(const APlayerController* PC, const FUniqueNetIdRepl FriendUserId, const FOnUnfriendComplete& OnComplete)
{
if (!ensure(FriendsInterface) || !ensure(PromptSubsystem))
{
UE_LOG_MANAGING_FRIENDS(Warning, TEXT("Cannot unfriend a friend. Friends Interface or Prompt Subsystem is not valid."));
return;
}
PromptSubsystem->ShowLoading(UNFRIEND_FRIEND_MESSAGE);
const int32 LocalUserNum = GetLocalUserNumFromPlayerController(PC);
OnUnfriendCompleteDelegateHandle = FriendsInterface->AddOnDeleteFriendCompleteDelegate_Handle(LocalUserNum, FOnDeleteFriendCompleteDelegate::CreateUObject(this, &ThisClass::OnUnfriendComplete, OnComplete));
FriendsInterface->DeleteFriend(LocalUserNum, FriendUserId.GetUniqueNetId().ToSharedRef().Get(), TEXT(""));
} -
フレンド解除プロセスが完了したときに呼び出される
OnUnfriendComplete()関数を定義します。この関数は、フレンド解除プロセスが成功したかどうかを示すログを出力し、コールバックデリゲートをトリガーします。void UManagingFriendsSubsystem_Starter::OnUnfriendComplete(int32 LocalUserNum, bool bWasSuccessful, const FUniqueNetId& FriendId, const FString& ListName, const FString& ErrorStr, const FOnUnfriendComplete OnComplete)
{
PromptSubsystem->HideLoading();
FriendsInterface->ClearOnDeleteFriendCompleteDelegate_Handle(LocalUserNum, OnUnfriendCompleteDelegateHandle);
if (bWasSuccessful)
{
UE_LOG_MANAGING_FRIENDS(Warning, TEXT("Success to unfriend a friend."));
PromptSubsystem->ShowMessagePopUp(MESSAGE_PROMPT_TEXT, SUCCESS_UNFRIEND_FRIEND);
OnComplete.ExecuteIfBound(true, TEXT(""));
}
else
{
UE_LOG_MANAGING_FRIENDS(Warning, TEXT("Failed to unfriend a friend. Error: %s"), *ErrorStr);
PromptSubsystem->ShowMessagePopUp(ERROR_PROMPT_TEXT, FText::FromString(ErrorStr));
OnComplete.ExecuteIfBound(false, ErrorStr);
}
}
ブロックされたプレイヤーリストの更新をリッスンする
プレイヤーがブロックまたはブロック解除されると、キャッシュされたブロックされたプレイヤーリストは AGS OSS によって自動的に更新されます。このセクションでは、ブロックされたプレイヤーリストが更新されたときに実行されるデリゲートをバインドする方法を学びます。これは、後で表示されるエントリウィジェットを更新する必要がある場合に役立ちます。
-
ManagingFriendsSubsystem_Starterクラスのヘッダーファイルを開き、以下の関数宣言を作成します:public:
// ...
void BindOnCachedBlockedPlayersDataUpdated(const APlayerController* PC, const FOnGetCacheBlockedPlayersDataUpdated& Delegate);
void UnbindOnCachedBlockedPlayersDataUpdated(const APlayerController* PC); -
ManagingFriendsSubsystem_Starterクラスの CPP ファイルを開き、上記の関数の定義を作成します。まずBindOnCachedBlockedPlayersDataUpdated()関数から始めます。void UManagingFriendsSubsystem_Starter::BindOnCachedBlockedPlayersDataUpdated(const APlayerController* PC, const FOnGetCacheBlockedPlayersDataUpdated& Delegate)
{
ensure(FriendsInterface);
const int32 LocalUserNum = GetLocalUserNumFromPlayerController(PC);
// Add on blocked players changed delegate.
OnBlockedPlayersChangeDelegateHandles.Add(LocalUserNum, FriendsInterface->AddOnBlockListChangeDelegate_Handle(LocalUserNum, FOnBlockListChangeDelegate::CreateWeakLambda(this, [Delegate](int32, const FString&) { Delegate.ExecuteIfBound(); })));
} -
UnbindOnCachedBlockedPlayersDataUpdated()関数の定義を作成します。void UManagingFriendsSubsystem_Starter::UnbindOnCachedBlockedPlayersDataUpdated(const APlayerController* PC)
{
ensure(FriendsInterface);
const int32 LocalUserNum = GetLocalUserNumFromPlayerController(PC);
// Clear on blocked players changed delegate.
FDelegateHandle TempHandle = OnBlockedPlayersChangeDelegateHandles[LocalUserNum];
if (TempHandle.IsValid())
{
FriendsInterface->ClearOnFriendsChangeDelegate_Handle(LocalUserNum, TempHandle);
}
} -
基本的に、これら2つの関数を使用すると、
BindOnCachedBlockedPlayersDataUpdated()関数を使用してブロックされたプレイヤーリストが更新されたときに実行されるデリゲートをバインドできます。そのデリゲートをアンバインドするには、UnbindOnCachedBlockedPlayersDataUpdated()関数を使用できます。これらの関数は、次のチュートリアルで表示されるエントリウィジェットを更新するために使用します。
リソース
- このチュートリアルセクションで使用されるファイルは、Unreal Byte Wars GitHub リポジトリで入手できます。