サブシステムを実装する - 専用サーバーを使用した参加可能なセッション - (Unreal Engine モジュール)
注釈:本資料はAI技術を用いて翻訳されています。
マッチセッションの実装は、2つの異なるクラスを通じて行われます。オンラインセッションクラスとゲームインスタンスサブシステムクラスです。オンラインセッションは、ゲームクライアントに関連するすべてのロジックを実装する場所であり、ゲームインスタンスサブシステムはサーバーロジック用です。
セッション閲覧フロー
このモジュールを開始する前に、セッション閲覧フローを理解してください。
ゲームクライアントのオンラインセッションをセットアップする
マッチセッションのゲームクライアント実装を処理するために、MatchSessionDSOnlineSession_Starter というオンラインセッションクラスを作成しました。このオンラインセッションクラスは、すぐに実装を開始できるように必要な宣言と定義を提供します。
MatchSessionDSOnlineSession_Starter クラスファイルは以下の場所にあります。
- ヘッダーファイル:
/Source/AccelByteWars/TutorialModules/Play/MatchSessionDS/MatchSessionDSOnlineSession_Starter.h - CPPファイル:
/Source/AccelByteWars/TutorialModules/Play/MatchSessionDS/MatchSessionDSOnlineSession_Starter.cpp
クラスで提供されている内容を確認してください。セッション入門モジュールでアクセスできたすべての関数に引き続きアクセスできることに注意してください。このオンラインセッションクラスの親として USessionEssentialsOnlineSession を使用しているためです。
-
MatchSessionDSOnlineSession_Starterヘッダーファイルには、名前にQueryUserInfoを含む関数と変数が表示されます。チュートリアルの目的上、これらの関数と変数は無視してください。マッチセッションの実装には必要ありませんが、Byte Wars には必要です。Byte Wars はこれらを使用して、サーバー上のバックエンドからプレイヤー情報を取得し、セッションの所有者のユーザー名を表示します。public:
// ...
virtual void DSQueryUserInfo(
const TArray<FUniqueNetIdRef>& UserIds,
const FOnDSQueryUsersInfoComplete& OnComplete) override;protected:
// ...
virtual void OnDSQueryUserInfoComplete(
const FListUserDataResponse& UserInfoList,
const FOnDSQueryUsersInfoComplete& OnComplete) override;private:
// ...
FDelegateHandle OnDSQueryUserInfoCompleteDelegateHandle;
// ...
void OnQueryUserInfoForFindSessionComplete(
const ::FOnlineError& Error,
const TArray<TSharedPtr<FUserOnlineAccountAccelByte>>& UsersInfo); -
ヘッダーファイルには、デリゲートとそのゲッターが表示されます。このデリゲートは、リクエストを行う際にUIを応答呼び出しに接続する方法になります。
public:
// ...
virtual FOnServerSessionUpdateReceived* GetOnSessionServerUpdateReceivedDelegates() override
{
return &OnSessionServerUpdateReceivedDelegates;
}
// ...
virtual FOnMatchSessionFindSessionsComplete* GetOnFindSessionsCompleteDelegates() override
{
return &OnFindSessionsCompleteDelegates;
}private:
// ...
FOnServerSessionUpdateReceived OnSessionServerUpdateReceivedDelegates;
// ...
FOnMatchSessionFindSessionsComplete OnFindSessionsCompleteDelegates; -
MatchSessionTemplateNameMapというTMap変数もあります。これを、以前にセットアップしたセッションテンプレートの名前に設定します。public:
// ...
const TMap<TPair<EGameModeNetworkType, EGameModeType>, FString> MatchSessionTemplateNameMap = {
{{EGameModeNetworkType::DS, EGameModeType::FFA}, "unreal-elimination-ds-ams"},
{{EGameModeNetworkType::DS, EGameModeType::TDM}, "unreal-teamdeathmatch-ds-ams"}
};
const TMap<TPair<EGameModeType, EGameStyle>, FString> MatchSessionTargetGameModeMap = {
{ { EGameModeType::FFA, EGameStyle::Zen }, "ELIMINATION-DS-USERCREATED" },
{ { EGameModeType::TDM, EGameStyle::Zen }, "TEAMDEATHMATCH-DS-USERCREATED" },
{ { EGameModeType::FFA, EGameStyle::Frenzy }, "FRENZY-ELIMINATION-DS-USERCREATED" },
{ { EGameModeType::TDM, EGameStyle::Frenzy }, "FRENZY-TEAMDEATHMATCH-DS-USERCREATED" }
}; -
後で追加する実装に使用される2つの変数があります。
private:
// ...
bool bIsInSessionServer = false;
// ...
TSharedRef<FOnlineSessionSearch> SessionSearch = MakeShared<FOnlineSessionSearch>(FOnlineSessionSearch());
int32 LocalUserNumSearching;
クライアントからサーバーへの移動
ゲームセッションに参加した後、バックエンドはサーバーのIPアドレスをゲームクライアントに送信します。ゲームクライアントは、指定されたIPアドレスに移動する方法が必要です。
-
関数を宣言します。
MatchSessionDSOnlineSession_Starterヘッダーファイルを開き、以下の宣言を追加します。public:
// ...
virtual bool TravelToSession(const FName SessionName) override;protected:
virtual void OnSessionServerUpdateReceived(FName SessionName) override;
virtual void OnSessionServerErrorReceived(FName SessionName, const FString& Message) override; -
MatchSessionDSOnlineSession_StarterCPPファイルを開き、以下の実装を追加します。TravelToSession()関数は、キャッシュされたセッション情報からサーバーのIPアドレスを取得し、そのサーバーへの移動を試みます。OnSessionServerUpdateReceivedとOnSessionServerErrorReceivedは、ゲームクライアントがバックエンドからサーバーに関する更新を受信したときに実行される関数です。bool UMatchSessionDSOnlineSession_Starter::TravelToSession(const FName SessionName)
{
UE_LOG_MATCHSESSIONDS(Verbose, TEXT("called"))
if (GetSessionType(SessionName) != EAccelByteV2SessionType::GameSession)
{
UE_LOG_MATCHSESSIONDS(Warning, TEXT("Not a game session"));
return false;
}
// Get session info
const FNamedOnlineSession* Session = GetSession(SessionName);
if (!Session)
{
UE_LOG_MATCHSESSIONDS(Warning, TEXT("The session is invalid"));
return false;
}
const TSharedPtr<FOnlineSessionInfo> SessionInfo = Session->SessionInfo;
if (!SessionInfo.IsValid())
{
UE_LOG_MATCHSESSIONDS(Warning, TEXT("The session info is invalid"));
return false;
}
const TSharedPtr<FOnlineSessionInfoAccelByteV2> AbSessionInfo = StaticCastSharedPtr<FOnlineSessionInfoAccelByteV2>(SessionInfo);
if (!AbSessionInfo.IsValid())
{
UE_LOG_MATCHSESSIONDS(Warning, TEXT("The session info is not FOnlineSessionInfoAccelByteV2"));
return false;
}
// get player controller of the local owner of the user
APlayerController* PlayerController = GetPlayerControllerByUniqueNetId(Session->LocalOwnerId);
// if nullptr, treat as failed
if (!PlayerController)
{
UE_LOG_MATCHSESSIONDS(Warning, TEXT("Can't find player controller with the session's local owner's unique ID"));
return false;
}
AAccelByteWarsPlayerController* AbPlayerController = Cast<AAccelByteWarsPlayerController>(PlayerController);
if (!AbPlayerController)
{
UE_LOG_MATCHSESSIONDS(Warning, TEXT("Player controller is not (derived from) AAccelByteWarsPlayerController"));
return false;
}
// Make sure this is not a P2P session
if (GetABSessionInt()->IsPlayerP2PHost(GetLocalPlayerUniqueNetId(PlayerController).ToSharedRef().Get(), SessionName))
{
UE_LOG_MATCHSESSIONDS(Warning, TEXT("The session is a P2P session"));
return false;
}
FString ServerAddress = "";
GetABSessionInt()->GetResolvedConnectString(SessionName, ServerAddress);
if (ServerAddress.IsEmpty())
{
UE_LOG_MATCHSESSIONDS(Warning, TEXT("Can't find session's server address"));
return false;
}
if (!bIsInSessionServer)
{
AbPlayerController->DelayedClientTravel(ServerAddress, TRAVEL_Absolute);
bIsInSessionServer = true;
}
else
{
UE_LOG_MATCHSESSIONDS(Warning, TEXT("Already in session's server"));
}
return true;
}void UMatchSessionDSOnlineSession_Starter::OnSessionServerUpdateReceived(FName SessionName)
{
UE_LOG_MATCHSESSIONDS(Verbose, TEXT("called"))
if (bLeavingSession)
{
UE_LOG_MATCHSESSIONDS(Warning, TEXT("called but leave session is currently running. Canceling attempt to travel to server"))
OnSessionServerUpdateReceivedDelegates.Broadcast(SessionName, FOnlineError(true), false);
return;
}
const bool bHasClientTravelTriggered = TravelToSession(SessionName);
OnSessionServerUpdateReceivedDelegates.Broadcast(SessionName, FOnlineError(true), bHasClientTravelTriggered);
}void UMatchSessionDSOnlineSession_Starter::OnSessionServerErrorReceived(FName SessionName, const FString& Message)
{
UE_LOG_MATCHSESSIONDS(Verbose, TEXT("called"))
FOnlineError Error;
Error.bSucceeded = false;
Error.ErrorMessage = FText::FromString(Message);
OnSessionServerUpdateReceivedDelegates.Broadcast(SessionName, Error, false);
} -
クライアントがサーバーから切断されたが、まだセッションサービスに接続されている場合の処理が必要です。この場合、プレイヤーは引き続きセッションの一部として扱われます。この切断が発生するたびに
LeaveSessionを呼び出します。Unreal Engine のオンラインセッションクラスが提供する関数、HandleDisconnectInternalを使用します。MatchSessionDSOnlineSession_Starterヘッダーファイルに戻り、この宣言を追加します。protected:
// ...
virtual bool HandleDisconnectInternal(UWorld* World, UNetDriver* NetDriver) override; -
MatchSessionDSOnlineSession_StarterCPPファイルを開き、以下の実装を追加します。bool UMatchSessionDSOnlineSession_Starter::HandleDisconnectInternal(UWorld* World, UNetDriver* NetDriver)
{
UE_LOG_MATCHSESSIONDS(Verbose, TEXT("called"))
LeaveSession(GetPredefinedSessionNameFromType(EAccelByteV2SessionType::GameSession));
bIsInSessionServer = false;
GEngine->HandleDisconnect(World, NetDriver);
return true;
}
マッチセッションを作成する
-
MatchSessionDSOnlineSession_Starterヘッダーファイルを開き、MatchSessionTemplateNameMapマップの値を、以前にセットアップしたセッションテンプレート名に設定していることを確認してください。チュートリアルとまったく同じ名前でセッションテンプレート名を作成した場合は、以下のコードをコピーするだけです。public:
// ...
const TMap<TPair<EGameModeNetworkType, EGameModeType>, FString> MatchSessionTemplateNameMap = {
{{EGameModeNetworkType::DS, EGameModeType::FFA}, "unreal-elimination-ds-ams"},
{{EGameModeNetworkType::DS, EGameModeType::TDM}, "unreal-teamdeathmatch-ds-ams"}
};
const TMap<TPair<EGameModeType, EGameStyle>, FString> MatchSessionTargetGameModeMap = {
{ { EGameModeType::FFA, EGameStyle::Zen }, "ELIMINATION-DS-USERCREATED" },
{ { EGameModeType::TDM, EGameStyle::Zen }, "TEAMDEATHMATCH-DS-USERCREATED" },
{ { EGameModeType::FFA, EGameStyle::Frenzy }, "FRENZY-ELIMINATION-DS-USERCREATED" },
{ { EGameModeType::TDM, EGameStyle::Frenzy }, "FRENZY-TEAMDEATHMATCH-DS-USERCREATED" }
}; -
ヘッダーファイルに、この関数宣言を追加します。
public:
// ...
virtual void CreateMatchSession(
const int32 LocalUserNum,
const EGameModeNetworkType NetworkType,
const EGameModeType GameModeType, const EGameStyle GameStyle) override; -
MatchSessionDSOnlineSession_StarterCPPファイルを開き、以下の実装を追加します。SessionSettingsにフラグGAME_SESSION_REQUEST_TYPEを設定していることに注意してください。これにより、FindSessions()関数がバックエンドにそのフラグを持つセッションのみを返すように指示できます。応答を手動でフィルタリングする必要がなくなります。void UMatchSessionDSOnlineSession_Starter::CreateMatchSession(
const int32 LocalUserNum,
const EGameModeNetworkType NetworkType,
const EGameModeType GameModeType, const EGameStyle GameStyle)
{
FOnlineSessionSettings SessionSettings;
// Set a flag so we can request a filtered session from backend
SessionSettings.Set(GAME_SESSION_REQUEST_TYPE, GAME_SESSION_REQUEST_TYPE_MATCHSESSION);
// flag to signify the server which game mode to use
SessionSettings.Set(GAMESETUP_GameModeCode, MatchSessionTargetGameModeMap[{ GameModeType, GameStyle }]);
// Get match session template name based on game mode type
FString MatchTemplateName = MatchSessionTemplateNameMap[{EGameModeNetworkType::DS, GameModeType}];
// Override match session template name if applicable.
if (!UTutorialModuleOnlineUtility::GetMatchSessionTemplateDSOverride().IsEmpty())
{
MatchTemplateName = UTutorialModuleOnlineUtility::GetMatchSessionTemplateDSOverride();
}
#pragma region "Region Preferences"
// include region preferences into session setting
if(NetworkType == EGameModeNetworkType::DS)
{
if (const UTutorialModuleDataAsset* ModuleDataAsset = UTutorialModuleUtility::GetTutorialModuleDataAsset(
FPrimaryAssetId{ "TutorialModule:REGIONPREFERENCES" },
this,
true))
{
const UAccelByteWarsGameInstance* GameInstance = StaticCast<UAccelByteWarsGameInstance*>(GetGameInstance());
ensure(GameInstance);
// Get enabled regions
TArray<FString> EnabledRegions = {};
if (ModuleDataAsset->IsStarterModeActive())
{
// Starter mode is active, use the starter subsystem
URegionPreferencesSubsystem_Starter* RegionPreferencesSubsystem = GameInstance->GetSubsystem<URegionPreferencesSubsystem_Starter>();
if(RegionPreferencesSubsystem != nullptr)
{
EnabledRegions = RegionPreferencesSubsystem->GetEnabledRegion();
}
}
else
{
// Starter mode is not active, use the non starter subsystem.
URegionPreferencesSubsystem* RegionPreferencesSubsystem = GameInstance->GetSubsystem<URegionPreferencesSubsystem>();
if(RegionPreferencesSubsystem != nullptr)
{
EnabledRegions = RegionPreferencesSubsystem->GetEnabledRegion();
}
}
if(!EnabledRegions.IsEmpty())
{
FOnlineSessionSettingsAccelByte::Set(SessionSettings, SETTING_GAMESESSION_REQUESTEDREGIONS, EnabledRegions);
}
}
}
#pragma endregion
CreateSession(
LocalUserNum,
GetPredefinedSessionNameFromType(EAccelByteV2SessionType::GameSession),
SessionSettings,
EAccelByteV2SessionType::GameSession,
MatchTemplateName);
}備考リージョンプリファレンスの部分は、マッチセッション機能のみを実装したい場合は必要ありません。この機能を独自のゲームに統合するためのサンプルとして使用している場合は、統合時にこの部分を削除しても構いません。
マッチセッションを検索する
-
MatchSessionDSOnlineSession_Starterヘッダーファイルを開き、以下の2つの関数宣言を追加します。これらは呼び出し関数と応答コールバックになります。public:
// ...
virtual void FindSessions(
const int32 LocalUserNum,
const int32 MaxQueryNum,
const bool bForce) override;protected:
// ...
virtual void OnFindSessionsComplete(bool bSucceeded) override; -
MatchSessionDSOnlineSession_StarterCPPファイルを開き、以下の実装を追加します。CreateMatchSessionの実装でSessionSettingsにフラグを設定したため、同じフラグをQuerySettingsとしても設定することに注意してください。また、FindSessions()を呼び出すときにクラスメンバー変数SessionSearchを渡していることにも注意してください。FindSessions()はFOnlineSessionSearch変数を参照し、参照が指す変数を更新するため、OnFindSessionsCompleteにはパラメータとしてセッション情報が含まれません。void UMatchSessionDSOnlineSession_Starter::FindSessions(
const int32 LocalUserNum,
const int32 MaxQueryNum,
const bool bForce)
{
UE_LOG_MATCHSESSIONDS(Verbose, TEXT("called"))
if (SessionSearch->SearchState == EOnlineAsyncTaskState::InProgress)
{
UE_LOG_MATCHSESSIONDS(Warning, TEXT("Currently searching"))
return;
}
// check cache
if (!bForce && MaxQueryNum <= SessionSearch->SearchResults.Num())
{
UE_LOG_MATCHSESSIONDS(Log, TEXT("Cache found"))
// return cache
ExecuteNextTick(FTimerDelegate::CreateWeakLambda(this, [this]()
{
OnFindSessionsComplete(true);
}));
return;
}
SessionSearch->SearchState = EOnlineAsyncTaskState::NotStarted;
SessionSearch->MaxSearchResults = MaxQueryNum;
SessionSearch->SearchResults.Empty();
LocalUserNumSearching = LocalUserNum;
// reset
SessionSearch->QuerySettings = FOnlineSearchSettings();
// Request a filtered session from backend based on the flag we set on CreateSession_Caller
SessionSearch->QuerySettings.Set(
GAME_SESSION_REQUEST_TYPE, GAME_SESSION_REQUEST_TYPE_MATCHSESSION, EOnlineComparisonOp::Equals);
if (!GetSessionInt()->FindSessions(LocalUserNum, SessionSearch))
{
ExecuteNextTick(FTimerDelegate::CreateWeakLambda(this, [this]()
{
OnFindSessionsComplete(false);
}));
}
}void UMatchSessionDSOnlineSession_Starter::OnFindSessionsComplete(bool bSucceeded)
{
UE_LOG_MATCHSESSIONDS(Log, TEXT("succeeded: %s"), *FString(bSucceeded ? TEXT("TRUE") : TEXT("FALSE")))
if (bSucceeded)
{
// Remove owned session from result if exists
const FUniqueNetIdPtr LocalUserNetId = GetIdentityInt()->GetUniquePlayerId(LocalUserNumSearching);
SessionSearch->SearchResults.RemoveAll([this, LocalUserNetId](const FOnlineSessionSearchResult& Element)
{
return CompareAccelByteUniqueId(
FUniqueNetIdRepl(LocalUserNetId),
FUniqueNetIdRepl(Element.Session.OwningUserId));
});
#pragma region "Region Preferences"
// remove session that not in region preferences
if (const UTutorialModuleDataAsset* ModuleDataAsset = UTutorialModuleUtility::GetTutorialModuleDataAsset(
FPrimaryAssetId{ "TutorialModule:REGIONPREFERENCES" },
this,
true))
{
const UAccelByteWarsGameInstance* GameInstance = StaticCast<UAccelByteWarsGameInstance*>(GetGameInstance());
ensure(GameInstance);
if (ModuleDataAsset->IsStarterModeActive())
{
// Starter is enabled, use the starter subsystem.
URegionPreferencesSubsystem_Starter* RegionPreferencesSubsystem = GameInstance->GetSubsystem<URegionPreferencesSubsystem_Starter>();
if(RegionPreferencesSubsystem != nullptr)
{
RegionPreferencesSubsystem->FilterSessionSearch(SessionSearch);
}
}
else
{
// Starter is not enabled, use the non starter subsystem.
URegionPreferencesSubsystem* RegionPreferencesSubsystem = GameInstance->GetSubsystem<URegionPreferencesSubsystem>();
if(RegionPreferencesSubsystem != nullptr)
{
RegionPreferencesSubsystem->FilterSessionSearch(SessionSearch);
}
}
}
#pragma endregion
// Trigger immediately if the results are empty at this point.
if (SessionSearch->SearchResults.IsEmpty())
{
OnFindSessionsCompleteDelegates.Broadcast({}, true);
return;
}
// Get owner’s user info for queried user info.
TArray<FUniqueNetIdRef> UserIds;
for (const FOnlineSessionSearchResult& SearchResult : SessionSearch->SearchResults)
{
UserIds.AddUnique(SearchResult.Session.OwningUserId->AsShared());
}
// Trigger to query user info
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 4
if (UStartupSubsystem* StartupSubsystem = GetWorld()->GetGameInstance()->GetSubsystem<UStartupSubsystem>())
#else
if (UStartupSubsystem* StartupSubsystem = GetWorld()->GetGameInstance<UStartupSubsystem>())
#endif
{
StartupSubsystem->QueryUserInfo(
LocalUserNumSearching,
UserIds,
FOnQueryUsersInfoCompleteDelegate::CreateUObject(this, &ThisClass::OnQueryUserInfoForFindSessionComplete));
return;
}
}
OnFindSessionsCompleteDelegates.Broadcast({}, false);
}備考リージョンプリファレンスの部分は、マッチセッション機能のみを実装したい場合は必要ありません。この機能を独自のゲームに統合するためのサンプルとして使用している場合は、統合時にこの部分を削除しても構いません。
-
OnFindSessionsCompleteをデリゲートにバインドします。CPPファイルで、RegisterOnlineDelegatesに移動し、以下のコードを追加します。void UMatchSessionDSOnlineSession_Starter::RegisterOnlineDelegates()
{
// ...
// Match session delegates
GetSessionInt()->OnFindSessionsCompleteDelegates.AddUObject(this, &ThisClass::OnFindSessionsComplete);
SessionSearch->SearchState = EOnlineAsyncTaskState::NotStarted;
} -
そのコールバックをアンバインドする方法を実装します。CPPファイルで、
ClearOnlineDelegatesに移動し、以下のコードを追加します。void UMatchSessionDSOnlineSession_Starter::ClearOnlineDelegates()
{
// ...
GetSessionInt()->OnFindSessionsCompleteDelegates.RemoveAll(this);
}ゲームクライアントのオンラインセッション実装が完了しました。
専用サーバーのオンラインサブシステムをセットアップする
マッチセッションのサーバー実装を処理するために、UMatchSessionDSServerSubsystem_Starter というゲームインスタンスサブシステムクラスが作成されています。このオンラインセッションクラスは、すぐに実装を開始できるように必要な宣言と定義を提供します。
UMatchSessionDSServerSubsystem_Starter クラスファイルは以下の場所にあります。
- ヘッダーファイル:
/Source/AccelByteWars/TutorialModules/Play/MatchSessionDS/MatchSessionDSServerSubsystem_Starter.h - CPPファイル:
/Source/AccelByteWars/TutorialModules/Play/MatchSessionDS/MatchSessionDSServerSubsystem_Starter.cpp
提供されているクラスを確認してください。
-
UMatchSessionDSServerSubsystem_Starterヘッダーファイルには、Game specific というラベルの付いたリージョンが表示されます。オンラインセッションのQueryUserInfoと同様に、このコードはマッチセッションの実装には必要ありませんが、Byte Wars には必要です。このコードは、サーバーにログインしたプレイヤーが実際にセッションの一部であることを確認します。そうでない場合は、そのプレイヤーをキックします。このチュートリアルでは、このセクションは無視してください。protected:
// ...
virtual void OnAuthenticatePlayerComplete_PrePlayerSetup(APlayerController* PlayerController) override; -
ヘッダーファイルには
OnlineSessionという変数もあります。これは、先ほど実装したオンラインセッションへのポインタです。private:
UPROPERTY()
UMatchSessionDSOnlineSession_Starter* OnlineSession;
サーバーがセッションを受信
サーバーがバックエンドに自身を登録した直後、セッションが専用サーバーを必要とする場合、バックエンドはその専用サーバーをセッションに割り当てます。これが発生すると、専用サーバーは通知を受け取ります。Byte Wars では、SessionSettings のフラグを使用して、サーバーが使用するゲームモードを決定しました。
-
UMatchSessionDSServerSubsystem_Starterヘッダーファイルを開き、この関数宣言を追加します。protected:
// ...
virtual void OnServerSessionReceived(FName SessionName) override; -
ここのコードのほとんどは Byte Wars 固有のものです。ゲームで必要になる可能性のある行をハイライトしました。これは、セッションデータ自体を取得することと、セッションの作成時に設定したカスタム
SessionSettingsを取得する方法の例です。void UMatchSessionDSServerSubsystem_Starter::OnServerSessionReceived(FName SessionName)
{
Super::OnServerSessionReceived(SessionName);
UE_LOG_MATCHSESSIONDS(Verbose, TEXT("called"))
#pragma region "Assign game mode based on SessionTemplateName from backend"
// Get GameMode
const UWorld* World = GetWorld();
if (!World)
{
UE_LOG_MATCHSESSIONDS(Warning, TEXT("World is invalid"));
return;
}
AGameStateBase* GameState = World->GetGameState();
if (!GameState)
{
UE_LOG_MATCHSESSIONDS(Warning, TEXT("Game State is invalid"));
return;
}
AAccelByteWarsGameState* AbGameState = Cast<AAccelByteWarsGameState>(GameState);
if (!AbGameState)
{
UE_LOG_MATCHSESSIONDS(Warning, TEXT("Game State is not derived from AAccelByteWarsGameState"));
return;
}
// Get game session
if (OnlineSession->GetSessionType(SessionName) != EAccelByteV2SessionType::GameSession)
{
UE_LOG_MATCHSESSIONDS(Warning, TEXT("Is not a game session"));
return;
}
const FNamedOnlineSession* Session = OnlineSession->GetSession(SessionName);
if (!Session)
{
UE_LOG_MATCHSESSIONDS(Warning, TEXT("The session is invalid"));
return;
}
// Get game related info from session
FString RequestedGameModeCode = TEXT("");
Session->SessionSettings.Get(GAMESETUP_GameModeCode, RequestedGameModeCode);
// Try getting manually set game rules, if GAMESETUP_DisplayName empty, go to the next flow
bool bIsCustomGame = false;
if (Session->SessionSettings.Get(GAMESETUP_IsCustomGame, bIsCustomGame) && bIsCustomGame)
{
AbGameState->AssignCustomGameMode(&Session->SessionSettings);
}
// If not complete, try getting requested game mode
else if (!RequestedGameModeCode.IsEmpty())
{
AbGameState->AssignGameMode(RequestedGameModeCode);
}
#pragma endregion
// Query all currently registered users' info
AuthenticatePlayer_OnRefreshSessionComplete(true);
} -
その関数をオンラインサブシステム(OSS)デリゲートにバインドします。CPPファイルで、
Initializeに移動し、以下のコードを追加します。void UMatchSessionDSServerSubsystem_Starter::Initialize(FSubsystemCollectionBase& Collection)
{
// ...
GetABSessionInt()->OnServerReceivedSessionDelegates.AddUObject(this, &ThisClass::OnServerSessionReceived);
} -
不要になったら、その関数をアンバインドします。
Deinitializeに移動し、以下のコードを追加します。void UMatchSessionDSServerSubsystem_Starter::Deinitialize()
{
// ...
GetABSessionInt()->OnServerReceivedSessionDelegates.RemoveAll(this);
}
リソース
- このチュートリアルセクションで使用されているファイルは、Byte Wars GitHubリポジトリで入手できます。
- AccelByteWars/Source/AccelByteWars/TutorialModules/Play/MatchSessionDS/MatchSessionDSOnlineSession_Starter.h
- AccelByteWars/Source/AccelByteWars/TutorialModules/Play/MatchSessionDS/MatchSessionDSOnlineSession_Starter.cpp
- AccelByteWars/Source/AccelByteWars/TutorialModules/Play/MatchSessionDS/MatchSessionDSServerSubsystem_Starter.h
- AccelByteWars/Source/AccelByteWars/TutorialModules/Play/MatchSessionDS/MatchSessionDSServerSubsystem_Starter.cpp